Hi Members!
In Micropython is is normal that after a reset the following files are executed in the following order:
1) boot.py
2) main.py
My XIAO RP2350 is flashed with:
MicroPython v1.24.0-preview.201.g269a0e0e1 on 2024-08-09; Raspberry Pi Pico2 with RP2350.
After a reset of this device only boot.by is executed.
The script main.py is not executed.
boot.py mounts succssfully the SDCard that is in the Seeed Expansion Board Base onto which the XIAO RP2350 is placed. At the end of boot.py the current directory is changed to the root directory of the device.
When I run main.py from within Thonny “by hand” this script runs without problem.
The file main.py has 308 lines of code. It is 11 kBytes in length.
In the XIAO RP2350’s memory there is a folder /lib that has only sdcard.py in it.
The length of sdcard.py has 306 lines of code. It is 11 kBytes in length.
In the root folder (‘/’) there are only boot.py (length 2 kBytes) and main.py.
All other needed library modules are in the SDCard in /sd/lib.
Here is the code of boot.py
# boot.py
# created for Seeed XIAO RP2350 with Seeed Epansion Board Base
# for MicroPython
# 2025-05-05 by Paulus Schulinck (Github handle: @PaulskPt)
# The idea is to call this script after booting
# and then use library files that are on the SDCard in folder /sd/lib
#
import machine
import os
import time
import sys
from lib.sdcard import SDCard
my_debug = False
fileTypeDir = 0x4000
fileTypeFile = 0x8000
PIN_SD_SCK = machine.Pin.board.GP2
PIN_SD_MOSI = machine.Pin.board.GP3
PIN_SD_MISO = machine.Pin.board.GP4
PIN_SD_CS = machine.Pin.board.GP28 # A2/D2
# Setup for SD Card
sd_spi = machine.SPI(0,
sck=machine.Pin(PIN_SD_SCK, machine.Pin.OUT), # for Presto it was pin 34
mosi=machine.Pin(PIN_SD_MOSI, machine.Pin.OUT), # same, pin 35
miso=machine.Pin(PIN_SD_MISO, machine.Pin.OUT)) # same, pin 36
def mount_sd():
sd = SDCard(sd_spi, machine.Pin(PIN_SD_CS)) # same, pin 39
ret = False
try:
# Mount the SD to the directory 'sd'
os.mount(sd, "/sd")
os.chdir("/sd")
print("SDCard mounted")
if my_debug:
print(f"Current directory: \"{os.getcwd()}\"")
os.chdir("/") # go back to the root directory
ret = True
except OSError as exc:
print("mounting SDCard failed")
sys.print_exception(exc)
# print(f"Error: {exc}")
return ret
if __name__ == '__main__':
mount_sd()
Here is the code of main.py:
#
# Micropython script for a Seeed XIAO RP2350 attached to a Seeed Expansion Board Base
# Test to receive ntp unixtime from another device: Pimoroni Pico Plus 2 with RM2 module attached
# also display/print sensor values from either mcp9808 or bme280 (see global flags below).
# by Paulus Schulinck (Github handle: @PaulskPt)
# 2025-05-08
# License: MIT
# Note: script uses modules in /sd/lib. The script in boot.py tries to mount the SDCard
#
import struct
import array, random
from machine import Pin, UART
import rp2
import time
import utime
import os
use_bme280 = True
use_mcp9808 = False
my_debug = False
try:
os.chdir('/sd')
from lib.pcf8563 import *
if use_mcp9808:
from lib.mcp9808 import MCP9808
if use_bme280:
from lib.bme280_f import BME280
from lib.ssd1306 import SSD1306_I2C
tz_offset = 0
from lib.secrets import TIMEZONE_OFFSET # get the local timezone offset from GMT
tz_offset = int(TIMEZONE_OFFSET)
print(f"TIMEZONE_OFFSET = {TIMEZONE_OFFSET}")
os.chdir('/')
except OSError as exc:
print(f"Error: {exc}")
raise
PIN_WIRE1_SCL = machine.Pin.board.GP7
PIN_WIRE1_SDA = machine.Pin.board.GP6
i2c = machine.I2C(id=1, scl=machine.Pin(PIN_WIRE1_SCL), sda=machine.Pin(PIN_WIRE1_SDA), freq=400000)
if use_mcp9808:
sensor = MCP9808(i2c) # create an instance of the MCP9808 sensor object
if use_bme280:
bme280 = BME280(i2c=i2c)
oled = SSD1306_I2C(128, 32, i2c) # create an instance of the OLED object
rtc = PCF8563(i2c) # create an instance of the rtc object
if my_debug:
print(f"type(rtc) = {type(rtc)}")
monthsLst = ["", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
wdDict = {0: "Mon",
1: "Tue",
2: "Wed",
3: "Thu",
4: "Fri",
5: "Sat",
6: "Sun"}
brill = 10 # Let the RGB Led shine just a bit
RED = (0, brill, 0)
BLUE = (brill, 0, 0)
GREEN = (0, 0, brill)
BLACK = (0, 0, 0)
uart = UART(0, 9600, tx = machine.Pin.board.GP0, rx= machine.Pin.board.GP1)
if my_debug:
print(f"type(uart) = {type(uart)}")
local_time_lst = []
weekdayStr = ""
yearday = 0
# yy, mo, dd, wd, hh, mm, ss
dt = (25, 5, 5, 0, 18, 20, 40) # pro-forma datetime tuple
rtc.DateTime(dt) # set the rtc
if my_debug:
print(rtc.DateTime())
# setup for RGB Led:
NUM_LEDS = 1
LED_PIN = 22 # PICO_DEFAULT_WS2812_PIN
POWER_PIN = 23 # PICO_DEFAULT_WS2812_POWER_PIN
# Global brightness variable (0.0 to 1.0)
BRIGHTNESS = 0.1
@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT, autopull=True, pull_thresh=24)
def ws2812():
T1 = 2
T2 = 5
T3 = 3
wrap_target()
label("bitloop")
out(x, 1) .side(0) [T3 - 1]
jmp(not_x, "do_zero") .side(1) [T1 - 1]
jmp("bitloop") .side(1) [T2 - 1]
label("do_zero")
nop() .side(0) [T2 - 1]
wrap()
# Set up the power pin
power_pin = Pin(POWER_PIN, Pin.OUT)
power_pin.value(1) # Turn on power to the LED
# Create the StateMachine with the ws2812 program, outputting on LED_PIN
sm = rp2.StateMachine(0, ws2812, freq=8_000_000, sideset_base=Pin(LED_PIN))
# Start the StateMachine, it will wait for data on its FIFO.
sm.active(1)
def set_led_color(color):
#TAG = "set_led_color(): "
color2 = 0
if isinstance(color, tuple):
color2 = color[0] | (color[1] << 8) | (color[2] << 16)
#print(TAG + "color = ({:d},{:d},{:d})".format(color[0], color[1], color[2]))
#print(TAG + "color2 = 0x{:02x}".format(color2))
else:
color2 = color
sm.put(array.array("I", [color2]), 8)
#--- end of setup for RGB Led ---
# [2026, 5, 4, 6, 18, 20, 40]
def unix_to_rtc():
global unixtime, tz_offset, local_time_lst, weekdayStr, yearday
if unixtime > 0:
# (yy, mo, dd, hh, mm, ss, wd, yd)
# example of time.localtime result: (2025, 5, 5, 18, 26, 38, 0, 125)
lt = time.gmtime(unixtime + (tz_offset * 3600) )
# yy mo dd wd hh mm ss
local_time_lst = [lt[0], lt[1], lt[2], lt[6], lt[3], lt[4], lt[5]]
#weekdayStr = wdDict[lt[2]]
#yearday = lt[7]
rtc.DateTime(local_time_lst)
print(f"rtc updated from ntp: {rtc.DateTime}")
def update_fm_ntp():
global unixtime, weekdayStr, yearday
t1 = "Unable to get time from NTP server.\n\nCheck your network and try again."
TAG = "update_fm_ntp(): "
ret = False
# Try to receive unixtime via UART from Pimoroni Pico Plus 2 (with RM2 WiFi/BT module connected)
if not my_debug:
print("\nWaiting to receive unixtime from Pimoroni Pico Plus 2")
ux_val = None
try_cnt = 0
try_cnt_max = 100
buflen = 10
while True:
rx_buf = bytearray(buflen) # create a clean buffer
rx_buf = uart.read()
# print(f"type(rx_buf) = {type(rx_buf)}")
if isinstance(rx_buf, bytes):
set_led_color(GREEN)
print("unixtime data received via UART")
# print(f"rx_buf = {rx_buf}, list(rx_buf) = {list(rx_buf)}")
try:
for i in range(3, 0, -1):
if rx_buf[i] == 0:
break
except IndexError: # occurred when something erratically occurred,
# for instance that the other device was reset.
continue
if i > 0:
if my_debug:
print(f"nr of bytes (with a value > 0) = {i}")
# Convert bytearray back to integer
ux_val = struct.unpack(">L", rx_buf)[0] # 'L' is for a 32-bit integer (unsigned long)
if my_debug:
print(f"rx_buf = {rx_buf}, ux_val = {ux_val}")
if ux_val > 0:
break
else:
try_cnt += 1
if my_debug:
print(f"try_cnt = {try_cnt}")
if try_cnt >= try_cnt_max:
print("receive of unixtime timed out")
break
time.sleep(0.01)
if ux_val > 0:
unixtime = ux_val + (tz_offset * 3600)
if my_debug:
print(f"ux_val = {ux_val}, unixtime (+ timezone offset) = {unixtime}")
#unix_to_rtc()
gmtTime = utime.localtime(ux_val)
loctime = utime.localtime(unixtime)
if my_debug:
print(f"gmtTime = {gmtTime}")
print(f"loctime = {loctime}")
upd_time = ( loctime[0], loctime[1], loctime[2],
loctime[6],
loctime[3], loctime[4], loctime[5])
weekdayStr = wdDict[loctime[6]]
yearday = loctime[7]
rtc.DateTime(upd_time)
if my_debug:
print(f"rtc updated from ntp: {rtc.DateTime()}")
time.sleep(1) # leave the RGB Led on for a while!
set_led_color(BLACK)
ret = True
return ret
def pr_dt():
global dt
TAG = "pr_dt(): "
if isinstance(dt, tuple) and len(dt) == 8:
print("datetime received from NTP server: ", end = '\n')
# print(f"weekday = {dt[6]}", end = '')
if dt[6] in wdDict.keys():
wday = wdDict[dt[6]]
else:
wday = str(dt[6])
if int(TIMEZONE_OFFSET) >= 0: # in case timezone(s) UTC or EAST of UTC
n = TIMEZONE_OFFSET.find('+')
if n == -1: # not found
tz = "+" + TIMEZONE_OFFSET
else:
tz = TIMEZONE_OFFSET
else: # in case timezone(s) WEST of UTC
n = TIMEZONE_OFFSET.find('-')
if n == -1: # not found
tz = "-" + TIMEZONE_OFFSET
else:
tz = TIMEZONE_OFFSET
print("{:4d}-{:02d}-{:02d} T {:02d}:{:02d}:{:02d}, {:s}, yearday: {:3d}, timezone: UTC{:s}".format( \
dt[0], dt[1], dt[2], dt[3], dt[4], dt[5], wday, dt[7], tz))
# year, month, day, hours, minutes, seconds, wday, yearday))
else:
print(TAG + f"expected global variable dt being a tuple,\n\thowever received a type \"{type(dt)}\". Check your code!")
def disp_date():
tm = time.localtime()
year, month, day, _, _, _, _, _ = tm
m = monthsLst[month]
t = "{:02d} {:s} {:04d}".format(day, m, year)
oled.fill(0)
oled.text(t, 75, VERT_MIDDLE+80) # was: -30
def weekday():
dt = rtc.DateTime()
# print(f"weekday(): dt = {dt}")
if dt[3] in wdDict.keys():
wDay = wdDict[dt[3]]
else:
wDay = "?"
return wDay
def dtToStr():
loctime = rtc.DateTime()
return "{:s} {:4d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(
wdDict[loctime[3]],
loctime[0], loctime[1], loctime[2],
loctime[4], loctime[5], loctime[6])
def main():
if use_bme280:
bme_val_idx = 0
while True:
t = ""
try:
update_fm_ntp()
if use_mcp9808:
tempC = sensor.get_temp()
if isinstance(tempC, float):
t = "Temp: {:<5.2f}C".format(tempC)
if use_bme280:
if not my_debug:
v = bme280.values
print(f"bme280.values = {v}")
# example: bme280.values = ('22.40C', '1000.68hPa', '43.85%')
if bme_val_idx == 0:
t = "Temp: {:s}".format(v[0])
if bme_val_idx == 1:
t = "Press:{:s}".format(v[1])
if bme_val_idx == 2:
t = "Hum: {:s}".format(v[2])
dt = rtc.Date()
print(f"date = {dt}")
tm = rtc.Time()
print(f"time = {tm}")
print(f"weekday = {weekdayStr}")
print(f"yearday = {yearday}")
print(dtToStr(), end ='')
print(' ', end='')
print(t)
oled.fill(0)
oled.text(t, 0, 0)
oled.text(dt, 0, 10)
oled.text(weekday(), 0, 20)
oled.text(tm, 30, 20)
oled.show()
if use_bme280:
bme_val_idx += 1
if bme_val_idx >=3:
bme_val_idx = 0
time.sleep(3)
except OSError as exc:
print(f"Error: {exc.args[0]}")
if __name__ == '__main__':
main()
Anyone has an idea what could be the cause the main.py doesn’t execute automatically after a reset or power-on?
Thank you,
Paulus