使用FAL操作STM32F103VET6单片机的片内flash和外部norflash(SFUD驱动)
1.新建一个命名为fal的工程,控制台串口我使用了uart5,对应管脚PC12和PD2

工程新建好以后,编译,报错

双击改报错信息,跳转到下图这个位置
 
把RT_WEAK改为rt_weak,后重新编译,下载到单片机中

重新正常运行
2.双击CubeMX Settings ,选择正确的单片机型号,配置norflash使用的SPI管脚,配置时钟
 

 



点击OK,软件自动配置时钟

我使用的是PB6作为SPI的CS管脚,这里配置为输出模式

配置SPI1参数

生成初始化代码
 
关闭STM32CuMX,可能不能一次关闭,需要连续不断点击右上角X标志,然后会弹出这个提示窗口
 
点击OK
 
将这个文件名称后面的_bak删了,最终更名为"stm32f1xx_hal_conf.h"

 
修改系统时钟为外部晶振
 
将时钟初始化函数粘贴到drv_clk.c中,放到clk_init函数的上面
 
按照board.h中SPI CONFIG 的要求配置SPI1
step1: 在RT-Thread Settings中进行设置


step2: #define BSP_USING_SPI1

step3:

step4:



将sample文件夹排除构建

把文件fal_flash_stm32f2_port.c重命名为fal_flash_stm32f1_port.c
并且用下面的内容替换文件内容
#include <string.h>
#include <fal.h>
#include <stm32f1xx.h>
#if defined(STM32F103xE)
#define PAGE_SIZE     2048
#else
#define PAGE_SIZE     1024
#endif
/*
STM32F1会因容量不同而不同
    小容量和中容量产品主存储块128KB以下,  每页1KB。
    大容量和互联型产品主存储块256KB以上,  每页2KB。
GD32   会因容量不同而不同
    1. Low-density Products     Flash容量从 16KB到  32KB的产品
    2. Medium-density Products  Flash容量从 64KB到 128KB的产品
          全是1K
    3. High-density Products    Flash容量从256KB到 512KB的产品
          全是2K
    4. XL-density Products      Flash容量从768KB到3072KB的产品
          <512K 是2K
          >512K 是4K
雅特力
    全是2K
STM32F4
    STM32F4的flash页尺寸不一样,低地址16KB,高地址32KB或128KB.
*/
static int init(void)
{
    /* do nothing now */
    return 1;
}
static int ef_err_port_cnt = 0;
int on_ic_read_cnt  = 0;
int on_ic_write_cnt = 0;
void feed_dog(void)
{
}
static int read(long offset, uint8_t *buf, size_t size)
{
    size_t i;
    uint32_t addr = stm32_onchip_flash.addr + offset;
    if( addr%4 != 0)
        ef_err_port_cnt++;
    for (i = 0; i < size; i++, addr++, buf++)
    {
        *buf = *(uint8_t *) addr;
    }
    on_ic_read_cnt++;
    return size;
}
static int write(long offset, const uint8_t *buf, size_t size)
{
    size_t   i;
    uint32_t addr = stm32_onchip_flash.addr + offset;
    __ALIGN_BEGIN uint32_t write_data __ALIGN_END;
    __ALIGN_BEGIN uint32_t read_data  __ALIGN_END;
    if(addr%4 != 0)
        ef_err_port_cnt++;
/*
    if((int)buf%4 != 0)
        ef_err_port_cnt++;
*/
    HAL_FLASH_Unlock();
    for (i = 0; i < size; i += 4, buf+=4, addr += 4) {
        memcpy(&write_data, buf, 4); //用以保证HAL_FLASH_Program的第三个参数是内存首地址对齐
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr, write_data);
        read_data = *(uint32_t *)addr;
        /* You can add your code under here. */
        if (read_data != write_data) {
            HAL_FLASH_Lock();
            return -1;
        }
        else{
            //FLash操作可能非常耗时,如果有看门狗需要喂狗,以下代码由用户实现
           feed_dog();
        }
    }
    HAL_FLASH_Lock();
    on_ic_write_cnt++;
    return size;
}
static int erase(long offset, size_t size)
{
    uint32_t addr = stm32_onchip_flash.addr + offset;
    HAL_StatusTypeDef flash_status;
    size_t erase_pages, i;
    uint32_t PAGEError = 0;
    erase_pages = size / PAGE_SIZE;
    if (size % PAGE_SIZE != 0) {
        erase_pages++;
    }
    FLASH_EraseInitTypeDef EraseInitStruct;
    EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
    EraseInitStruct.NbPages     = 1;  //一次擦出一个扇区, 以执行一次喂狗,防止超时
    HAL_FLASH_Unlock();
    for (i = 0; i < erase_pages; i++) {
        EraseInitStruct.PageAddress = addr + (FLASH_PAGE_SIZE * i);
        flash_status = HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError);
        if (flash_status != HAL_OK) {
            HAL_FLASH_Lock();
            return -1;
        }
        else{
            //FLash操作可能非常耗时,如果有看门狗需要喂狗,以下代码由用户实现
            feed_dog();
        }
    }
    HAL_FLASH_Lock();
    return size;
}
/*
  "stm32_onchip" : Flash 设备的名字。
  0x08000000: 对 Flash 操作的起始地址。
  1024*1024:Flash 的总大小(1MB)。
  128*1024:Flash 块/扇区大小(因为 STM32F2 各块大小不均匀,所以擦除粒度为最大块的大小:128K)。
  {init, read, write, erase} :Flash 的操作函数。 如果没有 init 初始化过程,第一个操作函数位置可以置空。
  8 : 设置写粒度,单位 bit, 0 表示未生效(默认值为 0 ),该成员是 fal 版本大于 0.4.0 的新增成员。各个 flash 写入粒度不尽相同,可通过该成员进行设置,以下列举几种常见 Flash 写粒度:
  nor flash:  1 bit
  stm32f2/f4: 8 bit
  stm32f1:    32 bit
  stm32l4:    64 bit
 */
//1.定义 flash 设备
const struct fal_flash_dev stm32_onchip_flash =
{
    .name       = "stm32_onchip",
    .addr       = 0x08000000,
    .len        = 512*1024,
    .blk_size   = 2*1024,
    .ops        = {init, read, write, erase},
    .write_gran = 32
};

将下面的内容替换fal_flash_sfud_port.c文件的内容
/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2018-01-26     armink       the first version
 */
#include <fal.h>
#include <sfud.h>
#ifdef FAL_USING_SFUD_PORT
#ifdef RT_USING_SFUD
#include <spi_flash_sfud.h>
#endif
#ifndef FAL_USING_NOR_FLASH_DEV_NAME
#define FAL_USING_NOR_FLASH_DEV_NAME             "norflash0"
#endif
static int init(void);
static int read(long offset, uint8_t *buf, size_t size);
static int write(long offset, const uint8_t *buf, size_t size);
static int erase(long offset, size_t size);
static sfud_flash_t sfud_dev = NULL;
struct fal_flash_dev nor_flash0 =
{
    .name       = FAL_USING_NOR_FLASH_DEV_NAME,
    .addr       = 0,
    .len        = 16 * 1024 * 1024,
    .blk_size   = 4096,
    .ops        = {init, read, write, erase},
    .write_gran = 1
};
static int init(void)
{
#ifdef RT_USING_SFUD
    /* RT-Thread RTOS platform */
    sfud_dev = rt_sfud_flash_find_by_dev_name(FAL_USING_NOR_FLASH_DEV_NAME);
#else
    /* bare metal platform */
    extern sfud_flash sfud_norflash0;
    sfud_dev = &sfud_norflash0;
#endif
    if (NULL == sfud_dev)
    {
        return -1;
    }
    /* update the flash chip information */
    nor_flash0.blk_size = sfud_dev->chip.erase_gran;
    nor_flash0.len = sfud_dev->chip.capacity;
    return 0;
}
static int read(long offset, uint8_t *buf, size_t size)
{
    assert(sfud_dev);
    assert(sfud_dev->init_ok);
    sfud_read(sfud_dev, nor_flash0.addr + offset, size, buf);
    return size;
}
static int write(long offset, const uint8_t *buf, size_t size)
{
    assert(sfud_dev);
    assert(sfud_dev->init_ok);
    if (sfud_write(sfud_dev, nor_flash0.addr + offset, size, buf) != SFUD_SUCCESS)
    {
        return -1;
    }
    return size;
}
static int erase(long offset, size_t size)
{
    assert(sfud_dev);
    assert(sfud_dev->init_ok);
    if (sfud_erase(sfud_dev, nor_flash0.addr + offset, size) != SFUD_SUCCESS)
    {
        return -1;
    }
    return size;
}
#endif /* FAL_USING_SFUD_PORT */

将下面的内容替换fal_cfg.h中的内容
/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2018-05-17     armink       the first version
 */
#ifndef _FAL_CFG_H_
#define _FAL_CFG_H_
#include <rtconfig.h>
#include <board.h>
#define NOR_FLASH_DEV_NAME "norflash0"
/* ===================== 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,                                                     \
}
/* ====================== 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}, \
}
#endif /* FAL_PART_HAS_TABLE_CFG */
#endif /* _FAL_CFG_H_ */
按下面的截图 修改main函数的内容

在applications文件夹下新增加一个norflash的文件夹,文件夹中增加2个文件,如图所示

norflash.h文件内如如下
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2023-12-13     Administrator       the first version
 */
#ifndef _NORFLASH_NORFLASH_H_
#define _NORFLASH_NORFLASH_H_
#define THREAD_NORFLASH_PRIORITY         13
#define THREAD_NORFLASH_STACK_SIZE       1024
#define THREAD_NORFLASH_TIMESLICE        10
#define BY25Q128AS_SPI_BUS_NAME        "spi1"    /* cubemx配置的SPI1*/
#define BY25Q128AS_SPI_DEVICE_NAME     "spi10"   /* SPI1总线上0号设备*/
//#define BY25Q128AS_SPI_DEVICE_NAME     "BY25Q128AS"   /* SPI1总线上0号设备*/
#define FLASH_DeviceID              0xAB
#define FLASH_ManufactDeviceID      0x90
#define CS_PIN   22   //PB6
int rt_hw_spi_flash_init(void);
#endif /* _NORFLASH_NORFLASH_H_ */

norflash.c文件内容如下
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2023-12-13     Administrator       the first version
 */
#include "spi_flash_sfud.h"
#include "stm32f1xx_hal.h"
#include "drv_spi.h"
#include "norflash.h"
static rt_thread_t norflash_thread = RT_NULL;
void cs_pin_init(void)
{
    __HAL_RCC_AFIO_CLK_ENABLE()
    ;
    __HAL_RCC_PWR_CLK_ENABLE()
    ;
    /*  NOJTAG: JTAG-DP Disabled and SW-DP Enabled  */
    __HAL_AFIO_REMAP_SWJ_NOJTAG()
    ;
    rt_pin_mode(CS_PIN, PIN_MODE_OUTPUT);
}
//* spi flash设备挂载(参考官方文档) */
int rt_hw_spi_flash_init(void)
{
    struct rt_spi_configuration cfg;
    struct rt_spi_device *spi_device = RT_NULL;
cs_pin_init();
    //分配内存空间
    spi_device = (struct rt_spi_device *) rt_malloc(sizeof(struct rt_spi_device));
    if (RT_NULL == spi_device)
    {
        rt_kprintf("Failed to malloc the spi device.");
        return -RT_ENOMEM;
    }
    if (RT_EOK != rt_hw_spi_device_attach(BY25Q128AS_SPI_BUS_NAME, BY25Q128AS_SPI_DEVICE_NAME, GPIOB, GPIO_PIN_6))
    {
        rt_kprintf("Failed to attach the spi device.");
        return -RT_ERROR;
    }
    //挂载 SPI FLASH BY25Q128AS
    if (RT_NULL == rt_sfud_flash_probe("BY25Q128AS", BY25Q128AS_SPI_DEVICE_NAME))
    {
        LOG_E("Failed to probe the %s.\n",BY25Q128AS_SPI_DEVICE_NAME);
        return -RT_ERROR;
    }
//    rt_hw_spi_device_attach(BY25Q128AS_SPI_BUS_NAME, BY25Q128AS_SPI_DEVICE_NAME, GPIOA, GPIO_PIN_15);
//    //配置 SPI 设备的传输参数
//    cfg.data_width = 8;
//    cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_3 | RT_SPI_MSB;
//    cfg.max_hz = 18 * 1000 * 1000; // 18M
//
//    rt_spi_configure(spi_device, &cfg);
//
//    //根据spi设备名称,查询挂载的SFUD Flash设备
//    spi_device = (struct rt_spi_device *) rt_device_find(BY25Q128AS_SPI_DEVICE_NAME);
//    if (RT_NULL == spi_device)
//    {
//        rt_kprintf("spi device find fail! norflash.c line = 55\n");
//    }
    return RT_EOK;
}
/* 导出组件初始化(或者在main初始化中调用) */
//INIT_COMPONENT_EXPORT(rt_hw_spi_flash_init);
增加h文件包含路径



在board.h中配置ON_CHIP_FLASH


 
运行效果




 
                     
                    
                 
                    
                 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号