Browse 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.
teensy4-core
Kurt Eckhardt 4 years ago
parent
commit
31c199b0b2
6 changed files with 23 additions and 8 deletions
  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 View File

extern "C" volatile uint32_t systick_cycle_count; extern "C" volatile uint32_t systick_cycle_count;
extern "C" uint32_t systick_safe_read; // micros() synchronization extern "C" uint32_t systick_safe_read; // micros() synchronization
extern "C" void systick_isr(void) 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_cycle_count = ARM_DWT_CYCCNT;
systick_millis_count++; systick_millis_count++;

+ 5
- 2
teensy4/EventResponder.h View File

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


class EventResponder; class EventResponder;
typedef EventResponder& EventResponderRef; typedef EventResponder& EventResponderRef;
detachNoInterrupts(); detachNoInterrupts();
_function = function; _function = function;
_type = EventTypeYield; _type = EventTypeYield;
yield_active_check_flags |= YIELD_CHECK_EVENT_RESPONDER; // user setup a yield type...
enableInterrupts(irq); enableInterrupts(irq);
} }


_function = function; _function = function;
_type = EventTypeInterrupt; _type = EventTypeInterrupt;
SCB_SHPR3 |= 0x00FF0000; // configure PendSV, lowest priority 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); enableInterrupts(irq);
} }


// used with a scheduler or RTOS. // used with a scheduler or RTOS.
bool waitForEvent(EventResponderRef event, int timeout); bool waitForEvent(EventResponderRef event, int timeout);
EventResponder * waitForEvent(EventResponder *list, int listsize, int timeout); EventResponder * waitForEvent(EventResponder *list, int listsize, int timeout);

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

+ 2
- 0
teensy4/HardwareSerial.cpp View File

if (!serial_event_handler_checks[hardware->serial_index]) { 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_handler_checks[hardware->serial_index] = hardware->serial_event_handler_check; // clear it out
serial_event_handlers_active++; serial_event_handlers_active++;
yield_active_check_flags |= YIELD_CHECK_HARDWARE_SERIAL;
} }
} }


if (serial_event_handler_checks[hardware->serial_index]) { if (serial_event_handler_checks[hardware->serial_index]) {
serial_event_handler_checks[hardware->serial_index] = nullptr; // clear it out serial_event_handler_checks[hardware->serial_index] = nullptr; // clear it out
serial_event_handlers_active--; serial_event_handlers_active--;
if (!serial_event_handlers_active) yield_active_check_flags &= ~YIELD_CHECK_HARDWARE_SERIAL;
} }
} }

+ 5
- 0
teensy4/core_pins.h View File

void _reboot_Teensyduino_(void) __attribute__((noreturn)); void _reboot_Teensyduino_(void) __attribute__((noreturn));
void _restart_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 yield(void);


void delay(uint32_t msec); void delay(uint32_t msec);

+ 1
- 2
teensy4/usb_inst.cpp View File

#endif #endif


#endif // F_CPU #endif // F_CPU
uint8_t usb_enable_serial_event_processing = 1;
void serialEvent() __attribute__((weak)); 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 View File



extern uint8_t usb_enable_serial_event_processing; // from usb_inst.cpp 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) __attribute__ ((weak));
void yield(void) void yield(void)
{ {
static uint8_t running=0; static uint8_t running=0;
if (!yield_active_check_flags) return; // nothing to do
if (running) return; // TODO: does this need to be atomic? if (running) return; // TODO: does this need to be atomic?
running = 1; running = 1;




// USB Serail - Add hack to minimize impact... // 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. // 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; running = 0;
EventResponder::runFromYield();
if (yield_active_check_flags & YIELD_CHECK_EVENT_RESPONDER) EventResponder::runFromYield();
}; };

Loading…
Cancel
Save