- 本芯片包含 1 颗 64K / 32K Byte 容量的嵌入式 Flash 存储器,包括一个 128 / 64 sector 的 Main Array区域,一个 8 sector 的 NVR 区域。每个 sector 的容量为 512 Byte。Flash 的 Main Array 区域是给用户使用的, 可以存放用户开发的程序和数据。 NVR 区域中, 一个 sector 用于存放系统配置, 一个 sector用于存放选项字节,其余的 6 个 sector 用于存放系统的 ISP 程序。本模块支持对 Flash 存储器的擦除、编程以及读取操作。此外,本模块支持对 Flash 存储器擦写的保护,以及控制寄存器的写保护。
Main Array 区域用于存放用户的代码。
NVR 区域的 sector 0~5 这 6 个 sector 用于存放厂家提供的系统 ISP(在系统可编程)代码,用户可以通过 ISP 代码下载开发的应用程序,用户程序不能对 ISP 代码进行读取或者擦除操作。NVR 区域的Sector 6 是选项字节区域, 用于用户实现部分系统功能的配置。 NVR 区域的 Sector 7 是系统配置区,用于存放系统配置值。
本控制器支持对 Flash 的 byte(8bits)、 half-word(16bits)、 word(32bits)三种位宽读写操作。 注意, byte操作的地址必须按 byte 对齐,half-word 操作的目标地址必须按 half-word 对齐(地址最低位为 0),word 操作的目标地址必须按 word 对齐(地址最低两位为 0)。如果读写操作的地址没有按照位宽规定对齐,该操作无效,并且系统会进入 hard fault 出错中断。
/********************************************************************************
* @file bsp_flash.c
* @author jianqiang.xue
* @version V1.0.0
* @date 2021-04-15
* @brief flash读写操作
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include "RTE_Components.h"
#include CMSIS_device_header
#include "bsp_flash.h"
#include "sys_api.h"
/* Private Includes ----------------------------------------------------------*/
#include "business_gpio.h"
#include "business_function.h"
/* Private Define ------------------------------------------------------------*/
#define BSP_FLASH_PAGE_SIZE FLASH_PAGE_SIZE
/* Private Variables ---------------------------------------------------------*/
/* Public Function Prototypes ------------------------------------------------*/
/**
* @brief Flash erase page
* @param page_addr: flash addr example,0xFE00(63.5K)
* @param page_num: Number of pages to erase
* @retval status
*/
uint8_t bsp_flash_erase_page(uint32_t page_addr, uint32_t page_num)
{
FLASH_EraseInitTypeDef flash_erase_init_t;
uint32_t error_page; //记录错误的写入位置
// 一页 512 字节
if (page_addr % BSP_FLASH_PAGE_SIZE != 0)
{
page_addr -= (page_addr % BSP_FLASH_PAGE_SIZE);
}
if (page_addr < 1)
{
page_addr = 1;
}
flash_erase_init_t.TypeErase = FLASH_TYPEERASE_PAGES;
flash_erase_init_t.PageAddress = page_addr;
flash_erase_init_t.NbPages = page_num;
return HAL_FLASH_Erase(&flash_erase_init_t, &error_page);
}
/**
* @brief flash 读字节
* @note NULL
* @param addr: flash地址
* @retval 字节内容
*/
uint8_t bsp_flash_read_byte(uint32_t addr)
{
return (uint8_t)*(uint32_t *)(addr);
}
/**
* @brief flash 读多字节
* @note NULL
* @param addr: flash地址
* @param *data: 缓存buff地址
* @param len: 读取长度
* @retval 0--失败 1--成功
*/
bool bsp_flash_read_nbyte(uint32_t addr, uint8_t *data, uint32_t len)
{
uint32_t i;
if (len == 0)
{
return false;
}
for (i = 0; i < len; i++)
{
*(data + i) = bsp_flash_read_byte(addr + i);
}
return true;
}
/**
* @brief flash 读半字
* @note NULL
* @param addr: flash地址
* @retval 半字内容
*/
uint16_t bsp_flash_read_halfword(uint32_t addr)
{
return (uint16_t)*(uint32_t *)(addr);
}
/**
* @brief flash 读字
* @note NULL
* @param addr: flash地址
* @retval 字内容
*/
uint32_t bsp_flash_read_word(uint32_t addr)
{
return (uint32_t)*(uint32_t *)(addr);
}
/**
* @brief flash 写字节
* @note NULL
* @param addr: flash地址
* @param data: 字节
* @retval 0--失败 1--成功
*/
bool bsp_flash_write_byte(uint32_t addr, uint8_t data)
{
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, addr, data))
{
return false;
}
return true;
}
/**
* @brief flash 写字
* @note NULL
* @param addr: flash地址
* @param data: 字
* @retval 0--失败 1--成功
*/
bool bsp_flash_write_word(uint32_t addr, uint32_t data)
{
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr, data))
{
return false;
}
return true;
}
/**
* @brief flash 写多字节
* @note NULL
* @param addr: flash地址
* @param *data: 数据缓冲区
* @param len: 数据长度
* @retval 0--失败 1--成功
*/
bool bsp_flash_write_nbyte(uint32_t addr, uint8_t *data, uint32_t len)
{
uint32_t i;
if (len == 0)
{
return false;
}
for (i = 0; i < len; i++)
{
HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, (addr + i), *(data + i));
}
return true;
}
/**
* @brief 得到flash每页字节大小
* @note
* @retval
*/
uint16_t bsp_flash_get_page_size(void)
{
return BSP_FLASH_PAGE_SIZE;
}
/**
* @brief flash 写多字节(带关闭中断函数)
* @note NULL
* @param addr: flash地址
* @param *data: 数据缓冲区
* @param len: 数据长度
* @retval 0--失败 1--成功
*/
bool bsp_flash_write_nbyte_s(uint32_t addr, uint8_t *data, uint32_t len)
{
bool ret;
sys_disable_irq();
ret = bsp_flash_write_nbyte(addr, data, len);
sys_enable_irq();
return ret;
}
/**
* @brief flash搬运 (addr2 搬运到 addr1 ,并擦除addr1)
* @note NULL
* @param t_addr: 目标地址(addr1)
* @param s_addr: 欲搬地址(addr2)
* @param size: 字节大小
* @retval 0--失败 1--成功
*/
bool bsp_flash_carry(uint32_t t_addr, uint32_t s_addr, uint32_t size)
{
bool ret = true;
uint32_t word_len;
uint32_t page_len;
uint32_t i;
word_len = (size / sizeof(uint32_t));
page_len = (size % BSP_FLASH_PAGE_SIZE) == 0 ?
(size / BSP_FLASH_PAGE_SIZE) : (size / BSP_FLASH_PAGE_SIZE) + 1;
for (i = 0; i < page_len; i++)
{
bsp_flash_erase_page(t_addr + i * BSP_FLASH_PAGE_SIZE, 1);
}
for (i = 0; i < word_len; i++)
{
ret = bsp_flash_write_word(t_addr + i * sizeof(uint32_t),
bsp_flash_read_word(s_addr + i * sizeof(uint32_t)));
if (ret == false)
{
break;
}
}
if (ret == true)
{
for (i = 0; i < page_len; i++)
{
bsp_flash_erase_page(s_addr + i * BSP_FLASH_PAGE_SIZE, 1);
}
}
return ret;
}
/********************************************************************************
* @file bsp_flash.h
* @author jianqiang.xue
* @version V1.0.0
* @date 2021-04-03
* @brief flash操作
********************************************************************************/
#ifndef __BSP_FLASH_H
#define __BSP_FLASH_H
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
/* Public struct ------------------------------------------------------------*/
typedef struct
{
uint32_t usercfg0;
uint32_t usercfg1;
uint32_t usercfg2;
uint32_t boot_state; // 0--run app 1--in dfu 2--move ota in app
uint32_t boot_run_tick; // 掉电次数
uint32_t boot_carry_size; // 需要复制的字节数量
uint32_t app_crc; // app 运行前先crc校验,防止app损坏
uint32_t chip_lock; // 任意值--锁住swo XXXX--特殊码解锁swo
} option_bytes_t;
typedef struct
{
uint32_t boot_state; // 0--run app 1--in dfu 2--move ota in app
uint32_t boot_run_tick; // 掉电次数
uint32_t boot_carry_size; // 需要复制的字节数量
uint32_t app_crc; // app 运行前先crc校验,防止app损坏
uint32_t chip_lock; // 任意值--锁住swo XXXX--特殊码解锁swo
} boot_info_t;
/* Public Function Prototypes ------------------------------------------------*/
uint8_t bsp_flash_erase_page(uint32_t page_addr, uint32_t page_num);
uint8_t bsp_flash_read_byte(uint32_t addr);
bool bsp_flash_read_nbyte(uint32_t addr, uint8_t *data, uint32_t len);
uint16_t bsp_flash_read_halfword(uint32_t addr);
uint32_t bsp_flash_read_word(uint32_t addr);
bool bsp_flash_write_byte(uint32_t addr, uint8_t data);
bool bsp_flash_write_nbyte(uint32_t addr, uint8_t *data, uint32_t len);
bool bsp_flash_write_nbyte_s(uint32_t addr, uint8_t *data, uint32_t len);
bool bsp_flash_write_word(uint32_t addr, uint32_t data);
uint16_t bsp_flash_get_page_size(void);
bool bsp_flash_carry(uint32_t t_addr, uint32_t s_addr, uint32_t size);
#endif