Add sdmmc module and enable fatfs.
This commit is contained in:
parent
31cb312c72
commit
fb62011ddf
|
@ -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
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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__ */
|
||||||
|
|
|
@ -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] ) )) {
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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);
|
|
||||||
|
|
|
@ -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);
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
||||||
//
|
//
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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 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 bytes)
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
`nil`
|
||||||
|
|
||||||
|
Error is thrown for invalid parameters or if sector(s) cannot be written.
|
|
@ -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.
|
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
|
@ -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'
|
||||||
|
|
Loading…
Reference in New Issue