历史上的今天
返回首页

历史上的今天

今天是:2025年02月04日(星期二)

2021年02月04日 | STM32H7外设配置速查【QSPI部分】

2021-02-04 来源:eefocus

QSPI协议

QSPI是Queued SPI(队列串行外围接口)的缩写,是由摩托罗拉公司推出的SPI协议的一个扩展,比SPI应用更加广泛,现在的FLASH、SRAM等存储器大多支持QSPI协议——QSPI是一种专用的通信接口,可连接单、双或四线SPI存储器

QSPI在SPI协议的基础上增加了队列传输机制。

STM32将Queued SPI协议接口实现为QUADSPI接口。QSPI的实现和SPI基本相似,有部分不同点,在下面列出。

物理连接

QSPI是标准的四信号线SPI,MCU与外设之间由六根线连接:NSS、IO0、IO1、IO2、IO3、SCLK,其中IO0-3是数据线;NSS又称CS,是片选信号线;SCLK又称SCK,是SPI/QSPI的同步时钟线

通信规则

读写命令

有且仅有一条数据线工作

读写数据

四条数据线同时工作

读写地址位时四条数据线发送不同的地址,从机自行分辨,引导向各自的地址;读写具体数据时根据对应的地址读写

STM32F1中的SPI特性

  • 三线全双工同步传输

  • 双线/三线单工同步传输

  • 8位/16位传输帧格式选择

  • 主从操作、支持多主模式

  • 8个主模式波特率分频系数(最高可达f P C L K / 2 f_{PCLK}/2fPCLK/2)

  • 硬件/软件可调的SS(CS片选信号)管理

  • 相关底层配置可编程

  • 可触发中断的发送/接收标志

  • SPI总线忙碌标志位

  • 支持硬件CRC校验

  • 支持DMA

STM32F4中的SPI实现

特性

  • 支持SPI的TI模式(主要是片选信号差异,用于TI系的IC)

  • 支持F1的全部功能

与F1的功能基本一致,满足SPI接口的使用需要

硬件实现

  1. 寄存器配置SPI设置

  2. 波特率发生器配置SCLK

  3. MOSI、MISO通过移位寄存器进行收发数据,接收数据即将数据从移位寄存器中复制到RxFIFO;发送数据即将数据放入TxFIFO后送入移位寄存器

  4. 主控制逻辑电路和通信控制电路调配相关收发过程

HAL库实现

直接将收发数据封装为库函数

STM32F7中的SPI特点

  • 支持F4的所有功能

  • 可调传输帧格式4位到16位(对应原来的8位/16位传输帧格式选择)

  • 具有DMA功能的两个32位内置Rx、Tx FIFO缓存

STM32H7中的SPI实现

特性

  • 支持F7的所有功能

  • 数据帧格式大小可从4位到32位

  • 双时钟域,外设内核时钟可以独立于PCLK

  • 更高的主频,8个主模式波特率预分频器(没有改动),主从模式频率均最高可达内核频率的1/2(f F C L K / 2 f_{FCLK}/2fFCLK/2)

  • 保护配置和设置

  • 数据之间的最小延时、SS与数据流之间的最小延时均可调

  • 底层配置可编程,支持SS信号极性、时序可编程和MISOxMOSI交互功能

  • 可调节的主器件接收器采样时间

  • 配备停止模式(不向外设IP提供时钟)

  • 具有停止模式下从器件发送/接收功能和低功耗唤醒功能

  • 可编程的FIFO阈值(数据打包)

  • 可编程的传输数据量

  • 具有DMA功能的Rx、Tx FIFO容量扩大到16x8位或8x8位且可选

  • 从模式下,下溢条件可配置,支持级联循环缓冲区

H7的SPI控制器比之前版本的控制器自由度更高(但大部分情况下用不上)

硬件实现

与之前的SPI控制器基本相同,但多了双时钟域的功能块:时钟寄存器控制时钟发生器工作,可以由SPI_PCLK或SPI_KER_CK提供时钟,SPI_KER_CK时钟直接提供给时钟发生器,进而用于SCK或MCK

软件配置

  1. 在CubeMX中根据外设IC配置GPIO复用和SPI相关设定

  2. CubeMX会使能外设时钟、配置SPI模式、地址、速率等参数并使能SPI外设;模式设定与f4设定基本类似,可参考【STM32F4外设配置速查总线协议部分】

  3. 编写对应外设IC的驱动程序

  4. 设置检验程序,上电后检验驱动程序及外设连接情况

  5. 编写应用程序

STM32F7/H7中的QSPI实现

QUADSPI主要用于控制SPI FLASH器件(只要满足QSPI时序就可以控制其他器件),工作在以下三种模式:

  1. 间接模式:使用QUADSPI寄存器执行全部操作

  2. 状态轮询模式:周期性轮询外部FLASH状态寄存器,如果为1(擦除/烧写完毕)则引发中断

  3. 内存映射模式:外部FLASH映射到MCU片上SRAM地址空间,系统将其视作内部FLASH存储器进行操作(

    内部FLASH只读

特别地,采用双闪存模式时,将同时访问两个QSPI FLASH,吞吐量和容量*2

特性

  • 双闪存模式:并行访问两块FLASH,同时收发8位数据

  • 支持SDR和DDR模式

  • 集成接收/发送FIFO

  • 允许8、16、32位数据访问

  • 间接模式下可使用DMA

  • 可使能的FIFO溢出、超时、操作完成、访问错误中断(异常)

硬件实现

可以实现单线、双线、四线SPI功能

与SPI控制器的不同点主要在于:FIFO和外设寄存器直接接入AHB总线

双闪存模式下,外设引脚复用可选择一个CS信号线或两个CS信号线

其他内容可参考MCU数据手册

软件配置

  1. 基本配置同上

外部SPI FLASH驱动代码如下,与上面的代码差别不大

/* W25Q256.h文件的函数声明 */

void NORFLASH_Init(void); //初始化W25QXX

void NORFLASH_Qspi_Enable(void); //使能QSPI模式

void NORFLASH_Qspi_Disable(void); //关闭QSPI模式

u16  NORFLASH_ReadID(void); //读取FLASH ID

u8 NORFLASH_ReadSR(u8 regno); //读取状态寄存器 

void NORFLASH_4ByteAddr_Enable(void); //使能4字节地址模式

void NORFLASH_Write_SR(u8 regno,u8 sr); //写状态寄存器

void NORFLASH_Write_Enable(void);  //写使能 

void NORFLASH_Write_Disable(void); //写保护

void NORFLASH_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite); //写flash,不校验

void NORFLASH_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead);    //读取flash

void NORFLASH_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite); //写入flash

void NORFLASH_Erase_Chip(void);      //整片擦除

void NORFLASH_Erase_Sector(u32 Dst_Addr); //扇区擦除

void NORFLASH_Wait_Busy(void);            //等待空闲


/* W25Q256.c文件全部内容 */

#include "norflash.h"

#include "qspi.h"

#include "delay.h"

#include "usart.h" 


u16 NORFLASH_TYPE=W25Q256; //使用W25Q256

u8 NORFLASH_QPI_MODE=0; //QSPI模式标志:0,SPI模式;1,QSPI模式


/**

 * 4Kbytes为一个Sector(扇区)

 * 16个扇区为1个Block(块)

 * W25Q64容量为8M字节,共有128个Block,2048个Sector,W25Q256刚好是它的4倍

 */


//初始化SPI FLASH的IO口

void NORFLASH_Init(void)

u8 temp;

QSPI_Init(); //初始化QSPI

  NORFLASH_Qspi_Enable(); //使能QSPI模式

NORFLASH_TYPE=NORFLASH_ReadID(); //读取FLASH ID

if(NORFLASH_TYPE==W25Q64)

{

NORFLASH_Write_Enable(); //写使能

QSPI_Send_CMD(W25X_SetReadParam,0,(3<<6)|(0<<4)|(0<<2)|(3<<0),0);

        //QSPI设置读参数指令,地址为0,4线传数据_8位地址_无地址_4线传输指令,无空周期,1个字节数据

temp=3<<4; //设置P4&P5=11,8个dummy clocks,104M

QSPI_Transmit(&temp,1); //发送1个字节

}

printf("ID:%xrn",NORFLASH_TYPE); //打印FLASH参数

}  


//W25QXX进入QSPI模式 

void NORFLASH_Qspi_Enable(void)

{

u8 stareg2=0;

stareg2=NORFLASH_ReadSR(2); //先读出状态寄存器2的原始值 

//printf("stareg2:%xrn",stareg2); //打印参数

if((stareg2&0X02)==0) //QE位未使能

NORFLASH_Write_Enable(); //写使能 

stareg2|=1<<1; //使能QE位

NORFLASH_Write_SR(2,stareg2); //写状态寄存器2

}

QSPI_Send_CMD(W25X_EnterQPIMode,0,(0<<6)|(0<<4)|(0<<2)|(1<<0),0);

    //写command指令,地址为0,无数据_8位地址_无地址_单线传输指令,无空周期,0个字节数据

NORFLASH_QPI_MODE=1; //标记QSPI模式

}


//W25QXX退出QSPI模式

void NORFLASH_Qspi_Disable(void)

QSPI_Send_CMD(W25X_ExitQPIMode,0,(0<<6)|(0<<4)|(0<<2)|(3<<0),0);

    //写command指令,地址为0,无数据_8位地址_无地址_4线传输指令,无空周期,0个字节数据

NORFLASH_QPI_MODE=0;//标记SPI模式

}


/* 读取W25QXX的状态寄存器 */

//W25QXX一共有3个状态寄存器

//状态寄存器1:

//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

//状态寄存器2:

//BIT7  6   5   4   3   2   1   0

//SUS   CMP LB3 LB2 LB1 (R) QE  SRP1

//状态寄存器3:

//BIT7      6    5    4   3   2   1   0

//HOLD/RST  DRV1 DRV0 (R) (R) WPS ADP ADS

//regno:状态寄存器号,范:1~3

//返回值:状态寄存器值

u8 NORFLASH_ReadSR(u8 regno)   

{  

u8 byte=0,command=0; 

    switch(regno)

    {

        case 1:

            command=W25X_ReadStatusReg1;    //读状态寄存器1指令

            break;

        case 2:

            command=W25X_ReadStatusReg2;    //读状态寄存器2指令

            break;

        case 3:

            command=W25X_ReadStatusReg3;    //读状态寄存器3指令

            break;

        default:

            command=W25X_ReadStatusReg1;    

            break;

    }   

if(NORFLASH_QPI_MODE)

        QSPI_Send_CMD(command,0,(3<<6)|(0<<4)|(0<<2)|(3<<0),0);

    //QSPI模式,写command指令,地址为0,4线传数据_8位地址_无地址_4线传输指令,无空周期,1个字节数据

else

        QSPI_Send_CMD(command,0,(1<<6)|(0<<4)|(0<<2)|(1<<0),0);

    //SPI模式,写command指令,地址为0,单线传数据_8位地址_无地址_单线传输指令,无空周期,1个字节数据

QSPI_Receive(&byte,1);

    

return byte;

}   


//写W25QXX状态寄存器

void NORFLASH_Write_SR(u8 regno,u8 sr)   

{   

    u8 command=0;

    switch(regno)

    {

        case 1:

            command=W25X_WriteStatusReg1;    //写状态寄存器1指令

            break;

        case 2:

            command=W25X_WriteStatusReg2;    //写状态寄存器2指令

            break;

        case 3:

            command=W25X_WriteStatusReg3;    //写状态寄存器3指令

            break;

        default:

            command=W25X_WriteStatusReg1;    

            break;

    }   

if(NORFLASH_QPI_MODE)

        QSPI_Send_CMD(command,0,(3<<6)|(0<<4)|(0<<2)|(3<<0),0);

    //QPI,写command指令,地址为0,4线传数据_8位地址_无地址_4线传输指令,无空周期,1个字节数据

else

        QSPI_Send_CMD(command,0,(1<<6)|(0<<4)|(0<<2)|(1<<0),0);

        //SPI,写command指令,地址为0,单线传数据_8位地址_无地址_单线传输指令,无空周期,1个字节数据

QSPI_Transmit(&sr,1);

}  


//W25QXX写使能

//将S1寄存器的WEL置位

void NORFLASH_Write_Enable(void)

{

if(NORFLASH_QPI_MODE)

        QSPI_Send_CMD(W25X_WriteEnable,0,(0<<6)|(0<<4)|(0<<2)|(3<<0),0);

    //QPI,写使能指令,地址为0,无数据_8位地址_无地址_4线传输指令,无空周期,0个字节数据

else

        QSPI_Send_CMD(W25X_WriteEnable,0,(0<<6)|(0<<4)|(0<<2)|(1<<0),0);

    //SPI,写使能指令,地址为0,无数据_8位地址_无地址_单线传输指令,无空周期,0个字节数据


//W25QXX写禁止

//将WEL清零  

void NORFLASH_Write_Disable(void)   

{  

if(NORFLASH_QPI_MODE)

        QSPI_Send_CMD(W25X_WriteDisable,0,(0<<6)|(0<<4)|(0<<2)|(3<<0),0);

    //QPI,写禁止指令,地址为0,无数据_8位地址_无地址_4线传输指令,无空周期,0个字节数据

else

        QSPI_Send_CMD(W25X_WriteDisable,0,(0<<6)|(0<<4)|(0<<2)|(1<<0),0);

    //SPI,写禁止指令,地址为0,无数据_8位地址_无地址_单线传输指令,无空周期,0个字节数据 


//返回值如下:    

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

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

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

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

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

//0XEF18,表示芯片型号为W25Q256

u16 NORFLASH_ReadID(void)

{

u8 temp[2];

u16 deviceid;

if(NORFLASH_QPI_MODE)

        QSPI_Send_CMD(W25X_ManufactDeviceID,0,(3<<6)|(2<<4)|(3<<2)|(3<<0),0);

    //QPI,读id,地址为0,4线传输数据_24位地址_4线传输地址_4线传输指令,无空周期,2个字节数据

else

        QSPI_Send_CMD(W25X_ManufactDeviceID,0,(1<<6)|(2<<4)|(1<<2)|(1<<0),0);

    //SPI,读id,地址为0,单线传输数据_24位地址_单线传输地址_单线传输指令,无空周期,2个字节数据

QSPI_Receive(temp,2);

deviceid=(temp[0]<<8)|temp[1];

    

return deviceid;

}    


//读取SPI FLASH,仅支持QSPI模式

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

//pBuffer:数据存储区

//ReadAddr:开始读取的地址(最大32bit)

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

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

QSPI_Send_CMD(W25X_FastReadData,ReadAddr,(3<<6)|(2<<4)|(3<<2)|(3<<0),8);

    //QPI,快速读数据,地址为ReadAddr,4线传输数据_24位地址_4线传输地址_4线传输指令,8空周期,NumByteToRead个数据

推荐阅读

史海拾趣

Gumstix公司的发展小趣事
检查电路连接是否松动或断裂,重新连接或更换损坏的部件。
DB Lectro Inc公司的发展小趣事

随着公司业务的不断拓展和市场竞争的加剧,DB Lectro Inc意识到知识产权保护的重要性。公司加强了知识产权的申请和保护工作,成功申请了一系列技术专利。同时,公司还积极参与知识产权维权行动,维护了自身的合法权益和公平竞争的市场环境。

汇顶科技(GOODiX)公司的发展小趣事

为了进一步扩大市场份额,DB Lectro Inc积极寻求与国际知名企业的合作。通过与多家国际公司的技术交流和合作,公司成功地将自身的气体检测技术应用于更多领域,如天然气开采、食品饮料生产等。同时,公司还积极参与国际展览和交流活动,展示了其先进的技术和产品,赢得了国际市场的广泛认可。

Amptek Inc公司的发展小趣事

为了满足亚洲市场的需求,DB Lectro Inc决定在中国上海设立子公司及工厂。这一战略举措不仅使公司能够更贴近亚洲客户,还大大降低了生产成本。在上海工厂的建设过程中,公司充分考虑到环保和可持续性发展的要求,采用了先进的生产工艺和设备。随着工厂的投产和产能的不断提升,DB Lectro Inc的产品在亚洲市场的占有率也稳步上升。

Corstat Containers公司的发展小趣事

Corstat Containers公司在电子行业中崭露头角,始于一次技术突破。当时,公司研发团队成功开发出一种新型的防静电电子元件包装盒,有效解决了电子产品在运输过程中因静电导致的损坏问题。这一创新产品迅速获得了市场的认可,许多知名电子品牌纷纷与Corstat Containers公司建立合作关系。随着订单量的不断增加,公司的规模逐渐扩大,生产线也更加完善。

DAICO公司的发展小趣事

DAICO公司深知品质的重要性,因此在生产过程中严格遵循国际标准和规范。公司不仅建立了完善的质量管理体系,还通过了多项国际认证,如ISO 9001等。这些认证证明了DAICO在产品质量和管理水平方面的实力,进一步提升了其在国际市场上的竞争力。

问答坊 | AI 解惑

为实现iGeneration构思远程信息系统个性化运输工具

跟许多人一样,我倾向于分三个阶段对发展中的市场和技术进行分析。首先是过去的趋势、成功和我们得到的教训;其次是我们现在面临的挑战;第三是,我是高度的乐观主义者,未来会发生各种可能性。 最近,在美国底特律举行的Telematics Update会上我有 ...…

查看全部问答>

AD6原理图编辑

第 3 章已经简要叙述了原理图设计的基本流程,本章将详细介绍如何在原理图上放置组件、原理图编辑器的使用和组件位置的编辑。 …

查看全部问答>

Embedded Software Development with C 中文版

Embedded Software Development with C 这本书有中文版的吗 请告知,谢谢…

查看全部问答>

cadence小问题!弱弱的问!

请教cadence画原理图时需要导入封装,我的主要芯片的封装都是自己通过向导做的 但是电容电阻这些封装应该不用自己做吧 我按照《cadence高速电路板设计与仿真》的介绍填上LED,但是生成网表后放置元件时报错 说找不到电容的封装 请问怎么解决这 ...…

查看全部问答>

求救:应用程序错误-0x00000000内存不能为written

只要打开应用程序就弹出   在线等 高分求救…

查看全部问答>

关于双网卡热备份

大家好?WIN2000下,双网卡热备份,也就是一个网卡坏了,另一个冗余网卡热切换,实现方案是什么?代码是什么?谢谢…

查看全部问答>

收到LPC1114样片及购买的EASYCORTEX-M3开发板

前几天收到了LPC1114的样片,要感谢SOSO。准备用此款芯片开发多功能电表,但是这个项目的时间比较靠后了。现在正在做一款手机测试电源,选择用LPC175X作为控制器,由于我从未用过过ARM,又申请不到开发板,为了尽快上手,所以让公司买了块EASYCORTE ...…

查看全部问答>

问一个LM3S库StellarisWare Graphics Library的问题

准备入手LM3S9B92,看了一些资料。 看了文档,StellarisWare Graphics Library这个库有对液晶屏的驱动,我看市面上的液晶屏有9320、9321、9325还有3225什么的驱动芯片,这个库都支持吗?TI的开发板上用的什么芯片呢? 谢谢大家。…

查看全部问答>