在用QuadSPI,在裸机环境下进行操作。
问题是:从QuadSPI Flash进行间接读取时,数据线上无通信,Fifo阈值标志始终被置位。
用了TouchGFX生成的代码(在STM32CubeIDE中打开),并且在运行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的单线指令和数据模式,而地址、交替字节和空周期均关闭。然后我设置间接读取模式,指定期望接收20字节的Flash ID(根据Flash IC的数据手册),并清除QSPI标志。将指令本身(读取ID的命令)加载到通信配置寄存器的INSTRUCTION位中。根据参考手册,这应该立即触发通信。代码等待直到达到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);
}
最后,主函数用于测试所有功能:
c
#include "main.h"
void system_hw_setup(void);
#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()。所有其他功能(包括UART DMA)100%正常工作。
如果我在循环中设置一个断点,使程序在每次调用qspi_read_id()之前暂停。在第一次调用read_id之前,QuadSPI->SR状态寄存器中唯一的标志是Fifo阈值标志。如果继续运行程序,1秒后我会再次在调用read_id之前暂停,此时我已经有了“busy”、“transfer complete”以及相同的“fifo threshold”标志。
|
|