cancel
Showing results for 
Search instead for 
Did you mean: 

How can I debug TIM1 triggering a DMA from ETR2 if it isn't working?

Legacy member
Not applicable

On an L412KB Nucleo, I configured TIM1 to use ETR2 as a clock source and set the counter period to 1 so that every time a rising edge occurs on the TIM1_ETR pin occurs, it should trigger a DMA. I set up DMA1/Ch6 to respond to TIM_UP for a byte sized peripheral-to-memory from GPIOA (since my D0-D7 input parallel data is on those pins).

I can start the TIM1 and verify it is triggering if I enable its interrupt. That works. However, I do not see the DMA happening when I examine the destination memory, nor is a DMA interrupt generated (it is also enabled in NVIC). So I can't tell where the failure is coming from. (I expect to see `byteBuffer` fill with &GPIOA->IDR which is hardwired externally to 0x82, but it remains zero). Did I forget to turn something on / enable something?

Here's the `main.c`:

/* USER CODE BEGIN Header */

/**

 ******************************************************************************

 * @file          : main.c

 * @brief         : Main program body

 ******************************************************************************

 * @attention

 *

 * <h2><center>&copy; Copyright (c) 2022 STMicroelectronics.

 * All rights reserved.</center></h2>

 *

 * This software component is licensed by ST under BSD 3-Clause license,

 * the "License"; You may not use this file except in compliance with the

 * License. You may obtain a copy of the License at:

 *                       opensource.org/licenses/BSD-3-Clause

 *

 ******************************************************************************

 */

/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/

#include "main.h"

/* Private includes ----------------------------------------------------------*/

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/

/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/

/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/

/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

I2C_HandleTypeDef hi2c1;

TIM_HandleTypeDef htim1;

TIM_HandleTypeDef htim2;

DMA_HandleTypeDef hdma_tim1_up;

/* USER CODE BEGIN PV */

volatile uint8_t idr = 0;

volatile uint8_t byteBuff[256];

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/

void SystemClock_Config(void);

static void MX_GPIO_Init(void);

static void MX_I2C1_Init(void);

static void MX_TIM2_Init(void);

static void MX_DMA_Init(void);

static void MX_TIM1_Init(void);

/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**

 * @brief The application entry point.

 * @retval int

 */

int main(void)

{

 /* USER CODE BEGIN 1 */

 /* USER CODE END 1 */

 /* MCU Configuration--------------------------------------------------------*/

 /* Reset of all peripherals, Initializes the Flash interface and the Systick. */

 HAL_Init();

 SystemClock_Config();

 MX_GPIO_Init();

 MX_I2C1_Init();

 MX_TIM2_Init();

 MX_DMA_Init();

 MX_TIM1_Init();

 idr = GPIOA->IDR;

 HAL_DMA_Start_IT(&hdma_tim1_up, (uint32_t)&(GPIOA->IDR), (uint32_t)byteBuff, 0x10);

 HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_MSI, RCC_MCODIV_2);

 HAL_TIM_Base_Start(&htim1);

 while (1)

 {

 }

}

static void MX_TIM1_Init(void)

{

 TIM_ClockConfigTypeDef sClockSourceConfig = {0};

 TIM_MasterConfigTypeDef sMasterConfig = {0};

 htim1.Instance = TIM1;

 htim1.Init.Prescaler = 0;

 htim1.Init.CounterMode = TIM_COUNTERMODE_UP;

 htim1.Init.Period = 1;

 htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

 htim1.Init.RepetitionCounter = 0;

 htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;

 if (HAL_TIM_Base_Init(&htim1) != HAL_OK)

 {

   Error_Handler();

 }

 sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_ETRMODE2;

 sClockSourceConfig.ClockPolarity = TIM_CLOCKPOLARITY_NONINVERTED;

 sClockSourceConfig.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1;

 sClockSourceConfig.ClockFilter = 15;

 if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)

 {

   Error_Handler();

 }

 sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;

 sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;

 sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;

 if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)

 {

   Error_Handler();

 }

}

static void MX_DMA_Init(void)

{

 __HAL_RCC_DMA1_CLK_ENABLE();

 HAL_NVIC_SetPriority(DMA1_Channel6_IRQn, 0, 0);

 HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn);

}

... and here's the MSP code ...

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)

{

 GPIO_InitTypeDef GPIO_InitStruct = {0};

 if(htim_base->Instance==TIM1)

 {

   __HAL_RCC_TIM1_CLK_ENABLE();

   __HAL_RCC_GPIOA_CLK_ENABLE();

   /**TIM1 GPIO Configuration

   PA12    ------> TIM1_ETR

   */

   GPIO_InitStruct.Pin = GPIO_PIN_12;

   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

   GPIO_InitStruct.Pull = GPIO_NOPULL;

   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

   GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;

   HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

   /* TIM1 DMA Init */

   /* TIM1_UP Init */

   hdma_tim1_up.Instance = DMA1_Channel6;

   hdma_tim1_up.Init.Request = DMA_REQUEST_7;

   hdma_tim1_up.Init.Direction = DMA_PERIPH_TO_MEMORY;

   hdma_tim1_up.Init.PeriphInc = DMA_PINC_DISABLE;

   hdma_tim1_up.Init.MemInc = DMA_MINC_ENABLE;

   hdma_tim1_up.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

   hdma_tim1_up.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;

   hdma_tim1_up.Init.Mode = DMA_NORMAL;

   hdma_tim1_up.Init.Priority = DMA_PRIORITY_HIGH;

   if (HAL_DMA_Init(&hdma_tim1_up) != HAL_OK)

   {

     Error_Handler();

   }

   __HAL_LINKDMA(htim_base,hdma[TIM_DMA_ID_UPDATE],hdma_tim1_up);

   /* TIM1 interrupt Init */

   HAL_NVIC_SetPriority(TIM1_BRK_TIM15_IRQn, 0, 0);

   HAL_NVIC_EnableIRQ(TIM1_BRK_TIM15_IRQn);

   HAL_NVIC_SetPriority(TIM1_UP_TIM16_IRQn, 0, 0);

   HAL_NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn);

   HAL_NVIC_SetPriority(TIM1_TRG_COM_IRQn, 0, 0);

   HAL_NVIC_EnableIRQ(TIM1_TRG_COM_IRQn);

   HAL_NVIC_SetPriority(TIM1_CC_IRQn, 0, 0);

   HAL_NVIC_EnableIRQ(TIM1_CC_IRQn);

 /* USER CODE BEGIN TIM1_MspInit 1 */

:

:

1 ACCEPTED SOLUTION

Accepted Solutions

Update, i.e. overflow of the counter, needs at least 2 edges of the input signal (with ARR=0 the timer is stopped, and with ARR=1 it needs to count 0, 1, before it overflows).

You can try to select ETR as input to slave-mode controller in TIMx_SMCR.TS, and then use Trigger as the signal to DMA (i.e. enabling DIER.TDE instead of DIER.UDE).

You've mentioned ETR2 in the initial post, but I can't see any TIM1_ETR2 in 'L412 DS nor RM, so I am not sure how to interpret that.

JW

View solution in original post

6 REPLIES 6

Read out and check/post content of TIM and DMA registers.

JW

Legacy member
Not applicable

Hello @Community member​,

Thank you for replying.

Is this enough?

   ifcr = DMA1->IFCR;

   isr = DMA1->ISR;

   sr  = TIM1->SR;

   dier = TIM1->DIER;

   egr = TIM1->EGR;

I wasn't sure where to set the breakpoint, so I generated a few rising edges on EFR then stopped in the while loop where these were assigned.

All are 0 except SR which is 0x3'001f, and all the lower (set) bits seem to indicate an update is in progress? Not sure how to interpret.

> Is this enough?

Debugger surely allows you to read out all the registers (all registers of of TIM, common and the channel-specific registers of DMA) comfortably. Post them all.

> I wasn't sure where to set the breakpoint,

After a couple of rising edges is OK, as long as it won't run DMA to completion. Otherwise, stop just after enabling everything, before any external signal.

> All are 0

If TIM1->DIER is 0, you don't have enabled DMA trigger nor interrupt. Or you have run to completion and Cube has cleared them for you.

JW

Legacy member
Not applicable

@Community member​ 

Thanks for the insight.

Ok, here are all of them (image below).

However, I think I fixed it. I set the DIER bit for UDE:

   TIM1->DIER |= TIM_DIER_UDE;

I thought CubeMX setting to TIM1_UP would set this bit, but apparently it did not. When I set this bit before while(1){} I now see the data from D0-D7 loading into the memory space (via debugger) and the DMA interrupt being set after 0x10 transfers. Awesome!!! However, the TIM1 requires 32 rising edges, rather than 16, and changing the period does fix that, nor does enabling the DIER_TDE bit since I figured the trigger would work.

Thanks for solving my first part! Any advice on the second part?

0693W00000LyFtZQAV.png

Update, i.e. overflow of the counter, needs at least 2 edges of the input signal (with ARR=0 the timer is stopped, and with ARR=1 it needs to count 0, 1, before it overflows).

You can try to select ETR as input to slave-mode controller in TIMx_SMCR.TS, and then use Trigger as the signal to DMA (i.e. enabling DIER.TDE instead of DIER.UDE).

You've mentioned ETR2 in the initial post, but I can't see any TIM1_ETR2 in 'L412 DS nor RM, so I am not sure how to interpret that.

JW

Legacy member
Not applicable

Everything is fixed. Thanks for the help!