cancel
Showing results for 
Search instead for 
Did you mean: 

Audio noise depends on buffer-size of I2S DMA

3deemon
Associate II
Posted on April 09, 2015 at 12:02

Hi! I am using STM405RGT6 and TI PCM3060 audio codec. I use DMA to RX and TX I2S data. I2S configured to 96000 Hz. 

When I set buffer size, for example, 64 samples I get parasitic frequency peaks at every 1,5 kHz (96000/64 = 1500) - 1.5 kHz, 3 kHz, 4.5 kHz... If I set buffer size 256 samples I get parasitic frequency peaks at every 375 Hz and so on. Level of this noise is about -60 dB. I am just send recieved data back to codec, not using any processing.

How can I remove this noise?

#dma #i2s #noise #audio
6 REPLIES 6
3deemon
Associate II
Posted on April 13, 2015 at 10:10

update:

Maybe it will help to recognize the reason of the noise: If I set DMA_PeripheralBurst to ''DMA_PeripheralBurst_INC16'' instead of ''DMA_PeripheralBurst_Single'' noise peaks becomes lower by 10 dB. 

I was wrong. Even if I send zeroes to codec (checked with oscilloscope) I hear noise. 
Posted on April 13, 2015 at 14:11

Sounds like digital leaking into analog. I would review the grounding and supplies first.

JW

3deemon
Associate II
Posted on April 21, 2015 at 13:55

Thank you for your answer!

I checked all grounds and didn't find any 1,5 kHz noise. But I noticed if I set ''Enable LTO'' in linker options the noise dissapears and if I uncheck this option it appears again. Disable LTO: 0690X00000605FqQAI.png Enable LTO: 0690X00000605GSQAY.png My Interrupt code:

void
I2S_RX_CallBack( unsigned 
int
*src, unsigned 
int
*dst, unsigned 
short
sz, unsigned 
short
ht ) {
for
( i = 0; i < sz; i++ )
dst[i] = src[i];
return
;
}
void
pcmGpioInit() {
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable I2S and I2C GPIO clocks */
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC, ENABLE );
/* CODEC_I2S output pins configuration: WS, SCK SD0 and SDI pins ------------------*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_14 | GPIO_Pin_15; 
// lrck, sck, sdo, sdi
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init( GPIOB, &GPIO_InitStructure );
/* CODEC_I2S pins configuration: MCO pin */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_Init( GPIOC, &GPIO_InitStructure );
/* Connect pins to I2S IN peripheral */
GPIO_PinAFConfig( GPIOB, GPIO_PinSource9, GPIO_AF_SPI2 );
GPIO_PinAFConfig( GPIOB, GPIO_PinSource10, GPIO_AF_SPI2 );
GPIO_PinAFConfig( GPIOB, GPIO_PinSource14, GPIO_AF_SPI2 );
GPIO_PinAFConfig( GPIOB, GPIO_PinSource15, GPIO_AF_SPI2 );
GPIO_PinAFConfig( GPIOC, GPIO_PinSource9, GPIO_AF_MCO );
// reset and PCM mode pin
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_Init( GPIOB, &GPIO_InitStructure );
GPIO_SetBits( GPIOB, GPIO_Pin_6 ); 
// FMT left-justified
GPIO_ResetBits( GPIOB, GPIO_Pin_7 ); 
// DEMP off
GPIO_SetBits( GPIOB, GPIO_Pin_0 ); 
// reset
}
void
pcmAudioInterfaceInit( unsigned 
int
freq ) {
// We should use SPI2 and I2S2Ext instead of SPI2 and full SPI3
I2S_InitTypeDef I2S_InitStructure;
/* Enable the CODEC_I2S peripheral clock */
RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE );
RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI3, ENABLE );
/* CODEC_I2S2 peripheral configuration for master TX */
SPI_I2S_DeInit( SPI2 );
I2S_InitStructure.I2S_AudioFreq = freq;
I2S_InitStructure.I2S_Standard = I2S_Standard_MSB;
I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_32b;
I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low;
I2S_InitStructure.I2S_Mode = I2S_Mode_MasterTx;
I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Disable;
/* Initialize the I2S main channel for TX */
I2S_Init( SPI2, &I2S_InitStructure );
/* Initialize the I2S extended channel for RX */
I2S_FullDuplexConfig( I2S2ext, &I2S_InitStructure );
}
void
dmaInit() {
/* Enable the DMA clock */
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_DMA1, ENABLE );
/* Configure the TX DMA Stream */
DMA_Cmd( DMA1_Stream4, DISABLE );
DMA_DeInit( DMA1_Stream4 );
/* Set the parameters to be configured */
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = ( unsigned 
int
) &SPI2->DR; 
// 0x4000380C
DMA_InitStructure.DMA_Memory0BaseAddr = ( uint32_t ) 0; 
/* This field will be configured in play function */
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_BufferSize = (uint32_t) 0xFFFE; 
/* This field will be configured in play function */
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_MemoryBurst_INC4;
DMA_Init( DMA1_Stream4, &DMA_InitStructure );
/* Enable the I2S DMA request */
SPI_I2S_DMACmd( SPI2, SPI_I2S_DMAReq_Tx, ENABLE );
/* Configure the RX DMA Stream */
DMA_Cmd( DMA1_Stream3, DISABLE );
DMA_DeInit( DMA1_Stream3 );
/* Set the parameters to be configured */
/* why is a separate initstructure needed here? */
DMA_InitStructure2.DMA_Channel = DMA_Channel_3;
DMA_InitStructure2.DMA_PeripheralBaseAddr = ( unsigned 
int
) &I2S2ext->DR; 
// 0x4000340C
DMA_InitStructure2.DMA_Memory0BaseAddr = (uint32_t) 0; 
/* This field will be configured in play function */
DMA_InitStructure2.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure2.DMA_BufferSize = (uint32_t) 0xFFFE; 
/* This field will be configured in play function */
DMA_InitStructure2.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure2.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure2.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure2.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure2.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure2.DMA_Priority = DMA_Priority_Medium;
DMA_InitStructure2.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure2.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
DMA_InitStructure2.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure2.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init( DMA1_Stream3, &DMA_InitStructure2 );
/* Enable the Half & Complete DMA interrupts */
DMA_ITConfig( DMA1_Stream3, DMA_IT_TC | DMA_IT_HT, ENABLE );
/* I2S DMA IRQ Channel configuration */
NVIC_EnableIRQ( DMA1_Stream3_IRQn );
/* Enable the I2S DMA request */
SPI_I2S_DMACmd( I2S2ext, SPI_I2S_DMAReq_Rx, ENABLE );
}
void
startDmaProcessing( unsigned 
int
txAddr, unsigned 
int
rxAddr, unsigned 
int
size ) {
/* save for IRQ svc */
txbuf = txAddr;
rxbuf = rxAddr;
szbuf = size; 
// because we measure in halfwords
/* Configure the tx buffer address and size */
DMA_InitStructure.DMA_Memory0BaseAddr = ( unsigned 
int
) txAddr;
DMA_InitStructure.DMA_BufferSize = ( unsigned 
int
) 2 * size;
/* Configure the DMA Stream with the new parameters */
DMA_Init( DMA1_Stream4, &DMA_InitStructure );
/* Configure the rx buffer address and size */
/* Again with the separate initstructure. Baroo?? */
DMA_InitStructure2.DMA_Memory0BaseAddr = ( unsigned 
int
) rxAddr;
DMA_InitStructure2.DMA_BufferSize = ( unsigned 
int
) 2 * size;
/* Configure the DMA Stream with the new parameters */
DMA_Init( DMA1_Stream3, &DMA_InitStructure2 );
/* Enable the I2S DMA Streams */
DMA_Cmd( DMA1_Stream3, ENABLE ); 
// enable RX
DMA_Cmd( DMA1_Stream4, ENABLE ); 
// enable TX
/* If the I2S peripheral is still not enabled, enable it */
if
( ( SPI3->I2SCFGR & 0x0400 ) == 0 ) {
I2S_Cmd( I2S2ext, ENABLE );
}
if
( ( SPI2->I2SCFGR & 0x0400 ) == 0 ) {
I2S_Cmd( SPI2, ENABLE );
}
}
void
DMA1_Stream3_IRQHandler() {
unsigned 
int
*src, *dst, sz;
/* Half Transfer complete interrupt */
if
( DMA_GetITStatus( DMA1_Stream3, AUDIO_I2S_EXT_DMA_FLAG_HT ) != RESET ) {
/* Point to 1st half of buffers */
sz = szbuf / 2;
src = ( unsigned 
int
* ) ( rxbuf );
dst = ( unsigned 
int
* ) ( txbuf );
/* Handle 1st half */
I2S_RX_CallBack( src, dst, sz, 1 );
/* Clear the Interrupt flag */
DMA_ClearITPendingBit( DMA1_Stream3, AUDIO_I2S_EXT_DMA_FLAG_HT );
DMA_ITConfig( DMA1_Stream3, DMA_IT_HT, DISABLE );
}
/* Transfer complete interrupt */
if
( DMA_GetITStatus( DMA1_Stream3, AUDIO_I2S_EXT_DMA_FLAG_TC ) != RESET ) {
/* Point to 2nd half of buffers */
sz = szbuf / 2;
src = ( unsigned 
int
* ) ( rxbuf ) + sz;
dst = ( unsigned 
int
* ) ( txbuf ) + sz;
/* Handle 2nd half */
I2S_RX_CallBack( src, dst, sz, 0 );
/* Clear the Interrupt flag */
DMA_ClearITPendingBit( DMA1_Stream3, AUDIO_I2S_EXT_DMA_FLAG_TC );
DMA_ITConfig( DMA1_Stream3, DMA_IT_HT, ENABLE );
}
}

3deemon
Associate II
Posted on April 22, 2015 at 17:09

I found an error in lines

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;

It should be

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

I tried to enable FIFO, to change memory data size, to set periph or memory bursts.. I tried to start DMA RX stream before TX stream and vice versa but it doesn't help.

I really stuck.

3deemon
Associate II
Posted on May 13, 2015 at 13:51

Can this noise appears because DMA makes pause between I2S transaction cycles?

3deemon
Associate II
Posted on May 14, 2015 at 19:40

The original post was too long to process during our migration. Please click on the provided URL to read the original post. https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I6hL&d=%2Fa%2F0X0000000btT%2F5kwGf2gWK5EcjbZRjne7j.QRA_O2hMGTgE2RGcOoodI&asPdf=false