2014-12-09 05:19 AM
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
2014-12-09 07:53 AM
Post a concise example showing code, I will look it over.
2014-12-09 06:32 PM
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.
tyro2014-12-09 11:42 PM
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.
2014-12-10 06:44 PM
Does this problem comes from Interrupt Service Routine settings...?
2014-12-10 07:58 PM
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?2014-12-10 11:32 PM
>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: I must be overlook some important issues.2014-12-11 05:17 AM
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 }; // unrelatedandI'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;2014-12-11 01:33 PM
The addressing looks reasonable, I'd probably use (uint32_t)&ADC3->DR
2014-12-11 06:23 PM
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?