2020-07-28 08:08 AM
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
2020-07-28 08:44 AM
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...
2020-07-28 08:57 AM
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 */
}
2020-07-28 09:14 AM
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
2020-07-28 09:18 AM
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)
2020-07-28 09:23 AM
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?
2020-07-28 10:44 AM
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;
2020-07-28 02:00 PM
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?
2020-07-29 01:30 AM
HAL_ADC_ConvCpltCallback and when you need repeat without start next conversion by sw , try
ContinuousConvMode or DMAContinuousRequests
2020-07-29 01:44 AM
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