本帖最后由 qjp1988113 于 2020-6-6 12:47 编辑
我看了下官方的FLASH读写程序感觉很单一,是对一个固定地址写数据读数据,不是很通用。
想起以前学STM32时,原子开发板FLASH例程不错,就拿来修修用。
由于不确定,MM32与STM32在FLASH这块到底有什么不同。
查看了中小容量的MM32L073的规格书,最大128页,每页1K字节:
查看了大容量的MM32F103XE的规格书,最大512页,每页同样1K字节:
而我记得ST的好像不一样,页数256以下的为1K,以上的为2K。MM32仅看了这2款,
不敢妄断就是1K,具体用的时候需要查看规格书。
单次读写操作都是2字节(16位),即半字,这点与ST的一致。
知道这个,下面就直接修改代码了:
#include "flash.h"
#include "led.h"
#include "uart.h"
#include "HAL_conf.h"
////每页大小为1024即1K字节 共128页
//#define FLASH_PAGE_SIZE ((uint16_t)0x400)
//#define BANK1_WRITE_START_ADDR ((uint32_t)0x08002800)
//#define BANK1_WRITE_END_ADDR ((uint32_t)0x08003200)
//uint32_t EraseCounter = 0x00, Address = 0x00;
//uint32_t Data = 0x12345679;
//uint32_t NbrOfPage = 0x00;
//volatile FLASH_Status FLASHStatus = FLASH_COMPLETE;
//读取指定地址的半字(16位数据)
//faddr:读地址(此地址必须为2的倍数!!)
//返回值:对应数据.
u16 FLASH_ReadHalfWord(u32 faddr)
{
return *(vu16*)faddr;
}
#if MM32_FLASH_WREN //如果使能了写
//不检查的写入
//WriteAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数
void FLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
{
u16 i;
for(i=0;i<NumToWrite;i++)
{
FLASH_ProgramHalfWord(WriteAddr,pBuffer);
WriteAddr+=2;//地址增加2.
}
}
//从指定地址开始写入指定长度的数据
//WriteAddr:起始地址(此地址必须为2的倍数!!)
//pBuffer:数据指针
//NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
//经查看,目前MM32的每页字节数好像没有大小页之分 固定在1K字节(不完全确定)
#if MM32_FLASH_SIZE<256
#define MM32_SECTOR_SIZE 1024 //字节 //MM32L073 128个页 每页1K字节
#else
//#define MM32_SECTOR_SIZE 2048//
#define MM32_SECTOR_SIZE 1024 //MM32的超过256的也是1K字节每页 这里仅查看了MM32F103XE的规格书
#endif
u16 MM32_FLASH_BUF[MM32_SECTOR_SIZE/2];//最多是1K字节
void FLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
{
u32 secpos; //扇区地址
u16 secoff; //扇区内偏移地址(16位字计算)
u16 secremain; //扇区内剩余地址(16位字计算)
u16 i;
u32 offaddr; //去掉0X08000000后的地址
if(WriteAddr<MM32_FLASH_BASE||(WriteAddr>=(MM32_FLASH_BASE+1024*MM32_FLASH_SIZE)))return;//非法地址
FLASH_Unlock(); //解锁
offaddr=WriteAddr-MM32_FLASH_BASE; //实际偏移地址.
secpos=offaddr/MM32_SECTOR_SIZE; //扇区地址 0~127 for STM32F103RBT6
secoff=(offaddr%MM32_SECTOR_SIZE)/2; //在扇区内的偏移(2个字节为基本单位.)
secremain=MM32_SECTOR_SIZE/2-secoff; //扇区剩余空间大小
if(NumToWrite<=secremain)secremain=NumToWrite;//不大于该扇区范围
while(1)
{
FLASH_Read(secpos*MM32_SECTOR_SIZE+MM32_FLASH_BASE,MM32_FLASH_BUF,MM32_SECTOR_SIZE/2);//读出整个扇区的内容
for(i=0;i<secremain;i++)//校验数据
{
if(MM32_FLASH_BUF[secoff+i]!=0XFFFF)break;//需要擦除
}
if(i<secremain)//需要擦除
{
FLASH_ErasePage(secpos*MM32_SECTOR_SIZE+MM32_FLASH_BASE);//擦除这个扇区
for(i=0;i<secremain;i++)//复制
{
MM32_FLASH_BUF[i+secoff]=pBuffer;
}
FLASH_Write_NoCheck(secpos*MM32_SECTOR_SIZE+MM32_FLASH_BASE,MM32_FLASH_BUF,MM32_SECTOR_SIZE/2);//写入整个扇区
}else FLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);//写已经擦除了的,直接写入扇区剩余区间.
if(NumToWrite==secremain)break;//写入结束了
else//写入未结束
{
secpos++; //扇区地址增1
secoff=0; //偏移位置为0
pBuffer+=secremain; //指针偏移
WriteAddr+=secremain; //写地址偏移
NumToWrite-=secremain; //字节(16位)数递减
if(NumToWrite>(MM32_SECTOR_SIZE/2))secremain=MM32_SECTOR_SIZE/2;//下一个扇区还是写不完
else secremain=NumToWrite;//下一个扇区可以写完了
}
};
FLASH_Lock();//上锁
}
#endif
//从指定地址开始读出指定长度的数据
//ReadAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数
void FLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)
{
u16 i;
for(i=0;i<NumToRead;i++)
{
pBuffer=FLASH_ReadHalfWord(ReadAddr);//读取2个字节.
ReadAddr+=2;//偏移2个字节.
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
//WriteAddr:起始地址
//WriteData:要写入的数据
void Test_Write(u32 WriteAddr,u16 WriteData)
{
FLASH_Write(WriteAddr,&WriteData,1);//写入一个字
}
///////////old code
//u8 FLASH_Program(void)
//{
//
// /* Porgram FLASH Bank1 ********************************************************/
// /* Unlock the Flash Bank1 Program Erase controller */
// FLASH_Unlock();
//
// /* Clear All pending flags */
// FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
//
// FLASH_ErasePage(BANK1_WRITE_START_ADDR);
//
// FLASH_ClearFlag(FLASH_FLAG_EOP );
//
// FLASHStatus = FLASH_ProgramWord(0x08001FFC, Data);
//
// FLASH_ClearFlag(FLASH_FLAG_EOP );
//
// FLASH_Lock();
//
// printf("%x\r\n",(*(__IO uint32_t*) 0x08001FFC));
//
// if((*(__IO uint32_t*) 0x08001FFC) != Data)
// {
// return 1;
// }
// return 0;
//}
主程序:
#include "delay.h"
#include "sys.h"
#include "led.h"
#include "uart.h"
#include "flash.h"
#include "stdio.h"
#include "string.h"
//要写入到STM32 FLASH的字符串数组
u8 TEXT_Buffer[]={"MM32 FLASH TEST"};
#define SIZE sizeof(TEXT_Buffer) //数组长度
#define FLASH_SAVE_ADDR 0X08009000 //设置FLASH 保存地址(必须为偶数,且其值要大于本代码所占用FLASH的大小+0X08000000)
/********************************************************************************************************
**函数信息 :main(void)
**功能描述 :
**输入参数 :无
**输出参数 :无
********************************************************************************************************/
int main(void)
{
u8 datatemp[SIZE];
u8 FlashOK**=0;
//下载程序前要选择全擦除
// u8 t;
delay_init();
LED_Init();
uart_initwBaudRate(115200);
// t=FLASH_Program();
FLASH_Write(FLASH_SAVE_ADDR,(u16*)TEXT_Buffer,SIZE);
delay_ms(200);
FLASH_Read(FLASH_SAVE_ADDR,(u16*)datatemp,SIZE);
delay_ms(200);
// while(1)
// {
printf("%s\r\n",datatemp);
delay_ms(2000);
// }
//
if(strstr((char*)datatemp,(char*)TEXT_Buffer)>0) FlashOK**=1;
else FlashOK**=0;
// while(1)
// {
// printf("%x\r\n",(*(__IO uint32_t*) 0x08001FFC));
// delay_ms(2000);
// }
if(FlashOK**>0)
while(1) //无限循环
{
printf("program ok\r\n");
LED1_TOGGLE();
LED2_TOGGLE();
LED3_TOGGLE();
LED4_TOGGLE();
delay_ms(1000);
}
else
while(1)
{
printf("program error\r\n");
delay_ms(1000);
}
}
调试下载,板上4LED闪烁,串口数据显示正常:
好了。就到这里了。
附上代码:
PROGRAM.rar
(2.2 MB)
|