8000 RP2: Add support for Arduino Nano RP2040. · micropython/micropython@40ff4f7 · GitHub
[go: up one dir, main page]

Skip to content

Commit 40ff4f7

Browse files
committed
RP2: Add support for Arduino Nano RP2040.
1 parent 3745c39 commit 40ff4f7

File tree

7 files changed

+368
-0
lines changed

7 files changed

+368
-0
lines changed

drivers/lsm6dsox/lsm6dsox.py

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
"""
2+
LSM6DSOX STMicro driver for MicroPython based on LSM9DS1:
3+
Source repo: https://github.com/hoihu/projects/tree/master/raspi-hat
4+
5+
The MIT License (MIT)
6+
7+
Copyright (c) 2021 Damien P. George
8+
Copyright (c) 2021 Ibrahim Abdelkader <iabdalkader@openmv.io>
9+
10+
Permission is hereby granted, free of charge, to any person obtaining a copy
11+
of this software and associated documentation files (the "Software"), to deal
12+
in the Software without restriction, including without limitation the rights
13+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14+
copies of the Software, and to permit persons to whom the Software is
15+
furnished to do so, subject to the following conditions:
16+
17+
The above copyright notice and this permission notice shall be included in
18+
all copies or substantial portions of the Software.
19+
20+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26+
THE SOFTWARE.
27+
28+
Basic example usage:
29+
30+
import time
31+
from lsm6dsox import LSM6DSOX
32+
33+
from machine import Pin, I2C
34+
lsm = LSM6DSOX(I2C(0, scl=Pin(13), sda=Pin(12)))
35+
36+
while (True):
37+
print('Accelerometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*lsm.read_accel()))
38+
print('Gyroscope: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*lsm.read_gyro()))
39+
print("")
40+
time.sleep_ms(100)
41+
"""
42+
import array
43+
44+
45+
class LSM6DSOX:
46+
CTRL3_C = const(0x12)
47+
CTRL1_XL = const(0x10)
48+
CTRL8_XL = const(0x17)
49+
CTRL9_XL = const(0x18)
50+
51+
CTRL2_G = const(0x11)
52+
CTRL7_G = const(0x16)
53+
54+
OUTX_L_G = const(0x22)
55+
OUTX_L_XL = const(0x28)
56+
MLC_STATUS = const(0x38)
57+
58+
DEFAULT_ADDR = const(0x6A)
59+
WHO_AM_I_REG = const(0x0F)
60+
61+
FUNC_CFG_ACCESS = const(0x01)
62+
FUNC_CFG_BANK_USER = const(0)
63+
FUNC_CFG_BANK_HUB = const(1)
64+
FUNC_CFG_BANK_EMBED = const(2)
65+
66+
MLC0_SRC = const(0x70)
67+
MLC_INT1 = const(0x0D)
68+
TAP_CFG0 = const(0x56)
69+
70+
EMB_FUNC_EN_A = const(0x04)
71+
EMB_FUNC_EN_B = const(0x05)
72+
73+
def __init__(
74+
self,
75+
i2c,
76+
address=DEFAULT_ADDR,
77+
gyro_odr=104,
78+
accel_odr=104,
79+
gyro_scale=2000,
80+
accel_scale=4,
81+
ucf=None,
82+
):
83+
"""Initalizes Gyro and Accelerator.
84+
accel_odr: (0, 1.6Hz, 3.33Hz, 6.66Hz, 12.5Hz, 26Hz, 52Hz, 104Hz, 208Hz, 416Hz, 888Hz)
85+
gyro_odr: (0, 1.6Hz, 3.33Hz, 6.66Hz, 12.5Hz, 26Hz, 52Hz, 104Hz, 208Hz, 416Hz, 888Hz)
86+
gyro_scale: (245dps, 500dps, 1000dps, 2000dps)
87+
accel_scale: (+/-2g, +/-4g, +/-8g, +-16g)
88+
ucf: MLC program to load.
89+
"""
90+
self.i2c = i2c
91+
self.address = address
92+
93+
# check the id of the Accelerometer/Gyro
94+
if self.__read_reg(WHO_AM_I_REG) != 108:
95+
raise OSError("No LSM6DS device was found at address 0x%x" % (self.address))
96+
97+
# allocate scratch buffer for efficient conversions and memread op's
98+
self.scratch_int = array.array("h", [0, 0, 0])
99+
100+
SCALE_GYRO = {250: 0, 500: 1, 1000: 2, 2000: 3}
101+
SCALE_ACCEL = {2: 0, 4: 2, 8: 3, 16: 1}
102+
# XL_HM_MODE = 0 by default. G_HM_MODE = 0 by default.
103+
ODR = {
104+
0: 0x00,
105+
1.6: 0x08,
106+
3.33: 0x09,
107+
6.66: 0x0A,
108+
12.5: 0x01,
109+
26: 0x02,
110+
52: 0x03,
111+
104: 0x04,
112+
208: 0x05,
113+
416: 0x06,
114+
888: 0x07,
115+
}
116+
117+
gyro_odr = round(gyro_odr, 2)
118+
accel_odr = round(accel_odr, 2)
119+
assert gyro_odr in ODR, "Invalid sampling rate: %d" % accel_odr
120+
assert gyro_scale in SCALE_GYRO, "invalid gyro scaling: %d" % gyro_scale
121+
122+
assert accel_odr in ODR, "Invalid sampling rate: %d" % accel_odr
123+
assert accel_scale in SCALE_ACCEL, "invalid accelerometer scaling: %d" % accel_scale
124+
125+
# Soft-reset the device.
126+
self.reset()
127+
128+
# Load and configure MLC if UCF file is provided
129+
if ucf != None:
130+
self.load_mlc(ucf)
131+
132+
# Set Gyroscope datarate and scale.
133+
# Note output from LPF2 second filtering stage is selected. See Figure 18.
134+
self.__write_reg(CTRL1_XL, (ODR[accel_odr] << 4) | (SCALE_ACCEL[accel_scale] << 2) | 2)
135+
136+
# Enable LPF2 and HPF fast-settling mode, ODR/4
137+
self.__write_reg(CTRL8_XL, 0x09)
138+
139+
# Set Gyroscope datarate and scale.
140+
self.__write_reg(CTRL2_G, (ODR[gyro_odr] << 4) | (SCALE_GYRO[gyro_scale] << 2) | 0)
141+
142+
self.gyro_scale = 32768 / gyro_scale
143+
self.accel_scale = 32768 / accel_scale
144+
145+
def __read_reg(self, reg, size=1):
146+
buf = self.i2c.readfrom_mem(self.address, reg, size)
147+
if size == 1:
148+
return int(buf[0])
149+
return [int(x) for x in buf]
150+
151+
def __write_reg(self, reg, val):
152+
self.i2c.writeto_mem(self.address, reg, bytes([val]))
153+
154+
def reset(self):
155+
self.__write_reg(CTRL3_C, self.__read_reg(CTRL3_C) | 0x1)
156+
for i in range(0, 10):
157+
if (self.__read_reg(CTRL3_C) & 0x01) == 0:
158+
return
159+
time.sleep_ms(10)
160+
raise OSError("Failed to reset LSM6DS device.")
161+
162+
def set_mem_bank(self, bank):
163+
cfg = self.__read_reg(FUNC_CFG_ACCESS) & 0x3F
164+
self.__write_reg(FUNC_CFG_ACCESS, cfg | (bank << 6))
165+
166+
def set_embedded_functions(self, enable, emb_ab=None):
167+
self.set_mem_bank(FUNC_CFG_BANK_EMBED)
168+
if enable:
169+
self.__write_reg(EMB_FUNC_EN_A, emb_ab[0])
170+
self.__write_reg(EMB_FUNC_EN_B, emb_ab[1])
171+
else:
172+
emb_a = self.__read_reg(EMB_FUNC_EN_A)
173+
emb_b = self.__read_reg(EMB_FUNC_EN_B)
174+
self.__write_reg(EMB_FUNC_EN_A, (emb_a & 0xC7))
175+
self.__write_reg(EMB_FUNC_EN_B, (emb_b & 0xE6))
176+
emb_ab = (emb_a, emb_b)
177+
178+
self.set_mem_bank(FUNC_CFG_BANK_USER)
179+
return emb_ab
180+
181+
def load_mlc(self, ucf):
182+
# Load MLC config from file
183+
with open(ucf, "r") as ucf_file:
184+
for l in ucf_file:
185+
if l.startswith("Ac"):
186+
v = [int(v, 16) for v in l.strip().split(" ")[1:3]]
187+
self.__write_reg(v[0], v[1])
188+
189+
emb_ab = self.set_embedded_functions(False)
190+
191+
# Disable I3C interface
192+
self.__write_reg(CTRL9_XL, self.__read_reg(CTRL9_XL) | 0x01)
193+
194+
# Enable Block Data Update
195+
self.__write_reg(CTRL3_C, self.__read_reg(CTRL3_C) | 0x40)
196+
197+
# Route signals on interrupt pin 1
198+
self.set_mem_bank(FUNC_CFG_BANK_EMBED)
199+
self.__write_reg(MLC_INT1, self.__read_reg(MLC_INT1) & 0x01)
200+
self.set_mem_bank(FUNC_CFG_BANK_USER)
201+
202+
# Configure interrupt pin mode
203+
self.__write_reg(TAP_CFG0, self.__read_reg(TAP_CFG0) | 0x41)
204+
205+
self.set_embedded_functions(True, emb_ab)
206+
207+
def read_mlc_output(self):
208+
buf = None
209+
if self.__read_reg(MLC_STATUS) & 0x1:
210+
self.__read_reg(0x1A, size=12)
211+
self.set_mem_bank(FUNC_CFG_BANK_EMBED)
212+
buf = self.__read_reg(MLC0_SRC, 8)
213+
self.set_mem_bank(FUNC_CFG_BANK_USER)
214+
return buf
215+
216+
def read_gyro(self):
217+
"""Returns gyroscope vector in degrees/sec."""
218+
mv = memoryview(self.scratch_int)
219+
f = self.gyro_scale
220+
self.i2c.readfrom_mem_into(self.address, OUTX_L_G, mv)
221+
return (mv[0] / f, mv[1] / f, mv[2] / f)
222+
223+
def read_accel(self):
224+
"""Returns acceleration vector in gravity units (9.81m/s^2)."""
225+
mv = memoryview(self.scratch_int)
226+
f = self.accel_scale
227+
self.i2c.readfrom_mem_into(self.address, OUTX_L_XL, mv)
228+
return (mv[0] / f, mv[1] / f, mv[2] / f)

drivers/lsm6dsox/lsm6dsox_basic.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# LSM6DSOX Basic Example.
2+
import time
3+
from lsm6dsox import LSM6DSOX
4+
5+
from machine import Pin, I2C
6+
7+
lsm = LSM6DSOX(I2C(0, scl=Pin(13), sda=Pin(12)))
8+
9+
while True:
10+
print("Accelerometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}".format(*lsm.read_accel()))
11+
print("Gyroscope: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}".format(*lsm.read_gyro()))
12+
print("")
13+
time.sleep_ms(100)

drivers/lsm6dsox/lsm6dsox_mlc.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# LSM6DSOX IMU MLC (Machine Learning Core) Example.
2+
# Download the raw UCF file, copy to storage and reset.
3+
4+
# NOTE: The pre-trained models (UCF files) for the examples can be found here:
5+
# https://github.com/STMicroelectronics/STMems_Machine_Learning_Core/tree/master/application_examples/lsm6dsox
6+
7+
import time
8+
from lsm6dsox import LSM6DSOX
9+
from machine import Pin, I2C
10+
11+
INT_MODE = True # Run in interrupt mode.
12+
INT_FLAG = False # Set True on interrupt.
13+
14+
15+
def imu_int_handler(pin):
16+
global INT_FLAG
17+
INT_FLAG = True
18+
19+
20+
if INT_MODE == True:
21+
int_pin = Pin(24)
22+
int_pin.irq(handler=imu_int_handler, trigger=Pin.IRQ_RISING)
23+
24+
i2c = I2C(0, scl=Pin(13), sda=Pin(12))
25+
26+
# Vibration detection example
27+
UCF_FILE = "lsm6dsox_vibration_monitoring.ucf"
28+
UCF_LABELS = {0: "no vibration", 1: "low vibration", 2: "high vibration"}
29+
# NOTE: Selected data rate and scale must match the MLC data rate and scale.
30+
lsm = LSM6DSOX(i2c, gyro_odr=26, accel_odr=26, gyro_scale=2000, accel_scale=4, ucf=UCF_FILE)
31+
32+
# Head gestures example
33+
# UCF_FILE = "lsm6dsox_head_gestures.ucf"
34+
# UCF_LABELS = {0:"Nod", 1:"Shake", 2:"Stationary", 3:"Swing", 4:"Walk"}
35+
# NOTE: Selected data rate and scale must match the MLC data rate and scale.
36+
# lsm = LSM6DSOX(i2c, gyro_odr=26, accel_odr=26, gyro_scale=250, accel_scale=2, ucf=UCF_FILE)
37+
38+
print("MLC configured...")
39+
40+
while True:
41+
if INT_MODE:
42+
if INT_FLAG:
43+
INT_FLAG = False
44+
print(UCF_LABELS[lsm.read_mlc_output()[0]])
45+
else:
46+
buf = lsm.read_mlc_output()
47+
if buf != None:
48+
print(UCF_LABELS[buf[0]])
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"deploy": [
3+
"../deploy.md"
4+
],
5+
"docs": "",
6+
"features": [
7+
"Breadboard Friendly",
8+
"Castellated Pads",
9+
"WiFi Nina-W102",
10+
"Bluetooth Nina-W102",
11+
"IMU LSM6DSOXTR",
12+
"Crypto IC ATECC608A-MAHDA-T",
13+
"Microphone MP34DT05",
14+
"SPI Flash 16MB",
15+
"USB-MICRO"
16+
],
17+
"images": [
18+
"ABX00052_01.iso_999x750.jpg"
19+
],
20+
"mcu": "RP2040",
21+
"product": "Arduino Nano RP2040 Connect",
22+
"thumbnail": "",
23+
"url": "https://store-usa.arduino.cc/products/arduino-nano-rp2040-connect",
24+
"vendor": "Arduino"
25+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
include("$(PORT_DIR)/boards/manifest.py")
2+
freeze("$(MPY_DIR)/drivers/lsm6dsox/", "lsm6dsox.py")
3+
include(
4+
"$(MPY_LIB_DIR)/micropython/bluetooth/aioble/manifest.py",
5+
client=True,
6+
central=True,
7+
l2cap=True,
8+
security=True,
9+
)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# cmake file for Arduino Nano RP2040 Connect.
2+
set(MICROPY_PY_BLUETOOTH 1)
3+
set(MICROPY_BLUETOOTH_NIMBLE 1)
4+
set(MICROPY_PY_NETWORK_NINAW10 1)
5+
set(MICROPY_HW_ENABLE_DOUBLE_TAP 1)
6+
set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//Board config for Arduino Nano RP2040 Connect.
2+
3+
// Board and hardware specific configuration
4+
#define MICROPY_HW_BOARD_NAME "Arduino Nano RP2040 Connect"
5+
#define MICROPY_HW_FLASH_STORAGE_BYTES (8 * 1024 * 1024)
6+
7+
// Enable networking and sockets.
8+
#define MICROPY_PY_NETWORK (1)
9+
#define MICROPY_PY_USOCKET (1)
10+
11+
// Enable USB Mass Storage with FatFS filesystem.
12+
#define MICROPY_HW_USB_MSC (1)
13+
#define MICROPY_HW_USB_VID (0x2341)
14+
#define MICROPY_HW_USB_PID (0x015e)
15+
16+
// UART 1 config.
17+
#define MICROPY_HW_UART1_TX (8)
18+
#define MICROPY_HW_UART1_RX (9)
19+
#define MICROPY_HW_UART1_CTS (10)
20+
#define MICROPY_HW_UART1_RTS (11)
21+
22+
// SPI 1 config.
23+
#define MICROPY_HW_SPI1_SCK (14)
24+
#define MICROPY_HW_SPI1_MOSI (11)
25+
#define MICROPY_HW_SPI1_MISO (8)
26+
27+
// Bluetooth config.
28+
#define MICROPY_HW_BLE_UART_ID (1)
29+
#define MICROPY_HW_BLE_UART_BAUDRATE (119600)
30+
31+
// WiFi/NINA-W10 config.
32+
#define MICROPY_HW_WIFI_SPI_ID (1)
33+
#define MICROPY_HW_WIFI_SPI_BAUDRATE (8 * 1000 * 1000)
34+
35+
// ublox Nina-W10 module config.
36+
#define MICROPY_HW_NINA_RESET (3)
37+
#define MICROPY_HW_NINA_GPIO0 (2)
38+
#define MICROPY_HW_NINA_GPIO1 (9)
39+
#define MICROPY_HW_NINA_ACK (10)

0 commit comments

Comments
 (0)
0