2020-09-23 11:20 PM
I wrote I2S Loop back test program. I2S2 as Master Transfer mode and I2S3 as Slave Receive mode. (Proto for ADC in and DAC out.)
It works OK when 16bit in 16bit frame. However, in 24 bit in 32bit frame, DMA pointer etc. are corrupted.
With step-by-step trace, I found crushing point in stmf4xx_hal_i2s.c.
Is this BUG or my program is wrong???
Many thanks in advance,
K.A.
Gist of the program is below and screen shot of IDE is attached.
int main(void) {
....
HAL_I2S_Receive_DMA(&hi2s3, (uint16_t *) ADC_Data, (uint16_t) (BUF_LEN*2) * 4) ; // (16bit*2)*stereo*double buffer
while (1)
{
while ((&hi2s2)->State != HAL_I2S_STATE_READY) ;
if (HAL_I2S_Transmit_DMA(&hi2s2, (uint16_t*) Out_buf, (uint16_t) (BUF_LEN*2) * 2) != HAL_OK) {
Error_Handler();
}
}
}
/********** call back **********/
void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef * hi2s3) {
ADC1_ptr = BUF_LEN*2 ;
}
void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef * hi2s3) {
ADC1_ptr = 0 ;
Solved! Go to Solution.
2020-09-24 03:14 AM
K.A.,
I don't use Cube so it's up to you to determine, what exactly the Size parameter in HAL_I2S_Receive_DMA() means.
Just a snippet to raise suspicion:
HAL_StatusTypeDef HAL_I2S_Receive_DMA(I2S_HandleTypeDef *hi2s, uint16_t *pData, uint16_t Size)
{
uint32_t *tmp = NULL;
uint32_t tmp1 = 0U;
if((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
if(hi2s->State == HAL_I2S_STATE_READY)
{
hi2s->pRxBuffPtr = pData;
tmp1 = hi2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN);
if((tmp1 == I2S_DATAFORMAT_24B) || (tmp1 == I2S_DATAFORMAT_32B))
{
hi2s->RxXferSize = (Size << 1U);
hi2s->RxXferCount = (Size << 1U);
}
else
{
hi2s->RxXferSize = Size;
hi2s->RxXferCount = Size;
}
JW
2020-09-24 12:18 AM
Do you define a large enough buffer in memory?
Note, that in Cube/HAL functions with DMA, you specify (probably - read the Cube/HAL manual or follow its code - I don't use Cube) number of *transfers* rather than bytes.
JW
2020-09-24 01:49 AM
Dear Jan,
Thank you very much for your reply.
As I attached the source code, I defined required buffer size. (I hope.)
Please check below.
K.A.
#define BUF_LEN 96 // 1msec data for 96kHz sampling
/*** I use 24bit data in 32bit frame, and I2S transfers 16bit data by DMA ***/
// Input Buffer
uint16_t ADC_Data [(BUF_LEN*2)*2*2] ; // (16bit*2) * stereo * double buffer ==> 1536byte
// Output Buffer
uint16_t Out_buf[(BUF_LEN*2)*2] ; // (16bit*2)*stereo ==>768 byte
// I2S Receive
HAL_I2S_Receive_DMA(&hi2s3, (uint16_t *) ADC_Data, (uint16_t) (BUF_LEN*2) * 4) ; // transfer size => 768
// IS2 Transmit
HAL_I2S_Transmit_DMA(&hi2s2, (uint16_t*) Out_buf, (uint16_t) (BUF_LEN*2) * 2) ; // transfer size => 384
2020-09-24 03:14 AM
K.A.,
I don't use Cube so it's up to you to determine, what exactly the Size parameter in HAL_I2S_Receive_DMA() means.
Just a snippet to raise suspicion:
HAL_StatusTypeDef HAL_I2S_Receive_DMA(I2S_HandleTypeDef *hi2s, uint16_t *pData, uint16_t Size)
{
uint32_t *tmp = NULL;
uint32_t tmp1 = 0U;
if((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
if(hi2s->State == HAL_I2S_STATE_READY)
{
hi2s->pRxBuffPtr = pData;
tmp1 = hi2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN);
if((tmp1 == I2S_DATAFORMAT_24B) || (tmp1 == I2S_DATAFORMAT_32B))
{
hi2s->RxXferSize = (Size << 1U);
hi2s->RxXferCount = (Size << 1U);
}
else
{
hi2s->RxXferSize = Size;
hi2s->RxXferCount = Size;
}
JW
2020-09-24 06:22 AM
Seems like your buffers are half as big as they need to be when using 24- or 32-bit frames. Easy enough to test.
2020-09-24 09:39 PM
Dear Jan and TDK,
Thank you very much for your kind reply.
Jan's comment remind me that I saw the same code somewhere in HAL source.
TDK's comment forced me to re-read HAL manual.
Code excerpt from stm32f4xx_hal_i2s.c (below) answer both of above. ("@note" is exactly the same comment as in HAL manual.)
* @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.
I read this if transfer data size were 100byte, Size parameter will be 50. Either in 16bit data frame or in 24/32bit data frame.
However, the same code Jan kindly mentioned is shown in line 40 and after;
if ((tmpreg_cfgr == I2S_DATAFORMAT_24B) || (tmpreg_cfgr == I2S_DATAFORMAT_32B))
{
hi2s->RxXferSize = (Size << 1U);
hi2s->RxXferCount = (Size << 1U);
}
That means Size parameter for 24/32bit data frame shall be 25 instead of 50 in the above.
(Then, I think "@note" should be "32-bit data length".)
I checked the program after changing the transfer size.
Thanks to your kind reply, it works with out crush!!!
However, all received data was 0xFFFF. (Input data (content of Out_buf) is sin wave.)
{In 16bit loopback, there also some data error in received data. Therefore, this will not the problem of software I suppose.}
Anyway, many thanks to both of you!!!
K.A.
/**
* @brief Receive an amount of data in non-blocking mode with DMA
* @param hi2s pointer to a I2S_HandleTypeDef structure that contains
* the configuration information for I2S module
* @param pData 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_I2S_Receive_DMA(I2S_HandleTypeDef *hi2s, uint16_t *pData, uint16_t Size)
{
uint32_t tmpreg_cfgr;
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
/* Process Locked */
__HAL_LOCK(hi2s);
if (hi2s->State != HAL_I2S_STATE_READY)
{
__HAL_UNLOCK(hi2s);
return HAL_BUSY;
}
/* Set state and reset error code */
hi2s->State = HAL_I2S_STATE_BUSY_RX;
hi2s->ErrorCode = HAL_I2S_ERROR_NONE;
hi2s->pRxBuffPtr = pData;
tmpreg_cfgr = hi2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN);
if ((tmpreg_cfgr == I2S_DATAFORMAT_24B) || (tmpreg_cfgr == I2S_DATAFORMAT_32B))
{
hi2s->RxXferSize = (Size << 1U);
hi2s->RxXferCount = (Size << 1U);
}
else
{
hi2s->RxXferSize = Size;
hi2s->RxXferCount = Size;
}
2020-09-25 12:42 AM
> However, all received data was 0xFFFF.
Observe the data using oscilloscope/LA. Check for bad solder joints.
JW
2020-09-25 08:14 PM
Dear Jan,
Thank you very much for your reply. Your comment is very encouraging.:smiling_face_with_smiling_eyes:
Unfortunately, I do not have Oscillo or Logic analyzer. But my test bed is very simple.
Therefore, I need check the received data.
In 16bit in 16bit data frame case, I thought loopback data (received data) is OK, but it was NOT.
Received data is unexpectedly SHIFTED. (see red part) [PDF attached]
And In 24bit in 32bit data frame, received data was DISASTROUS!!!
If you (and anyone!) have any idea what is wrong, please enlighten me.
Many many thanks in advance.
K.A.
2020-09-25 09:10 PM