cancel
Showing results for 
Search instead for 
Did you mean: 

It's 3 times slower - my one microsecond timer configured by CubeMX running on NUCLEO-C031C6 (STM32C031C6)

RongShengWang
Associate II

Hi, 

     My one microsecond timer configured by CubeMx running on NUCLEO-C031C6 (STM32C031C6) is 3 times slower than it should be. The code is attached below.

      the call "delay_us(60000000);" takes 3+ minutes to complete - it should be done in one minute.

      The LL timer (TIM3) init and interrupt code is generated by CubeMx..The system clock is 48 MHZ in CubeMx.

       How to fix it?

       Thanks,

      Rong

 

 

 

void MX_TIM3_Init(void)
{

  LL_TIM_InitTypeDef TIM_InitStruct = {0};

  /* Peripheral clock enable */
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM3);

  /* TIM3 interrupt Init */
  NVIC_SetPriority(TIM3_IRQn, 0);
  NVIC_EnableIRQ(TIM3_IRQn);

  /* USER CODE BEGIN TIM3_Init 1 */

  /* USER CODE END TIM3_Init 1 */
  TIM_InitStruct.Prescaler = 0;
  TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
  TIM_InitStruct.Autoreload = 48;
  TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
  LL_TIM_Init(TIM3, &TIM_InitStruct);
  LL_TIM_EnableARRPreload(TIM3);
  LL_TIM_SetClockSource(TIM3, LL_TIM_CLOCKSOURCE_INTERNAL);
  LL_TIM_SetTriggerOutput(TIM3, LL_TIM_TRGO_RESET);
  LL_TIM_DisableMasterSlaveMode(TIM3);
  /* TIM3 interrupt Init */
}

/* USER CODE BEGIN 1 */
unsigned long u_Count = 0;
/* USER CODE END 1 */
/**
  * @brief This function handles TIM3 global interrupt.
  */
void TIM3_IRQHandler(void)
{
  /* USER CODE BEGIN TIM3_IRQn 0 */

  if (u_Count)
  {
	  u_Count--;
  }
  if (LL_TIM_IsActiveFlag_UPDATE(TIM3))
 	LL_TIM_ClearFlag_UPDATE(TIM3);
  /* USER CODE END TIM3_IRQn 0 */
}

void delay_us(const unsigned long us_Count)
{
	u_Count = us_Count;
	LL_TIM_EnableIT_UPDATE(TIM3);
	LL_TIM_EnableCounter(TIM3);
	while (u_Count !=0) 
        {
        }
	LL_TIM_DisableIT_UPDATE(TIM3);
	LL_TIM_DisableCounter(TIM3);
}

int main(void)
{
  static unsigned int i = 0;
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM3_Init();
  MX_SPI1_Init();
  MX_USART2_UART_Init();

  delay_us(60000000);
}

 

 

   

7 REPLIES 7
TDK
Guru

The chip cannot process interrupts at 1 MHz. It will fall behind. Set your interrupt frequency to a max of about 10 kHz so one interrupt can finish before the next one is triggered.

Also note that if you have a timer frequency of 48 MHz, you want ARR=47 in order to have an update interval of 1 us. So for 10 kHz, it should be 4799.

If you feel a post has answered your question, please click "Accept as Solution".

As repeatedly covered on this forum, you can't sustain 1 MHz interrupt rate, it will saturated the processor just trying to do that. So don't do it that way.

Configure the TIM in maximal mode, say 0xFFFF or 0xFFFFFFFF with a prescaler that clocks the count at 1 MHz, and then delta the entry and exit points.

uint16_t start =TIM3->CNT;

while((TIM3->CNT - start) < usdelay);

For finer resolution clock faster. For longer delays with 16-bit counters, decompose into 60 ms (60000 us) intervals

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Hi, Guru,

    So I can not have a 1 us timer, which I need,in STM32C031C6?, 

    What is the fastest timer I can have in this micro ?

Thanks

Rong

Hi, Tesla,

     Could you give me the detail code for having 1 us timers? 

     I used CubeMx to generate the code. 

     "Configure the TIM in maximal mode," - How to do this?

    Thanks,

 

Rong

 

 

void MX_TIM3_Init(void)
{

  /* USER CODE BEGIN TIM3_Init 0 */

  /* USER CODE END TIM3_Init 0 */

  LL_TIM_InitTypeDef TIM_InitStruct = {0};

  /* Peripheral clock enable */
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM3);

  /* TIM3 interrupt Init */
  NVIC_SetPriority(TIM3_IRQn, 0);
  NVIC_EnableIRQ(TIM3_IRQn);

  /* USER CODE BEGIN TIM3_Init 1 */

  /* USER CODE END TIM3_Init 1 */
  TIM_InitStruct.Prescaler = 0;
  TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
  TIM_InitStruct.Autoreload = 48;
  TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
  LL_TIM_Init(TIM3, &TIM_InitStruct);
  LL_TIM_EnableARRPreload(TIM3);
  LL_TIM_SetClockSource(TIM3, LL_TIM_CLOCKSOURCE_INTERNAL);
  LL_TIM_SetTriggerOutput(TIM3, LL_TIM_TRGO_RESET);
  LL_TIM_DisableMasterSlaveMode(TIM3);
  /* USER CODE BEGIN TIM3_Init 2 */
  /* TIM3 interrupt Init */

  /* USER CODE END TIM3_Init 2 */

}

 

 

Not using interrupts

 

  TIM_InitStruct.Prescaler = 48 - 1; // Divider 48 MHz to 1 MHz (1 us ticks)
  TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
  TIM_InitStruct.Autoreload = 0xFFFF; // Maximal Count 0..65535
  TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;

You're using it to count elapsed time, up to 65.535 ms per update period

 

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
BarryWhit
Senior III

The combination of high resolution with very long delay times (1 minutes with 1us) is quite odd. If this is an actual requirement, you should explain where it came from - because it suggests that perhaps you haven't properly analyzed whatever problem you're trying to solve.

 

As TDK and tesla have said, you can setup a tick timer to go faster than the system tick timer (which runs at 1ms), but it's not reasonable to have it run 1000x faster. If you need higher resolution and a longer period, using a while loop to delay is almost certainly the wrong approach.

 

You should perhaps consider, instead, using a timer's update ("overflow") event to trigger an interrupt. With some tweaking of priorities and period values, you should be able to get the first instruction in your ISR to execute with sufficient accuracy.

 

The STM32C031C6 does not have a 32bit timer, only 16 bit timer. But TIM1 has a 16 bit repetition counter, so you could timing accuracy close to 1 cycle (you would have to tweak to account for interrupt overhead to time things just so).

 

But, a standard crystal will only give you around 20ppm accuracy, and even a pricey TCXO (~10$) would only get you down to 1ppm. That means that, over the span of a minute, the cumulative measurement error due to the the nominal frequency error of the crystal itself would be on the order of 1-20 us. So you would have to carefully tune your your timer values by comparing their timing to an even more accurate and reliable and well-maintained and expensive piece of test equipment which has traceable calibration to an atomic clock somewhere, probably at NIST. And you would have to do that for that particular board, and crystal, and it would be valid within a certain tolerance, within a specific range of environmental conditions, and for limited amount of time due to component aging. All of which you would have to calculate and validate and specify and document and pass through design review and monitor over time.  And all that's assuming that thermal and mechanical stresses during assembly, transportation, and operation do not degrade the performance of the circuit. Which means you'll have to setup a periodic calibration and maintenance schedule. Which means you'll also have to periodically calibrate and verify the accuracy of your expensive time-base test equipment. All this costs a lot of time and money. And your first step seems to have been to select a low-end budget-line MCU as the basis for your design. 

 

The point being that:

1. What you're trying to do is actually quite tricky and

2. You almost certainly don't have a real need to do it, or you would already be well aware of all of the above and have a shiny (and gold-plated beautifully with astonishing thickness uniformity) pin on your lapel which reads "Kiss the metrologist".

- If a post has answered your question, please acknowledge the help you received by clicking "Accept as Solution".
- Once you've solved your issue, please consider posting a summary of any additional details you've learned. Your new knowledge may help others in the future.

Hi, Tesla,

     Understand. I will try.

     Thank you very much. 

Rong