joepasquariello
Well-known member
The recent thread "Thoughts on Handling Complexity" led to a discussion of cooperative multi-tasking and the use of yield(). In Arduino, yield() is an empty function defined as "weak" to allow replacement with a function that does a cooperative task switch. Here is the comment from the Arduino core:
The calls to yield() in the latest version of the Teensy cores are listed below. All are made from within while loops, waiting either for a hardware operation to complete, or a timeout to expire. If using a cooperative RTOS, calling any of these functions from within a task will result in that task yielding the CPU if the function must wait for the operation to complete. If there is no need to wait, such as being able to put some number of bytes into a TX buffer, the function will return without yielding.
I think this is the right model to maintain, so the only change I would suggest to the cores is to add yield() to analogRead() in Teensy4/analog.c, to be consistent with Teensy3/analog.c.
The TeensyDuino libraries contain many uses of yield(), too many to discuss in one thread, but I’m interested in SPI and I2C, so I’ll focus on those for now. The SPI library transfer functions currently do not call yield(), and I think they could. For I2C, the Teensy4 file WireIMXRT does call yield() while waiting. WireKinetis has timeouts, but does not call yield(), and I think it should.
/* Empty yield() hook. This function is intended to be used by library writers
* to build libraries/sketches that support cooperative threads. It's defined as
* a weak symbol and can be redefined to implement a cooperative scheduler.
*/
The calls to yield() in the latest version of the Teensy cores are listed below. All are made from within while loops, waiting either for a hardware operation to complete, or a timeout to expire. If using a cooperative RTOS, calling any of these functions from within a task will result in that task yielding the CPU if the function must wait for the operation to complete. If there is no need to wait, such as being able to put some number of bytes into a TX buffer, the function will return without yielding.
I think this is the right model to maintain, so the only change I would suggest to the cores is to add yield() to analogRead() in Teensy4/analog.c, to be consistent with Teensy3/analog.c.
The TeensyDuino libraries contain many uses of yield(), too many to discuss in one thread, but I’m interested in SPI and I2C, so I’ll focus on those for now. The SPI library transfer functions currently do not call yield(), and I think they could. For I2C, the Teensy4 file WireIMXRT does call yield() while waiting. WireKinetis has timeouts, but does not call yield(), and I think it should.
Code:
Teensy (none)
Teensy3
analog.c (2)
analogRead - wait for conversion complete
main.cpp (1)
main - after each execution of loop()
pins_teensy.c (1)
delay - wait for delay complete
serial1.c, serial2.c (4)
serial_end - wait for TX complete
serial_putchar - wait for buffer to have room (without hardware FIFO)
serial_write - wait for buffer to have room (with hardware FIFO)
serial_flush - wait for TX complete
serial3.c, serial4.c, serial5.c, serial6.c, serial6_lpuart.c (3)
serial_end - wait for TX complete
serial_putchar - wait for buffer to have room (no hardware FIFO)
serial_flush - wait for TX complete
Stream.cpp
timedRead - wait for timeout (if no data available)
timedPeek - wait for timeout (if no data available)
usb_flightsim/joystick/keyboard/midi/mtp/rawhid/seremu/serial/serial2/serial3
(generally wait for send complete or timeout on read)
Teensy4 (same as Teensy3 with the exception of analogRead)
delay.c (1)
delay - wait for delay complete
HardwareSerial.cpp (3, one class for HardwareSerial1-8)
end - wait for TX complete
flush - wait for TX complete
write_9_bit - wait for buffer to have room
main.cpp
main - after each execution of loop()
Stream.cpp
timedRead - wait for timeout (if no data available)
timedPeek - wait for timeout (if no data available)
usb_flightsim/joystick/keyboard/midi/mtp/rawhid/seremu/serial/serial2/serial3
(generally wait for send complete or timeout on read)