Comments (15)
Now that I've disabled configSUPPORT_DYNAMIC_ALLOCATION
in my copy, the pxCurrentTCB
problem popped up again. I learned, this is due to LTO. The proposed #pragma GCC
solution led to an ICE, so I prepared a platform.txt
for my "ATmega328 on a breadboard" board, which disables LTO completely:
compiler.c.flags=-c -g -Os {compiler.warning_flags} -std=gnu11 -ffunction-sections -fdata-sections -MMD
compiler.c.elf.flags={compiler.warning_flags} -Os -g -fuse-linker-plugin -Wl,--gc-sections
compiler.S.flags=-c -g -x assembler-with-cpp -MMD
compiler.cpp.flags=-c -g -Os {compiler.warning_flags} -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD
That works fine. Together with the patch below my two-threads example saved ~250B SRAM and about 3kB flash. I'm now at ~6kB flash and 784B SRAM all statically allocated. 👍
diff --git a/src/FreeRTOSConfig.h b/src/FreeRTOSConfig.h
index 5422e2a..2c19f93 100644
--- a/src/FreeRTOSConfig.h
+++ b/src/FreeRTOSConfig.h
@@ -92,13 +92,13 @@
#define configMAX_PRIORITIES ( ( UBaseType_t ) 4 )
#define configMINIMAL_STACK_SIZE ( ( UBaseType_t ) 85 )
#define configIDLE_STACK_SIZE ( ( UBaseType_t ) 192 )
-#define configMAX_TASK_NAME_LEN ( 8 )
+#define configMAX_TASK_NAME_LEN ( 1 )
#define configUSE_TRACE_FACILITY 0
#define configUSE_16_BIT_TICKS 1
#define configIDLE_SHOULD_YIELD 1
#define configUSE_MUTEXES 1
-#define configUSE_RECURSIVE_MUTEXES 1
+#define configUSE_RECURSIVE_MUTEXES 0
#define configUSE_COUNTING_SEMAPHORES 1
#define configUSE_QUEUE_SETS 0
#define configQUEUE_REGISTRY_SIZE 0
@@ -106,11 +106,11 @@
#define configCHECK_FOR_STACK_OVERFLOW 1
#define configUSE_MALLOC_FAILED_HOOK 1
-#define configSUPPORT_DYNAMIC_ALLOCATION 1
+#define configSUPPORT_DYNAMIC_ALLOCATION 0
#define configSUPPORT_STATIC_ALLOCATION 1
/* Timer definitions. */
-#define configUSE_TIMERS 1
+#define configUSE_TIMERS 0
#define configTIMER_TASK_PRIORITY ( ( UBaseType_t ) 3 )
#define configTIMER_QUEUE_LENGTH ( ( UBaseType_t ) 10 )
#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
HTH,
Flössie
from arduino_freertos_library.
Thanks @Floessie. I see your pull #19 and it looks good.
I'll make a comment about it on the README soon.
There is a somewhat philosophical question to answer. Does using static Task creation make FreeRTOS easier for beginners to use? Before committing it, I will need to test it on all of the relevant ATmega versions (328p, 32u2, 32u4, 1284p, 2560) to make sure that this is the case, and that it just works for everyone.
I'd also point out that reducing the Task Name Length to a single character, and turning off the timer and recursive mutex features will save quite a bit of memory anyway, so the net RAM and Flash saving cannot be solely attributed to changing to static task RAM allocation. It would be interesting to see the net saving just from static task allocation.
Something else to look at for building a fully static FreeRTOS is the heap allocation process. I'm sure that you've noted that Arduino_FreeRTOS uses heap_3.c
for its pvPortMalloc()
implementation. In a fully static implementation of FreeRTOS we'd need to move this to use the heap_1.c
implementation. But doing this may be detrimental to the first principal, of Making FreeRTOS easier for beginners to use, by requiring heap management across device and individual projects.
I haven't worked out a way to do flexible heap assignment (i.e. just works across all ATmega hardware) without using the tunable variables from the avr-libc library, which are picked up by the standard malloc()
function. If you know a way, it would be good to include it in the pull request, for completeness.
from arduino_freertos_library.
There is a somewhat philosophical question to answer. Does using static Task creation make FreeRTOS easier for beginners to use? Before committing it, I will need to test it on all of the relevant ATmega versions (328p, 32u2, 32u4, 1284p, 2560) to make sure that this is the case, and that it just works for everyone.
That's what bothers me, too (an that's why I suggested to not default configSUPPORT_STATIC_ALLOCATION
to 1
). Your Blink_AnalogRead
takes 355B SRAM statically with configSUPPORT_DYNAMIC_ALLOCATION
, but ~1000B with both configSUPPORT_DYNAMIC_ALLOCATION
and configSUPPORT_STATIC_ALLOCATION
. Obviously one has to decide for one or the other, and configSUPPORT_DYNAMIC_ALLOCATION
is the proper default. I'll change that in my PR accordingly.
My plan is to provide my wrapper classes prepared for both cases (with static allocation taking precedence when configSUPPORT_STATIC_ALLOCATION
is defined), and to also provide a stripped down fork of your Arduino_FreeRTOS_Library with static allocation only, if I manage to solve the LTO issue without disabling it globally. With those wrappers the details are hidden and easy to grok also for beginners.
I'd also point out that reducing the Task Name Length to a single character, and turning off the timer and recursive mutex features will save quite a bit of memory anyway, so the net RAM and Flash saving cannot be solely attributed to changing to static task RAM allocation. It would be interesting to see the net saving just from static task allocation.
Absolutely. I can easily provide you with the flash numbers, but I've not yet found out, how to get the SRAM numbers for the dynamic allocation case on run time: Both MemoryFree and the freeRAM()
method yield -265
with Arduino_FreeRTOS. Maybe you've got a tip for me?
Something else to look at for building a fully static FreeRTOS is the heap allocation process. I'm sure that you've noted that Arduino_FreeRTOS uses heap_3.c for its pvPortMalloc() implementation. In a fully static implementation of FreeRTOS we'd need to move this to use the heap_1.c implementation. But doing this may be detrimental to the first principal, of Making FreeRTOS easier for beginners to use, by requiring heap management across device and individual projects.
For my fully static allocation test, I simply killed heap_3.c
and provided no heap_*
at all. As the manual for heap_1
says, "many small and deeply embedded applications create all the tasks, queues, semaphores, etc. required when the system boots, and then use all of these objects for the lifetime of program".
Let me propose this: I'll default configSUPPORT_STATIC_ALLOCATION
to 0 in my PR, try to solve the LTO issue, and see what can be done to conditionally compile heap_3.c
. Then Arduino_FreeRTOS is prepared for someone who wants to swap dynamic for static allocation. But really doing so is up to the user, and for everybody else it will stay the same. 😄
I haven't worked out a way to do flexible heap assignment (i.e. just works across all ATmega hardware) without using the tunable variables from the avr-libc library, which are picked up by the standard malloc() function. If you know a way, it would be good to include it in the pull request, for completeness.
Maybe this is not even needed, if one wants to do it all statically (which sure is beneficial for such a low memory device as the 328 and maybe not so much for the 1284)?
Best,
Flössie
from arduino_freertos_library.
Hi Phillip,
I think (just a wild guess) that the difference with the 2560 may be caused by an optimisation that is not in the Release, but is in Master. I was a little enthusiastic with the attribute((flatten)) attribute, since the 2560 has plenty of Flash to spare. I rolled that back but it is not yet in the Release. It could be that is what you're seeing.
That makes sense. 👍
Merged. #19.
Thanks. As far as I'm concerned you can close this now. Nice, we made it happen!
Best,
Flössie
from arduino_freertos_library.
First to the configUSE_TIMERS
question.
I've used a number of different timer options in my code over the years. Earlier FreeRTOS releases didn't support timers, so I grabbed timer code from Adam Dunkels' contiki to use when implementing uIP. Later, when FreeRTOS was given software timers, I've used them too.
The FreeRTOS timer solution runs in its own auto implemented mechanism that is very efficient. This means that the user doesn't have to care about running their own Task to manage software timers. This answers your question of why use timers within FreeRTOS. It is simply for the convenience. As with most things FreeRTOS, you turn a feature on or off as per your own preference. Just as a note, remember the software timer can't be have higher resolution than your system Tick. Trying to measure single milliseconds, for example, with a 15ms Tick will not be effective.
For implementing Static RAM allocation within FreeRTOS, the key thing you seem to have missed is actually allocating RAM for the Task heap and taskTCB
yourself. Since RAM for the taskTCB
is not allocated automatically, in the static implementation, you need to pass the address of the RAM you've prepared in advance to the xTaskCreateStatic()
function.
from arduino_freertos_library.
The FreeRTOS timer solution runs in its own auto implemented mechanism that is very efficient. This means that the user doesn't have to care about running their own Task to manage software timers. This answers your question of why use timers within FreeRTOS. It is simply for the convenience.
Thanks for the pointer. But I'm not concerned with how efficiently this feature is implemented code-wise but with the fact, that it takes SRAM for the stack and one of the four available priorities without being needed. As always, convenience doesn't come for free, it seems.
As with most things FreeRTOS, you turn a feature on or off as per your own preference.
I know. But there doesn't seem to be a way to do that with your code on a per project basis. If there was a #ifndef config*
around the #defines
one could override them before including Arduino_FreeRTOS.h
.
Just as a note, remember the software timer can't be have higher resolution than your system Tick. Trying to measure single milliseconds, for example, with a 15ms Tick will not be effective.
Sure.
For implementing Static RAM allocation within FreeRTOS, the key thing you seem to have missed is actually allocating RAM for the Task heap and taskTCB yourself. Since RAM for the taskTCB is not allocated automatically, in the static implementation, you need to pass the address of the RAM you've prepared in advance to the xTaskCreateStatic() function.
No, I haven't. That's why I had to move #include "FreeRTOSVariant.h"
to the end of Arduino_FreeRTOS.h
to make StaticTask_t
available before task.h
is included.
We rolled out a FreeRTOS based project at work some years ago, and I was i.a. responsible for implementing the threading wrapper (porting over from pthreads and earlier from eCos). Now I'm writing a C++11 wrapper for Arduino_FreeRTOS
for fun to put in some convenience with low overhead (using static polymorphism) and wanted to use the static variants, as stack size is always known at compile time. This would mean more control at compile time like the documentation says:
- The maximum RAM footprint can be determined at link time, rather than run time.
Thanks for your quick feedback. Much appreciated.
Best,
Flössie
from arduino_freertos_library.
But I'm not concerned with how efficiently this feature is implemented code-wise but with the fact, that it takes SRAM for the stack and
Yes it does take RAM for the (auto generated) timer Task. But, as noted it is very simple to turn it off, and roll your own Timers.
uses one of the four available priorities without being needed.
Perhaps you're getting confused by the FreeRTOS priority mechanism? You can have as many priorities as you choose. There is no maximum. For conservation the of RAM on the Arduino platform, and based on my own experience, I've selected four as a sensible maximum.
Also, there is no limitation to the number of Tasks that can share the same priority. Tasks with the same priority will share execution time in round-robin fashion. So the number of separate Tasks is not linked to the number of different priorities.
As with most things FreeRTOS, you turn a feature on or off as per your own preference.
I know. But there doesn't seem to be a way to do that with your code on a per project basis.
It is actually quite easy to change the configuration on a compile by compile basis, but you have to know where to look. FreeRTOS configuration files are stored in the ~/Arduino/libraries/FreeRTOS/src
directory in your Arduino installation. As every library is recompiled on each time you do an Arduino build, all you have to do is change the configuration in the FreeRTOSConfig.h
file in src folder to get whatever you need.
I have enabled everything that is sensible, in line with the Arduino philosophy that things should just work for beginners. For personal projects I only turn on what I need. If useful features were turned off, then people would wonder why something wasn't working and complain. Up until today that policy seems to be working, as no one has ever asked "Why doesn't xxx work in Arduino_FreeRTOS?"
Good luck with the static polymorphism. Way outside my experience, I'm afraid.
I'm focused on learning Z80 assembler currently.
from arduino_freertos_library.
Perhaps you're getting confused by the FreeRTOS priority mechanism?
Perhaps I just sounded a bit silly. Let's stop the discussion about timers here.
It is actually quite easy to change the configuration on a compile by compile basis, but you have to know where to look.
I know where to look, otherwise I wouldn't have been able to change the configs (see my initial post).
As every library is recompiled on each time you do an Arduino build, all you have to do is change the configuration in the FreeRTOSConfig.h file in src folder to get whatever you need.
Yeah, but I don't want to edit the library code when switching from one project to the next. That's not how a library works. Thus my suggestion to #ifndef
the configs, so one can optionally define them before including Arduino_FreeRTOS.h
on a per project basis.
I have enabled everything that is sensible, in line with the Arduino philosophy that things should just work for beginners.
Having the means for overriding those defaults on a per project basis would also attract non-beginners.
If useful features were turned off, then people would wonder why something wasn't working and complain. Up until today that policy seems to be working, as no one has ever asked "Why doesn't xxx work in Arduino_FreeRTOS?"
Well, then let me be the first: Why doesn't static allocation work in Arduino_FreeRTOS?
Good luck with the static polymorphism.
Thanks. Together with LTO it has no overhead currently. virtual
dispatch added 34B for two threads.
I'm focused on learning Z80 assembler currently.
Saw it on your blog. Impressive! Next stop monsterZ80... 😉
Thanks for your quick replies, although they are a bit too exegetical for me. I know some basics... 😁
Best,
Flössie
from arduino_freertos_library.
Sorry, didn't know there isn't a way to pass definitions from "sketch" to library in the Arduino IDE. 😖
Nevertheless, I was able to make it build with configSUPPORT_STATIC_ALLOCATION
, see #19. Feel free to not merge it with #define configSUPPORT_STATIC_ALLOCATION 1
, but maybe consider the other changes that were necessary to make it work.
HTH,
Flössie
from arduino_freertos_library.
Let me propose this: I'll default
configSUPPORT_STATIC_ALLOCATION
to 0 in my PR, try to solve the LTO issue, and see what can be done to conditionally compileheap_3.c
.
Standing by.
I've not yet found out, how to get the SRAM numbers for the dynamic allocation case on run time: Both MemoryFree and the freeRAM() method yield -265 with Arduino_FreeRTOS. Maybe you've got a tip for me?
I can only suggest compiling with dynamic allocation using heap_1.c
and then the heap management API of FreeRTOS is available. Use xPortGetMinimumEverFreeHeapSize()
to see how much heap is free, from what you've allocated when declaring the heap in configTOTAL_HEAP_SIZE
. This method ensures that you're capturing the entire heap RAM usage of the solution, provided that there are no direct calls to malloc()
or similar sins.
This example below for 328p, but I have different definitions available depending on the ATmega platform, and whether or not extended RAM is used (for the 2560).
uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
Very interested to see the comparisons.
from arduino_freertos_library.
I can only suggest compiling with dynamic allocation using heap_1.c and then the heap management API of FreeRTOS is available. Use xPortGetMinimumEverFreeHeapSize() to see how much heap is free, from what you've allocated when declaring the heap in configTOTAL_HEAP_SIZE. This method ensures that you're capturing the entire heap RAM usage of the solution, provided that there are no direct calls to malloc() or similar sins.
Unfortunately, you can't use heap_1.c
without configSUPPORT_DYNAMIC_ALLOCATION
. At least the source reads:
#if( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
#endif
But here are the numbers for my two demo tasks (85B + 192B stack size) without LTO:
- static: 9644 / 1047
- dynamic: 10152/726
With defaults restored and heap_3.c
.
from arduino_freertos_library.
Standing by.
Done in #19.
from arduino_freertos_library.
I'll have a look at the difference between heap_1.c
and heap_3.c
with dynamic allocation soon. That will provide a good view of the differences in RAM and Flash across those two options.
In my personal projects I never use heap_3.c
because it sucks in all of the avr-libc malloc()
code (and its friends calloc()
and realloc()
) which adds a quite few kB of Flash on any project. It is only used in this library because of the avr-libc auto variables enabling configuration free usage across ATmega devices.
Failing me getting to test #19 fully in the short term (holidays next week), is there any reason why it wouldn't work across all ATmega hardware, without further configuration? Can you check, please?
Also, since it there is a different usage model for using FreeRTOS features, with static allocation, which means the user has to be a lot more advanced and provide their own memory plan, I'm tempted to create a "Static AVR_FreeRTOS" branch and put #19 on that. But, I'll have to work on my very limited Gitfu to do that.
from arduino_freertos_library.
Failing me getting to test #19 fully in the short term (holidays next week), is there any reason why it wouldn't work across all ATmega hardware, without further configuration? Can you check, please?
No, that was my goal, but of course I can't prove that it works on every ATmega hardware. Anyway, here are some compile tests with Blink_AnalogRead.ino
:
Board | Vanilla flash/SRAM | Vanilla *.hex MD5 | #19 Vanilla flash/SRAM | #19 *.hex MD5 |
---|---|---|---|---|
Yun (atmega32u4) | 11462/320 | d0633a70625effeedb6ff45db36bdad1 | 11462/320 | d0633a70625effeedb6ff45db36bdad1 |
Uno (atmega328p) | 8930/356 | 746dbf2451179088f9354d54a489e355 | 8930/356 | 746dbf2451179088f9354d54a489e355 |
Nano (atmega168) | 8930/356 | 40f205460509f2ddd3f32c9eadf0f23d | 8930/356 | 40f205460509f2ddd3f32c9eadf0f23d |
Mega (atmega2560) | 30756/356 | b1b9089148d7a8d570e7b8acd2e2cf00 | 9416/356 | 96a8c53d987f87cacff6b11db7613b06 |
Mega (atmega1280) | 9584/356 | 33fe04467a18e7f0759146975fda787b | 9584/356 | 33fe04467a18e7f0759146975fda787b |
Mighty (atmega1284p) | 9128/356 | f0fd99e6b5066152f9b1e4fc176f318f | 9128/356 | f0fd99e6b5066152f9b1e4fc176f318f |
I checked atmega2560 twice, but the difference is real. Don't know, what you'll do with that. Maybe you have a Mega to test with. Otherwise I'm pretty confident, that those changes don't have an impact. 😄
Best,
Flössie
from arduino_freertos_library.
I think (just a wild guess) that the difference with the 2560 may be caused by an optimisation that is not in the Release, but is in Master. I was a little enthusiastic with the __attribute__((flatten))
attribute, since the 2560 has plenty of Flash to spare. I rolled that back but it is not yet in the Release. It could be that is what you're seeing.
Merged. #19.
from arduino_freertos_library.
Related Issues (20)
- STM32FreeRTOS myservo can not work. HOT 2
- what is the difference of three freertos? HOT 5
- FreeRTOS automatically restarts after the last task has finished on Arduino Mega 2560 HOT 7
- vTaskDelay not functioning as expected in setup HOT 3
- Is it possible to implement a system timer interrupt version (rather than WDT) compatible with Arduino IDE? HOT 2
- Generic device support HOT 3
- RTOS Example Compile Error HOT 4
- Where is the define of TaskControlBlock_t in task.h? HOT 1
- define delay() to vTaskDelay() HOT 3
- Arduino delay() changed its behavior to not do busy wait anymore HOT 19
- INCLUDE_vTaskDelayUntil and INCLUDE_xTaskDelayUntil && avr/io.h: No such file or directory HOT 3
- Arduino Due support HOT 4
- lgt8f328p compatibility HOT 22
- Arduino R4 HOT 5
- [Q] Unable to change FreeRTOSConfig.h for a single sketch on Arduino IDE 2.2.1 HOT 1
- Casting error on vPortDelay function
- Issue with delay(); HOT 1
- Teensy support HOT 4
- FAQ (for anyone who wishes to ask..) HOT 5
- Support for AWS FreeRTOS ESP32 HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from arduino_freertos_library.