大容量每个扇区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; }
