2014-12-01 04:06 PM
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
2014-12-15 04:50 PM
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 } }