Skip to content

Commit ad0a91e

Browse files
committed
Add support for the sdio peripheral
Initial support for the sdio peripheral found on the stm32f4 devices. Supports single block transfers and SDHC cards.
1 parent 24286fa commit ad0a91e

File tree

5 files changed

+1053
-0
lines changed

5 files changed

+1053
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1111

1212
- Implement `timer::Cancel` trait for `Timer<TIM>`.
1313
- Added DWT cycle counter based delay and stopwatch, including an example.
14+
- Added sdio driver
1415

1516
## [v0.8.0] - 2020-04-30
1617

Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ ssd1306 = "0.2.6"
5959
embedded-graphics = "0.4.9"
6060
usb-device = "0.2.5"
6161
usbd-serial = "0.1.0"
62+
usbd_scsi = "0.1.0"
63+
usbd_mass_storage = "0.1.0"
64+
rtt-target = {version = "0.1.1", features = ["cortex-m"]}
65+
panic-rtt-target = { version = "0.1", features = ["cortex-m"] }
6266

6367
[features]
6468
device-selected = []
@@ -97,6 +101,10 @@ opt-level = "s"
97101
name = "usb_serial"
98102
required-features = ["rt", "stm32f401", "usb_fs"]
99103

104+
[[example]]
105+
name = "sdio-usb-block"
106+
required-features = ["rt", "stm32f405", "usb_fs"]
107+
100108
[[example]]
101109
name = "delay-blinky"
102110
required-features = ["rt", "stm32f411"]

examples/sdio-usb-block.rs

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
use cortex_m_rt::entry;
5+
use stm32f4xx_hal as hal;
6+
7+
use panic_rtt_target as _;
8+
use rtt_target::{rprintln, rtt_init_print};
9+
10+
use hal::interrupt;
11+
use hal::sdio::Sdio;
12+
use hal::{prelude::*, stm32};
13+
14+
use cortex_m::peripheral::NVIC;
15+
use stm32f4xx_hal::otg_fs::{UsbBus, UsbBusType, USB};
16+
use usb_device::bus::UsbBusAllocator;
17+
use usb_device::prelude::*;
18+
19+
use core::cell::RefCell;
20+
use cortex_m::interrupt::Mutex;
21+
22+
use usbd_mass_storage;
23+
use usbd_scsi::{BlockDevice, BlockDeviceError, Scsi};
24+
25+
static mut EP_MEMORY: [u32; 1024] = [0; 1024];
26+
static mut USB_BUS: Option<UsbBusAllocator<UsbBusType>> = None;
27+
28+
static USB_DEV: Mutex<RefCell<Option<UsbDevice<UsbBusType>>>> = Mutex::new(RefCell::new(None));
29+
static USB_STORAGE: Mutex<RefCell<Option<usbd_scsi::Scsi<UsbBusType, Storage>>>> =
30+
Mutex::new(RefCell::new(None));
31+
32+
struct Storage {
33+
sdio: Sdio,
34+
}
35+
36+
impl BlockDevice for Storage {
37+
const BLOCK_BYTES: usize = 512;
38+
39+
fn read_block(&self, lba: u32, block: &mut [u8]) -> Result<(), BlockDeviceError> {
40+
self.sdio.read_block(lba, block).map_err(|e| {
41+
rprintln!("read error: {:?}", e);
42+
BlockDeviceError::HardwareError
43+
})
44+
}
45+
46+
fn write_block(&mut self, lba: u32, block: &[u8]) -> Result<(), BlockDeviceError> {
47+
self.sdio.write_block(lba, block).map_err(|e| {
48+
rprintln!("write error: {:?}", e);
49+
BlockDeviceError::WriteError
50+
})
51+
}
52+
53+
fn max_lba(&self) -> u32 {
54+
self.sdio.card().map(|c| c.block_count() - 1).unwrap_or(0)
55+
}
56+
}
57+
58+
#[entry]
59+
fn main() -> ! {
60+
rtt_init_print!(BlockIfFull);
61+
62+
let device = stm32::Peripherals::take().unwrap();
63+
let core = cortex_m::Peripherals::take().unwrap();
64+
65+
let rcc = device.RCC.constrain();
66+
let clocks = rcc
67+
.cfgr
68+
.use_hse(12.mhz())
69+
.require_pll48clk()
70+
.sysclk(168.mhz())
71+
.hclk(168.mhz())
72+
.pclk1(42.mhz())
73+
.pclk2(84.mhz())
74+
.freeze();
75+
76+
assert!(clocks.is_pll48clk_valid());
77+
78+
// Create a delay abstraction based on SysTick
79+
let mut delay = hal::delay::Delay::new(core.SYST, clocks);
80+
81+
let gpioa = device.GPIOA.split();
82+
let gpioc = device.GPIOC.split();
83+
let gpiod = device.GPIOD.split();
84+
85+
let mut red_led = {
86+
let mut led = gpioc.pc1.into_push_pull_output();
87+
let _ = led.set_low().ok();
88+
led
89+
};
90+
91+
let mut sdio = {
92+
let d0 = gpioc
93+
.pc8
94+
.into_push_pull_output()
95+
.into_alternate_af12()
96+
.internal_pull_up(true);
97+
98+
let d1 = gpioc
99+
.pc9
100+
.into_push_pull_output()
101+
.into_alternate_af12()
102+
.internal_pull_up(true);
103+
104+
let d2 = gpioc
105+
.pc10
106+
.into_push_pull_output()
107+
.into_alternate_af12()
108+
.internal_pull_up(true);
109+
110+
let d3 = gpioc
111+
.pc11
112+
.into_push_pull_output()
113+
.into_alternate_af12()
114+
.internal_pull_up(true);
115+
116+
let clk = gpioc
117+
.pc12
118+
.into_push_pull_output()
119+
.into_alternate_af12()
120+
.internal_pull_up(false);
121+
122+
let cmd = gpiod
123+
.pd2
124+
.into_push_pull_output()
125+
.into_alternate_af12()
126+
.internal_pull_up(true);
127+
128+
Sdio::new((clk, cmd, d0, d1, d2, d3))
129+
};
130+
131+
rprintln!("Waiting for card...");
132+
133+
// Loop until we have a card
134+
loop {
135+
match sdio.init_card() {
136+
Ok(_) => break,
137+
Err(err) => {
138+
rprintln!("Init err: {:?}", err);
139+
}
140+
}
141+
142+
delay.delay_ms(1000u32);
143+
red_led.toggle().ok();
144+
}
145+
146+
rprintln!("blocks: {:?}", sdio.card().map(|c| c.block_count()));
147+
148+
let sdhc = Storage { sdio };
149+
150+
unsafe {
151+
let usb = USB {
152+
usb_global: device.OTG_FS_GLOBAL,
153+
usb_device: device.OTG_FS_DEVICE,
154+
usb_pwrclk: device.OTG_FS_PWRCLK,
155+
pin_dm: gpioa.pa11.into_alternate_af10(),
156+
pin_dp: gpioa.pa12.into_alternate_af10(),
157+
};
158+
159+
let usb_bus = UsbBus::new(usb, &mut EP_MEMORY);
160+
USB_BUS = Some(usb_bus);
161+
162+
let scsi = Scsi::new(
163+
USB_BUS.as_ref().unwrap(),
164+
64,
165+
sdhc,
166+
"Fake Co.",
167+
"Fake product",
168+
"FK01",
169+
);
170+
171+
let usb_dev = UsbDeviceBuilder::new(USB_BUS.as_ref().unwrap(), UsbVidPid(0x16c0, 0x27dd))
172+
.manufacturer("Fake company")
173+
.product("SdUsb")
174+
.serial_number("TEST")
175+
.self_powered(true)
176+
.device_class(usbd_mass_storage::USB_CLASS_MSC)
177+
.build();
178+
179+
cortex_m::interrupt::free(|cs| {
180+
USB_DEV.borrow(cs).replace(Some(usb_dev));
181+
USB_STORAGE.borrow(cs).replace(Some(scsi));
182+
});
183+
};
184+
185+
unsafe {
186+
NVIC::unmask(stm32::Interrupt::OTG_FS);
187+
}
188+
189+
rprintln!("Init done");
190+
191+
loop {
192+
continue;
193+
}
194+
}
195+
196+
#[interrupt]
197+
fn OTG_FS() {
198+
usb_interrupt();
199+
}
200+
201+
fn usb_interrupt() {
202+
cortex_m::interrupt::free(|cs| {
203+
let mut dev = USB_DEV.borrow(cs).borrow_mut();
204+
let usb_dev = dev.as_mut().unwrap();
205+
206+
let mut scsi = USB_STORAGE.borrow(cs).borrow_mut();
207+
let scsi = scsi.as_mut().unwrap();
208+
209+
if !usb_dev.poll(&mut [scsi]) {
210+
return;
211+
}
212+
});
213+
}

src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ pub mod pwm;
145145
pub mod qei;
146146
#[cfg(feature = "device-selected")]
147147
pub mod rcc;
148+
#[cfg(all(
149+
feature = "device-selected",
150+
not(any(feature = "stm32f410", feature = "stm32f446",))
151+
))]
152+
pub mod sdio;
148153
#[cfg(feature = "device-selected")]
149154
pub mod serial;
150155
#[cfg(feature = "device-selected")]

0 commit comments

Comments
 (0)