2018-12-16 04:55 PM
Hello:
I am trying to come to an understanding using timer configurations with CubeMX/HAL. I hope someone can point me in the right direction. This is specifically for timer capture, but is probably applicable to PWM generation, and/or PWM capture too. This is using the Nucleo-L476RG demo board.
In general, I am spinning my wheels on the relationship of these things that all seemingly affect the frequency of an interrupt an capture. In the newest CubeMX, there is an example in: "STM32Cube_FW_L4_V1.13.0\Projects\NUCLEO-L476RG\Examples\TIM\TIM_PWMInput"
In the readme file, it states that:
The minimum frequency value to measure is (TIM3 counter clock / CCR MAX)
= (80 MHz)/ 65535
= 1120 Hz
That's great. So what is the right way to change the required variables to count a frequency of, let's say, 100Hz? If someone gives me a specific example, that's great too, but I still have not become self-educated. Without a core understanding of the relationship of the variables, I may get it to work this time, but what about next time?
One of the most pressing issues is that ST has provided these examples, without the ".ioc" files - the CubeMX files - so a person can open it up and understand with the configuration parameters just how this file was generated. Why are they not given with the examples?
I have been using the STM32F4, and never used CubeMX to code gen on that processor. Yet, I was able to do this fairly easily, getting perfect sub-hz resolution on frequency counts. I look at the code, see how it is done, but cannot replicate it with the STM32L4. So far, I have had nothing but frustration trying to set up CubeMX to do the same thing. None of the clock parameters I change in "SystemClock_Config" seem to get correct results, but lots of spasmodic numbers.
So...please, hopefully someone from ST can answer my question (more like a frustrated plea right now) and help me to fully understand this. Are there example/training videos? I have not found any. Just a lot of segmented training videos that don't really help put it together to figure this out.
Thank you...
Gary
2018-12-16 05:46 PM
The example sets the timer counter prescaler to zero, so the 80 MHz is fed unchanged into the counter. Set the prescaler and counter preset value to get the frequency you need.
Cheers, Hal
2018-12-17 09:04 AM
Thanks for the answer, but pretty much what I said. That's a specific answer, but I am looking for more, as above.
1- Why do the examples not come with the CubeMX generator files (.ioc) ? Without these, it is difficult to understand the concept and specifics of how the person designing the example used CubeMX to get the code. ST wants people to use CubeMX, then why not provide these....I see others have noted this too.
Regarding your answer, which of the below is to be changed to get the frequency range, and what is the general concept or formula to determine what it should be for a value or range:
void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
/* MSI is enabled after System reset, activate PLL with MSI as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
RCC_OscInitStruct.PLL.PLLM = 16;
RCC_OscInitStruct.PLL.PLLN = 10;
RCC_OscInitStruct.PLL.PLLR = 8;
RCC_OscInitStruct.PLL.PLLP = 7;
RCC_OscInitStruct.PLL.PLLQ = 8;
if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
/* Initialization Error */
while(1);
}
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
/* Initialization Error */
while(1);
}
}
Thanks,
Gary
2018-12-17 09:53 AM
I'm not a PWM expert, but from what I can see in the example, everything is in the main.c code. And, there is no need to change the system clock (which would affect everything) to get a lower frequency.
Take a look at the first figure in the General Timers section of the Reference Manual. It shows a timer counter prescalar register which can be used to generate lower frequency interrupts.
This is the code section in main.c that needs to be modified:
TimHandle.Init.Period = 0xFFFF;
TimHandle.Init.Prescaler = 0;
TimHandle.Init.ClockDivision = 0;
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
TimHandle.Init.RepetitionCounter = 0;
Check my math, but I believe the formula is:
Period * Prescalar = SysClock/Frequency
Usually the best solution is if Period and Prescaler are approximately equal, so 1000-1 and 800-1 should work well for 100 Hz.
Cheers, Hal
2018-12-17 11:43 AM
The examples aren't generated with CubeMX, they use the straight HAL, thus no .IOC
MSIRANGE_6 is 4 MHz
So 4 / 16 * 10 / 8, figure 312.5 KHz CPU Clock? Might want to printf() SystemCoreClock and confirm
If you have the APB clocking at 80 MHz, a Prescaler = 80-1 will clock the TIM at 1 MHz instead of 80 MHz. Prescaler is 16-bit wide and written in N-1 for, ie 0 for DIV1, 99 for DIV100
TIM2 should have a 32-bit Period, a Period of 65535 has 65536 cycles.
2018-12-17 07:57 PM
Ok, well thanks, but nothing is working. At this point - I cannot find any combination of period and prescalar that will find the input frequency of 100Hz. Must be more to it. The example, as is, works with the minimum input frequency of 1.4KHz and higher.
I would really like to have someone from ST step up and answer the question - how can we make a link between generated examples and CubeMX, when they don't give us the end to end examples? I am sure it would help solve a lot of these issues, at least for me..cause I don't get it. Maybe I need a few more runs at the brick wall, there's a spot or two on my skull that's not bleeding yet.
2018-12-17 08:26 PM
Some better results, but still trying to figure out what is going on. I want to capture a range from 10Hz all the way to around 500Hz. With period = 99999 and prescalar of 799, I am getting a result that is 800 times larger than the frequency. By dividing the result by 800, and casting to a float, it is producing the right value, with sub-hz resolution, which is the objective.
Can you explain why the prescalar and period cannot be set to do this without the division? Not so obvious...
2018-12-17 08:37 PM
>>I would really like to have someone from ST step up and answer the question
I've been here a decade, it's not going to happen. Got an FAE, bend his ear.
Low frequency capture, use TIM2, it's 32-bit wide, clocking at 80 MHz, you can measure intervals getting close to a minute. Prescaler = 0, Period = 0xFFFFFFFF
Pairs CH1 and CH2, and resets such that one captures total period, and the other the duty. Using one input pin, one gets selected in direct mode, the other in indirect.
The 16-bit ones don't have the span to provide good dynamic range.
2018-12-17 09:02 PM
Corporate ears bend when someone flashes $$$$$. Don't have those...cognac desires on a kool-aid and moonshine budget.
I'm now using my CubeMX generated example and it is working to sub-hz, providing I use period=99999, prescalar=799, and then:
uwFrequency = (2* HAL_RCC_GetPCLK1Freq()) / uwDiffCapture;
if(0 == ctr++%100) printf("frq = %.2f\n", (float)((uwFrequency)/799.0));
So that 100.70Hz in = 100.70Hz displayed
However, tried using period = 0xFFFFFFFF and 0, does not provide sub-hz. 100.7Hz in provides 100.00Hz
So....forgot to ask this: what's up with the divisor I am using that makes it work. How can I factor that into the period and/or prescalar instead of dividing down? Gave it much thought and tried some numbers...does not work.
Bizarre.
2018-12-21 05:07 PM
Hi,
Can anyone answer this question?
Why in the interrupt handler do I need to divide the return value by 799 to get the right frequency?
How can I accomplish this with modification of period and prescalar, if that is possible? Apparently it is supposed to be, but I cannot find values to accomplish this.
Gary