项目没有调试信息_SFUD | 一个简洁实用的开源项目,帮你轻松搞定SPI Flash

你是否因为搞不定 SPI Flash 而掉了好多头发?

你是否因为手撸 SPI Flash 驱动而浪费了大量开发时间?

你是否因为突然之间更换 SPI Flash 型号而去找产品打架?

如果没有,可以关闭这篇文章啦,有这时间去刷抖音开心开心不好吗~

如果有的话,你很幸运哈哈,在对的时间遇到对的库,接下来 mculover666 带你一起手把手在裸机移植 SFUD

废话少说,接下来有请主角 SFUD 登场~

1. SFUD

SFUD 全称 Serial Flash Universal Driver,是一款开源的串行 SPI Flash 通用驱动库。

SFUD主要特点有:

  • 支持 SPI/QSPI 接口

  • 面向对象思想编写(同时支持多个 Flash 对象)

  • 可灵活裁剪、扩展性强

SFUD的资源占用情况非常小:

  • 标准占用:RAM:0.2KB ROM:5.5KB

  • 最小占用:RAM:0.1KB ROM:3.6KB

SFUD 开源项目由 armink 大神发起,遵循 MIT 开源协议,代码在 Github 上的托管仓库如下:

https://github.com/armink/SFUD

文末点击阅读原文可以直接跳转到Github仓库哦~

2. 移植 SFUD 之前的准备

带有 SPI Flash的开发板准备

这里我准备的是小熊派开发板,主控芯片 STM32L431RCT6,板载 SPI Flash 型号为 W25Q64JV,板载 ST-Link下载器:

1502d1a629156fb2ed9cb2901ba2e271.png

工具准备

  • STM32CubeMX:用于配置QSPI外设和串口外设,并生成 MDK 工程;

  • Keil MDK:用于编译和下载工程;

  • 串口助手:用于查看开发板串口调试信息输出;

2ed6e176b702f92876280eb0311ed980.png

裸机工程准备

在移植之前,首先需要准备好一份裸机工程,主要完成以下配置:

  • 时钟配置

  • 根据实际 SPI Flash 硬件连接情况配置通信接口(SPI接口或者QSPI接口)

  • 根据实际情况配置一个串口;

具体的配置过程可以参考我的 STM32CubeMX 系列教程:

  • STM32Cube-18 | 使用QSPI读写SPI Flash(W25Q64)

SFUD源码准备

使用 Git 工具拉取 SFUD 源码到本地:

git clone https://github.com/armink/SFUD.git

SFUD 源码的几个文件夹作用如下:

dfaeaece27cd595fa5767abd89799e96.png

3. 复制 SFUD 文件到裸机工程

3.1. 复制裸机工程到 demo 文件夹

复制之前使用STM32CubeMX生成的裸机工程到 demo 文件夹中:

b39be209fc95a8900388ce85a3d17406.png

3.2. 创建 components 文件夹

在工程中创建 components 文件夹,用于存放 SFUD 适配本工程相关的一些代码,包括针对本工程的 printf 实现代码和 SFUD 配置代码。

建立 components/others 文件夹

该文件夹中主要存放两个文件:bsp.ctypes.h

types.h是 SFUD 用到的一些数据类型相关宏定义,无论什么型号芯片,都是通用的,可以直接从别的demo工程中复制过来。

bsp.c是printf重定向到串口的实现,SFUD 中的调试信息都是使用 printf 打印的,所以该文件非常重要,这里我使用的是STM32 HAL库,所以可以直接从STM32的demo工程中复制过来。

b5eefac7f2569efdb89cdffd54166b96.png
建立 components/sfud 文件夹

该文件夹主要存放 SFUD 适配本工程的文件, 包括 SFUD 底层移植文件sfud_port.c和 SFUD 配置文件sfud_cfg.h

这两个文件是需要自己适配的,这里我底层使用的是STM32 HAL库,所以我直接从其他 STM32 Demo 工程中拷贝过来:

46c9feb30460b3f5e70e6d4597b1037c.png

4. 添加文件并测试printf实现

打开工程中的 Keil-MDK 工程,开始向工程中添加printf实现文件 bsp.c,如图:

a9590dddf099ef819b62a79c6be2bede.png

添加之后在main.c中测试printf是否可以正常打印:

main.c 开始添加头文件:

c8bb8a741ebe2514f79b3900fdfae2d3.png

然后在 main函数 中开始测试:

6c7c8b5df3bc019336c56e985e6c7623.png

编译下载运行,在串口助手可以看到 printf 可以正常打印:

72848ff430c493641b93c99903252d5b.png

如果打印失败的话,就要停下来检查错误了,不能再进行下面的工作。

5. 添加和使用 SFUD 库

添加 SFUD 相关文件

向 MDK 工程中添加 SFUD 相关的文件:

新建 SFUD 组:

2e70f1da824bfd781e52fc08a13ae95a.png

添加 SFUD 实现文件:

3339ff410c088ac542e9376a1848ddf9.png

添加 SFUD 移植适配文件:

e86a2d76fb9acea984059cf452566711.png

添加 SFUD 相关头文件路径

838adb8cbb020bba3c8c41e3fd8d49ea.png

修改 SFUD 配置文件

首先在sfud_cfg.h中配置SFUD,具体的说明可以查看 SFUD 源码中的readme.md文件:

7ef9539a66b94886f2dcbee84f09eaf8.png

编写demo使用函数

首先包含 SFUD 头文件:

4d0ce0bc2bb981e1c85d952dce451b4d.png

然后开辟一个测试缓冲区:

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void sfud_demo(uint32_t addr, size_t size, uint8_t *data);

#define SFUD_DEMO_TEST_BUFFER_SIZE                     1024
static uint8_t sfud_demo_test_buf[SFUD_DEMO_TEST_BUFFER_SIZE];

/* USER CODE END 0 */

编写声明的 sfud_demo函数测试 SFUD 使用:

/* USER CODE BEGIN 4 */
/**
 * SFUD demo for the first flash device test.
 *
 * @param addr flash start address
 * @param size test flash size
 * @param size test flash data buffer
 */
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     {
        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;
    }
    /* write test */
    result = sfud_write(flash, addr, size, data);
    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         {
            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     {

        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);
    }
}

/* USER CODE END 4 */

最后在 main函数 中调用:

/* USER CODE BEGIN 2 */

printf("SFUD port by mculover666.\r\n");
/* SFUD initialize */
if (sfud_init() == SFUD_SUCCESS)
{
        /* enable qspi fast read mode, set one data lines width */
        sfud_qspi_fast_read_enable(sfud_get_device(SFUD_W25_DEVICE_INDEX), 1);
        sfud_demo(0, sizeof(sfud_demo_test_buf), sfud_demo_test_buf);
}
/* USER CODE END 2 */

测试结果

编译下载之后,在串口终端可以看到测试结果:

78fcd1368174b88cc035ee30b297a1eb.png
a8820c1f26a4d01770d53d1bb0b5b8cc.png
86a1e1bd1c3f2d1cb812e64be50d62cd.png

至此,SFUD移植测试完毕,大家有问题欢迎留言~

更多精彩文章及资源,欢迎关注我的微信公众号:『mculover666』。

a241a98603fdf338cc109b5a20875ae8.png

6af4125e1c101a3dfffbf4f57f183589.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值