cancel
Showing results for 
Search instead for 
Did you mean: 

Hi I like to read out 4 ADC Channels of ADC1 on every edge-change of Timer4. With Interrupt Mode its working, with DMA no restart.

dominik
Senior

I have Timer4 configured as a OC timer, the trigger Out event should trigger every rising and falling edge the ADC1 to read 4 channels (CH1-CH4). The trigger event to the ADC runs, when I don't use the DMA. I tried to use the Interrupt function with HAL_ADC_Start_IT(&hadc1); With this function its working, but I can't read in the different channels with the function "HAL_ADC_GetValue" in the IRQ-Function "void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)"

Because of this I tried to use the DMA and like to trigger the ADC like before and read out the values after converting the 4 Channels. But the DMA is not getting getriggered and the values are incorrect. How could this be so difficult to set-up, this is a really basic function. Please help me.

Thanks

9 REPLIES 9
MM..1
Chief III

Your code is little complicated . Simply you need start first conversion for DMA with HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buf, ADC_BUF_LEN);

where buf must exist and size for 1x chan_count or Nxchan_count for more as one measure store.

Then in dma complete irq you need restart it with same function...

I don't understand why I need to restart, with Interrupt I don't need to restart and its working, but ok, I restart in the DMA Interrupt and now the trigger is running, only the result is wrong (I have only the first 2 Channels, the CH3+4 is always 0.

static uint32_t ADC_Values[4];

In the init function I use:

HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC_Values, 4);

Then in the callback:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    if (hadc->Instance == ADC1)
    {
        HAL_GPIO_TogglePin (Error_Reset_1_GPIO_Port, Error_Reset_1_Pin);
        HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC_Values, 4);
 
        ADC_Niveau.BoilerLow = ADC_Values[0];
        ADC_Niveau.BoilerHigh = ADC_Values[1];
        ADC_Niveau.TankHigh = ADC_Values[2];
        ADC_Niveau.TankUeberlauf = ADC_Values[3];
 
    }
}

The DMA callback I don't use or should I place my code here?

/**
  * @brief This function handles DMA1 channel6 global interrupt.
  */
void DMA1_Channel6_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Channel6_IRQn 0 */
 
  /* USER CODE END DMA1_Channel6_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_adc1);
  /* USER CODE BEGIN DMA1_Channel6_IRQn 1 */
 
  /* USER CODE END DMA1_Channel6_IRQn 1 */
}

dominik
Senior

I changed the code to this function:

void ADC1_Read (void)
{
    ADC_Niveau.BoilerLow = ADC_Values[0];
    ADC_Niveau.BoilerHigh = ADC_Values[1];
    ADC_Niveau.TankHigh = ADC_Values[2];
    ADC_Niveau.TankUeberlauf = ADC_Values[3];
 
    HAL_GPIO_TogglePin (Error_Reset_1_GPIO_Port, Error_Reset_1_Pin);
    HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC_Values, 4);
}

called from the DMA:

void DMA1_Channel6_IRQHandler(void)
{
    /* USER CODE BEGIN DMA1_Channel6_IRQn 0 */
 
    /* USER CODE END DMA1_Channel6_IRQn 0 */
    HAL_DMA_IRQHandler(&hdma_adc1);
    /* USER CODE BEGIN DMA1_Channel6_IRQn 1 */
    ADC1_Read();
    /* USER CODE END DMA1_Channel6_IRQn 1 */
}

but The problem with the values was: (DMA on Wortd not HalfWord !!!)

hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;

Now I have all values in my Array, I will check tomorrow how its working

dominik
Senior

But I need to read out the data in the HAL_ADC_ConvCpltCallback Function, the DMA is firing twice...

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    if (hadc->Instance == ADC1)

dominik
Senior

The values are not really stable, but with a bigger sample time its better

sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5;

How I calculate the sample time for good results?

MM..1
Chief III

Yes HAL have this handler for complete dma adc

And i recommend use uint16_t ADC_Values[4];

  hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;

  hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;

So I should use the HAL_ADC_ConvCpltCallback or the DMA IRQ? I like to use the DMA IRQ, but I don't know why this IRQ is triggered twice, maybe on Start and End of DMA? Or is there a setup to choose which one should trigger the IRQ?

MM..1
Chief III

HAL_ADC_ConvCpltCallback and when you need repeat without start next conversion by sw , try

ContinuousConvMode or DMAContinuousRequests

dominik
Senior

Its working like this:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    if (hadc->Instance == ADC1)
    {
        ADC1_Read();
    }
}

and in the ADC1_Read function I start the DMA again, its running now without problem, trigger source is OC event from Timer4, the GPIO toggle was to check the time when ADC conversion is finished

void ADC1_Read (void)
{
    ADC_Niveau.BoilerLow = ADC_Values[0];
    ADC_Niveau.BoilerHigh = ADC_Values[1];
    ADC_Niveau.TankHigh = ADC_Values[2];
    ADC_Niveau.TankUeberlauf = ADC_Values[3];
    //eud Test
    HAL_GPIO_TogglePin (Error_Reset_1_GPIO_Port, Error_Reset_1_Pin);
    HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC_Values, 4);
}

Trigger for the ADC Event = CH1, CH2 = ADC to measure

0693W000003BaqqQAC.jpg