flash

The flash driver subsystem is a work in progress which aims at supporting common external SPI/I2C flash/eeprom memory chips. This is equivalent to what Linux calls MTD for Memory Technology Devices.

At the moment the only flash device that is already supported is the AT45DBxxx SPI flash family with the at45db driver.

The flash driver aims for full compatibility with the hal_flash API, which means initialization and usage can be performed by any fs that supports the hal_flash interface.

Initialization

To be compatible with the standard hal_flash interface, the at45db driver embeds a struct hal_flash to its own struct at45db_dev. The whole at45db_dev struct is shown below.

struct at45db_dev {
    struct hal_flash hal;
    struct hal_spi_settings *settings;
    int spi_num;
    void *spi_cfg;                  /** Low-level MCU SPI config */
    int ss_pin;
    uint32_t baudrate;
    uint16_t page_size;             /** Page size to be used, valid: 512 and 528 */
    uint8_t disable_auto_erase;     /** Reads and writes auto-erase by default */
};

To ease with initialization a helper function at45db_default_config was added. It returns an already initialized struct at45db_dev leaving the user with just having to provide the SPI related config.

To initialize the device, pass the at45db_dev struct to at45db_init.

int at45db_init(const struct hal_flash *dev);

For low-level access to the device the following functions are provided:

int at45db_read(const struct hal_flash *dev, uint32_t addr, void *buf,
                uint32_t len);
int at45db_write(const struct hal_flash *dev, uint32_t addr, const void *buf,
                 uint32_t len);
int at45db_erase_sector(const struct hal_flash *dev, uint32_t sector_address);
int at45db_sector_info(const struct hal_flash *dev, int idx, uint32_t *address,
                       uint32_t *sz);

Also, nffs is able to run on the device due to the fact that standard hal_flash interface compatibility is provided. Due to current limitations of nffs, it can only run on at45db if the internal flash of the MCU is not being used.

Dependencies

To include the at45db driver on a project, just include it as a dependency in your pkg.yml:

pkg.deps:
    - hw/drivers/flash/at45db

Header file

The at45db SPI flash follows the standard hal_flash interface but requires that a special struct

#include <at45db/at45db.h>

Example

This following examples assume that the at45db is being used on a STM32F4 MCU.

static const int SPI_SS_PIN   = MCU_GPIO_PORTA(4);
static const int SPI_SCK_PIN  = MCU_GPIO_PORTA(5);
static const int SPI_MISO_PIN = MCU_GPIO_PORTA(6);
static const int SPI_MOSI_PIN = MCU_GPIO_PORTA(7);

struct stm32f4_hal_spi_cfg spi_cfg = {
    .ss_pin   = SPI_SS_PIN,
    .sck_pin  = SPI_SCK_PIN,
    .miso_pin = SPI_MISO_PIN,
    .mosi_pin = SPI_MOSI_PIN,
    .irq_prio = 2
};

struct at45db_dev *my_at45db_dev = NULL;

my_at45db_dev = at45db_default_config();
my_at45db_dev->spi_num = 0;
my_at45db_dev->spi_cfg = &spi_cfg;
my_at45db_dev->ss_pin = spi_cfg.ss_pin;

rc = at45db_init((struct hal_flash *) my_at45db_dev);
if (rc) {
    /* XXX: error handling */
}

The enable nffs to run on the at45db, the flash_id 0 needs to map to provide a mapping from 0 to this struct.

const struct hal_flash *
hal_bsp_flash_dev(uint8_t id)
{
    if (id != 0) {
        return NULL;
    }
    return &my_at45db_dev;
}