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

Skip to content

Commit 1c6821b

Browse files
committed
RP2: Add support for Arduino Nano RP2040.
1 parent 0be3b91 commit 1c6821b

File tree

5 files changed

+345
-0
lines changed

5 files changed

+345
-0
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
include("$(PORT_DIR)/boards/manifest.py")
2+
freeze("$(BOARD_DIR)/modules")
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Helpers for generating BLE advertising payloads.
2+
3+
from micropython import const
4+
import struct
5+
import bluetooth
6+
7+
# Advertising payloads are repeated packets of the following form:
8+
# 1 byte data length (N + 1)
9+
# 1 byte type (see constants below)
10+
# N bytes type-specific data
11+
12+
_ADV_TYPE_FLAGS = const(0x01)
13+
_ADV_TYPE_NAME = const(0x09)
14+
_ADV_TYPE_UUID16_COMPLETE = const(0x3)
15+
_ADV_TYPE_UUID32_COMPLETE = const(0x5)
16+
_ADV_TYPE_UUID128_COMPLETE = const(0x7)
17+
_ADV_TYPE_UUID16_MORE = const(0x2)
18+
_ADV_TYPE_UUID32_MORE = const(0x4)
19+
_ADV_TYPE_UUID128_MORE = const(0x6)
20+
_ADV_TYPE_APPEARANCE = const(0x19)
21+
22+
23+
# Generate a payload to be passed to gap_advertise(adv_data=...).
24+
def advertising_payload(limited_disc=False, br_edr=False, name=None, services=None, appearance=0):
25+
payload = bytearray()
26+
27+
def _append(adv_type, value):
28+
nonlocal payload
29+
payload += struct.pack("BB", len(value) + 1, adv_type) + value
30+
31+
_append(
32+
_ADV_TYPE_FLAGS,
33+
struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)),
34+
)
35+
36+
if na 67E6 me:
37+
_append(_ADV_TYPE_NAME, name)
38+
39+
if services:
40+
for uuid in services:
41+
b = bytes(uuid)
42+
if len(b) == 2:
43+
_append(_ADV_TYPE_UUID16_COMPLETE, b)
44+
elif len(b) == 4:
45+
_append(_ADV_TYPE_UUID32_COMPLETE, b)
46+
elif len(b) == 16:
47+
_append(_ADV_TYPE_UUID128_COMPLETE, b)
48+
49+
# See org.bluetooth.characteristic.gap.appearance.xml
50+
if appearance:
51+
_append(_ADV_TYPE_APPEARANCE, struct.pack("<h", appearance))
52+
53+
return payload
54+
55+
56+
def decode_field(payload, adv_type):
57+
i = 0
58+
result = []
59+
while i + 1 < len(payload):
60+
if payload[i + 1] == adv_type:
61+
result.append(payload[i + 2 : i + payload[i] + 1])
62+
i += 1 + payload[i]
63+
return result
64+
65+
66+
def decode_name(payload):
67+
n = decode_field(payload, _ADV_TYPE_NAME)
68+
return str(n[0], "utf-8") if n else ""
69+
70+
71+
def decode_services(payload):
72+
services = []
73+
for u in decode_field(payload, _ADV_TYPE_UUID16_COMPLETE):
74+
services.append(bluetooth.UUID(struct.unpack("<h", u)[0]))
75+
for u in decode_field(payload, _ADV_TYPE_UUID32_COMPLETE):
76+
services.append(bluetooth.UUID(struct.unpack("<d", u)[0]))
77+
for u in decode_field(payload, _ADV_TYPE_UUID128_COMPLETE):
78+
services.append(bluetooth.UUID(u))
79+
return services
80+
81+
82+
def demo():
83+
payload = advertising_payload(
84+
name="micropython",
85+
services=[bluetooth.UUID(0x181A), bluetooth.UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")],
86+
)
87+
print(payload)
88+
print(decode_name(payload))
89+
print(decode_services(payload))
90+
91+
92+
if __name__ == "__main__":
93+
demo()
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
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+
Example usage:
29+
import time
30+
from lsm6dsox import LSM6DSOX
31+
32+
from machine import Pin, I2C
33+
lsm = LSM6DSOX(I2C(0, scl=Pin(13), sda=Pin(12)))
34+
35+
while (True):
36+
print('Accelerometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*lsm.read_accel()))
37+
print('Gyroscope: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*lsm.read_gyro()))
38+
print("")
39+
time.sleep_ms(100)
40+
"""
41+
import array
42+
43+
class LSM6DSOX:
44+
CTRL3_C = const(0x12)
45+
CTRL1_XL = const(0x10)
46+
CTRL8_XL = const(0x17)
47+
CTRL9_XL = const(0x18)
48+
49+
CTRL2_G = const(0x11)
50+
CTRL7_G = const(0x16)
51+
52+
OUTX_L_G = const(0x22)
53+
OUTX_L_XL = const(0x28)
54+
MLC_STATUS = const(0x38)
55+
56+
DEFAULT_ADDR = const(0x6A)
57+
WHO_AM_I_REG = const(0x0F)
58+
59+
FUNC_CFG_ACCESS = const(0x01)
60+
FUNC_CFG_BANK_USER = const(0)
61+
FUNC_CFG_BANK_HUB = const(1)
62+
FUNC_CFG_BANK_EMBED = const(2)
63+
64+
MLC0_SRC = const(0x70)
65+
MLC_INT1 = const(0x0D)
66+
TAP_CFG0 = const(0x56)
67+
68+
EMB_FUNC_EN_A = const(0x04)
69+
EMB_FUNC_EN_B = const(0x05)
70+
71+
def __init__(self, i2c, address=DEFAULT_ADDR, gyro_odr=104, accel_odr=104, gyro_scale=2000, accel_scale=4, ucf=None):
72+
""" Initalizes Gyro and Accelerator.
73+
accel_odr: (0, 1.6Hz, 3.33Hz, 6.66Hz, 12.5Hz, 26Hz, 52Hz, 104Hz, 208Hz, 416Hz, 888Hz)
74+
gyro_odr: (0, 1.6Hz, 3.33Hz, 6.66Hz, 12.5Hz, 26Hz, 52Hz, 104Hz, 208Hz, 416Hz, 888Hz)
75+
gyro_scale: (245dps, 500dps, 1000dps, 2000dps)
76+
accel_scale: (+/-2g, +/-4g, +/-8g, +-16g)
77+
ucf: MLC program to load.
78+
"""
79+
self.i2c = i2c
80+
self.address = address
81+
82+
# check the id of the Accelerometer/Gyro
83+
if (self.__read_reg(WHO_AM_I_REG) != 108):
84+
raise OSError("No LSM6DS device was found at address 0x%x"%(self.address))
85+
86+
# allocate scratch buffer for efficient conversions and memread op's
87+
self.scratch_int = array.array('h',[0, 0, 0])
88+
89+
SCALE_GYRO = {250:0, 500:1, 1000:2, 2000:3}
90+
SCALE_ACCEL = {2:0, 4:2, 8:3, 16:1}
91+
# XL_HM_MODE = 0 by default. G_HM_MODE = 0 by default.
92+
ODR = {0:0x00, 1.6:0x08, 3.33:0x09, 6.66:0x0A, 12.5:0x01, 26:0x02, 52:0x03, 104:0x04, 208:0x05, 416:0x06, 888:0x07}
93+
94+
gyro_odr = round(gyro_odr, 2)
95+
accel_odr = round(accel_odr, 2)
96+
assert gyro_odr in ODR, "Invalid sampling rate: %d" % accel_odr
97+
assert gyro_scale in SCALE_GYRO, "invalid gyro scaling: %d" % gyro_scale
98+
99+
assert accel_odr in ODR, "Invalid sampling rate: %d" % accel_odr
100+
assert accel_scale in SCALE_ACCEL, "invalid accelerometer scaling: %d" % accel_scale
101+
102+
# Soft-reset the device.
103+
self.reset()
104+
105+
# Load and configure MLC if UCF file is provided
106+
if (ucf != None):
107+
self.load_mlc(ucf)
108+
109+
# Set Gyroscope datarate and scale.
110+
# Note output from LPF2 second filtering stage is selected. See Figure 18.
111+
self.__write_reg(CTRL1_XL, (ODR[accel_odr] << 4) | (SCALE_ACCEL[accel_scale] << 2) | 2);
112+
113+
# Enable LPF2 and HPF fast-settling mode, ODR/4
114+
self.__write_reg(CTRL8_XL, 0x09);
115+
116+
# Set Gyroscope datarate and scale.
117+
self.__write_reg(CTRL2_G, (ODR[gyro_odr] << 4) | (SCALE_GYRO[gyro_scale] << 2) | 0);
118+
119+
self.gyro_scale = 32768 / gyro_scale
120+
self.accel_scale = 32768 / accel_scale
121+
122+
def __read_reg(self, reg, size=1):
123+
buf = self.i2c.readfrom_mem(self.address, reg, size)
124+
if (size == 1):
125+
return int(buf[0])
126+
return [int(x) for x in buf]
127+
128+
def __write_reg(self, reg, val):
129+
self.i2c.writeto_mem(self.address, reg, bytes([val]))
130+
131+
def reset(self):
132+
self.__write_reg(CTRL3_C, self.__read_reg(CTRL3_C) | 0x1)
133+
for i in range(0, 10):
134+
if ((self.__read_reg(CTRL3_C) & 0x01) == 0):
135+
return
136+
time.sleep_ms(10)
137+
raise OSError("Failed to reset LSM6DS device.")
138+
139+
def set_mem_bank(self, bank):
140+
cfg = self.__read_reg(FUNC_CFG_ACCESS) & 0x3F
141+
self.__write_reg(FUNC_CFG_ACCESS, cfg | (bank << 6))
142+
143+
def set_embedded_functions(self, enable, emb_ab=None):
144+
self.set_mem_bank(FUNC_CFG_BANK_EMBED)
145+
if (enable):
146+
self.__write_reg(EMB_FUNC_EN_A, emb_ab[0])
147+
self.__write_reg(EMB_FUNC_EN_B, emb_ab[1])
148+
else:
149+
emb_a = self.__read_reg(EMB_FUNC_EN_A)
150+
emb_b = self.__read_reg(EMB_FUNC_EN_B)
151+
self.__write_reg(EMB_FUNC_EN_A, (emb_a & 0xC7))
152+
self.__write_reg(EMB_FUNC_EN_B, (emb_b & 0xE6))
153+
emb_ab = (emb_a, emb_b)
154+
155+
self.set_mem_bank(FUNC_CFG_BANK_USER)
156+
return emb_ab
157+
158+
def load_mlc(self, ucf):
159+
# Load MLC config from file
160+
with open(ucf, "r") as ucf_file:
161+
for l in ucf_file:
162+
if (l.startswith("Ac")):
163+
v = [int(v, 16) for v in l.strip().split(" ")[1:3]]
164+
self.__write_reg(v[0], v[1])
165+
166+
emb_ab = self.set_embedded_functions(False)
167+
168+
# Disable I3C interface
169+
self.__write_reg(CTRL9_XL, self.__read_reg(CTRL9_XL) | 0x01)
170+
171+
# Enable Block Data Update
172+
self.__write_reg(CTRL3_C, self.__read_reg(CTRL3_C) | 0x40)
173+
174+
# Route signals on interrupt pin 1
175+
self.set_mem_bank(FUNC_CFG_BANK_EMBED)
176+
self.__write_reg(MLC_INT1, self.__read_reg(MLC_INT1) & 0x01)
177+
self.set_mem_bank(FUNC_CFG_BANK_USER)
178+
179+
# Configure interrupt pin mode
180+
self.__write_reg(TAP_CFG0, self.__read_reg(TAP_CFG0) | 0x41)
181+
182+
self.set_embedded_functions(True, emb_ab)
183+
184+
def read_mlc_output(self):
185+
buf = None
186+
if (self.__read_reg(MLC_STATUS) & 0x1):
187+
self.__read_reg(0x1A, size=12)
188+
self.set_mem_bank(FUNC_CFG_BANK_EMBED)
189+
buf = self.__read_reg(MLC0_SRC, 8)
190+
self.set_mem_bank(FUNC_CFG_BANK_USER)
191+
return buf
192+
193+
def read_gyro(self):
194+
"""Returns gyroscope vector in degrees/sec."""
195+
mv = memoryview(self.scratch_int)
196+
f = self.gyro_scale
197+
self.i2c.readfrom_mem_into(self.address, OUTX_L_G, mv)
198+
return (mv[0]/f, mv[1]/f, mv[2]/f)
199+
200+
def read_accel(self):
201+
"""Returns acceleration vector in gravity units (9.81m/s^2)."""
202+
mv = memoryview(self.scratch_int)
203+
f = self.accel_scale
204+
self.i2c.readfrom_mem_into(self.address, OUTX_L_XL, mv)
205+
return (mv[0]/f, mv[1]/f, mv[2]/f)
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 71B4 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