Examples by Board

Find examples that work only with specific boards, such as reading built-in sensors.

In this article, you will find examples that works only with specific boards. Each board also has a GPIO map that explains how each pin can be addressed.

Nano RP2040 Connect

Nano RP2040 Connect.
Nano RP2040 Connect.

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

Analog Read

Note: This is currently only available on the nightly build. Follow this link to download it.

To read an analog pin, we can use the

ADC.read_u16
command. This reads the specified analog pin and returns an integer in the range 0 - 65535. For this, we need to import
ADC
from the
machine
module.

1from machine import ADC
2
3while True:
4 adc = ADC("A4")
5 adc.read_u16()

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)

Nano 33 BLE

Nano 33 BLE.
Nano 33 BLE.

GPIO Map

The pinout for the Nano 33 BLE and the NRF52840 microcontroller varies greatly. For example, if we are to use

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

1# Defining "D2" on the Nano 33 BLE
2p0 = Pin(43, Pin.OUT)

In the MicroPython port of the Nano 33 BLE board, the pinout is the same as the Nordic NRF52840 (the microcontroller). You will find a GPIO Map below that explains how to address the different pins.

ArduinonRF52840
TX35
RX42
D243
D344
D447
D545
D646
D723
D821
D927
D1034
D1133
D1240
D1313
D14/A04
D15/A15
D16/A230
D17/A329
D18/A431
D19/A52
D20/A628
D21/A73

Analog Read

The following example is currently only possible with the nightly build

LED Control

There are 3 different LEDs that can be accessed on the Nano 33 BLE: RGB, the built-in LED and the power LED.

They can be accessed by importing the

LED
module, where the RGB and built-in LED can be accessed.

1from board import LED
2
3led_red = LED(1) # red LED
4led_green = LED(2) # green LED
5led_blue = LED(3) # blue LED
6led_builtin = LED(4) # classic built-in LED (also accessible through pin 13)

To access the power LED we need to import the

Pin
module.

1from machine import Pin
2
3led_pwr = Pin(41, Pin.OUT)

RGB

Blink all RGB lights every 0.25 seconds.

1from board import LED
2import time
3
4led_red = LED(1)
5led_green = LED(2)
6led_blue = LED(3)
7
8while (True):
9
10 # Turn on LEDs
11 led_red.on()
12 led_green.on()
13 led_blue.on()
14
15 # Wait 0.25 seconds
16 time.sleep_ms(250)
17
18 # Turn off LEDs
19 led_red.off()
20 led_green.off()
21 led_blue.off()
22
23 # Wait 0.25 seconds
24 time.sleep_ms(250)

Built-in LED

The classic blink example! Blink the built-in LED every 0.25 seconds.

1from board import LED
2import time
3
4led_builtin = LED(4)
5
6while (True):
7
8 # Turn on LED
9 led_builtin.on()
10
11 # Wait 0.25 seconds
12 time.sleep_ms(250)
13
14 # Turn off LED
15 led_builtin.off()
16
17 # Wait 0.25 seconds
18 time.sleep_ms(250)

Sensors

IMU (LSM9DS1, BMI270 + BMM150)

Access the

accelerometer
,
magnetometer
, and
gyroscope
data from the IMU module.

1import time
2import imu
3from machine import Pin, I2C
4
5bus = I2C(1, scl=Pin(15), sda=Pin(14))
6imu = imu.IMU(bus)
7
8while (True):
9 print('Accelerometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*imu.accel()))
10 print('Gyroscope: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*imu.gyro()))
11 print('Magnetometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*imu.magnet()))
12 print("")
13 time.sleep_ms(100)

Wireless

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 33 BLE" in the list of available devices. You need to pair in order to control the built-in LED.

1# Use nRF Connect from App store, connect to the Nano and write 1/0 to control the LED.
2
3import time
4from board import LED
5from ubluepy import Service, Characteristic, UUID, Peripheral, constants
6
7def event_handler(id, handle, data):
8 global periph
9 global service
10 if id == constants.EVT_GAP_CONNECTED:
11 pass
12 elif id == constants.EVT_GAP_DISCONNECTED:
13 # restart advertisement
14 periph.advertise(device_name="Nano 33 BLE", services=[service])
15 elif id == constants.EVT_GATTS_WRITE:
16 LED(1).on() if int(data[0]) else LED(1).off()
17
18# start off with LED(1) off
19LED(1).off()
20
21notif_enabled = False
22uuid_service = UUID("0x1523")
23uuid_led = UUID("0x1525")
24
25service = Service(uuid_service)
26char_led = Characteristic(uuid_led, props=Characteristic.PROP_WRITE)
27service.addCharacteristic(char_led)
28
29periph = Peripheral()
30periph.addService(service)
31periph.setConnectionHandler(event_handler)
32periph.advertise(device_name="Nano 33 BLE", services=[service])
33
34while (True):
35 time.sleep_ms(500)

Nano 33 BLE Sense

Nano 33 BLE Sense.
Nano 33 BLE Sense.

Pin Map

The pinout for the Nano 33 BLE Sense and the NRF52840 microcontroller varies greatly. For example, if we are to use

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

1# Defining "D2" on the Nano 33 BLE Sense
2p0 = Pin(43, Pin.OUT)

In the MicroPython port of the Nano 33 BLE Sense board, the pinout is the same as the Nordic NRF52840 (the microcontroller). You will find a pin map below this section that explains how to address the different pins.

ArduinonRF52840
TX35
RX42
D243
D344
D447
D545
D646
D723
D821
D927
D1034
D1133
D1240
D1313
D14/A04
D15/A15
D16/A230
D17/A329
D18/A431
D19/A52
D20/A628
D21/A73

LED Control

There are 3 different LEDs that can be accessed on the Nano 33 BLE Sense: RGB, the built-in LED and the power LED.

They can be accessed by importing the

LED
module, where the RGB and built-in LED can be accessed.

1from board import LED
2
3led_red = LED(1) # red LED
4led_green = LED(2) # green LED
5led_blue = LED(3) # blue LED
6led_builtin = LED(4) # classic built-in LED (also accessible through pin 13)

To access the power LED we need to import the

Pin
module.

1from machine import Pin
2
3led_pwr = Pin(41, Pin.OUT)

RGB

Blink all RGB lights every 0.25 seconds.

1from board import LED
2import time
3
4led_red = LED(1)
5led_green = LED(2)
6led_blue = LED(3)
7
8while (True):
9
10 # Turn on LEDs
11 led_red.on()
12 led_green.on()
13 led_blue.on()
14
15 # Wait 0.25 seconds
16 time.sleep_ms(250)
17
18 # Turn off LEDs
19 led_red.off()
20 led_green.off()
21 led_blue.off()
22
23 # Wait 0.25 seconds
24 time.sleep_ms(250)

Built-in LED

The classic blink example! Blink the built-in LED every 0.25 seconds.

1from board import LED
2import time
3
4led_builtin = LED(4)
5
6while (True):
7
8 # Turn on LED
9 led_builtin.on()
10
11 # Wait 0.25 seconds
12 time.sleep_ms(250)
13
14 # Turn off LED
15 led_builtin.off()
16
17 # Wait 0.25 seconds
18 time.sleep_ms(250)

Sensors

There are several sensors onboard the Nano 33 BLE Sense. The scripts below can be used to access the data from each of them.

IMU (LSM9DS1, BMI270 + BMM150)

Access the

accelerometer
,
magnetometer
, and
gyroscope
data from the IMU module.

1import time
2import imu
3from machine import Pin, I2C
4
5bus = I2C(1, scl=Pin(15), sda=Pin(14))
6imu = imu.IMU(bus)
7
8while (True):
9 print('Accelerometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*imu.accel()))
10 print('Gyroscope: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*imu.gyro()))
11 print('Magnetometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*imu.magnet()))
12 print("")
13 time.sleep_ms(100)

Temperature & Humidity (HTS221)

Access the

temperature
&
humidity
values from the HTS221 sensor.

1import time
2import hts221
3from machine import Pin, I2C
4
5bus = I2C(1, scl=Pin(15), sda=Pin(14))
6hts = hts221.HTS221(bus)
7
8while (True):
9 rH = hts.humidity()
10 temp = hts.temperature()
11 print ("rH: %.2f%% T: %.2fC" %(rH, temp))
12 time.sleep_ms(100)

Pressure (LPS22)

Access the

pressure
values from the LPS22 sensor.

1import time
2import lps22h
3from machine import Pin, I2C
4
5bus = I2C(1, scl=Pin(15), sda=Pin(14))
6lps = lps22h.LPS22H(bus)
7
8while (True):
9 pressure = lps.pressure()
10 temperature = lps.temperature()
11 print("Pressure: %.2f hPa Temperature: %.2f C"%(pressure, temperature))
12 time.sleep_ms(100)

Ambient Light (APDS9960)

Access the

Ambient Light
values from the APDS9960 sensor.

1from time import sleep_ms
2from machine import Pin, I2C
3from apds9960.const import *
4from apds9960 import uAPDS9960 as APDS9960
5
6bus = I2C(1, sda=Pin(13), scl=Pin(14))
7apds = APDS9960(bus)
8
9print("Light Sensor Test")
10print("=================")
11apds.enableLightSensor()
12
13while True:
14 sleep_ms(250)
15 val = apds.readAmbientLight()
16 print("AmbientLight={}".format(val))

Proximity (APDS9960)

Access the

Proximity values
from the APDS9960 sensor.

1from time import sleep_ms
2from machine import Pin, I2C
3
4from apds9960.const import *
5from apds9960 import uAPDS9960 as APDS9960
6
7bus = I2C(1, sda=Pin(13), scl=Pin(14))
8apds = APDS9960(bus)
9
10apds.setProximityIntLowThreshold(50)
11
12print("Proximity Sensor Test")
13print("=====================")
14apds.enableProximitySensor()
15
16while True:
17 sleep_ms(250)
18 val = apds.readProximity()
19 print("proximity={}".format(val))

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

Wireless

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 33 BLE Sense" in the list of available devices. You need to pair in order to control the built-in LED.

1# Use nRF Connect from App store, connect to the Nano and write 1/0 to control the LED.
2
3import time
4from board import LED
5from ubluepy import Service, Characteristic, UUID, Peripheral, constants
6
7def event_handler(id, handle, data):
8 global periph
9 global service
10 if id == constants.EVT_GAP_CONNECTED:
11 pass
12 elif id == constants.EVT_GAP_DISCONNECTED:
13 # restart advertisement
14 periph.advertise(device_name="Nano 33 BLE Sense", services=[service])
15 elif id == constants.EVT_GATTS_WRITE:
16 LED(1).on() if int(data[0]) else LED(1).off()
17
18# start off with LED(1) off
19LED(1).off()
20
21notif_enabled = False
22uuid_service = UUID("0x1523")
23uuid_led = UUID("0x1525")
24
25service = Service(uuid_service)
26char_led = Characteristic(uuid_led, props=Characteristic.PROP_WRITE)
27service.addCharacteristic(char_led)
28
29periph = Peripheral()
30periph.addService(service)
31periph.setConnectionHandler(event_handler)
32periph.advertise(device_name="Nano 33 BLE Sense", services=[service])
33
34while (True):
35 time.sleep_ms(500)

Portenta H7

Portenta H7.
Portenta H7.

Note that the Portenta H7 Lite and Portenta H7 Lite Connected boards are compatible with most examples listed here, as they are variations of the Portenta H7.

GPIO Map

Most of the pins are referred to via their port name or their function. Please refer to the list below to see which function corresponds to which port on the Portenta H7.

ArduinoSTM32H747
PA0PA0
PA1PA1
PA2PA2
PA3PA3
PA4PA4
PA5PA5
PA6PA6
PA7PA7
PA8PA8
PA9PA9
PA10PA10
PA11PA11
PA12PA12
PA13PA13
PA14PA14
PA15PA15
PB0PB0
PB1PB1
PB2PB2
PB3PB3
PB4PB4
PB5PB5
PB6PB6
PB7PB7
PB8PB8
PB9PB9
PB10PB10
PB11PB11
PB12PB12
PB13PB13
PB14PB14
PB15PB15
PC0PC0
PC1PC1
PC2PC2
PC3PC3
PC4PC4
PC5PC5
PC6PC6
PC7PC7
PC8PC8
PC9PC9
PC10PC10
PC11PC11
PC12PC12
PC13PC13
PC14PC14
PC15PC15
PD0PD0
PD1PD1
PD2PD2
PD3PD3
PD4PD4
PD5PD5
PD6PD6
PD7PD7
PD8PD8
PD9PD9
PD10PD10
PD11PD11
PD12PD12
PD13PD13
PD14PD14
PD15PD15
PE0PE0
PE1PE1
PE2PE2
PE3PE3
PE4PE4
PE5PE5
PE6PE6
PE7PE7
PE8PE8
PE9PE9
PE10PE10
PE11PE11
PE12PE12
PE13PE13
PE14PE14
PE15PE15
PF0PF0
PF1PF1
PF2PF2
PF3PF3
PF4PF4
PF5PF5
PF6PF6
PF7PF7
PF8PF8
PF9PF9
PF10PF10
PF11PF11
PF12PF12
PF13PF13
PF14PF14
PF15PF15
PG0PG0
PG1PG1
PG2PG2
PG3PG3
PG4PG4
PG5PG5
PG6PG6
PG7PG7
PG8PG8
PG9PG9
PG10PG10
PG11PG11
PG12PG12
PG13PG13
PG14PG14
PG15PG15
PH0PH0
PH1PH1
PH2PH2
PH3PH3
PH4PH4
PH5PH5
PH6PH6
PH7PH7
PH8PH8
PH9PH9
PH10PH10
PH11PH11
PH12PH12
PH13PH13
PH14PH14
PH15PH15
PI0PI0
PI1PI1
PI2PI2
PI3PI3
PI4PI4
PI5PI5
PI6PI6
PI7PI7
PI8PI8
PI9PI9
PI10PI10
PI11PI11
PI12PI12
PI13PI13
PI14PI14
PI15PI15
PJ0PJ0
PJ1PJ1
PJ2PJ2
PJ3PJ3
PJ4PJ4
PJ5PJ5
PJ6PJ6
PJ7PJ7
PJ8PJ8
PJ9PJ9
PJ10PJ10
PJ11PJ11
PJ12PJ12
PJ13PJ13
PJ14PJ14
PJ15PJ15
PK0PK0
PK1PK1
PK2PK2
PK3PK3
PK4PK4
PK5PK5
PK6PK6
PK7PK7
UART1_TXPA9
UART1_RXPA10
UART4_TXPA0
UART4_RXPI9
UART6_TXPG14
UART6_RXPG9
UART8_TXPJ8
UART8_RXPJ9
ETH_RMII_REF_CLKPA1
ETH_MDIOPA2
ETH_RMII_CRS_DVPA7
ETH_MDCPC1
ETH_RMII_RXD0PC4
ETH_RMII_RXD1PC5
ETH_RMII_TX_ENPG11
ETH_RMII_TXD0PG13
ETH_RMII_TXD1PG12
USB_HS_CLKPA5
USB_HS_STPPC0
USB_HS_NXTPH4
USB_HS_DIRPI11
USB_HS_D0PA3
USB_HS_D1PB0
USB_HS_D2PB1
USB_HS_D3PB10
USB_HS_D4PB11
USB_HS_D5PB12
USB_HS_D6PB13
USB_HS_D7PB5
USB_HS_RSTPJ4
USB_DMPA11
USB_DPPA12
BOOT0BOOT0
DAC1PA4
DAC2PA5
LEDRPK5
LEDGPK6
LEDBPK7
I2C1_SDAPB7
I2C1_SCLPB6
I2C3_SDAPH8
I2C3_SCLPH7
-WL_REG_ONPJ1
-WL_HOST_WAKEPJ5
-WL_SDIO_0PC8
-WL_SDIO_1PC9
-WL_SDIO_2PC10
-WL_SDIO_3PC11
-WL_SDIO_CMDPD2
-WL_SDIO_CLKPC12
-BT_RXDPF6
-BT_TXDPA15
-BT_CTSPF9
-BT_RTSPF8
-BT_REG_ONPJ12
-BT_HOST_WAKEPJ13
-BT_DEV_WAKEPJ14
-QSPI2_CSPG6
-QSPI2_CLKPF10
-QSPI2_D0PD11
-QSPI2_D1PD12
-QSPI2_D2PF7
-QSPI2_D3PD13

I/O Pins

To access the I/O pins, you can use the

Pin
module from the
pyb
library.

1from pyb import Pin

To reference a pin on the Portenta, you can use the

Pin()
constructor. The first argument you have to provide is the pin you want to use. The second parameter,
mode
, can be set as:
Pin.IN
,
Pin.OUT_PP
,
Pin.OUT_OD
,
Pin.AF_PP
,
Pin.AF_OD
or
Pin.ANALOG
. An explanation of the pin modes can be found here. The third parameter,
pull
, represents the pull mode. It can be set to:
Pin.PULL_NONE
,
Pin.PULL_UP
or
Pin.PULL_DOWN
. E.g.:

1pin0 = Pin('P0', mode, pull)

To get the logic level of a pin, call

.value()
. It will return a 0 or a 1. This corresponds to
LOW
and
HIGH
in Arduino terminology.

1pin0.value()

PWM

To use PWM, you import the

pyb
,
time
,
Pin
,
Timer
modules.

1import pyb
2import time
3from pyb import Pin, Timer

First you need to choose the pin you want to use PWM with.

1pin1 = Pin("PC6", Pin.OUT_PP, Pin.PULL_NONE)

Create a timer for the PWM, where you set the ID and the frequency.

1timer1 = Timer(3, freq=1000)

Then you need to start a PWM channel with the timer object.

1channel1 = timer1.channel(1, Timer.PWM, pin=pin1, pulse_width=0)

Get or set the pulse width value on a channel. To get, pass no arguments. To set, give a value as an argument.

1channel1.pulse_width(Width)

RGB LED

The Portenta H7 has built-in RGB that can be used as feedback for applications. Using the

pyb
library, you can easily define the different LED colors on the Portenta.

For this you will use the

pyb
library.

1import pyb

Now you can easily define the different colors of the built in LED.

1redLED = pyb.LED(1)
2greenLED = pyb.LED(2)
3blueLED = pyb.LED(3)

And then control them in our script.

1redLED.on()
2redLED.off()
3
4greenLED.on()
5greenLED.off()
6
7blueLED.on()
8blueLED.off()

You could also set a custom intensity for our LED lights. This ranges between the values 0 (off) and 255 (full on). Below you can see an example of how to set the intensity on our different LED lights.

1redLED.intensity(128)
2greenLED.intensity(64)
3blueLED.intensity(50)

If no argument is given in the

.intensity()
function, it will return the LED intensity.

Communication

Like other Arduino® products, the Portenta H7 features dedicated pins for different protocols.

SPI

The pins used for SPI on the Portenta H7 are the following:

PinFunction
PI0CS
PC3COPI
PI1CK
PC2CIPO

You can refer to the pinout above to find them on the board.

First, you have to import the relevant module from

pyb
.

1from pyb import SPI

When you initialize SPI, the only thing you need to state is the bus, which will always be

2
on the Portenta H7; this is the only available bus. The rest of the arguments are optional. But if it is needed, you can state the mode of the SPI device as either
SPI.MASTER
or
SPI.SLAVE
, you can also manually set the
baudrate
of the device.
Polarity
can be set to 0 or 1, and is the logic level the idle clock line sits at (HIGH or LOW).
Phase
can be 0 or 1 to sample data on the first (0) or second (1) clock edge.

1spi = SPI(2, SPI.MASTER, baudrate=100000, polarity=0, phase=0)

Now, if you want to send data over SPI, you simply call

.send()
inside the arguments you want to send.
data
is the data to send, which could be an integer (dataInt) or a buffer object (dataBuffer). It is optional to set the
timeout
, it indicates the timeout in milliseconds to wait for the send.

1dataInt = 21
2dataBuffer = bytearray(4)
3spi.send(data, timeout=5000)

Similarly, if you want to receive data over SPI, you call

.recv()
.
data
indicates the number of bytes to receive, this can be an integer (dataInt) or a buffer (dataBuffer), which will be filled with received bytes. It is optional to set the
timeout
, which is the time in milliseconds to wait for the receive.

1dataInt = 0
2dataBuffer = bytearray(4)
3SPI.recv(data, timeout=5000)

I2C

The pins used for I2C (Inter-Integrated Circuit) on the Portenta H7 are the following:

PinFunction
PH8SDA
PH7SCL

You can refer to the pinout above to find them on the board.

To use the I2C, you import the relevant module.

1from pyb import I2C

You can now create the I2C object. To create an I2C object you need to state the bus, this indicates what pins you will use for I2C. Giving bus a value of

3
starts I2C on the SCL and SDA pins on the Portenta H7. There are 4 I2C buses on the Portenta H7.

1i2c = I2C(3)

Now that the object is created, you can initialize it. You need to decide if your device is going to be a controller (I2C.MASTER) or a reader (I2C.SLAVE). If it is a reader device, you also need to set the

address
. You can then set a baudrate if you need to.

1i2c.init(I2C.MASTER, addr=address, baudrate=100000)

To receive data on the bus, you call the

.recv()
function. In the functions arguments
data
is the number of bytes to receive, it can be an integer (dataInt) or a buffer (dataBuffer), which will be filled with received bytes.
addr
is the address to receive from, this is only required in controller mode.
timeout
indicates how many milliseconds to wait for the receive. The code below shows how to receive and print your data in the OpenMV serial terminal.

1dataInt = 0
2dataBuffer = bytearray(4)
3receivedData = i2c.recv(data, addr=0, timeout=5000)
4Print(receivedData)

To send data on the bus, you can call the

.send()
function. In the functions arguments
data
is the data to send, an integer (dataInt) or a buffer object (dataBuffer).
addr
is the address to send to, this is only required in controller mode.
timeout
indicates how many milliseconds to wait for the send.

1dataInt = 412
2dataBuffer = bytearray(4)
3i2c.send(data, addr=0, timeout=5000)

If you need to make sure that devices are connected to the I2C bus, you can use the

.scan()
function. It will scan all I2C addresses from 0x01 to 0x7f and return a list of those that respond. It only works when in controller mode.

1i2c.scan()

UART

The pins used for UART on the Portenta H7 are the following:

PinFunction
PA10RX
PA9TX

You can refer to the pinout above to find them on the board.

To use the UART, you need to import the relevant module.

1from pyb import UART

To create the UART object, you need to indicate the UART bus, the Portenta has 3 UART buses, but there is only on UART bus available to use with OpenMV through the boards pins.

1uart = UART(1)

With the object created, you can initialize it with

init
. When initilazing, you can set the
baudrate
.
bits
is the number of bits per character (7, 8 or 9).
parity
can be set to
None
,
0
(even) or
1
(odd).
stop
is the number of stop bits, 1 or 2.
flow
sets the flow control type, can be 0, UART.RTS, UART.CTS or UART.RTS | UART.CTS. More information on this can be found here.
timeout
is the time in milliseconds to wait for writing/reading the first character.
timeout_char
is the timeout in milliseconds to wait between characters while writing or reading.
read_buf_len
is the character length of the read buffer (0 to disable).

1uart.init(baudrate, bits=8, parity=None, stop=1, timeout=0, flow=0, timeout_char=0, read_buf_len=64)

To read from UART, you can call

.read()
. If
bytes
is specified then read at most that many bytes. If
bytes
is not given then the method reads as much data as possible. It returns after the timeout has elapsed. The example code below will read bytes received through uart into an array and then print it in the serial terminal.

1array = bytearray(5)
2uart.read(array)
3print(array)

If you intend to write over UART, you can call

.write()
. The function writes
buffer
of bytes to the bus. If characters are 7 or 8 bits wide then each byte is one character. If characters are 9 bits wide then two bytes are used for each character and
buffer
must contain an even number of bytes.

1uart.write(buffer)

Wi-Fi®

To use Wi-Fi® you first need to import the relevant library.

1import network

Then you need to define the Wi-Fi® networks SSID and put that in a variable. You must do the same for the networks password.

1SSID=''
2PASSWORD=''

Next, you can create a WLAN network interface object. In the argument you can enter

network.STA_IF
, which indicates that your device will be a client and connect to a Wi-Fi® access point.

1wlan = network.WLAN(network.STA_IF)

To activate the network interface, you can simply call

.activate
with the argument
True
.

1wlan.active(True)

Now you can decide which network to connect to. Here it is where the

SSID
and
PASSWORD
variables come in handy.

1wlan.connect(SSID, PASSWORD, timeout=30000)

If you need to troubleshoot, the connection

.status()
can be used. This function will return a value that describes the connection status. It will also let you know what went wrong with the connection in case it failed.

1wlan.status()

Audio

If you want to use audio with the Portenta H7, you first need to include the

audio
module. Another helpful module is
micro_speech
, this runs Google's TensorFlow Lite for Microcontrollers Micro Speech framework for voice recognition.

1import audio, micro_speech

Next you need to initialize the audio object. In the initialization you can decide how many

channels
to use, it is possible to use either 1 or 2 channels. Frequency decides the sample frequency. Using a higher sample frequency results in a higher noise flow, meaning less effective bits per sample. By default audio samples are 8-bits with 7-bits of effective dynamic range.
gain_db
sets the microphone gain to use.
highpass
is the high pass filter cut off given the target sample frequency.

1audio.init(channels=2, frequency=16000, gain_db=24, highpass=0.9883)

If you need to deinitialize the audio object, you can simply call

deint()
.

1audio.deint()

To use micro_speech, you first need to create a micro_speech object. You can create this object in the variable

speech
.

1speech = micro_speech.MicroSpeech()

Next you can start streaming audio into the

micro_speech
object, to do this you can call
audio.start_streaming()
. Here you can pass the
micro_speech
object as the argument, this will fill the object with audio samples. The MicroSpeech module will compute the FFT of the audio samples and keep a sliding window internally of the FFT the last 100ms or so of audio samples received as features for voice recognition.

1audio.start_streaming(speech.audio_callback)

If you need to stop the audio streaming, you can call

.stop_streaming()
.

1audio.stop_streaming()

Portenta C33

Pinout Mapping

The Portenta C33 has two ways its pins are physically available: through its MKR-styled connectors and its High-Density connectors. Most pins are referred to via their port name or function. In the image below, the Portenta C33 MKR-styled connectors pinout is shown.

Portenta C33 MKR-styled connectors pinout
Portenta C33 MKR-styled connectors pinout

The MKR-styled connectors pinout is mapped in MicroPython as follows:

Arduino Pin MappingMicroPython Pin Mapping
P006
/
A0
P006
P005
/
A1
P005
P004
/
A2
P004
P002
/
A3
P002
P001
/
A4
P001
P015
/
A5
P015
P014
/
A6
P014
P105
/
D0
P105
P106
/
D1
P106
P111
/
D2
P111
P303
/
D3
P303
P401
/
D4
P401
P210
/
D5
P210
P602
P602
P110
P110
P408
P408
P407
P407
P315
P315
P204
P204
P900
P900
P402
P402
P601
P601

The complete MicroPython pinout is available here.

Input/Output Pins

The

Pin
class in the
machine
module is essential for controlling Input/Output (I/O) pins of the Portenta C33 board. These pins are crucial for a wide range of applications, including reading sensor data, controlling actuators, and interfacing with other hardware components.

Pin Initialization

To begin using an I/O pin of the Portenta C33 board with MicroPython, you need to initialize it using the

Pin
class from the
machine
module. This involves specifying the pin identifier and its mode (input, output, etc.).

1from machine import Pin
2
3# Initializing pin P107 as an output
4p107 = Pin('P107', Pin.OUT)

Configuring Pin Modes

You can configure a pin as an input or output. For input pins, it's often useful to activate an internal pull-up or pull-down resistor. This helps to stabilize the input signal, especially in cases where the pin is reading a mechanical switch or a button.

1# Configuring pin P105 as an input with its pull-up resistor enabled
2p105 = Pin('P105', Pin.IN, Pin.PULL_UP)

Reading from and Writing to Pins

To read a digital value from a pin, use the

.value()
method without any arguments. This is particularly useful for input pins. Conversely, to write a digital value, use the
.value()
method with an argument. Passing
1
sets the pin to
HIGH
, while
0
sets it to
LOW
. This is applicable to output pins.

1# Reading from P105
2pin_value = p105.value()
3
4# Writing to P107
5p107.value(1) # Set p2 to high

Advanced Pin Configuration

The Pin class allows dynamic reconfiguration of pins and setting up interrupt callbacks. This feature is essential for creating responsive and interactive applications.

1# Reconfiguring P105 as an input with a pull-down resistor
2p105.init(Pin.IN, Pin.PULL_DOWN)
3
4# Setting up an interrupt on P105
5p105.irq(lambda p: print("- IRQ triggered!", p))

Practical Example

In this example, we will configure one pin as an input to read the state of a button and another pin as an output to control an LED. The LED will turn on when the button is pressed and off when it's released.

1from machine import Pin
2import time
3
4# Configure pin P107 as an output (for the LED)
5led = Pin('P107', Pin.OUT_PP)
6
7# Configure pin P105 as input with pull-up resistor enabled (for the button)
8button = Pin('P105', Pin.IN, Pin.PULL_UP)
9
10while True:
11 # Read the state of the button
12 button_state = button.value()
13 if button_state == 0:
14 # Turn on LED if button is pressed (button_state is LOW)
15 led.value(1)
16 else:
17 # Turn off LED if button is not pressed (button_state is HIGH)
18 led.value(0)
19
20 # Short delay to debounce the button
21 time.sleep(0.1)

This practical example demonstrates controlling an LED based on a button's state. The LED, connected to pin

P107
(configured as an output), is turned on or off depending on the button's input read from pin
P105
(set as an input with a pull-up resistor). The main loop continually checks the button's state; pressing the button fixes the LED on while releasing it turns the LED off. A brief delay is included for debouncing, ensuring stable operation without false triggers from the button.

Analog to Digital Converter

The

ADC
class in MicroPython provides an interface for the Analog-to-Digital (ADC) converter of the Portenta C33 board, enabling the measurement of continuous voltages and their conversion into discrete digital values. This functionality is crucial for applications that, for example, require reading from analog sensors. The
ADC
class represents a single endpoint for sampling voltage from an analog pin and converting it to a digital value.

The available ADC pins of the Portenta C33 board in MicroPython are the following:

Available ADC Pins
P006
P005
P004
P002
P001
P015
P014
P000

Initializing the ADC

First, to use an ADC of the Portenta C33 board, create an ADC object associated with a specific pin. This pin will be used to read analog values.

1from machine import ADC
2
3# Create an ADC object on a specific pin
4adc = ADC(pin)

Reading Analog Values

You can read analog values as raw values using the

read_u16()
method. This method returns a raw integer from 0-65535, representing the analog reading.

1# Reading a raw analog value
2val = adc.read_u16()

Practical Example

This example demonstrates the use of the

ADC
class to read values from a potentiometer on the Portenta C33 board. First, connect your potentiometer to the Portenta C33 board. One outer pin goes to
GND
, the other to
3V3
, and the middle pin to an analog-capable I/O pin, such as
P006
. This setup creates a variable voltage divider, with the voltage at the center pin changing as you adjust the potentiometer.

1from machine import ADC, Pin
2import time
3
4# Initialize the ADC on the potentiometer-connected pin
5pot_pin = Pin('P006')
6pot_adc = ADC(pot_pin)
7
8while True:
9 # Read the raw analog value
10 raw_value = pot_adc.read_u16()
11 print("- Potentiometer raw value:", raw_value)
12
13 # Delay for readability
14 time.sleep(0.1)

The example starts by importing the necessary modules and setting up the ADC on a pin connected to a potentiometer (

P006
). The ADC object (
pot_adc
) is used to interface with the potentiometer. Inside the loop, the analog value from the potentiometer is continuously read using the
read_u16()
method that provides a raw integer value scaled between
0
and
65535
, reflecting the potentiometer's position. The analog value value is printed to the console, and a short delay is included in the loop to ensure the output is readable.

Pulse Width Modulation

Pulse Width Modulation (PWM) is a method to emulate an analog output using a digital pin. It does this by rapidly toggling the pin between low and high states. Two primary aspects define PWM behavior:

  • Frequency: This is the speed at which the pin toggles between low and high states. A higher frequency means the pin toggles faster.
  • Duty cycle: This refers to the ratio of the high state duration to the total cycle duration. A 100% duty cycle means the pin remains high all the time, while a 0% duty cycle means it stays low.

The available PWM pins of the Portenta C33 board in MicroPython are the following:

Available PWM Pins
P105
P106
P111
P303
P401
P601

Setting Up PWM

To use PWM, start by initializing a pin and then creating a PWM object associated with that pin.

1import machine
2
3# Initialize a pin for PWM (e.g., pin P105)
4p105 = machine.Pin('P105')
5pwm1 = machine.PWM(p105)

Configuring PWM Parameters

The frequency and duty cycle of the PWM signal are set based on the specific needs of your application:

1# Set the frequency to 500 Hz
2pwm1.freq(500)
3
4# Adjusting the duty cycle to 50 for 50% duty
5pwm1.duty(50)

Checking PWM Configuration

You can check the current configuration of the PWM object by printing it:

1# Will show the current frequency and duty cycle
2print(pwm1)

Retrieve the frequency and duty cycle values:

1current_freq = pwm1.freq()
2current_duty = pwm1.duty()

Deinitializing PWM

When PWM is no longer needed, the pin can be deinitialized:

1pwm1.deinit()

Practical Example

In this example, we will use PWM to control the brightness of an LED connected to pin

P105
of the Portenta C33 board.

1import machine
2import time
3
4# Configure the LED pin and PWM
5led_pin = machine.Pin('P105')
6led_pwm = machine.PWM(led_pin)
7led_pwm.freq(500)
8
9# Loop to vary brightness
10while True:
11 # Increase brightness
12 for duty in range(100):
13 led_pwm.duty(duty)
14 time.sleep(0.001)
15
16 # Decrease brightness
17 for duty in range(100, -1, -1):
18 led_pwm.duty(duty)
19 time.sleep(0.001)

Real-Time Clock

The

RTC
class in MicroPython provides a way to manage and utilize the Real-Time Clock (RTC) of the Portenta C33 board. This feature is essential for applications that require accurate timekeeping, even when the main processor is not active. The RTC maintains accurate time and date, functioning independently from the main system. It continues to keep track of the time even when the board is powered off, as long as it's connected to a power source like a battery.

Initializing the RTC

To use the RTC, first create an RTC object. This object is then used to set or read the current date and time.

1import machine
2
3# Create an RTC object
4rtc = machine.RTC()

Setting and Getting Date and Time

The RTC allows you to set and retrieve the current date and time. The date and time are represented as an 8-tuple format.

1# Setting the RTC date and time
2rtc.datetime((2024, 1, 4, 4, 20, 0, 0, 0))
3
4# Getting the current date and time
5current_datetime = rtc.datetime()
6print("- Current date and time:", current_datetime)

The 8-tuple for the date and time follows the format

(year, month, day, weekday, hours, minutes, seconds, subseconds)
.

Practical Example

A practical use case for the RTC is to add timestamps to sensor data readings. By setting the current time on the RTC, you can then append an accurate timestamp each time a sensor value is logged.

1import machine
2
3# Initialize the RTC and set the current datetime
4rtc.datetime((2024, 1, 4, 4, 20, 0, 0, 0))
5
6# Function to read a sensor value (placeholder)
7def read_sensor():
8 # Replace with actual sensor reading logic
9 return 42
10
11# Read sensor value and get the current time
12sensor_value = read_sensor()
13timestamp = rtc.datetime()
14
15# Output the sensor value with its timestamp
16print("- Sensor value at ", timestamp, ":", sensor_value)

In this example, every sensor reading is accompanied by a timestamp, which can be crucial for data analysis or logging purposes. The RTC's ability to maintain time independently of the main system's power status makes it reliable for time-sensitive applications.

Suggest changes

The content on docs.arduino.cc is facilitated through a public GitHub repository. If you see anything wrong, you can edit this page here.

License

The Arduino documentation is licensed under the Creative Commons Attribution-Share Alike 4.0 license.