STM32 Flash Learning (3)

hardware design

When starting up, display some prompt information first, and then detect two buttons in the main loop.
One of the keys WK_UP is used to perform the operation of writing to FLASH, and the other is used to perform the read operation according to KEY0.

software design

Added two files stmflash.c and stmflash.h.

#include "stmflash.h"
#include "delay.h"
#include "usart.h"

extern void FLASH_PageErase(uint32_t PageAddress);

//读取指定地址的半字(16位)
u16 STMFLASH_ReadHalfWord(u32 faddr)
{
    
    
	return *(vu16*)faddr;
}

//不检查的写入
void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
{
    
    
	u16 i;
	for(i=0; i<NumToWrite; i++){
    
    
			HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,WriteAddr,pBuffer[i]);
			WriteAddr+=2;//地址增加 2.
	}
}

//从指定地址开始写入指定长度的数据
#if STM32_FLASH_SIZE<256
#define STM_SECTOR_SIZE 1024 //字节
#else
#define STM_SECTOR_SIZE 2048 //字节

u16 STMFLASH_BUF[STM_VECTOR_SIZE/2];

void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
{
    
    
	u32 secpos; //扇区地址
	u16 secoff;//扇区内偏移地址(16位字计算)
	u16 secremain; //扇内剩余地址(16位字计算)
	u16 i;
	u32 offaddr; //去掉0x08000000后的地址

	if(WriteAddr<STN32_FLASH_BASE||(WriteAdd>=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE))) return;
	HAL_FLASH_Unlock(); //解锁
	offaddr = WriteAddr - STM32_FLASH_BASE;
	secpos = offaddr/SIM_SECTOR_SIZE;
	secoff = (offaddr%STM_SECTOR_SIZE)/2;
	secremain = SIM_SECTOR_SIZE/2 - secoff;
	if(NumToWrite <= secremain) secremain = NumToWrite;
	while(1) 
	{
    
    	
		STMFLASH_Read(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//读出整个扇区的内容
		for(i=0;i<secremain;i++)	//校验数据
		{
    
    
			if(STMFLASH_BUF[secoff+i]!=0XFFFF)break;//需要擦除  	  
		}
		if(i<secremain)				//需要擦除
		{
    
    
			FLASH_PageErase(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);	//擦除这个扇区
			FLASH_WaitForLastOperation(FLASH_WAITETIME);            	//等待上次操作完成
			CLEAR_BIT(FLASH->CR, FLASH_CR_PER);							//清除CR寄存器的PER位,此操作应该在FLASH_PageErase()中完成!
																		//但是HAL库里面并没有做,应该是HAL库bug!
			for(i=0;i<secremain;i++)//复制
			{
    
    
				STMFLASH_BUF[i+secoff]=pBuffer[i];	  
			}
			STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//写入整个扇区  
		}else 
		{
    
    
			FLASH_WaitForLastOperation(FLASH_WAITETIME);       	//等待上次操作完成
			STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);//写已经擦除了的,直接写入扇区剩余区间. 
		}
		if(NumToWrite==secremain)break;//写入结束了
		else//写入未结束
		{
    
    
			secpos++;				//扇区地址增1
			secoff=0;				//偏移位置为0 	 
		   	pBuffer+=secremain;  	//指针偏移
			WriteAddr+=secremain*2;	//写地址偏移(16位数据地址,需要*2)	   
		   	NumToWrite-=secremain;	//字节(16位)数递减
			if(NumToWrite>(STM_SECTOR_SIZE/2))secremain=STM_SECTOR_SIZE/2;//下一个扇区还是写不完
			else secremain=NumToWrite;//下一个扇区可以写完了
		}	 
	};	
	HAL_FLASH_Lock();		//上锁
}
#endif

STMFLASH_Write (u32 WriteAddr, u16 *pBuffer, u16 NumToWrite)
parameters:

  • WriteAddr: start address (must be a multiple of 2)
  • pBuffer: data pointer, pointing to the data buffer to be written
  • NumToWrite: 16-bit data volume (in half-word units, that is, two bytes)

Function:
This function is used to write the data of the specified length starting from the specified address into the flash memory.
First calculate the sector address where the target address is located and the offset address within the sector.
Then, read out the content of the entire sector from Flash, and check whether the erase operation needs to be performed.
If a sector needs to be erased, the erase operation is performed and the data is copied to the buffer.
Finally, use the STMFLASH_Write_NoCheck function to write the data of the entire sector into Flash.
If the erase operation is not required, directly use the STMFLASH_Write_NoCheck function to write data to the remaining space of the sector.

This function has requirements for the write address, and the following two points must be guaranteed:

  1. The address must be outside the user code area.
  2. The address must be a multiple of 2.

Condition 1, if the user code is erased, the running program will be disabled, and the computer may crash. Condition 2 is a requirement of STM32 FLASH. 16 bits must be written each time. If the written address is not a multiple of 2, the written data may be incorrect.

//从指定地址开始读出指定长度的数据
void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)
{
    
    
	u16 i;
	for(i=0; i<NumToRead; i++)
	{
    
    
		pBuffer[i] = STMFLASH_ReadHalfWord(ReadAddr); //读取2个字节
		ReadAddr += 2;
	}
}

//测试用
void Test_Write(u32 WriteAddr,u16 WriteData)
{
    
    
	STMFLASH_Write(WriteAddr, &WriteData, 1);//写入1个字
}

main.c file

#include "stmflash.h"

//要写入到STM32_FLASH的字符串数组
const u8 TEXT_Buffer[] = {
    
    "STM32 FLASH TEST"};
#define SIZE sizeof(TEXT_Buffer)
#define FLASH_SAVE_ADDR 0x08020000 //设置FLASH保存地址必须为偶数

int main(void)
{
    
    
	u8 key = 0;
	u8 datatemp[SIZE];

	HAL_Init();                    	 	//初始化HAL库    
    Stm32_Clock_Init(RCC_PLL_MUL9);   	//设置时钟,72M
	delay_init(72);               		//初始化延时函数
	uart_init(115200);					//初始化串口
	LED_Init();							//初始化LED	
	KEY_Init();							//初始化按键

	while(1)
	{
    
    
		key = KEY_SCAN(0);
		if(key = KEY1_PRES)
		{
    
    
			STMFLASH_Write(FLASH_SAVE_ADDR,(u16*)TEXT_Buffer,SIZE);
		}
		if(key==KEY0_PRES)	//KEY0按下,读取字符串并显示
		{
    
    
			STMFLASH_Read(FLASH_SAVE_ADDR,(u16*)datatemp,SIZE);
		}
	}
}

Guess you like

Origin blog.csdn.net/Caramel_biscuit/article/details/131933775