清丰网站建设,大连模板开发建站,公司网络推广排名定制,中国制造网外贸网站目录 嵌入式 Flash大概了解
数据手册2.3.2章节
结构图f407
等待周期 Flash 控制寄存器解锁
编程/擦除并行位数 擦除 编程#xff08;写入#xff09;
工程程序 嵌入式 Flash大概了解 可以从flash区域启动程序#xff1b;大概是程序区可以在flash#xff0c;所以是可以…目录 嵌入式 Flash大概了解
数据手册2.3.2章节
结构图f407
等待周期 Flash 控制寄存器解锁
编程/擦除并行位数 擦除 编程写入
工程程序 嵌入式 Flash大概了解 可以从flash区域启动程序大概是程序区可以在flash所以是可以直接读取数据的 数据手册2.3.2章节
Flash 接口可管理 CPU 通过 AHB I-Code 和 D-Code 对 Flash 进行的访问。该接口可针对 Flash 执行擦除和编程操作并实施读写保护机制。Flash 接口通过指令预取和缓存机制加速 代码执行。 Flash 结构如下 ● 主存储器块分为多个扇区。 ● 系统存储器器件在系统存储器自举模式下从该存储器启动 ● 512 OTP一次性可编程字节用于存储用户数据。 ● 选项字节用于配置读写保护、BOR 级别、软件/硬件看门狗以及器件处于待机或停止 模式下的复位。 可以知道flash是存储程序用的可以用来做主存储 结构图f407 主存储器大概有12个扇区主要的数据程序都在这里 当使用时要注意程序的大小在程序大小之外使用。不然会影响擦除原来存储的程序造成死机 等待周期
为了准确读取 Flash 数据必须根据 CPU 时钟 (HCLK) 频率和器件电源电压在 Flash 存取控 制寄存器 (FLASH_ACR) 中正确地编程等待周期数 (LATENCY) 所以一句话读取数据需要时间并且根据HCLK和电压范围得到的CPU周期 168M 的HCLK 和 3.3V的电压 可以知道等待周期大概6个CPU时间 Flash 控制寄存器解锁 复位后Flash 控制寄存器 (FLASH_CR) 不允许执行写操作以防因电气干扰等原因出现对 Flash 的意外操作。此寄存器的解锁顺序如下 1. 在 Flash 密钥寄存器 (FLASH_KEYR) 中写入 KEY1 0x45670123 2. 在 Flash 密钥寄存器 (FLASH_KEYR) 中写入 KEY2 0xCDEF89AB 如果顺序出现错误将返回总线错误并锁定 FLASH_CR 寄存器直到下一次复位。 所以操作配置的时候必须要先解锁 编程/擦除并行位数 通过 FLASH_CR 寄存器中的 PSIZE 字段配置并行位数。并行位数表示每次对 Flash 进行写 操作时将编程的字节数。 可以从手册知道位宽128,即32字节所以配置应该32字节即可 擦除
Flash 擦除操作可针对扇区或整个 Flash批量擦除执行。执行批量擦除时不会影响 OTP 扇区或配置扇区。 扇区擦除 扇区擦除的具体步骤如下 1. 检查 FLASH_SR 寄存器中的 BSY 位以确认当前未执行任何 Flash 操作 2. 在 FLASH_CR 寄存器中将 SER 位置 1并从主存储块的 12 个 (STM32F405xx/07xx 和 STM32F415xx/17xx) 或 24 个 (STM32F42xxx 和 STM32F43xxx) 扇区中选择要擦除 的扇区 (SNB) 3. 将 FLASH_CR 寄存器中的 STRT 位置 1 4. 等待 BSY 位清零 编程写入 标准编程 Flash 编程顺序如下 1. 检查 FLASH_SR 中的 BSY 位以确认当前未执行任何主要 Flash 操作。 2. 将 FLASH_CR 寄存器中的 PG 位置 1。 3. 针对所需存储器地址主存储器块或 OTP 区域内执行数据写入操作 — 并行位数为 x8 时按字节写入 — 并行位数为 x16 时按半字写入 — 并行位数为 x32 时按字写入 — 并行位数为 x64 时按双字写入 4. 等待 BSY 位清零。 工程程序
不懂地址谨慎使用会破坏原来的程序
文件C
#includeflash_eeprom.h/***** 读取字 *******/uint32_t flash_read_word( uint32_t *addr )
{return *addr;
}uint32_t flash_read( uint32_t addr,uint32_t *buff ,uint32_t cnt )
{uint32_t i;for(i0 ;icnt ;i){*buffflash_read_word( (uint32_t *)addr );addr4;}}
/*用地址来确定是flash的哪一个扇区addr flash的地址*/uint16_t flash_get_sector_x( uint32_t addr )
{if(addrFLASH_SECTOR1_ADDR ) return FLASH_Sector_0;else if( addrFLASH_SECTOR2_ADDR ) return FLASH_Sector_1;else if( addrFLASH_SECTOR3_ADDR ) return FLASH_Sector_2;else if( addrFLASH_SECTOR4_ADDR ) return FLASH_Sector_3;else if( addrFLASH_SECTOR5_ADDR ) return FLASH_Sector_4;else if( addrFLASH_SECTOR6_ADDR ) return FLASH_Sector_5;else if( addrFLASH_SECTOR7_ADDR ) return FLASH_Sector_6;else if( addrFLASH_SECTOR8_ADDR ) return FLASH_Sector_7;else if( addrFLASH_SECTOR9_ADDR ) return FLASH_Sector_8;else if( addrFLASH_SECTOR10_ADDR ) return FLASH_Sector_9;else if( addrFLASH_SECTOR11_ADDR ) return FLASH_Sector_10;else return FLASH_Sector_11;}void flash_write( uint32_t addr ,uint32_t *buff ,uint32_t cnt )
{FLASH_Status stateFLASH_COMPLETE; uint32_t start_addraddr;uint32_t end_addrstart_addrcnt*4;FLASH_Unlock();//解锁FLASH_DataCacheCmd(DISABLE);//禁止数据缓存if( (addr FLASH_START_ADDR addr FLASH_END_ADDR ) || addr%4 !0 ) return; //确保地址在主储存区域while( start_addr end_addr){if( flash_read_word( (uint32_t * )start_addr ) ! 0xffffffff) {stateFLASH_EraseSector( flash_get_sector_x(start_addr), VoltageRange_3 );//擦除需要电压相关得到周期时间if( state ! FLASH_COMPLETE ){break; }}start_addr4;}start_addraddr;if(state FLASH_COMPLETE){while(start_addr end_addr)//写数据进flash{if(FLASH_ProgramWord( start_addr , *buff) !FLASH_COMPLETE ){break;} start_addr4; }}FLASH_DataCacheCmd(ENABLE);//使能数据缓存FLASH_Lock();//锁上
}
文件H
#ifndef FLASH_EEPROM_H
#define FLASH_EEPROM_H#include main.h#define FLASH_START_ADDR 0x08000000#define FLASH_SECTOR0_ADDR 0X08000000 //16k
#define FLASH_SECTOR1_ADDR 0X08004000 //16k
#define FLASH_SECTOR2_ADDR 0X08008000 //16k
#define FLASH_SECTOR3_ADDR 0X0800C000 //16k#define FLASH_SECTOR4_ADDR 0X08010000 //64k#define FLASH_SECTOR5_ADDR 0X08020000 //128k
#define FLASH_SECTOR6_ADDR 0X08040000 //128k
#define FLASH_SECTOR7_ADDR 0X08060000 //128k
#define FLASH_SECTOR8_ADDR 0X08080000 //128k
#define FLASH_SECTOR9_ADDR 0X080A0000 //128k
#define FLASH_SECTOR10_ADDR 0X080C0000 //128k
#define FLASH_SECTOR11_ADDR 0X080E0000 //128k#define FLASH_END_ADDR 0x080EFFFF
#define FLASH_USER_ADDR 0X080E0000 //uint32_t flash_read( uint32_t addr,uint32_t *buff ,uint32_t cnt );
void flash_write( uint32_t addr ,uint32_t *buff ,uint32_t cnt );#endif
主 #include main.h
#define tmep_len 30
uint8_t temp_buf[tmep_len]{0};void test();
uint8_t *mian_temp;
double time_us;
int main(void)
{ u8 key,flag ,i,n5; //保存键值static bool cnt;
// delay_init(168); //初始化延时函数software_times_base_init( 168 );uart_init(115200);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);LED_Init(); //初始化LED端口 BEEP_Init(); //初始化蜂鸣器端口KEY_Init(); //初始化与按键连接的硬件接口LED1!LED1;LED0!LED0;while(1){keyKEY_Scan(0);if(key1){mian_temptemp_buf;memset( mian_temp, 0 ,tmep_len );flash_read( FLASH_USER_ADDR,(uint32_t *)mian_temp ,tmep_len );//读取 tmep_len 长的数据 并且要地址在程序区之外for(i0;i tmep_len;i){printf( %d ,mian_temp[i]);}printf( \r\n);}if(key2){mian_temptemp_buf;memset( mian_temp, n ,tmep_len );flash_write( FLASH_USER_ADDR ,(uint32_t *)mian_temp ,tmep_len );//写入 tmep_len 长的数据 并且要地址在程序区之外mian_temptemp_buf;memset( mian_temp, 0 ,tmep_len );flash_read( FLASH_USER_ADDR,(uint32_t *)mian_temp ,tmep_len );for(i0;i tmep_len;i){printf( %d ,mian_temp[i]);}printf( \r\n);}}}