RT-Thread 学习记录(二)SFUD挂载W25Q128,使用EasyFlash

一、前言

学习记录,已建好工程。FAL、SFUD、硬件SPI、W25Q128、EasyFlash。

二、步骤

一)配置Cube MX

双击 “Cube Mx Settings”(或“cubemx”->“cubemx.ioc”)打开Cube Mx,配置硬件SPI,选择hal库,点击生成。

二)配置RT-thread Settings

双击 “RT-Thread Settings”打开配置页面,添加软件包和组件。

1、添加组件FAL

使能组件“FAL”,并使能“使用SFUD驱动”,更改“设置使用FAL的设备名称”为“W25Q128”。

2、添加组件SPI

在组件“设备驱动程序”里使能“SPI驱动”,并使用“SFUD”,设置总线最大速度(自行更改)。

设置好后,图形配置界面会点亮这两个驱动。

3、EasyFlash

添加软件包“EasyFlash”,并配置。调试日志在测试完成后可关闭。

三)配置工程

1、排除构建

打开工程中“cubemx”文件夹,除“cubemx.ioc”外,其余全部排除构建。

2、复制生成的SPI相关函数

在软件左上角的“导航器”中选择项目,并将“cubemx”文件夹中“spi.c”文件的“MX_SPI1_Init”、“HAL_SPI_MspInit”、“HAL_SPI_MspDeInit”函数复制到“drivers”文件夹中“board.c”文件末尾。

有些SPI口上电后会默认为JTAG口,此时SPI初始化就会失败,需要在“HAL_SPI_MspInit”函数中禁止JTAG功能。

    __HAL_RCC_AFIO_CLK_ENABLE();
    __HAL_RCC_PWR_CLK_ENABLE();

    __HAL_AFIO_REMAP_SWJ_NOJTAG();

3、配置board.h文件

将SPI外设在“board.h"文件中打开宏定义。

4、配置stm32f1xx_hal_conf.h

在生成程序时,提示将“stm32f1xx_hal_conf.h”备份,并在“drivers”文件夹新建了“stm32f1xx_hal_conf_bak.h”文件,但是众多文件中调用的还是改名前的文件,所以会报错,这里选择将新建文件改为原来的名字(不知是否应这样处理)。

打开此文件,打开使能SPI模块宏。

5、添加fal_cfg.h

将“rt_thrread”->“components”->“fal”->“samples”->“porting”->“fal_cfg.h”文件移动到“drivers”->“include”文件夹中。

并在此文件中对设备名称、类型、空间分配函数进行更改。

#define NOR_FLASH_DEV_NAME             "W25Q128"   //设备名称,必须与fal设置一致

/* ===================== Flash device Configuration ========================= */
extern const struct fal_flash_dev stm32f2_onchip_flash;
extern struct fal_flash_dev nor_flash0;

/* flash device table */
//#define FAL_FLASH_DEV_TABLE                                          \
//{                                                                    \
//    &stm32f2_onchip_flash,                                           \
//    &nor_flash0,                                                     \
//}
#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,        "bl",     "stm32_onchip",         0,   64*1024, 0}, \
//    {FAL_PART_MAGIC_WORD,       "app",     "stm32_onchip",   64*1024,  704*1024, 0}, \
//    {FAL_PART_MAGIC_WORD, "easyflash", NOR_FLASH_DEV_NAME,         0, 1024*1024, 0}, \
//    {FAL_PART_MAGIC_WORD,  "download", NOR_FLASH_DEV_NAME, 1024*1024, 1024*1024, 0}, \
//}
#define FAL_PART_TABLE                                                               \
{                                                                                    \
    {FAL_PART_MAGIC_WORD, "easyflash", NOR_FLASH_DEV_NAME,         0, 1024*1024, 0}, \
    {FAL_PART_MAGIC_WORD,  "download", NOR_FLASH_DEV_NAME, 1024*1024, 1024*1024, 0}, \
    {FAL_PART_MAGIC_WORD,  "datafile", NOR_FLASH_DEV_NAME, 2*1024*1024, 8*1024*1024, 0}, \
}
#endif /* FAL_PART_HAS_TABLE_CFG */

6、添加fal_flash_sfud_port.c

将“rt_thrread”->“components”->“fal”->“samples”->“porting”->“fal_flash_sfud_port.c”文件移动到“drivers”文件夹中。打开此文件,按实际参数修改flash配置(大多数SPI Flash都支持sfud,无需程序配置即可自动读取参数)。

7、新建W25Qxx.c

在“application”文件夹新建“W25Qxx.c”文件,并在文件中自动挂载SPI设备,探测SPI Flash。

#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>

#define DBG_TAG "W25Qxx"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

#include <fal.h>
#include "drv_spi.h"
#include "spi_flash_sfud.h"

extern void Peripheral_power_ctrl(int  powermode); //flash供电

#define W25Q_SPI_DEVICE_NAME     "spi10"

/*********************************************************************************/

/*********************************************************************************/
/* 挂载设备到SPI总线,并向内核注册SPI设备
 * 设备为 spi10,即SPI1总线上的第0号设备
 * 设置SPI片选引脚
 * */
int w25q_spi_device_init()
{
    __HAL_RCC_GPIOA_CLK_ENABLE();
    return rt_hw_spi_device_attach("spi1", "spi10", GPIOA, GPIO_PIN_4);
}
INIT_DEVICE_EXPORT(w25q_spi_device_init);
/*********************************************************************************/

/*********************************************************************************/
/* 通过SFUD驱动库和SPI设备探测SPI Flash
 * */
static int rt_hw_spi_flash_with_sfud_init(void)
{
    Peripheral_power_ctrl(1);
    if (RT_NULL == rt_sfud_flash_probe("W25Q128", "spi10"))
    {
        return RT_ERROR;
    };

    return RT_EOK;
}
INIT_COMPONENT_EXPORT(rt_hw_spi_flash_with_sfud_init);
/*********************************************************************************/

此时编译下载程序,可以在打印出的调试信息中看到SPI Flash已经挂载成功。

如果需要直接驱动W25Q128,不使用fal,则不需要添加“fal_cfg.h”与“fal_flash_sfud_port.c”,通过获取sfud驱动句柄,使用sfud函数操作flash。

sfud_flash *g_pSfudDev_s = NULL;
/*********************************************************************************/
/* 挂载设备到SPI总线,并向内核注册SPI设备
 * 设备为 spi10,即SPI1总线上的第0号设备
 * 设置SPI片选引脚
 * */
int w25q_spi_device_init()
{
    __HAL_RCC_GPIOA_CLK_ENABLE();
    return rt_hw_spi_device_attach("spi1", "spi10", GPIOA, GPIO_PIN_4); //设置SPI片选引脚
}
INIT_DEVICE_EXPORT(w25q_spi_device_init);
/*********************************************************************************/

/*********************************************************************************/
/* 通过SFUD驱动库和SPI设备探测SPI Flash
 * */
int rt_hw_spi_flash_with_sfud_init(void)
{
    if (RT_NULL == rt_sfud_flash_probe("W25Q128", "spi10"))
    {
        return RT_ERROR;
    }

    g_pSfudDev_s = rt_sfud_flash_find("spi10");
    if(g_pSfudDev_s == RT_NULL)
    {
        return RT_ERROR;
    }

    return RT_EOK;
}
INIT_COMPONENT_EXPORT(rt_hw_spi_flash_with_sfud_init);
/*********************************************************************************/

/*********************************************************************************/
/* Flash校验函数
 */
void L_CheckFlash(void)
{
    static uint32_t s_DataAddr_u32 = 0;
    static uint8_t s_WriteData_u8 = 0, s_CommErrCnt_u8 = 0;
    uint8_t l_ReadData_u8 = 0;
    rt_uint32_t e = 0;
    sfud_err ret;

    //地址
    //每个扇区仅写1次,便转到下一个扇区
    if((s_DataAddr_u32 += 4096) > 16384000) // 4096Bytes/sector, 4096sector/chip
    {
        s_DataAddr_u32 = 0;
    }
    LOG_D("W25Q128 Addr: %d ", s_DataAddr_u32);

    //写入
    s_WriteData_u8 ++;
    ret = sfud_erase_write(g_pSfudDev_s, s_DataAddr_u32, 1, &s_WriteData_u8);
    if(ret == SFUD_SUCCESS)
    {
        LOG_D("write: %d ", s_WriteData_u8);
    }
    else
    {
        s_CommErrCnt_u8++;
        LOG_W("W25Q128 write err !");
    }

    //读取
    ret = sfud_read(g_pSfudDev_s, s_DataAddr_u32, 1, &l_ReadData_u8);
    if(ret == SFUD_SUCCESS)
    {
        LOG_D("read: %d ", l_ReadData_u8);
    }
    else
    {
        s_CommErrCnt_u8++;
        LOG_W("W25Q128 read err !");
    }

    //判断
    if(l_ReadData_u8 != s_WriteData_u8)
    {
        if(++s_CommErrCnt_u8 > 1) //连续2次校验不通过才认为失败
        {
            s_CommErrCnt_u8 = 1;
            LOG_E("comm err !"); //检验失败
        }
    }
    else
    {
        s_CommErrCnt_u8 = 0; //校验通过
    }
}
/*********************************************************************************/

在合适的地方调用fal初始化函数,编译下载程序,可以在打印出的调试信息中看到Flash已经按照设置分区。

fal_init();       //fal初始化

8、添加ef_fal_port.c

在软件左上角的“导航器”中选择项目,将“packages”->“EasyFlash”->“ports”->“ef_fal_port.c”文件文件移动到“drivers”文件夹中。并将文件中宏“FAL_EF_PART_NAME”改为““easyflash””。“default_env_set”结构体数组中存储的是环境变量的key-value值,可在此定义新的环境变量。

调用EasyFlash初始化函数,编译下载程序,可以在打印出的调试信息中看到EasyFlash已经初始化成功。

easyflash_init(); //easyflash初始化

9、测试功能

在main函数中新建2个线程,1个信号量。在线程1中设置环境变量,在线程2中读取环境变量。

fal_init();       //fal初始化
easyflash_init(); //easyflash初始化

env_load();       //环境变量载入

test_sem1 = rt_sem_create("sem1", 0, RT_IPC_FLAG_FIFO);

rt_thread_t thread1 = rt_thread_create("set_env", (void *)G_SetEnv_entry, RT_NULL, 2048, 25, 10);
if (thread1 != RT_NULL)
{
    rt_thread_startup(thread1);
}

rt_thread_t thread2 = rt_thread_create("read_env", (void *)G_ReadEnv_entry, RT_NULL, 1024, 25, 10);
if (thread2 != RT_NULL)
{
    rt_thread_startup(thread2);
}
/*********************************************************************************/
/* 环境变量载入
 */
void env_load(void)
{
    char temp[25] = {0};
    unsigned int len = 0;

    ef_get_env_blob("HardwareVersion",RT_NULL, 0, &len);
    if(len > 15)
    {
        LOG_E("HardwareVersion get env too lengthy");
        return;
    }
    ef_get_env_blob("HardwareVersion", temp, len, RT_NULL);
    get_config_data.HardwareVersion=atoi(temp);
    rt_memset(temp, 0, 25);

    ef_get_env_blob("SoftwareVersion",RT_NULL, 0, &len);
    if(len > 15)
    {
        LOG_E("SoftwareVersion get env too lengthy");
        return;
    }
    ef_get_env_blob("SoftwareVersion", temp, len, RT_NULL);
    get_config_data.SoftwareVersion = atoi(temp);
    rt_memset(temp, 0, 25);


    ef_get_env_blob("testdata1",RT_NULL, 0, &len);
    if(len > 15)
    {
        LOG_E("testdata1 get env too lengthy");
        return;
    }
    ef_get_env_blob("testdata1", temp, len, RT_NULL);
    get_config_data.testdata1 = atoi(temp);
    rt_memset(temp, 0, 25);

    ef_get_env_blob("testdata2",RT_NULL, 0, &len);
    if(len > 15)
    {
        LOG_E("testdata2 get env too lengthy");
        return;
    }
    ef_get_env_blob("testdata2", temp, len, RT_NULL);
    get_config_data.testdata2 = atoi(temp);
    rt_memset(temp, 0, 25);

    LOG_D("---------------ENV-------------------");
    LOG_D("Heartbeat:%d",            get_config_data.Heartbeat);
    LOG_D("Sending_interval_val:%d", get_config_data.Sending_interval_val);
    LOG_D("SoftwareVersion:%d",      get_config_data.SoftwareVersion);
    LOG_D("HardwareVersion:%d",      get_config_data.HardwareVersion);
    LOG_D("testdata1:%d",            get_config_data.testdata1);
    LOG_D("testdata2:%d",            get_config_data.testdata2);
    LOG_D("-------------------------------------");
}
/*********************************************************************************/
/*********************************************************************************/
void G_SetEnv_entry(void)
{
    char chartemp[15];
    int data1 = 20;
    int data2 = 11;

    while(1)
    {
        rt_memset(chartemp, 0, sizeof(chartemp));
        itoa(++data1, chartemp, 10);
        ef_set_env("testdata1", chartemp); //存入env中
        LOG_I("write testdata1: %d", data1);

        rt_memset(chartemp, 0, sizeof(chartemp));
        itoa(data2 += 2, chartemp, 10);
        ef_set_env("testdata2", chartemp); //存入env中
        LOG_I("write testdata2: %d", data2);

        rt_sem_release(test_sem1);

        rt_thread_delay(2000);
    }
}
/*********************************************************************************/

/*********************************************************************************/
void G_ReadEnv_entry(void)
{
    char temp[25] = {0};
    unsigned int len = 0;

    while(1)
    {
        rt_sem_take(test_sem1, RT_WAITING_FOREVER);

        ef_get_env_blob("testdata1",RT_NULL, 0, &len);
        if(len > 15)
        {
            LOG_E("testdata1 get env too lengthy");
    //            return;
        }
        ef_get_env_blob("testdata1", temp, len, RT_NULL);
        get_config_data.testdata1 = atoi(temp);
        LOG_I("read testdata1: %d", get_config_data.testdata1);
        rt_memset(temp, 0, 25);


        ef_get_env_blob("testdata2", RT_NULL, 0, &len);
        if(len > 15)
        {
            LOG_E("testdata2 get env too lengthy");
    //            return;
        }
        ef_get_env_blob("testdata2", temp, len, RT_NULL);
        get_config_data.testdata2 = atoi(temp);
        LOG_I("read testdata2: %d", get_config_data.testdata2);
        rt_memset(temp, 0, 25);

        rt_thread_delay(5);
    }
}
/*********************************************************************************/

编译下载后,可以看到环境变量依次写入与读取。

三、工程代码

https://gitee.com/www73554/stm32-l431_-test1.0.git

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值