stm32---SPI与外部FLASH

2020-03-26来源: eefocus关键字:stm32  SPI  外部FLASH

stm32外部flash是EN25QXX 芯片


使用 STM32F1 的 SPI 和外部 FLASH(EN25QXX)进行通信,实现数据的读写 操作。本章要实现的功能是:首先检测外部 FLASH 是否正常,然后使用 K__UP 和 K_DOWN 键控制 FLASH 的写入和读取,并将 数据显示在 串口助手上,同时控制 D1 指示灯不断闪烁,提示系统正常 运行


W25Q128 将 16M 的容量分为 256 个块( Block),每个块大小为 64K 字 节,每个块又分为 16 个扇区( Sector),每个扇区 4K 个字节。 W25Q128 的最小擦除单位为一个扇区,也就是每次必须擦除 4K 个字节。这样我们需要给 W25Q128 开辟一个至少 4K 的缓存区,这样对 SRAM 要求比较高,要求芯片必须 有 4K 以上 SRAM 才能很好的操作。


W25Q128


EN25QXX 芯片的操作

flash.c


#include "flash.h"

#include "spi.h"

#include "SysTick.h"   

#include "usart.h"

 

u16 EN25QXX_TYPE=EN25Q64;   //默认是EN25Q64

 

//4Kbytes为一个Sector

//16个扇区为1个Block

//EN25Q64

//容量为8M字节,共有128个Block(块),4096个Sector (扇区)

                                                     

//初始化SPI FLASH的IO口

void EN25QXX_Init()

{

    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOG|RCC_APB2Periph_GPIOF, ENABLE);

    

    /* FLASH_CS PG13 */

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOG,&GPIO_InitStructure);

    GPIO_SetBits(GPIOG,GPIO_Pin_13);

    

    /*SD_CS置1  ,PG14*/

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;

    GPIO_Init(GPIOG,&GPIO_InitStructure);

    GPIO_SetBits(GPIOG,GPIO_Pin_14);

    

    /*ENC28J60_CS置1  ,PB12*/

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_Init(GPIOB,&GPIO_InitStructure);

    GPIO_SetBits(GPIOB,GPIO_Pin_12);

    

    /*NRF24L01_CS置1  ,PF9*/

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

    GPIO_Init(GPIOF,&GPIO_InitStructure);

    GPIO_SetBits(GPIOF,GPIO_Pin_9);

    

    EN25QXX_CS = 1; //EN25QXX的片选信号置1表示取消片选,这个是低电平有效

    SPI2_Init();

    EN25QXX_TYPE = EN25QXX_ReadID();

    

}

 

/*读取EN25QXX的状态寄存器

BIT7  6   5   4   3   2   1   0

SPR   RV  TB BP2 BP1 BP0 WEL BUSY

SPR:默认0,状态寄存器保护位,配合WP使用

TB,BP2,BP1,BP0:FLASH区域写保护设置

WEL:写使能锁定

BUSY:忙标记位(1,忙;0,空闲)

默认:0x00*/

u8 EN25QXX_ReadSR()

{

    u8 byte = 0;

    EN25QXX_CS = 0;     //使能器件

    SPI2_ReadWriteByte(EN25X_ReadStatusReg); //发送读取状态寄存器命令

    byte = SPI2_ReadWriteByte(0Xff); //读取一个字节

    EN25QXX_CS = 1; //取消片选

    return byte;

}

 

//写EN25QXX状态寄存器

//只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写!!!

void EN25QXX_Write_SR(u8 sr)

{

    EN25QXX_CS = 0;  //使能器件

    SPI2_ReadWriteByte(EN25X_WriteStatusReg); //发送写取状态寄存器命令

    SPI2_ReadWriteByte(sr); //写入一个字节

    EN25QXX_CS = 1; //取消片选

}

 

//EN25QXX写使能    

//将WEL置位 

void EN25QXX_Write_Enable()

{

    EN25QXX_CS=0;                            //使能器件   

    SPI2_ReadWriteByte(EN25X_WriteEnable);      //发送写使能  

    EN25QXX_CS=1;                            //取消片选     

}

 

//EN25QXX写禁止    

//将WEL清零  

void EN25QXX_Write_Disable(void)   

{  

    EN25QXX_CS=0;                            //使能器件   

    SPI2_ReadWriteByte(EN25X_WriteDisable);     //发送写禁止指令    

    EN25QXX_CS=1;                            //取消片选               

 

//读取芯片ID

//返回值如下:                   

//0XEF13,表示芯片型号为EN25Q80  

//0XEF14,表示芯片型号为EN25Q16    

//0XEF15,表示芯片型号为EN25Q32  

//0XEF16,表示芯片型号为EN25Q64 

//0XEF17,表示芯片型号为EN25Q128    

u16 EN25QXX_ReadID()

{

    u16 temp = 0;

    EN25QXX_CS = 0;

    SPI2_ReadWriteByte(0x90);

    SPI2_ReadWriteByte(0x00);

    SPI2_ReadWriteByte(0x00);

    SPI2_ReadWriteByte(0x00);

    temp |= SPI2_ReadWriteByte(0xff)<<8;

    temp |= SPI2_ReadWriteByte(0xff);

    EN25QXX_CS = 1;

    return  temp;

}

 

 

//读取SPI FLASH  

//在指定地址开始读取指定长度的数据

//pBuffer:读取的数据存储区

//ReadAddr:开始读取的地址(24bit)

//NumByteToRead:要读取的字节数(最大65535)

void EN25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)   

    u16 i;                                              

    EN25QXX_CS=0;                            //使能器件   

    SPI2_ReadWriteByte(EN25X_ReadData);         //发送读取命令   

    SPI2_ReadWriteByte((u8)((ReadAddr)>>16));  //发送24bit地址    

    SPI2_ReadWriteByte((u8)((ReadAddr)>>8));   

    SPI2_ReadWriteByte((u8)ReadAddr);   

    for(i=0;i

    { 

        pBuffer[i]=SPI2_ReadWriteByte(0XFF);   //循环读数  

    }

    EN25QXX_CS=1;                             

}  

 

//SPI在一页(0~65535)内写入少于256个字节的数据

//在指定地址开始写入最大256字节的数据

//pBuffer:待输入的数据存储区

//WriteAddr:开始写入的地址(24bit)

//NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!   

void EN25QXX_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)

{

    u16 i;  

    EN25QXX_Write_Enable();                  //SET WEL 

    EN25QXX_CS=0;                            //使能器件   

    SPI2_ReadWriteByte(EN25X_PageProgram);      //发送写页命令   

    SPI2_ReadWriteByte((u8)((WriteAddr)>>16)); //发送24bit地址    

    SPI2_ReadWriteByte((u8)((WriteAddr)>>8));   

    SPI2_ReadWriteByte((u8)WriteAddr);   

    for(i=0;i

    {

        SPI2_ReadWriteByte(pBuffer[i]);//循环写数  

    }

    EN25QXX_CS=1;                            //取消片选 

    EN25QXX_Wait_Busy();                       //等待写入结束

}

 

//无检验写SPI FLASH 

//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!

//具有自动换页功能 

//在指定地址开始写入指定长度的数据,但是要确保地址不越界!

//pBuffer:数据存储区

//WriteAddr:开始写入的地址(24bit)

//NumByteToWrite:要写入的字节数(最大65535)

//CHECK OK

void EN25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)   

{                    

    u16 pageremain;    

    pageremain=256-WriteAddr%256; //单页剩余的字节数                

    if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节

    while(1)

    {      

        EN25QXX_Write_Page(pBuffer,WriteAddr,pageremain);

        if(NumByteToWrite==pageremain)break;//写入结束了

        else //NumByteToWrite>pageremain

        {

            pBuffer+=pageremain;

            WriteAddr+=pageremain;  

 

            NumByteToWrite-=pageremain;           //减去已经写入了的字节数

if(NumByteToWrite>256)pageremain=256;

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

上一篇:stm32---SPI与内部flash
下一篇:stm32---CAN通信

关注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