Question
Triple mode ADC with new HAL
Posted on December 01, 2014 at 22:52
Hello,
I'm trying to set the ADC(s) of the stm32f407 in triple mode, using DMA for data transfers. Based on the the only available example in the cube package and some old code, written using the stdpheriph, I wrote the following code but unfortunately it doesn't work. It never calls the DMA Interrupt service routine and the value in the ADC->CDR register stay stuck to the first conversion. Here's the code:void
HAL_ADC_MspInit(ADC_HandleTypeDef* adc_handler)
{
GPIO_InitTypeDef gpio_init_struct;
static
DMA_HandleTypeDef dma_adc_handler;
/*
Pins timer alternate function mapping:
-----------------------
Pin ADC Channel
-----------------------
PA01 ADC1 CH1
PA02 ADC2 CH2
PA03 ADC3 CH3
*/
// Enable DMA, ADC 1,2,3 and related GPIO ports clock
__DMA2_CLK_ENABLE();
__ADC1_CLK_ENABLE();
__ADC2_CLK_ENABLE();
__ADC3_CLK_ENABLE();
__GPIOA_CLK_ENABLE();
// ADCs GPIO pin configuration
gpio_init_struct.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3;
gpio_init_struct.Mode = GPIO_MODE_ANALOG;
gpio_init_struct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &gpio_init_struct);
// ADC1 master, ADC 2,3 slaves
// DMA2 Stream0 channel0 (physically mapped to ADC1) configuration
dma_adc_handler.Instance = DMA2_Stream0;
dma_adc_handler.Init.Channel = DMA_CHANNEL_0;
dma_adc_handler.Init.Direction = DMA_PERIPH_TO_MEMORY;
dma_adc_handler.Init.PeriphInc = DMA_PINC_DISABLE;
dma_adc_handler.Init.MemInc = DMA_MINC_ENABLE;
dma_adc_handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
dma_adc_handler.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
dma_adc_handler.Init.Mode = DMA_CIRCULAR;
dma_adc_handler.Init.Priority = DMA_PRIORITY_HIGH;
dma_adc_handler.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
dma_adc_handler.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
dma_adc_handler.Init.MemBurst = DMA_MBURST_SINGLE;
dma_adc_handler.Init.PeriphBurst = DMA_PBURST_SINGLE;
HAL_DMA_Init(&dma_adc_handler);
// Associate the initialized DMA handle to the the ADC handle
__HAL_LINKDMA(adc_handler, DMA_Handle, dma_adc_handler);
// NVIC configuration for DMA transfer complete interrupt
HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
}
//---------------------------------------------------------------------------------------------------------
void
Befm_Sense::init()
{
// ADC(s) configuration
adc1_handle.Instance = ADC1;
adc1_handle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
//0 [1] -> max ADC clock
adc1_handle.Init.Resolution = ADC_RESOLUTION12b;
adc1_handle.Init.ScanConvMode = DISABLE;
adc1_handle.Init.ContinuousConvMode = ENABLE;
adc1_handle.Init.DiscontinuousConvMode = DISABLE;
adc1_handle.Init.NbrOfDiscConversion = 0;
adc1_handle.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONVEDGE_NONE;
adc1_handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
// adc1_handle.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
// adc1_handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
adc1_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT;
adc1_handle.Init.NbrOfConversion = 1;
adc1_handle.Init.DMAContinuousRequests = ENABLE;
adc1_handle.Init.EOCSelection = EOC_SINGLE_CONV;
adc2_handle.Instance = ADC2;
adc2_handle.Init = adc1_handle.Init;
adc3_handle.Instance = ADC3;
adc3_handle.Init = adc1_handle.Init;
if
(HAL_ADC_Init(&adc1_handle) != HAL_OK) {
info::error();
}
if
(HAL_ADC_Init(&adc2_handle) != HAL_OK) {
info::error();
}
if
(HAL_ADC_Init(&adc3_handle) != HAL_OK) {
info::error();
}
// Configure ADC1 regular channel 1
adc_config_struct.Channel = ADC_CHANNEL_1;
adc_config_struct.Rank = 1;
adc_config_struct.SamplingTime = ADC_SAMPLETIME_15CYCLES;
adc_config_struct.Offset = 0;
if
(HAL_ADC_ConfigChannel(&adc1_handle, &adc_config_struct) != HAL_OK) {
info::error();
}
// Configure ADC2 regular channel 2
adc_config_struct.Channel = ADC_CHANNEL_2;
if
(HAL_ADC_ConfigChannel(&adc2_handle, &adc_config_struct) != HAL_OK) {
info::error();
}
// Configure ADC3 regular channel 3
adc_config_struct.Channel = ADC_CHANNEL_3;
if
(HAL_ADC_ConfigChannel(&adc3_handle, &adc_config_struct) != HAL_OK) {
info::error();
}
// Configure ADC(s) in triple-mode simultaneous
adc_multimode_struct.Mode = ADC_TRIPLEMODE_REGSIMULT;
adc_multimode_struct.DMAAccessMode = ADC_DMAACCESSMODE_1;
adc_multimode_struct.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES;
if
(HAL_ADCEx_MultiModeConfigChannel(&adc1_handle, &adc_multimode_struct) != HAL_OK) {
info::error();
}
if
(HAL_ADCEx_MultiModeConfigChannel(&adc2_handle, &adc_multimode_struct) != HAL_OK) {
info::error();
}
if
(HAL_ADCEx_MultiModeConfigChannel(&adc3_handle, &adc_multimode_struct) != HAL_OK) {
info::error();
}
// Start ADC
// Enables ADC DMA request after last transfer (Multi-ADC mode) and enables ADC peripheral
// Only master ADC (ADC1)
if
(HAL_ADCEx_MultiModeStart_DMA(&adc1_handle, (uint32_t *)&phases_v, 3) != HAL_OK) {
info::error();
}
}
//---------------------------------------------------------------------------------------------------------
// DMA (ADC) interrupt handler
void
DMA2_Stream0_IRQHandler(
void
)
{
HAL_DMA_IRQHandler(adc1_handle.DMA_Handle);
}
void
ADC_IRQHandler(
void
)
{
HAL_ADC_IRQHandler(&adc1_handle);
}
I've done many tests but I can't figure out why it doesn't work or if it's correct due to the lack of example code.
#hal-adc-dma-triplemode #i-can't-help-you-with-that