[DeviceDrivers]Add SPI flash probe and delete function to SFUD driver.

This commit is contained in:
armink 2016-10-10 10:24:30 +08:00
parent 16dad06fc7
commit 1d71f58350
4 changed files with 161 additions and 123 deletions

View File

@ -52,27 +52,11 @@
#define SFUD_USING_FLASH_INFO_TABLE #define SFUD_USING_FLASH_INFO_TABLE
#endif #endif
/**
* User defined flash device table.
* e.g.
* enum {
* SFUD_W25Q64_DEVICE_INDEX = 0,
* SFUD_SST25VF016B_DEVICE_INDEX = 1,
* };
* #define RT_SFUD_FLASH_DEVICE_TABLE \
* { \
* [SFUD_W25Q64_DEVICE_INDEX] = {.name = "W25Q64", .spi.name = "spi10"}, \
* [SFUD_SST25VF016B_DEVICE_INDEX] = {.name = "SST25VF016B", .spi.name = "spi30"}, \
* }
*/
#ifndef RT_SFUD_FLASH_DEVICE_TABLE
#error "Please configure the flash device information table in (in rtconfig.h)."
#else
#define SFUD_FLASH_DEVICE_TABLE RT_SFUD_FLASH_DEVICE_TABLE
#endif
#if !defined(RT_SFUD_USING_SFDP) && !defined(RT_SFUD_USING_FLASH_INFO_TABLE) #if !defined(RT_SFUD_USING_SFDP) && !defined(RT_SFUD_USING_FLASH_INFO_TABLE)
#error "Please configure RT_SFUD_USING_SFDP or RT_SFUD_USING_FLASH_INFO_TABLE at least one kind of mode (in rtconfig.h)." #error "Please configure RT_SFUD_USING_SFDP or RT_SFUD_USING_FLASH_INFO_TABLE at least one kind of mode (in rtconfig.h)."
#endif #endif
#define SFUD_FLASH_DEVICE_TABLE NULL
#endif /* _SFUD_CFG_H_ */ #endif /* _SFUD_CFG_H_ */

View File

@ -31,6 +31,9 @@ struct spi_flash_device
struct rt_device_blk_geometry geometry; struct rt_device_blk_geometry geometry;
struct rt_spi_device * rt_spi_device; struct rt_spi_device * rt_spi_device;
struct rt_mutex lock; struct rt_mutex lock;
void * user_data;
}; };
typedef struct spi_flash_device *rt_spi_flash_device_t;
#endif #endif

View File

@ -30,9 +30,9 @@
#ifdef RT_USING_SFUD #ifdef RT_USING_SFUD
#if RT_DEBUG_SFUD #if RT_DEBUG_SFUD
#define SFUD_TRACE rt_kprintf #define DEBUG_TRACE rt_kprintf("[SFUD] "); rt_kprintf
#else #else
#define SFUD_TRACE(...) #define DEBUG_TRACE(...)
#endif /* RT_DEBUG_SFUD */ #endif /* RT_DEBUG_SFUD */
#ifndef RT_SFUD_DEFAULT_SPI_CFG #ifndef RT_SFUD_DEFAULT_SPI_CFG
@ -231,47 +231,62 @@ sfud_err sfud_spi_port_init(sfud_flash *flash) {
} }
/** /**
* SPI Flash device initialize by SFUD(Serial Flash Universal Driver) library * Probe SPI flash by SFUD(Serial Flash Universal Driver) driver library and though SPI device.
* *
* @param rtt_dev the static RT-Thread's flash device object * @param spi_flash_dev_name the name which will create SPI flash device
* @param sfud_dev the static SFUD's flash device object * @param spi_dev_name using SPI device name
* *
* @return result * @return probed SPI flash device, probe failed will return RT_NULL
*/ */
rt_err_t rt_sfud_init(struct spi_flash_device *rtt_dev, sfud_flash *sfud_dev) { rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const char *spi_dev_name) {
rt_spi_flash_device_t rtt_dev = RT_NULL;
sfud_flash *sfud_dev = RT_NULL;
char *spi_flash_dev_name_bak = RT_NULL, *spi_dev_name_bak = RT_NULL;
extern sfud_err sfud_device_init(sfud_flash *flash); extern sfud_err sfud_device_init(sfud_flash *flash);
RT_ASSERT(rtt_dev); RT_ASSERT(spi_flash_dev_name);
RT_ASSERT(sfud_dev); RT_ASSERT(spi_dev_name);
rtt_dev = (rt_spi_flash_device_t) rt_malloc(sizeof(struct spi_flash_device));
sfud_dev = (sfud_flash_t) rt_malloc(sizeof(sfud_flash));
spi_flash_dev_name_bak = (char *) rt_malloc(rt_strlen(spi_flash_dev_name) + 1);
spi_dev_name_bak = (char *) rt_malloc(rt_strlen(spi_dev_name) + 1);
if (rtt_dev && sfud_dev && spi_flash_dev_name_bak && spi_dev_name_bak) {
rt_memset(rtt_dev, 0, sizeof(struct spi_flash_device)); rt_memset(rtt_dev, 0, sizeof(struct spi_flash_device));
rt_memset(sfud_dev, 0, sizeof(sfud_flash));
rt_strncpy(spi_flash_dev_name_bak, spi_flash_dev_name, rt_strlen(spi_flash_dev_name));
rt_strncpy(spi_dev_name_bak, spi_dev_name, rt_strlen(spi_dev_name));
/* make string end sign */
spi_flash_dev_name_bak[rt_strlen(spi_flash_dev_name)] = '\0';
spi_dev_name_bak[rt_strlen(spi_dev_name)] = '\0';
/* SPI configure */ /* SPI configure */
{ {
/* RT-Thread SPI device initialize */ /* RT-Thread SPI device initialize */
rtt_dev->rt_spi_device = (struct rt_spi_device *) rt_device_find(sfud_dev->spi.name); rtt_dev->rt_spi_device = (struct rt_spi_device *) rt_device_find(spi_dev_name);
if (rtt_dev->rt_spi_device == RT_NULL) { if (rtt_dev->rt_spi_device == RT_NULL) {
SFUD_TRACE("spi device %s not found!\r\n", sfud_dev->spi.name); rt_kprintf("ERROR: SPI device %s not found!\n", spi_dev_name);
return -RT_ENOSYS; goto error;
} }
sfud_dev->spi.name = spi_dev_name_bak;
/* using default flash SPI configuration for initialize SPI Flash /* using default flash SPI configuration for initialize SPI Flash
* @note you also can change the SPI to other configuration after initialized finish */ * @note you also can change the SPI to other configuration after initialized finish */
struct rt_spi_configuration cfg = RT_SFUD_DEFAULT_SPI_CFG; struct rt_spi_configuration cfg = RT_SFUD_DEFAULT_SPI_CFG;
rt_spi_configure(rtt_dev->rt_spi_device, &cfg); rt_spi_configure(rtt_dev->rt_spi_device, &cfg);
/* initialize lock */ /* initialize lock */
rt_mutex_init(&(rtt_dev->lock), sfud_dev->name, RT_IPC_FLAG_FIFO); rt_mutex_init(&(rtt_dev->lock), spi_flash_dev_name, RT_IPC_FLAG_FIFO);
} }
/* SFUD flash device initialize */ /* SFUD flash device initialize */
{ {
sfud_dev->name = spi_flash_dev_name_bak;
/* accessed each other */ /* accessed each other */
rtt_dev->user_data = sfud_dev; rtt_dev->user_data = sfud_dev;
rtt_dev->flash_device.user_data = rtt_dev; rtt_dev->flash_device.user_data = rtt_dev;
sfud_dev->user_data = rtt_dev; sfud_dev->user_data = rtt_dev;
/* initialize SFUD device */ /* initialize SFUD device */
if (sfud_device_init(sfud_dev) != SFUD_SUCCESS) { if (sfud_device_init(sfud_dev) != SFUD_SUCCESS) {
return -RT_EIO; rt_kprintf("ERROR: SPI flash probe failed by SPI device %s.\n", spi_dev_name);
goto error;
} }
/* when initialize success, then copy SFUD flash device's geometry to RT-Thread SPI flash device */ /* when initialize success, then copy SFUD flash device's geometry to RT-Thread SPI flash device */
rtt_dev->geometry.sector_count = sfud_dev->chip.capacity / sfud_dev->chip.erase_gran; rtt_dev->geometry.sector_count = sfud_dev->chip.capacity / sfud_dev->chip.erase_gran;
@ -288,7 +303,46 @@ rt_err_t rt_sfud_init(struct spi_flash_device *rtt_dev, sfud_flash *sfud_dev) {
rtt_dev->flash_device.write = rt_sfud_write; rtt_dev->flash_device.write = rt_sfud_write;
rtt_dev->flash_device.control = rt_sfud_control; rtt_dev->flash_device.control = rt_sfud_control;
rt_device_register(&(rtt_dev->flash_device), sfud_dev->name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE); rt_device_register(&(rtt_dev->flash_device), spi_flash_dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
DEBUG_TRACE("Probe SPI flash %s by SPI device %s success.\n",spi_flash_dev_name, spi_dev_name);
return rtt_dev;
} else {
rt_kprintf("ERROR: Low memory.\n");
goto error;
}
error:
/* may be one of objects memory was malloc success, so need free all */
rt_free(rtt_dev);
rt_free(sfud_dev);
rt_free(spi_flash_dev_name_bak);
rt_free(spi_dev_name_bak);
return RT_NULL;
}
/**
* Delete SPI flash device
*
* @param spi_flash_dev SPI flash device
*
* @return the operation status, RT_EOK on successful
*/
rt_err_t rt_sfud_flash_delete(rt_spi_flash_device_t spi_flash_dev) {
sfud_flash *sfud_flash_dev = (sfud_flash *) (spi_flash_dev->user_data);
RT_ASSERT(spi_flash_dev);
RT_ASSERT(sfud_flash_dev);
rt_device_unregister(&(spi_flash_dev->flash_device));
rt_mutex_detach(&(spi_flash_dev->lock));
rt_free(sfud_flash_dev->spi.name);
rt_free(sfud_flash_dev->name);
rt_free(sfud_flash_dev);
rt_free(spi_flash_dev);
return RT_EOK; return RT_EOK;
} }
@ -307,16 +361,17 @@ static void sf(uint8_t argc, char **argv) {
#define CMD_BENCH_INDEX 5 #define CMD_BENCH_INDEX 5
sfud_err result = SFUD_SUCCESS; sfud_err result = SFUD_SUCCESS;
const static sfud_flash *flash = NULL; static const sfud_flash *sfud_dev = NULL;
static rt_spi_flash_device_t rtt_dev = NULL, rtt_dev_bak = NULL;
size_t i = 0; size_t i = 0;
const char* sf_help_info[] = { const char* sf_help_info[] = {
[CMD_SETECT_INDEX] = "sf select [index] - select a flash chip with device's index", [CMD_SETECT_INDEX] = "sf probe [spi_device] - probe and init SPI flash by given 'spi_device'",
[CMD_READ_INDEX] = "sf read addr size - read 'size' bytes starting at 'addr'", [CMD_READ_INDEX] = "sf read addr size - read 'size' bytes starting at 'addr'",
[CMD_WRITE_INDEX] = "sf write addr data1 ... dataN - write some bytes 'data' to flash starting at 'addr'", [CMD_WRITE_INDEX] = "sf write addr data1 ... dataN - write some bytes 'data' to flash starting at 'addr'",
[CMD_ERASE_INDEX] = "sf erase addr size - erase 'size' bytes starting at 'addr'", [CMD_ERASE_INDEX] = "sf erase addr size - erase 'size' bytes starting at 'addr'",
[CMD_RW_STATUS_INDEX] = "sf status [<volatile> <status>] - read or write '1:volatile|0:non-volatile' 'status'", [CMD_RW_STATUS_INDEX] = "sf status [<volatile> <status>] - read or write '1:volatile|0:non-volatile' 'status'",
[CMD_BENCH_INDEX] = "sf bench - full chip benchmark. DANGER: it will erase full chip!", [CMD_BENCH_INDEX] = "sf bench - full chip benchmark. DANGER: It will erase full chip!",
}; };
if (argc < 2) { if (argc < 2) {
@ -329,48 +384,31 @@ static void sf(uint8_t argc, char **argv) {
const char *operator = argv[1]; const char *operator = argv[1];
uint32_t addr, size; uint32_t addr, size;
if (!strcmp(operator, "select")) { if (!strcmp(operator, "probe")) {
if (argc < 3) { if (argc < 3) {
rt_kprintf("Usage: %s.\n", sf_help_info[CMD_SETECT_INDEX]); rt_kprintf("Usage: %s.\n", sf_help_info[CMD_SETECT_INDEX]);
if (sfud_get_device_num() > 0) {
for (i = 0; i < sfud_get_device_num(); i++) {
if (sfud_get_device(i)->init_ok) {
rt_kprintf("The index %d flash device name is %s, ", i, sfud_get_device(i)->name);
if (sfud_get_device(i)->chip.capacity < 1024 * 1024) {
rt_kprintf("total is %d KB", sfud_get_device(i)->chip.capacity / 1024);
} else { } else {
rt_kprintf("total is %d MB", sfud_get_device(i)->chip.capacity / 1024 / 1024); char *spi_dev_name = argv[2];
} rtt_dev_bak = rtt_dev;
if (sfud_get_device(i)->chip.name != NULL) { rtt_dev = rt_sfud_flash_probe("sf_cmd", spi_dev_name);
rt_kprintf(", type is %s", sfud_get_device(i)->chip.name); if (!rtt_dev) {
}
rt_kprintf(".\n");
}
}
} else {
rt_kprintf("There is no flash device in device table.\n");
}
} else {
size_t device_index = atol(argv[2]);
if (device_index >= sfud_get_device_num()) {
rt_kprintf("Flash device index out bound[0:%d].\n", sfud_get_device_num() - 1);
return; return;
} }
if (!sfud_get_device(device_index)->init_ok) { /* already probe then delete the old SPI flash device */
rt_kprintf("Flash %s isn't initialize OK.\n", sfud_get_device(device_index)->name); if(rtt_dev_bak) {
return; rt_sfud_flash_delete(rtt_dev_bak);
} }
flash = sfud_get_device(device_index); sfud_dev = (sfud_flash_t)rtt_dev->user_data;
if (flash->chip.capacity < 1024 * 1024) { if (sfud_dev->chip.capacity < 1024 * 1024) {
rt_kprintf("%d KB %s is current selected device.\n", flash->chip.capacity / 1024, flash->name); rt_kprintf("%d KB %s is current selected device.\n", sfud_dev->chip.capacity / 1024, sfud_dev->name);
} else { } else {
rt_kprintf("%d MB %s is current selected device.\n", flash->chip.capacity / 1024 / 1024, rt_kprintf("%d MB %s is current selected device.\n", sfud_dev->chip.capacity / 1024 / 1024,
flash->name); sfud_dev->name);
} }
} }
} else { } else {
if (!flash) { if (!sfud_dev) {
rt_kprintf("No flash device selected. Please run 'sf select'.\n"); rt_kprintf("No flash device selected. Please run 'sf probe'.\n");
return; return;
} }
if (!rt_strcmp(operator, "read")) { if (!rt_strcmp(operator, "read")) {
@ -382,10 +420,10 @@ static void sf(uint8_t argc, char **argv) {
size = atol(argv[3]); size = atol(argv[3]);
uint8_t *data = rt_malloc(size); uint8_t *data = rt_malloc(size);
if (data) { if (data) {
result = sfud_read(flash, addr, size, data); result = sfud_read(sfud_dev, addr, size, data);
if (result == SFUD_SUCCESS) { if (result == SFUD_SUCCESS) {
rt_kprintf("Read the %s flash data success. Start from 0x%08X, size is %ld. The data is:\n", rt_kprintf("Read the %s flash data success. Start from 0x%08X, size is %ld. The data is:\n",
flash->name, addr, size); sfud_dev->name, addr, size);
rt_kprintf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"); rt_kprintf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
if (i % 16 == 0) { if (i % 16 == 0) {
@ -415,10 +453,10 @@ static void sf(uint8_t argc, char **argv) {
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
data[i] = atoi(argv[3 + i]); data[i] = atoi(argv[3 + i]);
} }
result = sfud_write(flash, addr, size, data); result = sfud_write(sfud_dev, addr, size, data);
if (result == SFUD_SUCCESS) { if (result == SFUD_SUCCESS) {
rt_kprintf("Write the %s flash data success. Start from 0x%08X, size is %ld.\n", rt_kprintf("Write the %s flash data success. Start from 0x%08X, size is %ld.\n",
flash->name, addr, size); sfud_dev->name, addr, size);
rt_kprintf("Write data: "); rt_kprintf("Write data: ");
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
rt_kprintf("%d ", data[i]); rt_kprintf("%d ", data[i]);
@ -437,34 +475,38 @@ static void sf(uint8_t argc, char **argv) {
} else { } else {
addr = atol(argv[2]); addr = atol(argv[2]);
size = atol(argv[3]); size = atol(argv[3]);
result = sfud_erase(flash, addr, size); result = sfud_erase(sfud_dev, addr, size);
if (result == SFUD_SUCCESS) { if (result == SFUD_SUCCESS) {
rt_kprintf("Erase the %s flash data success. Start from 0x%08X, size is %ld.\n", flash->name, rt_kprintf("Erase the %s flash data success. Start from 0x%08X, size is %ld.\n", sfud_dev->name,
addr, size); addr, size);
} }
} }
} else if (!rt_strcmp(operator, "status")) { } else if (!rt_strcmp(operator, "status")) {
if (argc < 3) { if (argc < 3) {
uint8_t status; uint8_t status;
result = sfud_read_status(flash, &status); result = sfud_read_status(sfud_dev, &status);
if (result == SFUD_SUCCESS) { if (result == SFUD_SUCCESS) {
rt_kprintf("The %s flash status register current value is 0x%02X.\n", flash->name, status); rt_kprintf("The %s flash status register current value is 0x%02X.\n", sfud_dev->name, status);
} }
} else if (argc == 4) { } else if (argc == 4) {
bool is_volatile = atoi(argv[2]); bool is_volatile = atoi(argv[2]);
uint8_t status = atoi(argv[3]); uint8_t status = atoi(argv[3]);
result = sfud_write_status(flash, is_volatile, status); result = sfud_write_status(sfud_dev, is_volatile, status);
if (result == SFUD_SUCCESS) { if (result == SFUD_SUCCESS) {
rt_kprintf("Write the %s flash status register to 0x%02X success.\n", flash->name, status); rt_kprintf("Write the %s flash status register to 0x%02X success.\n", sfud_dev->name, status);
} }
} else { } else {
rt_kprintf("Usage: %s.\n", sf_help_info[CMD_RW_STATUS_INDEX]); rt_kprintf("Usage: %s.\n", sf_help_info[CMD_RW_STATUS_INDEX]);
return; return;
} }
} else if (!rt_strcmp(operator, "bench")) { } else if (!rt_strcmp(operator, "bench")) {
if ((argc > 2 && rt_strcmp(argv[2], "yes")) || argc < 3) {
rt_kprintf("DANGER: It will erase full chip! Please run 'sf bench yes'.");
return;
}
/* full chip benchmark test */ /* full chip benchmark test */
addr = 0; addr = 0;
size = flash->chip.capacity; size = sfud_dev->chip.capacity;
uint32_t start_time, time_cast; uint32_t start_time, time_cast;
rt_uint32_t total_mem, used_mem, max_uesd_mem; rt_uint32_t total_mem, used_mem, max_uesd_mem;
rt_memory_info(&total_mem, &used_mem, &max_uesd_mem); rt_memory_info(&total_mem, &used_mem, &max_uesd_mem);
@ -479,9 +521,9 @@ static void sf(uint8_t argc, char **argv) {
if (write_data && read_data) { if (write_data && read_data) {
rt_memset(write_data, 0x55, write_size); rt_memset(write_data, 0x55, write_size);
/* benchmark testing */ /* benchmark testing */
rt_kprintf("Erasing the %s %ld bytes data, waiting...\n", flash->name, size); rt_kprintf("Erasing the %s %ld bytes data, waiting...\n", sfud_dev->name, size);
start_time = rt_tick_get(); start_time = rt_tick_get();
result = sfud_erase(flash, addr, size); result = sfud_erase(sfud_dev, addr, size);
if (result == SFUD_SUCCESS) { if (result == SFUD_SUCCESS) {
time_cast = rt_tick_get() - start_time; time_cast = rt_tick_get() - start_time;
rt_kprintf("Erase benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND, rt_kprintf("Erase benchmark success, total time: %d.%03dS.\n", time_cast / RT_TICK_PER_SECOND,
@ -490,10 +532,10 @@ static void sf(uint8_t argc, char **argv) {
rt_kprintf("Erase benchmark has an error. Error code: %d.\n", result); rt_kprintf("Erase benchmark has an error. Error code: %d.\n", result);
} }
/* write test */ /* write test */
rt_kprintf("Writing the %s %ld bytes data, waiting...\n", flash->name, size); rt_kprintf("Writing the %s %ld bytes data, waiting...\n", sfud_dev->name, size);
start_time = rt_tick_get(); start_time = rt_tick_get();
for (i = 0; i < size; i += write_size) { for (i = 0; i < size; i += write_size) {
result = sfud_write(flash, addr + i, write_size, write_data); result = sfud_write(sfud_dev, addr + i, write_size, write_data);
if (result != SFUD_SUCCESS) { if (result != SFUD_SUCCESS) {
break; break;
} }
@ -506,13 +548,13 @@ static void sf(uint8_t argc, char **argv) {
rt_kprintf("Write benchmark has an error. Error code: %d.\n", result); rt_kprintf("Write benchmark has an error. Error code: %d.\n", result);
} }
/* read test */ /* read test */
rt_kprintf("Reading the %s %ld bytes data, waiting...\n", flash->name, size); rt_kprintf("Reading the %s %ld bytes data, waiting...\n", sfud_dev->name, size);
start_time = rt_tick_get(); start_time = rt_tick_get();
for (i = 0; i < size; i += read_size) { for (i = 0; i < size; i += read_size) {
if (i + read_size <= size) { if (i + read_size <= size) {
result = sfud_read(flash, addr + i, read_size, read_data); result = sfud_read(sfud_dev, addr + i, read_size, read_data);
} else { } else {
result = sfud_read(flash, addr + i, size - i, read_data); result = sfud_read(sfud_dev, addr + i, size - i, read_data);
} }
if (result != SFUD_SUCCESS) { if (result != SFUD_SUCCESS) {
break; break;

View File

@ -29,13 +29,22 @@
#include "./sfud/inc/sfud.h" #include "./sfud/inc/sfud.h"
/** /**
* SPI Flash device initialize by SFUD(Serial Flash Universal Driver) library * Probe SPI flash by SFUD(Serial Flash Universal Driver) driver library and though SPI device.
* *
* @param rtt_dev the static RT-Thread's flash device object * @param spi_flash_dev_name the name which will create SPI flash device
* @param sfud_dev the static SFUD's flash device object * @param spi_dev_name using SPI device name
* *
* @return result * @return probed SPI flash device, probe failed will return RT_NULL
*/ */
extern rt_err_t rt_sfud_init(struct spi_flash_device *rtt_flash, sfud_flash *sfud_flash); rt_spi_flash_device_t rt_sfud_flash_probe(const char *spi_flash_dev_name, const char *spi_dev_name);
/**
* Delete SPI flash device
*
* @param spi_flash_dev SPI flash device
*
* @return the operation status, RT_EOK on successful
*/
rt_err_t rt_sfud_flash_delete(rt_spi_flash_device_t spi_flash_dev);
#endif /* _SPI_FLASH_SFUD_H_ */ #endif /* _SPI_FLASH_SFUD_H_ */