10000 rp2: Add MSC support. · micropython/micropython@d3acd73 · GitHub
[go: up one dir, main page]

Skip to content

Commit d3acd73

Browse files
committed
rp2: Add MSC support.
1 parent 8edc3aa commit d3acd73

File tree

9 files changed

+197
-0
lines changed

9 files changed

+197
-0
lines changed

ports/rp2/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ set(MICROPY_SOURCE_PORT
102102
rp2_pio.c
103103
tusb_port.c
104104
uart.c
105+
msc_disk.c
105106
)
106107

107108
set(MICROPY_SOURCE_QSTR

ports/rp2/boards/PICO/mpconfigboard.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
// Board and hardware specific configuration
22
#define MICROPY_HW_BOARD_NAME "Raspberry Pi Pico"
33
#define MICROPY_HW_FLASH_STORAGE_BYTES (1408 * 1024)
4+
5+
// Enable USB Mass Storage with FatFS filesystem.
6+
//#define MICROPY_HW_USB_MSC (1)

ports/rp2/main.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,11 @@ int main(int argc, char **argv) {
108108
rp2_pio_init();
109109

110110
// Execute _boot.py to set up the filesystem.
111+
#if MICROPY_VFS_FAT && MICROPY_HW_USB_MSC
112+
pyexec_frozen_module("_boot_fat.py");
113+
#else
111114
pyexec_frozen_module("_boot.py");
115+
#endif
112116

113117
// Execute user scripts.
114118
int ret = pyexec_file_if_exists("boot.py");

ports/rp2/modules/_boot_fat.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import os
2+
import machine, rp2
3+
4+
5+
# Try to mount the filesystem, and format the flash if it doesn't exist.
6+
# Note: the flash requires the programming size to be aligned to 256 bytes.
7+
bdev = rp2.Flash()
8+
try:
9+
vfs = os.VfsFat(bdev)
10+
os.mount(vfs, "/")
11+
except:
12+
os.VfsFat.mkfs(bdev)
13+
vfs = os.VfsFat(bdev)
14+
os.mount(vfs, "/")
15+
16+
del os, bdev, vfs

ports/rp2/mpconfigport.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,20 @@
143143
#define MICROPY_FATFS_ENABLE_LFN (1)
144144
#define MICROPY_FATFS_LFN_CODE_PAGE 437 /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */
145145
#define MICROPY_FATFS_RPATH (2)
146+
#if MICROPY_HW_USB_MSC
147+
#define MICROPY_FATFS_USE_LABEL (1)
148+
#define MICROPY_FATFS_MULTI_PARTITION (1)
149+
#define MICROPY_FATFS_MAX_SS (4096)
150+
#endif
146151

152+
#if MICROPY_VFS_FAT && MICROPY_HW_USB_MSC
153+
#define mp_type_fileio mp_type_vfs_fat_fileio
154+
#define mp_type_textio mp_type_vfs_fat_textio
155+
#elif MICROPY_VFS_LFS2
147156
// Use VfsLfs2's types for fileio/textio
148157
#define mp_type_fileio mp_type_vfs_lfs2_fileio
149158
#define mp_type_textio mp_type_vfs_lfs2_textio
159+
#endif
150160

151161
// Use VFS's functions for import stat and builtin open
152162
#define mp_import_stat mp_vfs_import_stat

ports/rp2/msc_disk.c

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2020-2021 Damien P. George
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*
24+
*/
25+
#include "tusb.h"
26+
#if CFG_TUD_MSC
27+
#include "mpconfigboard.h"
28+
#include "hardware/flash.h"
29+
#include "hardware/sync.h"
30+
#include "pico/stdlib.h"
31+
32+
#define BLOCK_SIZE (FLASH_SECTOR_SIZE)
33+
#define BLOCK_COUNT (MICROPY_HW_FLASH_STORAGE_BYTES / BLOCK_SIZE)
34+
#define FLASH_BASE_ADDR (PICO_FLASH_SIZE_BYTES - MICROPY_HW_FLASH_STORAGE_BYTES)
35+
#define FLASH_MMAP_ADDR (XIP_BASE + FLASH_BASE_ADDR)
36+
37+
static bool ejected = false;
38+
39+
// Invoked when received SCSI_CMD_INQUIRY
40+
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
41+
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) {
42+
const char vid[] = "Micropy";
43+
const char pid[] = "Mass Storage";
44+
const char rev[] = "1.0";
45+
46+
strncpy((char *)vendor_id, vid, 8);
47+
strncpy((char *)product_id, pid, 16);
48+
strncpy((char *)product_rev, rev, 4);
49+
}
50+
51+
// Invoked when received Test Unit Ready command.
52+
// return true allowing host to read/write this LUN e.g SD card inserted
53+
bool tud_msc_test_unit_ready_cb(uint8_t lun) {
54+
if (ejected) {
55+
tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00);
56+
return false;
57+
}
58+
return true;
59+
}
60+
61+
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
62+
// Application update block count and block size
63+
void tud_msc_capacity_cb(uint8_t lun, uint32_t *block_count, uint16_t *block_size) {
64+
*block_size = BLOCK_SIZE;
65+
*block_count = BLOCK_COUNT;
66+
}
67+
68+
// Invoked when received Start Stop Unit command
69+
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
70+
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
71+
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) {
72+
if (load_eject) {
73+
if (start) {
74+
// load disk storage
75+
ejected = false;
76+
} else {
77+
// unload disk storage
78+
ejected = true;
79+
}
80+
}
81+
return true;
82+
}
83+
84+
// Callback invoked when received READ10 command.
85+
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
86+
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) {
87+
uint32_t count = bufsize / BLOCK_SIZE;
88+
memcpy(buffer, (void *)(FLASH_MMAP_ADDR + lba * BLOCK_SIZE), count * BLOCK_SIZE);
89+
return count * BLOCK_SIZE;
90+
}
91+
92+
// Callback invoked when received WRITE10 command.
93+
// Process data in buffer to disk's storage and return number of written bytes
94+
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) {
95+
uint32_t count = bufsize / BLOCK_SIZE;
96+
uint32_t ints = save_and_disable_interrupts();
97+
flash_range_erase(FLASH_BASE_ADDR + lba * BLOCK_SIZE, count * BLOCK_SIZE);
98+
flash_range_program(FLASH_BASE_ADDR + lba * BLOCK_SIZE, buffer, count * BLOCK_SIZE);
99+
restore_interrupts(ints);
100+
return count * BLOCK_SIZE;
101+
}
102+
103+
// Callback invoked when received an SCSI command not in built-in list below
104+
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
105+
// - READ10 and WRITE10 has their own callbacks
106+
int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void *buffer, uint16_t bufsize) {
107+
int32_t resplen = 0;
108+
switch (scsi_cmd[0]) {
109+
case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
110+
// Sync the logical unit if needed.
111+
break;
112+
113+
default:
114+
// Set Sense = Invalid Command Operation
115+
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
116+
// negative means error -> tinyusb could stall and/or response with failed status
117+
resplen = -1;
118+
break;
119+
}
120+
return resplen;
121+
}
122+
#endif

ports/rp2/rp2_flash.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,13 +94,19 @@ STATIC mp_obj_t rp2_flash_writeblocks(size_t n_args, const mp_obj_t *args) {
9494
uint32_t offset = mp_obj_get_int(args[1]) * BLOCK_SIZE_BYTES;
9595
mp_buffer_info_t bufinfo;
9696
mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
97+
#if MICROPY_HW_USB_MSC
98+
uint32_t ints = save_and_disable_interrupts();
99+
#endif
97100
if (n_args == 3) {
98101
flash_range_erase(self->flash_base + offset, bufinfo.len);
99102
// TODO check return value
100103
} else {
101104
offset += mp_obj_get_int(args[3]);
102105
}
103106
flash_range_program(self->flash_base + offset, bufinfo.buf, bufinfo.len);
107+
#if MICROPY_HW_USB_MSC
108+
restore_interrupts(ints);
109+
#endif
104110
// TODO check return value
105111
return mp_const_none;
106112
}
@@ -122,7 +128,13 @@ STATIC mp_obj_t rp2_flash_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_
122128
return MP_OBJ_NEW_SMALL_INT(BLOCK_SIZE_BYTES);
123129
case MP_BLOCKDEV_IOCTL_BLOCK_ERASE: {
124130
uint32_t offset = mp_obj_get_int(arg_in) * BLOCK_SIZE_BYTES;
131+
#if MICROPY_HW_USB_MSC
132+
uint32_t ints = save_and_disable_interrupts();
133+
#endif
125134
flash_range_erase(self->flash_base + offset, BLOCK_SIZE_BYTES);
135+
#if MICROPY_HW_USB_MSC
136+
restore_interrupts(ints);
137+
#endif
126138
// TODO check return value
127139
return MP_OBJ_NEW_SMALL_INT(0);
128140
}

ports/rp2/tusb_config.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,20 @@
2525
#ifndef MICROPY_INCLUDED_RP2_TUSB_CONFIG_H
2626
#define MICROPY_INCLUDED_RP2_TUSB_CONFIG_H
2727

28+
#include "mpconfigboard.h"
29+
2830
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE)
2931

3032
#define CFG_TUD_CDC (1)
3133
#define CFG_TUD_CDC_RX_BUFSIZE (256)
3234
#define CFG_TUD_CDC_TX_BUFSIZE (256)
3335

36+
#if MICROPY_HW_USB_MSC
37+
// Board and hardware specific configuration
38+
#define CFG_TUD_MSC (1)
39+
// This must match both the FLASH_SECTOR_SIZE and FATFS_MAX_SS
40+
// Use 4096 to avoid caching.
41+
#define CFG_TUD_MSC_BUFSIZE (4096)
42+
#endif
43+
3444
#endif // MICROPY_INCLUDED_RP2_TUSB_CONFIG_H

ports/rp2/tusb_port.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,23 +30,36 @@
3030
#define USBD_VID (0x2E8A) // Raspberry Pi
3131
#define USBD_PID (0x0005) // RP2 MicroPython
3232

33+
#if CFG_TUD_MSC
34+
#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_MSC_DESC_LEN)
35+
#else
3336
#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
37+
#endif
3438
#define USBD_MAX_POWER_MA (250)
3539

3640
#define USBD_ITF_CDC (0) // needs 2 interfaces
41+
#define USBD_ITF_MSC (2)
42+
#if CFG_TUD_MSC
43+
#define USBD_ITF_MAX (3)
44+
#else
3745
#define USBD_ITF_MAX (2)
46+
#endif
3847

3948
#define USBD_CDC_EP_CMD (0x81)
4049
#define USBD_CDC_EP_OUT (0x02)
4150
#define USBD_CDC_EP_IN (0x82)
4251
#define USBD_CDC_CMD_MAX_SIZE (8)
4352
#define USBD_CDC_IN_OUT_MAX_SIZE (64)
4453

54+
#define EPNUM_MSC_OUT (0x03)
55+
#define EPNUM_MSC_IN (0x83)
56+
4557
#define USBD_STR_0 (0x00)
4658
#define USBD_STR_MANUF (0x01)
4759
#define USBD_STR_PRODUCT (0x02)
4860
#define USBD_STR_SERIAL (0x03)
4961
#define USBD_STR_CDC (0x04)
62+
#define USBD_STR_MSC (0x05)
5063

5164
// Note: descriptors returned from callbacks must exist long enough for transfer to complete
5265

@@ -73,13 +86,19 @@ static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = {
7386

7487
TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD,
7588
USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT, USBD_CDC_EP_IN, USBD_CDC_IN_OUT_MAX_SIZE),
89+
#if CFG_TUD_MSC
90+
TUD_MSC_DESCRIPTOR(USBD_ITF_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 64),
91+
#endif
7692
};
7793

7894
static const char *const usbd_desc_str[] = {
7995
[USBD_STR_MANUF] = "MicroPython",
8096
[USBD_STR_PRODUCT] = "Board in FS mode",
8197
[USBD_STR_SERIAL] = NULL, // generated dynamically
8298
[USBD_STR_CDC] = "Board CDC",
99+
#if CFG_TUD_MSC
100+
[USBD_STR_MSC] = "Board MSC",
101+
#endif
83102
};
84103

85104
const uint8_t *tud_descriptor_device_cb(void) {

0 commit comments

Comments
 (0)
0