2021-05-30 10:16 PM
I am using STM32L072xx module and I would like to use ADC4, ADC5 and ADC 17 (Vrefint) at the same time. But I want to use ADC4 with DMA of buffer size 500 or more. It is not necessary to store ADC5 & ADC17 in DMA.
Can I use DMA only for ADC 4 and dump 500 samples and use the following API calls for ADC5 and ADC17?
HAL_ADC_Start( &hadc);
/* Wait for the end of conversion */
HAL_ADC_PollForConversion( &hadc, HAL_MAX_DELAY );
/* Get the converted value of regular channel */
adcData = HAL_ADC_GetValue ( &hadc);
Is this the right way of configuring multiple ADC channels?
Solved! Go to Solution.
2021-06-01 05:05 AM
Hello @CDesh ,
You'll probably want to review the working "ADC_DMA_Transfer" example within the STM32CubeL0 MCU package and you can get inspired from this:
STM32Cube_FW_L0_V1.12.0\Projects\NUCLEO-L073RZ\Examples\ADC\ADC_DMA_Transfer
Imen
2021-06-01 05:05 AM
Hello @CDesh ,
You'll probably want to review the working "ADC_DMA_Transfer" example within the STM32CubeL0 MCU package and you can get inspired from this:
STM32Cube_FW_L0_V1.12.0\Projects\NUCLEO-L073RZ\Examples\ADC\ADC_DMA_Transfer
Imen
2021-07-05 07:36 AM
Hello @CDesh ,
On STM32L0, you cannot use DMA on only some ADC channels: when activated, it transfers data of all channels configured (it is not the case on some other STM32 series like STM32L4 with ADC featuring 2 groups regular and injected, in this case group regular can use DMA and group injected can operate without DMA transfer).
The right way to use multiple channels with DMA transfer (recommended to use DMA):
1. Enable DMA transfer:
hadc1.Init.DMAContinuousRequests = ENABLE;
...
HAL_ADC_Init(&hadc1)
2. Configure as many channels as you want:
sConfig.Channel = <ADC_CHANNEL_x>;
HAL_ADC_ConfigChannel(&adc1, &sConfig)
...
sConfig.Channel = <ADC_CHANNEL_y>;
HAL_ADC_ConfigChannel(&hadc1, &sConfig)
...
sConfig.Channel = <ADC_CHANNEL_z>;
HAL_ADC_ConfigChannel(&adc1, &sConfig)
3. Start conversion
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)aADCxConvertedData, ADC_CONVERTED_DATA_BUFFER_SIZE)
You can refer to examples in STM32L0 FW package:
Using ADC LL driver:
...\Firmware\Projects\NUCLEO-L073RZ\Examples_LL\ADC\ADC_MultiChannelSingleConversion
Using ADC HAL driver:
...\Firmware\Projects\NUCLEO-L053R8\Examples\ADC\ADC_Sequencer
Best regards
Philippe
2021-08-02 12:36 AM
Thanks @Imen DAHMEN and @Philippe Cherbonnel for you feedback. I followed the similar approach and able to handle DMA on multiple ADC channels.
But this approach posing a different challenge.
Along with ADC DMA on PA4, I am also using comparator COMP2 in interrupt mode. When ever I enable the following lines , controller is getting stuck.
HAL_NVIC_SetPriority(ADC1_COMP_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(ADC1_COMP_IRQn);
As a probably solution , I added following lines in the code which is not helping.
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn);
HAL_DMA_Abort(&hdma_adc);
}
Is this because ADC1_COMP_IRQn = 12, is a shared number for ADC1, COMP1 and COMP2 Interrupts and ADC transfer is happening via DMA. Please note, this issue did not occur when PollForConversion (HAL_ADC_PollForConversion( &hadc, HAL_MAX_DELAY );) was used.
If so, I am looking for a lead to handle these interrupts. Any feedback would be appreciated.
2021-08-02 05:55 AM
Hello @CDesh ,
Using ADC and comparator with the common interrupt line ADC1_COMP_IRQn is possible.
I have 2 comments:
1. ADC vs DMA IRQ handlers:
Function HAL_ADC_Start_DMA() does not enable ADC interruptions (except overrun, which should not occur unless wrong DMA config or high transfers load),
therefore using it or using polling should make any difference regarding this IRQ handler.
The IRQ handler used will be the one of DMA, for example DMA1_Channel1_IRQHandler().
Can you try to disable comparators and check that you do not enter in ADC1_COMP_IRQHandler(), and effectively enter in DMA1_Channel1_IRQHandler() ?
2. IRQ handler shared by ADC and comparators
When you mention "controller is getting stuck", are you able to break the program with a debugger ? If yes, the call stack shows program handler mode (from IRQ) or in thread mode ?
A hypothesis is that you are stuck in an IRQ handler.
Do you process all possible IRQ event sources like this :
void ADC1_COMP_IRQHandler(void)
{
HAL_ADC_IRQHandler(&AdcHandle);
HAL_COMP_IRQHandler(&Comp1Handle);
HAL_COMP_IRQHandler(&Comp2Handle);
}
Best regards
Philippe
2021-08-02 06:05 AM
@Philippe Cherbonnel Thanks for your response.
(1) when I comment following sections, code is working as expected with 4000 samples in DMA buffer
(2) I am getting stuck when I apply break points with debugger too. Unable to break the program with debugger at HAL_ADC_DeInit(&hadc); / HAL_ADC_Init( &hadc );
2021-08-03 02:15 AM
@Philippe Cherbonnel
I am processing IRQ event sources like:
void ADC1_COMP_IRQHandler(void)
{
HAL_COMP_IRQHandler(&Comp1Handle);
}
Also using overrun setting as mentioned below:
hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
2021-08-04 01:34 AM
Hello @CDesh ,
I have made a basic program running on board NUCLEO-STM32L053R8, see file attached "ADC_and_comparator_IT.zip":
- ADC conversion data transferred by DMA
- COMP1 trigger with interruption
- program generated from CubeMX for CubeIDE (if needed, you can generated for IAR-EWARM or MDK-ARM with CubeMX)
- Other details are in file readme.txt
All is working correctly with IRQ handler ADC1_COMP_IRQHandler shared by ADC and comparator.
Can you test it on your side and compare with your program ?
Best regards
Philippe
2021-08-05 02:10 PM
@Philippe Cherbonnel
I did compare your program with mine.
It would work fine if single channel with limited samples are used. But I am using the following with 3 different ADC channels with different buffer lengths
for (j=0; j<2; j++) {
MX_AdcInit(ADC_CHANNEL, (uint32_t *)aADCxConvertedData,4000 );
extract data from DMA buffer
}
where as :
void MX_AdcInit( uint32_t Channel, uint32_t* pData, uint32_t Length )
{
ADC_ChannelConfTypeDef sConfig;
hadc.Instance = ADC1;
hadc.Init.OversamplingMode = DISABLE;
hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV1;
hadc.Init.LowPowerAutoPowerOff = DISABLE;
hadc.Init.LowPowerFrequencyMode = ENABLE;
hadc.Init.LowPowerAutoWait = DISABLE;
hadc.Init.Resolution = ADC_RESOLUTION_12B;
hadc.Init.SamplingTime = ADC_SAMPLETIME_160CYCLES_5;
hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ContinuousConvMode = ENABLE;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START; /* Software start to trig the 1st conversion manually, without external event */
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc.Init.DMAContinuousRequests = ENABLE;
hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED; /* DR register is overwritten with the last conversion result in case of overrun */
ADCCLK_ENABLE();
if (HAL_ADC_Init(&hadc) != HAL_OK)
{
Error_Handler();
}
HAL_ADCEx_Calibration_Start(&hadc, ADC_SINGLE_ENDED);
/* Deselects all channels*/
sConfig.Channel = ADC_CHANNEL_MASK;
sConfig.Rank = ADC_RANK_NONE;
HAL_ADC_ConfigChannel( &hadc, &sConfig);
sConfig.Channel = Channel;
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
if(HAL_ADC_Start_DMA(&hadc,(uint32_t *)pData,Length) != HAL_OK)
{
PRINTF("ADC DMA error \n\r");
Error_Handler();
}
ADCCLK_DISABLE();
}
for j=0, I am able to getting values in buffer appropriately. When j increments to 1,
MX_AdcInit(ADC_CHANNEL, (uint32_t *)aADCxConvertedData,ADC_DATA_BUFFER_SIZE ); line is freezing forever.
I also tried the following, but is not helping.
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
HAL_ADC_Stop(&hadc);
or
HAL_NVIC_DisableIRQ(DMA1_Channel1_IRQn);
or
HAL_ADC_Stop_DMA(&hadc);
or
HAL_DMA_Abort(&hadc);
}
2021-08-06 08:06 AM
@Philippe Cherbonnel
I believe nesting of interrupts is not handled properly. Following are priorities assigned to IRQs
HAL_NVIC_SetPriority(ADC1_COMP_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(ADC1_COMP_IRQn);
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
Following is the output. ADC DMA1 IRQ is often getting interrupted by COM IRQ
----------------------------------------------------------------
adcFinal: 4095
Conversion completed
bufferVal:4095
Conversion completed
Comparator:1
Comparator:2
bufferVal:0
Comparator:3
Comparator:4
Comparator:5
Comparator:6
Comparator:7
adcFinal: 4095
Conversion completed
bufferVal:4095
-----------------------------------------------------------------
Any suggestion would be appreciated.