cancel
Showing results for 
Search instead for 
Did you mean: 

Quad-SPI indirect read mode without address, dummy cycles, and instruction words

alexborysevych9
Associate II

Hello ST community,

I have some troubles using Quad-SPI interface in STM32H7 micro.

I need to communicate with a custom part using quad SPI mode (4 data lines). The interface is configured for indirect mode and DMA is enabled.

In a super-simplified case I need to execute two transactions sequentially:

1. Send address byte, send two dummy cycles and read back one byte.

2. Read just one byte (no address, dummy cycles and instruction words)

The first transaction works fine all the time.

The second transaction failed in multiple ways. In different code variants, I was able to reproduce application crashes, or producing different than intended number of clock cycles during the bus transaction, or the completion interrupt is never fired.

Minimal working example:

uint8_t data_rx_ready = 0;
uint8_t data_packet_rx[16];
 
void TestRead_QuadSPI()
{
  QSPI_CommandTypeDef cmd;
  HAL_StatusTypeDef res;
 
  // FIRST TRANSACTION: address byte, dummy byte (two cycles) and one data byte to read
  
  cmd.AddressMode = QSPI_ADDRESS_4_LINES;
  cmd.AddressSize = QSPI_ADDRESS_8_BITS;
  cmd.Address = 0x5A; 
  cmd.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
  cmd.AlternateBytesSize = QSPI_ALTERNATE_BYTES_8_BITS;
  cmd.AlternateBytes = 0;
  cmd.DataMode = QSPI_DATA_4_LINES;
  cmd.DummyCycles = 2;
  cmd.SIOOMode = QSPI_SIOO_INST_ONLY_FIRST_CMD;
  cmd.DdrMode = QSPI_DDR_MODE_DISABLE;
  cmd.DdrHoldHalfCycle = 0;
  cmd.NbData = 1;
  cmd.InstructionMode = QSPI_INSTRUCTION_NONE;
  cmd.Instruction = 0;
  
  data_rx_ready = 0; // data_rx_ready is set in HAL_QSPI_RxCpltCallback
  HAL_QSPI_Command(&hqspi, &cmd, 5000);
  HAL_QSPI_Receive_DMA(&hqspi, data_packet_rx); 
  while (data_rx_ready == 0) ; // block while RX data is not ready
  
  // SECOND TRANSACTION: only one more byte to read
  
  cmd.AddressMode = QSPI_ADDRESS_NONE; // no address
  cmd.DummyCycles = 0; // no dummy bytes
  
  data_rx_ready = 0; // data_rx_ready is set in HAL_QSPI_RxCpltCallback
  HAL_QSPI_Command(&hqspi, &cmd, 5000); 
  HAL_QSPI_Receive_DMA(&hqspi, data_packet_rx); 
  while (data_rx_ready == 0) ; // block while RX data is not ready -- application hangs here!!
}
 
// this is override of callback to indicate that RX transfer is complete
void HAL_QSPI_RxCpltCallback(QSPI_HandleTypeDef *hqspi)
{
  data_rx_ready = 1;
}

The call of TestRead_QuadSPI() function never returns and application hangs at the last line of the function, which means that the last transaction is never completed.

But using the logic analyzer, I actually can see two clock cycles of the second transaction. So the hardware actually does something...

By troubleshooting deeper, I came to the following lines in HAL_QSPI_Receive_DMA function

/* QSPI need to be configured to indirect mode before starting
         the MDMA to avoid primatury triggering for the MDMA transfert */
      /* Configure QSPI: CCR register with functional as indirect read */
      MODIFY_REG(hqspi->Instance->CCR, QUADSPI_CCR_FMODE, QSPI_FUNCTIONAL_MODE_INDIRECT_READ); --- this actually starts the second transaction!!
 
      /* Start the transfer by re-writing the address in AR register */
      WRITE_REG(hqspi->Instance->AR, addr_reg);

I think the root cause of this behavior is in the register QUADSPI_CCR. Writing to this register will start new transfer in some particular peripheral settings. And seems like my second transaction is that case. The following is from the user manual:

0690X000009jAfyQAE.png

This is section 22.3.12 "QUADSPI usage" / "Indirect mode procedure" of the reference manual.

Thus, it does make sense that the transaction starts with writing to the QUADSPI_CCR register. However, it seems this particular use case is not implemented properly in HAL library, because it is assumed that an address byte is always being transmitted.

So I guess, my question is: how to perform indirect read without having instruction, address, alternative and dummy bytes in the transactions  (i.e. data bytes readout only) and use DMA?

Thank you for any thoughts!

I'm attaching Cube file and my main.c for the reference.

Processor: STM32H743ZITx

Board: Nucleo-H743ZI

Driver version: STM32Cube FW_H7 V1.4.0

Compiler: MDK-Lite Version 5.28.0.0

1 ACCEPTED SOLUTION

Accepted Solutions
Andreas Bolsch
Lead II

Check errata sheet ES0392, Rev. 6, 2.6.3.

View solution in original post

6 REPLIES 6
Andreas Bolsch
Lead II

Check errata sheet ES0392, Rev. 6, 2.6.3.

AVI-crak
Senior

Your program code does not make sense. External memory has its own unique documentation, all the answers you need to look for there. But you did not specify the chip used!

OP says it is a custom part using the interface, so think FPGA or CPLD

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Wow! Thank you so much for 100% accurate answer! Now it is clear.

I will leave it here for the future:

0690X000009jGy3QAE.png

I wanted to say that external memory chips do not have read options without a command and address.

The qspi interface was created for external memory, any memory has an address. Transmission command + address - causes the internal trigger of the logic to receive data. It is impossible to read in any other way - this is tough logic while saving transistors. The documentation indicates this.

I used qspi to read the AD9288BSTZ-100 at 100 MHz in DDR mode. Without transmitting the command and address - the data was not read. I used a simple RC delay circuit to turn on intermediate buffers while the address and command are being transmitted. While recording, you can’t access the fast memory - it will fail.

Thank you for your reply, I appreciate it too.

Unfortunately in my case I'm communicating with FPGA, so the protocol is not a real regular Quad SPI intended for memory chips.