Delaying tasks for short times

Hey folks, I’m the developper of a so-called brushless gimbal controller (STorM32: http://www.rcgroups.com/forums/showthread.php?t=2055844) and the code has become quite complex, so I want to use a RTOS. I think I’m OK at coding, but have not yet any experience with a RTOS. I’ve digested all the docu on the FreeRTOS web site, and also peeked a bit into the code, but some – probably very basic – questions remained, which I’d like to ask. Some prelim info: I’m using a STM32F103 @ 72MHz, arm-gcc, and CMSIS, I’m not using Cube. The code can be regarded as to consist of two “tasks”, one is a control loop executed every 1500 us triggered by the SysTick timer interrupt, and the second is everything else and not time critical. And that’s exactly how I’d like to do it, to start two tasks with high and low priorities. The control loop consumes about 700-1100 us. My problem, the control loop has some “time gaps”. For instance, it starts with triggering some sensors and doing a bit of stuff, but then there is a time gap of about 100 us where it’s just waiting for data to arrive. My question(s) will be about how to deal with that using FreeRTOS. I think the obvious answer of you will be that one just needs to suspend/block the control task and should modify the sensor reading routines such that the control task is resumed. However, for reasons which I feel would require too much space to explain and which I’d like to ask you to just accept, that’s not easily possible and I’m looking for alternatives. My first thought was to simply use the preemptive scheduler, give the control task a high priority, set the scheduling at 1500 us, and use e.g. vTaskDelay() to switch to the low-priority task while in a time gap. Question: Did I got that correct that one can delay a task only in multiples of the SysTick timer period, and that this approach would thus not help me? Question: Setting the scheduling time to e.g. 100 us or 50 us would however do what I want, right? Question: But that would not make much sense in terms of performance, or wouldn’t you be worried much about the overhead due to the frequent task switching? (I’ve read somewhere that it takes about 1 us, so that at 100 us it would be just 1%, not sure if that’s correct though) If that approach isn’t recommended, I obvioulsy would need a delay routine which allows me to delay for sub-scheduler times. E.g. one could set a timer, suspend, and make the timer interrupt to resume the task. Question: Is there anything like that already supported in FreeRTOS, e.g. by some sort of macros, templates or demos, which I just have missed to find? With such a delay routine, one also could consider, I think, to not use the premptive but the cooperative scheduler, which would also frees the SysTick handler from the scheduling. I’m somewhat confused about how the Systick timer is used with the cooperative scheduler. Question: Could I make FreeRTOS to not grab the SysTick interrupt and attach it’s own handler, so that I would be able to use my old SysTick handler without change, or do I still have to link my handler routine into FreeRTOS’? Sorry for the long post. And many thanks for FreeRTOS! Cheers, Olli

Delaying tasks for short times

First note – if you set the tick frequency above 1KHz then the pdMSTOTICKS() (or the older portTICKRATEMS macro) cannot be used. The macros are not used anywhere in the FreeRTOS code, but are used in a lot of the demos. Is the timing of the control loop critical? By that I mean, would any jitter in its timing be detremental to your motor control? If so I would consider triggering the interrupt of a separate interrupt (not the SysTick), and setting the priority of the interrupt above configMAXSYSCALLINTERRUPT_PRIORITY (which on an STM32 means a lower priority number to get a logically higher priority). An STM32 peripheral timer can be used for this purpose. Doing it that way will mean you can get extremely accurate timing, and that the interrupt will never get masked by FreeRTOS. However, it would mean you could not use any FreeRTOS API calls in the interrupt handler, and it might be that you need to do the control algorithm within the interrupt handler itself. An alternative would be to have the STM32 peripheral timer generate an interrupt at the frequency you need, then use a call to vTaskNotifyGiveFromISR() to unblock a high priority task from the interrupt. That way your interrupt handler can exit very quickly, and return directly to the task that then performs the control algorithm. Doing it that way means the processing is done in a task, rather than an interrupt, which might be better. As you were using the FreeRTOS API you would have to set the interrupt’s priority to configMAXSYSCALLINTERRUPT_PRIORITY, so the time at which the interrupt was entered would jitter a bit, but not much. In both cases, you would then be free to set FreeRTOS tick frequency to anything you like as the motor control would be triggered off a separate timer – probably quite a low frequency would be best for the tick as you want to spend a lot of time performing your motor control. Does that help? If not, or if I have confused by, reply back. Regards.

Delaying tasks for short times

wau, this was fast … many thx for these many good suggestions I need however a bit of time to properly comprehend them, I’ll certainly come back then thx a lot so far Olli

Delaying tasks for short times

You say: “My problem, the control loop has some “time gaps”. For instance, it starts with triggering some sensors and doing a bit of stuff, but then there is a time gap of about 100 us where it’s just waiting for data to arrive. My question(s) will be about how to deal with that using FreeRTOS.” When the data arrives, can you get an interrupt? If so, you can block for an event and let the interrupt signal that event.

Delaying tasks for short times

Thx again for the answers, MUCH appreciated 🙂 @Richard Damon: yes, the data reception is interrupt driven, and doing as you suggest is probably the proper “RTOS-ish” way … but as I tried to indicate this is not easily possible, for various reasons @RTE ltd: (:)) I’m not sure that the procedures you suggested directly target my “problem”. Both seem to target the issue of how to start the control task in regular intervals, while I was more concerned of how to switch tasks for the “time gaps”. They made me however realize that I haven’t understood the scheduling properly, so very useful, thx. It also makes me think that while my goal seems straightforward it may not be most simple. Maybe I should add some more details, which I probably should have done right away. My SysTick interrupt is set to the highest priority (0). This is mandatory and required for the I2C buses to work properly, which btw are also set to highest priority. In addition I have plenty of other interrupts, usb, 4x serial, 9xTimer, adc, and balancing their priorities was a bit of a pain. I also paid much attention to have the isr handlers as short as possible. The bottom line: Executing the control code, which is quite lengthy, in a high-priority isr wouldn’t be possible. 2nd bottom line: I do not have any timer available anymore of which I could set the period (I have a free running timer, so one may go via compare matches). The timing is done quite straight-forwardly, namely the SysTick sets a flag, and main() is essentially while(){ if( flag ){ //this is set to true every 1500 us by the sysTick flag = 0; trigger sensors; //this takes ca 50 us do some uncritical stuff I; //here we have time for about 100-150 us , this is the time gap I mentioned (one of them) do the control stuff; //this takes ca 500-1000 us do some uncritical stuff II; //do as much as you can, but avoid exceeding 1500 us } } Since the isrs are short and SysTick of high priority the jitter is quite low, something like 1-2 us. I do not think the jitter needs to be that small, but it should not be larger than few 10 us (to answer that). It is most important though that the code is repeated every 1500 us, i.e. no tick should be missed, so that the last part “do some uncritical stuff II” should never ever exceed beyond 1500 us. As regards starting the control loop, I think my earlier “idea” to use the preemptive scheduler was maybe incorrect, as this, as I think to understand now, wouldn’t automatically resume the high priority task. However, I think that somehow it should be possible to get the SysTick handler to resume the high priority task (not sure how, maybe by a vTaskNotifyGiveFromISR(), as you suggested, but placed early within the SysTick handler, or any other smarter method offered by FreeRTOS). From your response it seems to me that I actually would be best off if one could just avoid having a FreeRTOS tick. My original questions were concerned with how to get a task switch for e.g. 100 us in between the “trigger sensors” and “do the control stuff” sections, so that ALL the uncritical stuff could be placed within one low-priority task. The only idea which came to my mind is to use the free runing timer, i.e. to set a compare match to occur in 100 us, switch to the low priority task, and have the compare match isr to resume the control task. Hope that clarified things a bit, and thx in advance, Olli

Delaying tasks for short times

A couple of apparent misconceptions in your statements. First, making SysTic the highest priority is NOT going to help your interupt jitter to your tasks. No matter what the priority of the SysTic, all interrupts will need to be processed before main will resume and do its thing, so processing SysTic first isn’t going to help. Also I haven’t seen an I2C device that needs to be highest priority either to work. What I would do with this is have at least 2 seperate tasks. One the control loop which is a higher priority task that is something like void controltask(void* parm) { while (1) { Block waiting for event from 1500us timer Trigger Sensors. Block waiting for data from sensors Do control Stuff } } /* As many as needed / void backgroundtask(void parm) { while(1) { Do background task. } } If any of the background operations are to be done based on the control loop running, then the control task can set a semaphore at its end and the appropriate background task can wait for that semaphore. Note, that the 1500us timer does NOT need to be SysTic (and if fact might be better to not be) as extra work is done in the SysTic to count down expiring timeouts). We thus also have ISRs for the 1500us timer which send the event to controltask, and for the data available. Note, you will need to enable pre-emtion to get the response times you want (which is in my mind the normal state for a RTOS), and then the control task will start automatically when the data ready event is triggered. If the 100-150us delay is an I2C read cycle, then the the typical I2C driver blocking for the cycle complete interrupt is the interrupt you are working on.

Delaying tasks for short times

THX a lot for the suggestions, but they’re not really helpfull. The approach you outlined is the obvious, which I’ve ruled out twice in the above, including using a sensor isr to resume. As regards the SysTick and I2C isr priorities I’ve not said it’s a requirement by the I2C devices, it’s thouh required by the drivers, and practice has confirmed that (it’s a STM32F103). I’ve no doubt that my understanding is still full of missconceptions, but if this approach is the only possible with FreeRTOS it unfortunately wouldn’t be a solution for me. I was wondering to use e.g. a timer (specifically the free runing timer with compare matches) to temporarily switch to the background task for a predetermined time to fill up the time gap(s). And I was wondering if FreeRTOS wouldn’t already support something like that in some way (i.e. something like vTaskDelay() where only the time could be smaller than the ticks), since I would have thought that this could be a quite common thing. If not, going down the timer+compare path currently seems to be the best option. Your text suggests that it indeed should be possible to use SysTick to resume the control task every 1500 us, which would be just perfect. I’m not sure how that would actually be done (best) in code, it seems to me it’s not done by FreeRTOS by itself (or is it possible to block/wait for the next tick?). As much as I see one would have to e.g. insert a vTaskNotifyGiveFromISR() or a xTaskResumeFromISR() in the SysTick handler. Maybe one can hook that into the FreeRTOS handler. Alternatively, which I currently like better, one could abandon using FreeRTOS’s SysTick handler at all, but I would use mine and add the vTaskNotifyGiveFromISR() or xTaskResumeFromISR() in there. I don’t see I need what’s done in the FreeRTOS handler otherwise (seems to be just this xTaskIncrementTick() thing). In any case I would have to modify xPortStartScheduler() such as to not affect the SysTick priority. I’m not sure on these parts though, any suggestions are highly welcome. Thx again, Olli

Delaying tasks for short times

I am not familiar with the STM32F103, but it seems strange to have drivers that require these to be highest priority, as these sort of devices don’t normally need this sort of treatment, and forcing them to be highest priority would interfear with the devices that DO need this sort of treatment. I think that FreeRTOS doesn’t support a built in sub-tick delay becuase implementing it is very system specific (and not all processors/systems will have the needed spare timer). It isn’t that hard to implement an application specific version for your own use. If your SysTic is running at 1500us period, then it is very simple to get your task to startup on the SysTic, just call vTaskDelay(1), which will resume you on the next (1) SysTic.

Delaying tasks for short times

For whatever it is worth for other readers, and a bit on the side of main topic: The STM32F103 has quite a few erratas related to I2C module. One of them is that it may require the IRQ to have the highest pri (see device errata “Some software events must be managed before the current byte is being transferred, workaround method 2”). This goes for several other STM32 devices using the same STM I2C IP. Actually, making a good I2C driver for some STM32 devices is suprisingly difficult due to the errata (and design+documentation one might add).

Delaying tasks for short times

Kristian, Wow – I can say I have witnessed something like this really being a problem – I would suggest changing processors and/or getting an external controller with an I/F path that has no errata or errata at least that doesn’t affect mission critical requirements. Or move to SPI. SPI seems to be generally easier to work with and is more flexible IMHO. Regards, John W.