一、工程创建
打开STM32CubeMX,配置RCC,将PC13设置为GPIO_Output
配置系统时钟树
调整堆栈大小
二、代码配置
将flash.c和flash.h加入到工程中
flash.h
#ifndef _flash_H_
#define _flash_H_
#include "stm32f1xx_hal.h"
/*********************************************************************/
// 变量定义
/*********************************************************************/
//-- 用途划分
// 0x0800FC00-0x0800FFFF -- 使用最后4k 个字节用来存放电机信息
#define FMC_FLASH_BASE 0x08000000 // FLASH的起始地址
#define APP_MAX_SIZE 0x00010000 //
#define FMC_FLASH_END 0x08010000 // FLASH的结束地址 256
#define DEVICE_INFO_ADDRESS 0x0800C000 //(STM32_FLASH_END - DEVICE_INFO_SIZE) // 设备信息起始地址
#define DEVICE_LOG_ADDRESS 0x0800E000 //(STM32_FLASH_END - 2*DEVICE_INFO_SIZE) // 设备日志起始地址
#define FMC_FLASH_SIZE 64 // 定义Flash大小,单位KB
#if FMC_FLASH_SIZE < 256
#define FMC_SECTOR_SIZE 1024 // 字节
#define MOD_SECTOR_SIZE 0X3FF
#define PAGE_COUNT_BY16 512
#else
#define FMC_SECTOR_SIZE 2048
#define MOD_SECTOR_SIZE 0X7FF
#define PAGE_COUNT_BY16 1024
#endif
/*********************************************************************/
// 函数声明
/*********************************************************************/
void FlashWriteBuff( const uint32_t destination_address, uint8_t *const buffer,uint32_t length );
void FlashReadBuff(const uint32_t source_address,uint8_t *const buffer,uint16_t length);
#endif
flash.c
#include "flash.h"
// 不检查的写入
// WriteAddr:起始地址
// pBuffer: 数据指针
// NumToWrite:字节数数
void FlashWriteNoCheck( uint32_t WriteAddr,uint8_t *pBuffer,uint16_t NumToWrite )
{
uint16_t i;
for( i=0; i<NumToWrite; i+=4 )
{
while( HAL_OK != HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, WriteAddr+i,*(uint32_t *)(pBuffer+i) ) );
}
}
extern void FLASH_PageErase(uint32_t PageAddress);
void FlashWriteBuff( const uint32_t destination_address, uint8_t *const buffer,uint32_t length )
{
uint16_t i;
uint8_t FlashBuff[FMC_SECTOR_SIZE];
uint32_t StartAddress = destination_address - destination_address%FMC_SECTOR_SIZE;
uint16_t Offset = destination_address - StartAddress;
uint8_t *pBuf = buffer;
uint32_t remaindNum = length;
HAL_StatusTypeDef status = HAL_ERROR;
// 地址检查
if( (destination_address < FMC_FLASH_BASE) || ( destination_address + length >= FMC_FLASH_END) || (length <= 0) )
return;
HAL_FLASH_Unlock(); // 解锁
do
{
// 读出一页数据
for(i=0; i < FMC_SECTOR_SIZE; i += 4 )
*(uint32_t *)(FlashBuff+i) = *(uint32_t *)(StartAddress+i);
// 修改要改入的数据
for ( i=0; (i+Offset)<FMC_SECTOR_SIZE && i< remaindNum; i++ )
*(FlashBuff+Offset+i) = *(pBuf+i);
// 擦除一ROW数据
FLASH_PageErase( StartAddress );
// HAL库 FLASH_PageErase有BUFF,要加上下面三行代码
while( status != HAL_OK )
status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
CLEAR_BIT(FLASH->CR, FLASH_CR_PER);
// 写入数据
FlashWriteNoCheck( StartAddress,FlashBuff,FMC_SECTOR_SIZE );
// 为下一页做准备
StartAddress += FMC_SECTOR_SIZE;
remaindNum -= i;
pBuf += i;
Offset = 0;
} while( remaindNum > 0 );
HAL_FLASH_Lock(); // 上锁
}
// 从FLASH中读指定长度数据
void FlashReadBuff(const uint32_t source_address,uint8_t *const buffer,uint16_t length)
{
uint16_t i;
uint8_t Offset = 0;
uint32_t StartAddress = source_address;
uint16_t data;
// 地址检测
if( source_address + length > FMC_FLASH_END ) return;
// 如果没有对16齐
if( source_address & 1 )
{
Offset = 1;
StartAddress = source_address-1;
}
// flash的操作要求16对齐 最小读写操作16个比特
if ( Offset )
{
data = *(uint16_t *)(StartAddress);
buffer[0] = data >> 8;
StartAddress += 2;
}
for ( i = 0; i < (length-Offset); i += 2)
{
data = *(uint16_t *)(StartAddress+i);
buffer[i+Offset] = (data & 0xFF);
if ( (i+Offset) < (length - 1) )
buffer[i + Offset + 1] = (data >> 8);
}
}
将文件加入到工程后,在main.c中加入
#include "flash.h"
uint8_t i;
uint8_t FlashTest[] = "Hello This is ZhangShiSan Flash Test DEMO";
/****************************************/
FlashWriteBuff( DEVICE_INFO_ADDRESS, FlashTest,sizeof(FlashTest) ); // 写入数据到Flash
for(i=0;i<255;i++)
FlashWBuff[i] = i;
FlashWriteBuff(DEVICE_INFO_ADDRESS+ sizeof(FlashTest),FlashWBuff,255); // 写入数据到Flash
FlashReadBuff(DEVICE_INFO_ADDRESS+ sizeof(FlashTest),FlashRBuff,255); // 从Flash中读取数
uint8_t FlashWBuff [255];
uint8_t FlashRBuff [255];
三、实验结果
编译成功后将程序通过ST-link下载到板子中
进入调试界面,打开Memory1窗口
打开watch1窗口并勾选自动变量更新
通过Enter expression将FlashWBuff和FlashRBuff加入到观察窗口
在memory中输入0x0800c000,回车
F5运行,我们可以看到FlashRBuff里的内容变得和FlashWBuff里的一样了,表示我们写入flash成功
接着查看memory,FlashTest的内容写入成功
四、总结
本次实验进行了简单的FLASH读写
五、参考文献
https://blog.csdn.net/zhanglifu3601881/article/details/96632971