cancel
Showing results for 
Search instead for 
Did you mean: 

I2S/DMA 32Bit possible ?

Niklas Ciecior
Associate II
Posted on January 05, 2017 at 14:43

Hey Community,

Short question !

Is I2S DMA 32Bit stream possible ?

The Manual says : 'DMA capability for transmission and reception (16-bit wide)'.

Does it mean that I2S with DMA is only in 16Bit stream possible ? This sentence is not clear enough for me.

If 32Bit stream work, can someone send me an example ? I only found examples with 16Bit streams.

I am grateful for any help.

greetings

Niklas

#possible #32bit #i2s #dma
7 REPLIES 7
Posted on January 05, 2017 at 15:08

The SPI/I2S data register is 16-bit wide, so transfers (including DMA) from/to that register have to be 16-bit wide, i.e. that's what you set in DMA as peripheral transfer size.

However, the I2S machine itself can be set to transmit 32-bit words between toggling of the WS/LRCLK (i.e. 32-bit audio samples) - for this, you need 2 transfers from/to the SPIx_DR register per sample.

JW

Posted on January 05, 2017 at 15:40

That's what i thought too. So i programmed DMA as follow:

// Config Double Buffer , Priority level High, Memory Size 16Bit, 
// Peripherie Size 16 Bit, Circular Mode, Transfer Error interrupt, 
// Half Transfer Complete Interrupt, Memory increment mode
DMA1_Stream3->CR |= ( DMA_SxCR_DBM | DMA_SxCR_PL_1 | DMA_SxCR_MSIZE_0 | DMA_SxCR_PSIZE_0 | DMA_SxCR_CIRC | DMA_SxCR_TEIE | DMA_SxCR_HTIE | DMA_SxCR_MINC );
// Clear FCR register so DMA is in Direct Mode
DMA1_Stream3->FCR = 0;
// Count 16 times. BUFFERSIZE is 8. MSIZE = PSIZE * 2. -> 2 * BUFFERSIZE
DMA1_Stream3->NDTR = (2* BUFFERSIZE);
DMA1_Stream3->PAR = (uint32_t) (&(I2S2->DR));
DMA1_Stream3->M0AR = (uint32_t) (I2S2_Buffer1);
DMA1_Stream3->M1AR = (uint32_t) (I2S2_Buffer2);
// Enable DMA
DMA1_Stream3->CR |= DMA_SxCR_EN;�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

But it dont work. DMA writes random 32Bit numbers and most of the time the same numbers twice or more. My test signal is a sinus wave.

I tried also this config:

// Clear CR register
DMA1_Stream3->CR = 0; 
// Config Double Buffer , Priority level High, Memory Size 32Bit, 
// Peripherie Size 16 Bit, Circular Mode, Transfer Error interrupt, 
// Half Transfer Complete Interrupt, Memory increment mode
DMA1_Stream3->CR |= ( DMA_SxCR_DBM | DMA_SxCR_PL_1 | DMA_SxCR_MSIZE_1 | DMA_SxCR_PSIZE_0 | DMA_SxCR_CIRC | DMA_SxCR_TEIE | DMA_SxCR_HTIE | DMA_SxCR_MINC );
// Clear FCR register
DMA1_Stream3->FCR = 0;
// Config FIFO Error Interrupt, Disable Direct Mode, FIFO threshold 1/4 full
DMA1_Stream3->FCR |= ( DMA_SxFCR_FEIE | DMA_SxFCR_DMDIS );
// Count 16 times. BUFFERSIZE is 8. MSIZE = PSIZE * 2. -> 2 * BUFFERSIZE
DMA1_Stream3->NDTR = (2* BUFFERSIZE);
DMA1_Stream3->PAR = (uint32_t) (&(I2S2->DR));
DMA1_Stream3->M0AR = (uint32_t) (I2S2_Buffer1);
DMA1_Stream3->M1AR = (uint32_t) (I2S2_Buffer2);�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Same problem as with the first config.

Maybe i forgot something ?

My I2S config is correct. Works without DMA. An example for I2S DMA 32Bit would help me alot.

Niklas

Posted on January 05, 2017 at 16:11

Don't see any obvious problem in code you posted.

This is Rx, I suppose, and your external CODEC provides all the clocks?

How are buffers defined, and how is BUFFERSIZE?

Which mcu?

JW

Posted on January 05, 2017 at 16:38

I use the STM32F446 Nucleo 64 Board on Max speed ( 180 Mhz) .

The board working as a slave so every Clock for I2S coming from another Board. The clocks locking good and every clock is at the correct pin.

Here my complet Code:

H-File:

#include 'klippel_stm32fx.h'
#define BUFFERSIZE 8
void I2S_Init(void);
void I2S_Fetch(void);�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

C-File:

#include 'klippel_stm32_i2s.h'

uint32_t I2S2_Buffer1[BUFFERSIZE];
uint32_t I2S2_Buffer2[BUFFERSIZE];

void DMA1_Stream3_IRQHandler(void);
void I2S_Init(void)
{
// PB12 -> WS | PB13 -> CK | PB15 -> SD
// Alternate Mode
GPIOB->MODER |= 0x8A000000;
// Push Pull
GPIOB->OTYPER &= ~(0x0000B000);
// High Speed
GPIOB->OSPEEDR |= 0xCF000000;
// No Pull up/down
GPIOB->PUPDR &= ~(0xCF000000);
// Alternate function 5
GPIOB->AFR[1] |= 0x50550000;
// Enable SPI2 Clock
RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;
// Enable DMA1 Clock
RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN;
// Enable IRQ DMA1_stream3
NVIC_EnableIRQ(DMA1_Stream3_IRQn);
// Clear CR register
DMA1_Stream3->CR = 0; 
// Config Double Buffer , Priority level High, Memory Size 32Bit, 
// Peripherie Size 16 Bit, Circular Mode, Transfer Error interrupt, 
// Half Transfer Complete Interrupt, Memory increment mode
DMA1_Stream3->CR |= ( DMA_SxCR_DBM | DMA_SxCR_PL_1 | DMA_SxCR_MSIZE_1 | DMA_SxCR_PSIZE_0 | DMA_SxCR_CIRC | DMA_SxCR_TEIE | DMA_SxCR_HTIE | DMA_SxCR_MINC );
// Clear FCR register
DMA1_Stream3->FCR = 0;
// Config FIFO Error Interrupt, Disable Direct Mode, FIFO threshold 1/4 full
DMA1_Stream3->FCR |= ( DMA_SxFCR_FEIE | DMA_SxFCR_DMDIS );
// Count 16 times. BUFFERSIZE is 8. MSIZE = PSIZE * 2. -> 2 * BUFFERSIZE
DMA1_Stream3->NDTR = (2* BUFFERSIZE);
DMA1_Stream3->PAR = (uint32_t) (&(I2S2->DR));
DMA1_Stream3->M0AR = (uint32_t) (I2S2_Buffer1);
DMA1_Stream3->M1AR = (uint32_t) (I2S2_Buffer2);
DMA1_Stream3->CR |= DMA_SxCR_EN;
// Slave receive selected
SPI2->I2SCFGR |= SPI_I2SCFGR_I2SCFG_0; 
// Disable Asynchron Mode
SPI2>I2SCFGR &= ~(SPI_I2SCFGR_ASTRTEN);
// Select I2Sx Standard Mode
 SPI2>I2SCFGR &= ~(SPI_I2SCFGR_I2SSTD);
// I2S Selected | Data length 32 bit selected
 SPI2>I2SCFGR |= SPI_I2SCFGR_I2SMOD | SPI_I2SCFGR_DATLEN_1; 
}
void I2S_Receive(void)
{
// Check if I2Sx Instance is in Receive mode
if((SPI2->I2SCFGR & SPI_I2SCFGR_I2SCFG_0) == SPI_I2SCFGR_I2SCFG_0)
{
// Enable RX DMA request
SPI2->CR2 |= SPI_CR2_RXDMAEN;
// Enable I2Sx perhipery
SPI2->I2SCFGR |= SPI_I2SCFGR_I2SE;
}
}

void DMA1_Stream3_IRQHandler(void)
{
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Main:

#include 'klippel_stm32fx.h'
#include 'klippel_stm32f4xx_sysclk_config.h'
#include 'klippel_stm32_gpio.h'
#include 'klippel_stm32_i2s.h'

int main(void)
{
 // Set Clock to Max Speed ( 180Mhz )
 RCC_SetSystemClock180Mhz();
 
 // Enable all Peripherie 
 GPIO_Init();
 
 I2S_Init(void);
 I2S_Receive(void);
 
 while(1);
 
 
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

I hope i didn't forgot something. Niklas
Posted on January 05, 2017 at 17:07

I don't see anything obviously wrong.

Show example of received data (don't forget that I2S and DMA remain working while you stop the mcu in debugger, so you need to stop one of them or the clocks to be able to observe the received data).

JW

Posted on January 06, 2017 at 09:29

Ok i set the BUFFERSIZE to 100 and disabled the DMA after receceiving 100 Words.

My samplefrequency is 48kHz.

The Signal is a 23,999 kHz Sinus Wave with 0,01 amplitude.

The Master device sends only data on the left channel. Right channel is always zero.

With this setting i should get a positive word, a word filled with zero, negative word, a word filled with zero.

What i get can you see in the picture.

0690X00000605x3QAA.png

I get positive word. Then same positive word again. Negative word, and the same negative word again.

So the value looks good, only the zeroes are missing. Why is the data from the left channel always written twice ?

Niklas

Posted on January 06, 2017 at 10:05

Ok i found the problem. Wasn't a problem with the Code. I thought the Master send only data on left channel but he sended same data on the right channel. Now everything works correct.

Thanks alot for your help Jan.