使用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

 

 运行效果

 

posted on 2024-04-23 11:07  liusheldon  阅读(28)  评论(0编辑  收藏  举报