AnsweredAssumed Answered

I2S DMA

Question asked by morcom.john on Sep 16, 2012
Latest reply on Jan 23, 2013 by koehler.james
Hello,

I'm trying to receive data from I2S using DMA but despite reading the RM0090, the various discussions about using I2S with DMA on the forum and looking at the Discovery and peripheral library examples I've had no joy.

The STM32F4 I2S interface is operated in slave receive mode, driven from a Codec that supplies all the clocks.

Using polled mode I can receive a block of data into a buffer "RxBUfferDMA[]" and print it. Using DMA, I can print the buffer but its contents never change from its initial state of all zeros. 

Clearly I have missed something so all help gratefully received!

The basic code is show below.
001.#include "stm32f4xx.h"                  //
002.#include "USART.h"                      // USART 
003.  
004.#include <stdlib.h>                     // Standard C library
005.#include <stdio.h>                      // Standard C input/output  
006.#include <string.h>                     // C string handling functions
007.  
008./* Private typedef -----------------------------------------------------------*/
009.          
010./* Private define ------------------------------------------------------------*/
011.    GPIO_InitTypeDef GPIO_InitStructure;    // Structure requred for GP IO
012.    I2S_InitTypeDef I2S_InitStructure;      // Structure required for I2S
013.    DMA_InitTypeDef DMA_InitStructure;      // Structure required for DMA
014.    NVIC_InitTypeDef NVIC_InitStructure;    // Structure requried for Interrupts
015.  
016./* Exported constants --------------------------------------------------------
017. *  Connections are as follows:
018. *          Master Clock Input  MCLK        =   I2S2_CKIN       pin PC9
019. *          Bit Clock Input     BITCLK      =   I2S2_CK         pin PB13     
020. *          Word Sync Input     LRCLK       =   I2S2_WS         pin PB9
021. *          I2S Data input:     DIN         =   I2S2_SD         pin PC3
022. *          I2S Data output:    DOUT        =   I2S2ext_SD      pin PC2
023. */
024.    // I2Sx Communication Interface 
025.    #define I2Sx                          SPI2
026.    #define I2Sxext                       I2S2ext
027.    #define I2Sx_CLK                      RCC_APB1Periph_SPI2
028.    #define I2Sx_CLK_INIT                 RCC_APB1PeriphClockCmd
029.  
030.    // Master clock input ->            PC9 
031.    #define I2Sx_CKIN_PIN                 GPIO_Pin_9
032.    #define I2Sx_CKIN_GPIO_PORT           GPIOC
033.    #define I2Sx_CKIN_GPIO_CLK            RCC_AHB1Periph_GPIOC
034.    #define I2Sx_CKIN_SOURCE              GPIO_PinSource9
035.    #define I2Sx_CKIN_AF                  GPIO_AF_SPI2
036.  
037.    // Bit Clock Input ->               PB13
038.    #define I2Sx_CK_PIN                   GPIO_Pin_13
039.    #define I2Sx_CK_GPIO_PORT             GPIOB
040.    #define I2Sx_CK_GPIO_CLK              RCC_AHB1Periph_GPIOB
041.    #define I2Sx_CK_SOURCE                GPIO_PinSource13
042.    #define I2Sx_CK_AF                    GPIO_AF_SPI2
043.  
044.    // Word Sync (Left/Right) input ->  PB9 
045.    #define I2Sx_WS_PIN                   GPIO_Pin_9
046.    #define I2Sx_WS_GPIO_PORT             GPIOB
047.    #define I2Sx_WS_GPIO_CLK              RCC_AHB1Periph_GPIOB
048.    #define I2Sx_WS_SOURCE                GPIO_PinSource9
049.    #define I2Sx_WS_AF                    GPIO_AF_SPI2
050.  
051.    // I2S Data input ->                PC3         
052.    #define I2Sx_SD_PIN                   GPIO_Pin_3
053.    #define I2Sx_SD_GPIO_PORT             GPIOC
054.    #define I2Sx_SD_GPIO_CLK              RCC_AHB1Periph_GPIOC
055.    #define I2Sx_SD_SOURCE                GPIO_PinSource3
056.    #define I2Sx_SD_AF                    GPIO_AF_SPI2
057.  
058.    // I2S Data Output ->               PC2 
059.    #define I2Sxext_SD_PIN                GPIO_Pin_2
060.    #define I2Sxext_SD_GPIO_PORT          GPIOC
061.    #define I2Sxext_SD_GPIO_CLK           RCC_AHB1Periph_GPIOC
062.    #define I2Sxext_SD_SOURCE             GPIO_PinSource2
063.    #define I2Sxext_SD_AF                 GPIO_AF_SPI3
064.          
065./* Private macro -------------------------------------------------------------*/
066.          
067./* Private variables ---------------------------------------------------------*/
068.  
069.    #define RX_BUFFERSIZE 64        
070.  
071.    int16_t RxBufferDMA[RX_BUFFERSIZE];
072.      
073./* Private function prototypes -----------------------------------------------*/
074.  
075./* Private functions ---------------------------------------------------------*/
076.  
077.//=================================MAIN==========================================
078.  
079.int main(void)
080.{
081.    int i=0;
082.    int iRx=0;
083.    int I2SStatus=0;
084.      
085.    // Initialise DMA buffer
086.    for(i=0;i<64;i++)
087.        RxBufferDMA[i] = 0; 
088.          
089.      
090.    // USART Configuration
091.    USART2_init(460800);
092.          
093.// Configure I2S to operate in Slave mode driven by WM8805 spdif receiver 
094.// ==============================================================================
095.          
096.  
097.    // Enable the I2Sx/I2Sx_ext clock 
098.    RCC_I2SCLKConfig(RCC_I2S2CLKSource_Ext);
099.  
100.    // I2S2 Clock Enable 
101.    I2Sx_CLK_INIT(I2Sx_CLK, ENABLE);
102.      
103.  
104.    // Enable GPIO clocks - NB: including DMA1
105.    RCC_AHB1PeriphClockCmd(I2Sx_CKIN_GPIO_CLK | I2Sx_WS_GPIO_CLK | I2Sx_CK_GPIO_CLK | \
106.                         I2Sx_SD_GPIO_CLK | I2Sxext_SD_GPIO_CLK | RCC_AHB1Periph_DMA1, ENABLE);
107.  
108.    // I2S GPIO Configuration 
109.    // Connect I2S pins to Alternate functions 
110.    GPIO_PinAFConfig(I2Sx_CKIN_GPIO_PORT, I2Sx_CKIN_SOURCE, I2Sx_CKIN_AF);
111.    GPIO_PinAFConfig(I2Sx_CK_GPIO_PORT, I2Sx_CK_SOURCE, I2Sx_CK_AF);
112.    GPIO_PinAFConfig(I2Sx_WS_GPIO_PORT, I2Sx_WS_SOURCE, I2Sx_WS_AF);  
113.    GPIO_PinAFConfig(I2Sx_SD_GPIO_PORT, I2Sx_SD_SOURCE, I2Sx_SD_AF);
114.    GPIO_PinAFConfig(I2Sxext_SD_GPIO_PORT, I2Sxext_SD_SOURCE, I2Sxext_SD_AF);
115.  
116.    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
117.    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
118.    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
119.    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_DOWN;
120.  
121.    // I2S CKIN pin configuration = I2S Master Clock (256 x Fs) 
122.    GPIO_InitStructure.GPIO_Pin = I2Sx_CKIN_PIN;
123.    GPIO_Init(I2Sx_CKIN_GPIO_PORT, &GPIO_InitStructure);
124.  
125.    // I2S CK pin configuration = I2S Bit Clock
126.    GPIO_InitStructure.GPIO_Pin I2Sx_CK_PIN;
127.    GPIO_Init(I2Sx_CK_GPIO_PORT, &GPIO_InitStructure);
128.  
129.    // I2S WS pin configuration = I2S Left/Right Clock
130.    GPIO_InitStructure.GPIO_Pin = I2Sx_WS_PIN;
131.    GPIO_Init(I2Sx_WS_GPIO_PORT, &GPIO_InitStructure);
132.  
133.    // I2S SD pin configuration = I2S Serial data input
134.    GPIO_InitStructure.GPIO_Pin = I2Sx_SD_PIN;
135.    GPIO_Init(I2Sx_SD_GPIO_PORT, &GPIO_InitStructure);
136.  
137.    // I2S Extended SD pin configuration = I2S Serial Data Output
138.    GPIO_InitStructure.GPIO_Pin I2Sxext_SD_PIN;
139.    GPIO_Init(I2Sxext_SD_GPIO_PORT, &GPIO_InitStructure);
140.  
141.    // Deinitialize I2Sx 
142.    SPI_I2S_DeInit(I2Sx);
143.          
144.    // Configure the Audio Frequency, Standard and the data format 
145.    I2S_InitStructure.I2S_AudioFreq = I2S_AudioFreq_96k;
146.    I2S_InitStructure.I2S_Standard = I2S_Standard_Phillips;
147.    I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Disable;
148.    I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low;
149.    I2S_InitStructure.I2S_DataFormat I2S_DataFormat_24b;     //I2S_DataFormat_16b; //I2S_DataFormat_32b;
150.  
151.    // Configure I2Sx in slave receiver mode
152.    I2S_InitStructure.I2S_Mode = I2S_Mode_SlaveRx;      
153.    I2S_Init(I2Sx, &I2S_InitStructure);
154.          
155.    // Enable the I2Sx peripheral 
156.    I2S_Cmd(I2Sx, ENABLE);
157.  
158.          
159.// Configure DMA for I2S
160.// ====================================================================================     
161.    DMA_StructInit(&DMA_InitStructure);
162.  
163.    // DMA1_Stream3 channel3 configuration for I2S2_EXT_RX
164.  
165.    // Note: as per https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https%3a%2f%2fmy%2est%2ecom%2fpublic%2fSTe2ecommunities%2fmcu%2fLists%2fcortex%5fmx%5fstm32%2fI2S%20fullduplex%20with%20DMA&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B&currentviews=461
166.    // "Only DMA1 Stream3 Ch3 can be used for I2S2_EXT_RX"
167.    DMA_DeInit(DMA1_Stream3);
168.      
169.    DMA_InitStructure.DMA_Channel = DMA_Channel_3;  
170.    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(SPI2_BASE + 0x0C);
171.    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)RxBufferDMA;          
172.    DMA_InitStructure.DMA_BufferSize = RX_BUFFERSIZE;
173.    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
174.    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
175.    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
176.    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
177.    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
178.    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
179.    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
180.    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
181.    DMA_Init(DMA1_Stream3, &DMA_InitStructure);
182.  
183.    // Enable DMA channel 
184.    DMA_Cmd(DMA1_Stream3, ENABLE);
185.      
186.    // enable SPI interrupts to DMA
187.    SPI_I2S_DMACmd(I2Sx, SPI_I2S_DMAReq_Rx, ENABLE); 
188.    
189.  
190.  
191.    //initialise received string
192.    strcpy(received_string," ");
193.      
194.    while(1)
195.    {
196./*  Enable for polled mode.....
197.        iRx=0;
198.        while (iRx<RX_BUFFERSIZE)
199.        {
200.            I2SStatus=SPI2->SR ;
201.            if ((I2SStatus & SPI_I2S_FLAG_RXNE) != 0)               
202.            {
203.                // i2s Data is received through I2Sx SD pin in 16bit blocks
204.                RxBufferDMA[iRx] = SPI2->DR;
205.                iRx++;
206.            }
207.        
208.*/
209.          
210.        if (received_string[0] == 'G')
211.        {
212.            // Disable DMA channel 
213.            DMA_Cmd(DMA1_Stream3, DISABLE);
214.              
215.            strcpy(received_string," ");
216.            USART2_printf("========Rx============\r\n");         
217.              
218.            for(i=0;i<RX_BUFFERSIZE;i++)
219.                USART2_printf("%d\t%d\r\n",i,RxBufferDMA[i]);      //Reminder: we need a CR+LF (\r\n) for windows VB
220.              
221.            // Re-enable DMA channel 
222.            DMA_Cmd(DMA1_Stream3, ENABLE);
223.        }
224.    }
225.      
226.}
227.  
228.  
229.  
230.  
231.#ifdef  USE_FULL_ASSERT
232./**
233.  * @brief  Reports the name of the source file and the source line number
234.  *         where the assert_param error has occurred.
235.  * @param  file: pointer to the source file name
236.  * @param  line: assert_param error line source number
237.  * @retval None
238.  */
239.void assert_failed(uint8_t* file, uint32_t line)
240.
241.  /* User can add his own implementation to report the file name and line number,
242.     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
243.  
244.    USART2_printf("Wrong parameters value: file %s on line %d\r\n", file, line);
245.  /* Infinite loop */
246.  while (1)
247.  {
248.  }
249.}
250.#endif

Thanks very much,

John

Outcomes