STM32 連續操作flash

大容量每個扇區2048個字節 

本文需要注意的問題是就是防止棧溢出,

{

1、定義局部變量需要修改啓動文件棧的大小設置默認是0x400=1024個字節

2、定義一個全局變量

}

 

#ifndef __STMFLASH_H__
#define __STMFLASH_H__


#include "stm32f1xx_hal.h"

enum Flash{
 STM32_FLASH_BASE          =0x8000000,   //flash基地址
 STM32_FLASH_SIZE_K        =512,         // flash 大小KB
 STM32_FLASH_PAGE_SIZE     =2048,         // 刪去大小Byte
 PAGE_INT_SIZE             = 2048/4,
 PAGE_SHORT_SIZE             = 2048/2
};

uint32_t Read_4Byte_flash(uint32_t addr );                            
uint8_t Write_4Byte_flash(uint32_t addr ,uint32_t data);

uint8_t Write_N_4Byte_flash(uint32_t addr ,uint32_t *data,uint32_t len);

uint8_t __NeetErease(uint32_t start_addr ,uint32_t len);


#endif /* __STMFLASH_H__ */

 

#include "flash.h"
#include "string.h"
#include "stdlib.h"
uint32_t Read_4Byte_flash(uint32_t addr )
{
	uint32_t data;
	if(addr >STM32_FLASH_BASE)
		data= *(uint32_t*)addr;
	else
		data=0;
	return data;
		
}


uint8_t Write_4Byte_flash(uint32_t addr ,uint32_t data)
{
	uint16_t page=0;
	uint32_t _offset=0;
	FLASH_EraseInitTypeDef hflash;
	uint32_t error=0;
	uint32_t  flash_data[STM32_FLASH_PAGE_SIZE/4];
	uint16_t i=0;
	page=((uint32_t)addr-STM32_FLASH_BASE)/STM32_FLASH_PAGE_SIZE;
	_offset = (((uint32_t)addr-STM32_FLASH_BASE)%STM32_FLASH_PAGE_SIZE)/4;	
	if(Read_4Byte_flash(addr)!=0xffffffff)//需要先擦出再寫入
	{
		//擦除
		
		//讀取flash數據到緩衝
		for(;i<STM32_FLASH_PAGE_SIZE/4;i++)
		{
			flash_data[i]=Read_4Byte_flash(STM32_FLASH_BASE+page*STM32_FLASH_PAGE_SIZE+i*4);
		}
		//擦除頁
		hflash.TypeErase=FLASH_TYPEERASE_PAGES; //擦除類型 
		hflash.Banks = FLASH_BANK_1;
		hflash.PageAddress = STM32_FLASH_BASE+page*STM32_FLASH_PAGE_SIZE;//頁基地址
		hflash.NbPages = 1;//需要擦除的頁數
		HAL_FLASH_Unlock();
		if(HAL_FLASHEx_Erase(&hflash,&error)==HAL_OK)
		{
			flash_data[_offset] = data;
		}
		
		for(i=0;i<STM32_FLASH_PAGE_SIZE/4;i++)
		{
			HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,STM32_FLASH_BASE+page*STM32_FLASH_PAGE_SIZE+i*4,flash_data[i]);
		}
		HAL_FLASH_Lock();
	}
	else //直接可以編程寫入數據
	{
		HAL_FLASH_Unlock();
		HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,addr,data);
		HAL_FLASH_Lock();
	}
	
	return Read_4Byte_flash(addr)==data?1:0;
}
uint8_t __NeetErease(uint32_t start_addr ,uint32_t len)
{
	//該函數len必須是4的倍數 即 len%4==0
	volatile uint32_t i=0;
	for(;i<len;i++)
	{
		if(Read_4Byte_flash(start_addr)!=0xffffffff)
		{
			break;
		}
		start_addr+=4;
		
	}
	return i==len ? 0:1;
}
uint8_t _Erease_Flash(uint32_t base_addr)
{
	uint8_t flag=0;
	FLASH_EraseInitTypeDef hflash;
	//擦除頁
	hflash.TypeErase=FLASH_TYPEERASE_PAGES; //擦除類型 
	hflash.Banks = FLASH_BANK_1;
	hflash.PageAddress = base_addr;//頁基地址
	hflash.NbPages = 1;//需要擦除的頁數
	
	uint32_t error=0;
	if(HAL_FLASHEx_Erase(&hflash,&error)==HAL_OK)
	{
		flag=1;
	}
	return flag;
}
static uint32_t flash_data[STM32_FLASH_PAGE_SIZE/4] ;// __attribute__ ((at(0X20001000)));

uint8_t Write_One_Page_Data(uint32_t base_addr,uint32_t page_offst,uint32_t *data,volatile uint32_t erease_size)
{
	volatile uint8_t flag=0;
	uint16_t i=0;
	volatile uint32_t cur_addr=0;
//	uint32_t tempdata=0;
	//uint32_t flash_data[STM32_FLASH_PAGE_SIZE/4];
//	uint32_t *flash_data =(uint32_t*)malloc(erease_size);
//	if(flash_data==0)
//	{
//		flag=0;
//	}
	HAL_FLASH_Unlock();
	if(__NeetErease(base_addr,erease_size))
	{
		memset((void*)flash_data,0,STM32_FLASH_PAGE_SIZE);
		for(i=0;i<page_offst ;i++)
		{
			cur_addr = base_addr + i*4;
			flash_data[i]=Read_4Byte_flash(cur_addr);
		}
		_Erease_Flash(base_addr);
		//寫入數據
		for(i=page_offst;i<(erease_size+page_offst);i++)
		{
			flash_data[i]=*data;
			data++;
		}
		for(i=0;i<erease_size+page_offst;i++)
		{
			cur_addr = base_addr+i*4;
			if(cur_addr%4==0&& cur_addr >STM32_FLASH_BASE)
			{
				HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,cur_addr,flash_data[i]);
			}
		}
	}
	else //不需要擦除就從偏移開始
	{
		for(i=page_offst;i<erease_size+page_offst;i++)
		{
			cur_addr = base_addr+i*4;
			if(cur_addr%4==0&& cur_addr >STM32_FLASH_BASE)
			{
				HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,cur_addr,*data);
				data++;
			}
		}
	}
	
	
		
		
	HAL_FLASH_Lock();
	return flag;
}

/*
本函數操作的整型數據 4個字節;flash是以一個字節爲一個地址的
addr 起始地址
data 數據開始地址
surplus  整型數據長度1len=4Byte ;最大爲 	STM32_FLASH_PAGE_SIZE/4; 
*/
	
uint8_t Write_N_4Byte_flash(uint32_t addr ,uint32_t *data,uint32_t len)
{

	
	volatile uint32_t start_page=0;    //起始頁
	volatile uint32_t page_size=0;     //需要操作頁的大小
	volatile uint32_t _offset=0;       //頁操作頁碼的起始地址
	volatile uint32_t page_offset=0;   //頁偏移
	volatile uint32_t erease_size=0;  //本次操作頁可以使用的剩餘大小
	volatile uint32_t base_addr=0;    //本次操作頁的基地址		
	volatile uint32_t surplus=0;
	start_page=((uint32_t)addr-STM32_FLASH_BASE)/STM32_FLASH_PAGE_SIZE;
	_offset = (((uint32_t)addr-STM32_FLASH_BASE)%STM32_FLASH_PAGE_SIZE)/4;	
	
	if(PAGE_INT_SIZE-_offset>=len)
	{
		page_size=1;
		surplus=0;
	}
	else
	{
		page_size=1;
		surplus = len-(PAGE_INT_SIZE-_offset);
		page_size +=surplus/PAGE_INT_SIZE + surplus%PAGE_INT_SIZE>0?1:0;
		
	}
	surplus=len;
	for(page_offset=0;page_offset<page_size;page_offset++)
	{

		if(page_offset==0)
		{
			erease_size =(PAGE_INT_SIZE-_offset)<surplus ? (PAGE_INT_SIZE-_offset):surplus;
			base_addr = STM32_FLASH_BASE + start_page*STM32_FLASH_PAGE_SIZE;
			surplus = len-erease_size;
		}
		else
		{
			_offset=0;
			erease_size =surplus>PAGE_INT_SIZE ? PAGE_INT_SIZE:surplus;
			base_addr = STM32_FLASH_BASE + (start_page+page_offset)*STM32_FLASH_PAGE_SIZE;
			surplus = surplus-erease_size;
		}

		Write_One_Page_Data(base_addr,_offset,data,erease_size);	
		data+=erease_size;
			//_offset=0;
		
	}
	
	return 1;
}




 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章