stm32---SPI与内部flash

2020-03-26来源: eefocus关键字:stm32  SPI  内部flash

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

            

    }

}

关键字:stm32  SPI  内部flash 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic492635.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:stm32---ADXL345
下一篇:stm32---SPI与外部FLASH

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

stm8l低功耗系列
最近干刚做了一个stm8的项目用的是L低功耗系列,其中遇到一个问题。外设寄存器的值怎么都写入不进去。用IAR仿真产看寄存器的值,不论写进去多少,都是初始值。后来把所有寄存器都写了一遍,发现有的能写进去,有的写不进去。比如GPIO的寄存器就能写进去。百思不得姐,偶然查看clock的库函数发现个函数是设置外设时钟的。这个系列,亦或者整个低功耗系列的每个外设是不是都需要在时钟寄存器中单独设置时钟。(以前所使用的芯片都是在外设寄存器中使能或者是禁使能)
发表于 2020-03-09
STM8L+BC26双低功耗,微安
现在在做一个项目需要用到STM8L和BC26。长时间断链后连接下服务器,并且发送一下当前状态,需要用到STM8L和BC26的低功耗。STM8L低功耗,这里用HALT模式,RTC规定时间唤醒。第一步需要关闭所有外设,把所有管脚为设置为输出,并且输出低,管脚根据具体环境设置,需要输出高电平的则输出高电平。在关闭外设的是后是需要先_DeInit,然后在关闭外设始终,有点需要特别主要,要把在进入halt模式的时候需要把所有的中断的标志位清空,否则使用RTC唤醒则会不起作用。第二步就设置低功耗的一些配置。第三步配置完成后进入低功耗。项目中需要用到外部高速始终和BC26通信,所以在进入和退出halt模式的时候需要重新初始化active模式下的
发表于 2020-03-09
stm8l151低功耗程序架构,调试心得
最近帮医院做了一款体温记录仪,整个硬件方案资源是:stm8L151 + NTC*2 + EEPROM + 锂电池充电保护电路 + 18mAh纽扣电池;软件逻辑是,每隔一分钟,采样两路温度并保存在EEP里;通过USB转TTL,上位机能够读取,展示温度曲线,最大最小平均值等简单的运算;整个方案很简单,但也走了不少弯路......单片机程序框架之伪代码:void main(void){    CLK_Config();    GPIO_Config();    ADC_Config();    USART_Config();   
发表于 2020-03-09
STM8s外部时钟晶振失效时钟安全系统CSS启动演示
使用的最小系统晶振是8m的。这里说下配置过程:时钟自动切换,开启切换中断在中断里面清除中断标志,使能CSS并开启CSS中断CSS中断发生,清除CSS中断标志,将HSI二分频,即16M/2=8M,与外部晶振相同,这样不会影响串口波特率窗口输出配置信息:用手触碰PA1、PA2引脚使外部晶振失效串口输出CSS中断
发表于 2020-03-09
STM8s外部时钟晶振失效时钟安全系统CSS启动演示
STM8S103之时钟设置
最大时钟(指的是system clock):外部晶振24MHz,内部高速RC16MHz三个时钟源:外部晶振、内部高速RC(上电默认) +内部低速RC几个时钟:master clock(即sytem clock),fcpu,外设时钟、AWU时钟调用库函数中CLK_ClockSwitchConfig,参考库函数clk_clockselection,但是分频还得进一步设置上电默认:内部高速RC,HSIDIV=/8,CPUDIV=/1,外部时钟全使能,查看相关寄存器的Reset value
发表于 2020-03-09
STM8S103之时钟设置
stm8 16M晶振下精确软件延时
void inerDelay_us(unsigned char n) {for(;n>0;n--) { asm("nop"); //在STM8里面,16M晶振,_nop_() 延时了 333nsasm("nop"); asm("nop"); asm("nop"); }}//---- 毫秒级延时程序----------------------- void Delayms(unsigned int time) { unsigned int i; 
发表于 2020-03-08
小广播
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2020 EEWORLD.com.cn, Inc. All rights reserved