embox
191 строка · 5.4 Кб
1/**
2* @file stm32_qspi_flash_dev.c
3* @brief QSPI flash device driver (BSP-based)
4* @author Andrew Bursian
5* @date 05.05.2023
6*/
7
8#include <util/log.h>9
10#include <stdio.h>11#include <unistd.h>12#include <assert.h>13#include <string.h>14#include <stdbool.h>15#include <errno.h>16
17#include <util/math.h>18#include <util/macro.h>19
20//#include <arm/cpu_cache.h>
21#include <drivers/flash/flash.h>22#include <drivers/flash/flash_cache.h>23
24#include <framework/mod/options.h>25
26#define FLASH_NAME qspiflash27
28#if defined USE_STM32L475E_IOT0129#include "stm32l475e_iot01.h"30#include "stm32l475e_iot01_qspi.h" // includes "../Components/mx25r6435f/mx25r6435f.h"31#define QSPI_FLASH_SIZE MX25R6435F_FLASH_SIZE32#define QSPI_BLOCK_SIZE MX25R6435F_SECTOR_SIZE33#define QSPI_ERASE_TIME MX25R6435F_SECTOR_ERASE_MAX_TIME34
35#elif defined USE_STM32F769I_DISCOVERY36#include "stm32f769i_discovery.h"37#include "stm32f769i_discovery_qspi.h" // includes "../Components/mx25l512/mx25l512.h"38#define QSPI_FLASH_SIZE MX25L512_FLASH_SIZE39#define QSPI_BLOCK_SIZE MX25L512_SUBSECTOR_SIZE40#define QSPI_ERASE_TIME MX25L512_SUBSECTOR_ERASE_MAX_TIME41
42#error Unsupported platform // not tested properly yet43
44#else45#error Unsupported platform46#endif // defined USE_XXX47
48FLASH_CACHE_DEF(FLASH_NAME, sizeof(uint32_t), QSPI_BLOCK_SIZE);49
50/* reduce flash volume to check it fast */
51#define FLASH_CUT OPTION_GET(NUMBER,flash_cut)52#if FLASH_CUT53#undef QSPI_FLASH_SIZE54#define QSPI_FLASH_SIZE FLASH_CUT55#endif // FLASH_CUT56
57#define QSPI_ERASE_CHECK OPTION_GET(NUMBER,erase_check)58
59static int qspi_flash_read(struct flash_dev *dev, uint32_t addr, void *data, size_t len) {60if (addr + len > QSPI_FLASH_SIZE) {61log_error("End address is out of range. addr=0x%x,len=0x%x", addr, len);62return -1;63}64/* read can be unaligned */65memcpy(data, (void *) QSPI_BASE + addr, len);66return len;67}
68
69static inline int poll_flash_busy(int maxms) {70clock_t t0 = clock();71while ((clock()-t0 < CLOCKS_PER_SEC*maxms/1000) && (BSP_QSPI_GetStatus() == QSPI_BUSY)) {72usleep(1000);73}74return (clock()-t0)*1000/CLOCKS_PER_SEC;75}
76
77static int qspi_flash_erase_block(struct flash_dev *dev, uint32_t block) {78int res;79log_debug("Block %d", block);80BSP_QSPI_Init(); // exit memory mapped mode81if(poll_flash_busy(100) >= 100) {82log_error("Fail after BSP_QSPI_Init: flash chip busy > 100 ms");83BSP_QSPI_EnableMemoryMappedMode();84return QSPI_BUSY;85}86
87#if defined USE_STM32L475E_IOT0188res = BSP_QSPI_Erase_Sector(block);89#elif defined USE_STM32F769I_DISCOVERY90res = BSP_QSPI_Erase_Block(block * QSPI_BLOCK_SIZE);91#else92#error Unsupported platform93#endif // defined USE_XXX94if(res != QSPI_OK) {95log_error("Fail erasing block %d", block);96}97if(poll_flash_busy(QSPI_ERASE_TIME) >= QSPI_ERASE_TIME) {98log_error("Fail erasing block: flash chip busy > %d ms", QSPI_ERASE_TIME);99res = QSPI_BUSY;100}101
102BSP_QSPI_EnableMemoryMappedMode();103//dcache_flush_all(); // or use dcache_flush(const void *p, size_t size);104
105#if QSPI_ERASE_CHECK106/* check entire block */107for (int a=0; a < QSPI_BLOCK_SIZE; a++) {108if (*(uint8_t*)(QSPI_BASE + block * QSPI_BLOCK_SIZE + a) != 0xff) {109log_error("Erase fail, block %d, offset %d", block, a);110res = QSPI_ERROR;111break;112}113}114#endif115log_debug("Ok");116return res;117}
118
119static int qspi_flash_write(struct flash_dev *dev, uint32_t addr, const void *data, size_t len) {120int res;121int t0=clock();122log_debug("Addr %d, length %d", addr, len);123if (addr + len > QSPI_FLASH_SIZE) {124log_error("End address is out of range. addr=0x%x,len=0x%x", addr, len);125return -1;126}127
128BSP_QSPI_Init(); // exit memory mapped mode129log_debug("BSP_QSPI_Init(): %d", clock()-t0);t0=clock();130if(poll_flash_busy(100) >= 100) {131log_error("Fail after BSP_QSPI_Init: flash chip busy > 100 ms");132BSP_QSPI_EnableMemoryMappedMode();133return QSPI_BUSY;134}135log_debug("poll_flash_busy(): %d", clock()-t0);t0=clock();136
137res = BSP_QSPI_Write((uint8_t*) data, addr, len);138log_debug("BSP_QSPI_Write(): %d", clock()-t0);t0=clock();139if(res != QSPI_OK) {140log_error("QSPI write failed. addr=0x%x,len=0x%x", addr, len);141BSP_QSPI_EnableMemoryMappedMode();142return res;143}144if(poll_flash_busy(10) >= 10) {145log_error("Fail writing block: flash chip busy > 10 ms");146res = QSPI_BUSY;147}148log_debug("poll_flash_busy(): %d", clock()-t0);t0=clock();149
150BSP_QSPI_EnableMemoryMappedMode();151log_debug("BSP_QSPI_EnableMemoryMappedMode(): %d", clock()-t0);152//dcache_flush_all(); // or use dcache_flush(const void *p, size_t size);153log_debug("Ok");154return len;155}
156
157static const struct flash_dev_drv qspi_flash_drv;158
159static int qspi_flash_init(struct flash_dev *dev, void *arg) {160static uint32_t qspi_flash_aligned_word;161struct flash_dev *flash;162
163flash = flash_create(MACRO_STRING(FLASH_NAME), QSPI_FLASH_SIZE);164if (flash == NULL) {165log_error("Failed to create flash device!");166return -1;167}168flash->drv = &qspi_flash_drv;169flash->size = QSPI_FLASH_SIZE;170flash->num_block_infos = 1;171flash->block_info[0] = (struct flash_block_info) {172.fbi_start_id = 0,173.block_size = QSPI_BLOCK_SIZE,174.blocks = QSPI_FLASH_SIZE / QSPI_BLOCK_SIZE,175};176flash->fld_aligned_word = &qspi_flash_aligned_word;177flash->fld_word_size = sizeof(qspi_flash_aligned_word);178
179flash->fld_cache = FLASH_CACHE_GET(flash, FLASH_NAME);180
181return 0;182}
183
184static const struct flash_dev_drv qspi_flash_drv = {185.flash_init = qspi_flash_init,186.flash_read = qspi_flash_read,187.flash_erase_block = qspi_flash_erase_block,188.flash_program = qspi_flash_write,189};190
191FLASH_DEV_DEF(MACRO_STRING(FLASH_NAME), &qspi_flash_drv);192