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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-07-28 8: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
- Labels:
-
ADC
-
DMA
-
STM32Cube MCU Packages
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-07-28 8: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...
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-07-28 8: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 */
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-07-28 9: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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-07-28 9: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)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-07-28 9: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?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎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;
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-07-28 2: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?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-07-29 1:30 AM
HAL_ADC_ConvCpltCallback and when you need repeat without start next conversion by sw , try
ContinuousConvMode or DMAContinuousRequests
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-07-29 1: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
