Six projects for the near future of the Arduino open source project

161 views
Skip to first unread message

Massimo Banzi

unread,
Jun 7, 2017, 12:02:00 PM6/7/17
to Arduino Developers

A few weeks I gave my usual presentation at Maker Faire San Mateo about the work we’re doing on the Arduino open source project and in which directions we’re hoping to take the platform. One of the key messages was that we want to make it as easy as possible for the community to run their code on as many platforms as possible with the least amount of changes.

We need the help of the dev community to tackle some of these big items, please read and provide feedback!

Project Chainsaw; In recent years Arduino has been ported to a ton of different architectures and this has generated a lot of misalignment between each version, with different implementations of code that is essentially cross platform and there is no reason to re implement it multiple times.

A few months ago I realised I couldn’t re-use an example because the IPAddress class was older than in the SAMD core and I decided we had to do something.

Project “Chainsaw” is about separating the cross platform Arduino API code from the platform specific code creating a sort of “Hardware Abstraction Layer” which should make it much easier to port and maintain Arduino. We have an experimental repository we will open up in the next few weeks so that anybody can contribute and potentially adopt it for their port. This will mean that any bugfix in the common code will benefit all ports of Arduino and we can better pool resources between efforts and avoid duplications.

ArduinoAPI: When we launched Arduino we provided libraries for basic peripherals like SPI, I2C because the processors we used back then were quite simple and the projects people built were not that sophisticated yet. If somebody needed extra functionality they normally coded them in C or even Assembly. Right now, after the adoption of X86 or ARM processors we have more features available and each Arduino port is implementing them in a slightly different way. I think it’s important we have high level “abstract” API for thing like Bluetooth Low Energy , Low Power, Date/Time, IMU, HTTPClient, Timers, Crypto. I’ll publish the full list in a separate message to the developer list and release a set of repositories where we can comment on the API and hopefully converge.

Arduino Pre-Processor: In the last few years we’ve tried to “carve out” as much “business logic” as possible from the IDE to place it in external (open source) tools that are installed as binary command line processes. One of the major changes we introduced is the arduino-builder . This tool takes your code and  turn it into full blown C++ automating a numer of steps that people have to do by hand in other IDEs, things like: discover the dependencies for all the libraries you include, generate prototypes for the functions you create, pass the files to the compiler, get a binary file, upload it  and a lot more. Arduino-builder takes care of all of this. Unfortunately the pre-processing part had some weaknesses that made it unreliable in some edge cases. Thanks to an impressive effort of  our Cristian Maglie, he managed to re-write the preprocessor using  CLANG from LLVM. This means that parsing the code is more robust and the quality of the resulting code is better. Bonus feature is that we can use this new parser to ask to the compiler directly what functions can be used in a specific point in the code allowing us to add autocomplete to the IDE. Again look at the developer mailing list in the next few weeks when we’ll release this new experimental code. We need as many people as possible to test it before we can include it in the IDE. We’ll release this tomorrow!!!

Arduino Library format: With the introduction of Arduino 1.6.x we improved the layout of the Arduino libraries to support multiple architectures, metadata and more. One of the areas that needs improvement is documentation. At the moment documentation for libraries is kept separate from the source code itself.  We will update the specifications to the Arduino library format to include a folder for documentation that can be written either in markdown or asciidoc. This will allow us to keep the documentation in sync with the code and make sure they don’t go out of sync.

Finally there are two longer term project we definitely need to get done before the end of the year:

Scheduler: A task scheduler to achieve some level multitasking on Arduino. There is a lot of code out there but , unfortunately, it’s all quite hard to understand unless you’re an expert. Let’s see if we can build something that can be used by most of the Arduino users.

Debugging: We did quite a bit of work on the backend with the help of Matthijs Kooijman and we were waiting for a sponsorship to complete the UI part. Unfortunately the sponsorship didn’t materialise so we’ll schedule this as soon as we have funds or a developer who wants to do it!


Again thanks for taking the time to read and please provide your feedback

m




Thibaut VIARD

unread,
Jun 7, 2017, 12:20:22 PM6/7/17
to Massimo Banzi, Arduino Developers
Ciao Massimo,

That's great news, thanks for sharing the plans here!

Indeed Chainsaw and ArduinoAPI are something needed for a matter of consistency and portability across the different ports. Some rules and guidelines describing how the implementation should behave would be a great plus (and certainly require a huge documentation effort).

The scheduler offer may bring the demand in particular for communication tasks like usb, bluetooth, network, etc... and lead to very interesting features. 

Thibaut


--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+unsubscribe@arduino.cc.

Mikael Patel

unread,
Jun 7, 2017, 4:25:29 PM6/7/17
to Thibaut VIARD, Massimo Banzi, Arduino Developers
Hi!

I have done some work on two of these items.

Arduino-Scheduler (https://github.com/mikaelpatel/Arduino-Scheduler)
A somewhat more portable variant of the Scheduler for Due (SAM etc). Does not use assembly code.

Arduino-Debug (https://github.com/mikaelpatel/Arduino-Debug)
A pure on target debugger compiled directly into the sketch.

I have also done some work on designing APIs that are multi-tasking ready i.e. add support for device drivers to share resources such as SPI, I2C, etc. With a Scheduler the Arduino core(s) will have to move (slowly) towards a more traditional RTOS (or micro-kernel). The positive side effect is that this will improve integration of libraries (i.e. reduce conflicts and improve overall quality). For details see SPI, TWI, etc in Cosa (https://github.com/mikaelpatel/Cosa).

I could make time to contribute to official projects if needed.

Cheers! Mikael (https://www.linkedin.com/in/mikaelpatel)

Jacob Rosenthal

unread,
Jun 7, 2017, 4:36:03 PM6/7/17
to Mikael Patel, Thibaut VIARD, Massimo Banzi, Arduino Developers
This is a very exciting roadmap. Thanks for the update and invitation Massimo.

Aniruddha Patel

unread,
Jun 7, 2017, 4:42:44 PM6/7/17
to Jacob Rosenthal, Mikael Patel, Thibaut VIARD, Massimo Banzi, Arduino Developers
These are really exciting things and will take Arduino to the next level. Thanks for the updates Massimo.

With best regards,

Aniruddha Patel

Ralph Doncaster

unread,
Jun 7, 2017, 4:47:43 PM6/7/17
to Aniruddha Patel, Mikael Patel, Thibaut VIARD, Massimo Banzi, Jacob Rosenthal, Arduino Developers
I did not ask to join this list, and while technical discussions of MCU developent may be of interest to me, ass kissing messages are as annoying as spam.

Matthew Ford

unread,
Jun 7, 2017, 5:17:18 PM6/7/17
to Ralph Doncaster, Aniruddha Patel, Mikael Patel, Thibaut VIARD, Massimo Banzi, Jacob Rosenthal, Arduino Developers
That comment was uncalled.
Please keep this list polite and civil.


On 8/06/2017 6:47 AM, Ralph Doncaster wrote:

Ralph Doncaster

unread,
Jun 7, 2017, 5:25:41 PM6/7/17
to matthe...@forward.com.au, Aniruddha Patel, Mikael Patel, Thibaut VIARD, Massimo Banzi, Jacob Rosenthal, Arduino Developers
Maybe you can't recognize ass kissing when you see it, but I can.
Respect is earned. And since I didn't ask to be on this list, do you
really expect me to follow your prudish desires on decorum?

Matthew Ford

unread,
Jun 7, 2017, 5:34:23 PM6/7/17
to Ralph Doncaster, Aniruddha Patel, Mikael Patel, Thibaut VIARD, Massimo Banzi, Jacob Rosenthal, Arduino Developers
Please see if you can remove yourself from this list.

In the mean time I can filter your messages to junk.

Alexander Brevig

unread,
Jun 7, 2017, 5:35:44 PM6/7/17
to Ralph Doncaster, Mikael Patel, Thibaut VIARD, Massimo Banzi, Jacob Rosenthal, Aniruddha Patel, matthe...@forward.com.au, Arduino Developers
While I understand the desire to keep this civil I'm an old time contributor and I do find it odd that six years after I tried hard to contribute you're all so perfectly appreciative? AlphaBeta will be in most of those Playground logs. You are half a century late to get my help, I wish you all the luck. I learned what a pointer really is dissecting the Wiring framework and I'm grateful for you to expose me to it.

Phillip Stevens

unread,
Jun 7, 2017, 6:00:51 PM6/7/17
to Massimo Banzi, Arduino Developers

Scheduler: A task scheduler to achieve some level multitasking on Arduino. There is a lot of code out there but , unfortunately, it’s all quite hard to understand unless you’re an expert. Let’s see if we can build something that can be used by most of the Arduino users.

I'd like to suggest that rather than creating a new scheduler (with all of the workload associated with testing and maintaining this across all of the Arduino hardware platforms) that there is a perfectly good scheduler already available as FreeRTOS.

There are several advantages in using FreeRTOS as the scheduler for Arduino...

1. Tested and working on all of the MCU that are used in Arduino.
2. Has appropriate licencing to be incorporated, without tainting Arduino code.
3. FreeRTOS the most popular scheduler post on Arduino Create, and the topic of the #10th most popular post overall (60k+ views).
4. Installs seamlessly as a library on AVR, and would be similar for other platforms (if hardware timers are available).
5. Is very lightweight (essentially just 3 C files), and doesn't drag in unnecessary features that would conflict with the existing environment.
6. Is as commonly used as Android (2013), so allows Arduino developers skill reuse should they move on.
7. Directly supports low power and tick-less applications.
8. Supports fully static stack and heap memory allocations, or fully dynamic (using malloc). The choice is there.

Or, you could just write your own scheduler implementation from scratch. That would be more fun.

(Disclaimer - I have no association with FreeRTOS or its Author Richard Barrry).

Cheers.

bob

unread,
Jun 7, 2017, 6:16:37 PM6/7/17
to Developers, m.b...@bcmi-labs.cc
I tried FreeRTOS on an ARM project, nut it rapdily ate up RAM so I abandoned it and wrote my own, much lighter OS.

The FreeRTOS license has the following clause :

Clause 2: FreeRTOS may not be used for any competitive or comparative purpose, including the publication of any form of run time or compile time metric, without the express permission of Real Time Engineers Ltd. (this is the norm within the industry and is intended to ensure information accuracy).

For me, that is not an acceptable restriction, I would even say it makes it non-Open Source according to GPL principles.

https://www.gnu.org/philosophy/free-sw.en.html

"The freedom to run the program as you wish, for any purpose (freedom 0)."

Paul Stoffregen

unread,
Jun 7, 2017, 6:23:15 PM6/7/17
to devel...@arduino.cc
On 06/07/2017 02:25 PM, Ralph Doncaster wrote:
> And since I didn't ask to be on this list

You posted 36 messages to this mail list on 8 distinct threads between
April 2014 to February 2015. In several messages on Feb 25-26, 2015 you
seemed particularly upset about the differing SPI library API for chip
select pins on Arduino Due.

Recently this list has migrated a couple times to new servers. Back
then it was hosted by Google Groups. My guess is you likely changed a
Google Groups setting to no longer received email notifications, but
very likely remained subscribed to the group. That sort of
Google-specific setting was probably lost during the recent migration to
a different service.

In any case, the message history clearly shows you did indeed ask to be
on this list 3 years ago and you participated in several conversations.

> Respect is earned.

Indeed it is. Massimo Banzi has earned my respect, and that of many
others. He has worked hard, often under very difficult circumstances,
to do good for others.

You on the other hand, haven't. Looking through some of the 36 messages
you wrote, I see little of value, mostly just complaining. Your final 2
messages in February 2015 were similarly hostile to the ones you're
written today.

You really should just unsubscribe.


Thibaut VIARD

unread,
Jun 7, 2017, 6:24:08 PM6/7/17
to bob, m.b...@bcmi-labs.cc, devel...@arduino.cc
+1 
FreeRTOS should be one of the worse option ever.


--

Thomas Roell

unread,
Jun 7, 2017, 6:33:30 PM6/7/17
to Phillip Stevens, Massimo Banzi, Arduino Developers
There so many nuances to comment on. However first on the scheduler / RTOS.

For our STM32L4 core we urgently needed to add an RTOS, for handling internal things, like USB/MSC reading/writeing to the SDCARD while not blocking the main loop() when the SDCARD decides to throw a fit and wait.

What I found talking to folks about RTOS usage, most of them raised the issue of debugability. Stack overflow and such. Even seasoned developers all identified the same core issue. So whatever and however things happen, Debug and Scheduler need to go hand in hand.

Next the idea of of suggesting to use RTOS A or RTOS B. I think that is fundamentally the wrong approach. First it should be identified what the target audience needs minimally to get the maximum utility. 

The best integration of RTOS and Arduino style API I have seen comes from here:  https://pros.cs.purdue.edu

Only the key concepts are left, a "Task", a "Semaphore" and a "Mutex". How the implementation is done behind the scenes is then a different question. Just because RTOS xyz is popular or well known does not mean it's appropriate for the task at hand.

IMHO there are 4 key things that need to be sorted out for a "Scheduler":

(1) Power management. The "idle-task" or "idle-function" typically puts the MCU to sleep. So there is room to innovate.

(2) A RTC facility so that timing can be provided efficiently independent of "millis()" and "micros()", which are undesireable for low power modes. This RTC facility needs to provide periodic virtual timers, absolute and relative. That allows implementation of periodic tasks/jobs.

(3) The typical core objects, Task/Thread, Semaphore, Mutex and EventGroup.

(4) Expose atomics (uint32_t  atomic_uadd(&uint32_t, uint32_t), which serve as more efficient ISR -> TASK communication mechanism.

Anyway, another important issue is whether the target is AVR or more geared towards ARM/X86. Given the increased popularity of the SAMD platform it would seem unwise to limit functionality there, just to be compatible with AVR.

- Thomas

--

Ralph Doncaster

unread,
Jun 7, 2017, 6:36:42 PM6/7/17
to Paul Stoffregen, Arduino Developers
I joined the google group, and never requested or consented to
receiving email copies of the messages.
Despite some technical skill, you seem rather emotional, to the point
of imputing non-existent emotions to my behavior. Unlike you fickle
neurotypicals that are slaves to your limbic system, I maintain a much
more stoic and analytical demeanor. Not giving a fuck who takes
offence to my comments is much different than being angry.
I respect people like Hernando Barragán, but not people like Marchese
Banzi. But I'm not surprised that another american has low standards
for who they respect; Trump is a perfect example of that.
> --
> You received this message because you are subscribed to the Google Groups
> "Developers" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to developers+...@arduino.cc.
>

Gavin Stevens

unread,
Jun 7, 2017, 6:38:34 PM6/7/17
to Ralph Doncaster, Paul Stoffregen, Arduino Developers
Can we save the Trump bashing for CNN, not for the Arduino Dev forum ?

> email to developers+unsubscribe@arduino.cc.

>

--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+unsubscribe@arduino.cc.




--
Gavin Stevens
MCPS, MCSD, MCAD, MCNPS, MCTS
Gavin....@GMail.com
(602) 405-4799

Thomas Roell

unread,
Jun 7, 2017, 6:44:32 PM6/7/17
to Ralph Doncaster, Paul Stoffregen, Arduino Developers
Ralph,

mind just taking your anger out somewhere else ? It's rather counter productive and impolite to derail a productive discussion among adults by your preadolescencent behavior. I am really more interested in the constructive feedback that other people can provide here.

- Thomas

> email to developers+unsubscribe@arduino.cc.

>

--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+unsubscribe@arduino.cc.


Clóvis Fritzen

unread,
Jun 7, 2017, 6:54:58 PM6/7/17
to Massimo Banzi, Arduino Developers
Hi Mr. Banzi, Hi you all,

Interesting roadmap, it shows how much Arduino has grown in the past few years!. Regarding the news: I will be happy to help test the pre-processor!.
   Regarding where Arduino is going: The increasing processing power that can be stuffed in a silicon piece is a bit overwhelming to me in the sense of "how is this processor executing this or that task" - I think there are a bit too much abstraction layers to the Arduino project!. 
   While I understand that Arduino is here to be inclusive (and allow everyone anywhere to blink a LED using a single line of code) I would like to see more development of the "basics" (and processor-dependent) side: how to quickly toggle a pin (not digitalWrite-ing), how to implement USB from the ground-up, this kinds of things. 
   I know that to you (community) it means diverting from all those wonderful and comfy "abstraction layers" but I am sure that it can bring a lot more people to the dark side (HARDWARE) instead of a bunch of API users (not that API's are a bad thing, I did not say that hahaha).
   Talking about hardware, here is an idea: why don't Arduino ACTIVELY license board fabrication (assembly) in various countries around the world? I mean: charge a small-ish fee for every board produced (say 3-5%) and let local people sell "original" board to everybody!. I am located in Brazil and would (really) love to buy Arduino originals instead of $4 UNO's made by Chinese slaves. But of course that today I will not pay US$25 or EUR25 for an original. I thing everyone can benefit and profit from this business model (.CC, the local manufacturers, and most importantly the end user - me).  

Clovis Fritzen +55(47) 99204-6606

Matthew Ford

unread,
Jun 7, 2017, 7:03:47 PM6/7/17
to Thomas Roell, Phillip Stevens, Massimo Banzi, Arduino Developers
On 8/06/2017 8:33 AM, Thomas Roell wrote:
Only the key concepts are left, a "Task", a "Semaphore" and a "Mutex". How the implementation is done behind the scenes is then a different question. Just because RTOS xyz is popular or well known does not mean it's appropriate for the task at hand.

An alternative approach, designed for school kids, is used by micro:bit.  It is 'fibers'   (see https://lancaster-university.github.io/microbit-docs/concepts/#concurrency  and http://www.forward.com.au/pfod/microbit/gettingStarted.html)

Locks and semaphores (and interrupts) are a trap for young (and old) players.  micro:bit avoids them by using message passing and non-preemptive scheduling instead.  Much easier and more robust for programmers.

A non-preemptive scheduler is closer to what the current design of an arduino sketch is.  Just one thing happens at a time.

From http://www.forward.com.au/pfod/microbit/gettingStarted.html

Fibers (another sort of Thread)

Lancaster University's C++ support implements a lightweight thread model called fibers. The multi-tasking is co-operative. That means while one part of your program is running other parts are not. Programs that do more than one thing at a time are called concurrent programs. The micro:bit C++ runtime provides two ways you can achieve concurrency in your programs:

The multi-tasking scheduler is a type of non-preemptive scheduler. This means that the runtime will never take control away from your program - it will wait for it to make a call to a runtime function that is blocking. (All the functions that are blocking are listed as such in their documentation.) This means you do NOT need semaphores to guard lock test and set. If you need to guard a method from being run by more then one fiber you can just use a simple bool value, say for example bool status, and test it on entry and return if some other fiber has set it. See below for how to queue access to a resource. ....



Matthew Ford

unread,
Jun 7, 2017, 7:34:59 PM6/7/17
to Thomas Roell, devel...@arduino.cc

Hi Thomas,

> My USB/MSC requirement is such a good case

micro:bit handles USB and IMU OK.  I believe it does it with interrupts and posts messages.  For a example see my implementation of a serial connection to micro:bit BLE in the library
http://www.forward.com.au/pfod/pfodParserLibraries/pfodParserMicroBit.zip  
and for a  complete example see the project
http://www.forward.com.au/pfod/microbit/androidControl.html


On 8/06/2017 9:19 AM, Thomas Roell wrote:
Matthew,

thanx about the pointer to the fibers. I need to recheck those links you included.

Interrupts and bad effects. For the STM32L4 I ended up using the PendSV logic a lot (ARM Cortex). Essentially there is a callback queue (or event queue if you want), where the real ISR puts a callback plus some arguments. That conceptually is really a 2nd execution priority over the normal "loop()". The callbacks are really one-shot tasks, which is often what the name "fiber" is used for. Overall it turned out that users having access directly to ISRs is not a good idea, as most of them will screw up a carefull layer out priority scheme, but putting in a "delay(1000)" in the highest priority ISR ..

In general I'd argue that you need pre-emptive multitasking. My USB/MSC requirement is such a good case. The USB ISR drives the USB/MSC logic, which then forwards the the SCSI handling to such a PendSV handler. But the reading/writing to the medium should be left to a task, as it might block, and may have to deal with concurrent access to a SPI (this is where mutexes come in handy). Granted, this is a system layer requirement, and may or may not be relevant to a real user scenario in terms of API.

A good example for wanting a preemptive scheduler is when you do things like reading/processing IMU data. In that case you want your main task interrupted and the higher priority processing being done.  

- Thomas

Paul Stoffregen

unread,
Jun 7, 2017, 7:42:52 PM6/7/17
to devel...@arduino.cc
Something similar to the Microbit event system could also really help Arduino.

Currently Arduino has a mix of different events.  The serial devices have serialEvent() using weak symbols.  The USB host library does events too, using a Usb.Task() function in some versions.  The MIDI library has events for reception of MIDI messages.  Lack of a common API means each of these has to craft its own, and higher level software can't (easily) be built on top of the events.

If events could be serviced from delay() or yield(), perhaps much of the need for concurrency could be solved with a much simpler & intuitive system that avoids the complex issues of threads.
--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.


Thomas Roell

unread,
Jun 7, 2017, 8:02:40 PM6/7/17
to matthe...@forward.com.au, devel...@arduino.cc
micro:bit does not do USB/MSC. Simple things like USB/CDC can easily be handled via interrupts, event queues and perhaps messages.

Fibers as in micro:bit are really traditional tasks with preemption disabled. The source really has all the complexity of a normal preemptive scheduler (run queue, wait queue, sleep queue, a context switcher [CortexContextSwitch.s.gcc]. I might be missing something (haven't seen how stack allocation is done, similar to restricted tasks in uITRON ?)

The message bus is interesting. One grief I have with it right away is that you cannot listen to a combination of different events. Like "if there is a ACCELEROMETER event AND a COMPARE event". Granted you could implement that begin nested events, but that seems a tad convoluted.

BTW, Sun's OpenWindows code had a lot of groundbreaking concepts with non-realtime event distribution. Overall a very interesting concept.

One thing in general seems to be undesireable. There is a lot of dynamic memory allocation in the runtime. That's something a typical embedded system would want to avoid. Every creation of a listener (i.e. event registration) does a "new". 

- Thomas 

Thomas Roell

unread,
Jun 7, 2017, 8:09:49 PM6/7/17
to Paul Stoffregen, Arduino Developers
Paul,

serialEvents() is a rather bad example. Actually I just ran into this today with somebody who used serialEvents() to service a BLE UART bridge and a GPS. His "loop()" had a to low frequency, so he randomly lost data and was wondering why. So the interactivity of such a system depends really a lot upon whether you give up control quite frequently. 

Interesting though is that OSEK/Autosar defines tasks which are preemptable and non preemptable, and they document rather meticulously which APIs will do reschduling and which won't. uITRON allows you to disable all scheduling even for those APIs which normally would reschedule. OSEK/Autosar manage this schedule lock via a resouce (mutex). So the point is that good documentation is needed to avoid unexpected things.

Even a scheme that only uses delay() / yield() still needs to deal with stack corruption, which is the biggest problem ...

- Thomas

To unsubscribe from this group and stop receiving emails from it, send an email to developers+unsubscribe@arduino.cc.


--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+unsubscribe@arduino.cc.

John Plocher

unread,
Jun 8, 2017, 2:06:44 PM6/8/17
to Arduino Developers
While the discussion is still in the blue sky stage, it may be worthwhile looking at the design philosophy behind GCD, even though the actual implementation may well be overkill :-)

GCD's task queue model is amazingly powerful without explicitly exposing the complexities of TLS, mutexes and locks; something similar on the 'duino platform has the potential to cut thru the "comp sci" weeds that plague the user model of many RTOS projects..


  -John


Paul Stoffregen

unread,
Jun 8, 2017, 3:00:02 PM6/8/17
to devel...@arduino.cc
On 06/07/2017 05:09 PM, Thomas Roell wrote:
> serialEvents() is a rather bad example. Actually I just ran into this
> today with somebody who used serialEvents() to service a BLE UART
> bridge and a GPS. His "loop()" had a to low frequency, so he randomly
> lost data and was wondering why. So the interactivity of such a system
> depends really a lot upon whether you give up control quite frequently.

Indeed the current implementation leaves much to be desired.

If anything, I would argue this shows serialEvent() is a very good
example of an API that intuitively fits people's mental model and
expectations.

You raised many good implementation concerns, impressively packed into
just 2 short messages. These are critically important details for any
concurrency features. I'm glad you really understand these details and
you're thinking of them. We need much more of that around here! Many
details, I believe, are "only" technical challenges to solve. Some are
tough trade-offs to be made. Others, especially memory allocation
issues, do require thoughtful API design.

But human factors are by far the most important consideration for any
Arduino API. My main point here is that serialEvent() and similar event
processing really is intuitive for beginners. It's not a solution for
all concurrency needs, but for the places were events make sense, a
better implementation with a carefully considered API could really
benefit everyone.

Thomas Roell

unread,
Jun 9, 2017, 1:07:42 PM6/9/17
to matthe...@forward.com.au, Phillip Stevens, Massimo Banzi, Arduino Developers
All right, did a lot of research about this type of OS. There are multiple variants of the same theme, TinyOS -> Contiki -> OpenSwarm. The most interesting one is to allow some event handlers preempt the cooperatively scheduled threads to keep interactivity for low latency async IO. The implementation in micro:bit is abysmally bad (lots of O(n) or even O(n^2) complexity), it make more sense to stick at a abstract level looking at the concept.

Now there are two other things that I am concerned about with that model:

(1) Contiki got more or less forked into RIOTOS, where the protothreads have been replaced by a real full preemptive scheduler. 

(2) MBED OS moved from their MINAR event based system back again to a real full preemptive scheduler.


I have not found any good discussion out there as to why the move had been made in either case, i.e. there is no good account what problems specifically drove the decision process.

Another interesting RTOS morphing occurred over at Zypher. This RTOS initially started out as something that supported "Fibers" (one shot tasks without a private stack), and "Threads" (well, classic tasks with a private stack), nano-kernel/micro-kernel split, and now morphed into the class "Threads" preemptive scheduling model.


The only solid piece of information was that some cryptographic algorithms were taking too much time for a single shot thread model ... 


So is there something besides theoretical aspects behind the different models that tilts usability into one direction more ?

- Thomas





On Wed, Jun 7, 2017 at 5:03 PM, Matthew Ford <Matthe...@forward.com.au> wrote:

Carmine Spizuoco

unread,
Jun 9, 2017, 1:35:14 PM6/9/17
to Thomas Roell, Mikael Patel, Phillip Stevens, Massimo Banzi, Arduino Developers
Hi All,

building a middleware that manages the different libraries on the different hardware available I think is an ambitious and wonderful road. 
We talk about Hardware Abstraction Layer someone who manages resources at platform variation and is invisible to the end user more than just a IDE.

INFRASTRUCTURE
Develop Machine : OSx Sierra MacbookPro 
Arduino Device  : Arduino YUN


About Arduino-builder: 
  I've compiled the examples by “GO”, in test folder and works; but not able to run.
./arduino-builder -fqbn 'Arduino Yún' -hardware? -tools?  sketch.ino
Waiting for more documentation on a official page.


About Scheduling  and dubuggung I looked at Mikael Patel's code:

Work on my infrastructure, at first look. 
I tested a little bit SchedulerDemo, SchedulerEvent and work.
I tested a little bit SchedulerQueue, SchedulerSemaphore, not works for now, but i think some trouble in path hierarchy of include file, or yeld() function;

I think that for now is good starting point for understand more about question of Scheduling, and what , before to move in RTOS or other dependencies.

I need of more study but could introduce a priority on interrupt help us on this question?


Work on my infrastructure, at first look. 
Could be a starting point for create a UI interface, and more,  Openframworks, could be used for develop the graphic side.



In respect of collaboration
Thanks for sharing.






Carmine Spizuoco
Skype: Carmine.Spizuoco
Cell: 0034 640 20 43 52





Il giorno 08 giu 2017, alle ore 00:33, Thomas Roell <grumpyo...@gmail.com> ha scritto:

RTOS

Matthew Ford

unread,
Jun 9, 2017, 9:26:22 PM6/9/17
to Carmine Spizuoco, devel...@arduino.cc
Hi Carmine,
Can we have non-blocking reads wrapped up in a library
So the users don't have to remember to insert the yield.

// from  https://github.com/mikaelpatel/Arduino-Scheduler/blob/master/examples/SchedulerDemo/SchedulerDemo.ino
  while ((c = Serial.read()) != '\n') {
    if (c > 0)
      *bp++ = c;
    else {
      yields += 1;
      yield();
    }
  }

combining that with message passing via the Channels would give something like the micro:bit fibers/msg

I suppose what I am suggesting is that the scheduling / multi-threading be very distinct to the user.
The https://github.com/mikaelpatel/Arduino-Scheduler code, while appealing in that is re-uses setup() loop() method names
(at least in the examples),  does not make it clear in the loop that you are running multi-threaded. 

Also hide the low level mutex.wait() (Semaphore) under a waitOn msg and hide mutex.signal() under postMsg  (ak micro:bit)
This really just unifying the idea of sending messages

Finally the Serial.print  needs to be replace with a auto yielding wrapper.
When you think about this some more you see that it needs to be based on message passing, in general, otherwise you will get intermixed output.
--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.


Carmine Spizuoco

unread,
Jun 12, 2017, 4:03:13 AM6/12/17
to matthe...@forward.com.au, devel...@arduino.cc
Hi Matthew,

Thanks for response, i’ve grabbed the concept.

For do another step, we think about Scheduler like:

Multithreading Non-blocking Event Driven System based on message passing.

Is this right ?

C.


Carmine Spizuoco
Skype: Carmine.Spizuoco
Cell: 0034 640 20 43 52

Matthew Ford

unread,
Jun 12, 2017, 6:57:23 AM6/12/17
to Carmine Spizuoco, devel...@arduino.cc

Actually

Multithreading Non-preemptive Event Driven System based on message passing.

seems better to me.

You really want your longer running threads to block so that other threads get a chance to run.  For example delay() puts the current thread to sleep to be woken up later and lets other threads run.

Automatic low power sleep mode.

An interesting aside. If all threads are sleeping/blocked, then you can put the processor into low power mode automatically.  This removes the need for special processor specific sleep calls from the user code.  The microprocessor specifics are hidden from the user in the scheduler code.

I believe micro:bit does this.  It draws <2mA while running and connected via BLE and actively sending and receiving msgs.

Non-preemptive threads, on a single processor, removes the need for the user to use volatile (assuming they are not writing interrupt routines)

But we should consider how we will use this concept in multi-core processors.  Ideally the threads should run on any available core and the threading/scheduling library should look after volatile/synchronize as necessary.   The ESP32 already has 2 processors and in the near future Arduino boards will have more. 

Any design should take that into account.

all the best

matthew

Matthew Ford

unread,
Jun 12, 2017, 7:07:05 AM6/12/17
to Carmine Spizuoco, devel...@arduino.cc
On 12/06/2017 6:03 PM, Carmine Spizuoco wrote:
> Can we have non-blocking reads wrapped up in a library
> So the users don't have to remember to insert the yield.
This may have been confusing.

By non-blocking reads I meant, a thread to process a message from the
serial port.
No explicit yield necessary. The thread's method just ends after
handling the available serial input.
No while either. More data enters at the top of the thread method via a
msg posted by the serial port.

Thomas Roell

unread,
Jun 12, 2017, 8:32:08 AM6/12/17
to matthe...@forward.com.au, Carmine Spizuoco, devel...@arduino.cc
Non-preemptive threads means that at every moment only one thread is running. Hence it can only support one CPU core.

Any kind of thread based system can detect when there is no activity and then select a proper low power state.

Any thread based system needs to allocate a stack for threads that are blocking (a "delay()" is a blocking operation), so that another thread can continue. A classic event system uses only one-shot threads, meaning they cannot block. In practice that does not work well as you have threads that are running a long time and impact responsibility of a system if they cannot "yield()".

An event based system needs to queue up the events to dispatch them later. The size of the queue depends upon the amount of data each event carries along (if there is a payload). Some systems do queuing implicitly by queuing thread invocations, most of them do maintain one or more global event queues.

Most event based systems use a publish/subscribe model. The publisher is the source of an event essentially maintains the data-struct that tracks the active subscribers. A event handler or thread that blocks on an event implicitly or explicitly has to subscribe. If a non-publisher based model is used, then one has to keep global lists of event waiting entities, where the insert/lookup are at best O(log(n)), while with publish/subscribe this cost is payed only once per subscribe, rather than once per event-send. A non-subscription based system always has the problem of lost events, where between accepting one event and then waiting again for the next event all events that pop up inbetween are lost.

As pointed out before, classic event systems use something that now are called "fibers" or "oneshot-threads", which run from begin to end without being preempted once started. Those systems are interesting as all fibers can share a common stack. The event queue in this scenario is then really a queue of ready to run fibers, and each event really kicks off a separate fiber. However if you allow blocking in this model, you can end up with multiple active fibers for the same event. As pointed out above such a system then will require some sort of stack allocation at some point of time, perhaps lazy stack allocation. But at the end of the day it means unbound, unthrottled memory consumption.

micro:bit does look appealing on first glance. But it uses a fiber model that allows blocking. It does implement that via lazy stack allocation, which will lead to unbound memory consumption. Because the system (or better said the implementation) does not use a publish model, each event send has a O(n) complexity, whereby "n" is the number of waiting fibers. So essentially the system does not scale with the number of active events, and it will crash due to OOM due to fiber flooding if too many events are send at one point.

If event-based is appealing due to the underlying cooperative scheduling approach, which mostly avoids having event-group/semaphore/mutex objects involved, then I'd recommend looking at event based frameworks that solve the theoretical problems properly.

It should be also mentioned that a simple cooperative schedule has exposes a simple thread-sleep() / thread-wakeup() API can be used to layer an event-framework ontop of it. 

- Thomas

- Thomas




C.


To unsubscribe from this group and stop receiving emails from it, send an email to developers+unsubscribe@arduino.cc.



--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+unsubscribe@arduino.cc.

--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+unsubscribe@arduino.cc.

Thomas Roell

unread,
Jun 12, 2017, 8:44:20 AM6/12/17
to matthe...@forward.com.au, Carmine Spizuoco, devel...@arduino.cc
All io-operations that block can be wrapped transparently to "yield()". But libraries like "Wire" and "Uart" have to be perhaps rewritten to take advantage of that.

Suppose your I2C code is DMA/ISR driver and could send a I2C_TRANSFER_DONE event. Then in Wire.endTransmission, you'd simply kick off the operation and then have the thread yield() by waiting for the I2C_TRANSFER_DONE event.

Reads from CDC/Uart are non-blocking, except if you go throu the "Stream" class which uses a timeout. Not sure how to convert that ...

Anyway, with the Wire example above there is some detail that is non-intuitive. Since the Wire.endTransmission() does the implied yield, there is a chance that another thread wants to do a Wire.beginTransmission() while a transfer is active in the background. 

So you end up needing locks, either only under the hood, or exposed the the user as well. 

Ok, let me say that again, if you allow blocking in an event based model, you end up needing locks ...

- Thomas 




--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+unsubscribe@arduino.cc.


Matthew Ford

unread,
Jun 12, 2017, 9:19:58 AM6/12/17
to Thomas Roell, Carmine Spizuoco, devel...@arduino.cc
On 12/06/2017 10:32 PM, Thomas Roell wrote:
> Non-preemptive threads means that at every moment only one thread is
> running. Hence it can only support one CPU core.

My definition of non-preemptive only means a running thread is not
interrupted and does not stop unless it chooses to (i.e. delay,
blocking operation or end of method)

No reason multiple such threads cannot run on multiple cores at the same
time.

Consider a simple worker thread that is passed some data via message and
posts another message with the results and uses only local, stack,variables.

What multiple cores does mean is that later messages may be acted on
before some earlier message has finished being processed.

The implications of this is an example of what needs to be considered
for multi-core use.

all the best
matthew

Thomas Roell

unread,
Jun 12, 2017, 9:38:02 AM6/12/17
to matthe...@forward.com.au, Carmine Spizuoco, devel...@arduino.cc
If you allow 2 threads executing in parallel on 2 different CPU codes, you are preemptive by definition. You need locks and all the other synchronization primitives, which you tried to avoid by using cooperative schemduling.

Suppose as an example having 2 threads executing at the same time on 2 different CPUs, and both doing malloc() at the same time. That will not work unless you have locks in place.

The attractiveness of cooperative scheduling is that you don't need to change a whole lot in your source base and add locks all over the place. As soon as you have global data or globally shared resources there is no way around that. 

- Thomas

vbextreme vbextreme

unread,
Jun 12, 2017, 3:18:31 PM6/12/17
to Thomas Roell, matthe...@forward.com.au, Carmine Spizuoco, devel...@arduino.cc
Before talking about the scheduler it would be a good idea to fix Arduino's structure.
The years go by and the project becomes ever bigger and more complex, being able to stay simple for novices and valid for advanced users is not simple.

I think Arduino has to move to become an operating system, but for current modelling the only kernel that would fit the current Arduino structure without having to make substantial changes is the exokernel, that kernel is nothing more than a library where the application accesses to do its job.
Exokernel should only export HAL, scheduler and IPC (also mandatory for cooperative schedulers).
In this way, creating an Arduino core would be much simpler.
The exokernel should be written entirely in C, so you can run on most MCUs.

The second step would be to create device drivers (serial, i2c, etc.) without direct accessing the hardware, but always passing through the HAL of the exokernel, in this mode you don't have a duplicate the same driver on each core as it is now.
These device driver can be writen in C/C++/RUST  without any kind of problem.

Always remembering that there are a lot of tutorials, examples, work code running on the current Arduino model

Have a good life

Matthew Ford

unread,
Jun 12, 2017, 10:58:56 PM6/12/17
to vbextreme vbextreme, Thomas Roell, Carmine Spizuoco, devel...@arduino.cc
It seems to me that most RTOS projects concentrate on scheduling and
largely ignore data consistency.

i.e. it is left to the user to work out the locking etc.

I have a couple of suggestions to assist novice users to avoid corrupted
data with out the complication of locks, so avoiding deadlocks.

i) Non-peremptive tasks (on a single cpu) ensures data consistency
between blocking operations, without locks.

ii) static locals can be used instead of globals in a lot of cases for
better data security without locks

iii) message passing which includes data can be used to protect data in
a simple manner, from the user's point of view
The idea for passing data via msgs is that the producer calls new() and
passes that ptr with the message, BUT does not keep a copy if it.
The consumer ALWAYS frees the pointer on exit.
The consumer should be able to call a support method to find the size of
the data since the malloc() management must know this.
Of course being C the user can always shoot themselves in the foot, but
it requires extra code, i.e. explicitly saving the new() pointer in a
global variable

This should work in many cases.
The exception is where there are multiple consumers.

Question: How many commons use cases are there where there are multiple
consumers of complex data i.e. data bigger then int, (which can be
carried with the msg)?

micro:bits ManagedStrings
https://lancaster-university.github.io/microbit-docs/data-types/string/#managedstring
which are immutable would also be useful.


Thomas Roell

unread,
Jun 13, 2017, 12:49:28 AM6/13/17
to matthe...@forward.com.au, vbextreme vbextreme, Carmine Spizuoco, devel...@arduino.cc
Ad iii). The implied use of malloc for an event producer poses a problem with system generated events from the ISR level. I'd assume we'd want to have events like "SERIAL_DATA_AVAILABLE".  That also means that any kind of queueing operation needs to work without the use of malloc() (no list entries via new(), no queue resizing).

Multiple consumers are typically uses for barriers. 

Matthew Ford

unread,
Jun 13, 2017, 3:45:53 AM6/13/17
to Thomas Roell, vbextreme vbextreme, Carmine Spizuoco, devel...@arduino.cc

For Serial I was thinking of having 2 pre-allocated buffers which are never freed.  At the end of the message processing the call to "free" just marks the buffer a empty

so  receive a char,  put in buffer 1 post msg with buffer 1.

Switch to buffer 2 to hold subsequent received chars while waiting for buffer 1 to be processed and 'freed'  i.e. marked as empty

When buffer 1 is 'freed' then  post msg with buffer 2 and switch to filling buffer 1  etc

--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.

Thomas Roell

unread,
Jun 13, 2017, 8:17:01 AM6/13/17
to matthe...@forward.com.au, vbextreme vbextreme, Carmine Spizuoco, devel...@arduino.cc
Matthew,

you described the message passing process you had in mind that the producer allocates the container for the data via malloc() and the consumer would free that container again when the data has been processed via free().

Coming up for a special case for each instance when an ISR wants to be the producer of an event is not acceptable, as then the consumer needs to know about all the special cases, and where an event comes from. Even worse, each time a user wants to code a producer that is triggered via a callback to "attachInterrupt()" they need to special code that.

At the end of the day, malloc() / free() does not work for that purpose. 

What you could do is to have an event that is a tuple of { uint32_t eventID, void *data } and then let the user decide what "data" is, and how it's allocated and free, or unused. But in reality that will lead to a queue or ringbuffer type class implementation for each type of data you are passing around. So you need to supply a generic queue implementation the is preemption safe as well (as this is for the ISR producer, which cannot lock or block). In practice that is not any better for the user than having one global queue where data is copied into. 

Another solution could be to simply give up on passing around data, and just live with some "eventID" being passed around. 

In any case, if the goal is to have one producer and one consumer, in a classic RTOS this problem is solved by a queue object, where the writer is always non-blocking (ISR, Task), and the reader may be blocking/waiting (Task), or non-blocking (ISR). If the size of the data item is zero, this type of queue simple degenerates to a semaphore. So why reinvent the wheel ?

- Thomas

To unsubscribe from this group and stop receiving emails from it, send an email to developers+unsubscribe@arduino.cc.


William Westfield

unread,
Jun 13, 2017, 7:36:33 PM6/13/17
to Phillip Stevens, Massimo Banzi, Arduino Developers
>> Scheduler: A task scheduler to achieve some level multitasking on Arduino. There is a lot of code out there but , unfortunately, it’s all quite hard to understand unless you’re an expert. Let’s see if we can build something that can be used by most of the Arduino users.
>
> I'd like to suggest that rather than creating a new scheduler that there is a perfectly good scheduler already available as FreeRTOS.

I would also like to encourage use of an existing scheduler, rather than inventing something new.
Even if you take an existing OS and ignore as much of it as the Arduino core ignores avr-libc, that would probably be better than writing new code from scratch. (Does that mean we should look for an existing “microkernel” rather than an existing “OS”? Maybe.)

I’m doubtful that the “Arduino target audience” will ever understand “real multithreading.” Fortunately, the level of “multitasking” that they want to achieve more along the lines “I want to blink lights, play music, and offer a web service at the same time”, which might be easier…

The Arduino Scheduler needs to work with existing devices that already incorporate some level of operating system, whether that’s Linux on a Yun, the wireless kernel on an ESP8266, or the Nordic BTLE kernel on an Primo (or Arduino 101)?

Has anyone used the multitasking that Energia provided for the MSP432 TI board? It uses TI-RTOS, so it’s not directly useable, but I’m wondering more about the facade that they put on top of the RTOS…

The "scheduler problem" would get much easier if we decide “AVR Arduinos will not support a scheduler; 32bit CPU and 16k of RAM, minimum.” (just saying… Advanced users could still put FreeRTOS on their AVR if they wanted…)

BillW/WestfW

Thomas Roell

unread,
Jun 14, 2017, 7:47:40 AM6/14/17
to William Westfield, Phillip Stevens, Massimo Banzi, Arduino Developers
Energia is essentially just offering to run multiple "setup()" and "loop()" instances in parallel. They have some lower level examples that expose the preemptive TI-RTOS underneeth. The "task" objects use a hardcoded stack size of 2048 bytes (similar to Python, except there you can mess with the default stack size). There does not seem to be any official library, just examples of how you use the underlying TI-RTOS.

Nordic for their BLE stack has this black box called SoftDevice. It uses 2 interrupt levels for IO, and one interrupt level for deferred execution. Events are signaled back via a SoftDevice triggered interrupt. Events can be read via a single API, " sd_ble_evt_get(uint8_t *p_dest, uint16_t *p_len)". So kind of like a regular variable size queue in an RTOS without waiting. At the end of the day their approach is independent of any RTOS used underneeth.

An interesting point is that the Arduino API exposed does not need to reflect the RTOS that is used to implement that scheme. ESP8266 uses internally FreeRTOS for their TCP/IP stack. Other platforms use ChibiOS. But in both cases a simple cooperating scheduler can be exposed as a subset. Same goes for a pure event driven model. That means the functionality of the API exposed for our purposes should not be guided by what is available, but as to what the set of functionality we'd want to expose to a user is.

- Thomas 


William Westfield

unread,
Jun 15, 2017, 1:48:15 AM6/15/17
to Thomas Roell, Arduino Developers

On Jun 14, 2017, at 4:47 AM, Thomas Roell <grumpyo...@gmail.com> wrote:

> Energia is essentially just offering to run multiple "setup()" and "loop()" instances in parallel. They have some lower level examples that expose the preemptive TI-RTOS underneeth. The "task" objects use a hardcoded stack size of 2048 bytes (similar to Python, except there you can mess with the default stack size). There does not seem to be any official library, just examples of how you use the underlying TI-RTOS.

So the only thing they expose to users (other than “you can use TI-RTOS”) is the ability to have multiple setupN() and loopN() “functions”?

Has there been any indication of how that is working for the “non-technical users”? To be honest, this is pretty much the exact request that I see on the Arduino Forums - “I want to take this sketch that does X, and this other sketch that does Y (unrelated to X), and run them at the same time.”

The fear from "serious programmers” is that this would be pretty much impossible, quickly leading to all sorts of terrible problems. And yet people write and run multiple simple programs on their desktops all the time, without having to worry about locks and semaphores and so on. What needs to be done is all done “underneath” (and in an environment with much more complexity than Arduino.)

If the Energia model IS sufficient, I feel like it could be put on top of nearly any kernel, relatively easily. (If it’s not sufficient, we can explicitly reject it, which is also useful.)

BillW/WestfW

Mauro lesto

unread,
Jun 15, 2017, 2:02:15 AM6/15/17
to William Westfield, Thomas Roell, Arduino Developers

> To be honest, this is pretty much the exact request that I see on the Arduino Forums - “I want to take this sketch that does X, and this other sketch that does Y (unrelated to X), and run them at the same time.”

Quite a bit I don't follow the forum, bit normally people who make this statement what the two code speak each other, like showing the data of the sensor on a web page of using it controlling something.

And this is exactly where all the issue with synchronization come into play, issue that is not seems in the small independent program run on your PC; the PC is a complex beast with hw and sw specialized for multitasking, simulating even basic stuff on a MCU is way different and with different design challenge.

The fact that is *possible* does not make it a good idea; after all you can boot Ubuntu from an atmega.


--
You received this message because you are subscribed to the Google Groups "Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to developers+...@arduino.cc.

Thomas Roell

unread,
Jun 15, 2017, 8:33:16 AM6/15/17
to William Westfield, Arduino Developers
It's kind of tricky to say anything about it, mainly because there is not a lot of hard documentation about it.

Some observations from sifting throu the code. There is a "Task_Yield()" in the "delay()" function, which means the approach is probably similar to the cooperative scheduling we have been talking about (should mention here that in an RTOS "delay(0)" is often the "yield()" function). 

The Wire code does a lock()/unlock() in beginTransmission() / endTransmission() to establish ownership across task switches (Mutex objects). They are using thread locals to have per task buffers for Wire so you can read the buffers in one thread post Wire.requestFrom and then write in the other one (Task_getEnv() / Task_setEnv() / Task_self()).

SPI only contains blocking code, but they go throu a lot of logic to avoid conflicts with SWIs, which make single byte transfers almost impractially slow. N.b. that they don't have the beginTransaction()/endTransaction() interface yet, which could provide the place where you'd put in the basic locking.

HardwareSerial protects every write with a mutex, one shared buffer. Reads are non-blocking, so no ownership required there.


So I'd say that all of this is pretty much what we discussed here a cooperative scheduler based system needs to have. There are a couple of big shortcomings though (perhaps I simply didn't see that in the code):

- the use of mutex objects implies that only threads can access a peripheral. So no debugging output from and ISR to "Serial".

- there is no support for asynchronous operations (aka Wire.endTransfer(sendStop, callback) as discussed in another thread).

- there is no support for any way to communicate between Tasks or from ISRs to Tasks.

- there is no support for lock objects, so that a non-core library has no way of properly lock/unlock

- there is not support to create task via an API, just via the IDE (i.e. static vs. dynamic).

 
Overall pretty much of what we discussed, except that a lot of the discussion centers around how to add the pieces that are missing.


> I feel like it could be put on top of nearly any kernel, relatively easily.

Yes. That actually should be an explicit goal of any design for us. The code backing a design like this should be able to use FreeRTOS/SafeRTOS, ChibiOS, Mynewt, Zypher, ThreadX, uITRON, Contiki, RIOTOS, Nuttx, or whatever the system that Arduino runs on requires.

- Thomas

Dennis Lee Bieber

unread,
Jun 15, 2017, 11:44:30 AM6/15/17
to devel...@arduino.cc
On Wed, 14 Jun 2017 22:48:15 -0700, William Westfield
<wes...@mac.com> declaimed the following:


>The fear from "serious programmers” is that this would be pretty much impossible, quickly leading to all sorts of terrible problems. And yet people write and run multiple simple programs on their desktops all the time, without having to worry about locks and semaphores and so on. What needs to be done is all done “underneath”
(and in an environment with much more complexity than Arduino.)

Your desktop is also non-realtime pre-emptive, with an OS that sucks up
a lot of resources. For the target usage of Arduino, one should have
deterministic realtime (preemption may be permitted, but under known
conditions).

Ignoring big-iron with virtual memory and swapping disk, the one
desktop machine that I'm most familiar with for pre-emptive scheduling
would have been the Amiga -- which was barely usable with 256kB of RAM. It
had multiple priority, round-robin, preemptive scheduling, did not use
virtual memory, and no memory protection (making it easy to pass pointers
from application to file-system handler to device-driver and back --
everything in the system was built off priority double linked lists).

Back then, Macintosh and "DOS Extenders" were cooperative scheduled --
programs had to deliberately relinquish the processor so some other task
could run.

The Amiga "Exec" (kernel) only understood tasks, lists, semaphores, and
event flags (each task had a word of event bits). Device drivers were just
tasks loaded separately. By the time you got to user-space where programs
didn't have "to worry about locks and semaphores and so on" you had some
five layers of stuff running: Exec, Device drivers, File System Handlers
(device driver tasks handled physical hardware, file system handlers worked
with logical files and disks -- which is how the Amiga could issue prompts
for "insert 'XYZ' into any drive" when an application tries to open a file
on a logical volume -- the device driver would inform its file system
handler that the named volume was now mounted, and the file system handler
would inform the OS, etc.), in parallel with file system handlers is the
graphic system, above that is the command shell (AmigaDOS -- which itself
was a graphical window) in parallel with Workbench (the GUI shell).

The "shell" level is what hides all the details -- it is responsible
for creating a task when one enters the name of a program to be run. I/O
requests (which are normally blocking operations at this level) trigger SW
interrupts (System Service/Supervisor Call) in order to change to kernel
privilege levels (for systems with privilege/protection systems). Part of
the interrupt processing is to check the ready list of tasks to determine
which task to resume.

>
>If the Energia model IS sufficient, I feel like it could be put on top of nearly any kernel, relatively easily. (If it’s not sufficient, we can explicitly reject it, which is also useful.)

Note that TI has not ported the Energia scheduler to the TIVA boards,
even though TI-RTOS is supported on them via CCS, and the TIVA boards are
using fairly powerful ARM cores (Cortex M4F -- hardware floating point --
and the small one [123] has 256kB flash and 32kB RAM [that's more than
original TRS-80s with 180kB floppy and 16kB RAM, 16kB ROM*]; the bigger
ones [1294/129E] have 1MB flash and 256kB RAM)


* Every so often I wonder how much effort it would be to convert the LSDOS6
[8080] source code into ARM... Though making it have to copy from flash to
RAM to duplicate the normal running mode seems a waste]
--
Wulfraed Dennis Lee Bieber AF6VN
wlf...@ix.netcom.com HTTP://wlfraed.home.netcom.com/

Thomas Roell

unread,
Jun 15, 2017, 12:35:45 PM6/15/17
to Dennis Lee Bieber, Arduino Developers
Denis,

a big problem for the class of programmers that are the target of this system is that the majority is not skilled enough to deal with concurrency issues that typically arise from preemptively scheduled systems. If the barrier of entry is too high, the system becomes unattractive. What is even worse is that the whole Arduino API and the underlying newlib on platforms like SAMD is non-reentrant, which is a pre-requisite for proper multithreading. 

Cooperative scheduling is an escape route that offers the biggest !/$. In reality only a few instances that deal with communication peripherals need to be touched, if at all. A proper pre-emptive approach would require a massive rewrite, more like a "Arduino 2.0", than a "Arduino 1.0++". 

So while less than ideal a hybrid out of a cooperative scheduler and preemptive event callbacks seems to be the best balance. Many recent OS implementations for Wireless Sensor Nodes and other memory constraint devices, where hard realtime is not a driving requirement, are moving into this direction.

- Thomas


John Plocher

unread,
Jun 15, 2017, 1:32:35 PM6/15/17
to Thomas Roell, Dennis Lee Bieber, Arduino Developers
If threading and concurrency are somehow "too hard" for users, can we simplify the problem and make exposing them to users out of scope for now?  
There still are significant benefit to having these features available for implementors of the core system and of libraries, who can be expected to understand and handle such advanced topics...

Potential "vision" strawman:

Create an Arduino HAL that allows core and library developers to write platform independent and reusable code

IN SCOPE:

  • Provide common implementations that are usable across (a defined subset of?) 'duino compatible systems
  • Utilize RTOS/Thread/Event structures 
  • Incorporate feature support for all the features exposed on their system, with awareness of the complexities inherent with chip specific limitations (shared timers...)
  • Define a scoping/mapping mechanism to assign feature implementations to a MCU as part of the build system as opposed to putting everything into the core
    • not all systems have [I2C, WiFi, Date/Time...], if a feature isn't present, the core shouldn't leak definitions/code to confuse the sketch user
  • Safely and efficiently use multiple libraries/features in the same sketch (intra library coordination and resource sharing)
  • Safely and efficiently extend/leverage the same libraries in their own sketch code (let advanced users and in on the party)
  • Modify the Arduino Core to leverage a (set of?) RTOS-like frameworks internally 
  • Define a thread-aware core/library/device API
  • Aim for a deterministic static memory allocation baseline (no malloc() required...)

OUT OF SCOPE
  • Changing the design pattern for user's sketches ( setup() and loop() as a single threaded, blockable control flow.... )
  • Requiring users to explicitly use threads and/or locks in their sketch code
  • Adding requirements that a user's sketch - or arbitrary libraries it uses - not block the user's control flow.
  • Adopting/inventing yet another RTOS just for Arduino's own use (NIH is bad, lock in is bad...)
Proof point:
  • The result is suitable for optimized library use with a selected set of performance sensitive/complex subsystems [I2C, SPI, WiFi, BT, Serial, GPS, ...]

Dennis Lee Bieber

unread,
Jun 15, 2017, 2:55:17 PM6/15/17
to devel...@arduino.cc
On Thu, 15 Jun 2017 10:35:45 -0600, Thomas Roell
<grumpyo...@gmail.com> declaimed the
following:

>
>So while less than ideal a hybrid out of a cooperative scheduler and
>preemptive event callbacks seems to be the best balance. Many recent OS
>implementations for Wireless Sensor Nodes and other memory constraint
>devices, where hard realtime is not a driving requirement, are moving into
>this direction.
>
Yet, even after 35 years of programming, /I/ have problems every time I
try to make sense of a call-back based framework.

On the Amiga, even GUI program required the programmer to write the
event dispatch loop (all system events came in on one message port) -- a
modal dialog could be enforced by having the code that displayed the modal
dialog implement its own event loop ignoring events outside its domain).
Granted, GUI apps aren't what we are talking here.

Even the RTOS exposure (not much -- 4 years at GE Aviation, and
documentation for FreeRTOS, TI-RTOS) don't show anything that could really
be called "call-back" style. It's all priority threads (with or without
time-slicing) and predefined message queues/buffers (I/O device interrupt
handler passes bytes via queue to a SW interrupt handler which may gather
them until an EOL when it passes the buffer to the blocked read routine.
{Just a hypothetical -- I didn't have to work at that detail}

Even an asynchronous call-back event system (as seen by the user)
requires some sort of pre-emption at some stage -- if only to allow
interrupt handlers to process I/O ports.

Thomas Roell

unread,
Jun 16, 2017, 11:10:59 AM6/16/17
to John Plocher, Dennis Lee Bieber, Arduino Developers
/> If threading and concurrency are somehow "too hard" for users, can we simplify the problem and make exposing them to users out of > scope for now?  
> There still are significant benefit to having these features available for implementors of the core system and of libraries, who can be > expected to understand and handle such advanced topics...

"too hard" is relative. 


Let's argue for a moment what a library needs minimally:

(1) locks, so that a peripheral or module can own it's state across scheduling points

(2) semaphores (or some other mechanism), so that a waiting thread can be notified that async IO completed (which is needed to wrap blocking IO so that the next thread can execute while the current one is waiting).

(3) a way for a peripheral or module to allocate/maintain private per thread data

(4) a way to schedule work preempting threads, but having lower priority than interrupts (because you want to isolate that work from the main sketch).

(5) a way to schedule work at some defined point in the future, preempting threads, but having lower priority than interrupts
*

On the other hand, looking at a sketch point of view:

(1) run "setup()/loop()" and other threads concurrently (let's say a thread is more or less a function with it's own stack)

(2) avoid explicit lock requirements in user code by using a cooperative scheduler

(3) semaphores (or some other mechanism), so that a waiting thread can be notified that an ISR fired, or some other event happened


There is a lot of variation with recent RTOS designs regarding the "semaphores (or some other mechanism)". Event Flags / Event Groups, Message Queues, Event Queues, Condition Variables and so on are in common use as well. But it seems "semaphores" are the most generic mechanism that allows any kind of ISR -> ISR, ISR -> THREAD, THREAD -> TREAD and THREAD -> ISR synchronization. A nice read is this here: http://greenteapress.com/semaphores/LittleBookOfSemaphores.pdf

This is more or less what "_thread" and "threading" can do on Python. 


If the API would treat threads simply like "a function with a private stack that is started once", and thereby hiding a thread object, would that be non-intimidating enough for a entry level user ?

- Thomas

John Plocher

unread,
Jun 16, 2017, 12:03:01 PM6/16/17
to Thomas Roell, Dennis Lee Bieber, Arduino Developers

On Fri, Jun 16, 2017 at 8:10 AM, Thomas Roell <grumpyo...@gmail.com> wrote:
"too hard" is relative. 


... Which is why I put it in quotes :-)

The hard isn't really technical, it is educational, including updating all the various existing sketch example artifacts out there - a daunting task to say the least.

Subsetting the problem and solving it for core/lib devs without explicitly also changing the sketch design pattern means we can focus on the under the hood plumbing while keeping the "setup/loop" design pattern abstraction unchanged.

Certainly a future or spinoff effort could expose a new user design pattern, but cleaning up the core APIs shouldn't be dependent on a userland change happening in parallel.


Let's argue for a moment what a library needs minimally:

No argument - I tend to agree with your points, especially about the python/go/... inspired " a thread is more or less a function with it's own stack" pattern...

IFF a sketch's userland was launched by the core as you suggest above, the result would be an effectively unchanged experience from what we have today, without locking anyone out of using more advanced patterns along side or in the future.

  -John

Thomas Roell

unread,
Jun 16, 2017, 12:29:59 PM6/16/17
to John Plocher, Dennis Lee Bieber, Arduino Developers
John,

looks like the obvious has not been stated yet. 

    setup() / loop() would be a thread started by default. No observable change in behavior, no change in design pattern


So yes, a lot of work would be the "plumbing", adding locks / semaphores to do the right thing, automatically with as low overhead as possible (both runtime and memory requirement).


Your comment about python/go is interesting. Python uses explicit "Thread" objects, perhaps mainly to implement join(). Go on the other hand launches functions directly as threads. That's kind of the key API decision to make which scheme to follow.

N.b. Python has an interesting method, "threading.stack_size([size])". That sets the stack size subsequent threads are created with. If that style of API is chosen, a architecture specific default value would make it possible that the API that launches a new thread does not need to mess around with a stack size ... 

The pro argument for "Thread" objects is that you could allocate them statically (without malloc), while without "Thread" object, the stack has to be allocated at launch time.

- Thomas






Bruce Boyes

unread,
Jul 9, 2017, 6:35:51 PM7/9/17
to Massimo Banzi, Arduino Developers
Ciao Massimo, thanks for the update and for being open to input.

Documentation is something I feel strongly about. I am not a hobbyist. My small company designs hardware and writes code for commercial products expected to work in field 24/7 for 5-10 years. We have thousands of systems in the field which have achieved this and are still going. For better or worse, Arduino has taken over much of the embedded market space: even some major semiconductor vendors now release only or mainly support for Arduino libraries (Wiznet, Microchip, STM, etc) so we have to use that. Code quality, documentation, maintainability, and debugging are big concerns.

Arduino Library format: With the introduction of Arduino 1.6.x we improved the layout of the Arduino libraries to support multiple architectures, metadata and more. One of the areas that needs improvement is documentation. At the moment documentation for libraries is kept separate from the source code itself. 

I strongly encourage making the documentation in the code itself, where it belongs. You should write it while working on the code and also read it while looking at the code. If you have ever used the official Java documentation, created by javadoc, pulling tags and details from the code, you will agree. Here's an online example:the Java time package:

and the LocalDate class:

A close (relatively) OS tool to javadoc seems to be doxygen. 
We are starting to use it to document a large project with multiple libraries and some pretty complex data and hardware interfaces.

From that doxygen page ( this sounds perfect, right?):
Doxygen can also visualize the relations between the various elements by means of include dependency graphs, inheritance diagrams, and collaboration diagrams, which are all generated automatically.
You can also use doxygen for creating normal documentation (as I did for the doxygen user manual and web-site)

It is far easier to have the code and documentation in one place. At least the basic Java-like parameters, return values, etc. It's far more likely that the most important API documentation will be current if it is right there in the code. Change the code, its natural and easy to change the documentation - if it's easy and convenient to do so.

You can also link more extensive details (e.g. tutorials) from doxygen in a number of ways.

Do I have an example from our own code of which I am proud? Honestly "no" but we will soon...

A really excellent example is something we did not write, but are using extensively, @nox771's i2c_t3 library for (you guessed it) I2C on the Teensy3 modules from PJRC. 
His documentation is wonderful: it is in the github readme and also here

If all Arduino libraries were as robust and well-documented as this library, my life would be 100X easier. At the moment, for example, we are battling issues in the Ethernet and Ethernet2 libraries which we are using on our W5500/WIz850io module. Actually here is the github for test code related to that including test logs running into billions of SPI cycles.

I asked him how he generated the documentation and now I can't remember the answer. It's a great example, though. We can find out.

If there were a way to contribute documentation and libraries more easily to the Arduino ecosystem I would be happy to do so. We are making as much of ours OS as possible, at https://github.com/systronix

We are working to get a commercial system released in the next 30-60 days so right now my time is limited but after that things should be more open.

I'm sorry if some of that was a little off-topic, but the point is this:
  1. Good documentation is critical to any code, if you want it to be useable and maintainable, and to be a good example for students and beginners. And to be usable by collaborators (e.g. Linux).
  2. You must write the documentation first. Then code to that. Lather, rinse, repeat. (e.g Internet RFCs),
  3. Maintain the docs as you maintain the code. Otherwise point #1 suffers.
  4. Best if the most critical docs for using the code are actually in the code. Otherwise #3 suffers.
  5. Well documented code is well-designed code. "It is doubtful whether a man ever brings his faculties to bear with their full force on a subject until he writes upon it." -Cicero
Kind regards

Bruce Boyes


Reply all
Reply to author
Forward
0 new messages