From 878d65ec9f64002b7b7d152da58d11601b21ec50 Mon Sep 17 00:00:00 2001 From: Nicko van Someren Date: Sat, 4 May 2019 19:00:35 -0600 Subject: [PATCH 1/4] Initial implementation of SDCard support using the ESP32's built-in hardware SD/MMC host controller. --- ports/esp32/Makefile | 22 +++ ports/esp32/modsdcard.c | 352 +++++++++++++++++++++++++++++++++++++ ports/esp32/mpconfigport.h | 9 + 3 files changed, 383 insertions(+) create mode 100644 ports/esp32/modsdcard.c diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index ea90c9f3f5a9d..70b4b3058e0f2 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -111,6 +111,7 @@ INC_ESPCOMP += -I$(ESPCOMP)/app_trace/include INC_ESPCOMP += -I$(ESPCOMP)/app_update/include INC_ESPCOMP += -I$(ESPCOMP)/pthread/include INC_ESPCOMP += -I$(ESPCOMP)/smartconfig_ack/include +INC_ESPCOMP += -I$(ESPCOMP)/sdmmc/include # these flags are common to C and C++ compilation CFLAGS_COMMON = -Os -ffunction-sections -fdata-sections -fstrict-volatile-bitfields \ @@ -192,6 +193,7 @@ SRC_C = \ machine_wdt.c \ mpthreadport.c \ machine_rtc.c \ + modsdcard.c \ $(SRC_MOD) EXTMOD_SRC_C = $(addprefix extmod/,\ @@ -665,6 +667,23 @@ ESPIDF_WPA_SUPPLICANT_O = $(addprefix $(ESPCOMP)/wpa_supplicant/,\ port/os_xtensa.o \ ) +ESPIDF_SDMMC_O = $(addprefix $(ESPCOMP)/sdmmc/,\ + sdmmc_cmd.o \ + sdmmc_common.o \ + sdmmc_init.o \ + sdmmc_mmc.o \ + sdmmc_sd.o \ + sdmmc_io.o \ + ) \ + $(addprefix $(ESPCOMP)/driver/,\ + sdmmc_host.o \ + sdmmc_transaction.o \ + ) \ + $(addprefix $(ESPCOMP)/soc/,\ + esp32/sdmmc_periph.o \ + ) + + OBJ_ESPIDF = OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_NEWLIB_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_DRIVER_O)) @@ -693,6 +712,7 @@ OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SMARTCONFIG_ACK_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SPI_FLASH_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_ULP_O)) OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_WPA_SUPPLICANT_O)) +OBJ_ESPIDF += $(addprefix $(BUILD)/, $(ESPIDF_SDMMC_O)) $(OBJ_ESPIDF): $(SDKCONFIG_H) @@ -723,6 +743,7 @@ LIB_ESPIDF += ulp LIB_ESPIDF += lwip LIB_ESPIDF += mbedtls LIB_ESPIDF += wpa_supplicant +LIB_ESPIDF += sdmmc BUILD_ESPIDF_LIB = $(BUILD)/esp-idf @@ -763,6 +784,7 @@ $(eval $(call gen_espidf_lib_rule,ulp,$(ESPIDF_ULP_O))) $(eval $(call gen_espidf_lib_rule,lwip,$(ESPIDF_LWIP_O))) $(eval $(call gen_espidf_lib_rule,mbedtls,$(ESPIDF_MBEDTLS_O))) $(eval $(call gen_espidf_lib_rule,wpa_supplicant,$(ESPIDF_WPA_SUPPLICANT_O))) +$(eval $(call gen_espidf_lib_rule,sdmmc,$(ESPIDF_SDMMC_O))) LIB = $(foreach lib,$(LIB_ESPIDF),$(BUILD_ESPIDF_LIB)/$(lib)/lib$(lib).a) diff --git a/ports/esp32/modsdcard.c b/ports/esp32/modsdcard.c new file mode 100644 index 0000000000000..dbbad3cb1c867 --- /dev/null +++ b/ports/esp32/modsdcard.c @@ -0,0 +1,352 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Nicko van Someren + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "py/runtime.h" +#include "py/mphal.h" +#include "lib/oofatfs/ff.h" +#include "extmod/vfs_fat.h" + +#include "driver/sdmmc_host.h" +#include "driver/sdspi_host.h" +#include "sdmmc_cmd.h" +#include "esp_log.h" + +#define DEBUG 1 +#if DEBUG +#define DEBUG_printf(...) ESP_LOGI("modsdcard", __VA_ARGS__) +#else +#define DEBUG_printf(...) (0) +#endif + +// +// There are three layers of abstraction: host, slot and card. +// Creating an SD Card object will initialise the host and slot. +// The card gets initialised by ioctl op==1 and de-inited by ioctl 2 +// The host is de-inited in __del__ +// + +// Currently the ESP32 Library doesn't support MM cards, so +// we don't enable on MICROPY_HW_ENABLE_MMCARD. +#if MICROPY_HW_ENABLE_SDCARD + +// Forward declaration +const mp_obj_type_t esp32_sdcard_type; + +typedef struct _sdcard_obj_t { + mp_obj_base_t base; + mp_int_t flags; + sdmmc_host_t host; + // The card structure duplicates the host. It's not clear if we can avoid this + sdmmc_card_t card; +} sdcard_card_obj_t; + +#define SDCARD_CARD_FLAGS_HOST_INIT_DONE 0x01 +#define SDCARD_CARD_FLAGS_CARD_INIT_DONE 0x02 + +#define _SECTOR_SIZE(self) (self->card.csd.sector_size) + +STATIC esp_err_t check_esp_err(esp_err_t code) { + const mp_obj_type_t *ex_type = NULL; + + switch(code) { + case ESP_OK: + return ESP_OK; + case ESP_ERR_NO_MEM: + ex_type = &mp_type_MemoryError; + break; + case ESP_ERR_TIMEOUT: + ex_type = &mp_type_TimeoutError; + break; + case ESP_ERR_NOT_SUPPORTED: + ex_type = &mp_type_NotImplementedError; + break; + default: + mp_raise_OSError(code); + } + + mp_raise_msg(ex_type, "From ESP SDK"); +} + +STATIC esp_err_t sdcard_ensure_card_init(sdcard_card_obj_t *self, bool force) { + if (force || !(self->flags & SDCARD_CARD_FLAGS_CARD_INIT_DONE)) { + DEBUG_printf(" Calling card init"); + + esp_err_t err = sdmmc_card_init(&(self->host), &(self->card)); + if (err == ESP_OK) { + self->flags |= SDCARD_CARD_FLAGS_CARD_INIT_DONE; + } else { + self->flags &= ~SDCARD_CARD_FLAGS_CARD_INIT_DONE; + } + DEBUG_printf(" Card init returned: %i", err); + + return err; + } else { + return ESP_OK; + } +} + +/******************************************************************************/ +// MicroPython bindings +// +// Expose the SD card or MMC as an object with the block protocol. + +STATIC mp_obj_t esp32_sdcard_init() { + static int initialized = 0; + if (!initialized) { + // It might make sense to set up the host controller when the + // module is loaded, rather then when we slots are created. + + DEBUG_printf("Initialising sdcard module"); + + initialized = 1; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp32_sdcard_init_obj, esp32_sdcard_init); + + +// Create a new SDCard object +// card = SDCard(slot=1, width=None, present_pin=None, wp_pin=None) + +STATIC mp_obj_t esp32_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + // check arguments + enum { + ARG_slot, + ARG_width, + ARG_cd_pin, + ARG_wp_pin, + }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_slot, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, + { MP_QSTR_cd_pin, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, + { MP_QSTR_wp_pin, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, + }; + mp_arg_val_t arg_vals[MP_ARRAY_SIZE(allowed_args)]; + mp_map_t kw_args; + + DEBUG_printf("Making new SDCard:n"); + DEBUG_printf(" Unpacking arguments"); + + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + + mp_arg_parse_all(n_args, args, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, arg_vals); + + DEBUG_printf(" slot=%d, width=%d, cd_pin=%d, wp_pin=%d", + arg_vals[ARG_slot].u_int, arg_vals[ARG_width].u_int, + arg_vals[ARG_cd_pin].u_int, arg_vals[ARG_wp_pin].u_int); + + DEBUG_printf(" Setting up host configuration"); + + sdcard_card_obj_t *self = m_new0(sdcard_card_obj_t, 1); + self->base.type = &esp32_sdcard_type; + sdmmc_host_t _temp_host = SDMMC_HOST_DEFAULT(); + self->host = _temp_host; + + int slot_num = arg_vals[ARG_slot].u_int; + if (slot_num !=0 && slot_num != 1) + mp_raise_ValueError("Slot number must be 0 or 1"); + self->host.slot = slot_num; + + // Forcing pins into a usable state + gpio_set_pull_mode(15, GPIO_PULLUP_ONLY); // CMD, needed in 4- and 1- line modes + gpio_set_pull_mode(2, GPIO_PULLUP_ONLY); // D0, needed in 4- and 1-line modes + gpio_set_pull_mode(4, GPIO_PULLUP_ONLY); // D1, needed in 4-line mode only + gpio_set_pull_mode(12, GPIO_PULLUP_ONLY); // D2, needed in 4-line mode only + gpio_set_pull_mode(13, GPIO_PULLUP_ONLY); // D3, needed in 4- and 1-line modes + + DEBUG_printf(" Setting up slot configuration"); + + // This initializes the slot without card detect (CD) and write protect (WP) signals. + // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals. + sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); + + // TODO: Set up WP and CD pins if needed + // Do we want to require pin numbers or should we allow Pin objects too? + if (arg_vals[ARG_cd_pin].u_int != 0xffffffff || + arg_vals[ARG_wp_pin].u_int != 0xffffffff) + mp_raise_NotImplementedError("WP and CD pins not currently supported"); + + int width = arg_vals[ARG_width].u_int; + if (width != 0xffffffff) { + if (width == 1 || width == 4 || (width == 8 && slot_num == 0)) + slot_config.width = arg_vals[ARG_width].u_int; + else + mp_raise_ValueError("Width must be 1 or 4 (or 8 on slot 0)"); + } + + // Stronger external pull-ups are still needed but apparently it is a good idea to + // set the internal pull-ups anyway. + slot_config.flags = SDMMC_SLOT_FLAG_INTERNAL_PULLUP; + + DEBUG_printf(" Calling host.init()"); + + check_esp_err(self->host.init()); + self->flags |= SDCARD_CARD_FLAGS_HOST_INIT_DONE; + // TODO: Do we need to de-init the host if the slot init fails? + + DEBUG_printf(" Calling init_slot()"); + + check_esp_err(sdmmc_host_init_slot(self->host.slot, &slot_config)); + + DEBUG_printf(" Returning new card object: %p", self); + // return object + return MP_OBJ_FROM_PTR(self); +} + +STATIC mp_obj_t sd_deinit(mp_obj_t self_in) { + sdcard_card_obj_t *self = self_in; + + DEBUG_printf("De-init host\n"); + + if (self->flags & SDCARD_CARD_FLAGS_HOST_INIT_DONE) { + self->host.deinit(); + self->flags &= ~SDCARD_CARD_FLAGS_HOST_INIT_DONE; + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(sd_deinit_obj, sd_deinit); + +STATIC mp_obj_t sd_info(mp_obj_t self_in) { + sdcard_card_obj_t *self = self_in; + // TODO: Extract SD card data + + check_esp_err(sdcard_ensure_card_init((sdcard_card_obj_t *) self, false)); + + uint32_t card_type = 0; + uint32_t log_block_nbr = self->card.csd.capacity; + uint32_t log_block_size = _SECTOR_SIZE(self); + + mp_obj_t tuple[3] = { + mp_obj_new_int_from_ull((uint64_t)log_block_nbr * (uint64_t)log_block_size), + mp_obj_new_int_from_uint(log_block_size), + mp_obj_new_int(card_type), + }; + return mp_obj_new_tuple(3, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(sd_info_obj, sd_info); + + +STATIC mp_obj_t esp32_sdcard_readblocks(mp_obj_t self_in, mp_obj_t block_num, mp_obj_t buf) { + sdcard_card_obj_t *self = self_in; + mp_buffer_info_t bufinfo; + esp_err_t err; + err = sdcard_ensure_card_init((sdcard_card_obj_t *) self, false); + if (err != ESP_OK) + return false; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE); + err = sdmmc_read_sectors(&(self->card), bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / _SECTOR_SIZE(self) ); + return mp_obj_new_bool(err == ESP_OK); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_sdcard_readblocks_obj, esp32_sdcard_readblocks); + +STATIC mp_obj_t esp32_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t block_num, mp_obj_t buf) { + sdcard_card_obj_t *self = self_in; + mp_buffer_info_t bufinfo; + esp_err_t err; + err = sdcard_ensure_card_init((sdcard_card_obj_t *) self, false); + if (err != ESP_OK) + return false; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ); + err = sdmmc_write_sectors(&(self->card), bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / _SECTOR_SIZE(self) ); + return mp_obj_new_bool(err == ESP_OK); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_sdcard_writeblocks_obj, esp32_sdcard_writeblocks); + +STATIC mp_obj_t esp32_sdcard_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_in) { + sdcard_card_obj_t *self = self_in; + esp_err_t err = ESP_OK; + mp_int_t cmd = mp_obj_get_int(cmd_in); + switch (cmd) { + case BP_IOCTL_INIT: + err = sdcard_ensure_card_init(self, true); + return MP_OBJ_NEW_SMALL_INT((err == ESP_OK) ? 0 : -1); + + case BP_IOCTL_DEINIT: + // Ensure that future attempts to look at info re-read the card + self->flags &= ~SDCARD_CARD_FLAGS_CARD_INIT_DONE; + return MP_OBJ_NEW_SMALL_INT(0); // success + + case BP_IOCTL_SYNC: + // nothing to do + return MP_OBJ_NEW_SMALL_INT(0); // success + + case BP_IOCTL_SEC_COUNT: + err = sdcard_ensure_card_init(self, false); + if (err != ESP_OK) + return MP_OBJ_NEW_SMALL_INT(-1); + return MP_OBJ_NEW_SMALL_INT(self->card.csd.capacity); + + case BP_IOCTL_SEC_SIZE: + err = sdcard_ensure_card_init(self, false); + if (err != ESP_OK) + return MP_OBJ_NEW_SMALL_INT(-1); + return MP_OBJ_NEW_SMALL_INT(_SECTOR_SIZE(self)); + + default: // unknown command + return MP_OBJ_NEW_SMALL_INT(-1); // error + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_sdcard_ioctl_obj, esp32_sdcard_ioctl); + +STATIC const mp_rom_map_elem_t esp32_sdcard_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&sd_info_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&sd_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&sd_deinit_obj) }, + // block device protocol + { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&esp32_sdcard_readblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&esp32_sdcard_writeblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&esp32_sdcard_ioctl_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(esp32_sdcard_locals_dict, esp32_sdcard_locals_dict_table); + + +const mp_obj_type_t esp32_sdcard_type = { + { &mp_type_type }, + .name = MP_QSTR_SDCard, + .make_new = esp32_sdcard_make_new, + .locals_dict = (mp_obj_dict_t*)&esp32_sdcard_locals_dict, +}; + +STATIC const mp_rom_map_elem_t esp32_module_sdcard_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sdcard) }, + { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&esp32_sdcard_init_obj) }, + { MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&esp32_sdcard_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(esp32_module_sdcard_globals, esp32_module_sdcard_globals_table); + +const mp_obj_module_t mp_module_sdcard = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&esp32_module_sdcard_globals, +}; + + +#endif // MICROPY_HW_ENABLE_SDCARD diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 7b9b40025035a..01681c51a1244 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -141,6 +141,7 @@ #define MICROPY_PY_MACHINE_SPI_MSB (0) #define MICROPY_PY_MACHINE_SPI_LSB (1) #define MICROPY_PY_MACHINE_SPI_MAKE_NEW machine_hw_spi_make_new +#define MICROPY_HW_ENABLE_SDCARD (1) #define MICROPY_HW_SOFTSPI_MIN_DELAY (0) #define MICROPY_HW_SOFTSPI_MAX_BAUDRATE (ets_get_cpu_frequency() * 1000000 / 200) // roughly #define MICROPY_PY_USSL (1) @@ -178,6 +179,7 @@ extern const struct _mp_obj_module_t mp_module_usocket; extern const struct _mp_obj_module_t mp_module_machine; extern const struct _mp_obj_module_t mp_module_network; extern const struct _mp_obj_module_t mp_module_onewire; +extern const struct _mp_obj_module_t mp_module_sdcard; #define MICROPY_PORT_BUILTIN_MODULES \ { MP_OBJ_NEW_QSTR(MP_QSTR_esp), (mp_obj_t)&esp_module }, \ @@ -190,6 +192,12 @@ extern const struct _mp_obj_module_t mp_module_onewire; { MP_OBJ_NEW_QSTR(MP_QSTR__onewire), (mp_obj_t)&mp_module_onewire }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_uhashlib), (mp_obj_t)&mp_module_uhashlib }, \ +#if MICROPY_HW_ENABLE_SDCARD +#define SDCARD_BUILTIN_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_sdcard), (mp_obj_t)&mp_module_sdcard }, +#else +#define SDCARD_BUILTIN_MODULE +#endif + #define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ { MP_OBJ_NEW_QSTR(MP_QSTR_binascii), (mp_obj_t)&mp_module_ubinascii }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_collections), (mp_obj_t)&mp_module_collections }, \ @@ -201,6 +209,7 @@ extern const struct _mp_obj_module_t mp_module_onewire; { MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&uos_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_random), (mp_obj_t)&mp_module_urandom }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_re), (mp_obj_t)&mp_module_ure }, \ + SDCARD_BUILTIN_MODULE \ { MP_OBJ_NEW_QSTR(MP_QSTR_select), (mp_obj_t)&mp_module_uselect }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&mp_module_usocket }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_ssl), (mp_obj_t)&mp_module_ussl }, \ From 2805ee738bab214ec39bb3d49922f6be87c0f2f1 Mon Sep 17 00:00:00 2001 From: Nicko van Someren Date: Thu, 9 May 2019 11:11:33 -0600 Subject: [PATCH 2/4] Added support for using SD cards over SPI using the SDK. Added documentation in the esp32 module for the SDCard class. Added more thorough checks on paramter values. Moved the SDCard class from a module of its own into the esp32 module (a la the pyb.SDCard() class). --- docs/library/esp32.rst | 82 ++++++++ ports/esp32/Makefile | 29 +-- ports/esp32/{modsdcard.c => esp32_sdcard.c} | 206 ++++++++++++-------- ports/esp32/modesp32.c | 3 + ports/esp32/modesp32.h | 4 + ports/esp32/mpconfigport.h | 8 - 6 files changed, 225 insertions(+), 107 deletions(-) rename ports/esp32/{modsdcard.c => esp32_sdcard.c} (63%) diff --git a/docs/library/esp32.rst b/docs/library/esp32.rst index c934ef0954872..566b5b5ffd703 100644 --- a/docs/library/esp32.rst +++ b/docs/library/esp32.rst @@ -57,6 +57,88 @@ The Ultra-Low-Power co-processor Start the ULP running at the given *entry_point*. +SD/MMC Card interface +--------------------- + +.. class:: SDCard(slot=1, spi=false, width=1, cd=None, wp=None, sck=None, miso=None, mosi=None, cs=None) + + This class provides access to SD or MMC storage cards using either + the ESP32's dedicated SD/MMC interface hardware or through an SPI + channel using DMA for the data transfers. The class implements + that block protocol defined in the :class:`uos.AbstractBlockDev` + class. This allows the mounting of an SD card to be as simple as:: + + uos.mount(esp32.SDCard(), "/sd") + + The constrcutor takes the following paramters: + + - ``slot`` selects which of two interfaces to use. The ESP32 + provides two channels of SD/MMC hardware but it should be noted + that slot 0 is often used to communicate with on-board + flash memory on most ESP32 modules. As a result only slot 1 + will normally be available. When using SPI mode this selects + between the two hardware SPI drivers. + + - ``spi`` selects the use of an SPI interface instead of the + dedicated SD/MMC interface. + + - ``width`` selects the bus width for the SD/MMC interface. Slot + 0 supports 1, 4 or 8-bit wide access while slot 1 supports 1 ot + 4-bit access. Note that most ESP32 modules that provide an SD card slot + using the dedicated hardware only wire up 1 data pin so the + default is 1. + + - ``cd`` can be used to specify a card-detect pin. + + - ``wp`` can be used to specify a write-protect pin. + + - ``sck`` can be used to specify an SPI clock pin. + + - ``miso`` can be used to specify an SPI miso pin. + + - ``mosi`` can be used to specify an SPI mosi pin. + + - ``cs`` can be used to specify an SPI chip select pin. + + The pins used by the dedicated SD/MMC hardware are fixed; they are + assigned as follows: + + ====== ====== ====== + SD/MMC Slot 0 Slot 1 + ------ ------ ------ + Signal Pin Pin + ====== ====== ====== + cmd 11 15 + sck 6 14 + D0 7 2 + D1 8 4 + D2 9 12 + D3 10 13 + D4 16 + D5 17 + D6 5 + D7 18 + ====== ====== ====== + + The pins used by the SPI hardware can be reassigned. It should + however be noted that if any of the signals are remapped then all + of the SPI signals will pass through a GPIO multiplexer unit + which can limit the performance of high frequency signals. Since + the normal operating speed for SD cards is 40MHz this can cause + problems on some cards. The default (and preferred) pin assignment + are as follows: + + ====== ====== ====== + SPI Slot 0 Slot 1 + ------ ------ ------ + Signal Pin Pin + ====== ====== ====== + sck 18 14 + cs 5 15 + miso 19 12 + mosi 23 13 + ====== ====== ====== + Constants --------- diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 70b4b3058e0f2..c3cd499a98d2c 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -193,7 +193,7 @@ SRC_C = \ machine_wdt.c \ mpthreadport.c \ machine_rtc.c \ - modsdcard.c \ + esp32_sdcard.c \ $(SRC_MOD) EXTMOD_SRC_C = $(addprefix extmod/,\ @@ -668,20 +668,23 @@ ESPIDF_WPA_SUPPLICANT_O = $(addprefix $(ESPCOMP)/wpa_supplicant/,\ ) ESPIDF_SDMMC_O = $(addprefix $(ESPCOMP)/sdmmc/,\ - sdmmc_cmd.o \ - sdmmc_common.o \ - sdmmc_init.o \ - sdmmc_mmc.o \ - sdmmc_sd.o \ - sdmmc_io.o \ - ) \ - $(addprefix $(ESPCOMP)/driver/,\ + sdmmc_cmd.o \ + sdmmc_common.o \ + sdmmc_init.o \ + sdmmc_mmc.o \ + sdmmc_sd.o \ + sdmmc_io.o \ + ) \ + $(addprefix $(ESPCOMP)/driver/,\ sdmmc_host.o \ - sdmmc_transaction.o \ + sdmmc_transaction.o \ + sdspi_host.o \ + sdspi_transaction.o \ + sdspi_crc.o \ ) \ - $(addprefix $(ESPCOMP)/soc/,\ - esp32/sdmmc_periph.o \ - ) + $(addprefix $(ESPCOMP)/soc/,\ + esp32/sdmmc_periph.o \ + ) OBJ_ESPIDF = diff --git a/ports/esp32/modsdcard.c b/ports/esp32/esp32_sdcard.c similarity index 63% rename from ports/esp32/modsdcard.c rename to ports/esp32/esp32_sdcard.c index dbbad3cb1c867..7ead08ee61eb4 100644 --- a/ports/esp32/modsdcard.c +++ b/ports/esp32/esp32_sdcard.c @@ -28,7 +28,6 @@ #include "py/runtime.h" #include "py/mphal.h" -#include "lib/oofatfs/ff.h" #include "extmod/vfs_fat.h" #include "driver/sdmmc_host.h" @@ -36,21 +35,21 @@ #include "sdmmc_cmd.h" #include "esp_log.h" -#define DEBUG 1 +#define DEBUG 0 #if DEBUG #define DEBUG_printf(...) ESP_LOGI("modsdcard", __VA_ARGS__) #else -#define DEBUG_printf(...) (0) +#define DEBUG_printf(...) (void)0 #endif // // There are three layers of abstraction: host, slot and card. // Creating an SD Card object will initialise the host and slot. -// The card gets initialised by ioctl op==1 and de-inited by ioctl 2 -// The host is de-inited in __del__ +// Cards gets initialised by ioctl op==1 and de-inited by ioctl 2 +// Hosts are de-inited in __del__. Slots do not need de-initing. // -// Currently the ESP32 Library doesn't support MM cards, so +// Currently the ESP32 Library doesn't support MMC cards, so // we don't enable on MICROPY_HW_ENABLE_MMCARD. #if MICROPY_HW_ENABLE_SDCARD @@ -61,7 +60,8 @@ typedef struct _sdcard_obj_t { mp_obj_base_t base; mp_int_t flags; sdmmc_host_t host; - // The card structure duplicates the host. It's not clear if we can avoid this + // The card structure duplicates the host. It's not clear if we + // can avoid this given the way that it is copied. sdmmc_card_t card; } sdcard_card_obj_t; @@ -92,6 +92,18 @@ STATIC esp_err_t check_esp_err(esp_err_t code) { mp_raise_msg(ex_type, "From ESP SDK"); } +STATIC gpio_num_t pin_or_int(const mp_obj_t arg) { + if (mp_obj_is_small_int(arg)) + return MP_OBJ_SMALL_INT_VALUE(arg); + else + // This raises a value error if the argument is not a Pin. + return machine_pin_get_id(arg); +} + +#define SET_CONFIG_PIN(config, pin_var, arg_id) \ + if (arg_vals[arg_id].u_obj != mp_const_none) \ + config.pin_var = pin_or_int(arg_vals[arg_id].u_obj) + STATIC esp_err_t sdcard_ensure_card_init(sdcard_card_obj_t *self, bool force) { if (force || !(self->flags & SDCARD_CARD_FLAGS_CARD_INIT_DONE)) { DEBUG_printf(" Calling card init"); @@ -115,37 +127,38 @@ STATIC esp_err_t sdcard_ensure_card_init(sdcard_card_obj_t *self, bool force) { // // Expose the SD card or MMC as an object with the block protocol. -STATIC mp_obj_t esp32_sdcard_init() { - static int initialized = 0; - if (!initialized) { - // It might make sense to set up the host controller when the - // module is loaded, rather then when we slots are created. - - DEBUG_printf("Initialising sdcard module"); - - initialized = 1; - } - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_0(esp32_sdcard_init_obj, esp32_sdcard_init); - - // Create a new SDCard object +// The driver supports either the host SD/MMC controller (default) or SPI mode +// In both cases there are two "slots". Slot 0 on the SD/MMC controller is +// typically tied up with the flash interface in most ESP32 modules but in +// theory supports 1, 4 or 8-bit transfers. Slot 1 supports only 1 and 4-bit +// transfers. Only 1-bit is supported on the SPI interfaces. // card = SDCard(slot=1, width=None, present_pin=None, wp_pin=None) STATIC mp_obj_t esp32_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { // check arguments enum { ARG_slot, + ARG_spi, ARG_width, ARG_cd_pin, ARG_wp_pin, + ARG_miso_pin, + ARG_mosi_pin, + ARG_sck_pin, + ARG_cs_pin, }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_slot, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, - { MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, - { MP_QSTR_cd_pin, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, - { MP_QSTR_wp_pin, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} }, + STATIC const mp_arg_t allowed_args[] = { + { MP_QSTR_slot, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_spi, MP_ARG_KW_ONLY | MP_ARG_BOOL,{.u_bool = false} }, + { MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_cd, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_wp, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + // These are only needed if using SPI mode + { MP_QSTR_miso, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_mosi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_sck, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_cs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; mp_arg_val_t arg_vals[MP_ARRAY_SIZE(allowed_args)]; mp_map_t kw_args; @@ -155,67 +168,96 @@ STATIC mp_obj_t esp32_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); - mp_arg_parse_all(n_args, args, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, arg_vals); + mp_arg_parse_all(n_args, args, &kw_args, + MP_ARRAY_SIZE(allowed_args), allowed_args, arg_vals); - DEBUG_printf(" slot=%d, width=%d, cd_pin=%d, wp_pin=%d", + DEBUG_printf(" slot=%d, width=%d, cd_pin=%p, wp_pin=%p", arg_vals[ARG_slot].u_int, arg_vals[ARG_width].u_int, - arg_vals[ARG_cd_pin].u_int, arg_vals[ARG_wp_pin].u_int); + arg_vals[ARG_cd_pin].u_obj, arg_vals[ARG_wp_pin].u_obj); + + DEBUG_printf(" cd_pin=%p, wp_pin=%p, cd_pin=%p, wp_pin=%p", + arg_vals[ARG_miso_pin].u_obj, arg_vals[ARG_mosi_pin].u_obj, + arg_vals[ARG_sck_pin].u_obj, arg_vals[ARG_cs_pin].u_obj); + + bool is_spi = arg_vals[ARG_spi].u_bool; DEBUG_printf(" Setting up host configuration"); - sdcard_card_obj_t *self = m_new0(sdcard_card_obj_t, 1); + sdcard_card_obj_t *self = m_new_obj_with_finaliser(sdcard_card_obj_t); self->base.type = &esp32_sdcard_type; - sdmmc_host_t _temp_host = SDMMC_HOST_DEFAULT(); - self->host = _temp_host; + self->flags = 0; + // Note that these defaults are macros that expand to structure + // constants so we can't directly assign them to fields. + if (is_spi) { + sdmmc_host_t _temp_host = SDSPI_HOST_DEFAULT(); + self->host = _temp_host; + } else { + sdmmc_host_t _temp_host = SDMMC_HOST_DEFAULT(); + self->host = _temp_host; + } int slot_num = arg_vals[ARG_slot].u_int; if (slot_num !=0 && slot_num != 1) mp_raise_ValueError("Slot number must be 0 or 1"); - self->host.slot = slot_num; + if (is_spi) + self->host.slot = slot_num ? HSPI_HOST : VSPI_HOST; + else + self->host.slot = slot_num; - // Forcing pins into a usable state - gpio_set_pull_mode(15, GPIO_PULLUP_ONLY); // CMD, needed in 4- and 1- line modes - gpio_set_pull_mode(2, GPIO_PULLUP_ONLY); // D0, needed in 4- and 1-line modes - gpio_set_pull_mode(4, GPIO_PULLUP_ONLY); // D1, needed in 4-line mode only - gpio_set_pull_mode(12, GPIO_PULLUP_ONLY); // D2, needed in 4-line mode only - gpio_set_pull_mode(13, GPIO_PULLUP_ONLY); // D3, needed in 4- and 1-line modes + DEBUG_printf(" Calling host.init()"); - DEBUG_printf(" Setting up slot configuration"); + check_esp_err(self->host.init()); + self->flags |= SDCARD_CARD_FLAGS_HOST_INIT_DONE; - // This initializes the slot without card detect (CD) and write protect (WP) signals. - // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals. - sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); + if (is_spi) { + // SPI interface + STATIC const sdspi_slot_config_t slot_defaults[2] = { + { + .gpio_miso = GPIO_NUM_19, + .gpio_mosi = GPIO_NUM_23, + .gpio_sck = GPIO_NUM_18, + .gpio_cs = GPIO_NUM_5, + .gpio_cd = SDSPI_SLOT_NO_CD, + .gpio_wp = SDSPI_SLOT_NO_WP, + .dma_channel = 2 + }, + SDSPI_SLOT_CONFIG_DEFAULT() }; + + DEBUG_printf(" Setting up SPI slot configuration"); + sdspi_slot_config_t slot_config = slot_defaults[slot_num]; + + SET_CONFIG_PIN(slot_config, gpio_cd, ARG_cd_pin); + SET_CONFIG_PIN(slot_config, gpio_wp, ARG_wp_pin); + SET_CONFIG_PIN(slot_config, gpio_miso, ARG_miso_pin); + SET_CONFIG_PIN(slot_config, gpio_mosi, ARG_mosi_pin); + SET_CONFIG_PIN(slot_config, gpio_sck, ARG_sck_pin); + SET_CONFIG_PIN(slot_config, gpio_cs, ARG_cs_pin); + + DEBUG_printf(" Calling init_slot()"); + check_esp_err(sdspi_host_init_slot(self->host.slot, &slot_config)); + } else { + // SD/MMC interface + DEBUG_printf(" Setting up SDMMC slot configuration"); + sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); + + // Stronger external pull-ups are still needed but apparently + // it is a good idea to set the internal pull-ups anyway. + slot_config.flags = SDMMC_SLOT_FLAG_INTERNAL_PULLUP; - // TODO: Set up WP and CD pins if needed - // Do we want to require pin numbers or should we allow Pin objects too? - if (arg_vals[ARG_cd_pin].u_int != 0xffffffff || - arg_vals[ARG_wp_pin].u_int != 0xffffffff) - mp_raise_NotImplementedError("WP and CD pins not currently supported"); + SET_CONFIG_PIN(slot_config, gpio_cd, ARG_cd_pin); + SET_CONFIG_PIN(slot_config, gpio_wp, ARG_wp_pin); - int width = arg_vals[ARG_width].u_int; - if (width != 0xffffffff) { + int width = arg_vals[ARG_width].u_int; if (width == 1 || width == 4 || (width == 8 && slot_num == 0)) - slot_config.width = arg_vals[ARG_width].u_int; + slot_config.width = width; else mp_raise_ValueError("Width must be 1 or 4 (or 8 on slot 0)"); - } - // Stronger external pull-ups are still needed but apparently it is a good idea to - // set the internal pull-ups anyway. - slot_config.flags = SDMMC_SLOT_FLAG_INTERNAL_PULLUP; - - DEBUG_printf(" Calling host.init()"); - - check_esp_err(self->host.init()); - self->flags |= SDCARD_CARD_FLAGS_HOST_INIT_DONE; - // TODO: Do we need to de-init the host if the slot init fails? - - DEBUG_printf(" Calling init_slot()"); - - check_esp_err(sdmmc_host_init_slot(self->host.slot, &slot_config)); + DEBUG_printf(" Calling init_slot()"); + check_esp_err(sdmmc_host_init_slot(self->host.slot, &slot_config)); + } DEBUG_printf(" Returning new card object: %p", self); - // return object return MP_OBJ_FROM_PTR(self); } @@ -235,33 +277,36 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(sd_deinit_obj, sd_deinit); STATIC mp_obj_t sd_info(mp_obj_t self_in) { sdcard_card_obj_t *self = self_in; - // TODO: Extract SD card data + // We could potential return a great deal more SD card data but it + // is not clear that it is worth the extra code space to do + // so. For the most part people only care about the card size and + // block size. check_esp_err(sdcard_ensure_card_init((sdcard_card_obj_t *) self, false)); - uint32_t card_type = 0; uint32_t log_block_nbr = self->card.csd.capacity; uint32_t log_block_size = _SECTOR_SIZE(self); mp_obj_t tuple[3] = { mp_obj_new_int_from_ull((uint64_t)log_block_nbr * (uint64_t)log_block_size), mp_obj_new_int_from_uint(log_block_size), - mp_obj_new_int(card_type), }; return mp_obj_new_tuple(3, tuple); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(sd_info_obj, sd_info); - STATIC mp_obj_t esp32_sdcard_readblocks(mp_obj_t self_in, mp_obj_t block_num, mp_obj_t buf) { sdcard_card_obj_t *self = self_in; mp_buffer_info_t bufinfo; esp_err_t err; + err = sdcard_ensure_card_init((sdcard_card_obj_t *) self, false); if (err != ESP_OK) return false; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE); err = sdmmc_read_sectors(&(self->card), bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / _SECTOR_SIZE(self) ); + return mp_obj_new_bool(err == ESP_OK); } STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_sdcard_readblocks_obj, esp32_sdcard_readblocks); @@ -270,11 +315,14 @@ STATIC mp_obj_t esp32_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t block_num, m sdcard_card_obj_t *self = self_in; mp_buffer_info_t bufinfo; esp_err_t err; + err = sdcard_ensure_card_init((sdcard_card_obj_t *) self, false); if (err != ESP_OK) return false; + mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ); err = sdmmc_write_sectors(&(self->card), bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / _SECTOR_SIZE(self) ); + return mp_obj_new_bool(err == ESP_OK); } STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_sdcard_writeblocks_obj, esp32_sdcard_writeblocks); @@ -283,6 +331,7 @@ STATIC mp_obj_t esp32_sdcard_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t a sdcard_card_obj_t *self = self_in; esp_err_t err = ESP_OK; mp_int_t cmd = mp_obj_get_int(cmd_in); + switch (cmd) { case BP_IOCTL_INIT: err = sdcard_ensure_card_init(self, true); @@ -327,7 +376,6 @@ STATIC const mp_rom_map_elem_t esp32_sdcard_locals_dict_table[] = { STATIC MP_DEFINE_CONST_DICT(esp32_sdcard_locals_dict, esp32_sdcard_locals_dict_table); - const mp_obj_type_t esp32_sdcard_type = { { &mp_type_type }, .name = MP_QSTR_SDCard, @@ -335,18 +383,4 @@ const mp_obj_type_t esp32_sdcard_type = { .locals_dict = (mp_obj_dict_t*)&esp32_sdcard_locals_dict, }; -STATIC const mp_rom_map_elem_t esp32_module_sdcard_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sdcard) }, - { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&esp32_sdcard_init_obj) }, - { MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&esp32_sdcard_type) }, -}; - -STATIC MP_DEFINE_CONST_DICT(esp32_module_sdcard_globals, esp32_module_sdcard_globals_table); - -const mp_obj_module_t mp_module_sdcard = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&esp32_module_sdcard_globals, -}; - - #endif // MICROPY_HW_ENABLE_SDCARD diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c index 2e2d8236cf234..0728412b62c81 100644 --- a/ports/esp32/modesp32.c +++ b/ports/esp32/modesp32.c @@ -155,6 +155,9 @@ STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_hall_sensor), MP_ROM_PTR(&esp32_hall_sensor_obj) }, { MP_ROM_QSTR(MP_QSTR_ULP), MP_ROM_PTR(&esp32_ulp_type) }, +#if MICROPY_HW_ENABLE_SDCARD + { MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&esp32_sdcard_type) }, +#endif { MP_ROM_QSTR(MP_QSTR_WAKEUP_ALL_LOW), MP_ROM_PTR(&mp_const_false_obj) }, { MP_ROM_QSTR(MP_QSTR_WAKEUP_ANY_HIGH), MP_ROM_PTR(&mp_const_true_obj) }, diff --git a/ports/esp32/modesp32.h b/ports/esp32/modesp32.h index 1d18cb41fbe53..562aabe171970 100644 --- a/ports/esp32/modesp32.h +++ b/ports/esp32/modesp32.h @@ -28,4 +28,8 @@ extern const mp_obj_type_t esp32_ulp_type; +#if MICROPY_HW_ENABLE_SDCARD +extern const mp_obj_type_t esp32_sdcard_type; +#endif + #endif // MICROPY_INCLUDED_ESP32_MODESP32_H diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index 01681c51a1244..bd19c6bfbdb2d 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -179,7 +179,6 @@ extern const struct _mp_obj_module_t mp_module_usocket; extern const struct _mp_obj_module_t mp_module_machine; extern const struct _mp_obj_module_t mp_module_network; extern const struct _mp_obj_module_t mp_module_onewire; -extern const struct _mp_obj_module_t mp_module_sdcard; #define MICROPY_PORT_BUILTIN_MODULES \ { MP_OBJ_NEW_QSTR(MP_QSTR_esp), (mp_obj_t)&esp_module }, \ @@ -192,12 +191,6 @@ extern const struct _mp_obj_module_t mp_module_sdcard; { MP_OBJ_NEW_QSTR(MP_QSTR__onewire), (mp_obj_t)&mp_module_onewire }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_uhashlib), (mp_obj_t)&mp_module_uhashlib }, \ -#if MICROPY_HW_ENABLE_SDCARD -#define SDCARD_BUILTIN_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_sdcard), (mp_obj_t)&mp_module_sdcard }, -#else -#define SDCARD_BUILTIN_MODULE -#endif - #define MICROPY_PORT_BUILTIN_MODULE_WEAK_LINKS \ { MP_OBJ_NEW_QSTR(MP_QSTR_binascii), (mp_obj_t)&mp_module_ubinascii }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_collections), (mp_obj_t)&mp_module_collections }, \ @@ -209,7 +202,6 @@ extern const struct _mp_obj_module_t mp_module_sdcard; { MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&uos_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_random), (mp_obj_t)&mp_module_urandom }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_re), (mp_obj_t)&mp_module_ure }, \ - SDCARD_BUILTIN_MODULE \ { MP_OBJ_NEW_QSTR(MP_QSTR_select), (mp_obj_t)&mp_module_uselect }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&mp_module_usocket }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_ssl), (mp_obj_t)&mp_module_ussl }, \ From 35eb1d34ac60f0a8c908b11cb21ca55f24ec6fd1 Mon Sep 17 00:00:00 2001 From: Nicko van Someren Date: Fri, 31 May 2019 01:04:32 -0600 Subject: [PATCH 3/4] Addressed various pull request comments. Moved the SDCard class back to the machine module. Added documentation for the SDCard class for esp32 and stm32. --- docs/library/machine.SD.rst | 4 +- docs/library/machine.SDCard.rst | 133 ++++++++++++++++++ docs/library/machine.rst | 1 + ports/esp32/Makefile | 2 +- .../{esp32_sdcard.c => machine_sdcard.c} | 115 ++++++++------- ports/esp32/modesp32.c | 3 - ports/esp32/modesp32.h | 4 - ports/esp32/modmachine.c | 3 + ports/esp32/modmachine.h | 4 + 9 files changed, 201 insertions(+), 68 deletions(-) create mode 100644 docs/library/machine.SDCard.rst rename ports/esp32/{esp32_sdcard.c => machine_sdcard.c} (78%) diff --git a/docs/library/machine.SD.rst b/docs/library/machine.SD.rst index 9c58e73545edd..d985db231aa44 100644 --- a/docs/library/machine.SD.rst +++ b/docs/library/machine.SD.rst @@ -1,8 +1,8 @@ .. currentmodule:: machine .. _machine.SD: -class SD -- secure digital memory card -====================================== +class SD -- secure digital memory card (cc3200 port only) +========================================================= .. warning:: diff --git a/docs/library/machine.SDCard.rst b/docs/library/machine.SDCard.rst new file mode 100644 index 0000000000000..01f40bd3eed2f --- /dev/null +++ b/docs/library/machine.SDCard.rst @@ -0,0 +1,133 @@ +.. currentmodule:: machine +.. _machine.SDCard: + + + +class SDCard -- secure digital memory card +========================================== + +SD cards are one of the most common small form factor removable storage media. +SD cards come in a variety of sizes and phsyical form factors. MMC cards are +similar removable storage devices while eMMC devices are electically similar +storage devices designed to be embedded into other systems. All three form +share a common protocol for communication with their host system and high-level +support looks the same for them all. As such in micropython they are implemented +in a single class called :class:`machine.SDCard` . + +Both SD and MMC interfaces support being accessed with a variety of bus widths. +When being accessed with a 1-bit wide interface they can be accessed using the +SPI protocol. Different micropython hardware platforms support different widths +and pin configurations but for most platforms there is a standard configuation +for any given hardware. In general constructing an `SDCard`` object with without +passing any parameters will initialise the interface to the default card slot +for the current hardware. The arguments listed below represent the common +arguments that might need to be set in order to use either a non-stanard slot +or a non-standard pin assignment. The exact subset of arguments suported will +vary from platform to platform. + + +.. class:: SDCard(slot=1, width=1, cd=None, wp=None, sck=None, miso=None, mosi=None, cs=None) + + This class provides access to SD or MMC storage cards using either + the ESP32's dedicated SD/MMC interface hardware or through an SPI + channel using DMA for the data transfers. The class implements + that block protocol defined in the :class:`uos.AbstractBlockDev` + class. This allows the mounting of an SD card to be as simple as:: + + uos.mount(storage.SDCard(), "/sd") + + The constrcutor takes the following paramters: + + - ``slot`` selects which of the available interfaces to use. Leaving this + unset will select the default interface. + + - ``width`` selects the bus width for the SD/MMC interface. + + - ``cd`` can be used to specify a card-detect pin. + + - ``wp`` can be used to specify a write-protect pin. + + - ``sck`` can be used to specify an SPI clock pin. + + - ``miso`` can be used to specify an SPI miso pin. + + - ``mosi`` can be used to specify an SPI mosi pin. + + - ``cs`` can be used to specify an SPI chip select pin. + + + +Implementation-specific details +------------------------------- + +Different implementations of the ``SDCard`` class on different hardware support +varying subsets of the options above. + +PyBoard +``````` + +The standard PyBoard has just one slot. No arguments are necessary or supported. + +ESP32 +````` + +The ESP32 provides two channels of SD/MMC hardware and also supports +access to SD Cards through either of the two SPI ports that are +generally available to the user. As a result the ``slot`` argument can +take a value between 0 and 3, inclusive. Slots 0 and 1 use the +built-in SD/MMC hardware while slots 2 and 3 use the SPI ports. Slot 0 +supports 1, 4 or 8-bit wide access while slot 1 supports 1 or 4-bit +access; the SPI slots only support 1-bit access. + + .. note:: Slot 0 is used to communicate with on-board flash memory + on most ESP32 modules and so will be unavailable to the + user. + + .. note:: Most ESP32 modules that provide an SD card slot using the + dedicated hardware only wire up 1 data pin, so the default + value for ``width`` is 1. + +The pins used by the dedicated SD/MMC hardware are fixed. The pins +used by the SPI hardware can be reassigned. + + .. note:: If any of the SPI signals are remapped then all of the SPI + signals will pass through a GPIO multiplexer unit which + can limit the performance of high frequency signals. Since + the normal operating speed for SD cards is 40MHz this can + cause problems on some cards. + +The default (and preferred) pin assignment are as follows: + + ====== ====== ====== ====== ====== + Slot 0 1 2 3 + ------ ------ ------ ------ ------ + Signal Pin Pin Pin Pin + ====== ====== ====== ====== ====== + sck 6 14 18 14 + cmd 11 15 + cs 5 15 + miso 19 12 + mosi 23 13 + D0 7 2 + D1 8 4 + D2 9 12 + D3 10 13 + D4 16 + D5 17 + D6 5 + D7 18 + ====== ====== ====== ====== ====== + + + +cc3200 +`````` + +You can set the pins used for SPI access by passing a tuple as the +``pins`` argument. + +*Note:* The current cc3200 SD card implementation names the this class +:class:`machine.SD` rather than :class:`machine.SDCard` . + + + diff --git a/docs/library/machine.rst b/docs/library/machine.rst index a7b59577610be..8cc5efe593d4b 100644 --- a/docs/library/machine.rst +++ b/docs/library/machine.rst @@ -168,3 +168,4 @@ Classes machine.Timer.rst machine.WDT.rst machine.SD.rst + machine.SDCard.rst diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index c3cd499a98d2c..575238f35b9a1 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -193,7 +193,7 @@ SRC_C = \ machine_wdt.c \ mpthreadport.c \ machine_rtc.c \ - esp32_sdcard.c \ + machine_sdcard.c \ $(SRC_MOD) EXTMOD_SRC_C = $(addprefix extmod/,\ diff --git a/ports/esp32/esp32_sdcard.c b/ports/esp32/machine_sdcard.c similarity index 78% rename from ports/esp32/esp32_sdcard.c rename to ports/esp32/machine_sdcard.c index 7ead08ee61eb4..f69323cb36e42 100644 --- a/ports/esp32/esp32_sdcard.c +++ b/ports/esp32/machine_sdcard.c @@ -28,6 +28,7 @@ #include "py/runtime.h" #include "py/mphal.h" +#include "py/mperrno.h" #include "extmod/vfs_fat.h" #include "driver/sdmmc_host.h" @@ -35,7 +36,7 @@ #include "sdmmc_cmd.h" #include "esp_log.h" -#define DEBUG 0 +#define DEBUG 1 #if DEBUG #define DEBUG_printf(...) ESP_LOGI("modsdcard", __VA_ARGS__) #else @@ -54,7 +55,7 @@ #if MICROPY_HW_ENABLE_SDCARD // Forward declaration -const mp_obj_type_t esp32_sdcard_type; +const mp_obj_type_t machine_sdcard_type; typedef struct _sdcard_obj_t { mp_obj_base_t base; @@ -71,25 +72,21 @@ typedef struct _sdcard_obj_t { #define _SECTOR_SIZE(self) (self->card.csd.sector_size) STATIC esp_err_t check_esp_err(esp_err_t code) { - const mp_obj_type_t *ex_type = NULL; - switch(code) { case ESP_OK: return ESP_OK; case ESP_ERR_NO_MEM: - ex_type = &mp_type_MemoryError; + code = MP_ENOMEM; break; case ESP_ERR_TIMEOUT: - ex_type = &mp_type_TimeoutError; + code = MP_ETIMEDOUT; break; case ESP_ERR_NOT_SUPPORTED: - ex_type = &mp_type_NotImplementedError; + code = MP_EOPNOTSUPP; break; - default: - mp_raise_OSError(code); } - mp_raise_msg(ex_type, "From ESP SDK"); + mp_raise_OSError(code); } STATIC gpio_num_t pin_or_int(const mp_obj_t arg) { @@ -135,22 +132,20 @@ STATIC esp_err_t sdcard_ensure_card_init(sdcard_card_obj_t *self, bool force) { // transfers. Only 1-bit is supported on the SPI interfaces. // card = SDCard(slot=1, width=None, present_pin=None, wp_pin=None) -STATIC mp_obj_t esp32_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { +STATIC mp_obj_t machine_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { // check arguments enum { ARG_slot, - ARG_spi, ARG_width, - ARG_cd_pin, - ARG_wp_pin, - ARG_miso_pin, - ARG_mosi_pin, - ARG_sck_pin, - ARG_cs_pin, + ARG_cd, + ARG_wp, + ARG_miso, + ARG_mosi, + ARG_sck, + ARG_cs, }; STATIC const mp_arg_t allowed_args[] = { { MP_QSTR_slot, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, - { MP_QSTR_spi, MP_ARG_KW_ONLY | MP_ARG_BOOL,{.u_bool = false} }, { MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, { MP_QSTR_cd, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, { MP_QSTR_wp, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, @@ -171,20 +166,27 @@ STATIC mp_obj_t esp32_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, mp_arg_parse_all(n_args, args, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, arg_vals); - DEBUG_printf(" slot=%d, width=%d, cd_pin=%p, wp_pin=%p", + DEBUG_printf(" slot=%d, width=%d, cd=%p, wp=%p", arg_vals[ARG_slot].u_int, arg_vals[ARG_width].u_int, - arg_vals[ARG_cd_pin].u_obj, arg_vals[ARG_wp_pin].u_obj); + arg_vals[ARG_cd].u_obj, arg_vals[ARG_wp].u_obj); - DEBUG_printf(" cd_pin=%p, wp_pin=%p, cd_pin=%p, wp_pin=%p", - arg_vals[ARG_miso_pin].u_obj, arg_vals[ARG_mosi_pin].u_obj, - arg_vals[ARG_sck_pin].u_obj, arg_vals[ARG_cs_pin].u_obj); + DEBUG_printf(" miso=%p, mosi=%p, sck=%p, cs=%p", + arg_vals[ARG_miso].u_obj, arg_vals[ARG_mosi].u_obj, + arg_vals[ARG_sck].u_obj, arg_vals[ARG_cs].u_obj); - bool is_spi = arg_vals[ARG_spi].u_bool; + int slot_num = arg_vals[ARG_slot].u_int; + if (slot_num < 0 || slot_num > 3) + mp_raise_ValueError("Slot number must be between 0 and 3 inclusive"); + + // Slots 0 and 1 are native SD/MMC, slots 2 and 3 are SPI + bool is_spi = (slot_num >= 2); + if (is_spi) + slot_num -= 2; DEBUG_printf(" Setting up host configuration"); sdcard_card_obj_t *self = m_new_obj_with_finaliser(sdcard_card_obj_t); - self->base.type = &esp32_sdcard_type; + self->base.type = &machine_sdcard_type; self->flags = 0; // Note that these defaults are macros that expand to structure // constants so we can't directly assign them to fields. @@ -196,13 +198,10 @@ STATIC mp_obj_t esp32_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, self->host = _temp_host; } - int slot_num = arg_vals[ARG_slot].u_int; - if (slot_num !=0 && slot_num != 1) - mp_raise_ValueError("Slot number must be 0 or 1"); - if (is_spi) + if (is_spi) { self->host.slot = slot_num ? HSPI_HOST : VSPI_HOST; - else - self->host.slot = slot_num; + slot_num -= 2; + } DEBUG_printf(" Calling host.init()"); @@ -226,12 +225,12 @@ STATIC mp_obj_t esp32_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, DEBUG_printf(" Setting up SPI slot configuration"); sdspi_slot_config_t slot_config = slot_defaults[slot_num]; - SET_CONFIG_PIN(slot_config, gpio_cd, ARG_cd_pin); - SET_CONFIG_PIN(slot_config, gpio_wp, ARG_wp_pin); - SET_CONFIG_PIN(slot_config, gpio_miso, ARG_miso_pin); - SET_CONFIG_PIN(slot_config, gpio_mosi, ARG_mosi_pin); - SET_CONFIG_PIN(slot_config, gpio_sck, ARG_sck_pin); - SET_CONFIG_PIN(slot_config, gpio_cs, ARG_cs_pin); + SET_CONFIG_PIN(slot_config, gpio_cd, ARG_cd); + SET_CONFIG_PIN(slot_config, gpio_wp, ARG_wp); + SET_CONFIG_PIN(slot_config, gpio_miso, ARG_miso); + SET_CONFIG_PIN(slot_config, gpio_mosi, ARG_mosi); + SET_CONFIG_PIN(slot_config, gpio_sck, ARG_sck); + SET_CONFIG_PIN(slot_config, gpio_cs, ARG_cs); DEBUG_printf(" Calling init_slot()"); check_esp_err(sdspi_host_init_slot(self->host.slot, &slot_config)); @@ -242,10 +241,10 @@ STATIC mp_obj_t esp32_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, // Stronger external pull-ups are still needed but apparently // it is a good idea to set the internal pull-ups anyway. - slot_config.flags = SDMMC_SLOT_FLAG_INTERNAL_PULLUP; + // slot_config.flags = SDMMC_SLOT_FLAG_INTERNAL_PULLUP; - SET_CONFIG_PIN(slot_config, gpio_cd, ARG_cd_pin); - SET_CONFIG_PIN(slot_config, gpio_wp, ARG_wp_pin); + SET_CONFIG_PIN(slot_config, gpio_cd, ARG_cd); + SET_CONFIG_PIN(slot_config, gpio_wp, ARG_wp); int width = arg_vals[ARG_width].u_int; if (width == 1 || width == 4 || (width == 8 && slot_num == 0)) @@ -287,15 +286,15 @@ STATIC mp_obj_t sd_info(mp_obj_t self_in) { uint32_t log_block_nbr = self->card.csd.capacity; uint32_t log_block_size = _SECTOR_SIZE(self); - mp_obj_t tuple[3] = { + mp_obj_t tuple[2] = { mp_obj_new_int_from_ull((uint64_t)log_block_nbr * (uint64_t)log_block_size), mp_obj_new_int_from_uint(log_block_size), }; - return mp_obj_new_tuple(3, tuple); + return mp_obj_new_tuple(2, tuple); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(sd_info_obj, sd_info); -STATIC mp_obj_t esp32_sdcard_readblocks(mp_obj_t self_in, mp_obj_t block_num, mp_obj_t buf) { +STATIC mp_obj_t machine_sdcard_readblocks(mp_obj_t self_in, mp_obj_t block_num, mp_obj_t buf) { sdcard_card_obj_t *self = self_in; mp_buffer_info_t bufinfo; esp_err_t err; @@ -309,9 +308,9 @@ STATIC mp_obj_t esp32_sdcard_readblocks(mp_obj_t self_in, mp_obj_t block_num, mp return mp_obj_new_bool(err == ESP_OK); } -STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_sdcard_readblocks_obj, esp32_sdcard_readblocks); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(machine_sdcard_readblocks_obj, machine_sdcard_readblocks); -STATIC mp_obj_t esp32_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t block_num, mp_obj_t buf) { +STATIC mp_obj_t machine_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t block_num, mp_obj_t buf) { sdcard_card_obj_t *self = self_in; mp_buffer_info_t bufinfo; esp_err_t err; @@ -325,16 +324,16 @@ STATIC mp_obj_t esp32_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t block_num, m return mp_obj_new_bool(err == ESP_OK); } -STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_sdcard_writeblocks_obj, esp32_sdcard_writeblocks); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(machine_sdcard_writeblocks_obj, machine_sdcard_writeblocks); -STATIC mp_obj_t esp32_sdcard_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_in) { +STATIC mp_obj_t machine_sdcard_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_in) { sdcard_card_obj_t *self = self_in; esp_err_t err = ESP_OK; mp_int_t cmd = mp_obj_get_int(cmd_in); switch (cmd) { case BP_IOCTL_INIT: - err = sdcard_ensure_card_init(self, true); + err = sdcard_ensure_card_init(self, false); return MP_OBJ_NEW_SMALL_INT((err == ESP_OK) ? 0 : -1); case BP_IOCTL_DEINIT: @@ -362,25 +361,25 @@ STATIC mp_obj_t esp32_sdcard_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t a return MP_OBJ_NEW_SMALL_INT(-1); // error } } -STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp32_sdcard_ioctl_obj, esp32_sdcard_ioctl); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(machine_sdcard_ioctl_obj, machine_sdcard_ioctl); -STATIC const mp_rom_map_elem_t esp32_sdcard_locals_dict_table[] = { +STATIC const mp_rom_map_elem_t machine_sdcard_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&sd_info_obj) }, { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&sd_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&sd_deinit_obj) }, // block device protocol - { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&esp32_sdcard_readblocks_obj) }, - { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&esp32_sdcard_writeblocks_obj) }, - { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&esp32_sdcard_ioctl_obj) }, + { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&machine_sdcard_readblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&machine_sdcard_writeblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&machine_sdcard_ioctl_obj) }, }; -STATIC MP_DEFINE_CONST_DICT(esp32_sdcard_locals_dict, esp32_sdcard_locals_dict_table); +STATIC MP_DEFINE_CONST_DICT(machine_sdcard_locals_dict, machine_sdcard_locals_dict_table); -const mp_obj_type_t esp32_sdcard_type = { +const mp_obj_type_t machine_sdcard_type = { { &mp_type_type }, .name = MP_QSTR_SDCard, - .make_new = esp32_sdcard_make_new, - .locals_dict = (mp_obj_dict_t*)&esp32_sdcard_locals_dict, + .make_new = machine_sdcard_make_new, + .locals_dict = (mp_obj_dict_t*)&machine_sdcard_locals_dict, }; #endif // MICROPY_HW_ENABLE_SDCARD diff --git a/ports/esp32/modesp32.c b/ports/esp32/modesp32.c index 0728412b62c81..2e2d8236cf234 100644 --- a/ports/esp32/modesp32.c +++ b/ports/esp32/modesp32.c @@ -155,9 +155,6 @@ STATIC const mp_rom_map_elem_t esp32_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_hall_sensor), MP_ROM_PTR(&esp32_hall_sensor_obj) }, { MP_ROM_QSTR(MP_QSTR_ULP), MP_ROM_PTR(&esp32_ulp_type) }, -#if MICROPY_HW_ENABLE_SDCARD - { MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&esp32_sdcard_type) }, -#endif { MP_ROM_QSTR(MP_QSTR_WAKEUP_ALL_LOW), MP_ROM_PTR(&mp_const_false_obj) }, { MP_ROM_QSTR(MP_QSTR_WAKEUP_ANY_HIGH), MP_ROM_PTR(&mp_const_true_obj) }, diff --git a/ports/esp32/modesp32.h b/ports/esp32/modesp32.h index 562aabe171970..1d18cb41fbe53 100644 --- a/ports/esp32/modesp32.h +++ b/ports/esp32/modesp32.h @@ -28,8 +28,4 @@ extern const mp_obj_type_t esp32_ulp_type; -#if MICROPY_HW_ENABLE_SDCARD -extern const mp_obj_type_t esp32_sdcard_type; -#endif - #endif // MICROPY_INCLUDED_ESP32_MODESP32_H diff --git a/ports/esp32/modmachine.c b/ports/esp32/modmachine.c index bc459ee5c29b2..b4cdf0fa1a173 100644 --- a/ports/esp32/modmachine.c +++ b/ports/esp32/modmachine.c @@ -235,6 +235,9 @@ STATIC const mp_rom_map_elem_t machine_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Timer), MP_ROM_PTR(&machine_timer_type) }, { MP_ROM_QSTR(MP_QSTR_WDT), MP_ROM_PTR(&machine_wdt_type) }, +#if MICROPY_HW_ENABLE_SDCARD + { MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&machine_sdcard_type) }, +#endif // wake abilities { MP_ROM_QSTR(MP_QSTR_SLEEP), MP_ROM_INT(MACHINE_WAKE_SLEEP) }, diff --git a/ports/esp32/modmachine.h b/ports/esp32/modmachine.h index b65b427b4ea33..9bdea18381c2e 100644 --- a/ports/esp32/modmachine.h +++ b/ports/esp32/modmachine.h @@ -20,6 +20,10 @@ extern const mp_obj_type_t machine_hw_spi_type; extern const mp_obj_type_t machine_uart_type; extern const mp_obj_type_t machine_rtc_type; +#if MICROPY_HW_ENABLE_SDCARD +extern const mp_obj_type_t machine_sdcard_type; +#endif + void machine_pins_init(void); void machine_pins_deinit(void); void machine_timer_deinit_all(void); From 542df89ecd94f611eabedde08be0d06171aeaef0 Mon Sep 17 00:00:00 2001 From: Nicko van Someren Date: Sat, 1 Jun 2019 07:06:43 -0600 Subject: [PATCH 4/4] Revert out added to documentation in esp32 library due to moving class. --- docs/library/esp32.rst | 82 ------------------------------------------ 1 file changed, 82 deletions(-) diff --git a/docs/library/esp32.rst b/docs/library/esp32.rst index 566b5b5ffd703..c934ef0954872 100644 --- a/docs/library/esp32.rst +++ b/docs/library/esp32.rst @@ -57,88 +57,6 @@ The Ultra-Low-Power co-processor Start the ULP running at the given *entry_point*. -SD/MMC Card interface ---------------------- - -.. class:: SDCard(slot=1, spi=false, width=1, cd=None, wp=None, sck=None, miso=None, mosi=None, cs=None) - - This class provides access to SD or MMC storage cards using either - the ESP32's dedicated SD/MMC interface hardware or through an SPI - channel using DMA for the data transfers. The class implements - that block protocol defined in the :class:`uos.AbstractBlockDev` - class. This allows the mounting of an SD card to be as simple as:: - - uos.mount(esp32.SDCard(), "/sd") - - The constrcutor takes the following paramters: - - - ``slot`` selects which of two interfaces to use. The ESP32 - provides two channels of SD/MMC hardware but it should be noted - that slot 0 is often used to communicate with on-board - flash memory on most ESP32 modules. As a result only slot 1 - will normally be available. When using SPI mode this selects - between the two hardware SPI drivers. - - - ``spi`` selects the use of an SPI interface instead of the - dedicated SD/MMC interface. - - - ``width`` selects the bus width for the SD/MMC interface. Slot - 0 supports 1, 4 or 8-bit wide access while slot 1 supports 1 ot - 4-bit access. Note that most ESP32 modules that provide an SD card slot - using the dedicated hardware only wire up 1 data pin so the - default is 1. - - - ``cd`` can be used to specify a card-detect pin. - - - ``wp`` can be used to specify a write-protect pin. - - - ``sck`` can be used to specify an SPI clock pin. - - - ``miso`` can be used to specify an SPI miso pin. - - - ``mosi`` can be used to specify an SPI mosi pin. - - - ``cs`` can be used to specify an SPI chip select pin. - - The pins used by the dedicated SD/MMC hardware are fixed; they are - assigned as follows: - - ====== ====== ====== - SD/MMC Slot 0 Slot 1 - ------ ------ ------ - Signal Pin Pin - ====== ====== ====== - cmd 11 15 - sck 6 14 - D0 7 2 - D1 8 4 - D2 9 12 - D3 10 13 - D4 16 - D5 17 - D6 5 - D7 18 - ====== ====== ====== - - The pins used by the SPI hardware can be reassigned. It should - however be noted that if any of the signals are remapped then all - of the SPI signals will pass through a GPIO multiplexer unit - which can limit the performance of high frequency signals. Since - the normal operating speed for SD cards is 40MHz this can cause - problems on some cards. The default (and preferred) pin assignment - are as follows: - - ====== ====== ====== - SPI Slot 0 Slot 1 - ------ ------ ------ - Signal Pin Pin - ====== ====== ====== - sck 18 14 - cs 5 15 - miso 19 12 - mosi 23 13 - ====== ====== ====== - Constants ---------