STM32F40–Flash读写操作
一般在代码调节参数时,比如在调PID的时候,如果每次改参数就重新烧写代码就十分的麻烦。我们可以利用stm32内部flash的读写功能,实现数据保存。
可以从数据手册中查找Flash内存地址 可以看到F4的主存储器基地址位0x0800 0000,有12个扇区,我们可以在头文件中宏定义这些扇区。
flash.h
#ifndef _flash_H
#define _flash_H
#include "stm32f4xx.h"
#define TEST_ERROR -1
#define TEST_SUCCESS 0
#define DATA_FLASH_SAVE_NUM 2 //存储数据个数
#define FLASH_SAVE_ADDR ADDR_FLASH_SECTOR_4 //扇区有64kb的大小 一般寸几个数据已经足够
//FLASH 扇区的起始地址
#define ADDR_FLASH_SECTOR_0 ((u32)0x08000000) //扇区0起始地址, 16 Kbytes
#define ADDR_FLASH_SECTOR_1 ((u32)0x08004000) //扇区1起始地址, 16 Kbytes
#define ADDR_FLASH_SECTOR_2 ((u32)0x08008000) //扇区2起始地址, 16 Kbytes
#define ADDR_FLASH_SECTOR_3 ((u32)0x0800C000) //扇区3起始地址, 16 Kbytes
#define ADDR_FLASH_SECTOR_4 ((u32)0x08010000) //扇区4起始地址, 64 Kbytes
#define ADDR_FLASH_SECTOR_5 ((u32)0x08020000) //扇区5起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_6 ((u32)0x08040000) //扇区6起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_7 ((u32)0x08060000) //扇区7起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_8 ((u32)0x08080000) //扇区8起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_9 ((u32)0x080A0000) //扇区9起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_10 ((u32)0x080C0000) //扇区10起始地址,128 Kbytes
#define ADDR_FLASH_SECTOR_11 ((u32)0x080E0000) //扇区11起始地址,128 Kbytes
uint16_t STMFLASH_GetFlashSector(u32 addr);
void write_to_flash(void);
void read_from_flash(void);
void read_flash(uint16_t *FlashReadBuf);
int write_flash(uint16_t *FlashWriteBuf);
#endif
flash.c
#include "flash.h"
uint16_t write_data[DATA_FLASH_SAVE_NUM];
uint16_t read_data[DATA_FLASH_SAVE_NUM];
//通过地址获取扇区位置
uint16_t STMFLASH_GetFlashSector(u32 addr)
{
if(addr<ADDR_FLASH_SECTOR_1)return FLASH_Sector_0;
else if(addr<ADDR_FLASH_SECTOR_2)return FLASH_Sector_1;
else if(addr<ADDR_FLASH_SECTOR_3)return FLASH_Sector_2;
else if(addr<ADDR_FLASH_SECTOR_4)return FLASH_Sector_3;
else if(addr<ADDR_FLASH_SECTOR_5)return FLASH_Sector_4;
else if(addr<ADDR_FLASH_SECTOR_6)return FLASH_Sector_5;
else if(addr<ADDR_FLASH_SECTOR_7)return FLASH_Sector_6;
else if(addr<ADDR_FLASH_SECTOR_8)return FLASH_Sector_7;
else if(addr<ADDR_FLASH_SECTOR_9)return FLASH_Sector_8;
else if(addr<ADDR_FLASH_SECTOR_10)return FLASH_Sector_9;
else if(addr<ADDR_FLASH_SECTOR_11)return FLASH_Sector_10;
return FLASH_Sector_11;
}
//将数据写入内存 16位数据
int write_flash(uint16_t *FlashWriteBuf)
{
uint32_t StartAddr;
StartAddr = FLASH_SAVE_ADDR;
FLASH_Unlock(); //解锁
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
if (FLASH_COMPLETE != FLASH_EraseSector(STMFLASH_GetFlashSector(StartAddr),VoltageRange_2)) //擦除扇区内容
{
return TEST_ERROR;
}
for (int i = 0; i < DATA_FLASH_SAVE_NUM; i++)
{
if (FLASH_COMPLETE != FLASH_ProgramHalfWord(StartAddr, FlashWriteBuf[i])) //写入16位数据
{
return TEST_ERROR;
}
StartAddr += 2; //16位数据偏移两个位置
}
FLASH_Lock(); //上锁
return TEST_SUCCESS;
}
//从内存读数据 16位数据
void read_flash(uint16_t *FlashReadBuf)
{
uint32_t StartAddr = FLASH_SAVE_ADDR;
for (int i = 0; i < DATA_FLASH_SAVE_NUM; i++)
{
FlashReadBuf[i] = *(__IO uint16_t*)StartAddr;
StartAddr += 2;
}
}
void write_to_flash(void)
{
memset(write_data, 0, sizeof(write_data));
/*
//这里就可以写入一些参数 如kp、ki
write_data[0] = kp;
write_data[1] = ki;
*/
if(TEST_SUCCESS!=write_flash(write_data))
return; //写入错误
}
void read_from_flash(void)
{
memset(read_data, 0, sizeof(read_data));
read_flash(read_data);
/*
//这里读取数据
kp = read_data[0];
ki = read_data[1];
*/
}
main.c
#include "stm32f4xx.h"
#include "delay.h"
#include "flash.h"
int main(void)
{
delay_init(84);
LED_Init();
read_from_flash(); //这个函数必须在执行一次 write_to_flash() 后在加入这行,否则可能读取到内存一些不正常的数据
while (1)
{
//...
write_to_flash(); //可在修改完参数后执行
//...
}
}
//每次重新启动32后,参数数据就是从内存读取的数据
|