Merge pull request 'Handle partitioned and unpartitioned SD cards' (#32) from sd-partition-support into main
All checks were successful
Build RPi Pico firmware image / Build-Firmware (push) Successful in 3m30s
Check code formatting / Check-C-Format (push) Successful in 7s
Check code formatting / Check-Python-Flake8 (push) Successful in 9s
Check code formatting / Check-Bash-Shellcheck (push) Successful in 5s
Run unit tests on host / Run-Unit-Tests (push) Successful in 10s

Reviewed-on: #32
Reviewed-by: Stefan Kratochwil <kratochwil-la@gmx.de>
This commit was merged in pull request #32.
This commit is contained in:
2025-08-05 19:51:58 +00:00
4 changed files with 92 additions and 29 deletions

View File

@@ -5,7 +5,6 @@ import aiorepl
import asyncio import asyncio
import machine import machine
import micropython import micropython
import os
import time import time
from machine import Pin from machine import Pin
from math import pi, sin, pow from math import pi, sin, pow
@@ -17,8 +16,7 @@ from mfrc522 import MFRC522
from mp3player import MP3Player from mp3player import MP3Player
from nfc import Nfc from nfc import Nfc
from rp2_neopixel import NeoPixel from rp2_neopixel import NeoPixel
from rp2_sd import SDCard from utils import Buttons, SDContext, TimerManager
from utils import Buttons, TimerManager
micropython.alloc_emergency_exception_buf(100) micropython.alloc_emergency_exception_buf(100)
@@ -54,30 +52,6 @@ machine.mem32[0x4001c004 + 8*4] = 0x67
machine.mem32[0x40030000 + 0x00] = 0x10 machine.mem32[0x40030000 + 0x00] = 0x10
class SDContext:
def __init__(self, mosi, miso, sck, ss, baudrate):
self.mosi = mosi
self.miso = miso
self.sck = sck
self.ss = ss
self.baudrate = baudrate
def __enter__(self):
self.sdcard = SDCard(self.mosi, self.miso, self.sck, self.ss, self.baudrate)
try:
os.mount(self.sdcard, '/sd')
except Exception:
self.sdcard.deinit()
raise
return self
def __exit__(self, exc_type, exc_value, traceback):
try:
os.umount('/sd')
finally:
self.sdcard.deinit()
def run(): def run():
asyncio.new_event_loop() asyncio.new_event_loop()
# Setup LEDs # Setup LEDs
@@ -105,4 +79,6 @@ def run():
if __name__ == '__main__': if __name__ == '__main__':
run() if machine.Pin(17, machine.Pin.IN, machine.Pin.PULL_UP).value() != 0:
time.sleep(5)
run()

View File

@@ -2,6 +2,8 @@
# Copyright (c) 2025 Matthias Blankertz <matthias@blankertz.org> # Copyright (c) 2025 Matthias Blankertz <matthias@blankertz.org>
from utils.buttons import Buttons from utils.buttons import Buttons
from utils.mbrpartition import MBRPartition
from utils.sdcontext import SDContext
from utils.timer import TimerManager from utils.timer import TimerManager
__all__ = ["Buttons", "TimerManager"] __all__ = ["Buttons", "MBRPartition", "SDContext", "TimerManager"]

View File

@@ -0,0 +1,46 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2025 Matthias Blankertz <matthias@blankertz.org>
from array import array
import struct
class MBRPartition:
def __init__(self, bdev, partno):
assert partno >= 0 and partno < 4
self.bdev = bdev
bdev_len = bdev.ioctl(4, None)
bdev_bs = bdev.ioctl(5, None)
assert bdev_bs == 512
mbr = array('B', 512*b'0')
bdev.readblocks(0, mbr)
if mbr[510] != 0x55 or mbr[511] != 0xaa:
raise ValueError("Not a valid MBR")
partofs = 0x1be + partno*16
(boot_ind, _, _, _,
parttype, _, _, _,
lba_start, lba_len) = struct.unpack_from('<BBBBBBBBLL', mbr, partofs)
print(f'Partition {partno} bi {boot_ind} type {parttype} start {lba_start} len {lba_len}')
if (boot_ind != 0x00 and boot_ind != 0x80) or parttype == 0x00:
raise ValueError("Not a valid partition")
self.offset = lba_start
self.size = lba_len
assert lba_start + lba_len <= bdev_len
def ioctl(self, op, arg):
if op == 4:
return self.size
elif op == 5:
return 512
else:
return None
def readblocks(self, block, buf):
if block >= self.size:
raise ValueError("Block out of range")
return self.bdev.readblocks(block+self.offset, buf)
def writeblocks(self, block, buf):
if block >= self.size:
raise ValueError("Block out of range")
return self.bdev.writeblocks(block+self.offset, buf)

View File

@@ -0,0 +1,39 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2025 Matthias Blankertz <matthias@blankertz.org>
import os
from . import MBRPartition
from rp2_sd import SDCard
class SDContext:
def __init__(self, mosi, miso, sck, ss, baudrate):
self.mosi = mosi
self.miso = miso
self.sck = sck
self.ss = ss
self.baudrate = baudrate
def __enter__(self):
self.sdcard = SDCard(self.mosi, self.miso, self.sck, self.ss, self.baudrate)
# Try first partition
try:
self.part = MBRPartition(self.sdcard, 0)
os.mount(self.part, '/sd')
return self
except Exception:
print("Failed to mount SDCard partition, trying whole device...")
# Try whole device
try:
os.mount(self.sdcard, '/sd')
return self
except Exception as ex:
self.sdcard.deinit()
raise RuntimeError("Could not mount SD card") from ex
def __exit__(self, exc_type, exc_value, traceback):
try:
os.umount('/sd')
finally:
self.sdcard.deinit()