Nano RP2040 Connect Python API Guide

Discover how to access the features Nano RP2040 Connect using Python scripts.

The Nano RP2040 Connect
The Nano RP2040 Connect

The Nano RP2040 Connect board can be programmed using the popular Python programming language. The board is supported by upstream MicroPython and OpenMV's fork of MicroPython, where MicroPython is an implementation of the Python language, designed to run on microcontrollers.

In this article, you will find a lot of sample scripts that will work directly with your Nano RP2040 Connect, such as general GPIO control, reading onboard sensors and Wi-Fi/BLE communication!

  • If you want to read more about Arduino & Python, you can visit the Python with Arduino article. Here you will find a lot of useful examples, such as how to use delays, interrupts, reading pins and more general functions.

Hardware Requirements

Software Requirements

OpenMV Installation

To install the OpenMV IDE and load scripts to your board, you can refer to Getting started with OpenMV and Nano RP2040 Connect.

MicroPython Installation

To install upstream MicroPython and load scripts to your board, you will need to follow a few simple steps:

1. Connect your board to your computer via USB.

2. Download and install the Thonny Editor (or other preferred editors).

3. Download the

.uf2
file from the Nano RP2040 Connect's nightly build page

4. Place a jumper wire between the REC and GND pins on the board, then press the RESET button. This will open mass storage.

Place a jumper wire between REC and GND pins.
Place a jumper wire between REC and GND pins.

5. Drag and drop the

.uf2
file into mass storage. This will install MicroPython on your board.

6. In the Thonny Editor, navigate to Run > Select Interpreter.

Navigate to interpreter.
Navigate to interpreter.

7. Select MicroPython(generic) and from port, select your device (in this case, it is COM17).

Select the port.
Select the port.

8. Write a Python script (or select any example from the list below), and click on the Green Play Button (F5) to run it on your board.

Congratulations! You can now run MicroPython scripts on your Nano RP2040 Connect board!

You can visit the docs for MicroPython to get a better overview of the MicroPython API.

API

Below you will find a lot of useful examples that can be loaded to your Nano RP2040 Connect board. Many of these examples were extracted from the OpenMV repository, where you can find many useful examples for other boards as well.

In this article, you will only find examples for the Nano RP2040 Connect board. For more information on how to use delays, read and write to pins, please refer to the Python with Arduino main article.

GPIO Map

The pinout for the Nano RP2040 Connect and the RP2040 microcontroller varies greatly. For example, if we are to use

D2
according to the Arduino pinout, we would actually need to use pin 25.

1# Defining "D2" on the Arduino Nano RP2040 Connect
2p0 = Pin(25, Pin.OUT)

Before you start using the board's pins, it might be a good idea to check out the table below to understand the relationship between Arduino's pinout and the RP2040's pinout.

ArduinoRP2040Usage
TXGPIO0UART/TX
RXGPIO1UART/RX
D2GPIO25GPIO
D3GPIO15GPIO
D4GPIO16GPIO
D5GPIO17GPIO
D6GPIO18GPIO
D7GPIO19GPIO
D8GPIO20GPIO
D9GPIO21GPIO
D10GPIO5GPIO
D11GPIO7SPI/COPI
D12GPIO4SPI/CIPO
D13GPIO6SPI/SCK
D14/A0GPIO26ADC/RP2040
D15/A1GPIO27ADC/RP2040
D16/A2GPIO28ADC/RP2040
D17/A3GPIO29ADC/RP2040
D18/A4GPIO12I2C
D19/A5GPIO13I2C
D20/A6GPIO36ADC/NINA-W102
D21/A7GPIO35ADC/NINA-W102

Note that pins A4, A5 are used as an I2C bus and are not recommended to be used as analog pins.

Analog Pins

To read the analog pins on the Nano RP2040 Connect, we can choose from the following pins:

  • A0 -
    26
  • A1 -
    27
  • A2 -
    28
  • A3 -
    29
  • A4 -
    12
    (I2C bus, not recommended to use)
  • A5 -
    13
    (I2C bus, not recommended to use)
  • A6 -
    36
    (Connected to the NINA module)
  • A7 -
    35
    (Connected to the NINA module)

To define them, we need to import the

machine
module, and define the pin as follows:

1import machine
2
3adc_pin = machine.Pin(29)
4adc = machine.ADC(adc_pin)

To read the analog pin, simply use:

1reading = adc.read_u16() #16-bit resolution (0-65535)

The below script will read the

A3
pin on the Nano RP2040 Connect and print the value in the terminal.

1import machine
2import time
3
4adc_pin = machine.Pin(29) # A3
5adc = machine.ADC(adc_pin)
6
7while True:
8 reading = adc.read_u16()
9 print("ADC: ",reading)
10 time.sleep_ms(500)

Sensors

IMU (LSM6DSOX)

Prints the accelerometer and gyroscope values in the Serial Monitor.

1import time
2from lsm6dsox import LSM6DSOX
3
4from machine import Pin, I2C
5lsm = LSM6DSOX(I2C(0, scl=Pin(13), sda=Pin(12)))
6
7while (True):
8 print('Accelerometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*lsm.read_accel()))
9 print('Gyroscope: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*lsm.read_gyro()))
10 print("")
11 time.sleep_ms(100)

Microphone (MP34DT05)

Below example can be used with OpenMV's frame buffer window (top right corner).

1import image, audio, time
2from ulab import numpy as np
3from ulab import scipy as sp
4
5CHANNELS = 1
6FREQUENCY = 32000
7N_SAMPLES = 32 if FREQUENCY == 16000 else 64
8SCALE = 2
9SIZE = (N_SAMPLES * SCALE) // CHANNELS
10
11raw_buf = None
12fb = image.Image(SIZE+(50*SCALE), SIZE, image.RGB565, copy_to_fb=True)
13audio.init(channels=CHANNELS, frequency=FREQUENCY, gain_db=16)
14
15def audio_callback(buf):
16 # NOTE: do Not call any function that allocates memory.
17 global raw_buf
18 if (raw_buf == None):
19 raw_buf = buf
20
21# Start audio streaming
22audio.start_streaming(audio_callback)
23
24def draw_fft(img, fft_buf):
25 fft_buf = (fft_buf / max(fft_buf)) * SIZE
26 fft_buf = np.log10(fft_buf + 1) * 20
27 color = (0xFF, 0x0F, 0x00)
28 for i in range(0, len(fft_buf)):
29 img.draw_line(i*SCALE, SIZE, i*SCALE, SIZE-int(fft_buf[i]) * SCALE, color, SCALE)
30
31def draw_audio_bar(img, level, offset):
32 blk_size = (SIZE//10)
33 color = (0xFF, 0x00, 0xF0)
34 blk_space = (blk_size//4)
35 for i in range(0, int(round(level/10))):
36 fb.draw_rectangle(SIZE+offset, SIZE - ((i+1)*blk_size) + blk_space, 20 * SCALE, blk_size - blk_space, color, 1, True)
37
38while (True):
39 if (raw_buf != None):
40 pcm_buf = np.frombuffer(raw_buf, dtype=np.int16)
41 raw_buf = None
42
43 if CHANNELS == 1:
44 fft_buf = sp.signal.spectrogram(pcm_buf)
45 l_lvl = int((np.mean(abs(pcm_buf[1::2])) / 32768)*100)
46 else:
47 fft_buf = sp.signal.spectrogram(pcm_buf[0::2])
48 l_lvl = int((np.mean(abs(pcm_buf[1::2])) / 32768)*100)
49 r_lvl = int((np.mean(abs(pcm_buf[0::2])) / 32768)*100)
50
51 fb.clear()
52 draw_fft(fb, fft_buf)
53 draw_audio_bar(fb, l_lvl, 0)
54 draw_audio_bar(fb, l_lvl, 25*SCALE)
55 if CHANNELS == 2:
56 draw_audio_bar(fb, r_lvl, 25 * SCALE)
57 fb.flush()
58
59# Stop streaming
60audio.stop_streaming()

Communication

I2C

Scans for devices connected to the I2C buses:

1import time
2from machine import Pin, I2C
3
4i2c_list = [None, None]
5i2c_list[0] = I2C(0, scl=Pin(13), sda=Pin(12), freq=100_000)
6i2c_list[1] = I2C(1, scl=Pin(7), sda=Pin(6), freq=100_000)
7
8for bus in range(0, 2):
9 print("\nScanning bus %d..."%(bus))
10 for addr in i2c_list[bus].scan():
11 print("Found device at address %d:0x%x" %(bus, addr))

UART

To read data and write data through TX and RX pins, you can use

uart.write()
and
uart.read()
.

1from machine import UART, Pin
2import time
3
4uart = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1))
5
6while True:
7 uart.write('hello') # writes 5 bytes
8 val = uart.read(5) # reads up to 5 bytes
9 print(val) # prints data
10 time.sleep(1)

Wireless

Below are examples on wireless connectivity, using the NINA-W102 module onboard the Nano RP2040 Connect.

In order to use these examples, you may have to upgrade your firmware. You can find instructions on how to in Upgrading Nano RP2040 Connect NINA firmware.

Wi-Fi AP Mode

Turn your board into an access point:

1# Wi-Fi AP Mode Example
2#
3# This example shows how to use Wi-Fi in Access Point mode.
4import network, socket, sys, time, gc
5
6SSID ='My_Nano_RP2040_Connect' # Network SSID
7KEY ='1234567890' # Network key (must be 10 chars)
8HOST = '' # Use first available interface
9PORT = 8080 # Arbitrary non-privileged port
10
11# Init wlan module and connect to network
12wlan = network.WLAN(network.AP_IF)
13wlan.active(True)
14wlan.config(essid=SSID, key=KEY, security=wlan.WEP, channel=2)
15print("AP mode started. SSID: {} IP: {}".format(SSID, wlan.ifconfig()[0]))
16
17def recvall(sock, n):
18 # Helper function to recv n bytes or return None if EOF is hit
19 data = bytearray()
20 while len(data) < n:
21 packet = sock.recv(n - len(data))
22 if not packet:
23 raise OSError("Timeout")
24 data.extend(packet)
25 return data
26
27def start_streaming(server):
28 print ('Waiting for connections..')
29 client, addr = server.accept()
30
31 # set client socket timeout to 5s
32 client.settimeout(5.0)
33 print ('Connected to ' + addr[0] + ':' + str(addr[1]))
34
35 # FPS clock
36 clock = time.clock()
37 while (True):
38 try:
39 # Read data from client
40 data = recvall(client, 1024)
41 # Send it back
42 client.send(data)
43 except OSError as e:
44 print("start_streaming(): socket error: ", e)
45 client.close()
46 break
47
48while (True):
49 try:
50 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
51 # Bind and listen
52 server.bind([HOST, PORT])
53 server.listen(1)
54
55 # Set server socket to blocking
56 server.setblocking(True)
57 while (True):
58 start_streaming(server)
59 except OSError as e:
60 server.close()
61 print("Server socket error: ", e)

Wi-Fi Scan

To scan available networks:

1# Scan Example
2
3# This example shows how to scan for Wi-Fi networks.
4
5import time, network
6
7wlan = network.WLAN(network.STA_IF)
8wlan.active(True)
9
10print("Scanning...")
11while (True):
12 scan_result = wlan.scan()
13 for ap in scan_result:
14 print("Channel:%d RSSI:%d Auth:%d BSSID:%s SSID:%s"%(ap))
15 print()
16 time.sleep_ms(1000)

HTTP Request

Making an HTTP request (in this case to google):

Remember to enter your network name and password inside the SSID and KEY variables.

1import network, socket
2
3# AP info
4SSID='' # Network SSID
5KEY='' # Network key
6
7PORT = 80
8HOST = "www.google.com"
9
10# Init wlan module and connect to network
11print("Trying to connect. Note this may take a while...")
12
13wlan = network.WLAN(network.STA_IF)
14wlan.active(True)
15wlan.connect(SSID, KEY)
16
17# We should have a valid IP now via DHCP
18print("Wi-Fi Connected ", wlan.ifconfig())
19
20# Get addr info via DNS
21addr = socket.getaddrinfo(HOST, PORT)[0][4]
22print(addr)
23
24# Create a new socket and connect to addr
25client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
26client.connect(addr)
27
28# Set timeout
29client.settimeout(3.0)
30
31# Send HTTP request and recv response
32client.send("GET / HTTP/1.1\r\nHost: %s\r\n\r\n"%(HOST))
33print(client.recv(1024))
34
35# Close socket
36client.close()

NTP (Network Time Protocol)

Remember to enter your network name and password inside the SSID and KEY variables.

Obtain accurate time and date from the Internet:

1# NTP Example
2#
3# This example shows how to get the current time using NTP
4
5import network, usocket, ustruct, utime
6
7# AP info
8SSID='' # Network SSID
9KEY='' # Network key
10
11TIMESTAMP = 2208988800
12
13# Init wlan module and connect to network
14print("Trying to connect... (may take a while)...")
15
16wlan = network.WLAN()
17wlan.active(True)
18wlan.connect(SSID, key=KEY, security=wlan.WPA_PSK)
19
20# We should have a valid IP now via DHCP
21print(wlan.ifconfig())
22
23# Create new socket
24client = usocket.socket(usocket.AF_INET, usocket.SOCK_DGRAM)
25client.bind(("", 8080))
26#client.settimeout(3.0)
27
28# Get addr info via DNS
29addr = usocket.getaddrinfo("pool.ntp.org", 123)[0][4]
30
31# Send query
32client.sendto('\x1b' + 47 * '\0', addr)
33data, address = client.recvfrom(1024)
34
35# Print time
36t = ustruct.unpack(">IIIIIIIIIIII", data)[10] - TIMESTAMP
37print ("Year:%d Month:%d Day:%d Time: %d:%d:%d" % (utime.localtime(t)[0:6]))

In the terminal, we should see it in this format:

1Year:2021 Month:8 Day:10 Time: 7:56:30

Bluetooth® Low Energy

This example allows us to connect to our board via our phone, and control the built-in LED. We recommend using the nRF Connect applications.

After loading the script below, your board should be listed as "Nano RP2040 Connect" in the list of available devices. You need to pair in order to control the built-in LED.

1import bluetooth
2import random
3import struct
4import time
5from ble_advertising import advertising_payload
6from machine import Pin
7from micropython import const
8
9LED_PIN = 6
10
11_IRQ_CENTRAL_CONNECT = const(1)
12_IRQ_CENTRAL_DISCONNECT = const(2)
13_IRQ_GATTS_WRITE = const(3)
14
15_FLAG_READ = const(0x0002)
16_FLAG_WRITE = const(0x0008)
17_FLAG_NOTIFY = const(0x0010)
18_FLAG_INDICATE = const(0x0020)
19
20_SERVICE_UUID = bluetooth.UUID(0x1523)
21_LED_CHAR_UUID = (bluetooth.UUID(0x1525), _FLAG_WRITE)
22_LED_SERVICE = (_SERVICE_UUID, (_LED_CHAR_UUID,),)
23
24class BLETemperature:
25 def __init__(self, ble, name="NANO RP2040"):
26 self._ble = ble
27 self._ble.active(True)
28 self._ble.irq(self._irq)
29 ((self._handle,),) = self._ble.gatts_register_services((_LED_SERVICE,))
30 self._connections = set()
31 self._payload = advertising_payload(name=name, services=[_SERVICE_UUID])
32 self._advertise()
33
34 def _irq(self, event, data):
35 # Track connections so we can send notifications.
36 if event == _IRQ_CENTRAL_CONNECT:
37 conn_handle, _, _ = data
38 self._connections.add(conn_handle)
39 elif event == _IRQ_CENTRAL_DISCONNECT:
40 conn_handle, _, _ = data
41 self._connections.remove(conn_handle)
42 # Start advertising again to allow a new connection.
43 self._advertise()
44 elif event == _IRQ_GATTS_WRITE:
45 Pin(LED_PIN, Pin.OUT).value(int(self._ble.gatts_read(data[-1])[0]))
46
47 def _advertise(self, interval_us=500000):
48 self._ble.gap_advertise(interval_us, adv_data=self._payload)
49
50if __name__ == "__main__":
51 ble = bluetooth.BLE()
52 temp = BLETemperature(ble)
53
54 while True:
55 time.sleep_ms(1000)

Summary

In this article we have gone through a selection of scripts that will help you control your Nano RP2040 Connect board, via the OpenMV IDE. Feel free to check out our Python with Arduino boards article, where you can find guides to other boards, useful links to learn Python and more.

Contribute to Arduino

Join the community and suggest improvements to this article via GitHub. Make sure to read out contribution policy before making your pull request.

Missing something?

Check out our store and get what you need to follow this tutorial.

Suggest Changes

The content on docs.arduino.cc is facilitated through a public GitHub repository. You can read more on how to contribute in the contribution policy.