cancel
Showing results for 
Search instead for 
Did you mean: 

Stuck in HAL_I2SEx_TransmitReceive_IT because Interrupts called immediately but not handled as I2S_HandleTypeDef is still locked

Posted on May 10, 2016 at 09:10

Hi all,

I encountered a problem, using version 1.4.4 of the I2S Hal module driver in Master TX full duplex mode. Basically I'm just writing a test program to see that it works, the idea is to transmit data and connect the output pin back to the input pin (via a debug resistor) to see that it works.

Problem is that the program gets stuck in HAL_I2SEx_TransmitReceive_IT. I suspect that this is because it locks the I2S process and then enables the interrupts. The interrupt handler gets called immediately but doesn't do anything because the process is still locked. This happens repeatedly. A hack style workaround may be to simply not lock the process:

/**

  * @brief Full-Duplex Transmit/Receive data in non-blocking mode using Interrupt

  * @param  hi2s: pointer to a I2S_HandleTypeDef structure that contains

  *         the configuration information for I2S module

  * @param pTxData: a 16-bit pointer to the Transmit data buffer.

  * @param pRxData: a 16-bit pointer to the Receive data buffer.

  * @param Size: number of data sample to be sent:

  * @note When a 16-bit data frame or a 16-bit data frame extended is selected during the I2S

  *       configuration phase, the Size parameter means the number of 16-bit data length

  *       in the transaction and when a 24-bit data frame or a 32-bit data frame is selected

  *       the Size parameter means the number of 16-bit data length.

  * @note The I2S is kept enabled at the end of transaction to avoid the clock de-synchronization

  *       between Master and Slave(example: audio streaming).

  * @retval HAL status

  */

HAL_StatusTypeDef HAL_I2SEx_TransmitReceive_IT(I2S_HandleTypeDef *hi2s, uint16_t *pTxData, uint16_t *pRxData, uint16_t Size)

{

  uint32_t tmp1 = 0U;

  if(hi2s->State == HAL_I2S_STATE_READY)

  {

    if((pTxData == NULL ) || (pRxData == NULL ) || (Size == 0U))

    {

      return  HAL_ERROR;

    }

    hi2s->pTxBuffPtr = pTxData;

    hi2s->pRxBuffPtr = pRxData;

    tmp1 = hi2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN);

    /* Check the Data format: When a 16-bit data frame or a 16-bit data frame extended

       is selected during the I2S configuration phase, the Size parameter means the number

       of 16-bit data length in the transaction and when a 24-bit data frame or a 32-bit data

       frame is selected the Size parameter means the number of 16-bit data length. */

    if((tmp1 == I2S_DATAFORMAT_24B) || (tmp1 == I2S_DATAFORMAT_32B))

    {

      hi2s->TxXferSize = Size*2U;

      hi2s->TxXferCount = Size*2U;

      hi2s->RxXferSize = Size*2U;

      hi2s->RxXferCount = Size*2U;

    }

    else

    {

      hi2s->TxXferSize = Size;

      hi2s->TxXferCount = Size;

      hi2s->RxXferSize = Size;

      hi2s->RxXferCount = Size;

    }

    /* Process Locked */

    //__HAL_LOCK(hi2s);

    hi2s->State = HAL_I2S_STATE_BUSY_TX_RX;

    hi2s->ErrorCode = HAL_I2S_ERROR_NONE;

    tmp1 = hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SCFG;

    /* Check if the I2S_MODE_MASTER_TX or I2S_MODE_SLAVE_TX Mode is selected */

    if((tmp1 == I2S_MODE_MASTER_TX) || (tmp1 == I2S_MODE_SLAVE_TX))

    {

      /* Enable I2Sext RXNE and ERR interrupts */

      I2SxEXT(hi2s->Instance)->CR2 |= (I2S_IT_RXNE | I2S_IT_ERR);

      /* Enable I2Sx TXE and ERR interrupts */

      __HAL_I2S_ENABLE_IT(hi2s, (I2S_IT_TXE | I2S_IT_ERR));

      /* Check if the I2S is already enabled */

      if((hi2s->Instance->I2SCFGR &SPI_I2SCFGR_I2SE) != SPI_I2SCFGR_I2SE)

      {

        /* Enable I2Sext(receiver) before enabling I2Sx peripheral */

        I2SxEXT(hi2s->Instance)->I2SCFGR |= SPI_I2SCFGR_I2SE;

        /* Enable I2Sx peripheral */

        __HAL_I2S_ENABLE(hi2s);

      }

    }

    /* The I2S_MODE_MASTER_RX or I2S_MODE_SLAVE_RX Mode is selected */

    else

    {

      /* Enable I2Sext TXE and ERR interrupts */

      I2SxEXT(hi2s->Instance)->CR2 |= (I2S_IT_TXE |I2S_IT_ERR);

      /* Enable I2Sext RXNE and ERR interrupts */

      __HAL_I2S_ENABLE_IT(hi2s, (I2S_IT_RXNE | I2S_IT_ERR));

      /* Check if the I2S is already enabled */

      if((hi2s->Instance->I2SCFGR &SPI_I2SCFGR_I2SE) != SPI_I2SCFGR_I2SE)

      {

        /* Check if the I2S_MODE_MASTER_RX is selected */

        if((hi2s->Instance->I2SCFGR & SPI_I2SCFGR_I2SCFG) == I2S_MODE_MASTER_RX)

        {

          /* Prepare the First Data before enabling the I2S */

          if(hi2s->TxXferCount != 0U)

          {

            /* Transmit First data */

            I2SxEXT(hi2s->Instance)->DR = (*hi2s->pTxBuffPtr++);

            hi2s->TxXferCount--;

            if(hi2s->TxXferCount == 0U)

            {

              /* Disable I2Sext TXE interrupt */

              I2SxEXT(hi2s->Instance)->CR2 &= ~I2S_IT_TXE;

            }

          }

        }

        /* Enable I2S peripheral */

        __HAL_I2S_ENABLE(hi2s);

        /* Enable I2Sext(transmitter) after enabling I2Sx peripheral */

        I2SxEXT(hi2s->Instance)->I2SCFGR |= SPI_I2SCFGR_I2SE;

      }

    }

    /* Process Unlocked */

    __HAL_UNLOCK(hi2s);

    return HAL_OK;

  }

  else

  {

    return HAL_BUSY;

  }

}

Then on a side note, is HAL really the future of software on the STM32F? I much preferred the Standard peripheral Library's approach, I find the HAL to obscure sometimes, also it tries to do everything for you, e.g handling the interrupts, this gives you less control and flexibility. For example with the SPL I can swap transmit buffers while continuously transmitting I2S data (using interrupts), with the HAL there is a discontinuity if you swap buffers, you would probably need to use DMA or something else.

I would be using the SPL, but the thing is the USB is just so much easier to get going with the STM32 Cube and HAL...

#i2s #hal #interrupts
1 REPLY 1
Posted on May 10, 2016 at 09:23

Its because HAL_I2SEx_TransmitReceive_IT locks the i2s and enables the interrupts. Interrup handler is called, and HAL_I2S_IRQHandler then calls I2SEx_TransmitReceive_IT.  I2SEx_TransmitReceive_IT tries to lock the i2s again, but __HAL_LOCK is defined as follows:

  #define __HAL_LOCK(__HANDLE__)                                           \

                                do{                                        \

                                    if((__HANDLE__)->Lock == HAL_LOCKED)   \

                                    {                                      \

                                       return HAL_BUSY;                    \

                                    }                                      \

                                    else                                   \

                                    {                                      \

                                       (__HANDLE__)->Lock = HAL_LOCKED;    \

                                    }                                      \

                                  }while (0)

So the result is that the function returns busy and this happens repeatedly