cancel
Showing results for 
Search instead for 
Did you mean: 

I2S problem on stm32f411 and HAL

leogarberoglio
Associate III
Posted on September 17, 2015 at 03:03

 

 

The original post was too long to process during our migration. Please click on the attachment to read the original post.
13 REPLIES 13
Posted on September 23, 2015 at 09:16

> I've read erratum and never related that issue with my case. I asume I'm the master (and erratum is for slave). I don't take in account that Tx on ext pin is slave.

It's the unfortunate (to put it politely) way of how full-duplex I2S is implemented in the 'F4 - it's two simplex I2S units (one of them - the ''ext'' - crippled to be only I2S and only slave), with internally connected clocks (there is one more I2S erratum for  '405/407 witnessing that this connection went wrong in one case).

> So I will try to implement double buffer DMA transfer. The buffer exchange is made on RX/TX compleat interrupt? or is it a register configuration and part of the uC hardware?

Hardware - see Double buffer mode sub-chapter of DMA chapter in RM. DMA_SxCR.DBM switches on the double-buffer mode; you'll need to set the second buffer's address into DMA_SxM1AR  and DMA_SxCR.CT indicates which buffer is in use by DMA (i.e. the other buffer is available for the software to be manupulated with).

The double-buffer mode is not a necessary precondition. You can use a single buffer and write ahead of the DMA's read pointer, indicated by current NDTR value.

JW

leogarberoglio
Associate III
Posted on September 23, 2015 at 13:41

It will be a little tricky.... My device need to make several test on the pacient ear. For example, I need to send 2 tones and record the ear response at the same time. Each TransmitReceive will be for about 46mseg and I will need 100 or more TransmitReceive experiment. But the thing is that this is not the only thing  the equioment will do. So I will need turn off and on several time the I2S interface...

I think on move to 407, but if the I2S implementation is the same.... I will not move....

I search on TI and they don't have M4 with I2S. Freescale do have M4 with full I2S implementation...

Time to think how to continue...

Thank Jan

Posted on September 23, 2015 at 22:58

There is little tricky in using I2S, it's a fairly simple interface. You can stop both Rx and Tx and then restart them. Or you can stop Tx and wait for WS to become the proper level before restart. Or you can leave both running and just fill the buffers. Or you can set the double-buffer mode and only switch memory address of the inactive buffer to one of previously prepared buffers, even buffers in FLASH. There are so many ways to skin the cat...

JW

leogarberoglio
Associate III
Posted on September 24, 2015 at 01:54

Jan, I want to thank you so much for your answers!

It help me a lot. Now my project is working ok!!!! I just do this:

void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s)
{
f_mitad_buffer = 0;
}
void HAL_I2S_RxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
{
f_mitad_buffer = 1;
}
int main(void)
{
/* 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_I2C1_Init();
MX_I2S2_Init();
MX_USB_DEVICE_Init();
uint16_t i;
int32_t tmp=0;
int32_t tmp1=0;
// uint8_t cnt_PromSincr = 0;
/*
* Creo la señal de a sacar por los parlantes. Las frecuencias son Fsin1 y Fsin2
*/
for(i=0;i<
2
*SAMPLES;i+=2)
{
//Multiplico por 2^24/2 - 1. el -1 es fundamental para evitar overflow en algunos casos
tmp= ( sin(2*M_PI*(i/2)*Fsin1/Fs) ) * (int32_t)6088607;
tmp1= ( sin(2*M_PI*(i/2)*Fsin2/Fs) ) * (int32_t)6088607;
// Paso los 24bits como MSb
tmp <<= 8;
tmp1 <<= 8;
//Canal L
OutputBuffer[i] = ((tmp&0x0000FFFF)<<16) | ((tmp&0xFFFF0000)>>16);
//Canal R
OutputBuffer[i+1] = ((tmp1&0x0000FFFF)<<
16
) | ((tmp1&0xFFFF0000)>>16);
}
for(i=2*SAMPLES;i<
2
*2*SAMPLES;i++)
{
//Canal L y R
OutputBuffer[i] = 0;
}
/*
* Configuro el Audio Codec
* Al finalizar necesito un delay para asegurar que esté funcionando estable. 2000 es mucho, ir achicando
*/
codec_init();
HAL_Delay(2000);
HAL_I2SEx_TransmitReceive_DMA(&hi2s2, (uint16_t *)OutputBuffer, (uint16_t *)InputBuffer, 2*2*SAMPLES);
while(1)
{
if(fUSB_rcv) //Si se ha recivido un dato por el USB
{
switch (msg[0]) //Verifico que caracter me envió la PC
{
case 'Z':
while(f_mitad_buffer == 0);
for(
i
=
0
;i<2*SAMPLES;i+=2)
{
tmp
= 
InputBuffer
[i+140];
tmp = ((tmp&0x0000FFFF)<<16) | ((tmp&0xFFFF0000)>>16);
tmp >>= 8;
Input[i/2] = tmp;
fftInpSignal[i] = tmp; ///80;
fftInpSignal[i+1] = 0.0;
}
/* Process the data through the CFFT/CIFFT module */
arm_cfft_f32(&arm_cfft_sR_f32_len2048, fftInpSignal, ifftFlag, doBitReverse);
/* Process the data through the Complex Magnitude Module for
calculating the magnitude at each bin */
arm_cmplx_mag_f32(fftInpSignal, fftSignal, fftSize);
CDC_Transmit_FS((uint8_t *)&Input[0], SAMPLES*4);
HAL_Delay(100);
CDC_Transmit_FS((uint8_t *)&fftSignal[0], SAMPLES*4);
break;
}
fUSB_rcv=0;
} //Fin de la verificacion de recepcion de dato por USB
}
}

and configure DMA on Circular mode. The magic is on the flag that tells me that I just send half buffer (the sound I'm interested on) and the

while(f_mitad_buffer == 0);

before procees the buffer. There is more elegant way to do this, but this just work ok for now. BR