cancel
Showing results for 
Search instead for 
Did you mean: 

Triple mode ADC with new HAL

b2527456
Associate II
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
5 REPLIES 5
Posted on December 02, 2014 at 01:00

Please try the [DEAD LINK /public/STe2ecommunities/mcu/Lists/STM32Java/AllItems.aspx]HAL/Cube sub-forum

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
b2527456
Associate II
Posted on December 02, 2014 at 17:18

Please, can some from ST post some working example code. I'm not asking for a solution for my specific problem, just some example code as it was available int the old stdPeriph package.

b2527456
Associate II
Posted on December 02, 2014 at 18:16 I modified the code to ''link'' only ADC1 with DMA and manually start the ADC 2 and 3 withADCx->CR2 |= (uint32_t)ADC_CR2_ADON Still no improvements...

void
HAL_ADC_MspInit(ADC_HandleTypeDef* adc_handler)
{
if
(adc_handler->Instance != ADC1)
return
;
/****************************************************/

b2527456
Associate II
Posted on December 03, 2014 at 12:35

Since I've got no response I've try to follow another way using the ADC(s) independently with injected channel, and the conversion triggered by TIM1 CC4.

So, even in this case troubles... the manual UM1725, at page 97, says: Start the ADC peripheral using HAL_ADCEx_InjectedStart_DMA()

 

The problem is that there is NO such a function in the stm32f4xx_hal_adc_ex.c HAL file!

Totally nightmarish....

Posted on February 27, 2015 at 09:27

Hello,

The root cause of your problem is probably an overhead situation in IRQ handler:

Let’s calculate the ADC conversion rate vs CPU cycles:

The ADC are configured to run at PCLK/2. ADC is clocked by APB2. Assuming APB2 prescaler is 2, we have ADC clock frequency = PCLK/4.

Conversion time:

- ADC resolution 12 bits and sampling time 15 ADC cycles.

- conversion time = sampling time + conversion time = 15 ADC cycles + 12 ADC cycles = 27 ADC cycles.

- ADC single conversion rate is: 1 ADC conversion every 108 CPU cycles.

- multimode is regular simultaneous in triple mode: 3 conversions per 27 ADC cycles

- ADC multimode (triple mode) conversion rate is: 1 ADC conversion every 36 CPU cycles.

Then, all depends on you DMA buffer size (array ''phases_v'' in your program).

If you buffer size is 3, then you will have a DMA transfer complete interruption every 108 CPU cycles. => This is very short, if you have some other interruptions or some processing to treat, CPU will be saturated by DMA interruptions.

You must decrease the occurrence rate of DMA transfer complete, therefore:

- either increase the ADC sampling time

- either increase the DMA buffer size

An example is available in the STM32F4 HAL SW package, in folder:

STM32Cube_FW_F4_V1.4.0\Projects\STM324xG_EVAL\Examples\ADC\ADC_TripleModeInterleaved. Unfortunately, this example, has the same issue as yours: sampling time must be increased from ADC_SAMPLETIME_3CYCLES to ADC_SAMPLETIME_15CYCLES. This will be corrected in the next STM32F4 HAL package release.

About your last post in the forum: only regular group has DMA capability, not injected group.

The mention of '' HAL_ADCEx_InjectedStart_DMA()'' is an error and has been corrected in the last release of STM32F4 HAL driver (v1.4).

Best regards,

Heisenberg.