cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F373RB ADC+DMA+Interrupt

jogerh
Associate II
Posted on March 03, 2016 at 17:24

Dear Community

I have an STM32F373RB device and I try to use the DMA to read the ADC1. However the DMA interrupt is not triggered. Since there is no example on the µC how to use DMA and ADC together with interrupt I would be very happy if someone could give a hint what I could check in my next trial and error session.

Initialisation:

void ADC_1_Init() { 
GPIO_InitTypeDef GPIO_InitStructure; 
ADC_InitTypeDef ADC_InitStructure; 
DMA_InitTypeDef DMA_InitStructure; 
NVIC_InitTypeDef NVIC_InitStructure; //DMA Interupt 
// Enable DMA1 clock 
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); 
// Enable ADC1 clock 
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); 
RCC_ADCCLKConfig(RCC_PCLK2_Div4); // this I copied form the ADC_DMA example but I havent checked what it means so far 
//Enable GPIO Clock 
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE); 
// Configure PB.12 (ADC Channel8) in analog mode 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB10 --> ADC_IN10 
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; 
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; 
GPIO_Init(GPIOC, &GPIO_InitStructure); 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //PB11 --> ADC_IN11 
GPIO_Init(GPIOC, &GPIO_InitStructure); 
//DMA1 Channel1 configuration 
DMA_DeInit(DMA1_Channel1); 
DMA_InitStructure.DMA_BufferSize = sizeof(ADC1_Buffer); 
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC1_Buffer; 
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; 
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 
DMA_InitStructure.DMA_Priority = DMA_Priority_High; 
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; 
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //DMA_Mode_Normal; // 
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; 
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; 
DMA_Init(DMA1_Channel1, &DMA_InitStructure); 
//DMA_IT_TC: Transfer complete interrupt mask 
//DMA_IT_HT: Half transfer interrupt mask 
//DMA_IT_TE: Transfer error interrupt mask 
// Enable DMA1 channel6 IRQ Channel 
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn; 
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = ADC_Prio; 
NVIC_InitStructure.NVIC_IRQChannelSubPriority = ADC_subPrio; 
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
NVIC_Init(&NVIC_InitStructure); 
DMA_ITConfig(DMA1_Channel1,DMA_IT_TC, ENABLE); 
DMA_Cmd(DMA1_Channel1, ENABLE); 
// ADC1 configuration 
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //Enable for conti mode 
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //Enable for conti mode 
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2; //Trigger 
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; 
ADC_InitStructure.ADC_NbrOfChannel = 1; 
ADC_Init(ADC1, &ADC_InitStructure); 
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_7Cycles5); 
// Enable ADC1 DMA 
ADC_DMACmd(ADC1, ENABLE); 
//The folowing section is probably obsolete... 
// Enable ADC1 
ADC_Cmd(ADC1, ENABLE); 
// ADC1 reset calibration register 
ADC_ResetCalibration(ADC1); 
while(ADC_GetResetCalibrationStatus(ADC1)); 
// ADC1 calibration start 
ADC_StartCalibration(ADC1); 
while(ADC_GetCalibrationStatus(ADC1)); 
ADC_Cmd(ADC1, ENABLE); 
}

IRQ Handler:

void DMA1_Channel1_IRQHandler() { 
if(DMA_GetFlagStatus(DMA1_IT_TC1) != RESET) { 
ADC_Cmd(ADC1, DISABLE); 
} 
DMA_ClearITPendingBit(DMA1_IT_GL1); 
} 

Call from

DMA2_Channel3_IRQHandler()

: ADC_Cmd(ADC1, ENABLE); PS: This mechanism works on stm32L100 and now I try to migrate this to stm32373 for reaching higher performance.
3 REPLIES 3
Posted on March 03, 2016 at 18:28

Sorry, nobody has provided me with an F373 board,

For the F3 DISCO, this blind port from a couple of other F3 examples I've posted

// STM32 ADC 1UP DMA TIM STM32F3-Discovery - sourcer32@gmail.com
/**************************************************************************************/
// ADC1 ADC2 ADC3 ADC4
// IN1 PA0* PA4 PB1 PE14*
// IN2 PA1 PA5* PE9* PE15*
// IN3 PA2 PA6* PE13* PB12
// IN4 PA3 PA7* --- PB14
// IN5 PF4 PC4 PB13 PB15
//
// *Used on STM32F3-Discovery
// Free pins located in STM32F3-Discovery manual, UM1570
// ADC1 Trigger EXT3 TIM2_CC2
// Pins for this example PA1, PA4, PB1, PB12
/**************************************************************************************/
#include ''stm32f3_discovery.h''
#include ''stm32f30x.h''
/**************************************************************************************/
#define BUFSIZE 10
volatile uint16_t ADCConvertedValues[BUFSIZE];
uint16_t CalibrationValue;
/**************************************************************************************/
void ADC_GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable GPIOA Periph clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
/* ADC Channels configuration */
/* Configure PA1 as analog input */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/**************************************************************************************/
void ADC12_DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
/* Enable DMA1 clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/* DMA configuration */
/* DMA1 Channel1 Init Test */
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; // The register of a singular ADC
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValues[0];
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = BUFSIZE;
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_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure); // ADC1
}
/**************************************************************************************/
void ADC_Configuration(void)
{
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
volatile int i;
/* Configure the ADC clocks */
RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div1);
/* Enable ADC1/2 clocks */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ADC12, ENABLE);
/* ADC GPIO configuration */
ADC_GPIO_Configuration();
/* ADC DMA Channel configuration */
ADC12_DMA_Configuration();
/* ADC Calibration procedure */
ADC_VoltageRegulatorCmd(ADC1, ENABLE);
/* Insert delay equal to 10 µs */
for(i=0; i<10000; i++);
ADC_SelectCalibrationMode(ADC1, ADC_CalibrationMode_Single);
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1) != RESET );
CalibrationValue = ADC_GetCalibrationValue(ADC1);
/* ADC configuration */
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Clock = ADC_Clock_AsynClkMode;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; // Not Multi Mode
ADC_CommonInitStructure.ADC_DMAMode = ADC_DMAMode_Circular;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = 10;
ADC_CommonInit(ADC1, &ADC_CommonInitStructure);
/* */
ADC_InitStructure.ADC_ContinuousConvMode = ADC_ContinuousConvMode_Disable; // Triggered
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ExternalTrigConvEvent = ADC_ExternalTrigConvEvent_3; // ADC1/2 EXT3 TIM2_CC2
ADC_InitStructure.ADC_ExternalTrigEventEdge = ADC_ExternalTrigEventEdge_RisingEdge;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_OverrunMode = ADC_OverrunMode_Disable;
ADC_InitStructure.ADC_AutoInjMode = ADC_AutoInjec_Disable;
ADC_InitStructure.ADC_NbrOfRegChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 1, ADC_SampleTime_61Cycles5); // PA1
/* Configures the ADC DMA */
ADC_DMAConfig(ADC1, ADC_DMAMode_Circular);
/* Enable the ADC DMA */
ADC_DMACmd(ADC1, ENABLE);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* wait for ADC1 ADRDY */
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_RDY));
/* Enable the DMA channel */
DMA_Cmd(DMA1_Channel1, ENABLE);
/* Start ADC1 Software Conversion */
ADC_StartConversion(ADC1);
}
/**************************************************************************************/
void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
/* Enable TIM2 Peripheral clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_Period = (SystemCoreClock / 50) - 1; // 50 Hz Sample Rate
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel 2 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 10; // Some arbitary width
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC2Init(TIM2, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);
TIM_Cmd(TIM2, ENABLE);
}
/**************************************************************************************/
void DMA1_Channel1_IRQHandler(void) // 5 Hz
{
/* Test on DMA1 Channel1 Transfer Complete interrupt */
if(DMA_GetITStatus(DMA1_IT_TC1))
{
/* Clear DMA1 Channel1 Half Transfer, Transfer Complete and Global interrupt pending bits */
DMA_ClearITPendingBit(DMA1_IT_GL1); // DMA1_IT_TC1 would suffice
STM_EVAL_LEDToggle(LED3); // 2.5 Hz
}
}
/**************************************************************************************/
void TIM2_IRQHandler(void) // 50 Hz
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
STM_EVAL_LEDToggle(LED4); // 25 Hz
}
}
/**************************************************************************************/
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the DMA1 CH1 and TIM2 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_Init(&NVIC_InitStructure);
}
/**************************************************************************************/
int main(void)
{
/* Initialize LEDs available on STM32F-Discovery board */
STM_EVAL_LEDInit(LED3);
STM_EVAL_LEDInit(LED4);
/* Turn on LD3 */
STM_EVAL_LEDOn(LED3);
STM_EVAL_LEDOn(LED4);
NVIC_Configuration();
TIM2_Configuration();
ADC_Configuration();
/* Enable DMA1 Channel1 Transfer Complete interrupt */
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
/* TIM Interrupts enable */
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
while(1); // Don't want to exit
}
/**************************************************************************************/
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf(''Wrong parameters value: file %s on line %d

'', file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
/**************************************************************************************/

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
jogerh
Associate II
Posted on March 06, 2016 at 21:00

Dear community,

to use the ADC and the DMA together the STM32F373 requires

ADC_SoftwareStartConv(ADC1); // found by trial and error

Here is a working initialization for those who are searching for C&P Code (like me):

void ADC_1_Init() {
GPIO_InitTypeDef GPIO_InitStructure; 
ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure; //DMA Interupt
//*******CLOCK enable
// Enable DMA1 clock 
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
// Enable ADC1 clock 
RCC_ADCCLKConfig(RCC_PCLK2_Div2); 
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); 
//Enable GPIO Clock
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
// Configure PB.12 (ADC Channel8) in analog mode 
//GPIO init
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PC0 --> ADC_IN10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure); 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //PC1 --> ADC_IN11
GPIO_Init(GPIOC, &GPIO_InitStructure);
//DMA1 Channel1 configuration 
DMA_DeInit(DMA1_Channel1); 
DMA_InitStructure.DMA_BufferSize = sizeof(ADC1_Buffer); 
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC1_Buffer; //(uint32_t)&ADC1->DR
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //DMA_Mode_Normal; //
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
//DMA_IT_TC: Transfer complete interrupt mask 
//DMA_IT_HT: Half transfer interrupt mask 
//DMA_IT_TE: Transfer error interrupt mask
// Enable DMA1 channel6 IRQ Channel
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = ADC_Prio;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = ADC_subPrio;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DMA_ITConfig(DMA1_Channel1,DMA_IT_TC, ENABLE);
DMA_Cmd(DMA1_Channel1, ENABLE);
// ADC1 configuration 
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //Enable for multichannel mode
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //Enable for conti mode
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO;// ADC_ExternalTrigConv_T2_CC2; //Trigger 
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1; 
ADC_Init(ADC1, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_1Cycles5); 
// Enable ADC1 DMA 
ADC_DMACmd(ADC1, ENABLE); 
// Enable ADC1 
ADC_Cmd(ADC1, ENABLE); 
// ADC1 reset calibration register 
ADC_ResetCalibration(ADC1); 
while(ADC_GetResetCalibrationStatus(ADC1)); 
//ADC1 calibration start 
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1)); 
ADC_Cmd(ADC1, ENABLE);
ADC_SoftwareStartConv(ADC1); //this needs to be called 
}
void DMA1_Channel1_IRQHandler() {
if(DMA_GetFlagStatus(DMA1_IT_TC1) != RESET) {
ADC_Cmd(ADC1, DISABLE); 
}
DMA_ClearITPendingBit(DMA1_IT_GL1); 
}