cancel
Showing results for 
Search instead for 
Did you mean: 

Can I2S2_ext generate an IRQ on Rx DMA cplt on stm32f411?

leogarberoglio
Associate III
Posted on May 28, 2015 at 20:37

Hi, I'm using an audiocodec conected to I2S2 of the uC. Tx on I2S2_SD and Rx on I2S2_extSD.

I can send audio to the codec as a master and codec play the audio Ok. I'm using DMA and on DMA_Tx_Cplt IRQ I configure the next dma data and call HAL_I2S_Transmit_DMA and everithing work ok.

Now I want to record some sound from the microphone trough the codec. To receive I use I2S_ext pin. Configure dma stream and program the ISR. The problem is that IRQ never fire. I ask for 1000 halfword at 44Khz, so it will be a few mseg of sound, but my buffer is allways 0's and no IRQ fire.

Any Idea?

thank
5 REPLIES 5
Posted on May 28, 2015 at 21:19

The buffer is zerod, or just unwritten? If no data's being received the buffer won't fill and the interrupt won't occur. You're going to need to look very carefully at the initialization and source/nature of the clocking.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
leogarberoglio
Associate III
Posted on May 29, 2015 at 00:17

Clive, once again, thank you for your answer.

So, if the codec send all 0's becouse there is no sound on the mic then the buffer won't fill?

Codec send data on DOUT. Let me ask you a few more basic questions that is not clear to me. dma init code:

void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__DMA1_CLK_ENABLE();
/* DMA interrupt init */
HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
}

I2S init:

/* I2S2 init function */
void MX_I2S2_Init(void)
{
hi2s2.Instance = SPI2;
hi2s2.Init.Mode = I2S_MODE_MASTER_RX;
hi2s2.Init.Standard = I2S_STANDARD_PHILLIPS;
hi2s2.Init.DataFormat = I2S_DATAFORMAT_16B;
hi2s2.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE;
hi2s2.Init.AudioFreq = I2S_AUDIOFREQ_44K;
hi2s2.Init.CPOL = I2S_CPOL_LOW;
hi2s2.Init.ClockSource = I2S_CLOCK_PLL;
hi2s2.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_ENABLE;
HAL_I2S_Init(&hi2s2);
}
void HAL_I2S_MspInit(I2S_HandleTypeDef* hi2s)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(hi2s->Instance==SPI2)
{
/* USER CODE BEGIN SPI2_MspInit 0 */
/* USER CODE END SPI2_MspInit 0 */
/* Peripheral clock enable */
__SPI2_CLK_ENABLE();
/**I2S2 GPIO Configuration
PC2 ------> I2S2_ext_SD
PC3 ------> I2S2_SD
PA6 ------> I2S2_MCK
PB10 ------> I2S2_CK
PB12 ------> I2S2_WS
*/
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Alternate = GPIO_AF6_I2S2ext;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Alternate = GPIO_AF6_SPI2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Peripheral DMA init*/
hdma_i2s2_ext_rx.Instance = DMA1_Stream3;
hdma_i2s2_ext_rx.Init.Channel = DMA_CHANNEL_3;
hdma_i2s2_ext_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_i2s2_ext_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_i2s2_ext_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_i2s2_ext_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_i2s2_ext_rx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_i2s2_ext_rx.Init.Mode = DMA_NORMAL;
hdma_i2s2_ext_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_i2s2_ext_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_i2s2_ext_rx);
__HAL_LINKDMA(hi2s,hdmarx,hdma_i2s2_ext_rx);
/* USER CODE BEGIN SPI2_MspInit 1 */
/* USER CODE END SPI2_MspInit 1 */
}
}

I've test thw samw code but with

hi2s2.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_DISBLE;

hi2s2.Init.Mode = I2S_MODE_MASTER_RX; -> If I use I2S_MODE_MASTER_TX then when I call HAL_I2S_Receive_DMA(&hi2s2, InputBuffer, 10); no MCLK neither BCLK, Neither WCLK is generated. If I use MASTER_RX then there is CLK signals on the bus after Receive_DMA. So, what happen if I want to work on Full Duplex? My IRQ routines are:

void DMA1_Stream3_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Stream3_IRQn 0 */
/* USER CODE END DMA1_Stream3_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_i2s2_ext_rx);
/* USER CODE BEGIN DMA1_Stream3_IRQn 1 */
/* USER CODE END DMA1_Stream3_IRQn 1 */
}
/* USER CODE BEGIN 1 */
void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s)
{
//Recivimos todos los datos del micrófono, enviémoslo a los parlantes
HAL_I2S_Transmit_DMA(&hi2s2, InputBuffer, 44100);
}

Most of the code was generated by CubeMx Main routine:

int main(void)
{
/* USER CODE BEGIN 1 */
uint16_t i;
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_I2S2_Init();
/* USER CODE BEGIN 2 */
for(i=0;i<BufferSize;i++)
{
InputBuffer[i]=0xFFFF;
}
HAL_I2S_Receive_DMA(&hi2s2, InputBuffer, 10);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}

as you can see I intialize de buffer with 0xFFFF and then call I2S_Receive. I connect my oscilloscope on DOUT (equal to I2S_ext) and I see some square wave that change when I talk in front of the mic. So, the signal is incoming to the uC. Afetr I2S_Receive is executed, the input buffer is unchange. So it seems like a DMA configuration issue or something like that I see on reference manual (RM0383 rev 1 psgr 577: The extended I2Ss (I2Sx_ext) can be used only in full duplex mode. The I2Sx_ext operate always in slave mode.What this mean? can you tell my your impresion? thank again
Posted on May 29, 2015 at 01:24

HAL and I2S really aren't my forte. Seem to recall that in full-duplex you're going to need to pump data out to get the receive to work. You also need to be careful about the TX/RX sense of the pins.

Might want to review

STM32F4xx_DSP_StdPeriph_Lib_V1.3.0\Project\STM32F4xx_StdPeriph_Examples\I2S\I2S_TwoBoards\I2S_DataExchangePolling\

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
leogarberoglio
Associate III
Posted on May 29, 2015 at 01:33

It's seems that there is an issue on I2S2_ext pin....

I change my code and use HALF DUPLEX, and use I2S2_SD:

/* I2S2 init function */
void MX_I2S2_Init(void)
{
hi2s2.Instance = SPI2;
hi2s2.Init.Mode = I2S_MODE_MASTER_RX;
hi2s2.Init.Standard = I2S_STANDARD_PHILLIPS;
hi2s2.Init.DataFormat = I2S_DATAFORMAT_16B;
hi2s2.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE;
hi2s2.Init.AudioFreq = I2S_AUDIOFREQ_44K;
hi2s2.Init.CPOL = I2S_CPOL_LOW;
hi2s2.Init.ClockSource = I2S_CLOCK_PLL;
hi2s2.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_DISABLE;
HAL_I2S_Init(&hi2s2);
}
void HAL_I2S_MspInit(I2S_HandleTypeDef* hi2s)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(hi2s->Instance==SPI2)
{
/* USER CODE BEGIN SPI2_MspInit 0 */
/* USER CODE END SPI2_MspInit 0 */
/* Peripheral clock enable */
__SPI2_CLK_ENABLE();
/**I2S2 GPIO Configuration 
PC3 ------> I2S2_SD
PA6 ------> I2S2_MCK
PB10 ------> I2S2_CK
PB12 ------> I2S2_WS 
*/
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Alternate = GPIO_AF6_SPI2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Peripheral DMA init*/
hdma_spi2_rx.Instance = DMA1_Stream3;
hdma_spi2_rx.Init.Channel = DMA_CHANNEL_0;
hdma_spi2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi2_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_spi2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_spi2_rx.Init.Mode = DMA_NORMAL;
hdma_spi2_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_spi2_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_spi2_rx);
__HAL_LINKDMA(hi2s,hdmarx,hdma_spi2_rx);
/* USER CODE BEGIN SPI2_MspInit 1 */
/* USER CODE END SPI2_MspInit 1 */
}
}

int main(void)
{
/* USER CODE BEGIN 1 */
uint16_t i;
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_I2S2_Init();
/* USER CODE BEGIN 2 */
for(i=0;i<BufferSize;i++)
{
InputBuffer[i]=0xFFFF;
}
HAL_I2S_Receive_DMA(&hi2s2, InputBuffer, 44100);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}

And now, the buffer is fill with some data. So maybe I'm making a mistake on configuring full duplex to enable I2S2_ext an try to use it as Rx any idea?
leogarberoglio
Associate III
Posted on May 29, 2015 at 02:32

Ok, I think that the sentence ''

The I2Sx_ext

operate always in slave mode

''

refer to slave to I2Sx block.

I see this on your suggested code:

/* Configure I2Sx in Master Transmitter Mode */
I2S_InitStructure.I2S_Mode = I2S_Mode_MasterTx;
I2S_Init(I2Sx, &I2S_InitStructure);
/* Configure the I2Sx_ext (the second instance) in Slave Receiver Mode */
I2S_FullDuplexConfig(I2Sxext, &I2S_InitStructure);
/* Enable the I2Sx peripheral */
I2S_Cmd(I2Sx, ENABLE);
/* Enable the I2Sx_ext peripheral for Full Duplex mode */
I2S_Cmd(I2Sxext, ENABLE);

so, on standar periph library there is a command to configure I2S_ext pin. But on HAL there isn't. I see that there is two driver for I2S:stm32f4xx_hal_i2s_ex.c andstm32f4xx_hal_i2s.c. Onstm32f4xx_hal_i2s.c I foundHAL_I2S_Receive_DMA funtion, but onstm32f4xx_hal_i2s_ex.c there isn't and there is a function calledHAL_I2SEx_TransmitReceive_DMA. I think that I have to use it to work on full duplex and is in acordance with your thought: ''Seem to recall that in full-duplex you're going to need to pump data out to get the receive to work'' It's no clear to me what initialization code (HAL_I2S_Init), the one from hal_i2s.c or the one from hal_i2s_ex.c.... I'm looking that on hal_i2S.c the init code is declared weak: __weak HAL_StatusTypeDef HAL_I2S_Init(I2S_HandleTypeDef *hi2s) and I just check that the code runHAL_I2S_Init fromstm32f4xx_hal_i2s_ex.c so, definitley I have to useHAL_I2SEx_TransmitReceive_DMA... let my try.... Ok, usingHAL_I2SEx_TransmitReceive_DMA the buffer is fill! I have to review all of it to see how I have to work, but I, now, know how it work.... Thank!