硬件基础:野火霸道V2,外部Flash移植测试
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 高电平 */ }
-
fal移植
- 可以参考事在人wёi的fal移植博客,他也有一篇sfud移植的博文,写的也很好
- 移植好sfud后,fal移植比较简单,先修改fal_cfg.h,添加宏定义并根据需要修改宏定义
#define FAL_DEBUG 1
#define FAL_PART_HAS_TABLE_CFG
#define FAL_USING_SFUD_PORT
#define NOR_FLASH_DEV_NAME "norflash0"
/* flash device table */
#define FAL_FLASH_DEV_TABLE \
{ \
&nor_flash0, \
}
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG
/* partition table */
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WORD, "fdb_tsdb1", "norflash0", 0, 1024*1024, 0}, \
{FAL_PART_MAGIC_WORD, "fdb_kvdb1", "norflash0", 1024*1024, 1024*1024, 0}, \
}
- 其次修改sfud_port.c,SFUD_W25Q64BV_DEVICE_INDEX为sfud_cfg中定义的
#else
/* bare metal platform */
// extern sfud_flash sfud_norflash0;
// sfud_dev = &sfud_norflash0;
sfud_dev = sfud_get_device(SFUD_W25Q64BV_DEVICE_INDEX);
#endif
- 最后在sfud初始化后调用fal_init()测试即可
fdb移植
- 只需要将fdb_cfg头文件中的宏定义设置为1
#define FDB_WRITE_GRAN 1
- 然后复制demo中的测试代码即可
硬件基础:内部Flash,野火霸道V2
fal移植
- 对于内部Flash移植,主要看samples\porting文件夹下的demo
- 对于该款F1较为简单,它的page和sector是一个东西是2kb,如果sector包含多个page大小不同的需要参考demo中的F2芯片
- 我用的标准库,demo用的HAL库,主要修改这部分即可,再者可以修改cfg文件的地址,但要注意map文件显示的大小,防止影响程序代码
// 实现demo的宏定义
#define __ALIGN_BEGIN __align(4)
#define __ALIGN_END
// 野火是大容量ZET6
#define STM32F103xE
// Flash加锁和解锁
HAL_FLASH_Unlock();
HAL_FLASH_Lock();
// 替换为
FLASH_Unlock();
FLASH_Lock();
// Flash写入
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr, write_data);
// 替换为
FLASH_ProgramWord(addr, write_data);
// Flash擦除
HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError);
// 替换为
FLASH_ErasePage(PageAddress);
// 最下方的stm32_onchip_flash
.len = 256*1024,
// 替换为
.len = 512*1024,
#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_
#define FAL_DEBUG 1
#define FAL_PART_HAS_TABLE_CFG
/* ===================== Flash device Configuration ========================= */
extern const struct fal_flash_dev stm32_onchip_flash;
/* flash device table */
#define FAL_FLASH_DEV_TABLE \
{ \
&stm32_onchip_flash, \
}
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG
/* partition table */
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WORD, "fdb_tsdb1", "stm32_onchip", 104*1024, 8*1024, 0}, \
{FAL_PART_MAGIC_WORD, "fdb_kvdb1", "stm32_onchip", 112*1024, 16*1024, 0}, \
}
#endif /* FAL_PART_HAS_TABLE_CFG */
#endif /* _FAL_CFG_H_ */
- 修改完成后,在主函数调用fal的初始化,显示success即可
fdb移植
- 只需要修改cfg文件
#define FDB_WRITE_GRAN 32
- 此时在demo中复制测试代码,测试完成即可