sfud移植
- 首先看readme文档
文件结构
-
inc文件夹:各种头文件,注意flash_def和cfg头文件
-
port文件夹:接口文件
-
src文件夹:代码源文件
移植
-
基础:你的SPI没问题,用普通工程可以正常操作Flash
-
首先打开flash_def头文件,SFUD_FLASH_CHIP_TABLE宏定义是否有你使用的FLASH
-
若没有则添加,
-
比着葫芦画个瓢,名字 厂商ID 类型id 容量id 8M容量 page 256字节 sector 4KB 擦除命令
-
这几个参数可以在芯片pdf找到,Manufacturer and Device Identification表和BLOCK DIAGRAM框图
-
,
-
-
-
{"W25Q64BV", SFUD_MF_ID_WINBOND, 0x40, 0x17, 8L*1024L*1024L, SFUD_WM_PAGE_256B, 4096, 0x20}, \
-
-
打开cfg头文件,在枚举和宏定义,添加你的Flash型号
-
enum { SFUD_W25Q64BV_DEVICE_INDEX = 0, }; #define SFUD_FLASH_DEVICE_TABLE \ { \ [SFUD_W25Q64BV_DEVICE_INDEX] = {.name = "W25Q64BV", .spi.name = "SPI1"}, \ }
-
-
主要修改两个函数:spi_write_read和sfud_spi_port_init,在init函数绑定一些函数和初始化外设, SPI 读写驱动(必选)、重试次数(必选)、重试接口(可选)及 SPI 锁(可选)的配置。
-
分析代码后发现是各种函数都给在sfud.c实现了,例如开写保护发送0x06,在sfud.c中set_write_enabled实现,0x06命令对应宏定义SFUD_CMD_WRITE_ENABLE,如果命令与一般命令不同,可以通过自己定义宏定义进行覆盖。
-
因此spi_write_read函数只需要实现单纯数据发送和接收,不需要考虑其他
-
最后在主函数调用sfud_init()即可,最后打印success即移植成功
-
static sfud_err spi_write_read(const sfud_spi *spi, const uint8_t *write_buf, size_t write_size, uint8_t *read_buf, size_t read_size) { sfud_err result = SFUD_SUCCESS; if (write_size) { SFUD_ASSERT(write_buf); } if (read_size) { SFUD_ASSERT(read_buf); } SPI_FLASH_CS_LOW(); // 片选拉低 if (write_size) { SPI_FLASH_Write_Simple((uint8_t *)write_buf, write_size); } if (read_size) { memset((uint8_t *)read_buf, 0xFF, read_size); SPI_FLASH_Read_Simple((uint8_t *)read_buf, read_size); } SPI_FLASH_CS_HIGH(); // 片选拉高 return result; } /* about 100 microsecond delay */ static void retry_delay_100us(void) { uint32_t delay = 120; while (delay--) ; } static spi_user_data SPI_userData = {.spix = SPI1, .cs_gpiox = GPIOA, .cs_gpio_pin = GPIO_Pin_4}; sfud_err sfud_spi_port_init(sfud_flash *flash) { sfud_err result = SFUD_SUCCESS; // 直接调用自己的初始化函数 SPI_FLASH_Init(); // 追根溯源,sfud_flash这个参数有一部分为 // sfud_cfg.h中的SFUD_FLASH_DEVICE_TABLE switch (flash->index) { case SFUD_W25Q64BV_DEVICE_INDEX: // 是在 sfud_cfg.h 中定义的 { flash->spi.wr = spi_write_read; flash->spi.lock = spi_lock; flash->spi.unlock = spi_unlock; flash->spi.user_data = &SPI_userData; /* about 100 microsecond delay */ flash->retry.delay = retry_delay_100us; /* adout 60 seconds timeout */ flash->retry.times = 60 * 10000; break; } } return result; }
-
uint8_t SPI_FLASH_SendByte(uint8_t byte) { // 因为是全双工,接和收同时进行 SPITimeout = SPIT_FLAG_TIMEOUT; /* 等待发送缓冲区为空,TXE事件 */ while (SPI_I2S_GetFlagStatus(FLASH_SPIx, SPI_I2S_FLAG_TXE) == RESET) { if ((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(0); } /* 写入数据寄存器,把要写入的数据写入发送缓冲区 */ SPI_I2S_SendData(FLASH_SPIx, byte); SPITimeout = SPIT_FLAG_TIMEOUT; /* 等待接收缓冲区非空,RXNE事件 */ while (SPI_I2S_GetFlagStatus(FLASH_SPIx, SPI_I2S_FLAG_RXNE) == RESET) { if ((SPITimeout--) == 0) return SPI_TIMEOUT_UserCallback(1); } /* 读取数据寄存器,获取接收缓冲区数据 */ return SPI_I2S_ReceiveData(FLASH_SPIx); } void SPI_FLASH_Write_Simple(uint8_t *pBuffer, uint16_t NumByteToWrite) { // 片选统一使能 /* 写入数据*/ while (NumByteToWrite--) { /* 发送当前要写入的字节数据 */ SPI_FLASH_SendByte(*pBuffer); /* 指向下一字节数据 */ pBuffer++; } } void SPI_FLASH_Read_Simple(uint8_t *pBuffer, uint16_t NumByteToRead) { /* 选择FLASH: CS低电平 */ /* 读取数据 */ while (NumByteToRead--) /* while there is data to be read */ { /* 读取一个字节*/ *pBuffer = SPI_FLASH_SendByte(Dummy_Byte); /* 指向下一个字节缓冲区 */ pBuffer++; } /* 停止信号 FLASH: CS 高电平 */ }
-