1.时钟的配置主时钟为80M
2.配置QUSPI接口,同时使能上拉
3.QUSPI参数配置,开启全局中断
4.生成工程文件
5.下载SFUD文件,提供下载地址
6.添加printf重定向与us延时函数,用于系统调试和移植。
7.添加SFUD文件,需要添加相应了路径
8.底层函数移植,只需修改两个文件
9.头文件sfud_cfg.h修改实例
10.核心接口.c示例源码
#include <sfud.h>
#include <stdarg.h>
#include "quadspi.h"
#include "delay.h"
typedef struct
{
QSPI_HandleTypeDef *spix;
GPIO_TypeDef *cs_gpiox;
uint16_t cs_gpio_pin;
} spi_user_data, *spi_user_data_t;
void sfud_log_info(const char *format, ...);
static char log_buf[256];
void sfud_log_debug(const char *file, const long line, const char *format, ...);
sfud_err qspi_send_then_recv(const void *send_buf, size_t send_length, void *recv_buf, size_t recv_length);
static void spi_lock (const sfud_spi *spi);
static void spi_unlock(const sfud_spi *spi);
void sfud_log_debug(const char *file, const long line, const char *format, ...);
static void retry_delay_100us(void);
static spi_user_data spi1 = { .spix = &hqspi, .cs_gpiox = NULL, .cs_gpio_pin = NULL };
/**
* 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;
// uint8_t send_data, read_data;
/**
* add your spi write and read code
*/
spi_user_data_t spi_dev = (spi_user_data_t) spi->user_data;
if (write_size)
{
SFUD_ASSERT(write_buf);
}
if (read_size)
{
SFUD_ASSERT(read_buf);
}
//CS EN
if (spi_dev->cs_gpiox != NULL)
HAL_GPIO_WritePin(spi_dev->cs_gpiox, spi_dev->cs_gpio_pin, GPIO_PIN_RESET);
//读写数据
if (write_size && read_size)
{
/* read data */
qspi_send_then_recv(write_buf, write_size, read_buf, read_size);
}
else if (write_size)
{
/* send data */
qspi_send_then_recv(write_buf, write_size, NULL, NULL);
}
//CS DISABLE
if (spi_dev->cs_gpiox != NULL)
HAL_GPIO_WritePin(spi_dev->cs_gpiox, spi_dev->cs_gpio_pin, GPIO_PIN_SET);
return result;
}
#ifdef SFUD_USING_QSPI
/**
* read flash data by QSPI
*/
static sfud_err qspi_read(const struct __sfud_spi *spi, uint32_t addr, sfud_qspi_read_cmd_format *qspi_read_cmd_format,
uint8_t *read_buf, size_t read_size) {
sfud_err result = SFUD_SUCCESS;
/**
* add your qspi read flash data code
*/
QSPI_CommandTypeDef Cmdhandler;
/* set cmd struct */
Cmdhandler.Instruction = qspi_read_cmd_format->instruction;
if(qspi_read_cmd_format->instruction_lines == 0)
{
Cmdhandler.InstructionMode = QSPI_INSTRUCTION_NONE;
}else if(qspi_read_cmd_format->instruction_lines == 1)
{
Cmdhandler.InstructionMode = QSPI_INSTRUCTION_1_LINE;
}else if(qspi_read_cmd_format->instruction_lines == 2)
{
Cmdhandler.InstructionMode = QSPI_INSTRUCTION_2_LINES;
}else if(qspi_read_cmd_format->instruction_lines == 4)
{
Cmdhandler.InstructionMode = QSPI_INSTRUCTION_4_LINES;
}
Cmdhandler.Address = addr;
Cmdhandler.AddressSize = QSPI_ADDRESS_24_BITS;
if(qspi_read_cmd_format->address_lines == 0)
{
Cmdhandler.AddressMode = QSPI_ADDRESS_NONE;
}else if(qspi_read_cmd_format->address_lines == 1)
{
Cmdhandler.AddressMode = QSPI_ADDRESS_1_LINE;
}else if(qspi_read_cmd_format->address_lines == 2)
{
Cmdhandler.AddressMode = QSPI_ADDRESS_2_LINES;
}else if(qspi_read_cmd_format->address_lines == 4)
{
Cmdhandler.AddressMode = QSPI_ADDRESS_4_LINES;
}
Cmdhandler.AlternateBytes = 0;
Cmdhandler.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
Cmdhandler.AlternateBytesSize = 0;
Cmdhandler.DummyCycles = qspi_read_cmd_format->dummy_cycles;
Cmdhandler.NbData = read_size;
if(qspi_read_cmd_format->data_lines == 0)
{
Cmdhandler.DataMode = QSPI_DATA_NONE;
}else if(qspi_read_cmd_format->data_lines == 1)
{
Cmdhandler.DataMode = QSPI_DATA_1_LINE;
}else if(qspi_read_cmd_format->data_lines == 2)
{
Cmdhandler.DataMode = QSPI_DATA_2_LINES;
}else if(qspi_read_cmd_format->data_lines == 4)
{
Cmdhandler.DataMode = QSPI_DATA_4_LINES;
}
Cmdhandler.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
Cmdhandler.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
Cmdhandler.DdrMode = QSPI_DDR_MODE_DISABLE;
Cmdhandler.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
HAL_QSPI_Command(&hqspi, &Cmdhandler, 5000);
if (HAL_QSPI_Receive(&hqspi, read_buf, 5000) != HAL_OK)
{
//printf("myQSPI is ERR\n");
sfud_log_info("qspi recv data failed(%d)!", hqspi.ErrorCode);
hqspi.State = HAL_QSPI_STATE_READY;
result = SFUD_ERR_READ;
}
//else printf("myQSPI is OK\n");
return result;
}
#endif /* SFUD_USING_QSPI */
sfud_err sfud_spi_port_init(sfud_flash *flash) {
sfud_err result = SFUD_SUCCESS;
/**
* add your port spi bus and device object initialize code like this:
* 1. rcc initialize
* 2. gpio initialize
* 3. spi device initialize
* 4. flash->spi and flash->retry item initialize
* flash->spi.wr = spi_write_read; //Required
* flash->spi.qspi_read = qspi_read; //Required when QSPI mode enable
* flash->spi.lock = spi_lock;
* flash->spi.unlock = spi_unlock;
* flash->spi.user_data = &spix;
* flash->retry.delay = null;
* flash->retry.times = 10000; //Required
*/
switch (flash->index)
{
case SFUD_W25_DEVICE_INDEX:
{
/* set the interfaces and data */
flash->spi.wr = spi_write_read;
flash->spi.qspi_read = qspi_read;
flash->spi.lock = spi_lock;
flash->spi.unlock = spi_unlock;
flash->spi.user_data = &spi1;
/* about 100 microsecond delay */
flash->retry.delay = retry_delay_100us;
/* adout 60 seconds timeout */
flash->retry.times = 60 * 10000;
break;
}
}
return result;
}
/**
* This function is print debug info.
*
* @param file the file which has call this function
* @param line the line number which has call this function
* @param format output format
* @param ... args
*/
void sfud_log_debug(const char *file, const long line, const char *format, ...) {
va_list args;
/* args point to the first variable parameter */
va_start(args, format);
printf("[SFUD](%s:%ld) ", file, line);
/* must use vprintf to print */
vsnprintf(log_buf, sizeof(log_buf), format, args);
printf("%s\n", log_buf);
va_end(args);
}
/**
* This function is print routine info.
*
* @param format output format
* @param ... args
*/
void sfud_log_info(const char *format, ...)
{
va_list args;
/* args point to the first variable parameter */
va_start(args, format);
printf("[SFUD]");
/* must use vprintf to print */
vsnprintf(log_buf, sizeof(log_buf), format, args);
printf("%s\n", log_buf);
va_end(args);
}
sfud_err qspi_send_then_recv(const void *send_buf, size_t send_length, void *recv_buf, size_t recv_length)
{
assert_param(send_buf);
assert_param(recv_buf);
assert_param(send_length != 0);
QSPI_CommandTypeDef Cmdhandler;
unsigned char *ptr = (unsigned char *)send_buf;
size_t count = 0;
sfud_err result = SFUD_SUCCESS;
/* get instruction */
Cmdhandler.Instruction = ptr[0];
Cmdhandler.InstructionMode = QSPI_INSTRUCTION_1_LINE;
count++;
/* get address */
if (send_length > 1)
{
if (send_length >= 4)
{
/* address size is 3 Byte */
Cmdhandler.Address = (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]);
Cmdhandler.AddressSize = QSPI_ADDRESS_24_BITS;
count += 3;
}
else
{
return SFUD_ERR_READ;
}
Cmdhandler.AddressMode = QSPI_ADDRESS_1_LINE;
}
else
{
/* no address stage */
Cmdhandler.Address = 0 ;
Cmdhandler.AddressMode = QSPI_ADDRESS_NONE;
Cmdhandler.AddressSize = 0;
}
Cmdhandler.AlternateBytes = 0;
Cmdhandler.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
Cmdhandler.AlternateBytesSize = 0;
Cmdhandler.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
Cmdhandler.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
Cmdhandler.DdrMode = QSPI_DDR_MODE_DISABLE;
Cmdhandler.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
if (send_buf && recv_buf)
{
/* recv data */
/* set dummy cycles */
if (count != send_length)
{
Cmdhandler.DummyCycles = (send_length - count) * 8;
}
else
{
Cmdhandler.DummyCycles = 0;
}
/* set recv size */
Cmdhandler.DataMode = QSPI_DATA_1_LINE;
Cmdhandler.NbData = recv_length;
HAL_QSPI_Command(&hqspi, &Cmdhandler, 5000);
if (recv_length != 0)
{
if (HAL_QSPI_Receive(&hqspi, recv_buf, 5000) != HAL_OK)
{
// printf("rx is ERR\n");
sfud_log_info("qspi recv data failed(%d)!", hqspi.ErrorCode);
hqspi.State = HAL_QSPI_STATE_READY;
result = SFUD_ERR_READ;
}
//else printf("rx is OK\n");
}
return result;
}
else
{
/* send data */
/* set dummy cycles */
Cmdhandler.DummyCycles = 0;
/* determine if there is data to send */
if (send_length - count > 0)
{
Cmdhandler.DataMode = QSPI_DATA_1_LINE;
}
else
{
Cmdhandler.DataMode = QSPI_DATA_NONE;
}
/* set send buf and send size */
Cmdhandler.NbData = send_length - count;
HAL_QSPI_Command(&hqspi, &Cmdhandler, 5000);
if (send_length - count > 0)
{
if (HAL_QSPI_Transmit(&hqspi, (uint8_t *)(ptr + count), 5000) != HAL_OK)
{
// printf("tx is ER\n");
sfud_log_info("qspi send data failed(%d)!", hqspi.ErrorCode);
hqspi.State = HAL_QSPI_STATE_READY;
result = SFUD_ERR_WRITE;
}
//else
//printf("tx is OK\n");
}
return result;
}
}
static void spi_lock(const sfud_spi *spi)
{
__disable_irq();
}
static void spi_unlock(const sfud_spi *spi)
{
__enable_irq();
}
//需要移植时间延时函数
static void retry_delay_100us(void)
{
delay_us(100);
}
12. APP功能测试
main添加头文件#include <sfud.h>
main添加测试代码
printf("sfud_init is start\n");
if (sfud_init() == SFUD_SUCCESS)
{ printf("sfud_init is Ok\n");
/* enable qspi fast read mode, set four data lines width */
sfud_qspi_fast_read_enable(sfud_get_device(SFUD_W25_DEVICE_INDEX), 4);
sfud_demo(0, sizeof(sfud_demo_test_buf), sfud_demo_test_buf);
}
void sfud_demo(uint32_t addr, size_t size, uint8_t *data)
{
sfud_err result = SFUD_SUCCESS;
extern sfud_flash *sfud_dev;
const sfud_flash *flash = sfud_get_device(SFUD_W25_DEVICE_INDEX);
size_t i;
/* prepare write data */
for (i = 0; i < size; i++)
{
data[i] = i;
}
/* erase test */
result = sfud_erase(flash, addr, size);
if (result == SFUD_SUCCESS)
{
printf("Erase the %s flash data finish. Start from 0x%08X, size is %zu.\r\n", flash->name, addr, size);
}
else
{
printf("Erase the %s flash data failed.\r\n", flash->name);
return;
}
printf("here---1\n");
/* write test */
result = sfud_write(flash, addr, size, data);
printf("here---2\n");
if (result == SFUD_SUCCESS)
{
printf("Write the %s flash data finish. Start from 0x%08X, size is %zu.\r\n", flash->name, addr, size);
}
else
{
printf("Write the %s flash data failed.\r\n", flash->name);
return;
}
/* read test */
result = sfud_read(flash, addr, size, data);
if (result == SFUD_SUCCESS)
{
printf("Read the %s flash data success. Start from 0x%08X, size is %zu. The data is:\r\n", flash->name, addr, size);
printf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\r\n");
for (i = 0; i < size; i++)
{
if (i % 16 == 0)
{
printf("[%08X] ", addr + i);
}
printf("%02X ", data[i]);
if (((i + 1) % 16 == 0) || i == size - 1)
{
printf("\r\n");
}
}
printf("\r\n");
}
else
{
printf("Read the %s flash data failed.\r\n", flash->name);
}
/* data check */
for (i = 0; i < size; i++)
{
if (data[i] != i % 256)
{
printf("Read and check write data has an error. Write the %s flash data failed.\r\n", flash->name);
break;
}
}
if (i == size)
{
printf("The %s flash test is success.\r\n", flash->name);
}
13.观察串口打印效果
14.结束