/** * @file di_fw/drv/stm32fx_flash.h * @brief Cortex-M flash eeprom driver * @date March 22, 2016 * @author J.J.J. Jacobs * @copyright 2016 Dual Inventive Technology Centre B.V. * * Cortex-M flash eeprom emulation driver for di_config_ctx * @note di_time component MUST be initialized before using this driver */ #ifndef INCLUDE_DI_FW_FLASH_H_ #define INCLUDE_DI_FW_FLASH_H_ #include #include #define DI_FW_FLASH_ADDR_SECTOR1 (uint32_t)((FLASH_BASE) + 0x4000) #define DI_FW_FLASH_ID_SECTOR1 1U #define DI_FW_FLASH_ADDR_SECTOR2 (uint32_t)0x08008000 #define DI_FW_FLASH_ID_SECTOR2 2U #define DI_FW_FLASH_PAGE_ADDR_INVAL 0x0 /* Invalid page address */ #define DI_FW_FLASH_PAGE_STATUS_SIZE 2U /**< Size of flash page status field (in bytes) */ #define DI_FW_FLASH_PAGE_SIZE (1 * 1024) #define DI_FW_FLASH_SECTOR_SIZE (16 * 1024) #define DI_FW_FLASH_PAGE_CONFIG_SIZE (DI_FW_FLASH_PAGE_SIZE - \ DI_FW_FLASH_PAGE_STATUS_SIZE) /**< Page size for di_config_ctx size */ enum di_fw_flash_page_status { DI_FW_FLASH_PAGE_STATUS_ERASED = (uint16_t)0xffff, DI_FW_FLASH_PAGE_STATUS_WRITTEN = (uint16_t)0xeeee, DI_FW_FLASH_PAGE_STATUS_VALID = (uint16_t)0xeee0, DI_FW_FLASH_PAGE_STATUS_DIRTY = (uint16_t)0xee00, DI_FW_FLASH_PAGE_STATUS_CORRUPT = (uint16_t)0xe000 }; struct di_fw_flash_ctx { struct { uint32_t sector_one; /* First sector physical address */ uint32_t sector_two; /* Second sector physical address */ } addr; struct { uint32_t sector_one; /* Physical id of first sector */ uint32_t sector_two; /* Physical id of second sector */ } id; struct { uint32_t sector; /* Sector size in bytes */ uint32_t page; /* Page size in bytes */ uint32_t pages; /* Pages per sector */ } size; struct { uint32_t addr; /* Current valid/cached page address (0x0 when unset) */ uint32_t sector; /* Current page sector number */ uint8_t *cache; /* Page cache buffer */ bool is_cached; /* Page is cached flag */ } page; }; static inline void di_fw_flash_set_addr_sector_one(struct di_fw_flash_ctx *ctx, uint32_t addr) { ctx->addr.sector_one = addr; } static inline void di_fw_flash_set_addr_sector_two(struct di_fw_flash_ctx *ctx, uint32_t addr) { ctx->addr.sector_two = addr; } static inline void di_fw_flash_set_id_sector_one(struct di_fw_flash_ctx *ctx, uint32_t id) { ctx->id.sector_one = id; } static inline void di_fw_flash_set_id_sector_two(struct di_fw_flash_ctx *ctx, uint32_t id) { ctx->id.sector_two = id; } static inline void di_fw_flash_set_sector_size(struct di_fw_flash_ctx *ctx, uint32_t size) { ctx->size.sector = size; } static inline void di_fw_flash_set_page_size(struct di_fw_flash_ctx *ctx, uint32_t size) { ctx->size.page = size; ctx->size.pages = ctx->size.sector / ctx->size.page; } static inline void di_fw_flash_set_page_cache(struct di_fw_flash_ctx *ctx, uint8_t *page) { ctx->page.cache = page; ctx->page.is_cached = false; ctx->page.addr = DI_FW_FLASH_PAGE_ADDR_INVAL; ctx->page.sector = 0; } size_t di_fw_flash_read(struct di_config_ctx *ctx, uint32_t offset, void *data, size_t size); size_t di_fw_flash_write(struct di_config_ctx *ctx, uint32_t offset, const void *data, size_t size); void di_fw_flash_sector_erase(uint32_t sector_nr); void di_fw_flash_page_set_status(uint32_t addr, enum di_fw_flash_page_status status); enum di_fw_flash_page_status di_fw_flash_page_get_status(uint32_t addr); /** * Search for first flash page with given status * @param ctx Flash context * @param sector_addr The start address of the sector * @param status Page status to search for * @retval 0 When no such page is found * @retval !0 Valid base address of page */ uint32_t di_fw_flash_page_search(struct di_fw_flash_ctx *ctx, uint32_t sector_addr, enum di_fw_flash_page_status status); void di_fw_flash_read_data(uint32_t addr, uint8_t *data, size_t size); void di_fw_flash_write_data(uint32_t addr, const uint8_t *data, size_t size); void di_fw_flash_sync(struct di_config_ctx *ctx); #endif /* INCLUDE_DI_FW_FLASH_H */