Add sdmmc module and enable fatfs.

This commit is contained in:
devsaurus 2017-04-15 17:38:20 +02:00
parent 31cb312c72
commit fb62011ddf
16 changed files with 530 additions and 133 deletions

View File

@ -3,4 +3,4 @@ COMPONENT_SRCDIRS:=. option
COMPONENT_OBJS:=diskio.o ff.o myfatfs.o option/unicode.o COMPONENT_OBJS:=diskio.o ff.o myfatfs.o option/unicode.o
COMPONENT_ADD_INCLUDEDIRS:=. COMPONENT_ADD_INCLUDEDIRS:=.
EXTRA_CFLAGS:=-imacros fatfs_prefix_lib.h CFLAGS+=-imacros fatfs_prefix_lib.h

View File

@ -8,7 +8,11 @@
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#include "diskio.h" /* FatFs lower layer API */ #include "diskio.h" /* FatFs lower layer API */
#include "sdcard.h" #include "sdmmc_cmd.h"
// defined in components/modules/sdmmc.c
extern sdmmc_card_t lsdmmc_card[2];
static DSTATUS m_status = STA_NOINIT; static DSTATUS m_status = STA_NOINIT;
@ -20,6 +24,8 @@ DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */ BYTE pdrv /* Physical drive nmuber to identify the drive */
) )
{ {
(void)pdrv;
return m_status; return m_status;
} }
@ -33,9 +39,9 @@ DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */ BYTE pdrv /* Physical drive nmuber to identify the drive */
) )
{ {
if (platform_sdcard_init( 1, pdrv )) { (void)pdrv;
m_status &= ~STA_NOINIT;
} m_status &= ~STA_NOINIT;
return m_status; return m_status;
} }
@ -53,17 +59,10 @@ DRESULT disk_read (
UINT count /* Number of sectors to read */ UINT count /* Number of sectors to read */
) )
{ {
if (count == 1) { if (sdmmc_read_sectors( &(lsdmmc_card[pdrv]), buff, sector, count ) == ESP_OK)
if (! platform_sdcard_read_block( pdrv, sector, buff )) { return RES_OK;
return RES_ERROR;
}
} else {
if (! platform_sdcard_read_blocks( pdrv, sector, count, buff )) {
return RES_ERROR;
}
}
return RES_OK; return RES_ERROR;
} }
@ -78,17 +77,10 @@ DRESULT disk_write (
UINT count /* Number of sectors to write */ UINT count /* Number of sectors to write */
) )
{ {
if (count == 1) { if (sdmmc_write_sectors( &(lsdmmc_card[pdrv]), buff, sector, count ) == ESP_OK)
if (! platform_sdcard_write_block( pdrv, sector, buff )) { return RES_OK;
return RES_ERROR;
}
} else {
if (! platform_sdcard_write_blocks( pdrv, sector, count, buff )) {
return RES_ERROR;
}
}
return RES_OK; return RES_ERROR;
} }
@ -102,6 +94,9 @@ DRESULT disk_ioctl (
void *buff /* Buffer to send/receive control data */ void *buff /* Buffer to send/receive control data */
) )
{ {
(void)pdrv;
(void)buff;
switch (cmd) { switch (cmd) {
case CTRL_TRIM: /* no-op */ case CTRL_TRIM: /* no-op */
case CTRL_SYNC: /* no-op */ case CTRL_SYNC: /* no-op */

View File

@ -11,14 +11,14 @@ typedef struct {
#endif #endif
// Table to map physical drive & partition to a logical volume. // Table to map physical drive & partition to a logical volume.
// The first value is the physical drive and contains the GPIO pin for SS/CS of the SD card (default pin 8) // The first value is the physical drive which relates to the SDMMC slot number
// The second value is the partition number. // The second value is the partition number.
#define NUM_LOGICAL_DRIVES 4 #define NUM_LOGICAL_DRIVES 4
PARTITION VolToPart[NUM_LOGICAL_DRIVES] = { PARTITION VolToPart[NUM_LOGICAL_DRIVES] = {
{8, 1}, /* Logical drive "0:" ==> SS pin 8, 1st partition */ {1, 1}, /* Logical drive "0:" ==> slot 1, 1st partition */
{8, 2}, /* Logical drive "1:" ==> SS pin 8, 2st partition */ {1, 2}, /* Logical drive "1:" ==> slot 1, 2st partition */
{8, 3}, /* Logical drive "2:" ==> SS pin 8, 3st partition */ {1, 3}, /* Logical drive "2:" ==> slot 1, 3st partition */
{8, 4} /* Logical drive "3:" ==> SS pin 8, 4st partition */ {1, 4} /* Logical drive "3:" ==> slot 1, 4st partition */
}; };
#endif /* __FATFS_CONFIG_H__ */ #endif /* __FATFS_CONFIG_H__ */

View File

@ -185,6 +185,7 @@ DWORD get_fattime( void )
static int32_t myfatfs_umount( const struct vfs_vol *vol ) static int32_t myfatfs_umount( const struct vfs_vol *vol )
{ {
GET_FATFS_FS(vol); GET_FATFS_FS(vol);
(void)fs;
last_result = f_mount( NULL, myvol->ldrname, 0 ); last_result = f_mount( NULL, myvol->ldrname, 0 );
@ -354,6 +355,7 @@ static vfs_item *myfatfs_readdir( const struct vfs_dir *dd )
static void myfatfs_iclose( const struct vfs_item *di ) static void myfatfs_iclose( const struct vfs_item *di )
{ {
GET_FILINFO_FNO(di); GET_FILINFO_FNO(di);
(void)fno;
// free descriptor memory // free descriptor memory
free( (void *)di ); free( (void *)di );
@ -430,7 +432,7 @@ static vfs_vol *myfatfs_mount( const char *name, int num )
{ {
struct myvfs_vol *vol; struct myvfs_vol *vol;
// num argument specifies the physical driver = SS/CS pin number for this sd card // num argument specifies the physical driver
if (num >= 0) { if (num >= 0) {
for (int i = 0; i < NUM_LOGICAL_DRIVES; i++) { for (int i = 0; i < NUM_LOGICAL_DRIVES; i++) {
if (0 == strncmp( name, volstr[i], strlen( volstr[i] ) )) { if (0 == strncmp( name, volstr[i], strlen( volstr[i] ) )) {

View File

@ -116,6 +116,12 @@ config LUA_MODULE_OW
help help
Includes the 1-Wire (ow) module (recommended). Includes the 1-Wire (ow) module (recommended).
config LUA_MODULE_SDMMC
bool "SD-MMC module"
default "n"
help
Includes the sdmmc module.
config LUA_MODULE_SIGMA_DELTA config LUA_MODULE_SIGMA_DELTA
bool "Sigma-Delta module" bool "Sigma-Delta module"
default "n" default "n"

View File

@ -380,25 +380,6 @@ typedef struct {
} volume_type; } volume_type;
#ifdef CONFIG_BUILD_FATFS #ifdef CONFIG_BUILD_FATFS
// Lua: vol = file.mount("/SD0")
static int file_mount( lua_State *L )
{
const char *ldrv = luaL_checkstring( L, 1 );
int num = luaL_optint( L, 2, -1 );
volume_type *vol = (volume_type *)lua_newuserdata( L, sizeof( volume_type ) );
if ((vol->vol = vfs_mount( ldrv, num ))) {
/* set its metatable */
luaL_getmetatable(L, "vfs.vol");
lua_setmetatable(L, -2);
return 1;
} else {
// remove created userdata
lua_pop( L, 1 );
return 0;
}
}
// Lua: success = file.chdir("/SD0/") // Lua: success = file.chdir("/SD0/")
static int file_chdir( lua_State *L ) static int file_chdir( lua_State *L )
{ {
@ -409,29 +390,6 @@ static int file_chdir( lua_State *L )
} }
#endif #endif
static int file_vol_umount( lua_State *L )
{
volume_type *vol = luaL_checkudata( L, 1, "file.vol" );
luaL_argcheck( L, vol, 1, "volume expected" );
lua_pushboolean( L, 0 <= vfs_umount( vol->vol ) );
// invalidate vfs descriptor, it has been free'd anyway
vol->vol = NULL;
return 1;
}
static const LUA_REG_TYPE file_vol_map[] =
{
{ LSTRKEY( "umount" ), LFUNCVAL( file_vol_umount )},
//{ LSTRKEY( "getfree" ), LFUNCVAL( file_vol_getfree )},
//{ LSTRKEY( "getlabel" ), LFUNCVAL( file_vol_getlabel )},
//{ LSTRKEY( "__gc" ), LFUNCVAL( file_vol_free ) },
{ LSTRKEY( "__index" ), LROVAL( file_vol_map ) },
{ LNILKEY, LNILVAL }
};
// Module function map // Module function map
static const LUA_REG_TYPE file_map[] = { static const LUA_REG_TYPE file_map[] = {
{ LSTRKEY( "list" ), LFUNCVAL( file_list ) }, { LSTRKEY( "list" ), LFUNCVAL( file_list ) },
@ -453,15 +411,9 @@ static const LUA_REG_TYPE file_map[] = {
{ LSTRKEY( "fsinfo" ), LFUNCVAL( file_fsinfo ) }, { LSTRKEY( "fsinfo" ), LFUNCVAL( file_fsinfo ) },
{ LSTRKEY( "on" ), LFUNCVAL( file_on ) }, { LSTRKEY( "on" ), LFUNCVAL( file_on ) },
#ifdef CONFIG_BUILD_FATFS #ifdef CONFIG_BUILD_FATFS
{ LSTRKEY( "mount" ), LFUNCVAL( file_mount ) },
{ LSTRKEY( "chdir" ), LFUNCVAL( file_chdir ) }, { LSTRKEY( "chdir" ), LFUNCVAL( file_chdir ) },
#endif #endif
{ LNILKEY, LNILVAL } { LNILKEY, LNILVAL }
}; };
int luaopen_file( lua_State *L ) { NODEMCU_MODULE(FILE, "file", file_map, NULL);
luaL_rometatable( L, "file.vol", (void *)file_vol_map );
return 0;
}
NODEMCU_MODULE(FILE, "file", file_map, luaopen_file);

293
components/modules/sdmmc.c Normal file
View File

@ -0,0 +1,293 @@
#include "module.h"
#include "lauxlib.h"
#include "lmem.h"
#include "vfs.h"
#include "driver/sdmmc_host.h"
#include "sdmmc_cmd.h"
sdmmc_card_t lsdmmc_card[2];
typedef struct {
sdmmc_card_t *card;
vfs_vol *vol;
} lsdmmc_ud_t;
static int lsdmmc_init( lua_State *L )
{
const char *err_msg = "";
int stack = 0;
int slot = luaL_checkint( L, ++stack );
luaL_argcheck( L, slot == SDMMC_HOST_SLOT_0 || slot == SDMMC_HOST_SLOT_1,
stack, "invalid slot" );
// 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;
if (lua_type( L, ++stack ) == LUA_TTABLE) {
// retrieve slot configuration from table
lua_getfield( L, stack, "cd_pin" );
cd_pin = luaL_optint( L, -1, cd_pin );
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 );
}
// initialize SDMMC host
// tolerate error due to re-initialization
esp_err_t 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) {
// 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) {
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->vol = NULL;
// all done
return 1;
}
} else
err_msg = "failed to init card";
} else
err_msg = "failed to init slot";
sdmmc_host_deinit();
} else
err_msg = "failed to init sdmmc host";
return luaL_error( L, err_msg );
}
#define GET_CARD_UD \
lsdmmc_ud_t *ud = (lsdmmc_ud_t *)luaL_checkudata( L, 1, "sdmmc.card" ); \
sdmmc_card_t *card = ud->card;
// Lua: data = card:read( start_sec, num_sec )
static int lsdmmc_read( lua_State * L)
{
const char *err_msg = "";
GET_CARD_UD;
int stack = 1;
int start_sec = luaL_checkint( L, ++stack );
luaL_argcheck( L, start_sec >= 0, stack, "out of range" );
int num_sec = luaL_optint( L, ++stack, 1 );
luaL_argcheck( L, num_sec >= 0, stack, "out of range" );
// get read buffer
char *rbuf = luaM_malloc( L, num_sec * 512 );
if (sdmmc_read_sectors( card, rbuf, start_sec, num_sec ) == ESP_OK) {
luaL_Buffer b;
luaL_buffinit( L, &b );
luaL_addlstring( &b, rbuf, num_sec * 512 );
luaL_pushresult( &b );
luaM_free( L, rbuf );
// all ok
return 1;
} else
err_msg = "card access failed";
return luaL_error( L, err_msg );
}
// Lua: card:write( start_sec, data )
static int lsdmmc_write( lua_State * L)
{
const char *err_msg = "";
GET_CARD_UD;
int stack = 1;
int start_sec = luaL_checkint( L, ++stack );
luaL_argcheck( L, start_sec >= 0, stack, "out of range" );
size_t len;
const char *wbuf = luaL_checklstring( L, ++stack, &len );
luaL_argcheck( L, len % 512 == 0, stack, "must be multiple of 512" );
if (sdmmc_write_sectors( card, wbuf, start_sec, len / 512 ) == ESP_OK) {
// all ok
return 0;
} else
err_msg = "card access failed";
return luaL_error( L, err_msg );
}
#define SET_INT_FIELD(item, elem) \
lua_pushinteger( L, card->item.elem ); \
lua_setfield( L, -2, #elem );
// Lua: info = card:get_info()
static int lsdmmc_get_info( lua_State *L )
{
GET_CARD_UD;
lua_newtable( L );
// OCR
lua_pushinteger( L, card->ocr );
lua_setfield( L, -2, "ocr" );
// CID
lua_newtable( L );
SET_INT_FIELD(cid, mfg_id);
SET_INT_FIELD(cid, oem_id);
SET_INT_FIELD(cid, revision);
SET_INT_FIELD(cid, serial);
SET_INT_FIELD(cid, date);
lua_pushstring( L, card->cid.name );
lua_setfield( L, -2, "name" );
//
lua_setfield( L, -2, "cid" );
// CSD
lua_newtable( L );
SET_INT_FIELD(csd, csd_ver);
SET_INT_FIELD(csd, mmc_ver);
SET_INT_FIELD(csd, capacity);
SET_INT_FIELD(csd, sector_size);
SET_INT_FIELD(csd, read_block_len);
SET_INT_FIELD(csd, card_command_class);
SET_INT_FIELD(csd, tr_speed);
//
lua_setfield( L, -2, "csd" );
// SCR
lua_newtable( L );
SET_INT_FIELD(scr, sd_spec);
SET_INT_FIELD(scr, bus_width);
//
lua_setfield( L, -2, "scr" );
// RCA
lua_pushinteger( L, card->rca );
lua_setfield( L, -2, "rca" );
return 1;
}
// Lua: card:mount("/SD0"[, partition])
static int lsdmmc_mount( lua_State *L )
{
const char *err_msg = "";
GET_CARD_UD;
(void)card;
int stack = 1;
const char *ldrv = luaL_checkstring( L, ++stack );
int num = luaL_optint( L, ++stack, -1 );
if (ud->vol == NULL) {
if ((ud->vol = vfs_mount( ldrv, num )))
lua_pushboolean( L, true );
else
lua_pushboolean( L, false );
return 1;
} else
err_msg = "already mounted";
return luaL_error( L, err_msg );
}
// Lua: card:umount()
static int lsdmmc_umount( lua_State *L )
{
const char *err_msg = "";
GET_CARD_UD;
(void)card;
if (ud->vol) {
if (vfs_umount( ud->vol ) == VFS_RES_OK) {
ud->vol = NULL;
// all ok
return 0;
} else
err_msg = "umount failed";
} else
err_msg = "not mounted";
return luaL_error( L, err_msg );
}
static const LUA_REG_TYPE sdmmc_card_map[] = {
{ LSTRKEY( "read" ), LFUNCVAL( lsdmmc_read ) },
{ LSTRKEY( "write" ), LFUNCVAL( lsdmmc_write ) },
{ LSTRKEY( "get_info" ), LFUNCVAL( lsdmmc_get_info ) },
{ LSTRKEY( "mount" ), LFUNCVAL( lsdmmc_mount ) },
{ LSTRKEY( "umount" ), LFUNCVAL( lsdmmc_umount ) },
{ LSTRKEY( "__index" ), LROVAL( sdmmc_card_map ) },
{ LNILKEY, LNILVAL }
};
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( "W1BIT" ), LNUMVAL( SDMMC_HOST_FLAG_1BIT ) },
{ LSTRKEY( "W4BIT" ), LNUMVAL( SDMMC_HOST_FLAG_1BIT |
SDMMC_HOST_FLAG_4BIT ) },
{ LSTRKEY( "W8BIT" ), LNUMVAL( SDMMC_HOST_FLAG_1BIT |
SDMMC_HOST_FLAG_4BIT |
SDMMC_HOST_FLAG_8BIT ) },
{ LNILKEY, LNILVAL }
};
static int luaopen_sdmmc( lua_State *L )
{
luaL_rometatable(L, "sdmmc.card", (void *)sdmmc_card_map);
return 0;
}
NODEMCU_MODULE(SDMMC, "sdmmc", sdmmc_map, luaopen_sdmmc);

View File

@ -105,6 +105,7 @@ config BUILD_SPIFFS
config BUILD_FATFS config BUILD_FATFS
bool "Support for FAT filesystems" bool "Support for FAT filesystems"
default "n" default "n"
select LUA_MODULE_SDMMC
help help
Include support for accessing FAT filesystems on SD cards. Include support for accessing FAT filesystems on SD cards.

View File

@ -1,18 +0,0 @@
#ifndef _SDCARD_H
#define _SDCARD_H
#include <stdint.h>
#include <stddef.h>
int platform_sdcard_init( uint8_t spi_no, uint8_t ss_pin );
int platform_sdcard_status( void );
int platform_sdcard_error( void );
int platform_sdcard_type( void );
int platform_sdcard_read_block( uint8_t ss_pin, uint32_t block, uint8_t *dst );
int platform_sdcard_read_blocks( uint8_t ss_pin, uint32_t block, size_t num, uint8_t *dst );
int platform_sdcard_read_csd( uint8_t ss_pin, uint8_t *csd );
int platform_sdcard_read_cid( uint8_t ss_pin, uint8_t *cid );
int platform_sdcard_write_block( uint8_t ss_pin, uint32_t block, const uint8_t *src );
int platform_sdcard_write_blocks( uint8_t ss_pin, uint32_t block, size_t num, const uint8_t *src );
#endif

View File

@ -214,8 +214,6 @@ static int32_t myspiffs_vfs_format( void );
static int32_t myspiffs_vfs_errno( void ); static int32_t myspiffs_vfs_errno( void );
static void myspiffs_vfs_clearerr( void ); static void myspiffs_vfs_clearerr( void );
static int32_t myspiffs_vfs_umount( const struct vfs_vol *vol );
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// function tables // function tables
// //
@ -310,16 +308,6 @@ static const char *myspiffs_vfs_name( const struct vfs_item *di ) {
} }
// ---------------------------------------------------------------------------
// volume functions
//
static int32_t myspiffs_vfs_umount( const struct vfs_vol *vol ) {
// not implemented
return VFS_RES_ERR;
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// dir functions // dir functions
// //

View File

@ -1,7 +1,7 @@
# file Module # file Module
| Since | Origin / Contributor | Maintainer | Source | | Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ | | :----- | :-------------------- | :---------- | :------ |
| 2014-12-22 | [Zeroday](https://github.com/funshine) | [Zeroday](https://github.com/funshine) | [file.c](../../../app/modules/file.c)| | 2014-12-22 | [Zeroday](https://github.com/funshine) | [Zeroday](https://github.com/funshine) | [file.c](../../../components/modules/file.c)|
The file module provides access to the file system and its individual files. The file module provides access to the file system and its individual files.
@ -206,28 +206,6 @@ for k,v in pairs(l) do
end end
``` ```
## file.mount()
Mounts a FatFs volume on SD card.
Not supported for internal flash.
#### Syntax
`file.mount(ldrv[, pin])`
#### Parameters
- `ldrv` name of the logical drive, `SD0:`, `SD1:`, etc.
- `pin` 1~12, IO index for SS/CS, defaults to 8 if omitted.
#### Returns
Volume object
#### Example
```lua
vol = file.mount("SD0:")
vol:umount()
```
## file.on() ## file.on()
Registers callback functions. Registers callback functions.

155
docs/en/modules/sdmmc.md Normal file
View File

@ -0,0 +1,155 @@
# SDMMC Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2017-04-17 | [Arnim Läuger](https://github.com/devsaurus) | [Arnim Läuger](https://github.com/devsaurus) | [sdmmc.c](../../../components/modules/sdmmc.c)|
!!! note
MMC cards are not yet supported due to missing functionality in the IDF driver.
## 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:
| SD mode name | SPI mode name | ESP32 HS1 I/F | ESP32 HS2 I/F |
| :--- | :--- | :--- | :--- |
| `CLK` | `CK, SCLK` | `GPIO6, HS1_CLK, SD_CLK` | `GPIO14, HS2_CLK, MTMS` |
| `CMD` | `DI, MOSI` | `GPIO11, HS1_CMD, SD_CMD` | `GPIO15, HS2_CMD, MTDO` |
| `DAT0` | `DO, MISO` | `GPIO7, HS1_DATA0, SD_DATA_0` | `GPIO2, HS2_DATA0` |
| `DAT1` | n/a | `GPIO8, HS1_DATA1, SD_DATA_1` | `GPIO4, HS2_DATA1` |
| `DAT2` | n/a | `GPIO9, HS1_DATA2, SD_DATA_2` | `GPIO12, HS2_DATA2, MTDI` |
| `DAT3` | `CS, SS` | `GPIO10, HS1_DATA3, SD_DATA_3` | `GPIO13, HS2_DATA3, MTCK` |
| `DAT4` (MMC) | n/a | `GPIO16, HS1_DATA4` | n/a |
| `DAT5` (MMC) | n/a | `GPIO17, HS1_DATA5` | n/a |
| `DAT6` (MMC) | n/a | `GPIO5, HS1_DATA6` | n/a |
| `DAT7` (MMC) | n/a | `GPIO18, HS1_DATA7` | n/a |
| `VDD` | `VCC, VDD` | 3V3 supply | 3V3 supply |
| `VSS1, VSS2` | `VSS, GND` | common ground | common ground |
Connections to `CLK`, `CMD`, and `DAT0` are mandatory and enable basic operation in 1-bit mode. For 4-bit mode `DAT1`, `DAT2`, and `DAT3` are required additionally.
!!! important
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
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.init()
Initialize the SDMMC and probe the attached SD card.
#### Syntax
`sdmmc.init(slot[, cfg])`
#### Parameters
- `slot` SDMMC slot, one of `sdmmc.HS1` or `sdmmc.HS2`
- `cfg` optional table containing slot configuration:
- `cd_pin` card detect pin, none if omitted
- `wp_pin` write-protcet pin, none if omitted
- `fmax` maximum communication frequency, defaults to 20&nbsp; if omitted
- `width` bis width, defaults to `sdmmc.W1BIT` if omitted, one of:
- `sdmmc.W1BIT`
- `sdmmc.W4BIT`
- `sdmmc.W8BIT`, not supported yet
#### Returns
Card object.
Error is thrown for invalid parameters or if SDMMC hardware or card cannot be initialized.
## card:get_info()
Retrieve information from the SD card.
#### Syntax
`card:get_info()`
#### Returns
Table containing the card's OCR, CID, CSD, SCR, and RCA with elements:
- `ocr` Operation Conditions Register
- `cid` Card IDentification
- `date` manufacturing date
- `mfg_id` manufacturer ID
- `name` product name
- `oem_id` OEM/product ID
- `revision` product revision
- `serial` product serial number
- `csd` Card-Specific Data
- `capacity` total number of sectors
- `card_command_class` card command class for SD
- `csd_ver` CSD structure format
- `mmc_ver` MMC version (for CID format)
- `read_block_len` block length for reads
- `sector_size` sector size in bytes
- `tr_speed` maximum transfer speed
- `scr`
- `sd_spec` SD physical layer specification version, reported by card
- `bus_width` bus widths supported by card
- `rca` Relative Card Address
## card:mount()
Mount filesystem on SD card.
#### Syntax
`card:mount(ldrv[, slot])`
#### Parameters
- `ldrv` name of logical drive, "/SD0", "/SD1", etc.
- `slot` one of `sdmmc.HS1` or `sdmmc.HS2`, defaults to `sdmmc.HS2` if omitted
#### Returns
`true` if successful, `false` otherwise
Error is thrown for invalid parameters or if filesystem is already mounted.
## card:read()
Read one or more sectors.
#### Syntax
`card:read(start_sec, num_sec)`
#### Parameters
- `start_sec` first sector to read from
- `num_sec` number of sectors to read (>= 1)
#### Returns
String containing the sector data.
Error is thrown for invalid parameters or if sector(s) cannot be read.
## card:umount()
Unmount filesystem.
#### Syntax
`card:umount()`
#### Parameters
None
#### Returns
`nil`
Error is thrown if filesystem is not mounted or if it cannot be unmounted.
## card:write()
Write one or more sectors.
#### Syntax
`card:write(start_sec, data)`
#### Parameters
- `start_sec` first sector to write to
- `data` string of data to write, must be multiple fo sector size (512&nbsp;bytes)
#### Returns
`nil`
Error is thrown for invalid parameters or if sector(s) cannot be written.

43
docs/en/sdcard.md Normal file
View File

@ -0,0 +1,43 @@
# FAT File System on SD Card
Accessing files on external SD cards is currently only supported from the `file` module. This imposes the same overall restrictions of internal SPIFFS to SD cards:
- limited support for sub-folders
- no timestamps
- no file attributes (read-only, system, etc.)
Work is in progress to extend the `file` API with support for the missing features.
## Enabling FatFs
The FAT file system is implemented by [Chan's FatFs](http://elm-chan.org/fsw/ff/00index_e.html) version [R0.12a](http://elm-chan.org/fsw/ff/ff12a.zip). It's disabled by default to save memory space and has to be enabled before compiling the firmware:
Enable "Support for FAT filesystems" in Comoponent config ---> Platform config and enable the sdmmc module for low-level control.
## SD Card connection
Refer to the [`sdmmc` module documentation](modules/sdmmc.md).
## Lua bindings
Before mounting the volume(s) on the SD card, you need to initialize the SDMMC interface from Lua.
```lua
card = sdmmc.init(sdmmc.HS2, {width = sdmmc.W1BIT})
-- 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
card:mount("/SD0")
file.open("/SD0/path/to/somefile")
print(file.read())
file.close()
```
The logical drives are mounted at the root of a unified directory tree where the mount points distinguish between internal flash (`/FLASH`) and the card's paritions (`/SD0` to `/SD3`). Files are accessed via either the absolute hierarchical path or relative to the current working directory. It defaults to `/FLASH` and can be changed with `file.chdir(path)`.
Subdirectories are supported on FAT volumes only.
## Multiple partitions / multiple cards
The mapping from logical volumes (eg. `/SD0`) to partitions on an SD card is defined in [`fatfs_config.h`](../../components/fatfs/fatfs_config.h). More volumes can be added to the `VolToPart` array with any combination of physical drive number (aka SDMMC slots) and partition number. Their names have to be added to `_VOLUME_STRS` in [`ffconf.h`](../../components/fatfs/ffconf.h) as well.

BIN
docs/img/micro_sd-small.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
docs/img/micro_sd.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -25,6 +25,7 @@ pages:
- English: - English:
- Building the firmware: 'en/build.md' - Building the firmware: 'en/build.md'
- Flashing the firmware: 'en/flash.md' - Flashing the firmware: 'en/flash.md'
- Filesystem on SD card: 'en/sdcard.md'
- Uploading code: 'en/upload.md' - Uploading code: 'en/upload.md'
- FAQs: - FAQs:
- Lua Developer FAQ: 'en/lua-developer-faq.md' - Lua Developer FAQ: 'en/lua-developer-faq.md'
@ -40,6 +41,7 @@ pages:
- 'i2c': 'en/modules/i2c.md' - 'i2c': 'en/modules/i2c.md'
- 'node': 'en/modules/node.md' - 'node': 'en/modules/node.md'
- 'ow (1-Wire)': 'en/modules/ow.md' - 'ow (1-Wire)': 'en/modules/ow.md'
- 'sdmmc': 'en/modules/sdmmc.md'
- 'sigma delta': 'en/modules/sigma-delta.md' - 'sigma delta': 'en/modules/sigma-delta.md'
- 'struct': 'en/modules/struct.md' - 'struct': 'en/modules/struct.md'
- 'tmr': 'en/modules/tmr.md' - 'tmr': 'en/modules/tmr.md'