Parcourir la source

Reduce EventResponder overhead on systic and yield

A couple of minimalist changes.

systick_isr - By default it does nothing with the event responder.
Only if the user calls the attachInterrupt member of EventResponder will it install the version of the ISR that checks the list for any active ISR event Responders.

T4 Yield - try to keep bitfields for things yield should test
Make it such that yield hopefully can test to see there is nothing to do and returns quickly.

There are some interesting limitations, that is that the serialEvent
handling code. Both for USB and hardware Serial can only remove it self
if the default eventHandler is called once, as I don't know anyway to
detect if the default code (weak linkage) is included or if it is a user
version.  So waits until called to remove it self from active list.
Sketches can force this by simply calling the event method right after
calling begin on the serial port.
main
Kurt Eckhardt il y a 4 ans
Parent
révision
31c199b0b2
6 fichiers modifiés avec 23 ajouts et 8 suppressions
  1. +5
    -0
      teensy4/EventResponder.cpp
  2. +5
    -2
      teensy4/EventResponder.h
  3. +2
    -0
      teensy4/HardwareSerial.cpp
  4. +5
    -0
      teensy4/core_pins.h
  5. +1
    -2
      teensy4/usb_inst.cpp
  6. +5
    -4
      teensy4/yield.cpp

+ 5
- 0
teensy4/EventResponder.cpp Voir le fichier

@@ -339,6 +339,11 @@ extern "C" volatile uint32_t systick_millis_count;
extern "C" volatile uint32_t systick_cycle_count;
extern "C" uint32_t systick_safe_read; // micros() synchronization
extern "C" void systick_isr(void)
{
systick_cycle_count = ARM_DWT_CYCCNT;
systick_millis_count++;
}
extern "C" void systick_isr_with_timer_events(void)
{
systick_cycle_count = ARM_DWT_CYCCNT;
systick_millis_count++;

+ 5
- 2
teensy4/EventResponder.h Voir le fichier

@@ -59,6 +59,7 @@
* your function is called only one time, based on the last trigger
* event.
*/
extern "C" void systick_isr_with_timer_events(void);

class EventResponder;
typedef EventResponder& EventResponderRef;
@@ -87,6 +88,7 @@ public:
detachNoInterrupts();
_function = function;
_type = EventTypeYield;
yield_active_check_flags |= YIELD_CHECK_EVENT_RESPONDER; // user setup a yield type...
enableInterrupts(irq);
}

@@ -112,6 +114,8 @@ public:
_function = function;
_type = EventTypeInterrupt;
SCB_SHPR3 |= 0x00FF0000; // configure PendSV, lowest priority
// Make sure we are using the systic ISR that process this
_VectorsRam[15] = systick_isr_with_timer_events;
enableInterrupts(irq);
}

@@ -168,9 +172,8 @@ public:
// used with a scheduler or RTOS.
bool waitForEvent(EventResponderRef event, int timeout);
EventResponder * waitForEvent(EventResponder *list, int listsize, int timeout);

static void runFromYield() {
if (!firstYield) return;
if (!firstYield) return;
// First, check if yield was called from an interrupt
// never call normal handler functions from any interrupt context
uint32_t ipsr;

+ 2
- 0
teensy4/HardwareSerial.cpp Voir le fichier

@@ -568,6 +568,7 @@ void HardwareSerial::enableSerialEvents()
if (!serial_event_handler_checks[hardware->serial_index]) {
serial_event_handler_checks[hardware->serial_index] = hardware->serial_event_handler_check; // clear it out
serial_event_handlers_active++;
yield_active_check_flags |= YIELD_CHECK_HARDWARE_SERIAL;
}
}

@@ -576,5 +577,6 @@ void HardwareSerial::disableSerialEvents()
if (serial_event_handler_checks[hardware->serial_index]) {
serial_event_handler_checks[hardware->serial_index] = nullptr; // clear it out
serial_event_handlers_active--;
if (!serial_event_handlers_active) yield_active_check_flags &= ~YIELD_CHECK_HARDWARE_SERIAL;
}
}

+ 5
- 0
teensy4/core_pins.h Voir le fichier

@@ -1546,6 +1546,11 @@ static inline uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrde
void _reboot_Teensyduino_(void) __attribute__((noreturn));
void _restart_Teensyduino_(void) __attribute__((noreturn));

// Define a set of flags to know which things yield should check when called.
extern uint8_t yield_active_check_flags;
#define YIELD_CHECK_USB_SERIAL 0x1 // check the USB for Serial.available()
#define YIELD_CHECK_HARDWARE_SERIAL 0x2 // check Hardware Serial ports available
#define YIELD_CHECK_EVENT_RESPONDER 0x4 // User has created eventResponders that use yield
void yield(void);

void delay(uint32_t msec);

+ 1
- 2
teensy4/usb_inst.cpp Voir le fichier

@@ -96,6 +96,5 @@ usb_seremu_class Serial;
#endif

#endif // F_CPU
uint8_t usb_enable_serial_event_processing = 1;
void serialEvent() __attribute__((weak));
void serialEvent() {usb_enable_serial_event_processing = 0;}
void serialEvent() {yield_active_check_flags &= ~YIELD_CHECK_USB_SERIAL;}

+ 5
- 4
teensy4/yield.cpp Voir le fichier

@@ -33,22 +33,23 @@

extern uint8_t usb_enable_serial_event_processing; // from usb_inst.cpp

uint8_t yield_active_check_flags = YIELD_CHECK_USB_SERIAL; // default to check USB.
void yield(void) __attribute__ ((weak));
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 Serail - Add hack to minimize impact...
if (usb_enable_serial_event_processing && Serial.available()) serialEvent();
if ((yield_active_check_flags & YIELD_CHECK_USB_SERIAL) && Serial.available()) serialEvent();

// Current workaround until integrate with EventResponder.
if (HardwareSerial::serial_event_handlers_active) HardwareSerial::processSerialEvents();
if (yield_active_check_flags & YIELD_CHECK_HARDWARE_SERIAL) HardwareSerial::processSerialEvents();

running = 0;
EventResponder::runFromYield();
if (yield_active_check_flags & YIELD_CHECK_EVENT_RESPONDER) EventResponder::runFromYield();
};

Chargement…
Annuler
Enregistrer