匿名
未登录
登录
丢石头百科
搜索
查看“STM32CubeMX系列教程19:Quad-SPI”的源代码
来自丢石头百科
名字空间
页面
讨论
English
更多
更多
页面选项
查看
查看源代码
历史
←
STM32CubeMX系列教程19:Quad-SPI
因为以下原因,您没有权限编辑本页:
您所请求的操作仅限于该用户组的用户使用:
用户
您可以查看与复制此页面的源代码。
<b style="font-size: 14px; widows: auto; line-height: 16.8px; background-color: inherit;">一.Quad-SPI简介</b> <b style="background-color: inherit;"> </b> 在第十章和第十一章中,我们介绍了标准的SPI总线,SPI由四根线控制,NSS为片选,SCK为时钟信号线。MISO,MOSI为数据线,一根作为输入,一根作为输出。 [[File:184401w6y6byvybe6mdey6.png]] Quad-SPI,即四线SPI,由此可知其数据线比标准的SPI接口要多,最多支持四条数据线同时传输。连接单、双或四(条数据线) SPI Flash 存储介质。Quad-SPI总共有6根控制线:CS为片选,CLK为时钟信号线。IO0~IO3为数据线,可以发送数据也可以接收数据。 [[File:184402tprkrk92g92812g5.png]] <b style="background-color: inherit;">二.Quad-SPI 命令序列</b> <b style="background-color: inherit;"> </b> QUADSPI 通过命令与 Flash 通信 每条命令包括指令、地址、交替字节、空指令和数据这五个阶段 任一阶段均可跳过,但至少要包含指令、地址、交替字节或数据阶段之一。 nCS 在每条指令开始前下降,在每条指令完成后再次上升。 [[File:184402muqufqulvvplffpq.png]] <b style="background-color: inherit; font-size: 14px;">指令阶段</b> 这一阶段将发送一条8位指令到flash,指定待执行的类型。指令可以单线,双线或四线传输。 <b style="background-color: inherit; font-size: 14px;">地址阶段</b> 在地址阶段,将1-4字节发送到flash,指示操作地址,地址阶段可一次发送 1 位(在单线 SPI 模式中通过 IO0)、2 位(在双线 SPI 模式中通过 IO0/IO1 )或 4 位(在四线 SPI 模式中通过 IO0/IO1/IO2/IO3)。 <b style="background-color: inherit;">交替字节阶段</b> 在交替字节阶段,将 1-4 字节发送到 Flash,一般用于控制操作模式。可以通过可以单线,双线或四线传输。 <b style="background-color: inherit;"></b><b style="background-color: inherit;"></b><b style="font-size: 14px;">空指令周期阶段</b> 在空指令周期阶段,给定的 1-31个周期内不发送或接收任何数据,目的是当采用更高的时钟频率时,给 Flash 留出准备数据阶段的时间。 <b style="background-color: inherit;"></b><b style="font-size: 14px;">数据阶段</b> 在数据阶段,可从 Flash 接收或向其发送任意数量的字节。数据阶段如果发送数据IO口为输出,如果是接收数据则IO切换为输入,一次可发送 1 位(在单线 SPI 模式中通过 IO0)、2 位(在双线 SPI 模式中通过 IO0/IO1 )或 4 位(在四线 SPI 模式中通过 IO0/IO1/IO2/IO3)。 <b style="background-color: inherit;">三.新建工程</b> <b style="background-color: inherit;"> </b> <b style="background-color: inherit;"> 复制串口printf的工程,修改文件夹名。击STM32F746I.ioc打开STM32cubeMX的工程文件重新配置,QuadSPI模式选择Bank1四线SPI。 </b> <b style="background-color: inherit;"> </b> [[File:184402zf02tzvfuemftfv3.png]] 此时QUADSPI对应的IO口会被选中。 [[File:184403fdz1dlq8c1ycccpy.png]] [[File:184403ctmxe2kxhjh8jtmn.png]] [[File:184403skkkj66e3600kibo.png]] QUADSPI配置如下。时钟分频设置为2,故QSPI时钟 = 216M / (2+ 1) = 72MHz FIFO深度设置为4个字节,配置QSPI 在Flash 驱动信号后过半个CLK 周期才对Flash 驱动的数据采样。 Flash Size设置外部存储器大小,本实验以W25Q128FV芯片为例,大小为16MB(使用24位寻址),则设置为23。 [[File:184403plpz97e9zl9osoe1.png]] <b>四.应用程序</b> <b> </b> 生成报告以及代码,编译程序。在quadspi.c文件中可以看到初始化函数。在stm32f7xx_hal_qspic.h头文件中可以看到QSPI的操作函数。分别对应轮询,中断和DMA三种控制方式。 下面为W25QXX的驱动文件。下载并添加进工程中。(操作方式参照第十一章) <a class="attach" href="portal.php?mod=attachment&id=489" target="_blank">stm32746g_qspi.zip 在main.c文件中添加头文件 <syntaxhighlight lang="python"> /* USER CODE BEGIN Includes */ #include <string.h> #include "stm32746g_qspi.h" /* USER CODE END Includes */</string.h></syntaxhighlight> 声明变量: s_command为QSPI命令结构体,配置命令;pData存储读取ID值,rData,wData作为读写数据缓存 <syntaxhighlight lang="python"> <syntaxhighlight lang="python"> /* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ QSPI_CommandTypeDef s_command; uint8_t pData[3]; uint8_t wData[0x100]; uint8_t rData[0x100]; uint32_t i; /* USER CODE END PV */</syntaxhighlight> <code style="font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; background-color: inherit;"> </syntaxhighlight> 在main函数中添加应用程序,第一部分初始化W25Q128FV芯片,第二部分分别用单线,双线和四线三种模式读设备ID。第三部分则是读写擦除芯片操作实验。 <syntaxhighlight lang="python"> <syntaxhighlight lang="python"> /* USER CODE BEGIN 2 */ printf("W25Q128FV QuadSPI Test ....\r\n\r\n"); /*##-1- Initialize W25Q128FV ###########################################*/ BSP_QSPI_Init(); /*##-2-Read Device ID Test ###########################################*/ /* Read Manufacture/Device ID */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = READ_ID_CMD; s_command.AddressMode = QSPI_ADDRESS_1_LINE; s_command.AddressSize = QSPI_ADDRESS_24_BITS; s_command.Address = 0x000000; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_1_LINE; s_command.DummyCycles = 0; s_command.NbData = 2; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } if (HAL_QSPI_Receive(&hqspi, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } printf("SPI I/0 Read Device ID : 0x%2X 0x%2X\r\n",pData[0],pData[1]); /* Read Manufacture/Device ID Dual I/O*/ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = DUAL_READ_ID_CMD; s_command.AddressMode = QSPI_ADDRESS_2_LINES; s_command.AddressSize = QSPI_ADDRESS_24_BITS; s_command.Address = 0x000000; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_2_LINES; s_command.AlternateBytesSize= QSPI_ALTERNATE_BYTES_8_BITS; s_command.AlternateBytes = 0; s_command.DataMode = QSPI_DATA_2_LINES; s_command.DummyCycles = 0; s_command.NbData = 4; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } if (HAL_QSPI_Receive(&hqspi, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } printf("Dual I/O Read Device ID : 0x%2X 0x%2X\r\n",pData[0],pData[1]); /* Read Manufacture/Device ID Quad I/O*/ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = QUAD_READ_ID_CMD; s_command.AddressMode = QSPI_ADDRESS_4_LINES; s_command.AddressSize = QSPI_ADDRESS_24_BITS; s_command.Address = 0x000000; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_4_LINES; s_command.AlternateBytesSize= QSPI_ALTERNATE_BYTES_8_BITS; s_command.AlternateBytes = 0x00; s_command.DataMode = QSPI_DATA_4_LINES; s_command.DummyCycles = 4; s_command.NbData = 2; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } if (HAL_QSPI_Receive(&hqspi, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } printf("Quad I/O Read Device ID : 0x%2X 0x%2X\r\n",pData[0],pData[1]); /* Read JEDEC ID */ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = READ_JEDEC_ID_CMD; s_command.AddressMode = QSPI_ADDRESS_NONE; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; s_command.DataMode = QSPI_DATA_1_LINE; s_command.DummyCycles = 0; s_command.NbData = 3; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } if (HAL_QSPI_Receive(&hqspi, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } printf("Read JEDEC ID : 0x%2X 0x%2X 0x%2X\r\n\r\n",pData[0],pData[1],pData[2]); /*##-3-QSPI Erase/Write/Read Test ###########################################*/ /* fill buffer */ for(i =0;i<0x100;i ++) { wData[i] = i; rData[i] = 0; } if(BSP_QSPI_Erase_Block(0) == QSPI_OK) printf(" QSPI Erase Block ok\r\n"); else Error_Handler(); if(BSP_QSPI_Write(wData,0x00,0x100)== QSPI_OK) printf(" QSPI Write ok\r\n"); else Error_Handler(); if(BSP_QSPI_Read(rData,0x00,0x100)== QSPI_OK) printf(" QSPI Read ok\r\n\r\n"); else Error_Handler(); printf("QSPI Read Data : \r\n"); for(i =0;i<0x100;i++) printf("0x%02X ",rData[i]); printf("\r\n\r\n"); for(i =0;i<0x100;i++) if(rData[i] != wData[i])printf("0x%02X 0x%02X ",wData[i],rData[i]); printf("\r\n\r\n"); /* check date */ if(memcmp(wData,rData,0x100) == 0 ) printf(" W25Q128FV QuadSPI Test OK\r\n"); else printf(" W25Q128FV QuadSPI Test False\r\n"); /* USER CODE END 2 */</syntaxhighlight> <code style="font-family: Monaco, Consolas, Courier, 'Lucida Console', monospace; color: rgb(0, 130, 0) !important; background-color: inherit;"> 将W25QXX DataFlash Board模块插入到Open746I开发板I2C1中,编译程序并下载到开发板。打开串口调试助手。设置波特率为115200。串口助手上会显示如下信息。 </syntaxhighlight> <b style="background-color: inherit;">五.程序讲解</b> <b style="background-color: inherit;"> </b> <b style="background-color: inherit;"> 现在以四线读设备ID为例讲解QSPI如何进行一次读写操作。如下为四线</b>读制造商/设备ID命令(94H) [[File:184403sicq5o57mtxm0sdc.png]] 程序中先根据上面时序配置s_command命令结构体, * 命令为1线,命令为QUAD_READ_ID_CMD,在w25q128fv.h头文件中宏定义为0x94。* 地址为4线,地址长度为24位,地址为0x000000。* 交替字节阶段设置为4线,长度为8位,备用字节为0x00。* 空指令阶段为4个时钟周期* 数据为4线,字节为两个字节。 程序中先通过HAL_QSPI_Command()将命令发送出去,然后通过HAL_QSPI_Receive()命令接收数据。即完成一次读操作,如果是写操作,同样是先配置命令结构体,然后发送命令,最后通过HAL_QSPI_Transmit()命令发送数据。 </code></code> <syntaxhighlight lang="python"> <code style="font-family: Monaco, Consolas, Courier, 'Lucida Console', monospace; background-color: inherit;"> <syntaxhighlight lang="python"> /* Read Manufacture/Device ID Quad I/O*/ s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; s_command.Instruction = QUAD_READ_ID_CMD; s_command.AddressMode = QSPI_ADDRESS_4_LINES; s_command.AddressSize = QSPI_ADDRESS_24_BITS; s_command.Address = 0x000000; s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_4_LINES; s_command.AlternateBytesSize= QSPI_ALTERNATE_BYTES_8_BITS; s_command.AlternateBytes = 0x00; s_command.DataMode = QSPI_DATA_4_LINES; s_command.DummyCycles = 4; s_command.NbData = 2; s_command.DdrMode = QSPI_DDR_MODE_DISABLE; s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } if (HAL_QSPI_Receive(&hqspi, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) { Error_Handler(); } printf("Quad I/O Read Device ID : 0x%2X 0x%2X\r\n",pData[0],pData[1]);</syntaxhighlight> 关于W25Q128fv的读写擦除等驱动函数可以查看stm32746g-qspi.c文件,这里不再详细讲解。 </syntaxhighlight></code>
返回至
STM32CubeMX系列教程19:Quad-SPI
。
导航
导航
首页
最近更改
随机页面
MediaWiki帮助
首页
首页
树莓派
主机
配件包
外壳
键鼠
电源
扩展板
显示屏
墨水屏
摄像模块
通信模块
继电器
电机驱动板
游戏机
产品分类
树莓派
Arduino
micro:bit
STM32
Espressif
WiFi模块
蓝牙模块
无线模块
LoRa模块
4G模块
GSM
GPRS
以太网
导航模块
北斗卫星
GPS
LCD
墨水屏
OLED
摄像头
USB模块
串口模块
RS232
RS485
CAN
传感器
温度模块
湿度模块
气压模块
继电器
电机模块
指纹模块
电平转换
音频模块
编程器
Wiki工具
Wiki工具
特殊页面
页面工具
页面工具
用户页面工具
更多
链入页面
相关更改
页面信息
页面日志