cancel
Showing results for 
Search instead for 
Did you mean: 

Timer slave configuration is not initialized correct with CubeMX inside STM32CubeIDE

Benjamin Brammer
Senior II

Hello everybody,

I think I have stumbled accross a configuration and initialization error when using STM32CubeIDE and the CubeMX peripheral initialization:

I am using a NUCLEO-L476RG board and want to use TIM2 to trigger TIM3 as a slave and start both timers simultaniously. As for TIM2 I use the following settings:

0690X00000Aro6FQAR.png

for TIM3 the following:

0690X00000Aro6oQAB.png

I also have acitvated the global interrupt on both timers since I want to use TIM3 to trigger the ADC and convert samples as long as TIM3 runs. TIM2 is the period at which I will send the avareged ADC samples to an external host.

So I normaly thouight that the code generator would uses the

HAL_TIM_SlaveConfigSynchro_IT(&htim3, &sSlaveConfig)

function. But instead I get the following initialization which I then manually change in the interrupt driven slave configuration function:

void MX_TIM3_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_SlaveConfigTypeDef sSlaveConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
 
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 60000;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 0;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sSlaveConfig.SlaveMode = TIM_SLAVEMODE_COMBINED_RESETTRIGGER;
  sSlaveConfig.InputTrigger = TIM_TS_ITR1;
  if (HAL_TIM_SlaveConfigSynchro(&htim3, &sSlaveConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
 
}

Is this an error with the code generator, or do I misunderstand here something?

best regards

Benjamin

1 ACCEPTED SOLUTION

Accepted Solutions
Benjamin Brammer
Senior II

OK. I have found the problem.

The UIE Bit for update interval interrupt request inside the TIMx DMA/Interrupt enable register (TIMx_DIER) was not set on the slave timer. This gets set when the function HAL_TIM_Base_Start_IT(&htimx) gets called. This function is clever enough to check wether a timer instance is in triggered slave mode or not and activates the UIE Bit. Now everything works fine.

The function HAL_TIM_SlaveConfigSynchro_IT(&htim3, &sSlaveConfig) activates only the TIE Bit (trigger interrupt) not the UIE.

View solution in original post

6 REPLIES 6
Benjamin Brammer
Senior II

mhh...I think I need more advise than I expected, since what I want to achieve doesn't work so far:

I want to use Timer2 as period timer at which rate I write sampled ADC values to an external host. Timer3 shall act as the time how long I sample on the ADC and average the values. So for instance I want to sample over 1 second with Timer3 and send every 2 seconds (timer2) the avareged ADC value. The important part is, that the external host can change the ARR values of Timer2 and Timer3.

I tried to configure both timers in my post from above and to start the ADC conversion manually when I start Timer2:

/**
 * @brief	ADC conversion start depending on LENGTH and INTERVAL
 * 			(specified in the project specification). INTERVAL is
 * 			the time at which ADC conversions are sent to a host
 * 			(C3 or C4). LENGTH is the duration of ADC data acquisition.
 * 			LENGTH can never be more than INTERVAL!
 * @param	length, duration of ADC data acquisition in s.
 * 			interval, period at which ADC conversions are sent to a host in s.
 */
void ADC_start_conversion(uint16_t length, uint16_t interval)
{
 
	  TIM3->ARR = (uint16_t)length/0.0025;			// TIM3 runs at 2,5ms per tick
	  TIM2->ARR = (uint16_t)interval/0.0025;			//TIM2 runs at 2,5ms per tick
 
	  /* start ADC */
	  if(HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADCBuffer, 2) != HAL_OK)
	  {
		  Error_Handler();
	  }
 
	  if(HAL_TIM_Base_Start_IT(&htim2) != HAL_OK)
	  {
		  Error_Handler();
	  }
}

the problem is, that I only get a HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) from Timer2 but not Timer3. I also tried to implement the HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim) to see if this would trigger one or two of my timer handles, but there is nothing triggered.

Could someone give me a hint/hand on this?

I don't quite understand what do you want to achieve, but you can never go wrong by observing the timers' registers content and checking them against the expected ones.

If interrupts don't fire, check if the respective enable bit(s) in TIMx_DIER are set; if the conditions to fire the interrupt might be (e.g. in case of a large prescaler the timer might run too slowly to reach overflow in a reasonable time); if the proper ISR name is used (check in the disasm of the interrupt vector).

I don't Cube.

JW

Hello Jan,

I checked the interrupts and it seems that the HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim) gets triggered, but only one time.

I want to have a programmable time rate at which I sample ADC values (for averaging) and a programmable time at which I send these avareged values to an external host. either via UART or USB CDC. So I thought I want to achieve this with two timers. On that counts the period at which I send avareged samples and one that counts how long I will sample ADC values for averaging. I also utilize the ADC oversampling feature but nevertheless want to test if I can increase ADC performance and accuracy. At the moment I have about a 12mV error with the ADC. Since I also utilize the integrated OPAMPs peripheral and know that the signal value presented by the OPAMPs to the ADC peripheral is almost accurate (only one or two mV difference from the original input signal), the only point I could fix accuracy is the ADC peripheral.

But despite this, I stil need a programmable version of sample averaging time and sample period presentation time.

As an example, lets assume I want to average over one second and send every two seconds the averaged ADC values via UART.

At the moment this would not work, since the slave timer get's only triggered one time. What I want, is that the slave timer gets triggered every time the master timer (period timer) wraps around, so that every two seconds the averaging timer gets triggered again and starts a new ADC sample collection. But both timers must start at the same time with initial counting.

As I've said, check the timer registers, to find out why you don't have that interrupt.

JW

Maybe it is correct, that the interrupt gets triggered only one time and I am using the false approach for my problem...

I will look into it.

Benjamin Brammer
Senior II

OK. I have found the problem.

The UIE Bit for update interval interrupt request inside the TIMx DMA/Interrupt enable register (TIMx_DIER) was not set on the slave timer. This gets set when the function HAL_TIM_Base_Start_IT(&htimx) gets called. This function is clever enough to check wether a timer instance is in triggered slave mode or not and activates the UIE Bit. Now everything works fine.

The function HAL_TIM_SlaveConfigSynchro_IT(&htim3, &sSlaveConfig) activates only the TIE Bit (trigger interrupt) not the UIE.