Home > On-Demand Archives > Q&A Sessions >
Live Q&A - Best Practices for RTOS Application Design
Jacob Beningo - Watch Now - EOC 2021 - Duration: 19:35
Certainly!
Below are a few good ones and classics:
- Clean Architecture by Robert Martin
- Real-time Concepts for Embedded Systems by Qing Li
- Test Driven Development for Embedded C by James Grenning
- Real-time C++ by Chris Kormanyos
- Definitive Guide to ARm Cortex-M23 and Cortex-M33 Processors by Joseph Yiu
- The Art of Designing Embedded Systems by Jack Ganssle
- C in a Nutshell by Peter Prinz and Tony Crawford
- Expert C Programming Deep Secrets by Peter Van Dev Linden
Obviously there?s a ton more, but hopefully that helps give you some reading ideas!
What is the best way to implement an application which has an inherent need for state control
(i.e. state machine, controlled by driver inputs) in and RTOS design paradigm?
I have implemented an Event Handler which distributes messages from a Queue to the running context, but so far hasn't been deterministic.
Typically I run the state machine within the task using a StateMachineRun function. I then expose API's that can be used to trigger state transitions from other context.
How to handle Asynchronous data reception in the system. For example if there 2 UART peripherals(no flow ctrl), that should accept data, that later should be processed by application. How should this be handled ?
You could use a UART Gate Keeping task to manage it. You could also use a semaphore to signal which UART the data came from. Also a queue. Many different patterns you can use. let me know if that makes sense.
Jacob, great talk and Q&A session. I?d love to use Tracealyzer to learn more about what my application is really doing under the hood, but it?s just too expensive for occasional use. Have you found others such as SystemView to be almost as useful? Also I?m using ST-Link v2 on a custom STM32 board for debugging, but the turnaround time after making a change and loading into flash takes a minute or so, multiple times during the day. I know ST-Link v3 exists, but there seem to be multiple models and doesn?t seem to be available. Is something like I-Jet or J-link really any faster in practice? I know they offer unlimited breakpoints, which would help. Are they also fully compatible with custom STM32 boards (i think using SWO)? Thanks!
Thanks for the question.
SystemView can give you some details, but not as powerful as Tracealyzer. STM32CubeMonitor could also be helpful. Not used it much yet, but looked interesting.
I'm biased here, in that I always find paying for a tool is well worth the cost. So if you work for a business, I'd recommend you get them to just buy the Tracealyzer license. My technique is to convert the cost for a tool to the number of hours of my labor it takes to equal it. So if the tool is $1500 and I make $50/hr, then if the tool will annually save me at least 30 hours of work and debugging, it's well worth the investment.
I have not used the ST-Link v2 in quite some time. I use my J-Link Ultra+ most of the time. Typically the erase and load time is < 5 seconds. You may be able to update the ST-Link Firmware to V3.
The FreeRTOS CPU usage function doesn?t really work.
Its great to hear a few mentions of uC/OS-III. I use it every day and the book is very clear. I enjoyed your talk about MPUs also.
Thanks! That is good to know!
Great talk Jacob, how do you perform a Worst Case Stack Analysis? by checking all the variables within the task and sum the memory spaces?
There are two main ways I do it.
1) Analytical by using a static code analyzer. (Can also do it manually, but the code analyzer is faster)
2j through testing. Can use tools like RTOS aware debugging, ides, Tracealyzer, rtos stack monitors, stack watermarks, etc.
Jacob, I actually have a question about your 2020 talk "Developing Reusable Firmware for MCUs", but this seemed the best place to post it. In that video, some of the peripheral APIs you showed had a "CallbackRegister" function for which the function pointer had the formate "TYPE (*CallbackFunction)(type)". What are "TYPE"/"type" in that function signature? Thanks!
Thanks for the question. Yes so TYPE was my generic way of putting in some pseudo code that a developer would update. So TYPE would be replaced by uint32_t, uint8_t, or whatever type the application required. We could probably make it void or some generic return that is case into what is needed.
Hello Jacob... I have some questions:
1) I have a task that handle the UART messages logger. I create a queue that all the other task use for send message to the UART logger. The problem is that the object of the QUEUE that store the message consume much memory, because for example save 256 bytes to the message. If I defined a queue of the 200 elements... the queue use 51.2KB from RAM... What you suggest me to reduce this high consumption?
2) Related with "Best Practices for Setting Task Priorities"... What is the difference in the shortest response time vs shortest execution time? I understand execution time, but I don't understand the concept of shortest response
3) How measure the response and execution time of a Task?
4) How I can document a RTOS project (a tool) that show the relation between task, priorities, sempahores and mutexes?
Thanks for the questions. Please see below:
1) I would suggest that you pass the data by pointer. You can have a shared memory location of 256 bytes that stores several messages. Then pass the pointer to the memory location.
2) Basically the task that needs to respond quickly has the higher priority. For example, the response time on a vehicle brake peddle may be 30 ms, while the knob on a radio might be 100 ms. The brake peddle should therefore have the higher priority.
3) I use Tracealyzer to measure how my system is performing. It measures response time, execution time, periodicity and several other metrics.
4) I typically use a tool like Visio, eDraw Max or even sometimes PowerPoint.
Thanks Jacob
Great talk, and very cool approach for a lot of embedded, not just RT stuff! I'll try and apply it more in my general life as well
Thanks! I?m glad to hear that you like the approach! I hope it helps!
Concerning to setting task priorities, what is the difference between Response Time and Execution Time?
Response time will look at how quickly the task needs to start executing when it becomes due to run. Execution time is just based on how much CPU time the task needs to runs.
I was not sure concerning to the meaning of response time in this context, so you've clarified it. Thanks! And congratulations for the presentation, it was excellent!
Thanks!
Also, regarding the summary slide: Does your book on reusable firmware talk about how to build a diagnostic/fault detection task? What are some other resources you might recommend to learn more about implementing that?
I agree that generally you should do: Input-Process-Output but sometimes you may need to do Output-Input-Process especially in periodic tasks. The reason is to ensure that outputs always occur at predictable intervals. In you input and process, depending on the processing time for these then you would create jitter in the output is might not be acceptable. In fact, I would update ALL the outputs first and then read all the inputs and then do the processing afterwards.
Great suggestion! Totally agree!
One thing that would be worth mentioning is that all the RTOS services consume CPU cycles and thus the application developer needs to be mindful of that. So, yes, you should use RTOS services but be aware of the impact of performance.
Yes great suggestion / observation! These are often easy to overlook.
I like the idea of your task creation pattern. Makes it easier to make changes. However some off-the-shelf modules have their own initialization code so that cannot be called. Also, what do you do with other kernel objects?
Also, you used power-of-two stack size, any specific reason or, to make it easier to use with an MPU?
For task stack storage, you should never use dynamic memory location UNLESS you never delete tasks at run time which you should not anyway.
Thanks. So, I try to use this pattern if I can to manage my application tasks when it makes sense. Certainly third party libraries will create their own tasks such as spinning off TCP/IP, MQTT or other tasks. To find these, I usually have to trace the system.
With the other kernel objects, I generally try to abstract them into the modules that use them so that they are hidden.
To make it easier to use with an MPU ... ;-) After doing this for 20+ years I generally do everything in powers of two so it's just natural. Moving averages need to be done, power of two elements. Allocate memory, power of two. etc.
I 100% agree on never using dynamic memory. Unfortunately my examples are lazy in that they use dynamic memory. Prior to FreeRTOS v8, they didn't even support static allocation so the only way to safely allocate a task was to dynamically allocate it at start-up and then leave it there.
Are there situations where there is a value in reducing the number of interrupts by configuring some slow peripherals for polling instead of interrupts, assuming your system can can service them fast enough at a fixed rate?
Thanks for the question. There can be situations where it makes sense to avoid using the interrupts or at least need to be super careful how they are used. For example, if you are using input capture to calculate frequency or duty cycle and calculating in the ISR, you may find that with signals that are 5 KHz and up that most of your time is spent servicing the input capture interrupts. In these instances, it can make more sense to poll the timer at a known interval and take an average of the edges that were detected ( well at least for frequency measurement. That won't work for duty cycle).
Do you have a syntax or reference document for the data flow diagram you created? I have not seen that syntax before and I like it.
Thanks for the question. I don't actually. It's just notation that I started to use when I started to use RTOS based systems. I will do some checking to see if there is anything already formalized and if not, maybe i'll look to do so. Thanks for the feedback/question.
How to handle Asynchronous data reception in the system. For example if there 2 UART peripherals(no flow ctrl), that should accept data, that later should be processed by application. How should this be handled ?
There are different design patterns that can be used to handle something like this. First, I generally would have a single task to handle the incoming UART data. No need for two tasks to interface to similar devices. I would then use an interrupt, either from the UARTs or even DMA, to signal via a semaphore that there is data to be processed. The ISR would push the incoming byte into a circular buffer and then the UART task would manage the data that was received. This will vary from application to application but usually its served up to another function or task that validates it and figures out what to do with it.
what is the difference between Response Time and Execution Time? what can influence the response time of a task?
Thanks for the question. Execution time is how long it takes for the task to run. Response time is how long it takes until the task is able to run.
Hi Jacob, great talk. I want to ask you about low power techniques in RTOS. Apart from putting the MCU to sleep in the idle task, are there more things to consider? what approach do you usually use for battery powered systems where low power is crucial?
Thanks for the question. For low power systems, I generally try to make everything as event driven as possible. I try to eliminate periodic tasks. An event wakes the system up and signals a task that needs to run, it runs signals any others and when done the idle task is there to put the system back to sleep.
14:44:34 From Manuel Malagon : I don't have the "hand raise" icon. How do I ask a question on the microphone? 14:44:47 From Aabhas : Hi Jacob, Can we minimize communication between tasks by using shared memory? What problems can arise in the application? 14:45:01 From Dave Nadler : Not at all! Use the timer task callback to put something into a queue to start other processing. 14:45:13 From JCA Engineering : You can raise your hand from the reactions menu. 14:45:59 From afwaanquadri : I like the idea of placing Tasks info at one place. Been there were tasks were created all over the place :D 14:46:05 From Jean Labrosse : The Timer task execute data in order instead of by priority. So that defeats the idea of an RTOS 14:46:35 From afwaanquadri : I agree with Jean Labrosse 14:47:05 From ever : I will post my question here... if we have a NONE RTOS embedded system (legacy code) what will be the best practice to migrate to RTOS ?, what will be the best practice, seems in my expirience the best practice is to either stick the way it is OR rewrite everything 14:47:56 From Sergii Akhinko : How to handle Asynchronous data reception in the system. For example if there 2 UART peripherals(no flow ctrl), that should accept data, that later should be processed by application. How should this be handled ? 14:48:26 From Aldo Coronado : What is the best way to implement an application which has an inherent need for state control (i.e. state machine, controlled by driver inputs) in and RTOS design paradigm? I have implemented an Event Handler which distributes messages from a Queue to the running context, but so far hasn't been deterministic. 14:48:31 From Aditya S : Hi Jacob, I recently found using FreeRTOS that a memory pool I used to bind a channel input with an output (from one task to another) was overwritten when the task scheduler started. To get around it, I had to declare the buffers and the memory pool had outside of the stack. I had not come across this before, and wondered whether I just got lucky last couple of years with previous code where I had not had this issue before? And is this the case with other RTOSs as well? 14:49:41 From Dave Nadler : Adita, you should not be placing buffers and memory pool on stack. 14:49:43 From Jorge Conti : what is the best practice to define memory for each task? 14:50:16 From Dave Nadler : Adita, when tasks start, stack area from startup is used for other purposes - which is a good feature as otherwise memory is wasted. 14:52:03 From Jean Labrosse : In most cases, when the RTOS starts, the startup stack is LOST! There are ways to recover that. 14:52:34 From Dave Nadler : Its not lost, for example on Cortexx-4M it is reused as stack for ISRs. 14:52:46 From Aditya S : OK, thanks Dave. I think I follow. I suppose I probably got lucky previously based on the size of the pools defined. 14:52:51 From Dave Nadler : I'm speaking of FreeRTOS Jean. 14:52:51 From Rocco Brandi : what is the difference between Response Time and Execution Time? what can influence the response time of a task? 14:54:15 From Tim Michals : Are are not more RTOS vendors use lock free message queues? 14:54:23 From Nathan Jones : I think "response time" is similar to "deadline", meaning that it's the latest time the task can finish before something bad happens to the system (like not refreshing a screen at a sufficient rate). 14:54:28 From Davy Baker : How would you compare your go to methods, to Ganssle's? 14:54:30 From javi : ever, you can start by putting you baremetal infinite loop into a FreeRTOS task and then start creating new tasks for other parts as you progress, step by step 14:55:12 From Dave Nadler : Right Javi, or use this as a starting place for factoring what should be separate tasks. 14:55:14 From Jean Labrosse : Best practice to allocate memory, especially for stacks is STATIC. If you use malloc() to allocate task stacks as long as you never delete tasks. For sure, you should NEVER use malloc() and free() to allocate memory because of fragmentation. 14:56:08 From Andrei : Any useful plugins for looking at FreeRTOS tasks at a given moment (i.e. debug halt)? I mean, inspecting a queue (where if I remember correctly the "message" is copied) is pretty difficult 14:56:31 From Mark Z : Hey Jacob, something I was thinking about was how to guarantee the timing of a Real Time System that's using Rate Monotonic Scheduling and Interrupts. Interrupts can be small and fast and only set a flag so would it be good enough for RMS to verify the CPU Utilization of all the tasks plus the interrupts? Maybe switching to a different scheduling method that doesn't use interrupts would be preferrable (like polling server or deferred server?) 14:59:19 From Jean Labrosse : RTOS aware plugins in tools are STATIC and not dynamic so you have to STOP your application to see what happens. Not very useful for dynamic systems like control systems. 14:59:21 From Manuel Malagon : Tracealizer is expensive, what do you think about segger systemview? It is very good and it is free to use. 14:59:54 From Jean Labrosse : I used SystemView, I like it, super easy to use and last I checked, there was a free version. 15:00:21 From Jean Labrosse : Great job Jacob! 15:00:32 From Andrei : Thank you! 15:00:34 From Raul Pando : Thanks Jacob 15:00:35 From Mikael Albertsson : Thank you Jacob! 15:00:45 From Douglas Renaux : thanks alot 15:00:47 From Christopher Long : Thanks Jacob!
Hi Jacob,
Thank you very much for your talk.
I saw you have too many books behind you. Could you suggest me some of good books you have for embedded engineers?