cancel
Showing results for 
Search instead for 
Did you mean: 

ADC with DMA arrest on STM32F4

yoshi
Associate II
Posted on December 09, 2014 at 14:19

Dear All,

My board is 429I-DISCO. I tried to code a continuous A/D conversion via DMA on FreeRTOS.

At first A/D conversion shortly after power-up was starting nomally by ADC_SoftwareStartConv(ADC3).

On the rest of the next sequence, the value of uhADC3ConvertedValue - mostly copy & paste from STM's Peripheral_Examples\ADC_DMA - is not updated.

According to single step execution, it seems to stopped the conversion in vTaskStartScheduler().

Does anyone knows why stop the A/D conversion process? How should I fix this?

tyro

11 REPLIES 11
Posted on December 09, 2014 at 16:53

Post a concise example showing code, I will look it over.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
yoshi
Associate II
Posted on December 10, 2014 at 03:32

Hello clive1,

I'm coding this on FreeRTOS based on proprietary framework. So I can't list entire source code. I try to pickup the relating part.

GPIO initializing code shows below:

void
GPIO::init() 
{ 
ADC_InitTypeDef ADC_InitStructure; 
ADC_CommonInitTypeDef ADC_CommonInitStructure; 
GPIO_InitTypeDef GPIO_InitStructure; 
DMA_InitTypeDef DMA_InitStructure; 
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 
TIM_OCInitTypeDef TIM_OCInitStructure; 
/* Enable the GPIO_LED Clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); 
/* Configure the GPIO_LED pin */
GPIO_InitStructure.GPIO_Pin = USERIO_PIN[USER_LED_0] | USERIO_PIN[USER_LED_1]; 
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; 
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; 
GPIO_Init(GPIOC, &GPIO_InitStructure); 
/* Initialize the GPIO_LED pin */
for
(
int
i = 0; i < 2; i++) clear((USERIO_ID)i); 
/* TIM2 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); 
/* GPIOA clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); 
/* GPIOA Configuration: TIM2 CH1 (PA5) */
GPIO_InitStructure.GPIO_Pin = USERIO_PIN[USER_LED_2]; 
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; 
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; 
GPIO_Init(GPIOA, &GPIO_InitStructure); 
/* Connect TIM2 pins to AF1 */
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_TIM2); 
/* Compute the prescaler value */
PrescalerValue = (uint16_t) ((SystemCoreClock /2) / 30000000) - 1; 
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 999; 
TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue; 
TIM_TimeBaseStructure.TIM_ClockDivision = 0; 
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); 
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; 
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 
TIM_OCInitStructure.TIM_Pulse = CCR1_Val; 
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 
TIM_OC1Init(TIM2, &TIM_OCInitStructure); 
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); 
TIM_ARRPreloadConfig(TIM2, ENABLE); 
/* TIM2 enable counter */
TIM_Cmd(TIM2, ENABLE); 
/*** PROBLEMATIC A/D CONVERSION ***/
/* ADC3, DMA2 clocks enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); 
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE); 
/* DMA2 Stream0 channel2 configuration */
DMA_InitStructure.DMA_Channel = DMA_Channel_2; 
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)0x4001224C; 
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&uhADC3ConvertedValue; 
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; 
DMA_InitStructure.DMA_BufferSize = 1; 
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; 
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_High; 
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; 
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; 
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; 
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; 
DMA_Init(DMA2_Stream0, &DMA_InitStructure); 
DMA_Cmd(DMA2_Stream0, ENABLE); 
/* Configure ADC3 Channel13 pin as analog input */
GPIO_InitStructure.GPIO_Pin = USERIO_PIN[USER_VOL_0]; 
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; 
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; 
GPIO_Init(GPIOC, &GPIO_InitStructure); 
/* ADC Common Init */
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; 
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2; 
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; 
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; 
ADC_CommonInit(&ADC_CommonInitStructure); 
/* ADC3 Init */
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; 
ADC_InitStructure.ADC_ScanConvMode = DISABLE; 
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; 
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; 
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; 
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; 
ADC_InitStructure.ADC_NbrOfConversion = 1; 
ADC_Init(ADC3, &ADC_InitStructure); 
/* ADC3 regular channel13 configuration */
ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 1, ADC_SampleTime_3Cycles); 
/* Enable DMA request after last transfer (Single-ADC mode) */
ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE); 
/* Enable ADC3 with DMA */
ADC_DMACmd(ADC3, ENABLE); 
ADC_Cmd(ADC3, ENABLE); 
}

ADC3 Software Conversion starting section shows below:

Std::Std() : 
stdListener(0) 
{ 
/* Start ADC3 Software Conversion */
ADC_SoftwareStartConv(ADC3); 
uwVoltage = 0; 
}

A/D value readout section shows below:

uint32_t GPIO::getADC3CH13() 
{ 
/* convert the ADC value (from 0 to 0xFFF) to a voltage value (from 0V to 3.0V)*/
uwADC3ConvertedVoltage = uhADC3ConvertedValue *3000/0xFFF; 
return
uwADC3ConvertedVoltage; 
}

main.c shows below:

#include ''FreeRTOS.h'' 
#include ''task.h'' 
#include ''queue.h'' 
#define configGUI_TASK_PRIORITY ( tskIDLE_PRIORITY + 3 ) 
#define configGUI_TASK_STK_SIZE ( 950 ) 
static
void
GUITask(
void
* params) 
{ 
hoge::HAL::getInstance()->taskEntry(); 
} 
int
main (
void
) 
{ 
hw_init(); 
GPIO::init(); 
hoge_init(); 
xTaskCreate( GUITask, (
signed
char
*)
''GUITask''
, 
configGUI_TASK_STK_SIZE, 
NULL, 
configGUI_TASK_PRIORITY, 
NULL); 
/*** A/D stop roop ***/
vTaskStartScheduler(); 
for
(;;); 
}

In vTaskStartScheduler() calls below:

// FreeRTOS specific handlers 
extern
''C''
{ 
void
vApplicationStackOverflowHook( xTaskHandle xTask, 
signed
portCHAR *pcTaskName ) 
{ 
while
(1); 
} 
void
vApplicationMallocFailedHook( xTaskHandle xTask, 
signed
portCHAR *pcTaskName ) 
{ 
while
(1); 
} 
/*** A/D stop function??? ***/
void
vApplicationIdleHook( 
void
) 
{ 
vTaskSetApplicationTaskTag( NULL, IdleTaskHook ); 
while
(1) 
{ 
} 
} 
}

I'd like to sprit the probrem for FreeRTOS and Framework.

tyro
yoshi
Associate II
Posted on December 10, 2014 at 08:42

By any chance, Practically ADC with DMA is working nomally, but debugger stops continuous A/D conversion by stop-and-go process? -> No, It stopped continuous conversion in normal operation.

yoshi
Associate II
Posted on December 11, 2014 at 03:44

Does this problem comes from Interrupt Service Routine settings...?

Posted on December 11, 2014 at 04:58

The debugger can stop timers via the DBGMCU configuration, generally ADC/DMA operations will continuance despite what you might be doing in the debugger.

I would generally recommend using a larger buffer so you can see more sample, and ideally decimate the interrupt loading.

Do you need to be driving the ADC at it's maximal rate for just one sample? Could you pace it?
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
yoshi
Associate II
Posted on December 11, 2014 at 08:32

>Do you need to be driving the ADC at it's maximal rate for just one sample? Could you pace it?

I'm not interested in conversion speed at this time.

In my few knowledges, It seems to stop conversion by anything flag register, or some kind of overflow, or particular problem of using RTOS, ormy debugger operation.

I found similar case as below:

https://my.st.com/public/STe2ecommunities/mcu/Lists/STM32Discovery/Flat.aspx?RootFolder=https://my.st.com/public/STe2ecommunities/mcu/Lists/STM32Discovery/ADC%20with%20DMA%20in%20FreeRTOS&FolderCTID=0x01200200770978C69A1141439FE559EB459D75800084C20D8867EAD444A5987D47BE638E0F&currentviews=608

I must be overlook some important issues.

yoshi
Associate II
Posted on December 11, 2014 at 14:17

These variables are defined in GPIO class:

static

bool

userioState[2];

// unrelated variables

uint16_t CCR1_Val = 500;

// unrelated

uint16_t PrescalerValue = 0;

// unrelated

__IO uint16_t uhADC3ConvertedValue = 99;

// magic number for initializing check

__IO uint32_t uwADC3ConvertedVoltage = 99;

// magic number for initializing check

const

uint16_t USERIO_PIN[4] = { GPIO_Pin_11, GPIO_Pin_12,

GPIO_Pin_5, GPIO_Pin_3 };

// unrelated

andI'm using following code:

void

GPIO::clear(USERIO_ID id)

{

GPIOC->BSRRH = USERIO_PIN[id];

userioState[id] = 0; 

}

and the disassembly is below:

0x8071be4: 0x2200 MOVS R2, #0

0x8071be6: 0x490a LDR.N R1, ??DataTable7_1 ; userioState

0x8071be8: 0x5442 STRB R2, [R0, R1]

I found this strange disassembly:

0x8071bf2: 0x4807 LDR.N R0, ??DataTable7_1 ; userioState

at this routine:

uint32_t GPIO::getADC3CH13()

{

/* convert the ADC value (from 0 to 0xFFF) to a voltage (from 0V to 3.0V) */

uwADC3ConvertedVoltage = uhADC3ConvertedValue *3000/0xFFF;

// in this step

return

uwADC3ConvertedVoltage;

}

Is address designationright way?

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)0x4001224C;

DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&uhADC3ConvertedValue;

Posted on December 11, 2014 at 22:33

The addressing looks reasonable, I'd probably use (uint32_t)&ADC3->DR

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
yoshi
Associate II
Posted on December 12, 2014 at 03:23

I'm suspicious of DMA TCIF register. -> Probably, No... ->

I think that captured at the moment of DMA hang up. App::handleTickEvent() calls std.tick()

void App::handleTickEvent() 
{ 
std.tick(); // call Std::tick(), even as DMA hang up?
UApp::handleTickEvent(); 
}

void
Std::tick() 
{ 
getVoltageValue(); 
} 
void
Std::getVoltageValue(); 
{ 
uint32_t value = 0; 
value = GPIO::getADC3CH13(); 
uwVoltage = (value)/1000; 
uwMVoltage = (value%1000)/100; 
}

Pre-implimented on framework, Std::tick()is called at fixed intervals. Does DMA transferhung up by missing DMA waiting process?