Yup, that works good, but still leaves the rest of the EventResponder code (like the triggering of events and that timer that get's called with every systick)when needed I simply declared my own yield()
Yup, that works good, but still leaves the rest of the EventResponder code (like the triggering of events and that timer that get's called with every systick)when needed I simply declared my own yield()
Yield only calls EventResponder.
void yield(void)
{
static uint8_t running=0;
if (!yield_active_check_flags) return; // nothing to do
if (running) return; // TODO: does this need to be atomic?
running = 1;
// USB Serial - Add hack to minimize impact...
if (yield_active_check_flags & YIELD_CHECK_USB_SERIAL) {
if (Serial.available()) serialEvent();
if (_serialEvent_default) yield_active_check_flags &= ~YIELD_CHECK_USB_SERIAL;
}
#if defined(USB_DUAL_SERIAL) || defined(USB_TRIPLE_SERIAL)
if (yield_active_check_flags & YIELD_CHECK_USB_SERIALUSB1) {
if (SerialUSB1.available()) serialEventUSB1();
if (_serialEventUSB1_default) yield_active_check_flags &= ~YIELD_CHECK_USB_SERIALUSB1;
}
#endif
#ifdef USB_TRIPLE_SERIAL
if (yield_active_check_flags & YIELD_CHECK_USB_SERIALUSB2) {
if (SerialUSB2.available()) serialEventUSB2();
if (_serialEventUSB2_default) yield_active_check_flags &= ~YIELD_CHECK_USB_SERIALUSB2;
}
#endif
// Current workaround until integrate with EventResponder.
if (yield_active_check_flags & YIELD_CHECK_HARDWARE_SERIAL) HardwareSerial::processSerialEventsList();
running = 0;
if (yield_active_check_flags & YIELD_CHECK_EVENT_RESPONDER) EventResponder::runFromYield();
#ifdef USB_TRIPLE_SERIAL
uint8_t yield_active_check_flags = YIELD_CHECK_USB_SERIAL | YIELD_CHECK_USB_SERIALUSB1 | YIELD_CHECK_USB_SERIALUSB2; // default to check USB.
extern const uint8_t _serialEventUSB2_default;
extern const uint8_t _serialEventUSB1_default;
#elif defined(USB_DUAL_SERIAL)
uint8_t yield_active_check_flags = YIELD_CHECK_USB_SERIAL | YIELD_CHECK_USB_SERIALUSB1; // default to check USB.
extern const uint8_t _serialEventUSB1_default;
[B]#else
uint8_t yield_active_check_flags = YIELD_CHECK_USB_SERIAL; // default to check USB.
#endif[/B]
extern uint8_t yield_active_check_flags;
void serialEvent()
{
Serial.print("Event!");
}
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println(yield_active_check_flags, HEX);
delay(500);
}
As said above, overriding yield() is not enough to get rid of it.In my case yield() is overridden to (only) do a cooperative task switch,
is does.so my question for Paul was whether and where the core could contain calls to yield()
Suche "yield();" (20 Treffer in 15 Dateien von 155 gesucht)
C:\Arduino\hardware\teensy\avr\cores\teensy4\delay.c (1 Treffer)
Zeile 62: yield();
C:\Arduino\hardware\teensy\avr\cores\teensy4\HardwareSerial.cpp (3 Treffer)
Zeile 235: while (transmitting_) yield(); // wait for buffered data to send
Zeile 530: while (transmitting_) yield(); // wait
Zeile 570: yield(); // wait
C:\Arduino\hardware\teensy\avr\cores\teensy4\main.cpp (1 Treffer)
Zeile 54: yield();
C:\Arduino\hardware\teensy\avr\cores\teensy4\Stream.cpp (2 Treffer)
Zeile 36: yield();
Zeile 49: yield();
C:\Arduino\hardware\teensy\avr\cores\teensy4\usb_flightsim.cpp (1 Treffer)
Zeile 766: yield();
C:\Arduino\hardware\teensy\avr\cores\teensy4\usb_joystick.c (1 Treffer)
Zeile 96: yield();
C:\Arduino\hardware\teensy\avr\cores\teensy4\usb_keyboard.c (1 Treffer)
Zeile 545: yield();
C:\Arduino\hardware\teensy\avr\cores\teensy4\usb_midi.c (1 Treffer)
Zeile 163: yield();
C:\Arduino\hardware\teensy\avr\cores\teensy4\usb_mouse.c (1 Treffer)
Zeile 160: yield();
C:\Arduino\hardware\teensy\avr\cores\teensy4\usb_mtp.c (2 Treffer)
Zeile 138: yield();
Zeile 176: yield();
C:\Arduino\hardware\teensy\avr\cores\teensy4\usb_rawhid.c (2 Treffer)
Zeile 110: yield();
Zeile 135: yield();
C:\Arduino\hardware\teensy\avr\cores\teensy4\usb_seremu.c (1 Treffer)
Zeile 277: yield();
C:\Arduino\hardware\teensy\avr\cores\teensy4\usb_serial.c (1 Treffer)
Zeile 362: yield();
C:\Arduino\hardware\teensy\avr\cores\teensy4\usb_serial2.c (1 Treffer)
Zeile 344: yield();
C:\Arduino\hardware\teensy\avr\cores\teensy4\usb_serial3.c (1 Treffer)
Zeile 363: yield();
so my question for Paul was whether and where the core could contain calls to yield() to allow for that purpose.
I don't intend to try to mix the use of EventResponder and RTOS.
Would be fun to see a version of TeensyThreads set to be purely co-op multitasking. No timing swapping and interrupt overhead and spawned threads act like little loop()'s that run until they get bored or stuck. Though that wouldn't help on dual core without accounting for that.
years ago, I played with cooperative multitasking
https://github.com/WMXZ-EU/wmxzCore/tree/master/examples/testScheduler
Idea was to have audio processing running a lower priorities than acquisition isr.
It worked and only requirement was that sum of processing tasks where in average faster than acquisition (obviously).
Just for ref : Arduino-Events
Would be fun to see a version of TeensyThreads set to be purely co-op multitasking. No timing swapping and interrupt overhead and spawned threads act like little loop()'s that run until they get bored or stuck. Though that wouldn't help on dual core without accounting for that.
IMHO ... the only "compatibility" problem that might be needed to address how EventResponder works in a hypothetical RTOS environment is to ensure the context it executes in is that of the task that created it (or, possibly, another task selected when the callback is registered ... or changeable on the fly...).Which is why I asked the specific question, what features of EventResponder are believed to be incompatible with someday replacing EventResponder with a thin compatibility wrapper that just uses RTOS mailbox or queue or notification.
I fear that at least part of the "rather impatient tone" stems from a combination of "I'm catching up to a massive backlog of work" and "I will NOT merge such changes". A lot of people can see issues and have solutions, and it's frustrating for those people when even "minor work" and "quick changes" languish in the PR queue for years without any (apparent) attempt to triage them into "no, never", "look at later", and "yes, merge now" categories.I also tried to explain in msg #16 the reality of today's situation, where I'm catching up to a massive backlog of work that stalled while PJRC ran short-staffed due to Oregon's shelter-in-place order and other pandemic issues, which happened just as we had released Teensy 4.1 and a massive amount of software development was planned. Major developments are happening. Code security, MTP improvements, preliminary Arduino CLI & 2.0 packages have happened over the last several months. But there is still a huge backlog. I tried to explain in msg #16 that at this moment I'm *only* looking for specific feedback (my question above) and even minor work on EventResponder is not expected soon. Yet still, this thread is now filled with message complaining about low-level implementation details with a rather impatient tone, as if the words I wrote on msg #16 where invisible!
I still do want to help well reasoned opinion about specific EventResponder which may not be feasible to someday implement with a thin compatibility wrapper for RTOS APIs like mailboxes & queues. I would also appreciate a list of additional places yield() should be called. But I am NOT working on yield() and EventResponder at this time. Now is not the time to redo the active status stuff or significantly change the code. I will NOT merge such changes at this time. Too many far more important projects are pending, and I've learned the hard way many times how "quick" changes tend to become a major time sink. At this moment, I'm really only interested to hear about my original question for the sake of long-term planning.
Thanks a lot for the link to Events, it is nice to know, what the insiders are speaking of...
In my opinion, you can quite easily set up some cooperative multitasking with TeensyThreads. You only have to use a large time slice (for this task) and use threads.yield() to switch to the next task. Actually I am doing this for my high priority threads. Something like
while(triggerVariable==0) threads.yield();
The idea is, that if triggered, this high priority thread has enough time to complete it's job.
I am wondering, what percentage of my troubles, are caused by lack or hidden or hard to understand documentation. And some sort of assurance, that it was checked, that these components are working together. This is a valuable statement, because proved working libraries are a very good reason to buy Teensy.
What about the second suggestion of a proved Reference Configuration?
EventResponder was new to me, too. But it's sufficiently simple that I could manage without the documentation, read the code, and get it to do what I wanted. Obviously that's not going to be the case for everyone, for every library: I have two questions languishing in these forums without answers, where I simply can't see what's going on / what I'm "doing wrong", and no-one has (apparently) an answer.Hm, now had a look into EventResponder. This seems to be related to improve code efficiency in some cases as it would avoid polling and be faster.
For me this is something new and therefore would need very good examples and very good documentation.
I have learned in the past few years, that inventing something new or improving something makes it necessary to document it really well to make it useful. Often the workload for good documentation is higher, than for the implementation itself. So if you have got limited resources it might be better for everyone to implement something, with already existing and accessible documentation. (Yes, this is boring.)
Such is the nature of a forum discussion, I'm afraid...All in all I don't see the discussion about EventResponder to be helpful for beginners or advanced beginners in the context of the question: How to Handle Complexity more easily?
I guess that depends on Paul's and your definition of a "good" reason. Clearly a chunk of time has to be taken to support forthcoming elements that will be "forced" on the Teensy community, such as Arduino 2.0. But a lot of effort is also expended on things that aren't of interest to me (like code security, to take one example), and it's very hard for me to judge how much damage to PJRC's business there would be if they were not done, and PR and documentation maintenance were given a higher priority.@h4yn0nnym0u5e - indeed the list of things to get to before addressing anything presented here was likely the reason for the 'caveat' of not now but 'future' to see progress.
One good reason might be if the next Teensy with dual asymmetric cores somehow ships in 2022, any implementation will need to take into account the essential use and limitations of NXP's inbuilt 'Message Unit' and semaphore {assuming those are the right parts of the 'System Control' at hand} hardware implementation. So making a perfect solution now that isn't supported by those elements would require appropriate changes for production inter-processor functionality and full utility of both cores.
And some sort of assurance, that it was checked, that these components are working together. This is a valuable statement, because proved working libraries are a very good reason to buy Teensy.
I am wondering, what percentage of my troubles, are caused by lack or hidden or hard to understand documentation.
....
I have learned in the past few years, that inventing something new or improving something makes it necessary to document it really well to make it useful. Often the workload for good documentation is higher, than for the implementation itself. So if you have got limited resources it might be better for everyone to implement something, with already existing and accessible documentation. (Yes, this is boring.)
A lot of people can see issues and have solutions, and it's frustrating for those people when even "minor work" and "quick changes" languish in the PR queue for years without any (apparent) attempt to triage them into "no, never", "look at later", and "yes, merge now" categories.
But a lot of effort is also expended on things that aren't of interest to me (like code security, to take one example), and it's very hard for me to judge how much damage to PJRC's business there would be if they were not done, and PR and documentation maintenance were given a higher priority.
All in all I don't see the discussion about EventResponder to be helpful for beginners or advanced beginners in the context of the question: How to Handle Complexity more easily?
The core library does already have yield() calls. But more should probably be added. For example, we probably need yield() when Serial.available() will return zero.
@defragster said:
TeensyThreads has the means to save stack and jump tasks. Seems if not done with pre-emption ... but rather when a task was at a 'natural' pausing point with operation completed, or when awaiting input. Seems this Co-OP is how RTOS works in general?
As long you don't add a simple, empty serialEvent() or a "real event"As far as ESP32 and RTOS - it is a major PIA. ESP32's at 240 MHz are really SLOW as Frank noted.
> T_3.6 at 180 MHz counts 2 million loops/second
that's not a problem of ESP - it's your problem. It works good for me. On my Platformio a human readable dump gets displayed automatically. It show in which function, in which line somethin crashed and why. Automatically. You just need to enable it. You are not used to that... perhaps spend more time outside the Teesy-universe?BUT: When ESP32 Boot or 'helpful checking' doesn't casually stop execution (with a perpetual repeat restart) with a wonderfully painful DUMP of stuff I can't get deciphered doing 'Arduino'
LOL. The WDT is - surprise - it's documented. I know, it's confusing.. "docs"--you've never seen this on Teensy. And it prevents an endless hang. (The most usual crash on T4..)gets worse with RTOS threads enabled when some obscure WDT
It's also not a problem of the esp chip if it does not run on a experiental board by a dev who never read the basic datasheets (the board has basic schematic faults as you told me via mail) and a chiprev that is officially not recommended as has PSRAM problem which are documented in the errata.> So early project code was edit of the resetReason code to STOP the perpetual restart if the prior start failed - then the SerMon spew at least stopped to be read ...
and crashes silently... you wait... and after some minutes you realize that it stopped working.. . yes that rocks.. If a least a by default running ("obscure") *g*) WDT would restart it.. so that you have a chance to notice... hm. No.. Teensy ROCKS
To be really useful it has to be called by external, third-party libraries, too. Otherwise it may happen that it does not get called for several seconds.The core library does already have yield() calls. But more should probably be added.
Make sure there is a way to disable it in a way that it does not use resources like the mailboxes if an rtos needs them. and perhaps rename yield() (or find an other way) as yield() is (as far i know) needed by most rtos.I'm really only interested to hear about my original question for the sake of long-term planning.
As long nothing disables interrupts, the highest priority one has deterministic timing. Wether it has an rtos or not. The problem is not the OS - it's the Teensy core (and libs)
To be really useful it has to be called by external, third-party libraries, too. Otherwise it may happen that it does not get called for several seconds.
/* 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.
*/
static void __empty() { // Empty }
void yield(void) __attribute__ ((weak, alias("__empty")));
void delay(unsigned long ms) {
uint32_t start = micros();
while (ms > 0) {
yield();
while ( ms > 0 && (micros() - start) >= 1000) {
ms--;
start += 1000;
}
}
}