移植准备:
SFUD 是一款通用的flash驱动库,网上很多介绍,这里省略,有兴趣的去搜索。源文件下载 https://github.com/armink/SFUD,开源的,直接移植。
如下是根据所给例程移植的。
1.打开文件夹,直接拷贝sfud文件到工程中:
demo文件夹中是作者给出的几个平台的移植。仔细阅读readme.
2 工程中添加C文件
将如下三个.c添加到工程中,并包含到include Path中
3 修改接口,关键地方就是这里了
主要修改sfud_port.c中的sfud_spi_port_init()
sfud_err sfud_spi_port_init(sfud_flash *flash)
{
sfud_err result = SFUD_SUCCESS;
if (!strcmp(flash->spi.name, "SPI2")) {
w25qxx_init();
spi_lock_init();
/* 同步 Flash 移植所需的接口及数据 */
flash->spi.wr = spi_write_read;
flash->spi.lock = spi_lock;
flash->spi.unlock = spi_unlock;
// flash->spi.user_data = &spi2;
/* about 100 microsecond delay */
flash->retry.delay = retry_delay_100us;
/* adout 60 seconds timeout */
flash->retry.times = 60 * 1000;
}
return result;
}
/************************************************************/
其中 w25qxx_init()为flash硬件初始化,包括SPI的配置和GPIO的配置;
/************************************************************/
spi_lock_init();如果使用操作系统,可做如下:
// static SemaphoreHandle_t SfudMutexSemaphore = NULL;
static void spi_lock_init()
{
SfudMutexSemaphore = xSemaphoreCreateMutex();
if (SfudMutexSemaphore == NULL) {
sfud_log_debug("sfud semaphore create faild");
}
}
//关全局中断还是使用信号量,自行选择
static void spi_lock(const sfud_spi *spi)
{
// __disable_irq();
// if (SfudMutexSemaphore != NULL) {
// xSemaphoreTake(SfudMutexSemaphore, portMAX_DELAY);
// }
}
static void spi_unlock(const sfud_spi *spi)
{
// __enable_irq();
// if (SfudMutexSemaphore != NULL) {
// xSemaphoreGive(SfudMutexSemaphore); // send semaph
// }
}
若裸机,则直接搞个标志位就行;
或者不使用;直接为空;
/************************************************************/
spi_write_read()可做如下:
/**
* SPI write data then read data
*/
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_25QXX_CS_LOW();
if (write_size) {
spi_flash_buffer_write(write_buf, write_size);
}
if (read_size) {
spi_flash_buffer_read(read_buf, read_size);
}
SPI_25QXX_CS_HIGH();
return result;
}
static void spi_flash_buffer_write(const uint8_t *pbuf_write, size_t size_write)
{
// SPI_25QXX_CS_LOW();
while (size_write--) {
w25qxx_wr_byte(*pbuf_write);
pbuf_write++;
}
// SPI_25QXX_CS_HIGH();
}
static void spi_flash_buffer_read(uint8_t *pbuf_read, size_t size_read)
{
// SPI_25QXX_CS_LOW();
while (size_read--) {
*pbuf_read = w25qxx_wr_byte(GD25QXX_DUMMY);
pbuf_read++;
}
// SPI_25QXX_CS_HIGH();
}
//w25qxx_wr_byte()是GD官方库所给例程中的spi_send_byte(),然后自行封装的接口:
uint8_t spi_send_byte(uint32_t spi_periph, uint8_t byte)
{
uint8_t retry = 0;
/* loop while data register in not empty */
while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE)) {
retry++;
if (retry > SPI_RETRY_TIME) {
return ERROR;
}
}
/* send byte through the SPI5 peripheral */
spi_i2s_data_transmit(spi_periph, byte);
retry = 0;
/* wait to receive a byte */
while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE)) {
retry++;
if (retry > SPI_RETRY_TIME) {
return ERROR;
}
}
/* return the byte read from the SPI bus */
return(spi_i2s_data_receive(spi_periph));
}
flash->retry.delay和flash->retry.times可要可不要,自行选择;
还有个关键的flash设备表
如何配置及初始化设备,这个armlink大佬写的很详细,仔细阅读。其他部分,网上一堆,自行搜索。
还要注意是否使用QSPI。