2015-04-09 03:02 AM
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 #audio2015-04-13 01:10 AM
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.2015-04-13 05:11 AM
Sounds like digital leaking into analog. I would review the grounding and supplies first.
JW2015-04-21 04:55 AM
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: Enable LTO: 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 );
}
}
2015-04-22 08:09 AM
I found an error in lines
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte; It should beDMA_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.2015-05-13 04:51 AM
Can this noise appears because DMA makes pause between I2S transaction cycles?
2015-05-14 10:40 AM