add support for sdmmc cards in sd-spi mode (#2644)
This commit is contained in:
parent
e756dbce9c
commit
e9bf51eb8f
|
@ -12,7 +12,7 @@
|
|||
#include "sdmmc_cmd.h"
|
||||
|
||||
// defined in components/modules/sdmmc.c
|
||||
extern sdmmc_card_t lsdmmc_card[2];
|
||||
extern sdmmc_card_t *lsdmmc_card[];
|
||||
|
||||
|
||||
static DSTATUS m_status = STA_NOINIT;
|
||||
|
@ -60,7 +60,7 @@ DRESULT disk_read (
|
|||
UINT count /* Number of sectors to read */
|
||||
)
|
||||
{
|
||||
if (sdmmc_read_sectors( &(lsdmmc_card[pdrv]), buff, sector, count ) == ESP_OK)
|
||||
if (sdmmc_read_sectors( lsdmmc_card[pdrv], buff, sector, count ) == ESP_OK)
|
||||
return RES_OK;
|
||||
|
||||
return RES_ERROR;
|
||||
|
@ -80,7 +80,7 @@ DRESULT disk_write (
|
|||
UINT count /* Number of sectors to write */
|
||||
)
|
||||
{
|
||||
if (sdmmc_write_sectors( &(lsdmmc_card[pdrv]), buff, sector, count ) == ESP_OK)
|
||||
if (sdmmc_write_sectors( lsdmmc_card[pdrv], buff, sector, count ) == ESP_OK)
|
||||
return RES_OK;
|
||||
|
||||
return RES_ERROR;
|
||||
|
|
|
@ -13,12 +13,11 @@ typedef struct {
|
|||
// Table to map physical drive & partition to a logical volume.
|
||||
// The first value is the physical drive which relates to the SDMMC slot number
|
||||
// The second value is the partition number.
|
||||
#define NUM_LOGICAL_DRIVES 4
|
||||
PARTITION VolToPart[NUM_LOGICAL_DRIVES] = {
|
||||
{1, 1}, /* Logical drive "0:" ==> slot 1, 1st partition */
|
||||
{1, 2}, /* Logical drive "1:" ==> slot 1, 2st partition */
|
||||
{1, 3}, /* Logical drive "2:" ==> slot 1, 3st partition */
|
||||
{1, 4} /* Logical drive "3:" ==> slot 1, 4st partition */
|
||||
PARTITION VolToPart[FF_VOLUMES] = {
|
||||
{0, 1}, /* Logical drive "0:" ==> slot 0, 1st partition */
|
||||
{0, 2}, /* Logical drive "1:" ==> slot 0, 2st partition */
|
||||
{0, 3}, /* Logical drive "2:" ==> slot 0, 3st partition */
|
||||
{0, 4} /* Logical drive "3:" ==> slot 0, 4st partition */
|
||||
};
|
||||
|
||||
#endif /* __FATFS_CONFIG_H__ */
|
||||
|
|
|
@ -348,7 +348,7 @@ static vfs_vol *myfatfs_mount( const char *name, int num )
|
|||
|
||||
// num argument specifies the physical driver
|
||||
if (num >= 0) {
|
||||
for (int i = 0; i < NUM_LOGICAL_DRIVES; i++) {
|
||||
for (int i = 0; i < FF_VOLUMES; i++) {
|
||||
if (0 == strncmp( name, volstr[i], strlen( volstr[i] ) )) {
|
||||
VolToPart[i].pd = num;
|
||||
}
|
||||
|
|
|
@ -8,9 +8,19 @@
|
|||
|
||||
#include "driver/sdmmc_host.h"
|
||||
#include "sdmmc_cmd.h"
|
||||
#include "driver/sdspi_host.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
sdmmc_card_t lsdmmc_card[2];
|
||||
// the index of cards here must be aligned with the pdrv for fatfs
|
||||
// see FF_VOLUMES in ffconf.h
|
||||
#define NUM_CARDS 4
|
||||
sdmmc_card_t *lsdmmc_card[NUM_CARDS];
|
||||
|
||||
// local definition for SDSPI host
|
||||
#define LSDMMC_HOST_SDSPI 100
|
||||
#define LSDMMC_HOST_HSPI (LSDMMC_HOST_SDSPI + HSPI_HOST)
|
||||
#define LSDMMC_HOST_VSPI (LSDMMC_HOST_SDSPI + VSPI_HOST)
|
||||
|
||||
typedef struct {
|
||||
sdmmc_card_t *card;
|
||||
|
@ -22,58 +32,109 @@ static int lsdmmc_init( lua_State *L )
|
|||
{
|
||||
const char *err_msg = "";
|
||||
int stack = 0;
|
||||
int top = lua_gettop( L );
|
||||
|
||||
int slot = luaL_checkint( L, ++stack );
|
||||
luaL_argcheck( L, slot == SDMMC_HOST_SLOT_0 || slot == SDMMC_HOST_SLOT_1,
|
||||
luaL_argcheck( L, slot == SDMMC_HOST_SLOT_0 || slot == SDMMC_HOST_SLOT_1 ||
|
||||
slot == LSDMMC_HOST_HSPI || slot == LSDMMC_HOST_VSPI,
|
||||
stack, "invalid slot" );
|
||||
|
||||
bool is_sdspi = false;
|
||||
if (slot >= LSDMMC_HOST_SDSPI) {
|
||||
is_sdspi = true;
|
||||
slot -= LSDMMC_HOST_SDSPI;
|
||||
}
|
||||
|
||||
// set optional defaults
|
||||
int cd_pin = SDMMC_SLOT_NO_CD;
|
||||
int wp_pin = SDMMC_SLOT_NO_WP;
|
||||
int freq_khz = SDMMC_FREQ_DEFAULT;
|
||||
int width = SDMMC_HOST_FLAG_1BIT;
|
||||
// additional entries for SDSPI configuration
|
||||
int sck_pin = -1;
|
||||
int mosi_pin = -1;
|
||||
int miso_pin = -1;
|
||||
int cs_pin = -1;
|
||||
|
||||
if (lua_type( L, ++stack ) == LUA_TTABLE) {
|
||||
lua_pushvalue( L, stack );
|
||||
// retrieve slot configuration from table
|
||||
cd_pin = opt_checkint( L, "cd_pin", cd_pin );
|
||||
wp_pin = opt_checkint( L, "wp_pin", wp_pin );
|
||||
freq_khz = opt_checkint( L, "fmax", freq_khz * 1000 ) / 1000;
|
||||
width = opt_checkint( L, "width", width );
|
||||
|
||||
lua_getfield( L, stack, "cd_pin" );
|
||||
cd_pin = luaL_optint( L, -1, cd_pin );
|
||||
// mandatory entries for SDSPI configuration
|
||||
if (is_sdspi) {
|
||||
sck_pin = opt_checkint_range( L, "sck_pin", -1, 0, GPIO_NUM_MAX );
|
||||
mosi_pin = opt_checkint_range( L, "mosi_pin", -1, 0, GPIO_NUM_MAX );
|
||||
miso_pin = opt_checkint_range( L, "miso_pin", -1, 0, GPIO_NUM_MAX );
|
||||
cs_pin = opt_checkint_range( L, "cs_pin", -1, 0, GPIO_NUM_MAX );
|
||||
}
|
||||
|
||||
lua_getfield( L, stack, "wp_pin" );
|
||||
wp_pin = luaL_optint( L, -1, wp_pin );
|
||||
|
||||
lua_getfield( L, stack, "fmax" );
|
||||
freq_khz = luaL_optint( L, -1, freq_khz * 1000 ) / 1000;
|
||||
|
||||
lua_getfield( L, stack, "width" );
|
||||
width = luaL_optint( L, -1, width );
|
||||
|
||||
lua_pop( L, 4 );
|
||||
lua_settop( L, top );
|
||||
} else {
|
||||
// table is optional for SDMMC drivers, but mandatory for SD-SPI
|
||||
if (is_sdspi)
|
||||
return luaL_error( L, "missing slot configuration table" );
|
||||
}
|
||||
|
||||
// initialize SDMMC host
|
||||
// find first free card
|
||||
int card_idx;
|
||||
for (card_idx = 0; card_idx < NUM_CARDS; card_idx++) {
|
||||
if (lsdmmc_card[card_idx] == NULL) {
|
||||
lsdmmc_card[card_idx] = (sdmmc_card_t *)luaM_malloc( L, sizeof( sdmmc_card_t ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (card_idx == NUM_CARDS)
|
||||
return luaL_error( L, "too many cards" );
|
||||
|
||||
// initialize host
|
||||
// tolerate error due to re-initialization
|
||||
esp_err_t res = sdmmc_host_init();
|
||||
esp_err_t res;
|
||||
|
||||
if (is_sdspi) {
|
||||
res = sdspi_host_init();
|
||||
} else {
|
||||
res = sdmmc_host_init();
|
||||
}
|
||||
if (res == ESP_OK || res == ESP_ERR_INVALID_STATE) {
|
||||
|
||||
// configure SDMMC slot
|
||||
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
|
||||
slot_config.gpio_cd = cd_pin;
|
||||
slot_config.gpio_wp = wp_pin;
|
||||
if (sdmmc_host_init_slot( slot, &slot_config ) == ESP_OK) {
|
||||
if (is_sdspi) {
|
||||
// configure SDSPI slot
|
||||
sdspi_slot_config_t slot_config = SDSPI_SLOT_CONFIG_DEFAULT();
|
||||
slot_config.gpio_miso = miso_pin;
|
||||
slot_config.gpio_mosi = mosi_pin;
|
||||
slot_config.gpio_sck = sck_pin;
|
||||
slot_config.gpio_cs = cs_pin;
|
||||
slot_config.gpio_cd = cd_pin;
|
||||
slot_config.gpio_wp = wp_pin;
|
||||
res = sdspi_host_init_slot( slot, &slot_config );
|
||||
} else {
|
||||
// configure SDMMC slot
|
||||
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
|
||||
slot_config.gpio_cd = cd_pin;
|
||||
slot_config.gpio_wp = wp_pin;
|
||||
res = sdmmc_host_init_slot( slot, &slot_config );
|
||||
}
|
||||
if (res == ESP_OK) {
|
||||
|
||||
// initialize card
|
||||
sdmmc_host_t host_config = SDMMC_HOST_DEFAULT();
|
||||
host_config.slot = slot;
|
||||
host_config.flags = width;
|
||||
host_config.max_freq_khz = freq_khz;
|
||||
if (sdmmc_card_init( &host_config, &(lsdmmc_card[slot]) ) == ESP_OK) {
|
||||
sdmmc_host_t sdspi_host_config = SDSPI_HOST_DEFAULT();
|
||||
sdmmc_host_t sdmmc_host_config = SDMMC_HOST_DEFAULT();
|
||||
sdmmc_host_t *host_config = is_sdspi ? &sdspi_host_config : &sdmmc_host_config;
|
||||
host_config->slot = slot;
|
||||
host_config->flags &= ~SDMMC_HOST_FLAG_8BIT;
|
||||
host_config->flags |= width;
|
||||
host_config->max_freq_khz = freq_khz;
|
||||
if (sdmmc_card_init( host_config, lsdmmc_card[card_idx] ) == ESP_OK) {
|
||||
|
||||
lsdmmc_ud_t *ud = (lsdmmc_ud_t *)lua_newuserdata( L, sizeof( lsdmmc_ud_t ) );
|
||||
if (ud) {
|
||||
luaL_getmetatable(L, "sdmmc.card");
|
||||
lua_setmetatable(L, -2);
|
||||
ud->card = &(lsdmmc_card[slot]);
|
||||
ud->card = lsdmmc_card[card_idx];
|
||||
ud->vol = NULL;
|
||||
|
||||
// all done
|
||||
|
@ -86,7 +147,11 @@ static int lsdmmc_init( lua_State *L )
|
|||
} else
|
||||
err_msg = "failed to init slot";
|
||||
|
||||
sdmmc_host_deinit();
|
||||
if (is_sdspi ) {
|
||||
sdspi_host_deinit();
|
||||
} else {
|
||||
sdmmc_host_deinit();
|
||||
}
|
||||
} else
|
||||
err_msg = "failed to init sdmmc host";
|
||||
|
||||
|
@ -113,7 +178,8 @@ static int lsdmmc_read( lua_State * L)
|
|||
luaL_argcheck( L, num_sec >= 0, stack, "out of range" );
|
||||
|
||||
// get read buffer
|
||||
char *rbuf = luaM_malloc( L, num_sec * 512 );
|
||||
const size_t rbuf_size = num_sec * 512;
|
||||
char *rbuf = luaM_malloc( L, rbuf_size );
|
||||
|
||||
if (sdmmc_read_sectors( card, rbuf, start_sec, num_sec ) == ESP_OK) {
|
||||
luaL_Buffer b;
|
||||
|
@ -121,7 +187,7 @@ static int lsdmmc_read( lua_State * L)
|
|||
luaL_addlstring( &b, rbuf, num_sec * 512 );
|
||||
luaL_pushresult( &b );
|
||||
|
||||
luaM_free( L, rbuf );
|
||||
luaM_freearray( L, rbuf, rbuf_size, uint8_t );
|
||||
|
||||
// all ok
|
||||
return 1;
|
||||
|
@ -129,6 +195,7 @@ static int lsdmmc_read( lua_State * L)
|
|||
} else
|
||||
err_msg = "card access failed";
|
||||
|
||||
luaM_freearray( L, rbuf, rbuf_size, uint8_t );
|
||||
return luaL_error( L, err_msg );
|
||||
}
|
||||
|
||||
|
@ -274,6 +341,8 @@ static const LUA_REG_TYPE sdmmc_map[] = {
|
|||
{ LSTRKEY( "init" ), LFUNCVAL( lsdmmc_init ) },
|
||||
{ LSTRKEY( "HS1" ), LNUMVAL( SDMMC_HOST_SLOT_0 ) },
|
||||
{ LSTRKEY( "HS2" ), LNUMVAL( SDMMC_HOST_SLOT_1 ) },
|
||||
{ LSTRKEY( "HSPI" ), LNUMVAL( LSDMMC_HOST_HSPI ) },
|
||||
{ LSTRKEY( "VSPI" ), LNUMVAL( LSDMMC_HOST_VSPI ) },
|
||||
{ LSTRKEY( "W1BIT" ), LNUMVAL( SDMMC_HOST_FLAG_1BIT ) },
|
||||
{ LSTRKEY( "W4BIT" ), LNUMVAL( SDMMC_HOST_FLAG_1BIT |
|
||||
SDMMC_HOST_FLAG_4BIT ) },
|
||||
|
@ -287,6 +356,11 @@ static int luaopen_sdmmc( lua_State *L )
|
|||
{
|
||||
luaL_rometatable(L, "sdmmc.card", (void *)sdmmc_card_map);
|
||||
|
||||
// initialize cards
|
||||
for (int i = 0; i < NUM_CARDS; i++ ) {
|
||||
lsdmmc_card[i] = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -224,7 +224,15 @@ int lspi_master( lua_State *L )
|
|||
stack,
|
||||
"invalid host" );
|
||||
|
||||
luaL_checktype( L, ++stack, LUA_TTABLE );
|
||||
if (lua_type( L, ++stack ) != LUA_TTABLE) {
|
||||
// no configuration table provided
|
||||
// assume that host is already initialized and just provide the object
|
||||
lspi_host_t *ud = (lspi_host_t *)lua_newuserdata( L, sizeof( lspi_host_t ) );
|
||||
luaL_getmetatable( L, UD_HOST_STR );
|
||||
lua_setmetatable( L, -2 );
|
||||
ud->host = host;
|
||||
return 1;
|
||||
}
|
||||
|
||||
spi_bus_config_t config;
|
||||
memset( &config, 0, sizeof( config ) );
|
||||
|
|
|
@ -5,11 +5,19 @@
|
|||
|
||||
!!! note
|
||||
|
||||
MMC cards are not yet supported due to missing functionality in the IDF driver.
|
||||
MMC cards are not yet supported on HS1/HS2 interfaces due to missing functionality in the IDF driver. Use the SD SPI mode on HSPI/VSPI instead.
|
||||
|
||||
## SD Card connection
|
||||
|
||||
The SD card is operated in SDMMC mode, thus the card has to be wired to the ESP pins of the HS1_* or HS2_* interfaces. There are several naming schemes used on different adapters - the following list shows alternative terms:
|
||||
!!! caution
|
||||
|
||||
The adapter does not require level shifters since SD and ESP are supposed to be powered with the same voltage. If your specific model contains level shifters then make sure that both sides can be operated at 3V3.
|
||||
|
||||
![1:1 micro-sd adapter](../img/micro_sd-small.jpg "1:1 micro-sd adapter")
|
||||
|
||||
### SDMMC Mode
|
||||
|
||||
If the SD card is operated in SDMMC mode, then the card has to be wired to the ESP pins of the HS1_* or HS2_* interfaces. There are several naming schemes used on different adapters - the following list shows alternative terms:
|
||||
|
||||
| SD mode name | SPI mode name | ESP32 HS1 I/F | ESP32 HS2 I/F |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
|
@ -32,11 +40,24 @@ Connections to `CLK`, `CMD`, and `DAT0` are mandatory and enable basic operation
|
|||
|
||||
Connecting DAT0 to GPIO2 can block firmware flashing depending on the electrical configuration at this pin. Disconnect GPIO2 from the card adapter during flashing if unsure.
|
||||
|
||||
!!! caution
|
||||
### SD SPI Mode
|
||||
|
||||
The adapter does not require level shifters since SD and ESP are supposed to be powered with the same voltage. If your specific model contains level shifters then make sure that both sides can be operated at 3V3.
|
||||
In SD SPI mode the SD or MMC card is operated by the SPI host interfaces (HSPI or VSPI). Both hosts can be assigned to any GPIO pins.
|
||||
|
||||
![1:1 micro-sd adapter](../img/micro_sd-small.jpg "1:1 micro-sd adapter")
|
||||
| SPI mode name | ESP32 HSPI, VSPI I/F |
|
||||
| :--- | :--- |
|
||||
| `CK, SCLK` | Any GPIO |
|
||||
| `DI, MOSI` | Any GPIO |
|
||||
| `DO, MISO` | Any GPIO |
|
||||
| n/a | n/a |
|
||||
| n/a | n/a |
|
||||
| `CS, SS` | Any GPIO |
|
||||
| n/a | n/a |
|
||||
| n/a | n/a |
|
||||
| n/a | n/a |
|
||||
| n/a | n/a |
|
||||
| `VCC, VDD` | 3V3 supply |
|
||||
| `VSS, GND` | common ground |
|
||||
|
||||
## sdmmc.init()
|
||||
Initialize the SDMMC and probe the attached SD card.
|
||||
|
@ -44,7 +65,7 @@ Initialize the SDMMC and probe the attached SD card.
|
|||
#### Syntax
|
||||
`sdmmc.init(slot[, cfg])`
|
||||
|
||||
#### Parameters
|
||||
#### Parameters SDMMC Mode
|
||||
- `slot` SDMMC slot, one of `sdmmc.HS1` or `sdmmc.HS2`
|
||||
- `cfg` optional table containing slot configuration:
|
||||
- `cd_pin` card detect pin, none if omitted
|
||||
|
@ -55,6 +76,17 @@ Initialize the SDMMC and probe the attached SD card.
|
|||
- `sdmmc.W4BIT`
|
||||
- `sdmmc.W8BIT`, not supported yet
|
||||
|
||||
#### Parameters SD SPI Mode
|
||||
- `slot` SD SPI slot, one of `sdmmc.HSPI` or `sdmmc.VSPI`
|
||||
- `cfg` mandatory table containing slot configuration:
|
||||
- `sck_pin` SPI SCK pin, mandatory
|
||||
- `mosi_pin`, SPI MOSI pin, mandatory
|
||||
- `miso_pin`, SPI MISO pin, mandatory
|
||||
- `cs_pin`, SPI CS pin, mandatory
|
||||
- `cd_pin` card detect pin, none if omitted
|
||||
- `wp_pin` write-protcet pin, none if omitted
|
||||
- `fmax` maximum communication frequency, defaults to 20 if omitted
|
||||
|
||||
#### Returns
|
||||
Card object.
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ The host signals can be mapped to any suitable GPIO pins.
|
|||
Initializes a bus in master mode and returns a bus master object.
|
||||
|
||||
#### Syntax
|
||||
`spi.master(host, config[, dma])`
|
||||
`spi.master(host[, config[, dma]])`
|
||||
|
||||
#### Parameters
|
||||
- `host` id, one of
|
||||
|
@ -34,6 +34,10 @@ Initializes a bus in master mode and returns a bus master object.
|
|||
Enabling DMA allows sending and receiving an unlimited amount of bytes but has restrictions in halfduplex mode (see [`spi.master:device()`](#spimasterdevice)).
|
||||
Disabling DMA limits a transaction to 32 bytes max.
|
||||
|
||||
!!! not
|
||||
|
||||
Omitting the `config` table returns an SPI bus master object without further initialization. This enables sharing the same SPI host with `sdmmc` in SD-SPI mode. First call `sdmmc.init(sdmmc.VSPI, ...)`, then `spi.master(spi.VSPI)`.
|
||||
|
||||
#### Returns
|
||||
SPI bus master object
|
||||
|
||||
|
|
|
@ -23,8 +23,12 @@ Refer to the [`sdmmc` module documentation](modules/sdmmc.md).
|
|||
Before mounting the volume(s) on the SD card, you need to initialize the SDMMC interface from Lua.
|
||||
|
||||
```lua
|
||||
-- for SDMMC mode:
|
||||
card = sdmmc.init(sdmmc.HS2, {width = sdmmc.W1BIT})
|
||||
|
||||
-- for SD SPI mode:
|
||||
card = sdmmc.init(sdmmc.VSPI, {sck_pin = 18, mosi_pin = 23, miso_pin = 19, cs_pin = 22})
|
||||
|
||||
-- then mount the sd
|
||||
-- note: the card initialization process during `card:mount()` will set spi divider temporarily to 200 (400 kHz)
|
||||
-- it's reverted back to the current user setting before `card:mount()` finishes
|
||||
|
|
Loading…
Reference in New Issue