ADC + DMA stops reading
I have a setup which reads data from 4 step-motors and some sensors over ADC1(CH0, CH1, CH2, CH3), and ADC2(CH0, CH1).
The system executes continuous ADC conversions in DMA Mode in the following way:
- In the while-loop in the main function, it reads the actual position of the motors and the data of the sensors.
- The TIM3, which is configured to execute in an interval of 20ms, is responsible for controlling the motors.
The issue that I am facing is that both ADCs stop reading a few minutes after starting, and no data in the register DR is available, it just freezes, first one ADC then the other one, sometimes ADC1 freezes first, other ADC2.
I have checked both ADCs Overflow flags & DMA Transfer error flags, but they indicate no error. I thought some race conditions could be happening due to TIM3, so I have commented out its initialization, but even though the same issue persisted.
I am using the STM32F303VET
Microsoft Visual Studio Professional 2019 - Version 16.11.30
VisualGDB Version 5.6R9
The initialization codes are:
ADC1
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 9;
hadc1.Init.DMAContinuousRequests = ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure the ADC multi-mode
*/
multimode.Mode = ADC_MODE_INDEPENDENT;
if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.SamplingTime = ADC_SAMPLETIME_4CYCLES_5;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
The configuration for other Channels and ADC2 is the same
For DMA1:
hdma_adc1.Instance = DMA1_Channel1;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR;
hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
if (HAL_DMA_Init(&hdma_adc1) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
DMA2
hdma_adc2.Instance = DMA2_Channel1;
hdma_adc2.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc2.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc2.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc2.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc2.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc2.Init.Mode = DMA_CIRCULAR;
hdma_adc2.Init.Priority = DMA_PRIORITY_HIGH;
if (HAL_DMA_Init(&hdma_adc2) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc2);
__HAL_RCC_DMA2_CLK_ENABLE();
HAL_NVIC_SetPriority(DMA2_Channel1_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(DMA2_Channel1_IRQn);
TIM3
static const uint32_t TIM3_PRIORITY = 2;
static const uint32_t PRS_TIM3 = 19507 - 1;
static const uint8_t ARR_TIM3 = 2 - 1;
void InitializeTimerTim3()
{
// Enable TIM3 clock
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
// Configure TIM3
TIM3->PSC = PRS_TIM3; // Prescaler
TIM3->CR1 &= ~TIM_CR1_DIR; // Counter direction up
TIM3->ARR = ARR_TIM3; // Autoreload Register
TIM3->CR1 |= TIM_CR1_CKD_0; // Clock division: division by 1
TIM3->RCR = 0; // Repetition counter register
TIM3->CR1 |= TIM_CR1_CEN; // Enable TIM3
}
void EnableTimerInterruptTim3()
{
// Configure NVIC for TIM3 interrupt
HAL_NVIC_SetPriority(TIM3_IRQn, TIM3_PRIORITY, 0); // Set priority
HAL_NVIC_EnableIRQ(TIM3_IRQn); // Enable TIM3 interrupt
TIM3->DIER |= TIM_DIER_UIE; // Enable update interrupt
}
And the function in the main-loop to read from the ADC: adcMcu_executeDma()
void adcMcu_executeDma(adcMcu_DmaInterface_t *adc, uint64_t time)
{
if (adc->state == adc_wait && adc->nextUpdateTime <= time)
{
startDmaInput(adc, time);
}
if (adc->state == adc_finish)
{
uint64_t nextTime = UINT64_MAX;
for (uint8_t i = 0; i < adc->numberOfChannels; ++i)
{
calcInput(adc, i, time);
if (nextTime > adc->channels[i].nextUpdateTime_ms)
{
nextTime = adc->channels[i].nextUpdateTime_ms;
}
}
adc->nextUpdateTime = nextTime;
adc->state = adc_wait;
}
}
void startDmaInput(adcMcu_DmaInterface_t *adc, uint64_t time)
{
HAL_ADC_Start_DMA(adc->hadc, (uint32_t*)adc->rawValueMatrix, adc->numberOfChannels * adc->numberOfValues);
adc->state = adc_working;
}
I have run out of ideas about what might be causing it.
Any help is highly appreciated.
