Skip to content

Commit 99f91e8

Browse files
committed
add Adafruit_USBH_MSC_BlockDevice which implement SdFat FsBlockDeviceInterface API
add Adafruit_USBH_MSC.c/h, add msc_file_explorer example
1 parent 32e0862 commit 99f91e8

File tree

5 files changed

+365
-0
lines changed

5 files changed

+365
-0
lines changed

examples/DualRole/msc_file_explorer/.feather_rp2040_tinyusb.test.only

Whitespace-only changes.
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/*********************************************************************
2+
Adafruit invests time and resources providing this open source code,
3+
please support Adafruit and open-source hardware by purchasing
4+
products from Adafruit!
5+
6+
MIT license, check LICENSE for more information
7+
Copyright (c) 2019 Ha Thach for Adafruit Industries
8+
All text above, and the splash screen below must be included in
9+
any redistribution
10+
*********************************************************************/
11+
12+
13+
/* This example demonstrates use of both device and host, where
14+
* - Device run on native usb controller (controller0)
15+
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
16+
*
17+
* Requirements:
18+
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
19+
* - 2 consecutive GPIOs: D+ is defined by HOST_PIN_DP (gpio20), D- = D+ +1 (gpio21)
20+
* - Provide VBus (5v) and GND for peripheral
21+
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
22+
*/
23+
24+
// pio-usb is required for rp2040 host
25+
#include "pio_usb.h"
26+
27+
// SdFat is required for using Adafruit_USBH_MSC_SdFatDevice
28+
#include "SdFat.h"
29+
30+
// TinyUSB lib
31+
#include "Adafruit_TinyUSB.h"
32+
33+
// Pin D+ for host, D- = D+ + 1
34+
#define HOST_PIN_DP 20
35+
36+
// Pin for enabling Host VBUS. comment out if not used
37+
#define HOST_PIN_VBUS_EN 22
38+
#define HOST_PIN_VBUS_EN_STATE 1
39+
40+
// USB Host object
41+
Adafruit_USBH_Host USBHost;
42+
43+
// USB Host MSC Block Device object which implemented API for use with SdFat
44+
Adafruit_USBH_MSC_BlockDevice msc_block_dev;
45+
46+
// file system object from SdFat
47+
FatVolume fatfs;
48+
49+
// if file system is succesfully mounted on usb block device
50+
bool is_mounted = false;
51+
52+
//--------------------------------------------------------------------+
53+
// Setup and Loop on Core0
54+
//--------------------------------------------------------------------+
55+
56+
void setup()
57+
{
58+
Serial1.begin(115200);
59+
60+
Serial.begin(115200);
61+
//while ( !Serial ) delay(10); // wait for native usb
62+
63+
Serial.println("TinyUSB Dual Device Info Example");
64+
}
65+
66+
void loop()
67+
{
68+
}
69+
70+
//--------------------------------------------------------------------+
71+
// Setup and Loop on Core1
72+
//--------------------------------------------------------------------+
73+
74+
void setup1() {
75+
//while ( !Serial ) delay(10); // wait for native usb
76+
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
77+
78+
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
79+
uint32_t cpu_hz = clock_get_hz(clk_sys);
80+
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
81+
while ( !Serial ) {
82+
delay(10); // wait for native usb
83+
}
84+
Serial.printf("Error: CPU Clock = %u, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
85+
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n", cpu_hz);
86+
while(1) {
87+
delay(1);
88+
}
89+
}
90+
91+
#ifdef HOST_PIN_VBUS_EN
92+
pinMode(HOST_PIN_VBUS_EN, OUTPUT);
93+
digitalWrite(HOST_PIN_VBUS_EN, HOST_PIN_VBUS_EN_STATE);
94+
#endif
95+
96+
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
97+
pio_cfg.pin_dp = HOST_PIN_DP;
98+
USBHost.configure_pio_usb(1, &pio_cfg);
99+
100+
// run host stack on controller (rhport) 1
101+
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
102+
// host bit-banging processing works done in core1 to free up core0 for other works
103+
USBHost.begin(1);
104+
}
105+
106+
void loop1()
107+
{
108+
USBHost.task();
109+
}
110+
111+
//--------------------------------------------------------------------+
112+
// TinyUSB Host callbacks
113+
//--------------------------------------------------------------------+
114+
115+
// Invoked when device is mounted (configured)
116+
void tuh_mount_cb (uint8_t daddr)
117+
{
118+
(void) daddr;
119+
}
120+
121+
/// Invoked when device is unmounted (bus reset/unplugged)
122+
void tuh_umount_cb(uint8_t daddr)
123+
{
124+
(void) daddr;
125+
}
126+
127+
// Invoked when a device with MassStorage interface is mounted
128+
void tuh_msc_mount_cb(uint8_t dev_addr)
129+
{
130+
// Initialize block device with MSC device address
131+
msc_block_dev.begin(dev_addr);
132+
133+
// For simplicity this example only support LUN 0
134+
msc_block_dev.setActiveLUN(0);
135+
136+
is_mounted = fatfs.begin(&msc_block_dev);
137+
138+
if (is_mounted) {
139+
fatfs.ls(&Serial, LS_SIZE);
140+
}
141+
}
142+
143+
// Invoked when a device with MassStorage interface is unmounted
144+
void tuh_msc_umount_cb(uint8_t dev_addr)
145+
{
146+
(void) dev_addr;
147+
148+
// unmount file system
149+
is_mounted = false;
150+
fatfs.end();
151+
152+
// end block device
153+
msc_block_dev.end();
154+
}
155+

src/Adafruit_TinyUSB.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ void TinyUSB_Device_Init(uint8_t rhport);
6464
#if CFG_TUH_ENABLED
6565

6666
#include "arduino/Adafruit_USBH_Host.h"
67+
#if CFG_TUH_MSC
68+
#include "arduino/msc/Adafruit_USBH_MSC.h"
69+
#endif
6770

6871
#endif
6972

src/arduino/msc/Adafruit_USBH_MSC.cpp

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2022 Ha Thach (tinyusb.org) for Adafruit Industries
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_option.h"
26+
27+
#if CFG_TUH_ENABLED && CFG_TUH_MSC
28+
29+
#include "tusb.h"
30+
#include "Adafruit_USBH_MSC.h"
31+
32+
#if __has_include("SdFat.h")
33+
34+
Adafruit_USBH_MSC_BlockDevice::Adafruit_USBH_MSC_BlockDevice() {
35+
_daddr = _lun = 0;
36+
_busy = false;
37+
}
38+
39+
bool Adafruit_USBH_MSC_BlockDevice::begin(uint8_t dev_addr) {
40+
_daddr = dev_addr;
41+
return true;
42+
}
43+
44+
bool Adafruit_USBH_MSC_BlockDevice::setActiveLUN(uint8_t lun) {
45+
_lun = lun;
46+
return true;
47+
}
48+
49+
void Adafruit_USBH_MSC_BlockDevice::end(void) {
50+
_daddr = _lun = 0;
51+
}
52+
53+
bool Adafruit_USBH_MSC_BlockDevice::mounted(void) {
54+
return _daddr > 0;
55+
}
56+
57+
bool Adafruit_USBH_MSC_BlockDevice::isBusy(void) {
58+
return _busy;
59+
}
60+
61+
bool Adafruit_USBH_MSC_BlockDevice::wait_for_io(void) {
62+
while (_busy) {
63+
tuh_task();
64+
}
65+
66+
return true;
67+
}
68+
69+
bool Adafruit_USBH_MSC_BlockDevice::_io_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data) {
70+
if (dev_addr != _daddr) {
71+
// something wrong occurred, maybe device removed while transferring
72+
return false;
73+
}
74+
75+
// TODO skip csw status: assuming io is successful
76+
_busy = false;
77+
return true;
78+
}
79+
80+
static bool _msc_io_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data) {
81+
Adafruit_USBH_MSC_BlockDevice* sdfat_dev = (Adafruit_USBH_MSC_BlockDevice*) cb_data->user_arg;
82+
sdfat_dev->_io_complete_cb(dev_addr, cb_data);
83+
return true;
84+
}
85+
86+
uint32_t Adafruit_USBH_MSC_BlockDevice::sectorCount(void) {
87+
return tuh_msc_get_block_count(_daddr, _lun);
88+
}
89+
90+
bool Adafruit_USBH_MSC_BlockDevice::syncDevice(void) {
91+
// no caching
92+
return true;
93+
}
94+
95+
bool Adafruit_USBH_MSC_BlockDevice::readSectors(uint32_t block, uint8_t *dst, size_t ns) {
96+
_busy = true;
97+
if( tuh_msc_read10(_daddr, _lun, dst, block, (uint16_t) ns, _msc_io_complete_cb, (uintptr_t) this) ) {
98+
wait_for_io();
99+
return true;
100+
}else {
101+
_busy = false;
102+
return false;
103+
}
104+
}
105+
106+
bool Adafruit_USBH_MSC_BlockDevice::writeSectors(uint32_t block, const uint8_t *src, size_t ns) {
107+
_busy = true;
108+
if( tuh_msc_write10(_daddr, _lun, src, block, (uint16_t) ns, _msc_io_complete_cb, (uintptr_t) this) ) {
109+
wait_for_io();
110+
return true;
111+
}else {
112+
_busy = false;
113+
return false;
114+
}
115+
}
116+
117+
bool Adafruit_USBH_MSC_BlockDevice::readSector(uint32_t block, uint8_t *dst) {
118+
return readSectors(block, dst, 1);
119+
}
120+
121+
bool Adafruit_USBH_MSC_BlockDevice::writeSector(uint32_t block, const uint8_t *src) {
122+
return writeSectors(block, src, 1);
123+
}
124+
125+
#endif
126+
127+
//--------------------------------------------------------------------+
128+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
129+
//--------------------------------------------------------------------+
130+
131+
132+
//------------- IMPLEMENTATION -------------//
133+
134+
135+
#endif

src/arduino/msc/Adafruit_USBH_MSC.h

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2022 Ha Thach (tinyusb.org) for Adafruit Industries
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+
#ifndef ADAFRUIT_USBH_MSC_H_
26+
#define ADAFRUIT_USBH_MSC_H_
27+
28+
#include "tusb.h"
29+
30+
// define SdFat host helper class if SdFat library is available
31+
#if __has_include("SdFat.h")
32+
33+
#include "SdFat.h"
34+
35+
class Adafruit_USBH_MSC_BlockDevice : public FsBlockDeviceInterface {
36+
public:
37+
Adafruit_USBH_MSC_BlockDevice();
38+
39+
bool begin(uint8_t dev_addr);
40+
void end(void);
41+
42+
// Set active LUN
43+
bool setActiveLUN(uint8_t lun);
44+
45+
bool mounted(void);
46+
47+
//------------- SdFat v2 FsBlockDeviceInterface API -------------//
48+
virtual bool isBusy();
49+
virtual uint32_t sectorCount();
50+
virtual bool syncDevice();
51+
52+
virtual bool readSector(uint32_t block, uint8_t *dst);
53+
virtual bool readSectors(uint32_t block, uint8_t *dst, size_t ns);
54+
virtual bool writeSector(uint32_t block, const uint8_t *src);
55+
virtual bool writeSectors(uint32_t block, const uint8_t *src, size_t ns);
56+
57+
//------------- Internal APIs -------------//
58+
bool _io_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data);
59+
60+
private:
61+
uint8_t _daddr;
62+
uint8_t _lun;
63+
64+
// TODO use mutex to prevent race condition or atomic for better implementation
65+
volatile bool _busy;
66+
67+
bool wait_for_io(void);
68+
};
69+
70+
#endif
71+
72+
#endif

0 commit comments

Comments
 (0)