Skip to content

Commit 4adbd23

Browse files
committed
stm: Add sdioio support for feather_stm32f405_express
Currently, only the bus specs of the stm32f405xx have been coded. Other stm-family chips need (at a minimum) the specs added in their periph.[ch] files.
1 parent d30f111 commit 4adbd23

File tree

10 files changed

+463
-1
lines changed

10 files changed

+463
-1
lines changed

ports/stm/boards/feather_stm32f405_express/pins.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
1+
#include "py/objtuple.h"
12
#include "shared-bindings/board/__init__.h"
23

4+
const mp_rom_obj_tuple_t sdio_data_tuple = {
5+
{&mp_type_tuple},
6+
4,
7+
{
8+
MP_ROM_PTR(&pin_PC08),
9+
MP_ROM_PTR(&pin_PC09),
10+
MP_ROM_PTR(&pin_PC10),
11+
MP_ROM_PTR(&pin_PC11),
12+
}
13+
};
14+
315
STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
416
{ MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PA04) },
517
{ MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PA05) },
@@ -31,5 +43,9 @@ STATIC const mp_rom_map_elem_t board_module_globals_table[] = {
3143
{ MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) },
3244
{ MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) },
3345
{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) },
46+
47+
{ MP_ROM_QSTR(MP_QSTR_SDIO_CLOCK), MP_ROM_PTR(&pin_PC12) },
48+
{ MP_ROM_QSTR(MP_QSTR_SDIO_COMMAND), MP_ROM_PTR(&pin_PD02) },
49+
{ MP_ROM_QSTR(MP_QSTR_SDIO_DATA), MP_ROM_PTR(&sdio_data_tuple) },
3450
};
3551
MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table);

ports/stm/common-hal/busio/SPI.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ STATIC int check_pins(busio_spi_obj_t *self,
169169
if (spi_taken) {
170170
mp_raise_ValueError(translate("Hardware busy, try alternative pins"));
171171
} else {
172-
mp_raise_ValueError(translate("Invalid SPI pin selection"));
172+
mp_raise_ValueError_varg(translate("Invalid %q pin selection"), MP_QSTR_SPI);
173173
}
174174
}
175175

ports/stm/common-hal/sdioio/SDCard.c

Lines changed: 356 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,356 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2020 Jeff Epler for Adafruit Industries
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
#include <stdbool.h>
27+
28+
#include "shared-bindings/sdioio/SDCard.h"
29+
#include "py/mperrno.h"
30+
#include "py/runtime.h"
31+
32+
#include "shared-bindings/microcontroller/__init__.h"
33+
#include "shared-bindings/util.h"
34+
#include "boards/board.h"
35+
#include "supervisor/shared/translate.h"
36+
#include "common-hal/microcontroller/Pin.h"
37+
38+
#ifndef DEBUG_SDIO
39+
#define DEBUG_SDIO (0)
40+
#endif
41+
42+
#if DEBUG_SDIO
43+
#define DEBUG_PRINT(...) ((void)mp_printf(&mp_plat_print, __VA_ARGS__))
44+
#else
45+
#define DEBUG_PRINT(...) ((void)0)
46+
#endif
47+
48+
STATIC bool reserved_sdio[MP_ARRAY_SIZE(mcu_sdio_banks)];
49+
STATIC bool never_reset_sdio[MP_ARRAY_SIZE(mcu_sdio_banks)];
50+
51+
STATIC const mcu_periph_obj_t *find_pin_function(const mcu_periph_obj_t *table, size_t sz, const mcu_pin_obj_t *pin, int periph_index) {
52+
for(size_t i = 0; i<sz; i++, table++) {
53+
if(periph_index == table->periph_index && pin == table->pin ) {
54+
return table;
55+
}
56+
}
57+
return NULL;
58+
}
59+
60+
//match pins to SDIO objects
61+
STATIC int check_pins(sdioio_sdcard_obj_t *self,
62+
const mcu_pin_obj_t * clock, const mcu_pin_obj_t * command,
63+
uint8_t num_data, mcu_pin_obj_t ** data) {
64+
bool sdio_taken = false;
65+
66+
const uint8_t sdio_clock_len = MP_ARRAY_SIZE(mcu_sdio_clock_list);
67+
const uint8_t sdio_command_len = MP_ARRAY_SIZE(mcu_sdio_command_list);
68+
const uint8_t sdio_data0_len = MP_ARRAY_SIZE(mcu_sdio_data0_list);
69+
const uint8_t sdio_data1_len = MP_ARRAY_SIZE(mcu_sdio_data1_list);
70+
const uint8_t sdio_data2_len = MP_ARRAY_SIZE(mcu_sdio_data2_list);
71+
const uint8_t sdio_data3_len = MP_ARRAY_SIZE(mcu_sdio_data3_list);
72+
73+
74+
// Loop over each possibility for clock. Check whether all other pins can
75+
// be used on the same peripheral
76+
for (uint i = 0; i < sdio_clock_len; i++) {
77+
const mcu_periph_obj_t *mcu_sdio_clock = &mcu_sdio_clock_list[i];
78+
if (mcu_sdio_clock->pin != clock) {
79+
continue;
80+
}
81+
82+
int periph_index = mcu_sdio_clock->periph_index;
83+
84+
const mcu_periph_obj_t *mcu_sdio_command = NULL;
85+
if (!(mcu_sdio_command = find_pin_function(mcu_sdio_command_list, sdio_command_len, command, periph_index))) {
86+
continue;
87+
}
88+
89+
const mcu_periph_obj_t *mcu_sdio_data0 = NULL;
90+
if(!(mcu_sdio_data0 = find_pin_function(mcu_sdio_data0_list, sdio_data0_len, data[0], periph_index))) {
91+
continue;
92+
}
93+
94+
const mcu_periph_obj_t *mcu_sdio_data1 = NULL;
95+
if(num_data > 1 && !(mcu_sdio_data1 = find_pin_function(mcu_sdio_data1_list, sdio_data1_len, data[1], periph_index))) {
96+
continue;
97+
}
98+
99+
const mcu_periph_obj_t *mcu_sdio_data2 = NULL;
100+
if(num_data > 2 && !(mcu_sdio_data2 = find_pin_function(mcu_sdio_data2_list, sdio_data2_len, data[2], periph_index))) {
101+
continue;
102+
}
103+
104+
const mcu_periph_obj_t *mcu_sdio_data3 = NULL;
105+
if(num_data > 3 && !(mcu_sdio_data3 = find_pin_function(mcu_sdio_data3_list, sdio_data3_len, data[3], periph_index))) {
106+
continue;
107+
}
108+
109+
if (reserved_sdio[periph_index-1]) {
110+
sdio_taken = true;
111+
continue;
112+
}
113+
114+
self->clock = mcu_sdio_clock;
115+
self->command = mcu_sdio_command;
116+
self->data[0] = mcu_sdio_data0;
117+
self->data[1] = mcu_sdio_data1;
118+
self->data[2] = mcu_sdio_data2;
119+
self->data[3] = mcu_sdio_data3;
120+
121+
return periph_index;
122+
}
123+
124+
if (sdio_taken) {
125+
mp_raise_ValueError(translate("Hardware busy, try alternative pins"));
126+
} else {
127+
mp_raise_ValueError_varg(translate("Invalid %q pin selection"), MP_QSTR_SDIO);
128+
}
129+
}
130+
131+
132+
void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self,
133+
const mcu_pin_obj_t * clock, const mcu_pin_obj_t * command,
134+
uint8_t num_data, mcu_pin_obj_t ** data, uint32_t frequency) {
135+
136+
int periph_index = check_pins(self, clock, command, num_data, data);
137+
SDIO_TypeDef * SDIOx = mcu_sdio_banks[periph_index - 1];
138+
139+
GPIO_InitTypeDef GPIO_InitStruct = {0};
140+
141+
// /* GPIOC and GPIOD Periph clock enable */
142+
// RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD | SD_DETECT_GPIO_CLK, ENABLE);
143+
144+
/* Configure data PC.08, PC.09, PC.10, PC.11 pins: D0, D1, D2, D3 pins */
145+
for (int i=0; i<num_data; i++) {
146+
GPIO_InitStruct.Pin = pin_mask(data[i]->number);
147+
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
148+
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
149+
GPIO_InitStruct.Pull = GPIO_PULLUP;
150+
GPIO_InitStruct.Alternate = self->data[i]->altfn_index;
151+
HAL_GPIO_Init(pin_port(data[i]->port), &GPIO_InitStruct);
152+
}
153+
154+
/* Configure PD.02 CMD line */
155+
GPIO_InitStruct.Alternate = self->command->altfn_index;
156+
GPIO_InitStruct.Pin = pin_mask(command->number);
157+
HAL_GPIO_Init(pin_port(command->port), &GPIO_InitStruct);
158+
159+
/* Configure PC.12 pin: CLK pin */
160+
GPIO_InitStruct.Alternate = self->clock->altfn_index;
161+
GPIO_InitStruct.Pin = pin_mask(clock->number);
162+
HAL_GPIO_Init(pin_port(clock->port), &GPIO_InitStruct);
163+
164+
// XXX hard coded pin
165+
#define SD_DETECT_PIN GPIO_PIN_12
166+
#define SD_DETECT_GPIO_PORT GPIOB
167+
168+
/*!< Configure SD_SPI_DETECT_PIN pin: SD Card detect pin */
169+
GPIO_InitStruct.Pin = SD_DETECT_PIN;
170+
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
171+
GPIO_InitStruct.Pull = GPIO_PULLUP;
172+
HAL_GPIO_Init(SD_DETECT_GPIO_PORT, &GPIO_InitStruct);
173+
174+
__HAL_RCC_SDIO_CLK_ENABLE();
175+
176+
self->handle.Init.ClockDiv = SDIO_TRANSFER_CLK_DIV;
177+
self->handle.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
178+
self->handle.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
179+
self->handle.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
180+
self->handle.Init.BusWide = SDIO_BUS_WIDE_1B;
181+
self->handle.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
182+
self->handle.Instance = SDIOx;
183+
184+
HAL_StatusTypeDef r = HAL_SD_Init(&self->handle);
185+
if (r != HAL_OK) {
186+
mp_raise_ValueError_varg(translate("SDIO Init Error %d"), (int)r);
187+
}
188+
189+
HAL_SD_CardInfoTypeDef info;
190+
r = HAL_SD_GetCardInfo(&self->handle, &info);
191+
if (r != HAL_OK) {
192+
mp_raise_ValueError_varg(translate("SDIO GetCardInfo Error %d"), (int)r);
193+
}
194+
195+
self->num_data = 1;
196+
if (num_data == 4) {
197+
if ((r = HAL_SD_ConfigWideBusOperation(&self->handle, SDIO_BUS_WIDE_4B)) == HAL_SD_ERROR_NONE) {
198+
DEBUG_PRINT("Switched bus to 4B mode\n");
199+
self->handle.Init.BusWide = SDIO_BUS_WIDE_4B;
200+
self->num_data = 4;
201+
} else {
202+
DEBUG_PRINT("WideBus_Enable returned %r, leaving at 1B mode\n", (int)r);
203+
}
204+
}
205+
206+
self->capacity = info.BlockNbr * (info.BlockSize / 512);
207+
self->frequency = 25000000;
208+
209+
reserved_sdio[periph_index - 1] = true;
210+
211+
return;
212+
}
213+
214+
uint32_t common_hal_sdioio_sdcard_get_count(sdioio_sdcard_obj_t *self) {
215+
return self->capacity;
216+
}
217+
218+
uint32_t common_hal_sdioio_sdcard_get_frequency(sdioio_sdcard_obj_t *self) {
219+
return self->frequency; // self->frequency;
220+
}
221+
222+
uint8_t common_hal_sdioio_sdcard_get_width(sdioio_sdcard_obj_t *self) {
223+
return self->num_data; // self->width;
224+
}
225+
226+
STATIC void check_whole_block(mp_buffer_info_t *bufinfo) {
227+
if (bufinfo->len % 512) {
228+
mp_raise_ValueError(translate("Buffer must be a multiple of 512 bytes"));
229+
}
230+
}
231+
232+
STATIC void wait_write_complete(sdioio_sdcard_obj_t *self) {
233+
if (self->state_programming) {
234+
HAL_SD_CardStateTypedef st = HAL_SD_CARD_PROGRAMMING;
235+
// This waits up to 60s for programming to complete. This seems like
236+
// an extremely long time, but this is the timeout that micropython's
237+
// implementation uses
238+
for (int i=0; i < 60000 && st == HAL_SD_CARD_PROGRAMMING; i++) {
239+
st = HAL_SD_GetCardState(&self->handle);
240+
HAL_Delay(1);
241+
};
242+
self->state_programming = false;
243+
}
244+
}
245+
246+
STATIC void debug_print_state(sdioio_sdcard_obj_t *self, const char *what) {
247+
#if DEBUG_SDIO
248+
HAL_SD_CardStateTypedef st = HAL_SD_GetCardState(&self->handle);
249+
DEBUG_PRINT("%s, st=0x%x State=0x%x ErrorCode=0x%x\n", what, (int)st, self->handle.State, self->handle.ErrorCode);
250+
#endif
251+
}
252+
253+
STATIC void check_for_deinit(sdioio_sdcard_obj_t *self) {
254+
if (common_hal_sdioio_sdcard_deinited(self)) {
255+
raise_deinited_error();
256+
}
257+
}
258+
259+
int common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) {
260+
check_for_deinit(self);
261+
check_whole_block(bufinfo);
262+
wait_write_complete(self);
263+
self->state_programming = true;
264+
common_hal_mcu_disable_interrupts();
265+
HAL_StatusTypeDef r = HAL_SD_WriteBlocks(&self->handle, bufinfo->buf, start_block, bufinfo->len / 512, 1000);
266+
common_hal_mcu_enable_interrupts();
267+
if (r != HAL_OK) {
268+
debug_print_state(self, "after writeblocks error");
269+
return -EIO;
270+
}
271+
// debug_print_state(self, "after writeblocks OK");
272+
// debug_print_state(self, "after writeblocks complete");
273+
return 0;
274+
}
275+
276+
int common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) {
277+
check_for_deinit(self);
278+
check_whole_block(bufinfo);
279+
wait_write_complete(self);
280+
common_hal_mcu_disable_interrupts();
281+
HAL_StatusTypeDef r = HAL_SD_ReadBlocks(&self->handle, bufinfo->buf, start_block, bufinfo->len / 512, 1000);
282+
common_hal_mcu_enable_interrupts();
283+
if (r != HAL_OK) {
284+
debug_print_state(self, "after readblocks error");
285+
return -EIO;
286+
}
287+
return 0;
288+
}
289+
290+
bool common_hal_sdioio_sdcard_configure(sdioio_sdcard_obj_t *self, uint32_t frequency, uint8_t bits) {
291+
check_for_deinit(self);
292+
return true;
293+
}
294+
295+
bool common_hal_sdioio_sdcard_deinited(sdioio_sdcard_obj_t *self) {
296+
return self->command == NULL;
297+
}
298+
299+
STATIC void never_reset_mcu_periph(const mcu_periph_obj_t *periph) {
300+
if (periph) {
301+
never_reset_pin_number(periph->pin->port,periph->pin->number);
302+
}
303+
}
304+
305+
STATIC void reset_mcu_periph(const mcu_periph_obj_t *periph) {
306+
if (periph) {
307+
reset_pin_number(periph->pin->port,periph->pin->number);
308+
}
309+
}
310+
311+
void common_hal_sdioio_sdcard_deinit(sdioio_sdcard_obj_t *self) {
312+
if (common_hal_sdioio_sdcard_deinited(self)) {
313+
return;
314+
}
315+
316+
reserved_sdio[self->command->periph_index - 1] = false;
317+
never_reset_sdio[self->command->periph_index - 1] = false;
318+
319+
reset_mcu_periph(self->command);
320+
self->command = NULL;
321+
322+
reset_mcu_periph(self->clock);
323+
self->command = NULL;
324+
325+
for (size_t i=0; i<MP_ARRAY_SIZE(self->data); i++) {
326+
reset_mcu_periph(self->data[i]);
327+
self->data[i] = NULL;
328+
}
329+
}
330+
331+
void common_hal_sdioio_sdcard_never_reset(sdioio_sdcard_obj_t *self) {
332+
if (common_hal_sdioio_sdcard_deinited(self)) {
333+
return;
334+
}
335+
336+
if (never_reset_sdio[self->command->periph_index] - 1) {
337+
return;
338+
}
339+
340+
never_reset_sdio[self->command->periph_index - 1] = true;
341+
342+
never_reset_mcu_periph(self->command);
343+
never_reset_mcu_periph(self->clock);
344+
345+
for (size_t i=0; i<MP_ARRAY_SIZE(self->data); i++) {
346+
never_reset_mcu_periph(self->data[i]);
347+
}
348+
}
349+
350+
void sdioio_reset() {
351+
for (size_t i=0; i<MP_ARRAY_SIZE(reserved_sdio); i++) {
352+
if (!never_reset_sdio[i]) {
353+
reserved_sdio[i] = false;
354+
}
355+
}
356+
}

0 commit comments

Comments
 (0)