网站二级栏目,掌握商务网站建设策略,开放平台设计,怎么做才能提高网站权重以这篇未开始我将进行stm32学习整理为期一个月左右完成stm32知识学习整理内容顺序没有一定之规写到哪想到哪想到哪写到哪#xff0c;主要是扫除自己知识上的盲区完成一些基本外设操作。
以stm32f07为例子进行flash读写操作
stm32flash简介
参考资料正点原子和野火开发手册 …以这篇未开始我将进行stm32学习整理为期一个月左右完成stm32知识学习整理内容顺序没有一定之规写到哪想到哪想到哪写到哪主要是扫除自己知识上的盲区完成一些基本外设操作。
以stm32f07为例子进行flash读写操作
stm32flash简介
参考资料正点原子和野火开发手册 stm32f4中文参考手册和datasheet
Flash 接口可管理 CPU 通过 **AHB I-Code(指令指令总线) 和 D-Code (数据总线)**对 Flash 进行的访问。该接口可针对 Flash 执行擦除和编程操作并实施读写保护机制。Flash 接口通过指令预取和缓存机制加速 代码执行。 关于这两条总线先不细说参考链接 AHB I-Code(指令指令总线) 和 D-Code (数据总线)请参考 Cortex-M3 I-Code,D-Code,系统总线及其他总线接口
主要特性
● Flash 读操作 ● Flash 编程/擦除操作 ● 读/写保护 ● I-Code 上的预取操作 ● I-Code 上的 64 个缓存128 位宽 ● D-Code 上的 8 个缓存128 位宽
结构框图 Flash 具有以下主要特性 ● 对于 STM32F40x 和 STM32F41x容量高达 1 MB对于 STM32F42x 和 STM32F43x 容量高达 2 MB ● 128 位宽数据读取 ● 字节、半字、字和双字数据写入 ● 扇区擦除与全部擦除 ● 存储器组织结构 Flash 结构如下 — 主存储器块分为 4 个 16 KB 扇区、1 个 64 KB 扇区和 7 个 128 KB 扇区 — 系统存储器器件在系统存储器自举模式下从该存储器启动 — 512 字节 OTP一次性可编程用于存储用户数据 OTP 区域还有 16 个额外字节用于锁定对应的 OTP 数据块。 — 选项字节用于配置读写保护、BOR 级别、软件/硬件看门狗以及器件处于待机或 停止模式下的复位。 ● 低功耗模式有关详细信息请参见参考手册的“电源控制 (PWR)”部分 主存储器 一般我们说 STM32 内部 FLASH 的时候都是指这个主存储器区域它是存储用户应 用程序的空间芯片型号说明中的 256K FLASH、512K FLASH 都是指这个区域的大 小。
系统存储区 系统存储区是用户不能访问的区域它在芯片出厂时已经固化了启动代码它负责实现串口、USB 以及 CAN 等 ISP 烧录功能 ISP烧录就是,芯片通过某些方式进入芯片内部预置的ISP升级程序,开启升级功能,然后与外部通信,然后通过相关的协议,完成程序区的擦除,写入,校验和相关的配置等一些列操作的过程.。
选项字节 选项字节用于配置 FLASH 的读写保护、待机/停机复位、软件/硬件看门狗等功能这 部分共 16 字节。可以通过修改 FLASH 的选项控制寄存器修改。
OTP介绍 OTPone-time programmable,只允许一次编程也就是只能从1写0不能从0写1。这里可能有人要问这不是flash的特性么需要注意的是flash是允许擦除的是允许从0写1的。而OTP不允许擦除就算在ICP烧录代码时也不会丢。
3接口 4读写操作
执行任何 Flash 编程操作擦除或编程时CPU 时钟频率 (HCLK) 不能低于 1 MHz。如果 在 Flash 操作期间发生器件复位无法保证 Flash 中的内容。 在对 STM32F4xx 的 Flash 执行写入或擦除操作期间任何读取 Flash 的尝试都会导致总线 阻塞。只有在完成编程操作后才能正确处理读操作。这意味着写/擦除操作进行期间不能 从 Flash 中执行代码或数据获取操作。也就是说读写之间不能操作
4.1解锁
复位后你先解锁才能操作 复位后Flash 控制寄存器 (FLASH_CR) 不允许执行写操作以防因电气干扰等原因出现对 Flash 的意外操作。此寄存器的解锁顺序如下
在 Flash 密钥寄存器 (FLASH_KEYR) 中写入 KEY1 0x45670123在 Flash 密钥寄存器 (FLASH_KEYR) 中写入 KEY2 0xCDEF89AB如果顺序出现错误将返回总线错误并锁定 FLASH_CR 寄存器直到下一次复位。 也可通过软件将 FLASH_CR 寄存器中的 LOCK 位置为 1 来锁定 FLASH_CR 寄存器。
当 FLASH_SR 寄存器中的 BSY 位为 1 时将不能在写模式下访问 FLASH_CR 寄存器。 BSY 位为 1 时对该寄存器的任何写操作尝试都会导致 AHB 总线阻塞直到 BSY 位清零。
4.2擦除/编程位数
通过 FLASH_CR 寄存器中的 PSIZE 字段配置并行位数。并行位数表示每次对 Flash 进行写 操作时将编程的字节数。PSIZE 受限于电源电压以及是否使用外部 VPP 电源。因此在进行 任何编程/擦除操作前必须在 FLASH_CR 寄存器中对其进行正确配置。 编程就是读写 擦除受外部电压影响 Flash 擦除操作只能针对扇区或整个 Flash批量擦除执行。擦除时间取决于 PSIZE 编程 值。有关擦除时间的详细信息请参见器件数据手册的电气特性部分。 DW64 W32 HW16 Byte8位
写到这我想先写一个关于stm32程序存在了哪这涉及到了程序编译过程我先写这个但是排在第二篇吧 #stm32整理二关于MDK的编译过程及文件类型全解
4.3擦除
Flash 擦除操作可针对扇区或整个 Flash批量擦除执行。执行批量擦除时不会影响 OTP 扇区或配置扇区。 扇区擦除 扇区擦除的具体步骤如下
检查 FLASH_SR 寄存器中的 BSY 位以确认当前未执行任何 Flash 操作在 FLASH_CR 寄存器中将 SER 位置 1并从主存储块的 12 个 (STM32F405xx/07xx 和 STM32F415xx/17xx) 或 24 个 (STM32F42xxx 和 STM32F43xxx) 扇区中选择要擦除 的扇区 (SNB)将 FLASH_CR 寄存器中的 STRT 位置 1等待 BSY 位清零 批量擦除 要执行批量擦除建议采用以下步骤检查 FLASH_SR 寄存器中的 BSY 位以确认当前未执行任何 Flash 操作将 FLASH_CR 寄存器中的 MER 位置 1(STM32F405xx/07xx 和 STM32F415xx/17xx 器件将 FLASH_CR 寄存器中的 MER 和 MER1 位置 1STM32F42xxx 和 STM32F43xxx 器件 . 将 FLASH_CR 寄存器中的 STRT 位置 1等待 BSY 位清零 注意 如果 FLASH_CR 寄存器中的 MERx 位和 SER 位均置为 1则无法执行扇区擦除和批量擦除。
这里写一段flash 扇区删除的代码
Flash 状态寄存器 (FLASH_SR) Flash status register Flash 状态寄存器提供正在执行的编程和擦除操作的相关信息。 偏移地址0x0C 复位值0x0000 0000 访问无等待周期按字、半字和字节访问 用于 STM32F405xx/07xx 和 STM32F415xx/17xx 的 Flash 控制寄存器 (FLASH_CR) Flash control register Flash 控制寄存器用于配置和启动 Flash 操作。 偏移地址0x10 复位值0x8000 0000 访问当前未执行任何 Flash 操作时无等待周期按字、半字和字节访问。
注意FLASH的值擦完是FF写的时候是把1变0
//1. 检查 FLASH_SR 寄存器中的 BSY 位以确认当前未执行任何 Flash 操作 这相当于第一步
/*** brief 得到FLASH的错误状态* param 无* retval 执行结果* arg 0 : 已完成* arg 其他 : 错误编号*/
static uint8_t stmflash_get_error_status(void)
{uint32_t res 0;res FLASH-SR;if (res (1 16)) return 1; /* BSY1, 繁忙 */if (res (1 7)) return 2; /* PGSERR1,编程序列错误 */if (res (1 6)) return 3; /* PGPERR1,编程并行位数错误 */if (res (1 5)) return 4; /* PGAERR1,编程对齐错误 */if (res (1 4)) return 5; /* WRPERR1,写保护错误 */return 0; /* 没有任何状态/操作完成. */
}
/*** brief 等待操作完成* param time : 要延时的长短* retval 执行结果* arg 0 : 已完成* arg 0XFF: 超时* arg 其他 : 错误编号*/
static uint8_t stmflash_wait_done(uint32_t time)
{uint8_t res;do{res stmflash_get_error_status(); if (res ! 1){break; /* 非忙, 无需等待了, 直接退出 */}time--;} while (time);if (time 0)res 0XFF; /* 超时 */return res;
}/*** brief 获取某个地址所在的flash扇区* param faddr : flash地址* retval 0~11, 即addr所在的扇区*/
static uint8_t stmflash_get_flash_sector(uint32_t addr)
{if (addr ADDR_FLASH_SECTOR_1)return 0;else if (addr ADDR_FLASH_SECTOR_2)return 1;else if (addr ADDR_FLASH_SECTOR_3)return 2;else if (addr ADDR_FLASH_SECTOR_4)return 3;else if (addr ADDR_FLASH_SECTOR_5)return 4;else if (addr ADDR_FLASH_SECTOR_6)return 5;else if (addr ADDR_FLASH_SECTOR_7)return 6;else if (addr ADDR_FLASH_SECTOR_8)return 7;else if (addr ADDR_FLASH_SECTOR_9)return 8;else if (addr ADDR_FLASH_SECTOR_10)return 9;else if (addr ADDR_FLASH_SECTOR_11)return 10;return 11;
}static uint8_t stmflash_erase_sector(uint32_t saddr)
{uint8_t res 0;res stmflash_wait_done(0XFFFFFFFF); /* 等待上次操作结束 */ //1. 检查 FLASH_SR 寄存器中的 BSY 位以确认当前未执行任何 Flash 操作if (res 0){FLASH-CR ~(3 8); /* 清除PSIZE原来的设置 */ //默认8位编程FLASH-CR | 2 8; /* 设置为32bit宽,确保VCC2.7~3.6V之间!! */FLASH-CR ~(0X1F 3); /* 清除原来的设置 */FLASH-CR | saddr 3; /* 设置要擦除的扇区 */FLASH-CR | 1 1; /* 扇区擦除 */ // SER置1 激活扇区擦除FLASH-CR | 1 16; /* 开始擦除 */res stmflash_wait_done(0XFFFFFFFF); /* 等待操作结束 */ //位 16 STRT启动 (Start) 该位置 1 后可触发擦除操作。// **注意这里没有设置MERMER是按块擦除这里是按扇区擦除**if (res ! 1) /* 非忙 */{FLASH-CR ~(1 1); /* 清除扇区擦除标志 */// SER扇区擦除 (Sector Erase)}}return res;
}4.4编程写
Flash 编程顺序如下
检查 FLASH_SR 中的 BSY 位以确认当前未执行任何主要 Flash 操作。将 FLASH_CR 寄存器中的 PG 位置 1。针对所需存储器地址主存储器块或 OTP 区域内执行数据写入操作 — 并行位数为 x8 时按字节写入 — 并行位数为 x16 时按半字写入 — 并行位数为 x32 时按字写入 — 并行位数为 x64 时按双字写入等待 BSY 位清零
注意 把 Flash 的单元从“1”写为“0”时无需执行擦除操作即可进行连续写操作。把 Flash 的 单元从“0”写为“1”时则需要执行 Flash 擦除操作。 如果同时发出擦除和编程操作请求首先执行擦除操作。
这里放一段写代码
//从指定地址开始写入指定长度的数据
//WriteAddr:起始地址(此地址必须为2的倍数!!)
//pBuffer:数据指针
//NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
void Flash_Write(uint32_t WriteAddr, uint16_t *pBuffer, uint16_t NumToWrite)
{uint8_t status 0;uint32_t addrx 0;uint32_t endaddr0;uint8_t sector;if(WriteAddrSTM32_FLASH_BASE||WriteAddr%2||WriteAddr(STM32_FLASH_BASESTM32_FLASH_SIZE))//判断地址是否符合这里我们需注意基地址和flash大小可以根据手册查{return;//return 语句是提前结束函数的唯一办法。return 后面可以跟一份数据表示将这份数据返回到函数外面return 后面也可以不跟任何数据表示什么也不返回仅仅用来结束函数。}FLASH_Unlock();//解锁之前介绍过 直接用库函数中的函数FLASH_DataCacheCmd(DISABLE);//关闭数据缓存这里不关闭数据缓存擦除时可能会发生缓存不一致现象 这里我没验证相关可以参考 https://shequ.stmicroelectronics.cn/thread-621109-1-1.htmladdrxWriteAddr;//开始地址endaddrWriteAddrNumToWrite*2;//结束地址sectorstmflash_get_flash_sector(addrx);//获取扇区if(addrx0X1FFF0000)//地址0x1FFF 0000是系统存储器的地址{while(addrxendaddr){if(Flash_ReadHalfWord(addrx)!0XFFFF)//读到非零擦除{status stmflash_erase_sector(sector);if(status)break;}else{addrx2;}}}if(status0){status stmflash_wait_done(0XFFFFF);//这一句其实没用while(WriteAddrendaddr){if(stmflash_wait_done(0XFFFFF)0)statusFLASH_ProgramHalfWord(WriteAddr,*pBuffer);//半字写入elsebreak;WriteAddr2;pBuffer;}} //这里缺一点如果写入错误应该如何判断写入问题FLASH_DataCacheCmd(ENABLE);//使能数据缓冲FLASH_Lock();//上锁}读函数
//读取指定地址的半字(16位数据)
//faddr:读地址
//返回值:对应数据.
static uint16_t Flash_ReadHalfWord(uint32_t faddr)
{return *(vu16 *)faddr;//(vu16 *)将32位地址强制转换为16为__IO uint16_t 16位地址 第二个*才是返回该地址所存储的值。
}关于f1的和这个不一样先不写了先写到这里但是流程是差不多的。
1、这里注意我们在进行擦除和写入时操作的基本单元是sector 所以在进行操作时哪怕对某一个地址中的值进行修改需要先将扇区中的值读出来然后更改这个值再写进去所以当数据量特别大的时候我们也需要一个特别大的全局buffer现将值读出来有点不实用这里我想了一个思路还是要计算当前要写的字节在sector的大小然后把他给到一个临时buffer中然后修改临时buffer的值将buffer再写回sector中但是同样存在临时buffer太大栈溢出导致硬件中断错误 2、注意这里我们写的数据没有超过该secotr的大小如果超过了那么就坏了还要根据扇区大小不同判断剩余字节数 先写到这吧