STM32L432KC - Timer DMA Triggering ADC DMA?
Hi,
On my larger project, I would like to be able to generate a timer that will trigger an ADC read on each rising edge. I was able to tackle this problem by creating a smaller project and executing it! Super excited.
My excitement was a bit dampened when I realized how many interrupts were firing fromthe timer. For this test, I am currently operating my timer at ~123kHz which equates to roughly 8.13uS. While this is fine running on a while(1) loop example, I don't think it will go well with my larger project running FreeRTOS.
Now comes the question:
Is there a way to set this up where the timer can generate a DMA to trigger the ADC read using the DMA? I would imagine this is the best path forward to minimize CPU usage if possible. That way, I am not firing my interrupts every 8.13uS. If not, what is the best engineering practice?
Any example code is greatly appreciated! I just couldn't seem to find any post in this community trying to user a timer with DMA access to trigger an ADC DMA.
According to RM0393 (Page 776), it looks as if I should be able to doan event trigger on TIM15:
• Interrupt/DMA generation on the following events:
– Update: counter overflow, counter initialization (by software or internal/external trigger)
– Trigger event (counter start, stop, initialization or count by internal/external trigger)
– Input capture
– Output compare
– Break input (interrupt request)
Note: I am currently not DMA-ing the ADC in this example. This will be done on the larger project!
I am not actually grabbing the ADC value but toggling a pin to know that the ADC is being called on the rising edge of the timer.
Main:
int main(void)
{
/* Clock Inits*/
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_TIM15_Init();
MX_ADC1_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim15);
HAL_ADC_Start_IT(&hadc1);
/* USER CODE END 2 */
/* Infinite loop */
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
Callbacks:
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
if (hadc->Instance==ADC1)
{
HAL_GPIO_TogglePin(USER_ADC_TOGGLE_PIN_GPIO_Port, USER_ADC_TOGGLE_PIN_Pin);
}
}�?�?�?�?�?�?�?
Interrupt:
void TIM1_BRK_TIM15_IRQHandler(void)
{
HAL_GPIO_TogglePin(USER_TIMER_TOGGLE_PIN_GPIO_Port, USER_TIMER_TOGGLE_PIN_Pin);
HAL_TIM_IRQHandler(&htim15);
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
Timer / ADC Setup:
static void MX_TIM15_Init(void)
{
TIM_MasterConfigTypeDef sMasterConfig;
TIM_OC_InitTypeDef sConfigOC;
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig;
htimInstance = TIM15;
htimInit.Prescaler = 47;
htimInit.CounterMode = TIM_COUNTERMODE_UP;
htimInit.Period = 1;
htimInit.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htimInit.RepetitionCounter = 0;
if (HAL_TIM_PWM_Init(&htim15) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim15, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
if (HAL_TIM_PWM_ConfigChannel(&htim15, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 0;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.BreakFilter = 0;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
if (HAL_TIMEx_ConfigBreakDeadTime(&htim15, &sBreakDeadTimeConfig) != HAL_OK)
{
Error_Handler();
}
}
static void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig;
/**Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DiscontinuousConvMode = ENABLE;
hadc1.Init.NbrOfDiscConversion = 1;
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIG_T15_TRGO;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
hadc1.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/**Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_8;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
#•-interruptdma-generation-on-the-following-events:-–-up