2016-10-20 04:17 AM
Hi all,
HAL_SAI_Transmit_DMA fromstm32l4xx_hal_sai.c v1.5.1 does not follow the sequence described in RM0351 Rev 4 pg 1329:''In slave mode, the audio frame starts when the audio block is enabled and when a start of
frame is detected.
In Slave TX mode, no underrun event is possible on the first frame after the audio block is
enabled, because the mandatory operating sequence in this case is:
1. Write into the SAI_xDR (by software or by DMA).
2. Wait until the FIFO threshold (FLH) flag is different from 000b (FIFO empty).
3. Enable the audio block in slave transmitter mode.''
The result of this is that the SAI can sometimes have an incorrect left / right synchronization. (See [DEAD LINK /public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/STM32L476%20SAI%20frame%20synchronization%20is%20incorrect%20swapped%20left%20right%20if%20HAL_SAI_Transmit_DMA%20is%20called%204%20us%20after%20rising%20edge%20of%E2%80%A6&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=7]here)
May I suggest that the function is modified as follows (at least for the case of slave transmitter in I2S)
/**
* @brief Transmit an amount of data in non-blocking mode with DMA.
* @param hsai: pointer to a SAI_HandleTypeDef structure that contains
* the configuration information for SAI module.
* @param pData: Pointer to data buffer
* @param Size: Amount of data to be sent
* @retval HAL status
*/
HAL_StatusTypeDef HAL_SAI_Transmit_DMA(SAI_HandleTypeDef *hsai, uint8_t *pData, uint16_t Size)
{
if
((pData == NULL) || (Size == 0))
{
return
HAL_ERROR;
}
if
(hsai->State == HAL_SAI_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hsai);
hsai->pBuffPtr = pData;
hsai->XferSize = Size;
hsai->XferCount = Size;
hsai->ErrorCode = HAL_SAI_ERROR_NONE;
hsai->State = HAL_SAI_STATE_BUSY_TX;
/* Set the SAI Tx DMA Half transfer complete callback */
hsai->hdmatx->XferHalfCpltCallback = SAI_DMATxHalfCplt;
/* Set the SAI TxDMA transfer complete callback */
hsai->hdmatx->XferCpltCallback = SAI_DMATxCplt;
/* Set the DMA error callback */
hsai->hdmatx->XferErrorCallback = SAI_DMAError;
/* Set the DMA Tx abort callback */
hsai->hdmatx->XferAbortCallback = NULL;
/* Enable the Tx DMA Stream */
if
(HAL_DMA_Start_IT(hsai->hdmatx, (uint32_t)hsai->pBuffPtr, (uint32_t)&hsai->Instance->DR, hsai->XferSize) != HAL_OK)
{
__HAL_UNLOCK(hsai);
return
HAL_ERROR;
}
/* Enable the interrupts for error handling */
__HAL_SAI_ENABLE_IT(hsai, SAI_InterruptFlag(hsai, SAI_MODE_DMA));
// Following RM0351 Rev 4 pg 1329:
// 1) Write into the SAI_xDR (by software or by DMA). (We use DMA as this is the HAL_SAI_Transmit_DMA function)
/* Enable SAI Tx DMA Request */
hsai->Instance->CR1 |= SAI_xCR1_DMAEN;
// 2) Wait until the FIFO threshold (FLH) flag is different from 000b (FIFO empty).
// Don't wait for it to be e.g full as SAI might only generate DMA requests up until the FIFO is partially
// full according to the FTH FifoTHreshold bits
while
((hsai->Instance->SR & SAI_xSR_FLVL) == SAI_FIFOSTATUS_EMPTY){}
// 3) Enable the audio block in slave transmitter mode.
/* Check if the SAI is already enabled */
if
((hsai->Instance->CR1 & SAI_xCR1_SAIEN) == RESET)
{
/* Enable SAI peripheral */
__HAL_SAI_ENABLE(hsai);
}
/* Process Unlocked */
__HAL_UNLOCK(hsai);
return
HAL_OK;
}
else
{
return
HAL_BUSY;
}
}
#sai-hal_sai_transmit_dma
2016-11-07 03:37 AM
Hi RokitanskyAschoff,
Thanks for the feedback. I submit a request internally.-Hannibal-