完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
|
|
相关推荐
|
|
|
Quad-SPI,即四线SPI,由此可知其数据线比标准的SPI接口要多,最多支持四条数据线同时传输。
连接单、双或四(条数据线) SPI Flash 存储介质。Quad-SPI总共有6根控制线:CS为片选,CLK为时钟信号线。IO0~IO3为数据线,可以发送数据也可以接收数据。 file:///C:/Users/Administrator/AppData/Local/YNote/data/qq05E2D92FFCC85611A0CBEB4448FFA27E/d8ae71fb49fb4ca691bd0199ffefc3ce/clipboard.png |
|
|
|
|
|
|
|
|
二.Quad-SPI 命令序列
QUADSPI 通过命令与 Flash 通信 每条命令包括指令、地址、交替字节、空指令和数据这五个阶段 任一阶段均可跳过,但至少要包含指令、地址、交替字节或数据阶段之一。 nCS 在每条指令开始前下降,在每条指令完成后再次上升。 |
|
|
|
|
|
|
|
|
指令阶段
这一阶段将发送一条8位指令到flash,指定待执行的类型。指令可以单线,双线或四线传输。 地址阶段 在地址阶段,将1-4字节发送到flash,指示操作地址,地址阶段可一次发送 1 位(在单线 SPI 模式中通过 IO0)、2 位(在双线 SPI 模式中通过 IO0/IO1 )或 4 位(在四线 SPI 模式中通过 IO0/IO1/IO2/IO3)。 交替字节阶段 在交替字节阶段,将 1-4 字节发送到 Flash,一般用于控制操作模式。可以通过可以单线,双线或四线传输。 空指令周期阶段 在空指令周期阶段,给定的 1-31个周期内不发送或接收任何数据,目的是当采用更高的时钟频率时,给 Flash 留出准备数据阶段的时间。 数据阶段 在数据阶段,可从 Flash 接收或向其发送任意数量的字节。数据阶段如果发送数据IO口为输出,如果是接收数据则IO切换为输入,一次可发送 1 位(在单线 SPI 模式中通过 IO0)、2 位(在双线 SPI 模式中通过 IO0/IO1 )或 4 位(在四线 SPI 模式中通过 IO0/IO1/IO2/IO3)。 |
|
|
|
|
|
|
|
|
三.新建工程
复制串口printf的工程,修改文件夹名。击STM32F746I.ioc打开STM32cubeMX的工程文件重新配置,QuadSPI模式选择Bank1四线SPI。 file:///C:/Users/Administrator/AppData/Local/YNote/data/qq05E2D92FFCC85611A0CBEB4448FFA27E/1fd43f860796433991e30efe538d56fd/clipboard.png 此时QUADSPI对应的IO口会被选中。 |
|
|
|
|
|
|
|
|
QUADSPI配置如下。时钟分频设置为2,故QSPI时钟 = 216M / (2+ 1) = 72MHz
FIFO深度设置为4个字节,配置QSPI 在Flash 驱动信号后过半个CLK 周期才对Flash 驱动的数据采样。 Flash Size设置外部存储器大小,本实验以W25Q128FV芯片为例,大小为16MB(使用24位寻址),则设置为23。 file:///C:/Users/Administrator/AppData/Local/YNote/data/qq05E2D92FFCC85611A0CBEB4448FFA27E/eb2a7c567b974c809b073cfef202ef5c/clipboard.png |
|
|
|
|
|
|
|
|
本帖最后由 lee_st 于 2016-7-17 11:20 编辑
四.应用程序 生成报告以及代码,编译程序。在quadspi.c文件中可以看到初始化函数。在stm32f7xx_hal_qspic.h头文件中可以看到QSPI的操作函数。分别对应轮询,中断和DMA三种控制方式。 下面为W25QXX的驱动文件。下载并添加进工程中。(操作方式参照第十一章) file:///C:/Users/Administrator/AppData/Local/YNote/data/qq05E2D92FFCC85611A0CBEB4448FFA27E/ae9fc63596d14771b05827f7a8a2fdb0/attachment.png?1462271806030file:///C:/Users/Administrator/AppData/Local/YNote/data/qq05E2D92FFCC85611A0CBEB4448FFA27E/5c611c791bf1411d88a3db0c895c08b5/attachment.png?1462271806031file:///C:/Users/Administrator/AppData/Local/YNote/data/qq05E2D92FFCC85611A0CBEB4448FFA27E/8ff6aa59959b47cd9ae4a41eb144ac6a/attachment.png?1462271806032 stm32746g_qspi.zip 在main.c文件中添加头文件 1 /* USER CODE BEGIN Includes */ 2 #include 3 #include "stm32746g_qspi.h" 4 /* USER CODE END Includes */ |
|
|
|
|
|
|
|
|
声明变量: s_command为QSPI命令结构体,配置命令;pData存储读取ID值,rData,wData作为读写数据缓存
01 /* USER CODE BEGIN PV */ 02 /* Private variables ---------------------------------------------------------*/ 03 QSPI_CommandTypeDef s_command; 04 uint8_t pData[3]; 05 06 uint8_t wData[0x100]; 07 uint8_t rData[0x100]; 08 09 uint32_t i; 10 /* USER CODE END PV */ |
|
|
|
|
|
|
|
|
在main函数中添加应用程序,第一部分初始化W25Q128FV芯片,第二部分分别用单线,双线和四线三种模式读设备ID。第三部分则是读写擦除芯片操作实验。
001 /* USER CODE BEGIN 2 */ 002 printf("W25Q128FV QuadSPI Test ....rnrn"); 003 004 /*##-1- Initialize W25Q128FV ###########################################*/ 005 BSP_QSPI_Init(); 006 007 /*##-2-Read Device ID Test ###########################################*/ 008 /* Read Manufacture/Device ID */ 009 s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; 010 s_command.Instruction = READ_ID_CMD; 011 s_command.AddressMode = QSPI_ADDRESS_1_LINE; 012 s_command.AddressSize = QSPI_ADDRESS_24_BITS; 013 s_command.Address = 0x000000; 014 s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 015 s_command.DataMode = QSPI_DATA_1_LINE; 016 s_command.DummyCycles = 0; 017 s_command.NbData = 2; 018 s_command.DdrMode = QSPI_DDR_MODE_DISABLE; 019 s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 020 s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 021 022 if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) 023 { 024 Error_Handler(); 025 } 026 if (HAL_QSPI_Receive(&hqspi, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) 027 { 028 Error_Handler(); 029 } 030 printf("SPI I/0 Read Device ID : 0x%2X 0x%2Xrn",pData[0],pData[1]); 031 032 033 /* Read Manufacture/Device ID Dual I/O*/ 034 s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; 035 s_command.Instruction = DUAL_READ_ID_CMD; 036 s_command.AddressMode = QSPI_ADDRESS_2_LINES; 037 s_command.AddressSize = QSPI_ADDRESS_24_BITS; 038 s_command.Address = 0x000000; 039 s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_2_LINES; 040 s_command.AlternateBytesSize= QSPI_ALTERNATE_BYTES_8_BITS; 041 s_command.AlternateBytes = 0; 042 s_command.DataMode = QSPI_DATA_2_LINES; 043 s_command.DummyCycles = 0; 044 s_command.NbData = 4; 045 s_command.DdrMode = QSPI_DDR_MODE_DISABLE; 046 s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 047 s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 048 049 if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) 050 { 051 Error_Handler(); 052 } 053 if (HAL_QSPI_Receive(&hqspi, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) 054 { 055 Error_Handler(); 056 } 057 printf("Dual I/O Read Device ID : 0x%2X 0x%2Xrn",pData[0],pData[1]); 058 059 /* Read Manufacture/Device ID Quad I/O*/ 060 s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; 061 s_command.Instruction = QUAD_READ_ID_CMD; 062 s_command.AddressMode = QSPI_ADDRESS_4_LINES; 063 s_command.AddressSize = QSPI_ADDRESS_24_BITS; 064 s_command.Address = 0x000000; 065 s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_4_LINES; 066 s_command.AlternateBytesSize= QSPI_ALTERNATE_BYTES_8_BITS; 067 s_command.AlternateBytes = 0x00; 068 s_command.DataMode = QSPI_DATA_4_LINES; 069 s_command.DummyCycles = 4; 070 s_command.NbData = 2; 071 s_command.DdrMode = QSPI_DDR_MODE_DISABLE; 072 s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 073 s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 074 075 if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) 076 { 077 Error_Handler(); 078 } 079 if (HAL_QSPI_Receive(&hqspi, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) 080 { 081 Error_Handler(); 082 } 083 printf("Quad I/O Read Device ID : 0x%2X 0x%2Xrn",pData[0],pData[1]); 084 085 /* Read JEDEC ID */ 086 s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; 087 s_command.Instruction = READ_JEDEC_ID_CMD; 088 s_command.AddressMode = QSPI_ADDRESS_NONE; 089 s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; 090 s_command.DataMode = QSPI_DATA_1_LINE; 091 s_command.DummyCycles = 0; 092 s_command.NbData = 3; 093 s_command.DdrMode = QSPI_DDR_MODE_DISABLE; 094 s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 095 s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 096 097 if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) 098 { 099 Error_Handler(); 100 } 101 if (HAL_QSPI_Receive(&hqspi, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) 102 { 103 Error_Handler(); 104 } 105 printf("Read JEDEC ID : 0x%2X 0x%2X 0x%2Xrnrn",pData[0],pData[1],pData[2]); 106 107 108 /*##-3-QSPI Erase/Write/Read Test ###########################################*/ 109 /* fill buffer */ 110 for(i =0;i<0x100;i ++) 111 { 112 wData[i] = i; 113 rData[i] = 0; 114 } 115 116 if(BSP_QSPI_Erase_Block(0) == QSPI_OK) 117 printf(" QSPI Erase Block okrn"); 118 else 119 Error_Handler(); 120 121 if(BSP_QSPI_Write(wData,0x00,0x100)== QSPI_OK) 122 printf(" QSPI Write okrn"); 123 else 124 Error_Handler(); 125 126 if(BSP_QSPI_Read(rData,0x00,0x100)== QSPI_OK) 127 printf(" QSPI Read okrnrn"); 128 else 129 Error_Handler(); 130 131 printf("QSPI Read Data : rn"); 132 for(i =0;i<0x100;i++) 133 printf("0x%02X ",rData[i]); 134 printf("rnrn"); 135 136 for(i =0;i<0x100;i++) 137 if(rData[i] != wData[i])printf("0x%02X 0x%02X ",wData[i],rData[i]); 138 printf("rnrn"); 139 /* check date */ 140 if(memcmp(wData,rData,0x100) == 0 ) 141 printf(" W25Q128FV QuadSPI Test OKrn"); 142 else 143 printf(" W25Q128FV QuadSPI Test Falsern"); 144 /* USER CODE END 2 */ 将W25QXX DataFlash Board模块插入到Open746I开发板I2C1中,编译程序并下载到开发板。打开串口调试助手。设置波特率为115200。串口助手上会显示如下信息。 |
|
|
|
|
|
|
|
|
五.程序讲解
现在以四线读设备ID为例讲解QSPI如何进行一次读写操作。如下为四线读制造商/设备ID命令(94H) [size=1em] |
|
|
|
|
|
|
|
|
程序中先根据上面时序配置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()命令发送数据。 01 /* Read Manufacture/Device ID Quad I/O*/ 02 s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE; 03 s_command.Instruction = QUAD_READ_ID_CMD; 04 s_command.AddressMode = QSPI_ADDRESS_4_LINES; 05 s_command.AddressSize = QSPI_ADDRESS_24_BITS; 06 s_command.Address = 0x000000; 07 s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_4_LINES; 08 s_command.AlternateBytesSize= QSPI_ALTERNATE_BYTES_8_BITS; 09 s_command.AlternateBytes = 0x00; 10 s_command.DataMode = QSPI_DATA_4_LINES; 11 s_command.DummyCycles = 4; 12 s_command.NbData = 2; 13 s_command.DdrMode = QSPI_DDR_MODE_DISABLE; 14 s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY; 15 s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; 16 17 if (HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) 18 { 19 Error_Handler(); 20 } 21 if (HAL_QSPI_Receive(&hqspi, pData, HAL_QPSI_TIMEOUT_DEFAULT_VALUE) != HAL_OK) 22 { 23 Error_Handler(); 24 } 25 printf("Quad I/O Read Device ID : 0x%2X 0x%2Xrn",pData[0],pData[1]); 关于W25Q128fv的读写擦除等驱动函数可以查看stm32746g-qspi.c文件,这里不再详细讲解。 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
552 浏览 0 评论
706 浏览 0 评论
883 浏览 0 评论
839 浏览 0 评论
RT-Thread与英飞凌(infineon)合作得板子PSOC 6 板子学习
775 浏览 0 评论
【youyeetoo X1 windows 开发板体验】少儿AI智能STEAM积木平台
17069 浏览 31 评论
/9
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-12-15 06:58 , Processed in 0.852132 second(s), Total 85, Slave 69 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191

淘帖