cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7 SPI TXP flag not resetting

DGupt
Associate III

Hi Everyone

I have a very strange issue in the SPI of my STM32H745.

Consider following information

0) No Master present on the Bus

1) SPI5 is configured in slave.

2) No interrupts, no DMA just polling

3) Following is the initialization code (FIFO is set to One byte)

STATIC void MX_SPI5_Init(void)
{
 
    /* USER CODE BEGIN SPI5_Init 0 */
 
    /* USER CODE END SPI5_Init 0 */
 
    /* USER CODE BEGIN SPI5_Init 1 */
 
    /* USER CODE END SPI5_Init 1 */
    /* SPI5 parameter configuration*/
    hspi5.Instance = SPI5;
    hspi5.Init.Mode = SPI_MODE_SLAVE;
    hspi5.Init.Direction = SPI_DIRECTION_2LINES;
    hspi5.Init.DataSize = SPI_DATASIZE_8BIT;
    hspi5.Init.CLKPolarity = SPI_POLARITY_LOW;
    hspi5.Init.CLKPhase = SPI_PHASE_1EDGE;
    hspi5.Init.NSS = SPI_NSS_SOFT;
    hspi5.Init.FirstBit = SPI_FIRSTBIT_MSB;
    hspi5.Init.TIMode = SPI_TIMODE_DISABLE;
    hspi5.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    hspi5.Init.CRCPolynomial = 0x0;
    hspi5.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
    hspi5.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
    hspi5.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
    hspi5.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
    hspi5.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
    hspi5.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
    hspi5.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
    hspi5.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
    hspi5.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
    hspi5.Init.IOSwap = SPI_IO_SWAP_DISABLE;
    if (HAL_SPI_Init(&hspi5) != HAL_OK)
    {
        // Error_Handler(); //todo
    }
    /* USER CODE BEGIN SPI5_Init 2 */
 
    /* USER CODE END SPI5_Init 2 */
}

4) When i call the function HAL_SPI_TransmitReceive() i enter in following code section of the function

while ((initial_TxXferCount > 0UL) || (initial_RxXferCount > 0UL))
    {
      /* check TXP flag */
      if ((__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXP)) && (initial_TxXferCount > 0UL))
      {
        if ((initial_TxXferCount > 3UL) && (hspi->Init.FifoThreshold > SPI_FIFO_THRESHOLD_03DATA))
        {
          *((__IO uint32_t *)&hspi->Instance->TXDR) = *((uint32_t *)hspi->pTxBuffPtr);
          hspi->pTxBuffPtr += sizeof(uint32_t);
          hspi->TxXferCount -= (uint16_t)4UL;
          initial_TxXferCount = hspi->TxXferCount;
        }
        else if ((initial_TxXferCount > 1UL) && (hspi->Init.FifoThreshold > SPI_FIFO_THRESHOLD_01DATA))
        {
#if defined (__GNUC__)
          *ptxdr_16bits = *((uint16_t *)hspi->pTxBuffPtr);
#else
          *((__IO uint16_t *)&hspi->Instance->TXDR) = *((uint16_t *)hspi->pTxBuffPtr);
#endif /* __GNUC__ */
          hspi->pTxBuffPtr += sizeof(uint16_t);
          hspi->TxXferCount -= (uint16_t)2UL;
          initial_TxXferCount = hspi->TxXferCount;
        }
        else
        {
          *((__IO uint8_t *)&hspi->Instance->TXDR) = *((uint8_t *)hspi->pTxBuffPtr);
          hspi->pTxBuffPtr += sizeof(uint8_t);
          hspi->TxXferCount--;
          initial_TxXferCount = hspi->TxXferCount;
        }
      }
 
      /* Wait until RXWNE/FRLVL flag is reset */
      if (((hspi->Instance->SR & (SPI_FLAG_RXWNE | SPI_FLAG_FRLVL)) != 0UL) && (initial_RxXferCount > 0UL))
      {
        if ((hspi->Instance->SR & SPI_FLAG_RXWNE) != 0UL)
        {
          *((uint32_t *)hspi->pRxBuffPtr) = *((__IO uint32_t *)&hspi->Instance->RXDR);
          hspi->pRxBuffPtr += sizeof(uint32_t);
          hspi->RxXferCount -= (uint16_t)4UL;
          initial_RxXferCount = hspi->RxXferCount;
        }
        else if ((hspi->Instance->SR & SPI_FLAG_FRLVL) > SPI_RX_FIFO_1PACKET)
        {
#if defined (__GNUC__)
          *((uint16_t *)hspi->pRxBuffPtr) = *prxdr_16bits;
#else
          *((uint16_t *)hspi->pRxBuffPtr) = *((__IO uint16_t *)&hspi->Instance->RXDR);
#endif /* __GNUC__ */
          hspi->pRxBuffPtr += sizeof(uint16_t);
          hspi->RxXferCount -= (uint16_t)2UL;
          initial_RxXferCount = hspi->RxXferCount;
        }
        else
        {
          *((uint8_t *)hspi->pRxBuffPtr) = *((__IO uint8_t *)&hspi->Instance->RXDR);
          hspi->pRxBuffPtr += sizeof(uint8_t);
          hspi->RxXferCount--;
          initial_RxXferCount = hspi->RxXferCount;
        }
      }
 
      /* Timeout management */
      if ((((HAL_GetTick() - tickstart) >=  Timeout) && (Timeout != HAL_MAX_DELAY)) || (Timeout == 0U))
      {
        /* Call standard close procedure with error check */
        SPI_CloseTransfer(hspi);
 
        /* Process Unlocked */
        __HAL_UNLOCK(hspi);
 
        SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_TIMEOUT);
        hspi->State = HAL_SPI_STATE_READY;
        return HAL_ERROR;
      }
    }

Problem:

When following line of code is executed

*((__IO uint8_t *)&hspi->Instance->TXDR) = *((uint8_t *)hspi->pTxBuffPtr);

i am expecting the TXP flag to get reset, but it get reset only when i execute above line of code 8 times, but my FIFO is set to one.

Following is the screenshot of debug window

0693W00000GVnz9QAD.pngWhat is missing, am i doing something wrong.

just for the information initial_RxXferCount is not decrementing that means indeed the master is not clocking. Also if i write manually some data in TXDR register through expression window during Debug then TXP flags get reset (as expected)

Please let me know if you need more information.

4 REPLIES 4
TDK
Guru

Per the RM:

TXP flag is cleared when the

TxFIFO contains less than

FTHLV empty locations

Since it can hold 8 bytes, and if you have FTHLV = 1 byte, it takes 8 writes to fill it up and reset the flag.

Edit: might be wrong about the exact size of the TXFIFO, but the concept is correct--it takes more than one write for the free space in the FIFO to drop below the threshold.

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

Hi,

Many Thanks For your answer,

Following is my config so it is not 8 bytes, it is 1 data which should correspond to 1 byte

0693W00000GVrdlQAD.png 

It should take two writes to clear the TXP flag, During first write, the data will be written to fifo and immediately gets transferred to SPI transmit register making the FIFO empty, During second write the data will remain in the FIFO as it cannot transfer the data to SPI transmit register (as it is holding the old data during first write.).

During Second write TXP flag should get reset, but it is not. As i mentioned TXP is becoming zero if you write two time in TXDR register through expression window during debug.

Any clue why?

Thanks again

Best wishes

TDK
Guru

> It should take two writes to clear the TXP flag, During first write, the data will be written to fifo and immediately gets transferred to SPI transmit register making the FIFO empty, During second write the data will remain in the FIFO as it cannot transfer the data to SPI transmit register (as it is holding the old data during first write.).

I don't believe the Reference Manual supports this claim. That is how it would work on the STM32F4, but the STM32H7 SPI does not function the same as older/simpler families.

> As i mentioned TXP is becoming zero if you write two time in TXDR register through expression window during debug.

Presumably, writing through the debug window is a 32-bit access, not an 8-bit access.

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

Thanks, you are absolutely right,