Toggling pins with vTaskDelay in RTOS - delay
I'm using a RTOS distribution on an ARM embedded device.
Currently i'm in need of toggling a signal like this
GPIO_Write(PIN_1, LOW);
vTaskDelay(msec_to_ticks(1));
GPIO_Write(PIN_1, HIGH);
vTaskDelay(msec_to_ticks(1));
GPIO_Write(PIN_1, LOW);
vTaskDelay(msec_to_ticks(3));
GPIO_Write(PIN_1, HIGH);
if (option1){
vTaskDelay(msec_to_ticks(3));
GPIO_Write(PIN_1, LOW);
vTaskDelay(msec_to_ticks(1));
} else {
vTaskDelay(msec_to_ticks(1));
GPIO_Write(PIN_1, LOW);
vTaskDelay(msec_to_ticks(3));
}
GPIO_Write(PIN_1, HIGH);
if (option2){
vTaskDelay(msec_to_ticks(3));
GPIO_Write(PIN_1, LOW);
vTaskDelay(msec_to_ticks(1));
} else {
vTaskDelay(msec_to_ticks(1));
GPIO_Write(PIN_1, LOW);
vTaskDelay(msec_to_ticks(3));
}
GPIO_Write(PIN_1, HIGH);
vTaskDelay(msec_to_ticks(3));
GPIO_Write(PIN_1, LOW);
What i noticed is that based on where and when i call this function (separate thread/task) the signal can be completely wrong (1-2ms off sometimes).
I'm wondering if using taskENTER_CRITICAL() and taskEXIT_CRITICAL can help me to ensure a somewhat accurate signal.
One idea i have is that interrupts with higher priority may kick in and delay the code somewhere (although i've set max priority on the task).
The other one is that the timings are correct but GPIO_Write is not taking place immediately.
Any other idea on how can i ensure the code is not interrupted?
Regards,
Here are a few things to think about.
1) What is the period of the timer used by vTaskDelay()? The amount of error in the delay period could be up to one tick. For example if you start the delay just prior to when the next tick is about to occur then the delay could be up to one tick too short.
If the tick period is 1 millisecond then you cannot accurately measure 1 millisecond delays because the relatively low resolution of the timer means those delays could be up to one millisecond or 100% too short. Hopefully the tick period is 0.01 milliseconds or less because that would allow it to measure a 1 millisecond with 1% error or less.
2) The FreeRTOS documentation explains why vTaskDelay() is not a good method of controlling the frequency of periodic tasks.
vTaskDelay() specifies a time at which the task wishes to unblock
relative to the time at which vTaskDelay() is called. For example,
specifying a block period of 100 ticks will cause the task to unblock
100 ticks after vTaskDelay() is called. vTaskDelay() does not
therefore provide a good method of controlling the frequency of a
periodic task as the path taken through the code, as well as other
task and interrupt activity, will effect the frequency at which
vTaskDelay() gets called and therefore the time at which the task next
executes. See vTaskDelayUntil() for an alternative API function
designed to facilitate fixed frequency execution. It does this by
specifying an absolute time (rather than a relative time) at which the
calling task should unblock.
3) Using taskENTER_CRITICAL and taskEXIT_CRITICAL around calls to vTaskDelay() seems like a bad idea to me. The reason for calling vTaskDelay() is to give other tasks a chance to run while this task is delaying. So it seems counterproductive to disable interrupts with taskENTER_CRITICAL. If you don't want other tasks to run during the delays then call a non-blocking delay function rather than vTaskDelay(). Then if the timing of your non-blocking function is still being affected by interrupts then maybe you could consider putting it into a critical section.
One problem is that the first pin set occurs asynchronously to the RTOS clock, so may occur anywhere in the clock period:
Tick: | | | |
________ __________
Signal: |____| |__________________
<--------->
First transition
may occur anywhere here.
This can be resolved by inserting a single tick delay before the first transition.
Tick: | | | |
__ __________
Signal: |__________| |__________________
Delay(1)-^
Transition occurs on the tick boundary
Higher priority tasks and interrupts may delay transitions and cause jitter, but if you lock the scheduler or disable interrupts, then those tasks will not run, and if your application can take that then those tasks are have been assigned inappropriate priority. Equally is the jitter is significant, then again you have tasks with inappropriately high priority or conversely inappropriate behaviour and schedulability for a high priority task.
Task priority is not about "importance" it is about schedulability and deadlines. As a guide, tasks that have hard-real-time deadlines and run for short deterministic periods should have high priority. In this case the task spends most of its time in delay - the GPIO switches will take very few clock cycles, so this task can probably safely be assigned a high priority.
Tasks that do not behave deterministically should have a low priority in order not to affect time-critical tasks. If this fragment is part of some task that does other perhaps non-deterministic things, then your task partitioning may need re-thinking. Task partitioning is not always about the "job", again it is about schedulability and an intuitively single feature or behaviour may need to be split amongst more that one task. For example this signal might be generated by a high-priority task waiting on an event triggered by some lower priority task rather then implemented directly in the low priority task.
Related
Measuring Semaphore wait times with Micrometer
We have a throttling implementation that essentially boils down to: Semaphore s = new Semaphore(1); ... void callMethod() { s.acquire(); timer.recordCallable(() -> // call expensive method); s.release(); } I would like to gather metrics about the impact semaphore has on the overall response time of the method. For example, I would like to know the number of threads that were waiting for acquire, the time spend waiting etc., What, I guess, I am looking for is guage that also captures timing information? How do I measure the Semphore stats?
There are multiple things you can do depending on your needs and situation. LongTaskTimer is a timer that measures tasks that are currently in-progress. The in-progress part is key here, since after the task has finished, you will not see its effect on the timer. That's why it is for long running tasks, I'm not sure if it fits your use case. The other thing that you can do is having a Timer and a Gauge where the timer measures the time it took to acquire the Semaphore while with the gauge, you can increment/decrement the number of threads that are currently waiting on it.
difference between update_rq_clock and update_rq_clock_task
I understand the notion of update_rq_clock as it updates the run queue clock on system tick periodically. But this function calls update_rq_clock_task(). What is the purpose behind this function?
Within update_rq_clock the difference between the CPU timestamp and the run queue clock is calculated (The rq->clock variable represents the last clock read from the CPU). That difference is added to the rq->clock and to the rq->clock_task (Which is the same as rq->clock - time for interrupts and stolen time) through update_rq_clock_task. There are a couple of options within the function, which you can activate with kernel build options. But basically it breaks down to: ... rq->clock_task += delta; ... update_rq_clock_pelt(rq, delta); ... So, both functions together update the clock of the run queue and the clock of the run queue without accounting for interrupts and stolen time (unless you activated that accounting through the kernel options), so the actual time that the tasks used.
Maximum number of tasks supported in AUTOSAR
What is the maximum number of tasks supported in AUTOSAR compliant systems? In Linux, I can check the maximum process IDs supported to get the maximum number of tasks supported. However, I couldn't find any source that states the maximum number of tasks supported by AUTOSAR. Thank you very much for your help!
Well, we are still in an embedded automotive world and not on a PC. There is usually a tradeoff between the number of tasks you have and what it takes to schedule them and what RAM/ROM and runtime resources your configuration uses. As already said, if you just need a simple timed loop with some interrupts in between, one task may be ok. It might be also enough, to have e.g. 3 tasks running at 5ms, 10ms and 20ms cycle. But you could also schedule this in simple cases like this with a single 5ms task: TASK(TASK_5ms) { static uint8 cnt = 0; cnt++; // XXX and YYY Mainfunctions shall only be called every 10ms // but do a load balancing, that does not run 3 functions every 10ms // and 1 every 5ms, but only two every 5ms if (cnt & 1) { XXX_Mainfunction_10ms(); } else { YYY_Mainfunction_10ms(); } ZZZ_Mainfunction_5ms(); } So, if you need something to be run every 5, 10 or 20ms, you put these runnables into the corresponding tasks. The old OSEK also had a notion of BASIC vs EXTENDED Tasks, where only extended tasks where able to react on OsEvents. This tasks might not run cyclically, but only on configured OsEvents. You would have an OS Waitpoint there, where the tasks is more or less stopped and only woken up by the OS on the arrival of an event. There are also OSALARM, which could either directly trigger the activation of a OsTask, or indirectly over an Event, so, you could e.g. wait on the same Waitpoint on both a cyclic event from an OsAlarm or an OsEvent set by something else e.g. by another task or from an ISR. TASK(TASK_EXT) { EventMaskType evt; for(;;) { WaitEvent(EVT_XXX_START | EVT_YYY_START | EVT_YYY_FINISHED); GetEvent(TASK_EXT, &evt); // Start XXX if triggered, but YYY has reported to be finished if ((evt & (EVT_XXX_START | EVT_YYY_FINISHED) == (EVT_XXX_START | EVT_YYY_FINISHED)) { ClearEvent(EVT_XXX_START); XXX_Start(); } // Start YYY if triggered, will report later to start XXX if (evt & EVT_YYY_START) { ClearEvent(EVT_YYY_START); YYY_Start(); } } } This direct handling of scheduling is now mostly done/generated within the RTE based on the events you have configured for your SWCs and the Event to Task Mapping etc. Tasks are scheduled mainly by their priority, that's why they can be interrupted anytime by a higher priority taks. Exception here is, if you configure your OS and tasks to be not preemptive but cooperative. Then it might be necessary to also use Schedule() points in your code, to give up the CPU. On bigger systems and also on MultiCore systems with an MultiCore OS, there will be higher nunbers of Tasks, because Tasks are bound to a Core, though the Tasks on different Cores run independently, except maybe for the Inter-Core-Synchronization. This can also have a negative performance impact (Spinlocks can stop the whole system) e.g. there could be some Cyclic Tasks for normal BaseSW components and one specific only for Communication components (CAN Stack and Comm-Services). We usually separate the communication part, since they need a certain cycle time like 5..10ms, since this cycle is used by the Comm-Stack for message transmission scheduling and also reception timeout monitoring. Then there might be a task to handle the memory stack (Ea/Fls, Eep/Fee, NvM). There might be also some kind of Event based Tasks to trigger certain HW-control and processing chains of measured data, since they might be put on different cores, and can be scheduled by start or finished events of each other. On the other side, for all your cyclic tasks, you should also make sure, that the functions run within such task do not run longer than your task cycle, otherwise you get an OS Shutdown due to multiple activation of the same task, since your task is started again, before it actually finished. And you might have some constraints, that require some tasks to finish in your applications expected measurement cycle. In safety relevant systems (ASIL-A .. ASIL-D) you'll also have at least one task fpr each safety-level to get freedome-from-interference. In AUTOSAR, you already specify that on the OSApplication which the tasks are assigned to, which also allows you to configure the MemoryProtection (e.g. WrAccess to memory partitions by QM, ASIL-A, ASIL-B application and tasks). That is then another part, the OS has to do at runtime, to reconfigure the MPU according to the OsApplications MemoryAccess settings. But again, the more tasks you create, the higher the usage of RAM, ROM and runtime. RAM - runtime scheduling structures and different task stacks ROM - the actual task and event configurations Runtime - the context switches of the tasks and also the scheduling itself
It seems to vary. I found that ETAS RTA offers 1024 tasks*, whereas Vector's MICROSAR OS has 65535. For task handling, OSEK/ASR provides the following functions: StatusType ActivateTask (TaskType TaskID) StatusType TerminateTask (void) StatusType Schedule (void) StatusType GetTaskID (TaskRefType TaskID) StatusType GetTaskState (TaskType TaskID, TaskStateRefType State) *Link might change in future, but it is easy to search ETAS page directly for manuals etc.: https://www.etas.com/en/products/download_center.php
Formally you can have an infinite number of OsTasks. According to the spec. the configuration of the Os can have 0..* OsTask. Apart from that the (OS) software uses data type TaskType for Task-Index variables. Therefore, if TaskType is of uint16 you could not have more than 65535 tasks. Besides that, if you have a lot of tasks, you might re-think your design.
Accurate interval timer inside rendering loop linux
What is the best way to do the following in Linux while(continue) { render(); //this function will take a large fraction of the framerate wait(); //Wait until the full frame period has expired. } On windows, waitable timers seems to work pretty well (within 1 ms). One way of proceeding is to use a separate thread that just sleeps and triggers a sychronization mechanism. However I do not know how much overhead there are in this. Note: Accuracy is more important than high frequency: A timer with frequency 1.000 kHz is preffered over a timer with 1 MHz.
Assuming you're looking for an answer in the C language: I don't remember the precision, but I recall I used to use the setitimer() function when I needed good precision. Here's an example of how to use it: http://docs.oracle.com/cd/E23824_01/html/821-1602/chap7rt-89.html
delay generated from the for loop
//say delay_ms = 1 void Delay(const unsigned int delay_ms) { unsigned int x,y; for(x=0;x<delay_ms;x++) { for(y=0;y<120;y++); } } I am trying to use the C code above for my 8051 microcontroller. I wish to know what is the delay time generated above. I am using a 12MHz oscillator.
This is a truly lousy way to generate a time delay. If you look at the assembler generated by the compiler then, from the data sheet for the processor variant that you are using, you can look up the clock cycles required for each instruction in the listing. Add these up and you will get the minimum delay time that this code will produce. If you have interrupts enabled on your processor then the delay time will be extended by the execution time of any of the interrupt handlers that are triggered during the delay. These will add an essentially random amount of time to each delay function call depending upon the frequency and processing requirements of each interrupt. The 8051 is built with hardware timer/counters that are designed to produce a signal after a user programmable delay. These are not affected by interrupt processing (it is true that the servicing of their trigger events may be delayed by another interrupt source) and so give a far more reliable duration for the delay .