I’m trying to get an HR timer in freertos(STM32F344) to work and generate an update interrupt of 500 kHz. I’ve noticed that whenever I call HAL_HRTIM_SimpleBaseStart_IT(&hhrtim1,HRTIM_TIMERINDEX_MASTER) to launch the timer, the tasks don’t run at all but the ISR handle is called. When I coment out HAL_HRTIM_SimpleBaseStart_IT(&hhrtim1,HRTIM_TIMERINDEX_MASTER) or I lower down the timer to 100Hz the system works correctly. My tasks priorities are 24 and HR timer 5. The system frequency is 32MHz.
I tried to change the timer priority, to clear the IT update flags manually but with no success. Is timers and freertos a no go? I remember I had this issue before with a general purpose timer in another board and I had to significantly change my implementation. Any hint?
First thing I would recommend is abandon the ST HAL. It is poorly written, hard to read and very likely generates a good deal of runtime overhead. If timing and real time deadlines are a concern of yours, try to write your code as close to the hardware as possible without having to rely on 3rd party code.
Although M4 cores are a very popular target for FreeRTOS and many readers on this forum are thoroughly familiar with it, questions about using the HAL should are probably better placed in an ST forum.
concerning your question whether “timers and freertos is a nogo” - definitely not. When I worked with FreeRTOS on M4 cores, I used MCU timers in many contexts with no problems, but in particular with high frequency timers, you need to make sure that your timer isrs do not interfere with system operation. That concerns both the holy rules of interrupts under FreeRTOS (ie only call …FromISR variations of sytem calls and only if your isr runs below MAX_SYSCALL priority) and throughput - if your timers interrupts fire so fast that your timer and the systick timer eat up all of the CPU time, the rest of the system is starved. In such situations, you may need to very highly optimize your timers such that literally every unneccesary cpu cycle will go from the code.
Is that applied even if the system frequency is much higher than the timer frequency? In my case , the core runs at 32MHz and a 500KHz timer is just a tiny piece of that…
On the Cortex, optimization levels can make difference in code size that make you dizzy. Between time optimized and code optimized versions of the same source, there may be multitudes. And if a HAL decides to traverse 5 or 6 call levels before finally addressing the hardware, it adds up.
Another thing is that the ST HAL always grabs one free running timer simply for the management of HAL delays. That does normally not eat up too many cycles by itself but also adds up to the overall concurrency.
Your problem at hand may of course also be simply a bug in application code, but we would need to see the code to help you there - which would of course also require that someone with knowledge of the ST HAL looks at it (for which I do not qualify as I kicked the HAL a long time ago).
32 MHz is not “much higher” than 500 KHz, as that is only 64 CPU cycles per interrupt. Just getting into an ISR will use up a lot of that time because the M4 automatically pushes a number of register on the stack at ISR entry, costing typically 12 cycles to start the ISR (going up to 29 if it needs to save the FPU status) and another 10 to exit. This leaves VERY few cycles left for your program, and if it is written is C, it likely begins by pushing (and then popping at the end) a few more registers.
After some research I figure out where the problem was. I experimentally drooped down the NVIC priority for HRTIM on CubeMX, starting from 5. For a priority of 8 the tasks runned every once in a while. Then I dropped down to 10 and all the tasks are running full-time. So, the higher the hardware timer clock, the lowest the priority it should have in NVIC.
thanks for the update, but Richard’s remark still holds. Unless your 500kHZ timer is perfectly and highly optimized, it is expected to trash the CPU (probably even then).
Even at 64 MHz, the ISR will be using a large part of your time, and needs to be kept very short. If that is ok, you are fine, just beware of it. Note, the priority of the interrupt doesn’t affect this, but does influence which other ISRs it might block, which could be part of your problems.
The issue is that 500 kHz is very fast for an interrupt rate. Part of the design process is to evaluate your resource needs, which includes execution times, and make sure you have chosen proper hardware, and hopefully have included some slack to allow for future changes in requirements. Not knowing what you are doing in the 500 kHz ISR (and why), it is hard to tell if you have problems.
Note, the priority of the interrupt doesn’t affect this, but does influence which other ISRs it might block
FreeRTOS on ST boards usually relies on a general purpose timer as a time base.
Not knowing what you are doing in the 500 kHz ISR (and why), it is hard to tell if you have problems.
For the sake of best practices I usually keep my ISR as short as I can. In this project I’m just checking which adc is instanced and relaunching it. The purpose of doing so? Well just trying to follow the requirements of the project I’m involved into.
By “relaunching”, do you mean starting a conversion? If so, it would be better to use a timer that can just auto trigger the ADC. My guess is you likely have a lot of sampling jitter if you are really trying to sample at 500 kHz and are using processor kicking to start it.
The purpose is to actually trigger the ADC. I tried to adapt the example presented on the ST YouTube channel (the video has the title Hands-On with STM32 Timers: Trigger Periodic ADC Conversions) into DMA mode. Because they use interruption mode, they just fetch the ADC conversion on the ISR. Because I’m using DMA in normal mode, it was stopping after the first conversion. So I decided to relaunch it.
My guess is you likely have a lot of sampling jitter if you are really trying to sample at 500 kHz and are using processor kicking to start it.
You guessed right! But even triggering at a 200Hz rate I get the jitters. I’m trying to solve this now. I may need to play a bit with the ADC and DMA configurations. I noticed for instance that using ADC in continuous mode was causing the ADC error handler to get called. When I check the error code, it points to “internal error”.
Lower speed can’t remove the jitter, it can just lower what percentage of the sampling time it will be, which can help. My point was more that at that sample rate, putting the processor in the loop tends to be asking for problems.
My second comment, which you are probably not going to like, is to guess you are using the ST provided HAL library, and having issues with it, which in my experience is almost a necessary consequence of using the ST Hal library. The library design staff made some very strange design decisions, and I find for many things their HAL library just not that helpful.
I will admit that I haven’t used the STM32F series of parts, but have used other parts in related series, and I found triggering the ADC with a timer not a problem. If you are going to need an ISR anyway to do something, letting the timer trigger the conversion, and saving the results in the ISR would be more accurate, and my guess is that you should be able to get the DMA programmed to automatically save the results and give you an interrupt when the buffer was full. You just might not be able to do that with the HAL.
Thank you for sharing this @richard-damon . Well I probably will not be able to give up from HAL right now, but I’ll explore more the bare metal-approach on my next projects. As an option I can for now rewrite only the ADC driver on bare metal if HAL doesn’t do the job.
Yes, if you have been tied to the HAL, going “cold turkey” can be hard. Changing the part where the problem occurs is often a viable approach. Don’t be afraid to change the structure of the API, as that is often where the biggest issues are.