|
| 1 | +<img src="https://content.arduino.cc/website/Arduino_logo_teal.svg" height="100" align="right" /> |
| 2 | + |
1 | 3 | `Arduino_ThreadsafeIO`
|
2 | 4 | ======================
|
3 | 5 |
|
4 | 6 | [](https://github.com/arduino-libraries/Arduino_ThreadsafeIO/actions/workflows/check-arduino.yml)
|
5 | 7 | [](https://github.com/arduino-libraries/Arduino_ThreadsafeIO/actions/workflows/compile-examples-private.yml)
|
6 | 8 | [](https://github.com/arduino-libraries/Arduino_ThreadsafeIO/actions/workflows/spell-check.yml)
|
| 9 | + |
| 10 | +This Arduino library provides thread-safe access to `Wire`, `SPI` and `Serial` which is relevant when creating multi-threaded sketches with `Arduino_Threads`. |
| 11 | + |
| 12 | +## :zap: Features |
| 13 | +### :thread: Threadsafe |
| 14 | +A key problem of multi-tasking is the **prevention of erroneous state when multiple threads share a single resource**. The following example borrowed from a typical application demonstrates the problems resulting from multiple threads sharing a single resource: |
| 15 | + |
| 16 | +Imagine a embedded system where multiple `Wire` client devices are physically connected to a single `Wire` server. Each `Wire` client device is managed by a separate software thread. Each thread polls its `Wire` client device periodically. Access to the I2C bus is managed via the `Wire` library and typically follows this pattern: |
| 17 | + |
| 18 | +```C++ |
| 19 | +/* Wire Write Access */ |
| 20 | +Wire.beginTransmission(addr); |
| 21 | +Wire.write(val); |
| 22 | +Wire.endTransmission(); |
| 23 | + |
| 24 | +/* Wire Read Access */ |
| 25 | +Wire.beginTransmission(addr); |
| 26 | +Wire.write(val); |
| 27 | +Wire.endTransmission(); |
| 28 | +Wire.requestFrom(addr, bytes) |
| 29 | +while(Wire.available()) { |
| 30 | + int val = Wire.read(); |
| 31 | +} |
| 32 | +``` |
| 33 | + |
| 34 | +Since we are using [ARM Mbed OS](https://os.mbed.com/mbed-os/) which is a [preemptive](https://en.wikipedia.org/wiki/Preemption_(computing)) [RTOS](https://en.wikipedia.org/wiki/Real-time_operating_system) for achieving multi-tasking capability and under the assumption that all threads share the same priority (which leads to a [round-robin](https://en.wikipedia.org/wiki/Round-robin_scheduling) scheduling) it can easily happen that one thread is half-way through its Wire IO access when the scheduler interrupts it and schedules the next thread which in turn starts/continues/ends its own Wire IO access. |
| 35 | + |
| 36 | +As a result this interruption by the scheduler will break Wire IO access for both devices and leave the Wire IO controller in an undefined state. :fire:. |
| 37 | + |
| 38 | +`Arduino_ThreadsafeIO` solves this problem by encapsulating a complete IO access (e.g. reading from a `Wire` client device) within a single function call which generates an IO request to be asynchronously executed by a high-priority IO thread. The high-priority IO thread is the **only** instance which actually directly communicates with physical hardware. |
| 39 | + |
| 40 | +### :zzz: Asynchronous |
| 41 | + |
| 42 | +The mechanisms implemented in this library allow any thread to dispatch an IO request asynchronously and either continue operation or [yield](https://en.wikipedia.org/wiki/Yield_(multithreading))-ing control to the next scheduled thread. All IO requests are stored in a queue and are executed within a high-priority IO thread after a context-switch. An example of this can be seen [here](examples/Threadsafe_SPI/Threadsafe_SPI.ino)). |
| 43 | + |
| 44 | +### :sparkling_heart: Convenient API |
| 45 | + |
| 46 | +Although you are free to directly manipulate IO requests and responses (e.g. [Threadsafe_Wire](examples/Threadsafe_Wire/Threadsafe_Wire.ino)) there do exist convenient `read`/`write`/`write_then_read` abstractions inspired by the [Adafruit_BusIO](https://github.com/adafruit/Adafruit_BusIO) library (e.g. [Threadsafe_Wire_BusIO](examples/Threadsafe_Wire_BusIO/Threadsafe_Wire_BusIO.ino)). |
| 47 | + |
| 48 | +## :mag_right: Resources |
| 49 | + |
| 50 | +* [How to install a library](https://www.arduino.cc/en/guide/libraries) |
| 51 | +* [Help Center](https://support.arduino.cc/) |
| 52 | +* [Forum](https://forum.arduino.cc) |
| 53 | + |
| 54 | +## :bug: Bugs & Issues |
| 55 | + |
| 56 | +If you want to report an issue with this library, you can submit it to the [issue tracker](issues) of this repository. Remember to include as much detail as you can about your hardware set-up, code and steps for reproducing the issue. Make sure you're using an original Arduino board. |
| 57 | + |
| 58 | +## :technologist: Development |
| 59 | + |
| 60 | +There are many ways to contribute: |
| 61 | + |
| 62 | +* Improve documentation and examples |
| 63 | +* Fix a bug |
| 64 | +* Test open Pull Requests |
| 65 | +* Implement a new feature |
| 66 | +* Discuss potential ways to improve this library |
| 67 | + |
| 68 | +You can submit your patches directly to this repository as Pull Requests. Please provide a detailed description of the problem you're trying to solve and make sure you test on real hardware. |
| 69 | + |
| 70 | +## :yellow_heart: Donations |
| 71 | + |
| 72 | +This open-source code is maintained by Arduino with the help of the community. We invest a considerable amount of time in testing code, optimizing it and introducing new features. Please consider [donating](https://www.arduino.cc/en/donate/) or [sponsoring](https://github.com/sponsors/arduino) to support our work, as well as [buying original Arduino boards](https://store.arduino.cc/) which is the best way to make sure our effort can continue in the long term. |
0 commit comments