Because the SysTick ISR have been assigned to the FreeRTOS Xportsystickhandler () function without regard to HAL operations.
I think this can is corrected by calling Hal_inctick () before calling Xportsystickhandler () in Systick_handler () similar T o as follows:
void Systick_handler (void) { // for internal HAL function Hal_gettick () use Hal_inctick (); //*must* is called last or a hard Fault 'll be generated Xportsystickhandler ();}
Note:for some reason, if the Xportsystickhandler () function is isn't called last in Systick_handler (), a hard Fault exception'll occur!
Also note, it is quite confusing to see multiple instances of SysTick being initialized in these examples:
- In Hal_init ()
- In Systemclock_config ()
- In Vtaskstartscheduler ()
Also, HAL code initializes and expects the systicks generated to be 1 MS ticks,
But the FreeRTOS can easily is configured (via FreeRTOSConfig.hconfigtick_rate_hz)
To is another value, which would cause the hal-related timeouts to be incorrect.
A Hard fault occurs because we execute the Xportsystickhandler () and the scheduler are not yet started,
To avoid it can add the following code into the Systick interrupt:
void Systick_handler (void) { if (xtaskgetschedulerstate ()! = Taskscheduler_not_ STARTED) { xportsystickhandler (); } Hal_inctick ();}
Actually in this stm32cube version we had to configure both HAL and FreeRTOS ticks with Systick interrupt
And with the same frequency (every 1 ms), an update would be do on next releases
The Hal_delay function is implemented as "weak",
So what I had done was to re-map it to the FreeRTOS task-aware Vtaskdelay () function:
void Hal_delay (volatile uint32_t millis) { /* replace HAL library blocking Delay function */ Vtaskdelay (Millis);}
In addition, I-Call the Hal_inctick () function from the FreeRTOS Tickhook:
void Vapplicationtickhook (void) { hal_inctick ();}
Hello Lix and all
Thank-The Hunts, but I-think I need to is more specific in my problem description.
I am using DMA in order to perform i²c reads/writes using functionnality from STM32F4XX_HAL_I2C.C and STM32F4XX_HAL_DMA.C.
When the DMA transfer completes, it calls "I2C_DMAMASTERTRANSMITCPLT"
Which itself call "if (I2c_waitonflaguntiltimeout (HI2C, I2C_FLAG_BTF, RESET, i2c_timeout_flag)! = HAL_OK)"
(In fact multiple calls to the same function for different flags).
The "I2c_waitonflaguntiltimeout" relies on the Hal_gettick.
The problem:
-In the "Free RTOs" port, the Systick priority was set to lowest priority
-Since my code is currently executing the DMA driver code, the Systick cannot execute,
The i2c_waitonflaguntiltimeout hangs in permanent loop if the flag does not reach the expected state.
(Please note this STM32CUBEMX set the Systick priority to the highest priority so the "does not" show up in non RTOS AP plication).
Since Hal_gettick is declared weak (thanks Lix for mentionning it), I-Override it with:
uint32_t Hal_gettick (void) { /// GY bug with timeout function // if0x0f000ul) { SCB->icsr |= scb_icsr_pendstclr_ Msk; Uwtick+ +; } // GY end bug with timeout function return Uwtick;}
The timeout is now "kind of" working.
(It would fail if I get event that would has higher priority than Systick).
In my opinion, this "solution" was a kludge on top of a combination of design flaws.
In the first place, and in the fact the route cause of the problem, a driver are supposed to being short lived.
The driver should never poll waiting on an event.
Instead of polling it should just exit and let an I²C driver wait for the relevant interrupt.
(Eventually, driver could "test the water" and do the job if the flag was in the expected state
In order to avoid extra interrupt, it is need to being carefully thought not to fall into time race condition).
Doing so would return the processing to user level code allowing low priority drivers to execute and likely letting RTOS D o its job.
Then the FreeRTOS port should don't move the systick priority as long as the base stm32f HAL drivers expect it to be the HIG Hest priority.
Even if switching Systick prirority to highest would solve the "Driver timeout isssue",
It could workaround since being stuck in a driver for tens of milliseconds was bad
In the environment and unacceptable in RTOS environment.
You should note several things:
First and foremost, FreeRTOS sets the SysTick by itself, and if you try to override it's a bad idea (as the ST HAL Librar IES sometime do).
Normally, the SysTick is set to Prio 5 (check the FreeRTOSConfig.h file, the Configlibrary_max_syscall_interrupt_prior ity define).
That means this all interrupt handlers the use FreeRTOS APIs (semaphores, mutexes, queues, etc) must has a lower priorit Y than the FreeRTOS scheduler.
Only interrupt handlers that don ' t use FreeRTOS APIs can have higher priorities than configlibrary_max_syscall_interru Pt_priority.
Therefore keeping the ST original SysTick priority was not a option, on the contrary,
All initialisations of SysTick off of FreeRTOS should be eliminated
(I found one in the USB Device Library, but maybe there is others too, didn ' t search for all).
Now to my solutions:
For one, re-mapping hal_delay () to Vtaskdelay () solves the problem of blocking a function in a timeout.
The FreeRTOS delay doesn ' t hold the whole processor and only the task that calls it.
On another hand, by letting the FreeRTOS Tickhook to increment HALs millisecond variable
You still assure compatibility to possible functions the would directly use Hal_gettick () function
(as "i2c_waitonflaguntiltimeout" does) but with the mention, which is the task aware,
As it is called from inside FreeRTOS.
Moreover, there is no more priority issues, as long as the rule regarding calls from interrupts
To the FreeRTOS APIs are observed (see also the FreeRTOS documentation).
By the the-the-solution proposed by me?
I See no reason that it doesn ' t solve your problem.
You are only having the to-take care not-use this delay in interrupt handlers. But who would inserts delays in an interrupt handler anyway?
And yes, you is right, the most ST HAL drivers is not (yet) thread aware
(In fact, there was a mention of this in the file stm32f4xx_hal_def.h, check the Use_rtos define).
So if you really want to does it properly, then you have to modify the drivers using FreeRTOS semaphores and queues
Between interrupt handlers and background driver functions.
It ' s what I do e.g. for the USB CDC Device implementation as well as for UARTs.
The fact that the use_rtos is defined at all, could give us a slight hope that ST'll sometimes later issue also HAL Drive RS that is RTOS aware.
Only time would tell ...
Hi Lix,
Thanks again for those explanations.
Yes, I did try to your solution but it does not work for me.
You mention "Normally, the Systick was set to Prio 5" but I noticed it was set to 15
(both reading scb->shp from debugger and checking source code as described below).
Did you initialize it by yourself to the value, and in the case how is you sure there is no side effect?
I concur with yourself it "all initializations of SysTick out of FreeRTOS should be eliminated" which are why I am reluct Ant to modify it.
Explanantion of Systick Prio set to 15 * * * * *
This is based on free RTOs port from ST
From port.c around line 336 in Xportstartscheduler (void)
/* Make PENDSV and SysTick the lowest priority interrupts. */
Portnvic_syspri2_reg |= Portnvic_pendsv_pri;
Portnvic_syspri2_reg |= Portnvic_systick_pri;
Going through the various defines, we can find that both portnvic_pendsv_pri and portnvic_systick_pri
is based upon Configkernel_interrupt_priority, itself based on configlibrary_lowest_interrupt_priority
Which is set to (effectively the lowest priority/highest priority number)
They is not based on configlibrary_max_syscall_interrupt_priority (value of 5)
End explanantion of Systick Prio set to 15 * * * * *
If Systick Prio is set to 5 and my driver interrupt set to higher value than 5 (lower Prio)
Then I think this both your proposed solution and the ST provided HAL driver timeout would work.
Regarding another possibility I did already protect the I²c driver with semaphores and queues to make them RTOS safe for M Y application.
As you mentionned I also hope we'll get RTOS aware HAL drivers
And to your question "but who would inserts delays in an interrupt handler anyway?",
One answer is (and may be, the only one), the STM32F4XX_I2C_HAL.C handlers provided by ST.
SysTick is set to Prio, and this is true also for the stock FreeRTOS distribution for ARM.
I was confused by the configlibrary_max_syscall_interrupt_priority define which are indeed set to 5. It's another story.
That being said, the truth was that there was many interrupt handlers in the HAL library that's not RTOS compliant,
And unfortunately for this cases there are no other alternative than to write your our own driver.
I jumped on the HAL quite recently (about one month ago) and I am still discovering its shortcomings.
I am amazed at how many interrupt handlers does delays in interrupt!
As an example, I wrote my own UART interrupt handler (still based on HAL)
Using queues for transmit and receive to communicate between interrupt and background code.
So I would does the same for i²c, as there is indeed calls to Hal_delay () in the I²c interrupt handler.
Just use a semaphore and transfer most of the processing out of the interrupt handler
(i.e deferred interrupt handling, see the FreeRTOS User Guide).
Thanks for your comments.
I concur with your about the shortcomings of the HAL drivers and the need to rewrite them to being user friendly in general
(No wait for event loops or call to delay, no un-needed interrupt-or rather user configurable based on handle content-
Like the half transfer one in DMA) and FreeRTOS aware.
Overall The HAL driver concept is great and the implementation requires significant improvements to make it effective.
I would appreciate if someone from ST would comment on the timefrane for improving the HAL drivers
(i.e., making them RTOS aware) and for the FreeRTOS port to take advantage of them.
STM32CUBEF4 FreeRTOS Examples don ' t work correctly with Hal_gettick