cancel
Showing results for 
Search instead for 
Did you mean: 

Fast SPI with large data on STM32U5 ( HAL vs register level)

Bertha
Associate III

Dear all,

Can someone help me on that topic ?

Goal :

I need to send a large amount of 8 bit via SPI as fast as possible (SPI display).

The frame buffer is around 160 000b so size need to be uint32_t.

Strategy :

Use SPI register to avoid 16bit size HAL limitation.

Use HAL_SPI_TRANSFERT as reference in terms of performance, register manipulation should give us a speed rate >= HAL.

Start with small framebuffer ie : uint8_t image[1000]

Environment:

I am working with a nucloSTM32U5 on SPI2 with no slave attached, but CLK and MOSI monitored.

See attached configuration

The code:

void xSPI_Send_Data( SPI_TypeDef *spi, uint8_t *pdata, uint32_t size)
{
 
  // Disable SPI2
  CLEAR_BIT(spi->CR1, SPI_CR1_SPE);
 
  
  // Set TSIZE to 0 (defaut value) for unknown size transfert 
  MODIFY_REG(spi->CR2, SPI_CR2_TSIZE, 0);
 
 
 
  // Enable SPI2
  if ((spi->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE) {
            // If disabled, I enable it
            SET_BIT(spi->CR1, SPI_CR1_SPE);
    }
 
  // Master transfert start
  SET_BIT(spi->CR1, SPI_CR1_CSTART);
 
  // Transfert in 8 bit Mode
 
  while (size > 0)
    {
      if(SPI_IsActiveFlag_TXP)
       {
          *(volatile uint8_t *)&spi->TXDR = *pdata;
          pdata += sizeof(uint8_t);
          size--;
          //HAL_Delay(10);
      }
 
    }
 
  // Disable SPI2
  CLEAR_BIT(spi->CR1, SPI_CR1_SPE);
 
}
 
 
uint8_t SPI_IsActiveFlag_TXP(SPI_TypeDef *SPIx)
{
  return ((READ_BIT(SPIx->SR, SPI_SR_TXP) == (SPI_SR_TXP)) ? 1 : 0);
}

Results :

Can't manage to get all the datas (see attached) and in terms of speed rate i am about 10-15%% faster then HAL library but with data corruption.

Next ? :

I tried to add some tests on the register code, datas are fine but the speed rate is divided by 2.

Can someone point me out what I am missing here ?

Thanks

7 REPLIES 7
MM..1
Chief II

Dont waste time with this hard chaos. Use Transmit_DMA.

		spi_init(word16bit);
		HAL_SPI_Transmit_DMA(&hspi, pBuff, Len); 

Bertha
Associate III

Thank for your answer, but I really want to understand what is missing.

If someone used SPI U5 registers can share there.

I mean you have more fails first

if(SPI_IsActiveFlag_TXP)

second

uint8_t SPI_IsActiveFlag_TXP(SPI_TypeDef *SPIx)
{
  return ((READ_BIT(SPIx->SR, SPI_SR_TXP) == (SPI_SR_TXP)) ? 1 : 0);
}

check if this code works and dont need !

TDK
Guru

Why do you think there's a 16-bit limitation in HAL? Word size for SPI can be 32-bits.

Code would be faster by writing 32-bits at once instead of 8 (or using DMA in the first place).

> if(SPI_IsActiveFlag_TXP)

This is nonsense, you're not calling the function. If you want to check the flag:

if (spi->SR & SPI_SR_TXP)

If you feel a post has answered your question, please click "Accept as Solution".
Bertha
Associate III

Thanks for pointing out my mistake.

I copy the code if someone needs it

void xSPI_Send_Data( SPI_TypeDef *spi, uint8_t *pdata, uint32_t size)
{
 
  // Disable SPI2
  CLEAR_BIT(spi->CR1, SPI_CR1_SPE);
 
 
  // Set TSIZE to 0 (defaut value) for unknown size transfert
  MODIFY_REG(spi->CR2, SPI_CR2_TSIZE, 0);
 
 
 
  // Enable SPI2
  if ((spi->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE) {
            // If disabled, I enable it
            SET_BIT(spi->CR1, SPI_CR1_SPE);
    }
 
  // Master transfert start
  SET_BIT(spi->CR1, SPI_CR1_CSTART);
 
  // Transfert in 8 bit Mode
 
  while (size > 0)
    {
      if (SPI_IsActiveFlag_TXP (spi))
       {
          *(volatile uint8_t *)&spi->TXDR = *pdata;
          pdata += sizeof(uint8_t);
          size--;
 
      }
 
    }
 
  // Wait last TxFIFO transmission complete
  while (!(SPI_IsActiveFlag_TXC (spi)))
    {
 
    }
  // Disable SPI2
  CLEAR_BIT(spi->CR1, SPI_CR1_SPE);
 
}
 
 
uint8_t SPI_IsActiveFlag_TXP(SPI_TypeDef *SPIx)
{
  return ((READ_BIT(SPIx->SR, SPI_SR_TXP) == (SPI_SR_TXP)) ? 1 : 0);
}
 
uint8_t
SPI_IsActiveFlag_TXC (SPI_TypeDef *SPIx)
{
  return ((READ_BIT(SPIx->SR, SPI_SR_TXC) == (SPI_SR_TXC)) ? 1 : 0);
}
 

I forgot also to wait TXC flag, before disable SPI.

Now it is working fine.

Bertha
Associate III

Thank again TDK,

Just a reply here concerning what I meant with the 16 bit HAL limitation:

I was not clear, HAL for U5 use TSIZE register and this register is 16bit, so TxXferCount max value is 65535.

You are right, 32bit can be used instead of 8bit, so you can trick it and send 4 times more bits, but still you are limited to 4 * 65535 bits.

If bigger data need, HAL_SPI can be call again ;)

Ah okay, it does appear to take the length as a 16-bit parameter even though it doesn't need to.

HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
 

DMA has a similar 65535 transaction limit on other families. Haven't played with the U5 at all, probably still there.

If you feel a post has answered your question, please click "Accept as Solution".