Skip to content

Commit 6c0cf44

Browse files
Add SDCardManager
1 parent 833dcf4 commit 6c0cf44

2 files changed

Lines changed: 290 additions & 0 deletions

File tree

docs/frameworks/sdcard-manager.md

Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
# SDCardManager
2+
3+
SDCardManager provides a unified API for SD card initialization, mounting, and management in both SPI and SDIO modes. It follows the singleton + class-method-delegation pattern used by all MPOS frameworks.
4+
5+
## Overview
6+
7+
SDCardManager centralizes all SD card operations in a single class:
8+
9+
- **Dual-Mode Support** - Auto-detects SPI or SDIO based on provided pins
10+
- **Unified API** - Single `from mpos import SDCardManager` for all SD card needs
11+
- **Safe Mounting** - Idempotent mount (treats already-mounted as success)
12+
- **Format Support** - Format uninitialized cards as FAT32
13+
- **Singleton Pattern** - Class methods delegate to a single instance initialized at boot
14+
15+
## Architecture
16+
17+
SDCardManager is initialized once at boot by the board definition, then accessed via class methods:
18+
19+
```python
20+
class SDCardManager:
21+
_instance = None
22+
23+
@classmethod
24+
def init(cls, mode=None, spi_bus=None, cs_pin=None, cmd_pin=None, clk_pin=None,
25+
d0_pin=None, d1_pin=None, d2_pin=None, d3_pin=None, slot=1, width=None, freq=20000000):
26+
...
27+
28+
@classmethod
29+
def mount(cls, format=False):
30+
if not cls._instance:
31+
return False
32+
...
33+
```
34+
35+
The board definition calls `SDCardManager.init(...)` at boot with the hardware-specific pin configuration. Apps then call `mount()`, `is_mounted()`, `get_mount_point()`, etc. without needing to know about the underlying hardware.
36+
37+
## Usage
38+
39+
### Basic Mount
40+
41+
```python
42+
from mpos import SDCardManager
43+
44+
SDCardManager.mount()
45+
mountpoint = SDCardManager.get_mount_point()
46+
if mountpoint:
47+
import os
48+
os.listdir(mountpoint)
49+
```
50+
51+
### Checking Mount Status
52+
53+
```python
54+
from mpos import SDCardManager
55+
56+
if SDCardManager.is_mounted():
57+
mp = SDCardManager.get_mount_point()
58+
mode = SDCardManager.get_mode()
59+
print("SD card mounted at %s (%s mode)" % (mp, mode))
60+
```
61+
62+
### Format and Mount
63+
64+
```python
65+
from mpos import SDCardManager
66+
67+
SDCardManager.mount(format=True)
68+
```
69+
70+
### Listing Contents
71+
72+
```python
73+
from mpos import SDCardManager
74+
75+
if SDCardManager.is_mounted():
76+
contents = SDCardManager.get_raw().list(SDCardManager.get_mount_point())
77+
for item in contents:
78+
print(item)
79+
```
80+
81+
## API Reference
82+
83+
### Class Methods
84+
85+
#### `init(mode=None, spi_bus=None, cs_pin=None, cmd_pin=None, clk_pin=None, d0_pin=None, d1_pin=None, d2_pin=None, d3_pin=None, slot=1, width=None, freq=20000000)`
86+
87+
Initialize the SD card hardware. Called once at boot by the board definition. Mode is auto-detected from which pins are provided (SDIO pins → SDIO mode, SPI pins → SPI mode). Can be overridden with the `mode` parameter.
88+
89+
**Parameters:**
90+
- `mode` (str, optional): `'spi'` or `'sdio'`. Auto-detected if not provided.
91+
- `spi_bus` (machine.SPI, optional): SPI bus instance for SPI mode.
92+
- `cs_pin` (int, optional): Chip-select pin number for SPI mode.
93+
- `cmd_pin` (int, optional): CMD pin for SDIO mode.
94+
- `clk_pin` (int, optional): CLK pin for SDIO mode.
95+
- `d0_pin` (int, optional): Data 0 pin for SDIO mode (required).
96+
- `d1_pin` (int, optional): Data 1 pin for 4-bit SDIO mode.
97+
- `d2_pin` (int, optional): Data 2 pin for 4-bit SDIO mode.
98+
- `d3_pin` (int, optional): Data 3 pin for 4-bit SDIO mode.
99+
- `slot` (int): SDIO slot number (0 or 1). Default: `1`.
100+
- `width` (int, optional): SDIO bus width (`1` or `4`). Auto-detected from data pins if not provided.
101+
- `freq` (int): SDIO clock frequency in Hz. Default: `20000000`.
102+
103+
**Example:**
104+
```python
105+
import machine
106+
from mpos import SDCardManager
107+
108+
# SPI mode
109+
spi = machine.SPI(2, baudrate=20000000, sck=machine.Pin(40), mosi=machine.Pin(41), miso=machine.Pin(38))
110+
SDCardManager.init(spi_bus=spi, cs_pin=21)
111+
112+
# SDIO 1-bit mode
113+
SDCardManager.init(cmd_pin=39, clk_pin=40, d0_pin=38, width=1)
114+
```
115+
116+
---
117+
118+
#### `mount(format=False)`
119+
120+
Mount the SD card at `/sdcard`. Returns `True` on success, `False` on failure. Treats already-mounted as success. If `format=True` and the mount fails, the card is formatted as FAT32 and re-mounted.
121+
122+
**Parameters:**
123+
- `format` (bool): Whether to format the card if mount fails. Default: `False`.
124+
125+
**Returns:** bool - `True` if mounted, `False` otherwise.
126+
127+
**Example:**
128+
```python
129+
SDCardManager.mount()
130+
SDCardManager.mount(format=True)
131+
```
132+
133+
---
134+
135+
#### `is_mounted()`
136+
137+
Check whether the SD card is currently mounted at `/sdcard`. Verifies by listing the root directory and testing with a temporary directory.
138+
139+
**Returns:** bool - `True` if mounted, `False` otherwise.
140+
141+
**Example:**
142+
```python
143+
if SDCardManager.is_mounted():
144+
print("SD card is ready")
145+
```
146+
147+
---
148+
149+
#### `get_mount_point()`
150+
151+
Get the mount point path if the card is mounted, or `None` if not.
152+
153+
**Returns:** str or None - `"/sdcard"` if mounted, `None` otherwise.
154+
155+
**Example:**
156+
```python
157+
mp = SDCardManager.get_mount_point()
158+
if mp:
159+
print("Mounted at %s" % mp)
160+
```
161+
162+
---
163+
164+
#### `get_mode()`
165+
166+
Get the current mode (`'spi'` or `'sdio'`), or `None` if not initialized.
167+
168+
**Returns:** str or None
169+
170+
**Example:**
171+
```python
172+
mode = SDCardManager.get_mode()
173+
print("SD card mode: %s" % mode)
174+
```
175+
176+
---
177+
178+
#### `format()`
179+
180+
Format the SD card as FAT32. Unmounts first if already mounted.
181+
182+
**Returns:** bool - `True` on success, `False` on failure.
183+
184+
**Example:**
185+
```python
186+
SDCardManager.format()
187+
```
188+
189+
---
190+
191+
#### `get_raw()`
192+
193+
Get the underlying `SDCardManager` instance. Useful for calling instance methods like `list()`.
194+
195+
**Returns:** SDCardManager instance or None
196+
197+
**Example:**
198+
```python
199+
instance = SDCardManager.get_raw()
200+
if instance:
201+
files = instance.list(SDCardManager.get_mount_point())
202+
```
203+
204+
## Practical Examples
205+
206+
### App Using SD Card for File Storage
207+
208+
Real-world example from the Retro-Go launcher app:
209+
210+
```python
211+
from mpos import SDCardManager
212+
213+
class RetroLauncher(Activity):
214+
def onResume(self, screen):
215+
self.bootfile_prefix = ""
216+
SDCardManager.mount()
217+
prefix = SDCardManager.get_mount_point()
218+
if prefix:
219+
self.bootfile_prefix = prefix + "/"
220+
```
221+
222+
([View on GitHub](https://github.com/MicroPythonOS/MicroPythonOS/blob/main/internal_filesystem/apps/com.micropythonos.doom_launcher/retrogo_launcher.py#L122))
223+
224+
### SPI Board Configuration
225+
226+
```python
227+
import machine
228+
from mpos import SDCardManager
229+
230+
spi = machine.SPI(2, baudrate=20000000, sck=machine.Pin(40), mosi=machine.Pin(41), miso=machine.Pin(38))
231+
SDCardManager.init(spi_bus=spi, cs_pin=21)
232+
```
233+
234+
### SDIO 4-Bit Board Configuration
235+
236+
```python
237+
from mpos import SDCardManager
238+
239+
SDCardManager.init(
240+
cmd_pin=39, clk_pin=40,
241+
d0_pin=38, d1_pin=37, d2_pin=36, d3_pin=35,
242+
width=4, freq=20000000
243+
)
244+
```
245+
246+
## Implementation Details
247+
248+
### File Structure
249+
250+
```
251+
mpos/
252+
├── sdcard.py # SDCardManager implementation
253+
└── __init__.py # Exports SDCardManager
254+
```
255+
256+
### Initialization Flow
257+
258+
1. **Boot** - Board definition calls `SDCardManager.init(...)` with hardware-specific pins
259+
2. **On Demand** - Apps call `SDCardManager.mount()` when they need SD access
260+
3. **Safe** - Mount is idempotent; already-mounted returns `True`
261+
4. **Fallback** - If `format=True`, failed mount triggers format-and-retry
262+
263+
## Design Patterns
264+
265+
### Singleton with Class Method Delegation
266+
267+
```python
268+
class SDCardManager:
269+
_instance = None # Set once at boot
270+
271+
@classmethod
272+
def mount(cls, format=False):
273+
if not cls._instance:
274+
return False
275+
return cls._instance._try_mount(_MOUNT_POINT)
276+
```
277+
278+
All public methods are class methods that forward to the single instance. Apps never create instances directly.
279+
280+
## Related Frameworks
281+
282+
- **[FileExplorerActivity](file-explorer-activity.md)** - File browser that uses SDCardManager for SD card access
283+
- **[BuildInfo](build-info.md)** - Build and board configuration metadata
284+
285+
## See Also
286+
287+
- [Architecture Overview](../architecture/overview.md)
288+
- [Frameworks](../architecture/frameworks.md)
289+
- [Creating Apps](../apps/creating-apps.md)

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ nav:
7171
- NotificationManager: frameworks/notification-manager.md
7272
- NumberFormat: frameworks/number-format.md
7373
- Preferences: frameworks/preferences.md
74+
- SDCardManager: frameworks/sdcard-manager.md
7475
- SensorManager: frameworks/sensor-manager.md
7576
- Service: frameworks/service.md
7677
- SettingActivity: frameworks/setting-activity.md

0 commit comments

Comments
 (0)