Triple ADC w/ DMA

μC Board: STM32F429ZI-Discovery
IDE: μVision V5.13.0.0

Enable ADC Peripheral, in Triple Mode, using DMA.

CDR ADC Priority Channel Pin
1 ADC1 1 CH13 PC3
2 ADC2 1 CH00 PA0
3 ADC3 1 CH15 PF5
4 ADC1 2 CH08 PB0
5 ADC2 2 CH10 PC0
6 ADC3 2 CH09 PF3
7 ADC1 3 CH06 PA6
8 ADC2 3 CH14 PC4
9 ADC3 3 CH03 PA3

 


TIM2 Enable

#define ADC_PER 4499

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

TIM_BaseStruct_ST.TIM_Prescaler = 0;
TIM_BaseStruct_ST.TIM_CounterMode = TIM_CounterMode_Up;
 // 899 => 100kHz, 2249 => 40kHz, 4499 => 20kHz, 8999 => 10kHz
TIM_BaseStruct_ST.TIM_Period = ADC_PER; 
TIM_BaseStruct_ST.TIM_ClockDivision = TIM_CKD_DIV1;

TIM_TimeBaseInit(TIM2, &TIM_BaseStruct_ST);
TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);

ADC Clock Enable

#include "stm32f4xx_adc.h"
RCC_APB2PeriphClockCmd (RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd (RCC_APB2Periph_ADC2, ENABLE);
RCC_APB2PeriphClockCmd (RCC_APB2Periph_ADC3, ENABLE);

ADC set to Triple Mode, DMA Enable, No Prescaler

ADC_CommonInitTypeDef ADC_CommonInitStructure;

ADC_CommonInitStructure.ADC_Mode          = ADC_TripleMode_RegSimult;
ADC_CommonInitStructure.ADC_Prescaler     = ADC_Prescaler_Div2;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1;
ADC_CommonInit (&ADC_CommonInitStructure);

3 conversions for each ADC, hence 9 in total.
Highest resolution of 12 bits, right data alignment and event trigger by TIM2 interrupts.

ADC_InitTypeDef ADC_InitStructure;

ADC_InitStructure.ADC_ScanConvMode       = ENABLE;
ADC_InitStructure.ADC_NbrOfConversion    = 3;
ADC_InitStructure.ADC_Resolution         = ADC_Resolution_12b;
ADC_InitStructure.ADC_DataAlign          = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;

TIM_SelectOutputTrigger (TIM2, TIM_TRGOSource_Update);
ADC_InitStructure.ADC_ExternalTrigConv     = ADC_ExternalTrigConv_T2_TRGO;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;

ADC_Init(ADC1, &ADC_InitStructure);
ADC_Init(ADC2, &ADC_InitStructure);
ADC_Init(ADC3, &ADC_InitStructure);

Set each channel to the right pin, with 15 cycles for sampling the signal

ADC_RegularChannelConfig (ADC1, ADC_Channel_13, 1, ADC_SampleTime_15Cycles);
ADC_RegularChannelConfig (ADC1, ADC_Channel_8,  2, ADC_SampleTime_15Cycles);
ADC_RegularChannelConfig (ADC1, ADC_Channel_6,  3, ADC_SampleTime_15Cycles);

ADC_RegularChannelConfig (ADC2, ADC_Channel_0,  1, ADC_SampleTime_15Cycles);
ADC_RegularChannelConfig (ADC2, ADC_Channel_10, 2, ADC_SampleTime_15Cycles);
ADC_RegularChannelConfig (ADC2, ADC_Channel_14, 3, ADC_SampleTime_15Cycles);

ADC_RegularChannelConfig (ADC3, ADC_Channel_15, 1, ADC_SampleTime_15Cycles);
ADC_RegularChannelConfig (ADC3, ADC_Channel_9,  2, ADC_SampleTime_15Cycles);
ADC_RegularChannelConfig (ADC3, ADC_Channel_3,  3, ADC_SampleTime_15Cycles);

DMA Clock Enable.

Setup DMA data transport, base address, matrix size, half word data transfer and circular mode.

Enable Stream4 of DMA2.

#include "stm32f4xx_dma.h"
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

DMA_InitTypeDef DMA_InitStructure;

DMA_InitStructure.DMA_DIR     = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_Channel = DMA_Channel_0;

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC->CDR;
DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_Memory0BaseAddr    = (uint32_t)(&adc[0]);
DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;

DMA_InitStructure.DMA_BufferSize = 9;

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_HalfWord;

DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

DMA_Init(DMA2_Stream4, &DMA_InitStructure)

Setup and enable interrupt event of DMA

NVIC_InitTypeDef ADCNVICConfig;
ADCNVICConfig.NVIC_IRQChannel = DMA2_Stream4_IRQn;
ADCNVICConfig.NVIC_IRQChannelPreemptionPriority = 0;
ADCNVICConfig.NVIC_IRQChannelSubPriority = 1;
ADCNVICConfig.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&ADCNVICConfig);

ADC_DMACmd(ADC1, ENABLE);
ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
DMA_ITConfig(DMA2_Stream4, DMA_IT_TC, ENABLE);

DMA_Cmd(DMA2_Stream4, ENABLE); 

Setup ADC1 as Master and ADC2 and ADC3 as Slaves, enable DMA and all ADCs.

ADC_DMACmd(ADC1, ENABLE);
ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);

ADC_Cmd(ADC1, ENABLE);
ADC_Cmd(ADC2, ENABLE);
ADC_Cmd(ADC3, ENABLE);

The full code can be found in GitHUB

Published By
admin

1 Comment

aatif shaikh

#define ADC_PER 4499
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_BaseStruct_ST.TIM_Prescaler = 0;
TIM_BaseStruct_ST.TIM_CounterMode = TIM_CounterMode_Up;
// 899 => 100kHz, 2249 => 40kHz, 4499 => 20kHz, 8999 => 10kHz
TIM_BaseStruct_ST.TIM_Period = ADC_PER;
TIM_BaseStruct_ST.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM2, &TIM_BaseStruct_ST);
TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);

If I’m not mistaken you used this “Timer2” to trigger the “ADC start conversion”. I’ve ported your code for STM32F205xx(HSI-16Mhz) with slight modification. In my case, I’m using 4 channels on two different ADC. the issue I’m getting is that it is not calling it on its own (Timer trigger), I’ve to personally call the ADC_SoftwareStartConv(ADC1); to trigger the conversion.

Leave a Comment

Your email address will not be published.