cancel
Showing results for 
Search instead for 
Did you mean: 

Triple mode ADC with new HAL

b2527456
Associate II
Posted on December 02, 2014 at 01:06

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
10 REPLIES 10
chrispaulcole
Associate
Posted on December 16, 2014 at 01:50

I finally figured it out yesterday -- I now have a DMA driven ADC!   I am only using ADC1 -- I know you are trying to get all three ADC units working together, but were you able to get just one to work by itself first?  Here is my code (I am taking 16 samples of ADC1 each time) -- I hope it helps:

#include ''main.h''

#include ''lcd.h''

#include ''stm32f429i_discovery.h''

#include ''stm32f429i_discovery_sdram.h''

#include ''ili9341.h''

#include ''utils.h''

#include ''graphics.h''

void adc_init(void);

volatile uint32_t adcdata[16] = {0};

volatile int debug = 0;

ADC_HandleTypeDef adc_handle;

int main(void)

{

    int reading;

    int i;

    HAL_Init();

    SystemClock_Config();

    BSP_SDRAM_Init();

    LCD_Config();

    lcd_clear();

    adc_init();

    while (1) {

        reading = 0;

        for (i=0; i<16; i++) {

            reading += adcdata[i];

        }

        reading = (reading/56) - 23*10; // formula for zx47 power detector

        print_value(reading, 0);

        HAL_Delay(100);

    }

}

void HAL_ADC_MspInit(ADC_HandleTypeDef* adc_handler)

{

    GPIO_InitTypeDef gpio_init_struct;

    static DMA_HandleTypeDef dma_adc_handler;

    // Enable DMA, ADC and related GPIO ports clock

    __DMA2_CLK_ENABLE();

    __ADC1_CLK_ENABLE();

    __GPIOA_CLK_ENABLE();

    // ADCs GPIO pin configuration

    gpio_init_struct.Pin = GPIO_PIN_5;

    gpio_init_struct.Mode = GPIO_MODE_ANALOG;

    gpio_init_struct.Pull = GPIO_NOPULL;

    HAL_GPIO_Init(GPIOA, &gpio_init_struct);

    // DMA2 Stream4 channel1 (physically mapped to ADC1) configuration

    dma_adc_handler.Instance = DMA2_Stream4;

    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_Stream4_IRQn, 0, 0);

    HAL_NVIC_EnableIRQ(DMA2_Stream4_IRQn);

}

void DMA2_Stream4_IRQHandler(void)

{

    HAL_DMA_IRQHandler(adc_handle.DMA_Handle);

}

void adc_init(void)

{

    ADC_ChannelConfTypeDef adc_config_struct;

    // ADC configuration

    adc_handle.Instance = ADC1;

    adc_handle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV8;

    adc_handle.Init.Resolution = ADC_RESOLUTION12b;

    adc_handle.Init.ScanConvMode = DISABLE;

    adc_handle.Init.ContinuousConvMode = ENABLE;

    adc_handle.Init.DiscontinuousConvMode = DISABLE;

    adc_handle.Init.NbrOfDiscConversion = 0;

    adc_handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;

    adc_handle.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONVEDGE_NONE;

    adc_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT;

    adc_handle.Init.NbrOfConversion = 16;

    adc_handle.Init.DMAContinuousRequests = ENABLE;

    adc_handle.Init.EOCSelection = EOC_SINGLE_CONV;

    if (HAL_ADC_Init(&adc_handle) != HAL_OK) {

        // error

    }

    // Configure ADC channel

    adc_config_struct.Channel = ADC_CHANNEL_5;

    adc_config_struct.Rank = 1;

    adc_config_struct.SamplingTime = ADC_SAMPLETIME_480CYCLES;

    adc_config_struct.Offset = 0;

    if(HAL_ADC_ConfigChannel(&adc_handle, &adc_config_struct) != HAL_OK) {

        // error

    }

    if (HAL_ADC_Start_DMA(&adc_handle, (uint32_t *)&adcdata, 16) != HAL_OK) {

        // error

    }

}