历史上的今天
返回首页

历史上的今天

今天是: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=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))return;//非法地址

    

    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);

            

    }

}

推荐阅读

史海拾趣

Elpaq公司的发展小趣事
GC Electronics公司的发展小趣事
定期检查传感器的工作状态,确保其能够准确监测水量或水温。
Bipolar Integrated Technology Inc公司的发展小趣事

随着国内市场的饱和,BIT开始将目光投向国际市场。他们通过参加国际电子展会、与海外企业建立合作关系等方式,积极拓展海外市场。同时,BIT还在全球范围内设立研发中心和生产基地,以便更好地满足不同地区客户的需求。

Decawave公司的发展小趣事

Decawave公司成立于2007年,总部位于爱尔兰都柏林。成立之初,公司就专注于超宽带(UWB)技术的研发。在初创阶段,Decawave面临着技术难度大、资金紧张等挑战。然而,凭借对UWB技术的深入理解和研究,公司成功开发出了具有高精度定位能力的UWB芯片,这一技术突破为Decawave在电子行业中赢得了声誉。

Fagor Electrónica公司的发展小趣事

1959年,Fagor Electrónica在电子领域崭露头角,当时它还只是Ulgor, S. Coop.公司旗下的一个电子部门。这一年,公司开始制造硒板和整流器,这标志着其电子制造业务的开始。尽管初始规模不大,但Fagor Electrónica凭借其高质量的产品和卓越的客户服务,迅速在市场上赢得了声誉。

Clever Little Box公司的发展小趣事

Clever Little Box公司成立于1964年,当时正值电子行业的蓬勃发展时期。创始人凭借对音频和电子技术的深厚理解,以及对市场的敏锐洞察,决定成立这家公司,专注于音频和电子组件的分销。创业初期,公司面临着资金短缺、市场竞争激烈等诸多挑战,但创始人凭借坚定的信念和不懈的努力,逐渐在市场中站稳了脚跟。

问答坊 | AI 解惑

事件管理器模块(EV)

事件管理器模块(EV)…

查看全部问答>

要暂时中断winCE的学习,转去看windows下USB驱动的开发,郁闷中……

公司一个项目要做windows下USB驱动的开发,老大叫我跟着一起看看相关的知识,并跟我说了一大通做USB设备驱动的前景。USB驱动比较复杂,要花时间去学习的,那我就要暂时中断winCE的学习了。但心里还是想朝winCE这个方向发展,况且也学了一些日子了, ...…

查看全部问答>

求助软件mcu_ideV3.0

谁有mcu_ideV3.0,(装上去之后自带工具链,如keil c51,一共四种,就是有2KB代码限制的哪个版本) 官网上下的没有工具链,…

查看全部问答>

modelsim如何固定仿真信号显示的顺序?

用modelsim进行仿真,为了便于观察,我希望仿真结果按一定的顺序显示。可是每次手动调整完信号顺序后,再重新仿真,顺序又乱了,有没有办法将这些信号的顺序固定下来,每仿真一次都按这个顺序显示结果?…

查看全部问答>

stm32菜鸟级问题:TIMx输入时钟设置方面的

在STM32F10X参考手册上的第21(实际36)页,有一个时钟树。上面"APB1 Prescaler /1,2,4,8,16"下面"TIM2,3,4 *1,2 Multiplier"是不是可倍频的意思呀?我没有找到这一项的设置呢?哪一个寄存器位是设置这一项?菜鸟 ...…

查看全部问答>

反相降压—升压拓扑可调节 LED 电流

LED 亮度控制要求有一个能够提供恒定、稳压电流的驱动器。要想达到这一目标,驱动器拓扑必须能够产生足够大的输出电压来正向偏置 LED。因此,如果输入和输出电压范围重叠时,我们又该做何选择呢?   德州仪器 (TI) 应用工程师John Betten, ...…

查看全部问答>

闲了

大三了,没课了…

查看全部问答>

教材分享:基于MDK的LPC1100处理器开发应用

教材大分享!想要学习LPC1100开发的工程师朋友,就从《基于MDC的LPC1100微处理器开发应用》这本书开始吧!书中含有详细的LPC1100结构、功能和特性介绍,丰富的编程实例,为工程师朋友提供全面的LPC1100开发参考。…

查看全部问答>

FPGA设计,最重要的是什么?

面试考官问我,“FPGA设计,最重要的是什么?”我一时慌乱,想不到什么是最重要的,大家谈谈自己的看法。…

查看全部问答>

在玩nxp1768是出现HardFault_Handler

在学习nxp1768,,在编程中出现HardFault_Handler,,程序运行就死在.s文件的HardFault_Handler上了,不知什么原因。程序是对的,求解 一下是程序,调用这个程序,就出现错误 void CAN_SendMessage( uint32_t CanNum,CAN_MSG *pTxBuf ) { &n ...…

查看全部问答>