stm: Mount SD card on 1:/ if present.

If SD card is present on (soft) reset then it's mounted on 1:/ and files
can be openned using, eg, open('1:/test.txt', 'r'), or 'w' for writing.
This commit is contained in:
Damien George 2014-02-08 16:00:15 +00:00
parent aea532ece1
commit 23177088d2
11 changed files with 351 additions and 135 deletions

View file

@ -58,7 +58,7 @@ SRC_C = \
usb.c \
timer.c \
audio.c \
sdio.c \
sdcard.c \
i2c.c \
usrsw.c \
adc.c \

View file

@ -13,20 +13,20 @@
#include "diskio.h" /* FatFs lower layer API */
#include "misc.h"
#include "storage.h"
#include "sdcard.h"
PARTITION VolToPart[] = {
{0, 1}, // Logical drive 0 ==> Physical drive 0, 1st partition
{1, 0}, // Logical drive 1 ==> Physical drive 1 (auto detection)
/*
{0, 2}, // Logical drive 1 ==> Physical drive 0, 2nd partition
{0, 3}, // Logical drive 2 ==> Physical drive 0, 3rd partition
{1, 0}, // Logical drive 3 ==> Physical drive 1 (auto detection)
{0, 2}, // Logical drive 2 ==> Physical drive 0, 2nd partition
{0, 3}, // Logical drive 3 ==> Physical drive 0, 3rd partition
*/
};
/* Definitions of physical drive number for each media */
#define PD_FLASH (0)
#define PD_SD (1)
#define BLOCK_SIZE (512)
#define PD_SDCARD (1)
/*-----------------------------------------------------------------------*/
/* Initialize a Drive */
@ -37,9 +37,16 @@ DSTATUS disk_initialize (
)
{
switch (pdrv) {
case PD_FLASH :
case PD_FLASH:
storage_init();
return 0;
case PD_SDCARD:
if (!sdcard_power_on()) {
return STA_NODISK;
}
// TODO return STA_PROTECT if SD card is read only
return 0;
}
return STA_NOINIT;
@ -58,8 +65,9 @@ DSTATUS disk_status (
// flash is ready
return 0;
case PD_SD:
return STA_NOINIT;
case PD_SDCARD:
// TODO return STA_PROTECT if SD card is read only
return 0;
}
return STA_NOINIT;
@ -79,7 +87,16 @@ DRESULT disk_read (
switch (pdrv) {
case PD_FLASH:
for (int i = 0; i < count; i++) {
if (!storage_read_block(buff + i * BLOCK_SIZE, sector + i)) {
if (!storage_read_block(buff + i * FLASH_BLOCK_SIZE, sector + i)) {
return RES_ERROR;
}
}
return RES_OK;
case PD_SDCARD:
// TODO have a multi-block read function
for (int i = 0; i < count; i++) {
if (!sdcard_read_block(buff + i * SDCARD_BLOCK_SIZE, sector + i)) {
return RES_ERROR;
}
}
@ -104,7 +121,16 @@ DRESULT disk_write (
switch (pdrv) {
case PD_FLASH:
for (int i = 0; i < count; i++) {
if (!storage_write_block(buff + i * BLOCK_SIZE, sector + i)) {
if (!storage_write_block(buff + i * FLASH_BLOCK_SIZE, sector + i)) {
return RES_ERROR;
}
}
return RES_OK;
case PD_SDCARD:
// TODO have a multi-block write function
for (int i = 0; i < count; i++) {
if (!sdcard_write_block(buff + i * SDCARD_BLOCK_SIZE, sector + i)) {
return RES_ERROR;
}
}
@ -138,6 +164,18 @@ DRESULT disk_ioctl (
*((DWORD*)buff) = 1; // high-level sector erase size in units of the small (512) block size
return RES_OK;
}
break;
case PD_SDCARD:
switch (cmd) {
case CTRL_SYNC:
return RES_OK;
case GET_BLOCK_SIZE:
*((DWORD*)buff) = 1; // high-level sector erase size in units of the small (512) block size
return RES_OK;
}
break;
}
return RES_PARERR;
@ -148,6 +186,7 @@ DWORD get_fattime (
void
)
{
// TODO replace with call to RTC
int year = 2013;
int month = 10;
int day = 12;

View file

@ -136,7 +136,7 @@
/ Drive/Volume Configurations
/----------------------------------------------------------------------------*/
#define _VOLUMES 1
#define _VOLUMES 2
/* Number of volumes (logical drives) to be used. */

View file

@ -35,6 +35,7 @@
#include "servo.h"
#include "lcd.h"
#include "storage.h"
#include "sdcard.h"
#include "mma.h"
#include "usart.h"
#include "usb.h"
@ -50,6 +51,7 @@
int errno;
static FATFS fatfs0;
static FATFS fatfs1;
void flash_error(int n) {
for (int i = 0; i < n; i++) {
@ -224,15 +226,6 @@ static mp_obj_t pyb_set_repl_info(mp_obj_t o_value) {
return mp_const_none;
}
#if MICROPY_HW_HAS_SDCARD
// SD card test
static mp_obj_t pyb_sd_test(void) {
extern void sdio_init(void);
sdio_init();
return mp_const_none;
}
#endif
static void SYSCLKConfig_STOP(void) {
/* After wake-up from STOP reconfigure the system clock */
/* Enable HSE */
@ -639,6 +632,9 @@ int main(void) {
// more sub-system init
#if MICROPY_HW_HAS_SWITCH
switch_init();
#endif
#if MICROPY_HW_HAS_SDCARD
sdcard_init();
#endif
storage_init();
@ -692,7 +688,7 @@ soft_reset:
rt_store_attr(m, MP_QSTR_gc, (mp_obj_t)&pyb_gc_obj);
rt_store_attr(m, qstr_from_str("repl_info"), rt_make_function_n(1, pyb_set_repl_info));
#if MICROPY_HW_HAS_SDCARD
rt_store_attr(m, MP_QSTR_sd_test, rt_make_function_n(0, pyb_sd_test));
rt_store_attr(m, qstr_from_str("SD"), (mp_obj_t)&pyb_sdcard_obj);
#endif
rt_store_attr(m, MP_QSTR_stop, rt_make_function_n(0, pyb_stop));
rt_store_attr(m, MP_QSTR_standby, rt_make_function_n(0, pyb_standby));
@ -844,6 +840,16 @@ soft_reset:
// turn boot-up LED off
led_state(PYB_LED_G1, 0);
#if MICROPY_HW_HAS_SDCARD
// if an SD card is present then mount it on 1:/
if (sdcard_is_present()) {
FRESULT res = f_mount(&fatfs1, "1:", 1);
if (res != FR_OK) {
printf("[SD] could not mount SD card\n");
}
}
#endif
// run main script
{
vstr_t *vstr = vstr_new();

204
stm/sdcard.c Normal file
View file

@ -0,0 +1,204 @@
// TODO
// make it work with DMA
#include <stdio.h>
//#include "stm32f4xx_sdio.h"
#include "stm324x7i_eval_sdio_sd.h"
#include "misc.h"
#include "systick.h"
#include "mpconfig.h"
#include "qstr.h"
#include "obj.h"
#include "runtime.h"
#include "sdcard.h"
#if 0
#define BLOCK_SIZE 512 /* Block Size in Bytes */
uint8_t aBuffer_Block_Rx[BLOCK_SIZE];
void sdio_init(void) {
SD_Error error = SD_Init();
printf("Init: %x\n", error);
uint8_t det = SD_Detect();
printf("Detc: %x\n", det);
if (!det) {
printf("no card detected\n");
SD_PowerOFF();
SD_DeInit();
return;
}
// read a block!
error = SD_ReadBlock(aBuffer_Block_Rx, 512, BLOCK_SIZE);
printf("ReadBlock: %d\n", error);
/*
// Check if the Transfer is finished
error = SD_WaitReadOperation();
printf("WaitReadOp: %d\n", error);
*/
uint32_t stc = sys_tick_counter;
while (SD_GetStatus() != SD_TRANSFER_OK) {
if (sys_tick_has_passed(stc, 2000)) {
printf("timeout waiting for read to finish\n");
break;
}
}
printf("done!!\n");
printf("%.16s", aBuffer_Block_Rx);
/*
snprintf((char*)aBuffer_Block_Rx, BLOCK_SIZE, "Here is some data back for you!\nBLOCK_SIZE=%d\n", BLOCK_SIZE);
error = SD_WriteBlock(aBuffer_Block_Rx, 512, BLOCK_SIZE);
printf("WriteBlock: %d\n", error);
while (SD_GetStatus() != SD_TRANSFER_OK) {
}
printf("done writing!\n");
*/
SD_PowerOFF();
SD_DeInit();
}
#endif
void sdcard_init(void) {
// init the SD card detect pin
SD_LowLevel_Init_Detect();
}
bool sdcard_is_present(void) {
return SD_Detect() != 0;
}
bool sdcard_power_on(void) {
if (!SD_Detect()) {
return false;
}
SD_Error status = SD_Init();
if (status != SD_OK) {
SD_PowerOFF();
SD_DeInit();
return false;
}
return true;
}
void sdcard_power_off(void) {
SD_PowerOFF();
SD_DeInit();
}
bool sdcard_read_block(uint8_t *dest, uint32_t block_num) {
// TODO return error if not powered on
SD_Error status;
status = SD_ReadBlock(dest, block_num * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE);
if (status != SD_OK) {
return false;
}
#ifdef SD_DMA_MODE
// wait for DMA transfer to finish
status = SD_WaitReadOperation();
if (status != SD_OK) {
return false;
}
#endif
// wait for SD controller to finish
uint32_t stc = sys_tick_counter;
while (SD_GetStatus() != SD_TRANSFER_OK) {
if (sys_tick_has_passed(stc, 5000)) {
//printf("[ERROR] timeout waiting for SD card read to finish\n");
return false;
}
}
return true;
}
bool sdcard_write_block(const uint8_t *src, uint32_t block_num) {
// TODO return error if not powered on
SD_Error status;
status = SD_WriteBlock((uint8_t*)src, block_num * SDCARD_BLOCK_SIZE, SDCARD_BLOCK_SIZE);
if (status != SD_OK) {
return false;
}
#ifdef SD_DMA_MODE
// wait for DMA transfer to finish
status = SD_WaitReadOperation();
if (status != SD_OK) {
return false;
}
#endif
// wait for SD controller to finish
uint32_t stc = sys_tick_counter;
while (SD_GetStatus() != SD_TRANSFER_OK) {
if (sys_tick_has_passed(stc, 5000)) {
//printf("[ERROR] timeout waiting for SD card write to finish\n");
return false;
}
}
return true;
}
/******************************************************************************/
// Micro Python bindings
static mp_obj_t sd_present(mp_obj_t self) {
return MP_BOOL(sdcard_is_present());
}
static MP_DEFINE_CONST_FUN_OBJ_1(sd_present_obj, sd_present);
static mp_obj_t sd_power(mp_obj_t self, mp_obj_t state) {
bool result;
if (rt_is_true(state)) {
result = sdcard_power_on();
} else {
sdcard_power_off();
result = true;
}
return MP_BOOL(result);
}
static MP_DEFINE_CONST_FUN_OBJ_2(sd_power_obj, sd_power);
static mp_obj_t sd_read(mp_obj_t self, mp_obj_t block_num) {
uint8_t *dest = m_new(uint8_t, SDCARD_BLOCK_SIZE);
if (!sdcard_read_block(dest, mp_obj_get_int(block_num))) {
m_free(dest, SDCARD_BLOCK_SIZE);
return mp_const_none;
}
return mp_obj_new_bytearray_by_ref(SDCARD_BLOCK_SIZE, dest);
}
static MP_DEFINE_CONST_FUN_OBJ_2(sd_read_obj, sd_read);
static const mp_method_t sdcard_methods[] = {
{ "present", &sd_present_obj },
{ "power", &sd_power_obj },
{ "read", &sd_read_obj },
{ NULL, NULL },
};
static const mp_obj_type_t sdcard_type = {
{ &mp_const_type },
"SDcard",
.methods = sdcard_methods,
};
const mp_obj_base_t pyb_sdcard_obj = {&sdcard_type};

11
stm/sdcard.h Normal file
View file

@ -0,0 +1,11 @@
// this is a fixed size and should not be changed
#define SDCARD_BLOCK_SIZE (512)
void sdcard_init(void);
bool sdcard_is_present(void);
bool sdcard_power_on(void);
void sdcard_power_off(void);
bool sdcard_read_block(uint8_t *dest, uint32_t block_num);
bool sdcard_write_block(const uint8_t *src, uint32_t block_num);
extern const struct _mp_obj_base_t pyb_sdcard_obj;

View file

@ -1,60 +0,0 @@
// TODO
// make it work with DMA
#include <stdio.h>
//#include "stm32f4xx_sdio.h"
#include "stm324x7i_eval_sdio_sd.h"
#include "misc.h"
#include "systick.h"
#define BLOCK_SIZE 512 /* Block Size in Bytes */
uint8_t aBuffer_Block_Rx[BLOCK_SIZE];
void sdio_init(void) {
SD_Error error = SD_Init();
printf("Init: %x\n", error);
uint8_t det = SD_Detect();
printf("Detc: %x\n", det);
if (!det) {
printf("no card detected\n");
SD_PowerOFF();
SD_DeInit();
return;
}
// read a block!
error = SD_ReadBlock(aBuffer_Block_Rx, 512, BLOCK_SIZE);
printf("ReadBlock: %d\n", error);
/*
// Check if the Transfer is finished
error = SD_WaitReadOperation();
printf("WaitReadOp: %d\n", error);
*/
uint32_t stc = sys_tick_counter;
while (SD_GetStatus() != SD_TRANSFER_OK) {
if (sys_tick_has_passed(stc, 2000)) {
printf("timeout waiting for read to finish\n");
break;
}
}
printf("done!!\n");
printf("%.16s", aBuffer_Block_Rx);
/*
snprintf((char*)aBuffer_Block_Rx, BLOCK_SIZE, "Here is some data back for you!\nBLOCK_SIZE=%d\n", BLOCK_SIZE);
error = SD_WriteBlock(aBuffer_Block_Rx, 512, BLOCK_SIZE);
printf("WriteBlock: %d\n", error);
while (SD_GetStatus() != SD_TRANSFER_OK) {
}
printf("done writing!\n");
*/
SD_PowerOFF();
SD_DeInit();
}

View file

@ -84,6 +84,34 @@ void SD_LowLevel_DeInit(void)
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
/* Init just the detect pin.
* This is so we can save power by not enabling the whole SD card interface,
* yet still detect when a card is inserted.
*/
void SD_LowLevel_Init_Detect(void) {
GPIO_InitTypeDef GPIO_InitStructure;
/* Periph clock enable */
RCC_AHB1PeriphClockCmd(SD_DETECT_GPIO_CLK, ENABLE);
/*!< Configure SD_SPI_DETECT_PIN pin: SD Card detect pin */
#if defined(PYBOARD3)
// dpgeorge: PYBv2-v3: switch is normally open, connected to VDD when card inserted
GPIO_InitStructure.GPIO_Pin = SD_DETECT_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; // needs to be 2MHz due to restrictions on PC13
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_Init(SD_DETECT_GPIO_PORT, &GPIO_InitStructure);
#elif defined(PYBOARD4)
// dpgeorge: PYBv4: switch is normally open, connected to GND when card inserted
GPIO_InitStructure.GPIO_Pin = SD_DETECT_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(SD_DETECT_GPIO_PORT, &GPIO_InitStructure);
#endif
}
/**
* @brief Initializes the SD Card and put it into StandBy State (Ready for
* data transfer).
@ -92,6 +120,9 @@ void SD_LowLevel_DeInit(void)
*/
void SD_LowLevel_Init(void)
{
// init the detect pin first
SD_LowLevel_Init_Detect();
GPIO_InitTypeDef GPIO_InitStructure;
/* GPIOC and GPIOD Periph clock enable */
@ -120,23 +151,6 @@ void SD_LowLevel_Init(void)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/*!< Configure SD_SPI_DETECT_PIN pin: SD Card detect pin */
#if defined(PYBOARD3)
// dpgeorge: PYBv2-v3: switch is normally open, connected to VDD when card inserted
GPIO_InitStructure.GPIO_Pin = SD_DETECT_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; // needs to be 2MHz due to restrictions on PC13
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_Init(SD_DETECT_GPIO_PORT, &GPIO_InitStructure);
#elif defined(PYBOARD4)
// dpgeorge: PYBv4: switch is normally open, connected to GND when card inserted
GPIO_InitStructure.GPIO_Pin = SD_DETECT_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(SD_DETECT_GPIO_PORT, &GPIO_InitStructure);
#endif
/* Enable the SDIO APB2 Clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SDIO, ENABLE);

View file

@ -103,7 +103,8 @@
* @{
*/
void SD_LowLevel_DeInit(void);
void SD_LowLevel_Init(void);
void SD_LowLevel_Init_Detect(void);
void SD_LowLevel_Init(void);
void SD_LowLevel_DMA_TxConfig(uint32_t *BufferSRC, uint32_t BufferSize);
void SD_LowLevel_DMA_RxConfig(uint32_t *BufferDST, uint32_t BufferSize);

View file

@ -10,51 +10,50 @@
#include "flash.h"
#include "storage.h"
#define BLOCK_SIZE (512)
#define CACHE_MEM_START_ADDR (0x10000000) // CCM data RAM, 64k
#define FLASH_PART1_START_BLOCK (0x100)
#define FLASH_PART1_NUM_BLOCKS (224) // 16k+16k+16k+64k=112k
#define FLASH_MEM_START_ADDR (0x08004000) // sector 1, 16k
static bool is_initialised = false;
static uint32_t cache_flash_sector_id;
static uint32_t cache_flash_sector_start;
static uint32_t cache_flash_sector_size;
static bool cache_dirty;
static uint32_t sys_tick_counter_last_write;
static bool flash_is_initialised = false;
static bool flash_cache_dirty;
static uint32_t flash_cache_sector_id;
static uint32_t flash_cache_sector_start;
static uint32_t flash_cache_sector_size;
static uint32_t flash_sys_tick_counter_last_write;
static void cache_flush(void) {
if (cache_dirty) {
static void flash_cache_flush(void) {
if (flash_cache_dirty) {
// sync the cache RAM buffer by writing it to the flash page
flash_write(cache_flash_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, cache_flash_sector_size / 4);
cache_dirty = false;
flash_write(flash_cache_sector_start, (const uint32_t*)CACHE_MEM_START_ADDR, flash_cache_sector_size / 4);
flash_cache_dirty = false;
// indicate a clean cache with LED off
led_state(PYB_LED_R1, 0);
}
}
static uint8_t *cache_get_addr_for_write(uint32_t flash_addr) {
static uint8_t *flash_cache_get_addr_for_write(uint32_t flash_addr) {
uint32_t flash_sector_start;
uint32_t flash_sector_size;
uint32_t flash_sector_id = flash_get_sector_info(flash_addr, &flash_sector_start, &flash_sector_size);
if (cache_flash_sector_id != flash_sector_id) {
cache_flush();
if (flash_cache_sector_id != flash_sector_id) {
flash_cache_flush();
memcpy((void*)CACHE_MEM_START_ADDR, (const void*)flash_sector_start, flash_sector_size);
cache_flash_sector_id = flash_sector_id;
cache_flash_sector_start = flash_sector_start;
cache_flash_sector_size = flash_sector_size;
flash_cache_sector_id = flash_sector_id;
flash_cache_sector_start = flash_sector_start;
flash_cache_sector_size = flash_sector_size;
}
cache_dirty = true;
flash_cache_dirty = true;
// indicate a dirty cache with LED on
led_state(PYB_LED_R1, 1);
return (uint8_t*)CACHE_MEM_START_ADDR + flash_addr - flash_sector_start;
}
static uint8_t *cache_get_addr_for_read(uint32_t flash_addr) {
static uint8_t *flash_cache_get_addr_for_read(uint32_t flash_addr) {
uint32_t flash_sector_start;
uint32_t flash_sector_size;
uint32_t flash_sector_id = flash_get_sector_info(flash_addr, &flash_sector_start, &flash_sector_size);
if (cache_flash_sector_id == flash_sector_id) {
if (flash_cache_sector_id == flash_sector_id) {
// in cache, copy from there
return (uint8_t*)CACHE_MEM_START_ADDR + flash_addr - flash_sector_start;
}
@ -63,16 +62,16 @@ static uint8_t *cache_get_addr_for_read(uint32_t flash_addr) {
}
void storage_init(void) {
if (!is_initialised) {
cache_flash_sector_id = 0;
cache_dirty = false;
is_initialised = true;
sys_tick_counter_last_write = 0;
if (!flash_is_initialised) {
flash_cache_dirty = false;
flash_cache_sector_id = 0;
flash_is_initialised = true;
flash_sys_tick_counter_last_write = 0;
}
}
uint32_t storage_get_block_size(void) {
return BLOCK_SIZE;
return FLASH_BLOCK_SIZE;
}
uint32_t storage_get_block_count(void) {
@ -81,11 +80,11 @@ uint32_t storage_get_block_count(void) {
bool storage_needs_flush(void) {
// wait 2 seconds after last write to flush
return cache_dirty && sys_tick_has_passed(sys_tick_counter_last_write, 2000);
return flash_cache_dirty && sys_tick_has_passed(flash_sys_tick_counter_last_write, 2000);
}
void storage_flush(void) {
cache_flush();
flash_cache_flush();
}
static void build_partition(uint8_t *buf, int boot, int type, uint32_t start_block, uint32_t num_blocks) {
@ -145,9 +144,9 @@ bool storage_read_block(uint8_t *dest, uint32_t block) {
} else if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS) {
// non-MBR block, get data from flash memory, possibly via cache
uint32_t flash_addr = FLASH_MEM_START_ADDR + (block - FLASH_PART1_START_BLOCK) * BLOCK_SIZE;
uint8_t *src = cache_get_addr_for_read(flash_addr);
memcpy(dest, src, BLOCK_SIZE);
uint32_t flash_addr = FLASH_MEM_START_ADDR + (block - FLASH_PART1_START_BLOCK) * FLASH_BLOCK_SIZE;
uint8_t *src = flash_cache_get_addr_for_read(flash_addr);
memcpy(dest, src, FLASH_BLOCK_SIZE);
return true;
} else {
@ -164,10 +163,10 @@ bool storage_write_block(const uint8_t *src, uint32_t block) {
} else if (FLASH_PART1_START_BLOCK <= block && block < FLASH_PART1_START_BLOCK + FLASH_PART1_NUM_BLOCKS) {
// non-MBR block, copy to cache
uint32_t flash_addr = FLASH_MEM_START_ADDR + (block - FLASH_PART1_START_BLOCK) * BLOCK_SIZE;
uint8_t *dest = cache_get_addr_for_write(flash_addr);
memcpy(dest, src, BLOCK_SIZE);
sys_tick_counter_last_write = sys_tick_counter;
uint32_t flash_addr = FLASH_MEM_START_ADDR + (block - FLASH_PART1_START_BLOCK) * FLASH_BLOCK_SIZE;
uint8_t *dest = flash_cache_get_addr_for_write(flash_addr);
memcpy(dest, src, FLASH_BLOCK_SIZE);
flash_sys_tick_counter_last_write = sys_tick_counter;
return true;
} else {

View file

@ -1,3 +1,5 @@
#define FLASH_BLOCK_SIZE (512)
void storage_init(void);
uint32_t storage_get_block_size(void);
uint32_t storage_get_block_count(void);