Commit e43a74a4 authored by Damien George's avatar Damien George

drivers/memory/spiflash: Add MICROPY_HW_SPIFLASH_ENABLE_CACHE option.

This only needs to be enabled if a board uses FAT FS on external SPI flash.
When disabled (and using external SPI flash) 4k of RAM can be saved.
Signed-off-by: default avatarDamien George <damien@micropython.org>
parent 061cb1a7
...@@ -287,6 +287,8 @@ int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint ...@@ -287,6 +287,8 @@ int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint
/******************************************************************************/ /******************************************************************************/
// Interface functions that use the cache // Interface functions that use the cache
#if MICROPY_HW_SPIFLASH_ENABLE_CACHE
void mp_spiflash_cached_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) { void mp_spiflash_cached_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest) {
if (len == 0) { if (len == 0) {
return; return;
...@@ -509,3 +511,5 @@ int mp_spiflash_cached_write(mp_spiflash_t *self, uint32_t addr, size_t len, con ...@@ -509,3 +511,5 @@ int mp_spiflash_cached_write(mp_spiflash_t *self, uint32_t addr, size_t len, con
mp_spiflash_release_bus(self); mp_spiflash_release_bus(self);
return 0; return 0;
} }
#endif // MICROPY_HW_SPIFLASH_ENABLE_CACHE
...@@ -38,6 +38,7 @@ enum { ...@@ -38,6 +38,7 @@ enum {
struct _mp_spiflash_t; struct _mp_spiflash_t;
#if MICROPY_HW_SPIFLASH_ENABLE_CACHE
// A cache must be provided by the user in the config struct. The same cache // A cache must be provided by the user in the config struct. The same cache
// struct can be shared by multiple SPI flash instances. // struct can be shared by multiple SPI flash instances.
typedef struct _mp_spiflash_cache_t { typedef struct _mp_spiflash_cache_t {
...@@ -45,6 +46,7 @@ typedef struct _mp_spiflash_cache_t { ...@@ -45,6 +46,7 @@ typedef struct _mp_spiflash_cache_t {
struct _mp_spiflash_t *user; // current user of buf, for shared use struct _mp_spiflash_t *user; // current user of buf, for shared use
uint32_t block; // current block stored in buf; 0xffffffff if invalid uint32_t block; // current block stored in buf; 0xffffffff if invalid
} mp_spiflash_cache_t; } mp_spiflash_cache_t;
#endif
typedef struct _mp_spiflash_config_t { typedef struct _mp_spiflash_config_t {
uint32_t bus_kind; uint32_t bus_kind;
...@@ -59,7 +61,9 @@ typedef struct _mp_spiflash_config_t { ...@@ -59,7 +61,9 @@ typedef struct _mp_spiflash_config_t {
const mp_qspi_proto_t *proto; const mp_qspi_proto_t *proto;
} u_qspi; } u_qspi;
} bus; } bus;
#if MICROPY_HW_SPIFLASH_ENABLE_CACHE
mp_spiflash_cache_t *cache; // can be NULL if cache functions not used mp_spiflash_cache_t *cache; // can be NULL if cache functions not used
#endif
} mp_spiflash_config_t; } mp_spiflash_config_t;
typedef struct _mp_spiflash_t { typedef struct _mp_spiflash_t {
...@@ -75,9 +79,11 @@ int mp_spiflash_erase_block(mp_spiflash_t *self, uint32_t addr); ...@@ -75,9 +79,11 @@ int mp_spiflash_erase_block(mp_spiflash_t *self, uint32_t addr);
void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest); void mp_spiflash_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest);
int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src); int mp_spiflash_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src);
#if MICROPY_HW_SPIFLASH_ENABLE_CACHE
// These functions use the cache (which must already be configured) // These functions use the cache (which must already be configured)
void mp_spiflash_cache_flush(mp_spiflash_t *self); void mp_spiflash_cache_flush(mp_spiflash_t *self);
void mp_spiflash_cached_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest); void mp_spiflash_cached_read(mp_spiflash_t *self, uint32_t addr, size_t len, uint8_t *dest);
int mp_spiflash_cached_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src); int mp_spiflash_cached_write(mp_spiflash_t *self, uint32_t addr, size_t len, const uint8_t *src);
#endif
#endif // MICROPY_INCLUDED_DRIVERS_MEMORY_SPIFLASH_H #endif // MICROPY_INCLUDED_DRIVERS_MEMORY_SPIFLASH_H
...@@ -77,6 +77,7 @@ void board_sleep(int value); ...@@ -77,6 +77,7 @@ void board_sleep(int value);
// SPI flash #1, block device config // SPI flash #1, block device config
extern const struct _mp_spiflash_config_t spiflash_config; extern const struct _mp_spiflash_config_t spiflash_config;
extern struct _spi_bdev_t spi_bdev; extern struct _spi_bdev_t spi_bdev;
#define MICROPY_HW_SPIFLASH_ENABLE_CACHE (1)
#define MICROPY_HW_BDEV_IOCTL(op, arg) ( \ #define MICROPY_HW_BDEV_IOCTL(op, arg) ( \
(op) == BDEV_IOCTL_NUM_BLOCKS ? (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) : \ (op) == BDEV_IOCTL_NUM_BLOCKS ? (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) : \
(op) == BDEV_IOCTL_INIT ? spi_bdev_ioctl(&spi_bdev, (op), (uint32_t)&spiflash_config) : \ (op) == BDEV_IOCTL_INIT ? spi_bdev_ioctl(&spi_bdev, (op), (uint32_t)&spiflash_config) : \
......
...@@ -40,6 +40,7 @@ extern const struct _mp_spiflash_config_t spiflash_config; ...@@ -40,6 +40,7 @@ extern const struct _mp_spiflash_config_t spiflash_config;
extern struct _spi_bdev_t spi_bdev; extern struct _spi_bdev_t spi_bdev;
#if !USE_QSPI_XIP #if !USE_QSPI_XIP
#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0) #define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (0)
#define MICROPY_HW_SPIFLASH_ENABLE_CACHE (1)
#define MICROPY_HW_BDEV_IOCTL(op, arg) ( \ #define MICROPY_HW_BDEV_IOCTL(op, arg) ( \
(op) == BDEV_IOCTL_NUM_BLOCKS ? ((1 << MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2) / 8 / FLASH_BLOCK_SIZE) : \ (op) == BDEV_IOCTL_NUM_BLOCKS ? ((1 << MICROPY_HW_QSPIFLASH_SIZE_BITS_LOG2) / 8 / FLASH_BLOCK_SIZE) : \
(op) == BDEV_IOCTL_INIT ? spi_bdev_ioctl(&spi_bdev, (op), (uint32_t)&spiflash_config) : \ (op) == BDEV_IOCTL_INIT ? spi_bdev_ioctl(&spi_bdev, (op), (uint32_t)&spiflash_config) : \
......
...@@ -22,6 +22,7 @@ void STM32L476DISC_board_early_init(void); ...@@ -22,6 +22,7 @@ void STM32L476DISC_board_early_init(void);
// block device config for SPI flash // block device config for SPI flash
extern const struct _mp_spiflash_config_t spiflash_config; extern const struct _mp_spiflash_config_t spiflash_config;
extern struct _spi_bdev_t spi_bdev; extern struct _spi_bdev_t spi_bdev;
#define MICROPY_HW_SPIFLASH_ENABLE_CACHE (1)
#define MICROPY_HW_BDEV_IOCTL(op, arg) ( \ #define MICROPY_HW_BDEV_IOCTL(op, arg) ( \
(op) == BDEV_IOCTL_NUM_BLOCKS ? (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) : \ (op) == BDEV_IOCTL_NUM_BLOCKS ? (MICROPY_HW_SPIFLASH_SIZE_BITS / 8 / FLASH_BLOCK_SIZE) : \
(op) == BDEV_IOCTL_INIT ? spi_bdev_ioctl(&spi_bdev, (op), (uint32_t)&spiflash_config) : \ (op) == BDEV_IOCTL_INIT ? spi_bdev_ioctl(&spi_bdev, (op), (uint32_t)&spiflash_config) : \
......
...@@ -286,6 +286,14 @@ ...@@ -286,6 +286,14 @@
#define MICROPY_HW_BDEV_WRITEBLOCK flash_bdev_writeblock #define MICROPY_HW_BDEV_WRITEBLOCK flash_bdev_writeblock
#endif #endif
// Whether to enable caching for external SPI flash, to allow block writes that are
// smaller than the native page-erase size of the SPI flash, eg when FAT FS is used.
// Enabling this enables spi_bdev_readblocks() and spi_bdev_writeblocks() functions,
// and requires a valid mp_spiflash_config_t.cache pointer.
#ifndef MICROPY_HW_SPIFLASH_ENABLE_CACHE
#define MICROPY_HW_SPIFLASH_ENABLE_CACHE (0)
#endif
// Enable the storage sub-system if a block device is defined // Enable the storage sub-system if a block device is defined
#if defined(MICROPY_HW_BDEV_IOCTL) #if defined(MICROPY_HW_BDEV_IOCTL)
#define MICROPY_HW_ENABLE_STORAGE (1) #define MICROPY_HW_ENABLE_STORAGE (1)
......
...@@ -41,19 +41,23 @@ int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) { ...@@ -41,19 +41,23 @@ int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) {
return 0; return 0;
case BDEV_IOCTL_IRQ_HANDLER: case BDEV_IOCTL_IRQ_HANDLER:
#if MICROPY_HW_SPIFLASH_ENABLE_CACHE
if ((bdev->spiflash.flags & 1) && HAL_GetTick() - bdev->flash_tick_counter_last_write >= 1000) { if ((bdev->spiflash.flags & 1) && HAL_GetTick() - bdev->flash_tick_counter_last_write >= 1000) {
mp_spiflash_cache_flush(&bdev->spiflash); mp_spiflash_cache_flush(&bdev->spiflash);
led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off
} }
#endif
return 0; return 0;
case BDEV_IOCTL_SYNC: case BDEV_IOCTL_SYNC:
#if MICROPY_HW_SPIFLASH_ENABLE_CACHE
if (bdev->spiflash.flags & 1) { if (bdev->spiflash.flags & 1) {
uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access
mp_spiflash_cache_flush(&bdev->spiflash); mp_spiflash_cache_flush(&bdev->spiflash);
led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off led_state(PYB_LED_RED, 0); // indicate a clean cache with LED off
restore_irq_pri(basepri); restore_irq_pri(basepri);
} }
#endif
return 0; return 0;
case BDEV_IOCTL_BLOCK_ERASE: { case BDEV_IOCTL_BLOCK_ERASE: {
...@@ -66,6 +70,7 @@ int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) { ...@@ -66,6 +70,7 @@ int32_t spi_bdev_ioctl(spi_bdev_t *bdev, uint32_t op, uint32_t arg) {
return -MP_EINVAL; return -MP_EINVAL;
} }
#if MICROPY_HW_SPIFLASH_ENABLE_CACHE
int spi_bdev_readblocks(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uint32_t num_blocks) { int spi_bdev_readblocks(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access
mp_spiflash_cached_read(&bdev->spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, dest); mp_spiflash_cached_read(&bdev->spiflash, block_num * FLASH_BLOCK_SIZE, num_blocks * FLASH_BLOCK_SIZE, dest);
...@@ -85,6 +90,7 @@ int spi_bdev_writeblocks(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_nu ...@@ -85,6 +90,7 @@ int spi_bdev_writeblocks(spi_bdev_t *bdev, const uint8_t *src, uint32_t block_nu
return ret; return ret;
} }
#endif // MICROPY_HW_SPIFLASH_ENABLE_CACHE
int spi_bdev_readblocks_raw(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uint32_t block_offset, uint32_t num_bytes) { int spi_bdev_readblocks_raw(spi_bdev_t *bdev, uint8_t *dest, uint32_t block_num, uint32_t block_offset, uint32_t num_bytes) {
uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access uint32_t basepri = raise_irq_pri(IRQ_PRI_FLASH); // prevent cache flushing and USB access
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment