Just to get a sense of perspective, running this demo sketch (the two blinking LEDs): ---------------------------------------------------------------------- Arduino Mega2560 (8K SRAM, 256KB flash) ---------------------------------------------------------------------- Sketch uses 14476 bytes (5%) of program storage space. Maximum is 253952 bytes. Global variables use 595 bytes (7%) of dynamic memory, leaving 7597 bytes for local variables. Maximum is 8192 bytes. -------------------------- Compilation complete. ---------------------------------------------------------------------- The Arduino Uno (2K SRAM, 32KB flash) ---------------------------------------------------------------------- Sketch uses 144544 bytes (45%) of program storage space. Maximum is 32256 bytes. Global variables use 563 bytes (27%) of dynamic memory, leaving 1485 bytes for local variables. Maximum is 2048 bytes. -------------------------- Compilation complete. Slight discrepancy between devices as I've been playing about with the code for the Mega2560!
Hey, another great video Ralph. This left me with a bunch of questions though. Like, how much space does the RTOS use up? What other functions are available in freeRTOS? What are the differences in RTOS on esp32 vs Arduino? Also, what are the advantages/disadvantages of using RTOS rather than the millis() multiprocessing techniques you demonstrated in the other video? I think there's easily enough questions around RTOS for you to do a follow-up video.
Got a question, John? OMG an avalanche is more like it! Well, there's no such thing as a free lunch so RTOS does use up some space which is why this all runs much better on an Arduino Mega2560 with 8K SRAM. Differences there are, as this is a lightweight, sneak-it-in implementation of RTOS rather than a full blown ESP32 rewrite. For example, the loop doesn't run the way you might think it should (see Github 'issues' tab for more info). github.com/RalphBacon/244-RTOS-for-Arduino/issues My milliseconds approach is a much memory friendlier approach but relies on each function completing in a reasonable amount of time - there is no pre-empting in my way so a heavy function will just continue to run until it runs out of things to do. FreeRTOS only gives each task a 15mS time-slice before pre-empting it for other tasks to run. I might have to do a follow up using a Mega2560... or a Nano Every 4809 if I can get FreeRTOS running on it.
Ralph, thanks for referring to my library. I’d suggest some improvements to your recommendation to use of the Arduino delay() function. Basically don’t use it. In a Task, delay() uses processor cycle counting, which keeps the Task Running rather than Blocked, preventing lower priority Tasks from getting any processor time. This will also cause the standard Arduino loop() to break, when running as the FreeRTOS idle Task, as it is normally set up at the lowest priority. Could be why it didn’t work for you. Best to use this delay function : vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for 1000 ms in this case, which puts the Task to sleep and uses no processor time.
I used FreeRTOS on AVR at least 10y ago. But use the biggest one in Dip (in terms of RAM size), the Mega 1284, which had 16k RAM. Worked fine. I even had a C++ layer for FreeRTOS, as functions having an object pointer as first parameter, can easily be adapted to object methods (correct C++ term: member functions).
@@RalphBacon smd, expensive and if you have a Mega324 Dip40 board (with socket) Mega1284 is a good replacement. And twice the RAM of the Mega2560. Plus it’s the biggest Flash, that still uses 16bit PC. GCC does not really like the 24-bit PC of the Mega2560.
Please repeat all after "Aaaaaand Welcome Back" Lol ! don't think I'm gonna be using this anytime soon but It's great to know I have this for a reference in the future, being able to 'Ref' your work got me through the early days so cheers Ralph !
lol... I see you realised the task handle names were wrong after you recorded this 😂 Great explainer video as always Ralph. I don't think I'd ever use this on a Atmega328 or even a 2560 - I prefer state machine for those, but it was a nice simple introduction to FreeRTOS nonetheless. Thank you! :)
Hi Ralph. It's nice to see two LEDs working with RTOS. What scares me is Stack size. As you say "Wild guess..". Well I don't like "magic numbers" because I know that Stack can make serious problems. I suggest to read an article about "Toyota’s killer firmware".
I use the following code to check how much stack space is left (for each task): // Check stack space void checkStack(uint8_t taskNo) { unsigned long remainingStack = uxTaskGetStackHighWaterMark(NULL); printf("Task %d Free stack:%lu ", taskNo, remainingStack); } It's the same code I use in my ESP32 projects.
-hmmm..not hearing from you again?..nah, can't have that, always love to hear from you! I am surprised that you didn't believe a operating system could run on Arduino, of course there is limitations but the old Z80 could run OS.
I wonder how the Z80 compares to an ATMega328P? It seems others have asked this and it would more than hold the pace, probably be faster than a Z80 running CP/M but it's the memory that would hold it back. More here: bit.ly/3G62pCU
This is great Ralph, love your teaching methods and how the video was put together! Really appreciate the code breakdown, the syntax is a bit weird to me.
An interesting experiment Ralph, but I have a few concerns about using it in serious projects. 1) An atmega328p is very resource constrained. Using multiple 256 stacks, one per task seems poor use of the 2k available. 2) the Arduino Freertos implementation uses the watchdog timer with a 15ms heartbeat. That's too slow! We should aim for 1ms for an RTOS. 3) You are living dangerously with the Neopixel code. The timing requirements of Neopixels are challenging. The Adafruit Neopixel library generates timing by disabling interrupts and using hand-crafted assembler code for bit banging. Disabling interrupts in any RTOS is asking for trouble!. So, a fun project, but I'd suggest a rewrite with a polling approach to avoid technical debt. Nothing in the application needs an RTOS.
Your observations on timers and such using the Adafruit library are valid, but you're looking at this from the wrong direction, Mike. This demo was to see if (a) RTOS could even run on the Arduino (b) whether it could do anything sensible So we proved point (a) with the two flashing LEDs but I thought what could I use (quickly) to prove (b). Well, the code for the Neopixels was still fresh in my mind (I'm using it in my current project) so I just threw it in, with scant regard for timers or much else to tell the truth. I was amazed it worked but it did prove that RTOS on the Arduino could do some "real work" other than two flashing LEDs. But I doubt whether I'd use this on a real project as the memory is limited (I'm using 220 bytes per task right now with 38 bytes free stack). But a simple sensor task would be fine, I'm sure. A Mega2560 is probably more sensible (8K SRAM) but I've yet to plug that in.
I don't suppose you can run NASA on an Arduino RTOS board 😁 but for simple stuff it might prove useful - even more so an an introduction to multitasking.
Good morning Ralph, Great video I love all the little tid bits you hand out on programming. Thanks.. I wonder if you think doing a series like 10 or so shortish video's on learning to code on Arduino or just with C++? long term project??? You have so many great video's on these topics but I don't think a course from beginning to end...Just a thought. and thanks again for all your dedication to us....
Remember you must not put anything in the task that delays or waits for longer than the time each task has been allocated, or you will have fun with the watchdog biting you rear.
Delays are no issue if the FreeRTOS delay functions are used. They put a Task to sleep, until it is due to run again. 0 overhead waiting for as long as you want. vTaskDelay() or vTaskDelayUntil() are your friends.
@@ThreeDRaymaker TaskDelays are ok, but you need to be careful with beginners and delays and loops etc, you have to get your head around the fact the tasks being jumped around in time slices. And don’t like any blocking code.
I've updated my demo sketch in the GitHub that contains vTaskDelay and got the loop sorted out too (thanks to a nudge from Phillip, the FreeRTOS for Arduino author).
I would consider struct { uint8_t pin; uint16 delay; } grnLED, redLED,...; and simply fill in the struct for each LED. Alternately, Arduino uses C++ so you could also make a class complete with blink function, instantiate cBlinker grnLED(grnPin, grnDly), redLED(redPin, redDly); and pass pointers to the objects to the task manger. The classes are a more type-safe way to do it and don't need global structs. I like these approaches because they are easily extendable to more LEDs.
If you want to use objects for RTOS you need to read up on a library by Flossie that puts this RTOS inside an OOP statically allocated wrapper. See: github.com/Floessie/frt Your code suggestions are great, but remember this demo was to encourage beginners and the inexperienced to have a go, not to put them off with structs, pointers or objects (two of which are subjects of a future video, so we are thinking along the same lines). But which scare the bejesus out of the aforementioned viewers. I've maintained C++ rarely needs pointers (so I'd see if a reference was enough for your suggested code) but I've just had to use pointers in a bit of code here and no, a reference was not enough this time. Thanks for posting, Byron, good to hear from you 👍🏻
@@RalphBacon I was unaware of Floessie so thanks for that. I have previously utilized "adapter functions" with ISRs that use class objects and I suspect that the wrapper does the same. Once you realize that the first (hidden) parameter to class functions is the pointer to 'this,' a new world opens up...
its also a good habit to put vTaskDelete(NULL); right before end of TaskBlink, its not madatory but larger handler might break its 'for' loop. Anyway learning how to write properly code under FreeRTOS might be nightmare but after 1 month its begin real relief how convenient it is.
Feels a bit like putting an engine management system on a lawnmower. And it messes anything timing related. But interesting idea and a workable option on a chip with more resources.The evil memory management looks a bit tricky
Hang on, your lawnmower _doesn't_ have an engine management system? No turbo? No supercharger? I guess it's a push-along rather than a sit-on, with 4 speeds (and reverse)? 😁🤣(No mini beer fridge either, I'll be bound). I like the analogy though. I think using it on a Mega2560 is a better place to start (8K SRAM) just to experiment. I don't like the lack of a loop() though, unlike the ESP32. But using it on an UNO just as an introduction to multi-tasking still works (as this video shows).
OK: C does not have references but it does have pointers. Enough? Sigh. Thought not. In C you are programming very close to the metal. So C lets you do pretty much what you want with pointers, even pointing to an invalid location or variable type. C++ tried to tame this behaviour with references so that some logic was brought in so that pointers could only point to ONE valid thing (and cannot be changed afterwards) - and called them references. More to it than this but that's about it. C++ has pointers too of course.
@@RalphBacon Thanks so much for the succinct reply. I had really not thought about references much before, but your video piqued my curiosity. I hadn't realised the safety aspect was the reason for choosing references over pointers.
Bjarne Stroustrup and I were having a drink a week ago and were mulling over the dangers of pointers in C and he said "That's why I created references for my C++". Enough said. Can't argue with the C++ inventor can we?
But can't you do the same thing without that Real Time O/S? (the task as the end of the video I am talking about). Nice video, by the way, and great video production with the code in full screen, and you on the bottom right, I guess filming on a green screen. Very nice video production. That takes a lot of work to do all that. It is appreciated.
Yes you can! If you use the pseudo-multitasking method I showed recently (video #BB5 - ruclips.net/video/hwEo49yyU88/видео.html ) using millis, then you do not have to use an RTOS at all. I use that all the time on the smaller (and not so small) processors. Thank you for your kind words about my videos. Yes, they take time but the end result justifies the effort IMHO 😉
@@RalphBacon It's always kind of cool and weird when you get back a reply from someone on the "TV". I just saw a video of your 1985 "claim to fame circuit" that got publiished in a magazine. I am sure you were making circuits long before that. Since we are talking about the past, in 1975, I built the Paia Gnome synth. ruclips.net/video/jSpXtQxYWfg/видео.html After seeing this video, I wished I had of kept it. I think I ended up just throwing it away. I think they are worth quite a bit now.
Yes I have, a very early version of the IDE that kept falling over, but when it worked it was OK. I muse try it again with a processor that supports it. I used the Arduino Zero last time but that has been withdrawn.
This is great. One task for the motion sensor and one to monitor the bucket of water's trigger! LOL. I've played with Arduino over the years, nothing serious, nothing in production running around the house, but the little I did, I thought it wasn't reliable meaning it would lose itself so I felt I needed to code a shutdown/restart so it regularly restarted. All the code I've ever run was very basic. What do you think about Arduino's reliability?
The Arduino will run for years - if the code is good. That said, my fridge alarm did stop every few months or so and required a reset. I suspect a power glitch. If you are worried that the Arduino will suddenly hang, implement the watchdog timer to reset it automatically. That's what it's there for!
I have an arduino which reminds the boss to take her pills at breakfast. Been running for 2+ years and on the same 3 AA batteries! RTC does the timing.
You need your glasses on Ralph, that's the nightly build from May 17th (3 days ago!) :p But yeah, IDE 2.0 is starting to become usable - I still won't write in it yet but it's definitely more 'meaty'. Interesting look at RTOS. I mean back in the day a 16MHz 386 could do many things in real time, so it's no suprise an arduino can do it. Although single core processors, basically just do one thing at a time and 'flit' between the two at incredible speeds. A task that never ends? Like house cleaning or looking after your children? (I don't have children! :p) I do wonder how memory intensive and that kinda stuff will be, since in the 'Duino world we only have bytes of memory (unlike i386 or even ESP). I'm looking forward to your 'Bacon Bytes' explanation of pointers and can't remember you doing a deep dive on structs yet. Please? What do you mean no? :( Also... Last time, not sure I count as padiwan and now I don't think I class as young being over 30 xD P.S Do you remember me telling you about my accessible lighting product? I'm thinking of going to copper with the design, since trying to write the program on breadboard is a nightmare. Stray inductance, capacitance etc and if you put it away you can have a lead fall off, then you end up debugging for hours before you realise "oh yeah, that fell off", so gonna build a development board to make it easier. Not the final design but something to help me get ready for it and learn the design tools. Hope everything with you and yours is still good :)
I'm at the stage of things falling off my prototype breadboard for my storage bin project; so I ordered a PCB yesterday from JLCPCB and it's 50% already! It will be nice to have all the components soldered so they can't move - and I can show everyone my new sockets that don't fall apart, too! Pointers video soon, although in the C++ world they are less required (or wanted, poor things). If (big IF) there is time (don't hold your breath) I'll sneak in a bit about structs. 😜
I _think_ that the standard Espressif RTOS can be used with the ESP8266, as it's a much bigger chip and is, basically, the smaller brother of the ESP32. It's certainly available via the Espressif SDK for the ESP8266 but you will have to Google to see whether someone has created an Arduino IDE-compatible version (maybe Espressif have).
The arduino uno has the Atmega 328. I have a Movi Audeme shield it has an A13 chip on it. A13 is a 64 bit processor, Arm Cortex 8, and Linux Kernel. The problem is that it would be considered as the slave to the Master Arduino Uno Atmega 328. Is there way to utilize that chip on the Movi shield for the FreeRTOS instead of putting it to the Arduino Uno 328 that is the Master?
Well, that Movi Auderne is for voice recognition (Alexa, shut the bleep UP!) because the Arduino would take about an hour to decipher each voice command. I have no idea whether you can run other stuff on that shield, I'm afraid. As it can "understand" 150 sentences I guess it's highly tuned to running its own software already.
I had to listen to the video to find out what you meant - and, yes, those were real birds outside my workshop. Making quite a lot of noise for tiny sparrows 🐦
Thinking the Arduino is not a freely programmable computer because its programmes are in ROM and it cannot have a linux like kernel because it does not have enough RAM but too many registers to save state ... you proofed me wrong. maybe connecting a system like RTOS and the Xorg loop to make the Arduino loop part of the linux loop and so an os that actually spans two or more computer might be a thing.
Hello, When I compile the code I get this error: Compilation error: 'pcTaskGetName' was not declared in this scope...Would you be so kind as to help me correct this? Thank you!
Did you take my example code first (we know that compiles) and try that? That sort of error usually means that you either have really not got a function called 'pcTaskGetName' or you have not got an #include for the file in which it was written. Basically, the compiler cannot find it at the time it needs it. Are you using Arduino IDE or Visual Studio Code with PlatformIO?
It takes less than you might think. My three task, LED blinker compiled to: 14,544 (45%) of 32,256 bytes 563 bytes (27%) of dynamic memory leaving 1,485 bytes for local variables But that's before the task memory is allocated.
You're on the right track. I've cast the void* incoming parameters as a uint8_t (one byte) pointer and got the value (dereferenced) that. No idea how this is working 😲 The line: uint8_t ledPin = *((uint8_t)parameters); should say uint8_t ledPin = *((int)parameters); // could say int16_t instead of int
@@RalphBacon Not sure what you mean there. Although pointers on this architecture are 2 bytes in size they can just the same point to a data type that is just 1 byte in size. You actually have *((uint8_t *)parameters) in your video which seems perfectly fine to me. Maybe you thought you were casting the pointer itself to the actual data? That's what it seems to me from the example above.
Ok, there is no bug after all.🤦♂️ For some reason I was convinced I was using an integer uint16_t to pass the parameter around but it's not, it's a one byte uint8_t integer. I did this deliberately so why I lost the plot I shall never know. So it's all working fine.
That's s shame, Stephen. Are you familiar with Arduino coding in the traditional way? That is, writing code in the 'loop' and calling various functions from it? What this allows is for independent tasks to run without any interference from the loop function at all. They will run forever. Like blinking an LED but more realistically reading a memory buffer and playing the MP3 streaming from an Internet radio station.
I use this code, called every so often, to check on stack space for each task: // Check stack space void checkStack(uint8_t binNo) { unsigned long remainingStack = uxTaskGetStackHighWaterMark(NULL); printf("Task %d Free stack:%lu ", binNo, remainingStack); }
@@RalphBacon looks like a useful bit of information to know. I'm working on tasks using wifi it would be good to know if I'm giving them too much stack space. so i might try this and store the max amount of space used. I might be able to spread it about more without killing the canary.
Yes, I call this routine every minute or so during debugging, then every hour for longer term testing just to ensure the free stack doesn't suddenly shrink (which it can do).
Just to get a sense of perspective, running this demo sketch (the two blinking LEDs):
----------------------------------------------------------------------
Arduino Mega2560 (8K SRAM, 256KB flash)
----------------------------------------------------------------------
Sketch uses 14476 bytes (5%) of program storage space. Maximum is 253952 bytes.
Global variables use 595 bytes (7%) of dynamic memory, leaving 7597 bytes for local variables. Maximum is 8192 bytes.
--------------------------
Compilation complete.
----------------------------------------------------------------------
The Arduino Uno (2K SRAM, 32KB flash)
----------------------------------------------------------------------
Sketch uses 144544 bytes (45%) of program storage space. Maximum is 32256 bytes.
Global variables use 563 bytes (27%) of dynamic memory, leaving 1485 bytes for local variables. Maximum is 2048 bytes.
--------------------------
Compilation complete.
Slight discrepancy between devices as I've been playing about with the code for the Mega2560!
I like the way the green task has the handle for the red task and vice versa just to throw us off the scent :D
I put that in deliberately to see if you were paying attention 🤥
Hi Ralph. It's nice to see your going great. Or at least looks like it. Don't forget to go outside and enjoy spring.
Thank you, I will!
Hey, another great video Ralph. This left me with a bunch of questions though. Like, how much space does the RTOS use up? What other functions are available in freeRTOS? What are the differences in RTOS on esp32 vs Arduino? Also, what are the advantages/disadvantages of using RTOS rather than the millis() multiprocessing techniques you demonstrated in the other video?
I think there's easily enough questions around RTOS for you to do a follow-up video.
Got a question, John? OMG an avalanche is more like it! Well, there's no such thing as a free lunch so RTOS does use up some space which is why this all runs much better on an Arduino Mega2560 with 8K SRAM.
Differences there are, as this is a lightweight, sneak-it-in implementation of RTOS rather than a full blown ESP32 rewrite. For example, the loop doesn't run the way you might think it should (see Github 'issues' tab for more info). github.com/RalphBacon/244-RTOS-for-Arduino/issues
My milliseconds approach is a much memory friendlier approach but relies on each function completing in a reasonable amount of time - there is no pre-empting in my way so a heavy function will just continue to run until it runs out of things to do. FreeRTOS only gives each task a 15mS time-slice before pre-empting it for other tasks to run.
I might have to do a follow up using a Mega2560... or a Nano Every 4809 if I can get FreeRTOS running on it.
@@RalphBacon Would love to see something on the 4809; so little out there
Ralph, thanks for referring to my library. I’d suggest some improvements to your recommendation to use of the Arduino delay() function. Basically don’t use it. In a Task, delay() uses processor cycle counting, which keeps the Task Running rather than Blocked, preventing lower priority Tasks from getting any processor time. This will also cause the standard Arduino loop() to break, when running as the FreeRTOS idle Task, as it is normally set up at the lowest priority. Could be why it didn’t work for you.
Best to use this delay function : vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for 1000 ms in this case, which puts the Task to sleep and uses no processor time.
Drop me a note on GitHub. Or email if you prefer. P.
sure way of wakeing the watchdog is using a delay function like that.
Hang on, who is John?
@@RalphBacon I believe it is a C++ reference to Ralph :)
@@RalphBacon easy
#define John Ralph
job done
I used FreeRTOS on AVR at least 10y ago. But use the biggest one in Dip (in terms of RAM size), the Mega 1284, which had 16k RAM. Worked fine. I even had a C++ layer for FreeRTOS, as functions having an object pointer as first parameter, can easily be adapted to object methods (correct C++ term: member functions).
The Mega2560 has 8K SRAM, 4 x more than the 2K of the Arduino Uno/Nano; RTOS should really fly on that.
@@RalphBacon it does fly on that.
@@RalphBacon smd, expensive and if you have a Mega324 Dip40 board (with socket) Mega1284 is a good replacement. And twice the RAM of the Mega2560. Plus it’s the biggest Flash, that still uses 16bit PC. GCC does not really like the 24-bit PC of the Mega2560.
Please repeat all after "Aaaaaand Welcome Back" Lol ! don't think I'm gonna be using this anytime soon but It's great to know I have this for a reference in the future, being able to 'Ref' your work got me through the early days so cheers Ralph !
Noted! But I do recommend just trying it out for future reference if nothing else, Andy.
Well presented as usual, and you get surprised what you can do with our old, trusty Arduino. So cheers, and yes, this was inspirational.
Glad you enjoyed it!
Wow ! I would not have believed this myself had I not seen it. There must be some serious "code squashing" going on to get this to fit on an arduino
Me neither (believed it, I mean). Hence my previous scepticism. But I was proved wrong.
I love that linear LED array
Yes, very eye-catching and not very much money either. Always good to keep one in your toolkit for experiments.
I had to put my coffee down when I heard RTOS and Arduino in the same sentence.
Funnily enough I was a bit like that. Unbelievable. But true.
lol... I see you realised the task handle names were wrong after you recorded this 😂 Great explainer video as always Ralph. I don't think I'd ever use this on a Atmega328 or even a 2560 - I prefer state machine for those, but it was a nice simple introduction to FreeRTOS nonetheless. Thank you! :)
Thanks 👍But I tried it on a Mega2560 and it does run very well indeed in its 8K SRAM.
Hi Ralph. It's nice to see two LEDs working with RTOS. What scares me is Stack size. As you say "Wild guess..". Well I don't like "magic numbers" because I know that Stack can make serious problems. I suggest to read an article about "Toyota’s killer firmware".
I use the following code to check how much stack space is left (for each task):
// Check stack space
void checkStack(uint8_t taskNo) {
unsigned long remainingStack = uxTaskGetStackHighWaterMark(NULL);
printf("Task %d Free stack:%lu
", taskNo, remainingStack);
}
It's the same code I use in my ESP32 projects.
-hmmm..not hearing from you again?..nah, can't have that, always love to hear from you!
I am surprised that you didn't believe a operating system could run on Arduino, of course there is limitations but the old Z80 could run OS.
I wonder how the Z80 compares to an ATMega328P? It seems others have asked this and it would more than hold the pace, probably be faster than a Z80 running CP/M but it's the memory that would hold it back.
More here: bit.ly/3G62pCU
@@RalphBacon Wouldn't it be posible to add more memory?
thank you for all your videos they make my work so much easier!
You are so welcome!
This is great Ralph, love your teaching methods and how the video was put together! Really appreciate the code breakdown, the syntax is a bit weird to me.
Yes, the syntax is C for the most part, but it gets easier the more you use it. Wait until you see my Pointers video, your brain will hurt.
@@RalphBacon Good stuff! Looking forward to it!
An interesting experiment Ralph, but I have a few concerns about using it in serious projects. 1) An atmega328p is very resource constrained. Using multiple 256 stacks, one per task seems poor use of the 2k available. 2) the Arduino Freertos implementation uses the watchdog timer with a 15ms heartbeat. That's too slow! We should aim for 1ms for an RTOS. 3) You are living dangerously with the Neopixel code. The timing requirements of Neopixels are challenging. The Adafruit Neopixel library generates timing by disabling interrupts and using hand-crafted assembler code for bit banging. Disabling interrupts in any RTOS is asking for trouble!. So, a fun project, but I'd suggest a rewrite with a polling approach to avoid technical debt. Nothing in the application needs an RTOS.
Your observations on timers and such using the Adafruit library are valid, but you're looking at this from the wrong direction, Mike.
This demo was to see if
(a) RTOS could even run on the Arduino
(b) whether it could do anything sensible
So we proved point (a) with the two flashing LEDs but I thought what could I use (quickly) to prove (b). Well, the code for the Neopixels was still fresh in my mind (I'm using it in my current project) so I just threw it in, with scant regard for timers or much else to tell the truth.
I was amazed it worked but it did prove that RTOS on the Arduino could do some "real work" other than two flashing LEDs. But I doubt whether I'd use this on a real project as the memory is limited (I'm using 220 bytes per task right now with 38 bytes free stack). But a simple sensor task would be fine, I'm sure.
A Mega2560 is probably more sensible (8K SRAM) but I've yet to plug that in.
I learned how to use FreeRTOS with an esp32. When I did try to use it on an uno it used up too many resources. Can not remember if it was ram or rom.
I don't suppose you can run NASA on an Arduino RTOS board 😁 but for simple stuff it might prove useful - even more so an an introduction to multitasking.
Good morning Ralph, Great video I love all the little tid bits you hand out on programming. Thanks.. I wonder if you think doing a series like 10 or so shortish video's on learning to code on Arduino or just with C++? long term project??? You have so many great video's on these topics but I don't think a course from beginning to end...Just a thought. and thanks again for all your dedication to us....
Great suggestion! But maybe I need to put all these C++ videos into a playlist of their own (like Bacon Bytes playlist)? What do you think, Gene?
Remember you must not put anything in the task that delays or waits for longer than the time each task has been allocated, or you will have fun with the watchdog biting you rear.
Delays are no issue if the FreeRTOS delay functions are used. They put a Task to sleep, until it is due to run again. 0 overhead waiting for as long as you want.
vTaskDelay() or vTaskDelayUntil() are your friends.
@@ThreeDRaymaker TaskDelays are ok, but you need to be careful with beginners and delays and loops etc, you have to get your head around the fact the tasks being jumped around in time slices. And don’t like any blocking code.
I've updated my demo sketch in the GitHub that contains vTaskDelay and got the loop sorted out too (thanks to a nudge from Phillip, the FreeRTOS for Arduino author).
I would consider
struct {
uint8_t pin;
uint16 delay;
} grnLED, redLED,...;
and simply fill in the struct for each LED. Alternately, Arduino uses C++ so you could also make a class complete with blink function, instantiate
cBlinker grnLED(grnPin, grnDly), redLED(redPin, redDly);
and pass pointers to the objects to the task manger. The classes are a more type-safe way to do it and don't need global structs. I like these approaches because they are easily extendable to more LEDs.
If you want to use objects for RTOS you need to read up on a library by Flossie that puts this RTOS inside an OOP statically allocated wrapper. See: github.com/Floessie/frt
Your code suggestions are great, but remember this demo was to encourage beginners and the inexperienced to have a go, not to put them off with structs, pointers or objects (two of which are subjects of a future video, so we are thinking along the same lines). But which scare the bejesus out of the aforementioned viewers.
I've maintained C++ rarely needs pointers (so I'd see if a reference was enough for your suggested code) but I've just had to use pointers in a bit of code here and no, a reference was not enough this time.
Thanks for posting, Byron, good to hear from you 👍🏻
@@RalphBacon I was unaware of Floessie so thanks for that. I have previously utilized "adapter functions" with ISRs that use class objects and I suspect that the wrapper does the same. Once you realize that the first (hidden) parameter to class functions is the pointer to 'this,' a new world opens up...
its also a good habit to put vTaskDelete(NULL); right before end of TaskBlink, its not madatory but larger handler might break its 'for' loop. Anyway learning how to write properly code under FreeRTOS might be nightmare but after 1 month its begin real relief how convenient it is.
It might be worth putting that into the loop that is NOT part of the idle task. I do this on the ESP32 sometimes.
Well I am stuck for words, so it is back to the Arduino book for Dummies for me:-) Great video Ralph
woof
@@TheEmbeddedHobbyist Fetch boy :-)
Don't you mean back to the Noddy Arduino book? 😲😜 Interesting video though, right?
@@RalphBacon of course:-)
@@fredflintstone1 squeak!!!!!
Feels a bit like putting an engine management system on a lawnmower. And it messes anything timing related.
But interesting idea and a workable option on a chip with more resources.The evil memory management looks a bit tricky
Hang on, your lawnmower _doesn't_ have an engine management system? No turbo? No supercharger? I guess it's a push-along rather than a sit-on, with 4 speeds (and reverse)? 😁🤣(No mini beer fridge either, I'll be bound).
I like the analogy though. I think using it on a Mega2560 is a better place to start (8K SRAM) just to experiment. I don't like the lack of a loop() though, unlike the ESP32. But using it on an UNO just as an introduction to multi-tasking still works (as this video shows).
Great stuff as always, thanks for sharing this!!
Glad you enjoyed it!
Ralph: "C does not have references," nice gem there: would you be able to expand on this a little?
OK: C does not have references but it does have pointers. Enough? Sigh. Thought not.
In C you are programming very close to the metal. So C lets you do pretty much what you want with pointers, even pointing to an invalid location or variable type.
C++ tried to tame this behaviour with references so that some logic was brought in so that pointers could only point to ONE valid thing (and cannot be changed afterwards) - and called them references. More to it than this but that's about it. C++ has pointers too of course.
@@RalphBacon Thanks so much for the succinct reply. I had really not thought about references much before, but your video piqued my curiosity. I hadn't realised the safety aspect was the reason for choosing references over pointers.
Bjarne Stroustrup and I were having a drink a week ago and were mulling over the dangers of pointers in C and he said "That's why I created references for my C++". Enough said. Can't argue with the C++ inventor can we?
@@RalphBacon Too true :)
But can't you do the same thing without that Real Time O/S? (the task as the end of the video I am talking about). Nice video, by the way, and great video production with the code in full screen, and you on the bottom right, I guess filming on a green screen. Very nice video production. That takes a lot of work to do all that. It is appreciated.
Yes you can! If you use the pseudo-multitasking method I showed recently (video #BB5 - ruclips.net/video/hwEo49yyU88/видео.html ) using millis, then you do not have to use an RTOS at all. I use that all the time on the smaller (and not so small) processors.
Thank you for your kind words about my videos. Yes, they take time but the end result justifies the effort IMHO 😉
@@RalphBacon It's always kind of cool and weird when you get back a reply from someone on the "TV". I just saw a video of your 1985 "claim to fame circuit" that got publiished in a magazine. I am sure you were making circuits long before that. Since we are talking about the past, in 1975, I built the Paia Gnome synth. ruclips.net/video/jSpXtQxYWfg/видео.html
After seeing this video, I wished I had of kept it. I think I ended up just throwing it away. I think they are worth quite a bit now.
Probably worth thousands now. Oh well. 😥
Thanks Ralph
My pleasure, Wayne, I hope you found it interesting.
Very good,
have you used the Debug in ver 2 of the IDE, will you be doing a video on it, thanks
Yes I have, a very early version of the IDE that kept falling over, but when it worked it was OK. I muse try it again with a processor that supports it. I used the Arduino Zero last time but that has been withdrawn.
This is great. One task for the motion sensor and one to monitor the bucket of water's trigger! LOL. I've played with Arduino over the years, nothing serious, nothing in production running around the house, but the little I did, I thought it wasn't reliable meaning it would lose itself so I felt I needed to code a shutdown/restart so it regularly restarted. All the code I've ever run was very basic. What do you think about Arduino's reliability?
The Arduino will run for years - if the code is good. That said, my fridge alarm did stop every few months or so and required a reset. I suspect a power glitch. If you are worried that the Arduino will suddenly hang, implement the watchdog timer to reset it automatically. That's what it's there for!
I have an arduino which reminds the boss to take her pills at breakfast. Been running for 2+ years and on the same 3 AA batteries! RTC does the timing.
You need your glasses on Ralph, that's the nightly build from May 17th (3 days ago!) :p But yeah, IDE 2.0 is starting to become usable - I still won't write in it yet but it's definitely more 'meaty'. Interesting look at RTOS. I mean back in the day a 16MHz 386 could do many things in real time, so it's no suprise an arduino can do it. Although single core processors, basically just do one thing at a time and 'flit' between the two at incredible speeds.
A task that never ends? Like house cleaning or looking after your children? (I don't have children! :p)
I do wonder how memory intensive and that kinda stuff will be, since in the 'Duino world we only have bytes of memory (unlike i386 or even ESP).
I'm looking forward to your 'Bacon Bytes' explanation of pointers and can't remember you doing a deep dive on structs yet. Please? What do you mean no? :( Also... Last time, not sure I count as padiwan and now I don't think I class as young being over 30 xD
P.S Do you remember me telling you about my accessible lighting product? I'm thinking of going to copper with the design, since trying to write the program on breadboard is a nightmare. Stray inductance, capacitance etc and if you put it away you can have a lead fall off, then you end up debugging for hours before you realise "oh yeah, that fell off", so gonna build a development board to make it easier. Not the final design but something to help me get ready for it and learn the design tools.
Hope everything with you and yours is still good :)
I'm at the stage of things falling off my prototype breadboard for my storage bin project; so I ordered a PCB yesterday from JLCPCB and it's 50% already! It will be nice to have all the components soldered so they can't move - and I can show everyone my new sockets that don't fall apart, too!
Pointers video soon, although in the C++ world they are less required (or wanted, poor things). If (big IF) there is time (don't hold your breath) I'll sneak in a bit about structs. 😜
thanks for sharing, do you know something similar to esp8266? usin RTOS for esp8266
I _think_ that the standard Espressif RTOS can be used with the ESP8266, as it's a much bigger chip and is, basically, the smaller brother of the ESP32. It's certainly available via the Espressif SDK for the ESP8266 but you will have to Google to see whether someone has created an Arduino IDE-compatible version (maybe Espressif have).
The arduino uno has the Atmega 328. I have a Movi Audeme shield it has an A13 chip on it. A13 is a 64 bit processor, Arm Cortex 8, and Linux Kernel. The problem is that it would be considered as the slave to the Master Arduino Uno Atmega 328. Is there way to utilize that chip on the Movi shield for the FreeRTOS instead of putting it to the Arduino Uno 328 that is the Master?
Well, that Movi Auderne is for voice recognition (Alexa, shut the bleep UP!) because the Arduino would take about an hour to decipher each voice command. I have no idea whether you can run other stuff on that shield, I'm afraid. As it can "understand" 150 sentences I guess it's highly tuned to running its own software already.
15:35 gotta like background birds
I had to listen to the video to find out what you meant - and, yes, those were real birds outside my workshop. Making quite a lot of noise for tiny sparrows 🐦
At 13:15 Ralph, that's a lot of code, to do so little!
You think so? I thought it was quite terse, all things considered. Go on, download my demo sketches and play about.
Interesting stuff 👍 thanks 🙏
Glad you think so!
Thinking the Arduino is not a freely programmable computer because its programmes are in ROM and it cannot have a linux like kernel because it does not have enough RAM but too many registers to save state ... you proofed me wrong. maybe connecting a system like RTOS and the Xorg loop to make the Arduino loop part of the linux loop and so an os that actually spans two or more computer might be a thing.
I'm glad it made you think about it, at least! Try it on the Mega2560, that has 8K SRAM and RTOS works very well there.
will you be doing anymore projects?
Yes, I will (still am), but I have backlog of "techniques" videos I need to clear too, which I've been remiss in finishing.
Very informative video Sir
Thank you, nice to see you hear again Muhammad 😉
Hello, When I compile the code I get this error: Compilation error: 'pcTaskGetName' was not declared in this scope...Would you be so kind as to help me correct this? Thank you!
Did you take my example code first (we know that compiles) and try that?
That sort of error usually means that you either have really not got a function called 'pcTaskGetName' or you have not got an #include for the file in which it was written. Basically, the compiler cannot find it at the time it needs it.
Are you using Arduino IDE or Visual Studio Code with PlatformIO?
Thank you! An update of the header files solved all the problems!
Best regards
I assume the rtos library is petty big. Do you know how much memory is free with it installed?
Fairly accurate use of additional ROM storage.
// Device: loop() -> FreeRTOS | Additional Program Storage
// Uno: 444 -> 7018 | 20%
// Goldilocks: 502 -> 7086 | 5%
// Leonardo: 3618 -> 10166 | 23%
// Yun: 3612 -> 10160 | 23%
// Mega: 656 -> 7086 | 2%
It takes less than you might think. My three task, LED blinker compiled to:
14,544 (45%) of 32,256 bytes
563 bytes (27%) of dynamic memory leaving 1,485 bytes for local variables
But that's before the task memory is allocated.
Is the bug declaring the led pins as uint8_t but then casting them to uint8_t pointers?
You're on the right track. I've cast the void* incoming parameters as a uint8_t (one byte) pointer and got the value (dereferenced) that. No idea how this is working 😲
The line:
uint8_t ledPin = *((uint8_t)parameters);
should say
uint8_t ledPin = *((int)parameters); // could say int16_t instead of int
@@RalphBacon Not sure what you mean there. Although pointers on this architecture are 2 bytes in size they can just the same point to a data type that is just 1 byte in size. You actually have *((uint8_t *)parameters) in your video which seems perfectly fine to me. Maybe you thought you were casting the pointer itself to the actual data? That's what it seems to me from the example above.
Ok, there is no bug after all.🤦♂️ For some reason I was convinced I was using an integer uint16_t to pass the parameter around but it's not, it's a one byte uint8_t integer. I did this deliberately so why I lost the plot I shall never know. So it's all working fine.
Perfect
I just know you are talking about me, Ariyan 😜
Nice jacket :D
They called me Mr Style in the old days. 🤥
😍😍😍😍😍😍😍😍😍😍😍😍😍😍😍
You're up earlyu today, Yoghesh (as usual, it must be said).
@@RalphBacon sir you available twitter , facebook ya any more sight
I’m afraid I am completely lost on this.
That's s shame, Stephen. Are you familiar with Arduino coding in the traditional way? That is, writing code in the 'loop' and calling various functions from it?
What this allows is for independent tasks to run without any interference from the loop function at all. They will run forever. Like blinking an LED but more realistically reading a memory buffer and playing the MP3 streaming from an Internet radio station.
Watch out for having too low an amount of stack memory as you will kill the canary as i did.
I use this code, called every so often, to check on stack space for each task:
// Check stack space
void checkStack(uint8_t binNo) {
unsigned long remainingStack = uxTaskGetStackHighWaterMark(NULL);
printf("Task %d Free stack:%lu
", binNo, remainingStack);
}
@@RalphBacon looks like a useful bit of information to know. I'm working on tasks using wifi it would be good to know if I'm giving them too much stack space. so i might try this and store the max amount of space used. I might be able to spread it about more without killing the canary.
Yes, I call this routine every minute or so during debugging, then every hour for longer term testing just to ensure the free stack doesn't suddenly shrink (which it can do).