ST意法半导体
直播中

一刀两断

9年用户 1067经验值
私信 关注
[问答]

STM32F746-Disco从QuadSPI Flash间接读取数据失败是哪里出了问题呢

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 在断点处暂停也不会停止:

我显然配置错误了一些东西,但我没有主意。我阅读了一些关于这个主题的材料,也会继续研究,但我希望有人能指出我正确的方向。


回帖(1)

李凤英

2022-12-8 16:25:21
我仍然不知道,我做错了什么,显然是某处配置错误,但我设法解决了。我跳过了时钟启用和 GPIO 配置,我确信它们是正确的,并且我只在初始化部分复制了一对代码,毕竟我只需要看到第一个传输就知道它在工作。我必须修改该代码以适合我的闪存 IC。这是我的有效代码(我确定了定期交流的范围):


  •         // QSPI peripheral initialization.
  •         // Set Flash size; 128Mb = 16MB = 2^(23+1) bytes.
  •         QUADSPI->DCR |= (23 << QUADSPI_DCR_FSIZE_Pos);
  •         // Set 1-wire data mode with 24-bit addressing.
  •         QUADSPI->CCR |= ((2 << QUADSPI_CCR_ADSIZE_Pos) | (1 << QUADSPI_CCR_IMODE_Pos));

  •         // Wait an extra half-cycle to read, and set a clock prescaler of 2+1=3.
  •         QUADSPI->CR |= ( QUADSPI_CR_SSHIFT | (2 << QUADSPI_CR_PRESCALER_Pos));
  •         // Enable the peripheral.
  •         QUADSPI->CR |= ( QUADSPI_CR_EN);

  •         // Set the 'enter QSPI mode' instruction.
  •         QUADSPI->CCR |= (MT25QL128ABA1EW9_COMMAND_ENTER_QUAD_IO_MODE << QUADSPI_CCR_INSTRUCTION_Pos);
  •         // Wait for the transaction to complete, and disable the peripheral.
  •         while ( QUADSPI->SR & QUADSPI_SR_BUSY) {
  •         };
  •         QUADSPI->CR &= ~( QUADSPI_CR_EN);

它的评论很差,因为它是文章的复制粘贴。但它确实有效,我在循环中定期调用它,我看到东西在我的示波器上跳跃,芯片选择上没有疯狂的波形。我想我现在要退后一步,想想我最初做错了什么,然后对代码进行一些设计。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分