STM32CubeIDE 1.8.0
STM32F746-Disco
我正在学习 QuadSPI 并使用 C 在裸机中完成所有工作,它让我了解了硬件。
QSPI 闪存 IC,mouser,带数据表
问题的简短摘要:从 QuadSPI Flash 间接读取,数据线上没有
通信,Fifo 阈值标志始终设置。
我以前从未使用过QuadSPI,所以我阅读了STM32F746的参考手册,似乎或多或少清楚了,至少我准备尝试一下,它通常是这样工作的。
我使用在 STM32CubeIDE 中打开的 TouchGFX 生成的代码来获取 QuadSPI 的一些参数,并且在运行 TouchGFX 程序时我还使用了一个断点来检查我的 QuadSPI 寄存器是否具有相同或相似的值,以及是否没有重要的遗漏(因为 TouchGFX以不同方式使用 QuadSPI 闪存,其中之一,不是在间接模式下)。我确保我的 GPIO 配置相同,一切都已计时,等等。
所以,这是我设置这些东西的方法:
- void qspi_setup_indirect_mode(void){
- //NOR Flash MT25QL128ABA 128Mb=16MB
- /*
- * Control Register
- * Prescaler: Fclock = AHBclock/2
- * FIFO Threshold: FTF is set when 4 or more bytes available to be written to FIFO
- *
- * */
- QUADSPI->CR |= QUADSPI_CR_ABORT; //abort ongoing commands
- while(QUADSPI->CR & QUADSPI_CR_ABORT); //wait while aborted
- QUADSPI->CR = 0x00; //reset register
- QUADSPI->CR |= QUADSPI_CR_SSHIFT | (0x03 << QUADSPI_CR_FTHRES_Pos) | (0x01 << QUADSPI_CR_PRESCALER_Pos);
- /*
- * Device Configuraion register
- * Clock Mode 0 (default)
- * Chip Select High time 6 Cycles
- * Flash Size 16MB = 2^24 bytes
- *
- * */
- QUADSPI->DCR = 0x00; //reset
- QUADSPI->DCR |= (0x05 << QUADSPI_DCR_CSHT_Pos) | (23U << QUADSPI_DCR_FSIZE_Pos);
- /*
- * Communication configuration register
- * Address size 24 bits
- *
- * */
- QUADSPI->CCR = ((QUADSPI->CCR) & (~(0x03 << QUADSPI_CCR_ADSIZE_Pos))) | (0x02 << QUADSPI_CCR_ADSIZE_Pos);
- QUADSPI->CR |= QUADSPI_CR_EN; //enable QUADSPI
- }
这似乎反映了 TouchGFX QuadSPI 参数。
接下来,我在 QuadSPI 的单行上设置指令和数据,同时关闭地址、交替字节和虚拟周期。然后我设置间接读取模式,根据闪存 IC 的数据表设置我希望接收 20 个字节的闪存 ID,然后清除 QSPI 标志。接下来我加载指令本身——读取 ID 的命令——引入通信配置寄存器的指令位。根据参考手册,这应该会立即触发通信。接下来我的代码只是等到达到 fifo 阈值 - 4 个字节 - 到达,这样我就可以从数据寄存器中以 uint32_t 的形式一次读取它们。我现在不关心接下来的字节会发生什么,我不处理它们,当我看到我收到任何东西时我会担心它。
- void qspi_read_id(void){
- qspi_set_command_mode(QSPI_IMODE_1, QSPI_ADMODE_0, QSPI_ABMODE_0, 0x00, QSPI_DMODE_1);//set command mode, 1 data line for instruction, 1 data line for data
- QUADSPI->CCR &= ~QUADSPI_CCR_FMODE | (0x01 << QUADSPI_CCR_FMODE_Pos); //indirect read mode
- QUADSPI->DLR = (uint32_t) 19; //expect to receive 20 bytes
- QUADSPI->FCR |= QUADSPI_FCR_CTOF | QUADSPI_FCR_CSMF | QUADSPI_FCR_CTCF | QUADSPI_FCR_CTEF;
- QUADSPI->CCR = (MT25QL128ABA1EW9_COMMAND_READ_ID_1 << QUADSPI_CCR_INSTRUCTION_Pos); //must trigger command transmission
- while(!(QUADSPI->SR & QUADSPI_SR_FTF)); //wait until there are 4 bytes of data to read
- }
- void qspi_set_command_mode(uint8_t imode, uint8_t admode, uint8_t abmode, uint8_t dcyc, uint8_t dmode){
- /*
- * Communication configuration register
- * First, reset all mode values
- * Set new values
- * */
- QUADSPI->CCR = QUADSPI->CCR & ~(QUADSPI_CCR_IMODE) & ~(QUADSPI_CCR_ADMODE) & ~(QUADSPI_CCR_ABMODE) & ~(QUADSPI_CCR_DCYC) & ~(QUADSPI_CCR_DMODE);
- QUADSPI->CCR = QUADSPI->CCR | (imode << QUADSPI_CCR_IMODE_Pos) | (admode << QUADSPI_CCR_ADMODE_Pos) | (abmode << QUADSPI_CCR_ABMODE_Pos) | (dcyc << QUADSPI_CCR_DCYC_Pos) | (dmode << QUADSPI_CCR_DMODE_Pos);
- }
最后,我简单的小 main() 应该测试所有这些:
- #include "main.h"
- void system_hw_setup(void);
- int main(void) {
- system_hw_setup(); //initialize hardware
- uint8_t receivedQSPIdata[4];
- while (1) {
- system_msdelay(1000U);
- //BREAKPOINT HERE
- qspi_read_id();
- uint32_t temp = QUADSPI->DR;
- receivedQSPIdata[0] = temp & 0xFF;
- receivedQSPIdata[1] = (temp >> 8) & 0xFF;
- receivedQSPIdata[2] = (temp >> 16) & 0xFF;
- receivedQSPIdata[3] = (temp >> 24) & 0xFF;
- usart_dma_sendArray(USART1, receivedQSPIdata, sizeof(receivedQSPIdata));
- }
- }
system_hw_setup 初始化时钟和所有硬件、UART、DMA、NVIC、Systick 等,包括 qspi_setup_indirect_mode()。所有其他功能 100% 工作,包括 uart dma。
如果我在循环中放置一个断点,以便程序在每次调用 qspi_read_id() 之前暂停。在第一次调用 read_id 之前,QuadSPI->SR 状态寄存器中的唯一标志是 Fifo 阈值标志。如果我继续该程序,1 秒后我会在再次调用 read_id 之前暂停,并且我已经有标志“忙”、“传输完成”和相同的“fifo 阈值”。
D0 线绝对固定在 0v,示波器永远不会触发。片选在第一次调用 read_id 后变得疯狂,
即使 MCU 在断点处暂停也不会停止:
我显然配置错误了一些东西,但我没有主意。我阅读了一些关于这个主题的材料,也会继续研究,但我希望有人能指出我正确的方向。
0