2023-01-29 01:52 AM
I am using STM32F446 Nuclero and STM32CubeIDE.
I wrote a loopback code from I2S_ADC (PCM1808PWR) to internal DAC.
MCU is slave mode (external clock to IS2_CKIN).
I works fine.
However, when I try to "Pause DMA" and "Resume DMA", I2S of MCU does not sync with PCM1808PWR.
Phenomena is like this;
Sometimes, MCU sync with PCM1808. However (most of the case), those do not sync, and data is mess.
Manual reads, (in HAL_I2S_Receive_DMA section)
"The I2S is kept enabled at the end of transaction to avoid the clock de-synchronization between Master and Slave(example: audio streaming)."
Therefore, I think I can expect MCU will keep in synchronized while Paused.
Or at least, MCU will sync with PCM1808 when it Resumes.
Please help me to avoid the above phenomena.
Thank you for your kind help in advance.
// in main().c
****
HAL_TIM_Base_Start(&htim2) ; // 48kHz timer for DAC start
// Start DAC
if (HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t *) DAC_In, (uint32_t) BLK_SZ*2, DAC_ALIGN_12B_R) != HAL_OK) {
Error_Handler() ;
}
// Start I2S as Slave Receive @48kHz, 24bit in 32bit frame, stereo
if (((I2S_HandleTypeDef *)&hi2s2)->State == HAL_I2S_STATE_READY) {
if (HAL_I2S_Receive_DMA(&hi2s2, (uint16_t*) I2S_ADC_data, (uint16_t) BLK_SZ_IQ_DBL) != HAL_OK) {
// 3rd parameter Size is number of 16bit data in ADC_data even in format 24bit data in 32bit frame (=16bit*2)
Error_Handler();
}
}
HAL_Delay(2000) ;
// above code works well.
while (1) {
if (HAL_I2S_DMAPause(&hi2s2) != HAL_OK) {
Error_Handler();
}
HAL_Delay(5000) ;
if (HAL_I2S_DMAResume(&hi2s2) != HAL_OK) {
Error_Handler();
}
// There is no ERROR, but data is not correct in most of time. (sometimes, it sync and works.)
HAL_Delay(5000) ;
}
2023-01-29 09:38 AM
why do "pause" then? at running I2S DMA should not be stopped.
if you want stop data flow, better stop SCKI on PCM1808 .
2023-01-29 09:51 PM
Dear AScha.3,
Thank you very much for your reply.
I am running MCU with Slave receive mode and PCM1808 with Master transmit mode with common master clock (48kH*256 =12.288MHz).
What I need to do is stop DMA only. DMA is just transfer data from RX Data Register to buffer. (I2S module is keep running. And different from UART, it does not raise overrun or underrun error.)
Therefore, I just want to stop Data transfer to buffer, and resume it when it requires.
I suppose DMAPause and DMAResume are for such purpose.
As you mentioned, it is possible to stop I2S data flow from PCM1808 by halting master clock. (12.288MHz)
Actually, I tried it. But it does not work either.
2023-01-29 11:38 PM
>Actually, I tried it. But it does not work either.
what it is doing then ? from ds PCM1808 it should be the best way to "pause" (clock halt power down).
DMAPause i never tried - i always run I2S connection without any stop; DMA works on circular buffer and when no need for new data (=pause), just dont copy new data from buffer, but the transfer i2s-dma-buffer always running. this works without problems.
maybe you could try DMAStop - just as test.
2023-01-30 04:08 AM
Dear A.Scha.3,
Yes, you are completely correct.
My bypass code for this issue is the same as your comment.
I keep DMA run, and control copying new data from buffer on and off using flag.
But I think it is not cool solution, therefore, I asked to the experts of the Community.
And Yes, DMAStop works when MCU is Master mode. (PCM1808 will sync with MCU.)
Lastly, I checked HAL_I2S_DMAResume() source code and tried a modification. (below)
It will improve the possibility to sync with PCM1808, but no more than 50%.
I think some error check / sync code will be required in the code.
Hope HAL development team review the code.
Thank you,
/// in stm32f4xx_hal_i2s.c ///
HAL_StatusTypeDef HAL_I2S_DMAResume(I2S_HandleTypeDef *hi2s)
{
/* Process Locked */
__HAL_LOCK(hi2s);
if (hi2s->State == HAL_I2S_STATE_BUSY_TX)
{
/* Enable the I2S DMA Tx request */
SET_BIT(hi2s->Instance->CR2, SPI_CR2_TXDMAEN);
}
else if (hi2s->State == HAL_I2S_STATE_BUSY_RX)
{
/************************************/
__HAL_I2S_CLEAR_OVRFLAG(hi2s); // Added this code to clear error flag
/************************************/
/* Enable the I2S DMA Rx request */
SET_BIT(hi2s->Instance->CR2, SPI_CR2_RXDMAEN);
}