Author Topic: Help with STM32duino timers and frequency measurement  (Read 6177 times)

0 Members and 1 Guest are viewing this topic.

Offline timdf911Topic starter

  • Contributor
  • Posts: 23
  • Country: gb
Help with STM32duino timers and frequency measurement
« on: December 01, 2022, 05:12:11 pm »
Hi guys
1st post but long term lurker !

I've been trying to update a design I originally did 7 years ago which used a Teensy processor and was written entirely in C using the Atmel environmanr.

I've recently discovered the delights of an STM32F401re and have started to port the code using stm32duino environment - but I've run into a road block and despite lots of googling I've made little progress due to being overwhelmed with all the registers associated with the timers and what I suspect is limited timer functionality in the stm32duino environment.

Here's what I need to do - basically a one shot measurement of a frequency between 1 and 30MHz to a resolution of 10kHz.

Here's how I think it should be done

1.  Use timer 2 with the signal using ETR input with possibly the prescaler if it can't handle 30MHz directly
2.  Set the timer2 counter to zero
3. Open the gate for 1mS using a second timer (say timer3) then read the timer 2 to see how many times it's been incremented.  The resulting count should be between 1000 and 30000

To do the above seems to need a bunch of registers setting,  I've had some limited success using some snippets of code from Andrewbcn GPSDO project, but frankly my attempt is a mess and I'd be ashamed to post it !

I'm hoping someone can give me a few pointers on key registers and settings which will link the two timers together and operate as above.

I've tried reading the data and using CubeMx but managed to get myself wrapped round the axle there aswell.

Regards Tim
Tinkering for over 50 years and still learning  G4WIM KT6UK
 


Offline timdf911Topic starter

  • Contributor
  • Posts: 23
  • Country: gb
Re: Help with STM32duino timers and frequency measurement
« Reply #2 on: December 01, 2022, 07:15:47 pm »
Thanks for those links, however during my extensive googling I had already come across them, but maybe I need to give them a second look / chance.

I was deterred from following them as some used CubeMX and / or  did not explicitly use the ETR input for maximum frequency operation.

Maybe I need to practice figuring out how to use CubeMX more efficiently and how to embed the code it generates into mine.

Regards Tim
Tinkering for over 50 years and still learning  G4WIM KT6UK
 

Offline paulca

  • Super Contributor
  • ***
  • Posts: 4046
  • Country: gb
Re: Help with STM32duino timers and frequency measurement
« Reply #3 on: December 01, 2022, 07:55:34 pm »
CubeMX will guide you in what way you 'can' configure all the timers, making it quick to try things.

There is nothing preventing you from creating the basic project in a rapid throw away fashion using CubMX generated code and then put your own further register based code into an isolated C file.  You can re-run the code generation when ever you want if you do it right.

I did this when I wanted to use a single timer to do two different things based on a sequence of interrupt cascades.  CubeMX would set the timer up for me in the first mode, I then take over using the registers (and a few HAL functions and macros) to reconfigure and restart the timer in PWM DMA mode or basic counter delay timer.
"What could possibly go wrong?"
Current Open Projects:  STM32F411RE+ESP32+TFT for home IoT (NoT) projects.  Child's advent xmas countdown toy.  Digital audio routing board.
 

Offline timdf911Topic starter

  • Contributor
  • Posts: 23
  • Country: gb
Re: Help with STM32duino timers and frequency measurement
« Reply #4 on: December 01, 2022, 09:20:04 pm »
Thanks for the ideas -funnily enough the timers will need to be reconfigured depending on what's happening with the device.
However given that my code size is already 150kB for all the other stuff going on before I add this frequency measurement part and the other code which goes round it (stepper motor control) I suspect it might be easier to integrate the CubeMX code into my code base rather than the other way around.

I had tried with CubeMX to generate the timer code but came a bit unstuck with exactly how to interconnect the timers such that the gating timer could gate the signal into the main counter for counting and what modes thy needed to be in etc - if that makes sense.

Basically how to configure using a two timer approach to count the incoming cycles over a fixed period of time.

Tomorrows another day and I'll have another crack at CubeMX by first getting the gating timer going at 1mS and checking with a scope it's operating  as intended.

So much to learn and so few brain cells left :-)

Regards Tim
Tinkering for over 50 years and still learning  G4WIM KT6UK
 

Offline paulca

  • Super Contributor
  • ***
  • Posts: 4046
  • Country: gb
Re: Help with STM32duino timers and frequency measurement
« Reply #5 on: December 01, 2022, 10:02:31 pm »
I've not slaved timers before.  However I believe that is the area you want to be looking.  That or "Triggers".  One timer can be slaved to another.

Use CubeMX for what it's good for.  Rapid prototyping.  Try the timer idea out on it's own using Cube to get the bulk of the code written.  Then it will give you a base to work from and port back to your actual app.

On code size.  I need to look for a way to split the symbol file in CubeMX.  It seems those it makes the elf with debug symbols in it.  There should, hopefully be an option to save it externally and load it into the debugger, rather than flash the damn thing to the MCU flash memory!
"What could possibly go wrong?"
Current Open Projects:  STM32F411RE+ESP32+TFT for home IoT (NoT) projects.  Child's advent xmas countdown toy.  Digital audio routing board.
 

Offline Kleinstein

  • Super Contributor
  • ***
  • Posts: 14192
  • Country: de
Re: Help with STM32duino timers and frequency measurement
« Reply #6 on: December 01, 2022, 10:19:58 pm »
The ELF and similar output file is not directly giving the flash usage. The files tend to be a lot larger.

In the debug mode the compiler uses not optimization and this can make the code a lot longer. The prodution type make creates shorter code that is however harder to debug with the debugger. One can still use it for debugging: decalre the variables in question volatile, which restricts much of the optimizations where those variables are used.

The CubeMx code adds a bit to the code - to a large part for the initialization of the HW parts used. So when adding the actual frequency measurement this would not add that much code. It is more like some 16 kB to start with for the init part.
 

Offline langwadt

  • Super Contributor
  • ***
  • Posts: 4422
  • Country: dk
Re: Help with STM32duino timers and frequency measurement
« Reply #7 on: December 01, 2022, 10:20:13 pm »
I've not slaved timers before.  However I believe that is the area you want to be looking.  That or "Triggers".  One timer can be slaved to another.

Use CubeMX for what it's good for.  Rapid prototyping.  Try the timer idea out on it's own using Cube to get the bulk of the code written.  Then it will give you a base to work from and port back to your actual app.

On code size.  I need to look for a way to split the symbol file in CubeMX.  It seems those it makes the elf with debug symbols in it.  There should, hopefully be an option to save it externally and load it into the debugger, rather than flash the damn thing to the MCU flash memory!

surely the debugger only flashes the srec/hex/bin extracted from the elf   
 

Offline langwadt

  • Super Contributor
  • ***
  • Posts: 4422
  • Country: dk
Re: Help with STM32duino timers and frequency measurement
« Reply #8 on: December 01, 2022, 10:24:25 pm »
Thanks for those links, however during my extensive googling I had already come across them, but maybe I need to give them a second look / chance.

I was deterred from following them as some used CubeMX and / or  did not explicitly use the ETR input for maximum frequency operation.

Maybe I need to practice figuring out how to use CubeMX more efficiently and how to embed the code it generates into mine.

you might want to change the cube code generation to use the LL instead of HAL
 

Offline ozcar

  • Frequent Contributor
  • **
  • Posts: 322
  • Country: au
Re: Help with STM32duino timers and frequency measurement
« Reply #9 on: December 02, 2022, 06:22:45 am »
I had tried with CubeMX to generate the timer code but came a bit unstuck with exactly how to interconnect the timers such that the gating timer could gate the signal into the main counter for counting and what modes thy needed to be in etc - if that makes sense.

Basically how to configure using a two timer approach to count the incoming cycles over a fixed period of time.


I have mostly only used CubeMX to set up clock trees - it seems quite useful for that. Anyway, I tried to generate some code using the old version of CubeMX I have installed, and I sort-of got it to work. It was really just a matter of setting the more-or-less obvious things for the timers on the Pinout and Configuration tabs (myself, I don't quite follow the logic of what is under the one tab vs the other). I could not get it to enable the interrupt to grab the timer counter so in the end just gave up and set the required flag in the DIER register directly in the generated code.

I set it up using TIM3 (16 bit) to gate TIM2 (32 bit), with TIM2 counting the signal to measure. For 84MHz timer clock I set TIM3 prescaler to divide by 300, channel count of 28,000 and ARR = 28,280, for gate time of 100ms, repeated every 101ms, and it gives plausible results. I did not put any code in to display the result, I just ran it under the debugger to see what it got.

For what it is worth, this is the resulting main.c.  I enabled both the MCO outputs and also got it to blink the user LED on the Nucleo board in the interrupt routine as part of my sanity checking. Except for the few lines added to main.c, I inserted a call to the TIM3_IRQHandler_main() into the generated stm32f4xx_it.c.

Code: [Select]
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  ** This notice applies to any and all portions of this file
  * that are not between comment pairs USER CODE BEGIN and
  * USER CODE END. Other portions of this file, whether
  * inserted by the user or by software development tools
  * are owned by their respective copyright owners.
  *
  * COPYRIGHT(c) 2022 STMicroelectronics
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f4xx_hal.h"

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim3;

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

volatile uint32_t TimeCount=0;
uint32_t TimeCountm=0;


/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM2_Init(void);
static void MX_TIM3_Init(void);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */

void TIM3_IRQHandler_main(void)
{
   // at this time, TIM2 counter is stopped
  TimeCount = TIM2->CNT;
  TIM2->CNT = 0;  // reset
  HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);  // Nucleo LED
}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  *
  * @retval None
  */
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();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

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

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */

  TIM2->CNT = 0;
  TIM3->DIER |= TIM_DIER_CC1IE;                // enable interrupt for channel 1 compare
  HAL_TIM_Base_Start(&htim3);                  // turns on CEN in CR1
  HAL_TIM_Base_Start(&htim2);                  // turns on CEN in CR1

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
      TimeCountm = TimeCount;
      if ( TimeCountm )
HAL_Delay(1);

  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */

}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

    /**Configure the main internal regulator output voltage
    */
  __HAL_RCC_PWR_CLK_ENABLE();

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);

    /**Initializes the CPU, AHB and APB busses clocks
    */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**Initializes the CPU, AHB and APB busses clocks
    */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSE, RCC_MCODIV_1);

  HAL_RCC_MCOConfig(RCC_MCO2, RCC_MCO2SOURCE_SYSCLK, RCC_MCODIV_4);

    /**Configure the Systick interrupt time
    */
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

    /**Configure the Systick
    */
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

/* TIM2 init function */
static void MX_TIM2_Init(void)
{

  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_SlaveConfigTypeDef sSlaveConfig;
  TIM_MasterConfigTypeDef sMasterConfig;

  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 0;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 0xffffffff;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_ETRMODE2;
  sClockSourceConfig.ClockPolarity = TIM_CLOCKPOLARITY_NONINVERTED;
  sClockSourceConfig.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1;
  sClockSourceConfig.ClockFilter = 0;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sSlaveConfig.SlaveMode = TIM_SLAVEMODE_GATED;
  sSlaveConfig.InputTrigger = TIM_TS_ITR2;
  if (HAL_TIM_SlaveConfigSynchronization(&htim2, &sSlaveConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

}

/* TIM3 init function */
static void MX_TIM3_Init(void)
{

  TIM_ClockConfigTypeDef sClockSourceConfig;
  TIM_MasterConfigTypeDef sMasterConfig;
  TIM_OC_InitTypeDef sConfigOC;

  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 299;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 28280;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_OC1REF;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 28000;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

}

/** Configure pins as
        * Analog
        * Input
        * Output
        * EVENT_OUT
        * EXTI
     PC9   ------> RCC_MCO_2
     PA8   ------> RCC_MCO_1
*/
static void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct;

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);

  /*Configure GPIO pin : PA5 */
  GPIO_InitStruct.Pin = GPIO_PIN_5;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pin : PC9 */
  GPIO_InitStruct.Pin = GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF0_MCO;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pin : PA8 */
  GPIO_InitStruct.Pin = GPIO_PIN_8;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF0_MCO;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @param  file: The file name as string.
  * @param  line: The line in file as a number.
  * @retval None
  */
void _Error_Handler(char *file, int line)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  while(1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/


Edit:

This is from the CubeMX "report" showing the settings there:

Code: [Select]
PERIPHERALS MODES FUNCTIONS PINS
RCC Crystal/Ceramic Resonator RCC_OSC_IN PH0 - OSC_IN
RCC Crystal/Ceramic Resonator RCC_OSC_OUT PH1 - OSC_OUT
RCC Clock-out-1 RCC_MCO_1 PA8
RCC Clock-out-2 RCC_MCO_2 PC9
SYS SysTick SYS_VS_Systick VP_SYS_VS_Systick
TIM2 Gated Mode TIM2_VS_ControllerModeGated VP_TIM2_VS_ControllerModeGated
TIM2 ITR2 TIM2_VS_ClockSourceITR VP_TIM2_VS_ClockSourceITR
TIM2 ETR2 TIM2_ETR PA0-WKUP
TIM3 Internal Clock TIM3_VS_ClockSourceINT VP_TIM3_VS_ClockSourceINT
TIM3 PWM Generation No Output TIM3_VS_no_output1 VP_TIM3_VS_no_output1


« Last Edit: December 02, 2022, 06:32:56 am by ozcar »
 

Offline timdf911Topic starter

  • Contributor
  • Posts: 23
  • Country: gb
Re: Help with STM32duino timers and frequency measurement
« Reply #10 on: December 02, 2022, 09:10:42 am »
Hi guys,

many thanks for your useful tips - I didn't know that CubeMX could be configured to use LL rather than HAL - I'll give that a go.

Thanks ozcar for your code snippets and tips, I'll have a play around and experiment, hopefully learning a few things along the way as I customize it for my exact needs.  I seem to learn best by doing, testing and repeating until I get what I'm aiming for.


I wish I'd posted here last week rather going down rabbit holes and getting totally lost !  At least now I've got a starting point.

I'll keep you posted as to how it comes along and maybe a bit more info about the completed project.

Here's a summary.
The first part is in next months RadCom describing how it controls an antenna rotator.
The second part describes how it uses a Goertzel filter to facilitate doppler radio direction finding and the third and final part (where this timer issues comes in ) is to automatically tune a magnetic loop antenna.
System uses a 480x320 touch SPI LCD and parts 1 & 2 work really well.  Part 3 was going to be a port of my Teensy code, but is now looking for like a complete re-write.

Again many thanks to everyone.

Regards Tim
Tinkering for over 50 years and still learning  G4WIM KT6UK
 

Offline paulca

  • Super Contributor
  • ***
  • Posts: 4046
  • Country: gb
Re: Help with STM32duino timers and frequency measurement
« Reply #11 on: December 02, 2022, 10:07:53 am »
The ELF and similar output file is not directly giving the flash usage. The files tend to be a lot larger.

In the debug mode the compiler uses not optimization and this can make the code a lot longer. The prodution type make creates shorter code that is however harder to debug with the debugger. One can still use it for debugging: decalre the variables in question volatile, which restricts much of the optimizations where those variables are used.

Interesting.  I thought the elf had the symbols in it and it went onto the device.  I recall hitting 101% memory on an F030F4 and changing to Release mode dropped that to 40% or something.   I assumed it was symbols.  I write my code pretty verbosely.  Maybe, it's so verbose the compiler removes 50% of it during Release compile, but that sounds excessive!    Granted the total memory in that device was only 4K.

Then again, it does ask for the ELF file if you want to attach to a running MCU (which doesn't work by the way).  So maybe on flash it filters them out, or maybe it does a really, really poor job of filtering them out.
"What could possibly go wrong?"
Current Open Projects:  STM32F411RE+ESP32+TFT for home IoT (NoT) projects.  Child's advent xmas countdown toy.  Digital audio routing board.
 
The following users thanked this post: timdf911

Offline timdf911Topic starter

  • Contributor
  • Posts: 23
  • Country: gb
Re: Help with STM32duino timers and frequency measurement
« Reply #12 on: December 02, 2022, 07:50:41 pm »
Hi Guys,

making some good progress manipulating registers to control timers and irqs etc - but have run into another problem.  I'm using the Arduino environment which is C++ and previously I've attached an interupt by simply doing something like:

tim1Hz->attachInterrupt(Timer_ISR_1Hz)

now I'm using :

NVIC_EnableIRQ(TIM9_IRQn);

with matching irqhandler, it compiles ok  but the handler doesn't execute.

Preceding the isr with extern "C" doesn't fix it and the complier complains of multiple definitions so I'm wondering if there's anotherway to associated isr with a timer generated irq within the stm32arduino environment ?

Anyway having lots of fun exploring all the registers and things are making much more sense than a couple of days ago.

Regards Tim

Tinkering for over 50 years and still learning  G4WIM KT6UK
 

Offline ozcar

  • Frequent Contributor
  • **
  • Posts: 322
  • Country: au
Re: Help with STM32duino timers and frequency measurement
« Reply #13 on: December 02, 2022, 11:25:56 pm »
I'm wondering if there's anotherway to associated isr with a timer generated irq within the stm32arduino environment ?

Stm32duino does provide some timer support. It does not cover fangled things like slave mode or using DMA with a timer, but should be able to do what you are asking about now.

Have a look at this example:

https://github.com/stm32duino/STM32Examples/blob/main/examples/Peripherals/HardwareTimer/Timebase_callback/Timebase_callback.ino
 
The following users thanked this post: timdf911

Offline timdf911Topic starter

  • Contributor
  • Posts: 23
  • Country: gb
Re: Help with STM32duino timers and frequency measurement
« Reply #14 on: December 03, 2022, 08:21:00 am »
Hi ozcar,
yes that's the way I have been attaching interupts within Arduino, very easy to do but somewhat limited.
In my quest to learn and write better code I was hoping to avoid using attachinterupt and to achieve my goal by setting registers (which I largely understand now) and using nvic.  The latter seems to conflict with arduino environment, so in the short term I'll use registers to chain the timers together and attachinterupt to check the timings until I find a better way.

Thanks again for your support and guidance

Regards im

Tinkering for over 50 years and still learning  G4WIM KT6UK
 

Offline timdf911Topic starter

  • Contributor
  • Posts: 23
  • Country: gb
Re: Help with STM32duino timers and frequency measurement
« Reply #15 on: December 03, 2022, 11:58:33 am »
I've been making progress of sorts using TIM2 as a slave gated by TIM3 every 100mS

Here's my settings for TIM2 with what I think I'm doing

 TIM2->DIER |= TIM_DIER_CC3IE;   // enable capture compare irq for channel 3
 TIM2->ARR = 0xffffffff; // count to 2^32, then wraparound (approximately every 429 seconds)
 TIM2->SMCR |= TIM_SMCR_ECE;    // select external clock source mode 2 by writing ECE=1 in the TIM2_SMCR register
 TIM2->SMCR |= TIM_TS_ITR2 ;  // input trigger from timer 3
 TIM2->CR1 |= 0x01; //Enable counting

Here's my settings for TIM3 with what I think I'm doing

TIM3 -> PSC = 300;  // divides clock 84MHz to 280kHz
TIM3 -> ARR = 28280 ;  // generates a 100mS overflow
TIM3->DIER |= 0x01; //Enable interrupt
TIM3->SMCR |= TIM_TS_ITR2 ; // generate output trigger
TIM3->CR2 |= TIM_TRGO_OC1REF ; // Master mode selection generate TRGO for OC1REF to trigger capture compare on timer 2
TIM3->CR1 |= 0x01; //Enable counting

TIM3 -> CCMR2 |= TIM_CCMR2_OC3M ;  // output compare mode 3
TIM3 -> CCMR2 |= TIM_CCMR2_OC3PE ; // Output compare 3 preload enable
TIM3 -> CCER |= TIM_CCER_CC3P ; //Capture/Compare 3 output Polarity
TIM3 -> CCER |= TIM_CCER_CC3E ; //Capture/Compare 3 output enable

In the main loop I check this every second

Freq_Raw = TIM2->CCR3;

then serial print, but always shows 0.

I know my 100mS irq is running because I can see it if I attach an interupt to TIM3 and toggle a GPIO, so I suspect I have a disconnect / wrong settting between the two timers.

Any ideas ?

Regards Tim

« Last Edit: December 03, 2022, 12:56:29 pm by timdf911 »
Tinkering for over 50 years and still learning  G4WIM KT6UK
 

Offline ozcar

  • Frequent Contributor
  • **
  • Posts: 322
  • Country: au
Re: Help with STM32duino timers and frequency measurement
« Reply #16 on: December 04, 2022, 12:38:25 am »
Hi ozcar,
yes that's the way I have been attaching interupts within Arduino, very easy to do but somewhat limited.
In my quest to learn and write better code I was hoping to avoid using attachinterupt and to achieve my goal by setting registers (which I largely understand now) and using nvic.  The latter seems to conflict with arduino environment, so in the short term I'll use registers to chain the timers together and attachinterupt to check the timings until I find a better way.

Thanks again for your support and guidance

Regards im

I thought you were saying that something that worked with TeensyDuino (or whatever Arduino for Teensy is called - I'm not familiar with it at all), did not work for stm32duino.

If that works but is not good enough, I've seen some mention over on stm32duino.com about using a header file called hal_conf_extra.h to selectively disable parts of the core - eg here https://www.stm32duino.com/viewtopic.php?t=1072. However I have never had occasion to use that, so I'm not sure if that will help in any way. Best place to ask about that would be over there, where the guys who wrote the stm32duino code hang out. I see you have posted your original question there.
 
The following users thanked this post: timdf911

Offline ozcar

  • Frequent Contributor
  • **
  • Posts: 322
  • Country: au
Re: Help with STM32duino timers and frequency measurement
« Reply #17 on: December 04, 2022, 12:43:08 am »
I've been making progress of sorts using TIM2 as a slave gated by TIM3 every 100mS

Here's my settings for TIM2 with what I think I'm doing

 TIM2->DIER |= TIM_DIER_CC3IE;   // enable capture compare irq for channel 3
 TIM2->ARR = 0xffffffff; // count to 2^32, then wraparound (approximately every 429 seconds)
 TIM2->SMCR |= TIM_SMCR_ECE;    // select external clock source mode 2 by writing ECE=1 in the TIM2_SMCR register
 TIM2->SMCR |= TIM_TS_ITR2 ;  // input trigger from timer 3
 TIM2->CR1 |= 0x01; //Enable counting

Here's my settings for TIM3 with what I think I'm doing

TIM3 -> PSC = 300;  // divides clock 84MHz to 280kHz
TIM3 -> ARR = 28280 ;  // generates a 100mS overflow
TIM3->DIER |= 0x01; //Enable interrupt
TIM3->SMCR |= TIM_TS_ITR2 ; // generate output trigger
TIM3->CR2 |= TIM_TRGO_OC1REF ; // Master mode selection generate TRGO for OC1REF to trigger capture compare on timer 2
TIM3->CR1 |= 0x01; //Enable counting

TIM3 -> CCMR2 |= TIM_CCMR2_OC3M ;  // output compare mode 3
TIM3 -> CCMR2 |= TIM_CCMR2_OC3PE ; // Output compare 3 preload enable
TIM3 -> CCER |= TIM_CCER_CC3P ; //Capture/Compare 3 output Polarity
TIM3 -> CCER |= TIM_CCER_CC3E ; //Capture/Compare 3 output enable

In the main loop I check this every second

Freq_Raw = TIM2->CCR3;

then serial print, but always shows 0.

I know my 100mS irq is running because I can see it if I attach an interupt to TIM3 and toggle a GPIO, so I suspect I have a disconnect / wrong settting between the two timers.

Any ideas ?

Regards Tim

I've lost track of what you are doing in terms of generating code using CubeMX, or using stm32duino instead, or a bit of both, or maybe neither of those.

I also don't know if you are now just trying to duplicate what I posted before without using HAL, or if you have come up with a better way. I get the feeling you that you are maybe trying to use input capture somehow? Short of wiring the two timers together externally I don't know how you would do that, but then there are more ways in heaven and STM32 timers than in my philosophy.

The HAL code I posted before results in the timers ending up as shown below (just stopped at some random point).

Besides deciding what gate time would be best, with 84MHz timer clock, you'd have to set the external trigger prescaler to divide by 2 to reach 30MHz (ETPS = 01 in SMCR).



 

Offline ozcar

  • Frequent Contributor
  • **
  • Posts: 322
  • Country: au
Re: Help with STM32duino timers and frequency measurement
« Reply #18 on: December 04, 2022, 01:36:54 am »
I just noticed that you set TIM3 PSC to 300, saying that divides 84MHz down to 280KHz. Close, but not quite right. PSC=0 divides by 1, and PSC=299 divides by 300.

Also, it is the CCR1 value of 28,000 in my attempt that sets the gate time to 100ms. ARR=28,280 is a bit arbitrary, and serves only to give a little time for the ISR to grab the then frozen count.
 

Offline timdf911Topic starter

  • Contributor
  • Posts: 23
  • Country: gb
Re: Help with STM32duino timers and frequency measurement
« Reply #19 on: December 04, 2022, 09:43:26 pm »
Hi ozcar

thanks for taking the time to reply again - I've not had as much spare time today as I would have like but I've come to the conclusion that setting all the required registers manually is probably not the smartest thing to try, on the plus side I now have a much better understanding how the registers work and control the timers.  Surprising what you learn when you study the data sheets !

Anyway I'm going to use cubemx and cubeide to get something going using HAL then try the samething using LL before inserting the resulting code into the STM32duino environment where the rest of my code is developed.

OK on your comments about my register setting - at this point I'd be happy to get anything working

Regards Tim
Tinkering for over 50 years and still learning  G4WIM KT6UK
 

Offline paulca

  • Super Contributor
  • ***
  • Posts: 4046
  • Country: gb
Re: Help with STM32duino timers and frequency measurement
« Reply #20 on: December 05, 2022, 08:37:56 am »
Once they gave me a working IDE and a working (to professional level) debugger et. al.  Eclipse (aka CubeMXIDE) I couldn't go back to the "maker" IDEs.

As the previous screenshot highlights.  CubeMXIDe will allow you to not only breakpoint the core, but also view the live registers and .... even modify them as you please from the debugger.  You can even browse and modify memory while it's running.

It makes the Arduino IDE look like Notepad.
"What could possibly go wrong?"
Current Open Projects:  STM32F411RE+ESP32+TFT for home IoT (NoT) projects.  Child's advent xmas countdown toy.  Digital audio routing board.
 

Offline paulca

  • Super Contributor
  • ***
  • Posts: 4046
  • Country: gb
Re: Help with STM32duino timers and frequency measurement
« Reply #21 on: December 05, 2022, 08:41:44 am »
From my memory of baremetal programming the timers.  There is a gotcha.  The EGR register has an "update" bit.  It's like the "commit bit" on the timer registers.  It forces the timer to update based on it's registers.  If you don't set that bit the timer will carry on doing whatever it was doing until it hits an update event.  Setting the bit forces the timer to do that NOW.
"What could possibly go wrong?"
Current Open Projects:  STM32F411RE+ESP32+TFT for home IoT (NoT) projects.  Child's advent xmas countdown toy.  Digital audio routing board.
 
The following users thanked this post: timdf911

Offline ozcar

  • Frequent Contributor
  • **
  • Posts: 322
  • Country: au
Re: Help with STM32duino timers and frequency measurement
« Reply #22 on: December 05, 2022, 10:08:12 am »
From my memory of baremetal programming the timers.  There is a gotcha.  The EGR register has an "update" bit.  It's like the "commit bit" on the timer registers.  It forces the timer to update based on it's registers.  If you don't set that bit the timer will carry on doing whatever it was doing until it hits an update event.  Setting the bit forces the timer to do that NOW.

The deferred update, aka  "preload" applies to the ARR, CCRn and PSC registers, but for ARR and CCRn preload is optional, and is actually turned off out of reset (controlled by CR1/ARPE and CCMRn/OCnPE flags).
 

Offline timdf911Topic starter

  • Contributor
  • Posts: 23
  • Country: gb
Re: Help with STM32duino timers and frequency measurement
« Reply #23 on: December 05, 2022, 06:06:55 pm »
paulca

you've convinced me to invest more time learning how to drive cubemx / ide properly  - certainly stm32duino enables quick results but as I'm discovering it lacks the fine control I desire, hence my attempts at baremetal programming.

I think I'll go and find a simple project to strat with which wil enable me to explore the debug facilities that way I can hopefully answer my own questions with having to post here.

Regards Tim
Tinkering for over 50 years and still learning  G4WIM KT6UK
 

Online DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5902
  • Country: es
Re: Help with STM32duino timers and frequency measurement
« Reply #24 on: December 06, 2022, 03:04:24 am »
Seems like a job for DMA.

16bit TimerA:
- Pwm mode, one channel, no output.
- Timebase slightly larger than 100ms.
- Channel 1 would be "Frequency reading", adjust for 100ms.
   Enable capture ch1 DMA, peripheral to memory, both Word size, no increment, circular mode.
- Enable TRGO output, use update flag.

32bit TimerB:
- Setup external clock, prescaler(I think 30MHz is fine), etc...
- Slave in Reset Mode, configure ITR to take TRGO from Timer A

- Disable interrupts for all timers and their dmas.

Workflow:
Start TimerA Ch1 DMA: From TimerB->CNT to a 32-bit variable.

Start TimerA, start TimerB.

At 100ms, TimerA pwm will trigger a DMA request and transfer the counter value from TimerB into your variable.

Shortly after, TimerA will overflow and reset, the TRGO signal will also reset TimerB.

Now you can read your variable at any time to check the latest reading.
« Last Edit: December 06, 2022, 03:18:29 am by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf