历史上的今天
今天是: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接口的使用需要
硬件实现
寄存器配置SPI设置
波特率发生器配置SCLK
MOSI、MISO通过移位寄存器进行收发数据,接收数据即将数据从移位寄存器中复制到RxFIFO;发送数据即将数据放入TxFIFO后送入移位寄存器
主控制逻辑电路和通信控制电路调配相关收发过程
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
软件配置
在CubeMX中根据外设IC配置GPIO复用和SPI相关设定
CubeMX会使能外设时钟、配置SPI模式、地址、速率等参数并使能SPI外设;模式设定与f4设定基本类似,可参考【STM32F4外设配置速查总线协议部分】
编写对应外设IC的驱动程序
设置检验程序,上电后检验驱动程序及外设连接情况
编写应用程序
STM32F7/H7中的QSPI实现
QUADSPI主要用于控制SPI FLASH器件(只要满足QSPI时序就可以控制其他器件),工作在以下三种模式:
间接模式:使用QUADSPI寄存器执行全部操作
状态轮询模式:周期性轮询外部FLASH状态寄存器,如果为1(擦除/烧写完毕)则引发中断
内存映射模式:外部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数据手册
软件配置
基本配置同上
外部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个数据
史海拾趣
|
跟许多人一样,我倾向于分三个阶段对发展中的市场和技术进行分析。首先是过去的趋势、成功和我们得到的教训;其次是我们现在面临的挑战;第三是,我是高度的乐观主义者,未来会发生各种可能性。 最近,在美国底特律举行的Telematics Update会上我有 ...… 查看全部问答> |
|
Embedded Software Development with C 中文版 Embedded Software Development with C 这本书有中文版的吗 请告知,谢谢… 查看全部问答> |
|
请教cadence画原理图时需要导入封装,我的主要芯片的封装都是自己通过向导做的 但是电容电阻这些封装应该不用自己做吧 我按照《cadence高速电路板设计与仿真》的介绍填上LED,但是生成网表后放置元件时报错 说找不到电容的封装 请问怎么解决这 ...… 查看全部问答> |
|
收到LPC1114样片及购买的EASYCORTEX-M3开发板 前几天收到了LPC1114的样片,要感谢SOSO。准备用此款芯片开发多功能电表,但是这个项目的时间比较靠后了。现在正在做一款手机测试电源,选择用LPC175X作为控制器,由于我从未用过过ARM,又申请不到开发板,为了尽快上手,所以让公司买了块EASYCORTE ...… 查看全部问答> |
|
问一个LM3S库StellarisWare Graphics Library的问题 准备入手LM3S9B92,看了一些资料。 看了文档,StellarisWare Graphics Library这个库有对液晶屏的驱动,我看市面上的液晶屏有9320、9321、9325还有3225什么的驱动芯片,这个库都支持吗?TI的开发板上用的什么芯片呢? 谢谢大家。… 查看全部问答> |




