历史上的今天
今天是:2025年03月26日(星期三)
2020年03月26日 | stm32---SPI与内部flash
2020-03-26 来源:eefocus
STM32F1 的闪存(Flash)模块由:主存储器、信息块和闪存存储器接口寄 存器等 3 部分组成。
主存储器:存放代码和数据常数 , (BOOT0,BOOT1)= (0,0)
信息块:分为两个小部分,其中启动程序代码存储stm的自带的启动程序用于串口下载(1,0)。其中用户选择字节,则一般用于配置写保护、读保护等功能。
闪存存储器接口寄存器:该部分用于控制闪存读写等,是整个闪存模块的 控制机构。
同样,STM32 的 FLASH 在编程的时候,也必须要求其写入地址的 FLASH 是 被擦除了的(也就是其值必须是 0XFFFF),否则无法写入,在 FLASH_SR 寄存 器的 PGERR 位将得到一个警告。
flash配置步骤
① 检查 FLASH_CR 的 LOCK 是否解锁,如果没有则先解锁
② 检查 FLASH_SR 寄存器的 BSY 位,以确认没有其他正在进行的编程操作
③ 设置 FLASH_CR 寄存器的 PG 位为’1’
④ 在指定的地址写入要编程的半字
⑤ 等待 BSY 位变为’0’
⑥ 读出写入的地址并验证数据
页擦除操作
①检查 FLASH_CR 的 LOCK 是否解锁,如果没有则先解锁
②检查 FLASH_SR 寄存器中的 BSY 位,确保当前未执行任何 FLASH 操作
③设置 FLASH_CR 寄存器的 PER 位为’1’
④用 FLASH_AR 寄存器选择要擦除的页
⑤设置 FLASH_CR 寄存器的 STRT 位为’1’
⑥等待 BSY 位变为’0’
⑦读出被擦除的页并做验证
stm__flash.c
#include "stm32_flash.h"
//读取指定地址的半字(16位数据)
//faddr:读地址(此地址必须为2的倍数!!)
//返回值:对应数据.
vu16 STM32_FLASH_ReadHalfWord(u32 faddr)
{
return *(vu16*)faddr;
}
vu16
//不检查的写入,即不检查存储空间是否都是空字节
//WriteAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数
void STM32_FLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
{
u16 i;
for(i=0;i FLASH_ProgramHalfWord(WriteAddr,pBuffer[i]);//在指定地址编写半字 WriteAddr+=2;//地址增加2. } } //从指定地址开始写入指定长度的数据 //WriteAddr:起始地址(此地址必须为2的倍数) //pBuffer:数据指针 //NumToWrite:半字(16位)数(就是要写入的16位数据的个数.) #if STM32_FLASH_SIZE<256 #define STM32_SECTOR_SIZE 1024 //字节 #else #define STM32_SECTOR_SIZE 2048 #endif u16 STM32_FLASH_BUF[STM32_SECTOR_SIZE/2];//最多是2K字节 void STM32_FLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite) { u32 secpos; //扇区地址 u16 secoff; //扇区内偏移地址(16位字计算) u16 secremain; //扇区内剩余地址(16位字计算) u16 i; u32 offaddr; //去掉0X08000000后的地址 if(WriteAddr FLASH_Unlock(); //解锁 offaddr=WriteAddr-STM32_FLASH_BASE; //实际偏移地址. secpos=offaddr/STM32_SECTOR_SIZE; //扇区地址 0~127 for STM32F103RBT6 secoff=(offaddr%STM32_SECTOR_SIZE)/2; //在扇区内的偏移(2个字节为基本单位.) secremain=STM32_SECTOR_SIZE/2-secoff; //扇区剩余空间大小 if(NumToWrite<=secremain)secremain=NumToWrite;//不大于该扇区范围 while(1) { STM32_FLASH_Read(secpos*STM32_SECTOR_SIZE+STM32_FLASH_BASE,STM32_FLASH_BUF,STM32_SECTOR_SIZE/2);//读出整个扇区的内容 for(i=0;i if(STM32_FLASH_BUF[secoff+i]!=0XFFFF) break;//需要擦除 } if(i FLASH_ErasePage(secpos*STM32_SECTOR_SIZE+STM32_FLASH_BASE);//擦除这个扇区 for(i=0;i STM32_FLASH_BUF[i+secoff]=pBuffer[i]; } STM32_FLASH_Write_NoCheck(secpos*STM32_SECTOR_SIZE+STM32_FLASH_BASE,STM32_FLASH_BUF,STM32_SECTOR_SIZE/2);//写入整个扇区 } else STM32_FLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);//写已经擦除了的,直接写入扇区剩余区间. if(NumToWrite==secremain) break;//写入结束了 else//写入未结束 { secpos++; //扇区地址增1 secoff=0; //偏移位置为0 pBuffer+=secremain; //指针偏移 WriteAddr+=secremain; //写地址偏移 NumToWrite-=secremain; //字节(16位)数递减 if(NumToWrite>(STM32_SECTOR_SIZE/2)) secremain=STM32_SECTOR_SIZE/2;//下一个扇区还是写不完 else secremain=NumToWrite;//下一个扇区可以写完了 } } FLASH_Lock();//上锁 6 } //从指定地址开始读出指定长度的数据 //ReadAddr:起始地址 //pBuffer:数据指针 //NumToWrite:半字(16位)数 void STM32_FLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead) { u16 i; for(i=0;i pBuffer[i]=STM32_FLASH_ReadHalfWord(ReadAddr);//读取2个字节. ReadAddr+=2;//偏移2个字节. } } stm__flash.h #ifndef _stm32_flash_H #define _stm32_flash_H #include "system.h" //用户根据自己的需要设置 #define STM32_FLASH_SIZE 512 //所选STM32的FLASH容量大小(单位为K) //FLASH起始地址 #define STM32_FLASH_BASE 0x08000000 //STM32 FLASH的起始地址 vu16 STM32_FLASH_ReadHalfWord(u32 faddr); void STM32_FLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite); //从指定地址开始写入指定长度的数据 void STM32_FLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead); //从指定地址开始读出指定长度的数据 #endif main.c #include "system.h" #include "SysTick.h" #include "led.h" #include "usart.h" #include "flash.h" #include "key.h" #include "stm32_flash.h" const u8 text_buf[] = "www.baidu.com"; //待存储进FLASH的内容数组 #define TEXTLEN sizeof(text_buf) //数据的长度 #define STM32_FLASH_SAVE_ADDR 0X08070000 //设置FLASH 保存地址(必须为偶数,且其值要大于本代码所占用FLASH的大小+0X08000000) int main() { u8 i=0; u8 key; u8 read_buf[TEXTLEN]; //读取的数据保存到此数组 SysTick_Init(72); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2组 LED_Init(); USART1_Init(9600); KEY_Init(); while(1) { key = KEY_Scan(0); if(key==KEY_UP) { STM32_FLASH_Write(STM32_FLASH_SAVE_ADDR,(u16*)text_buf,TEXTLEN); printf("写入数据为:%srn",text_buf); } if(key==KEY_DOWN) { STM32_FLASH_Read(STM32_FLASH_SAVE_ADDR,(u16 *)read_buf,TEXTLEN); printf("读取数据为:%srn",read_buf); } i++; if(i%20==0) { led1=!led1; } delay_ms(10); } }
上一篇:stm32---ADXL345
史海拾趣
|
要暂时中断winCE的学习,转去看windows下USB驱动的开发,郁闷中…… 公司一个项目要做windows下USB驱动的开发,老大叫我跟着一起看看相关的知识,并跟我说了一大通做USB设备驱动的前景。USB驱动比较复杂,要花时间去学习的,那我就要暂时中断winCE的学习了。但心里还是想朝winCE这个方向发展,况且也学了一些日子了, ...… 查看全部问答> |
|
用modelsim进行仿真,为了便于观察,我希望仿真结果按一定的顺序显示。可是每次手动调整完信号顺序后,再重新仿真,顺序又乱了,有没有办法将这些信号的顺序固定下来,每仿真一次都按这个顺序显示结果?… 查看全部问答> |
|
在STM32F10X参考手册上的第21(实际36)页,有一个时钟树。上面"APB1 Prescaler /1,2,4,8,16"下面"TIM2,3,4 *1,2 Multiplier"是不是可倍频的意思呀?我没有找到这一项的设置呢?哪一个寄存器位是设置这一项?菜鸟 ...… 查看全部问答> |
|
LED 亮度控制要求有一个能够提供恒定、稳压电流的驱动器。要想达到这一目标,驱动器拓扑必须能够产生足够大的输出电压来正向偏置 LED。因此,如果输入和输出电压范围重叠时,我们又该做何选择呢? 德州仪器 (TI) 应用工程师John Betten, ...… 查看全部问答> |
|
教材大分享!想要学习LPC1100开发的工程师朋友,就从《基于MDC的LPC1100微处理器开发应用》这本书开始吧!书中含有详细的LPC1100结构、功能和特性介绍,丰富的编程实例,为工程师朋友提供全面的LPC1100开发参考。… 查看全部问答> |
|
在学习nxp1768,,在编程中出现HardFault_Handler,,程序运行就死在.s文件的HardFault_Handler上了,不知什么原因。程序是对的,求解 一下是程序,调用这个程序,就出现错误 void CAN_SendMessage( uint32_t CanNum,CAN_MSG *pTxBuf ) { &n ...… 查看全部问答> |




