AnsweredAssumed Answered

STM32F4-Discovery ADC Dual Mode DMA Sample Alignment

Question asked by sargent.derek on Mar 11, 2014
Latest reply on Mar 11, 2014 by Clive One
For my project, I am doing audio mixing from three inputs (pins PC1, PC2, PC4 over Channel 11, 12, 14, respectively) and outputting it the external DAC on the F4-Discovery board. The mixing seems to work properly, albeit its done in a somewhat haphazard way - I'm drastically oversampling the inputs into a circular array and then pulling samples from the array at the I2S clock speed. The sample rate isn't my current concern at this point, however. The mixing is done by summing the three values from the circular array. This is currently working, however, its clear that my understanding how the DMA works in this example isn't correct.

My biggest concern is understanding alignment of samples in the circular buffer. I naively assumed that the samples would just continuously be placed in order (e.g. [sample_from_PC1, sample_from_PC2, sample_from_PC4, sample_from_PC1, ...]. However, this is clearly not the case. How do I determine the alignment of samples in the circular array so that I can accurately get a single sample from each input?

001.#include "main.h"
002. 
003.#define ADC_CCR_ADDRESS    ((uint32_t)0x40012308)
004. 
005./* Private typedef -----------------------------------------------------------*/
006./* Private define ------------------------------------------------------------*/
007./* Private macro -------------------------------------------------------------*/
008./* Private variables ---------------------------------------------------------*/
009.__IO uint16_t aADCDualConvertedValue[12];
010. 
011./* Private function prototypes -----------------------------------------------*/
012.static void DMA_Config(void);
013.static void GPIO_Config(void);
014.static void ADC1_CH10_CH11_Config(void);
015.static void ADC2_CH11_CH12_Config(void);
016. 
017./* Private functions ---------------------------------------------------------*/
018. 
019.int main(void)
020.{
021.  ADC_CommonInitTypeDef ADC_CommonInitStructure;
022.   
023.  /*!< At this stage the microcontroller clock setting is already configured,
024.this is done through SystemInit() function which is called from startup
025.files (startup_stm32f40xx.s/startup_stm32f427x.s) before to branch to
026.application main.
027.To reconfigure the default setting of SystemInit() function, refer to
028.system_stm32f4xx.c file
029.*/
030. 
031.  /* Enable peripheral clocks *************************************************/
032.  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
033.  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
034.  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
035.  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
036.     
037.  /* DMA2 Stream0 channel0 configuration **************************************/
038.  DMA_Config();
039.   
040.  /* ADCs configuration ------------------------------------------------------*/
041.  /* Configure ADC Channel 10, 11, 12 pin as analog input */
042.  GPIO_Config();
043. 
044.  /* ADC Common Init */
045.  ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult;
046.  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
047.  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1;
048.  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
049.  ADC_CommonInit(&ADC_CommonInitStructure);
050. 
051.  /* ADC1 regular channels 10, 11 configuration */
052.  ADC1_CH10_CH11_Config();
053. 
054.  /* ADC2 regular channels 11, 12 configuration */
055.  ADC2_CH11_CH12_Config();
056. 
057.  /* Enable DMA request after last transfer (Multi-ADC mode) */
058.  ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
059. 
060.  /* Enable ADC1 */
061.  ADC_Cmd(ADC1, ENABLE);
062. 
063.  /* Enable ADC2 */
064.  ADC_Cmd(ADC2, ENABLE);
065. 
066.  /* Start ADC1 Software Conversion */
067.  ADC_SoftwareStartConv(ADC1);
068. 
069.    SystemInit();
070.    codec_init();
071.    codec_ctrl_init();
072. 
073.    I2S_Cmd(CODEC_I2S, ENABLE);
074.     
075.  while (1)
076.  {
077.        if (SPI_I2S_GetFlagStatus(CODEC_I2S, SPI_I2S_FLAG_TXE))
078.        {
079.            SPI_I2S_SendData(CODEC_I2S, (int16_t) sample);
080. 
081.            //only update on every second sample to insure that L & R ch. have the same sample value
082.            if (sampleCounter & 0x00000001)
083.            {
084.                sample = (((int32_t) aADCDualConvertedValue[0] + aADCDualConvertedValue[1] + aADCDualConvertedValue[2]));
085.     
086.                if (sample > 0xFFFF)
087.                {
088.                    sample = 0xFFFF;
089.                }
090.            }
091.            sampleCounter++;
092.        }
093.  }
094.    return 0;
095.}
096. 
097.static void ADC1_CH10_CH11_Config(void)
098.{
099.  ADC_InitTypeDef ADC_InitStructure;
100. 
101.  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
102.  ADC_InitStructure.ADC_ScanConvMode = ENABLE;
103.  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
104.  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
105.  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
106.  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
107.  ADC_InitStructure.ADC_NbrOfConversion = 2;
108.  ADC_Init(ADC1, &ADC_InitStructure);
109. 
110.  /* ADC1 regular channels 14, 11 configuration */
111.  ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 1, ADC_SampleTime_28Cycles);
112.  ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_28Cycles);
113.}
114. 
115.static void ADC2_CH11_CH12_Config(void)
116.{
117.  ADC_InitTypeDef ADC_InitStructure;
118. 
119.  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
120.  ADC_InitStructure.ADC_ScanConvMode = ENABLE;
121.  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
122.  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
123.  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
124.  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
125.  ADC_InitStructure.ADC_NbrOfConversion = 2;
126.  ADC_Init(ADC2, &ADC_InitStructure);
127. 
128.  /* ADC2 regular channels 11, 12 configuration */
129.  ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 1, ADC_SampleTime_28Cycles);
130.  ADC_RegularChannelConfig(ADC2, ADC_Channel_12, 2, ADC_SampleTime_28Cycles);
131.}
132. 
133.static void DMA_Config(void)
134.{
135.  DMA_InitTypeDef DMA_InitStructure;
136. 
137.  DMA_InitStructure.DMA_Channel = DMA_Channel_0;
138.  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&aADCDualConvertedValue;
139.  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC_CCR_ADDRESS;
140.  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
141.  DMA_InitStructure.DMA_BufferSize = 3;
142.  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
143.  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
144.  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
145.  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
146.  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
147.  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
148.  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
149.  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
150.  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
151.  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
152.  DMA_Init(DMA2_Stream0, &DMA_InitStructure);
153. 
154.  /* DMA2_Stream0 enable */
155.  DMA_Cmd(DMA2_Stream0, ENABLE);
156.}
157. 
158.static void GPIO_Config(void)
159.{
160.  GPIO_InitTypeDef GPIO_InitStructure;
161.     
162.    /* ADC Channel 14 -> PC4
163.       ADC Channel 11 -> PC1
164.       ADC Channel 12 -> PC2
165.    */
166.     
167.  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_1 | GPIO_Pin_2;
168.  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
169.  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
170.  GPIO_Init(GPIOC, &GPIO_InitStructure);
171.}
172. 
173.#ifdef USE_FULL_ASSERT
174. 
175.void assert_failed(uint8_t* file, uint32_t line)
176.{
177.  /* User can add his own implementation to report the file name and line number,
178.ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
179. 
180.  /* Infinite loop */
181.  while (1)
182.  {
183.  }
184.}
185.#endif

Outcomes