cancel
Showing results for 
Search instead for 
Did you mean: 

STM32U5xx: OCTOSPI (as QSPI) with regular QSPI transaction - for you

tjaekel
Lead

STM says: OCTOSPI can generate a "regular SPI" transaction. But is not true:
A "regular SPI transaction" means actually on OCTOSPI: a half-duplex SPI transaction (using just IO0, but for both directions).

I you want to generate a "regular" SPI transactions, as full-duplex ! (IO0 = MOSI, IO1 = MISO, bi-directional) - it is NOT possible.

OCTOSPI cannot do WRITE and READ at the same time (always just half-duplex), And the pins for OCTOSPI are NOT shared with a "regular SPI device" (like SPI1, SPI2, SPI3).

Here is a solution:

  • run the OCTOSPI as a SPI Master (only as TX, bits out on IO0 pin as MOSI)
  • configure another "regular SPI" device, e.g. SPI3, as a SPI3 Slave (in NCS SW mode: just connect SCK and receive via SPI3 MOSI: connect with IO1 on QSPI header: IO1 is MISO in this mode, luckily in "regular" OCTOSPI mode it is floating
  • now, the OCTOSPI generates a SPI TX (MOSI), provides the SCK for external device and signal is looped back to SPI3 Slave SCK.
    IO0 is MOSI: IO1 is not used on OCTOSPI but acts (connected) as SPI3 Slave MOSI (Slave RX), same pin on QSPI header.
  • run both devices in parallel ("listen via SPI3 Slave what comes back from extern slave device")

Now I have a shared use of the OCTOSPI pins (as QSPI), also like a "regular SPI" (e.g. changing to full-duplex, bi-directional SPI slave connected).

See my schematics for it at the end:
connect SCK from OCTOSPI Master to SPI3 Slave SCK and listen on OCTOSPI IO1 as SPI3 Slave MOSI (RX). It works (up to 40 MHz).
The project is here (for my own PCB, on NUCLEO board you need two flying wires):

https://github.com/tjaekel/NUCLEO-U5A5JZ-Q_QSPI 

Remark:

The OCTOSPI cannot generate just a transaction without CMD. So, the first data byte to send via OCTOSPI as "regular" SPI master goes into the CMD register. Now the following bytes to send can be the data part (no ADDR and no ALT bytes to send).

This makes it a bit tricky on SPI3 as Slave RX: the first two bytes come very fast together: one data byte is the CMD byte and then the 2nd data byte, without any gap on SCK signal.

So, my TX and RX loop looks like this:

 

	      do
	      {
	    	*((__IO uint8_t *)data_reg) = *hospi->pBuffPtr;

	        /* Wait till fifo threshold or transfer complete flags are set to read received data */
	        status = OSPI_WaitFlagStateUntilTimeout(hospi, (HAL_OSPI_FLAG_FT | HAL_OSPI_FLAG_TC), SET, tickstart, Timeout);

	        if (status != HAL_OK)
	        {
	          break;
	        }

	        if (i == 0)
	        {
	        	/* on first iteration we get CMD and one byte! */
	        	while ( ! __HAL_SPI_GET_FLAG(&hspi3, SPI_FLAG_RXP)) {;}
	        	*(hospi->pBuffPtr - 1) = SPI3->RXDR;
	        	while ( ! __HAL_SPI_GET_FLAG(&hspi3, SPI_FLAG_RXP)) {;}
	        	*hospi->pBuffPtr = SPI3->RXDR;
	        	i = 1;
	        }
	        else
	        {
	        	while ( ! __HAL_SPI_GET_FLAG(&hspi3, SPI_FLAG_RXP)) {;}
	        	*hospi->pBuffPtr = SPI3->RXDR;			//XXXX
	        }

	        hospi->pBuffPtr++;
	        hospi->XferCount--;
	      } while (hospi->XferCount > 0U);

 

See, that I am expecting to get two bytes at the beginning (CMD with data0 and regular data1), sent by the OCTOSPI TX when starting the transaction.

Schematics:

Here the schematics I use on my PCB (SPI3 is a Slave listener on OCTOSPI signals). On a NUCLEO board you need external wires to accomplish the same (see the pink traces under the STM MCU chip, on NUCLEO board as flying wires).

STM32U5A5_QSPI_schematics_2.png

Only this gives me a REAL "regular" SPI on OCTOSPI (with sharing the same pins).

1 ACCEPTED SOLUTION

Accepted Solutions
tjaekel
Lead

It works fine for me (except: SPI3 as Slave is not so fast as OCTOSPI can generate transactions, max. is 40 MHz).

View solution in original post

1 REPLY 1
tjaekel
Lead

It works fine for me (except: SPI3 as Slave is not so fast as OCTOSPI can generate transactions, max. is 40 MHz).