T4 - Correct Way to Connect SVC Handler to Interrupt?

Status
Not open for further replies.

Bill Greiman

Well-known member
I am porting the ChibiOS RTOS to T4 and need to use the SVC Call vector. Here is the code I am currently using for SVC_Handler and periodic tick.

Code:
static void tick() {
  CH_IRQ_PROLOGUE();
  chSysLockFromISR();
  chSysTimerHandlerI();
  chSysUnlockFromISR();
  CH_IRQ_EPILOGUE();
}

extern "C" void SVC_Handler(void);

IntervalTimer chTimer;

extern "C" void st_lld_init(void) {
  _VectorsRam[11] = SVC_Handler;
  chTimer.begin(tick, 1000);
}

Is there a better way to connect to the SVC Call vector?

The above works fine. The T4 is great with ChibiOS. A context switch triggered by a semaphore in the following example takes only 200 ns.

This means that an interrupt handler can start a thread in 200 ns with a semaphore.

Code:
// Connect a scope to pin 13
// Measure difference in time between first pulse with no context switch
// and second pulse started in thread 2 and ended in thread 1.
// Difference should be about 15-16 usec on a 16 MHz 328 Arduino.
// 200 ns on T4.


#include "ChRt.h"

// LED_BUILTIN pin on Arduino is usually pin 13.

// Semaphore to trigger context switch
SEMAPHORE_DECL(sem, 0);
//------------------------------------------------------------------------------
// thread 1 - high priority thread to set pin low.
// 64 byte stack beyond task switch and interrupt needs.
static THD_WORKING_AREA(waThread1, 64);

static THD_FUNCTION(Thread1, arg) {
  (void)arg;
  while (true) {
    chSemWait(&sem);
    digitalWrite(LED_BUILTIN, LOW);
  }
}
//------------------------------------------------------------------------------
// thread 2 - lower priority thread to toggle LED and trigger thread 1.
// 64 byte stack beyond task switch and interrupt needs.
static THD_WORKING_AREA(waThread2, 64);

static THD_FUNCTION(Thread2, arg) {
  (void)arg;
  pinMode(LED_BUILTIN, OUTPUT);
  while (true) {
    // First pulse to get time with no context switch.
    digitalWrite(LED_BUILTIN, HIGH);
    digitalWrite(LED_BUILTIN, LOW);
    // Start second pulse.
    digitalWrite(LED_BUILTIN, HIGH);
    // Trigger context switch for task that ends pulse.
    chSemSignal(&sem);
    // Sleep until next tick.
    chThdSleep(1);
  }
}
//------------------------------------------------------------------------------
void chSetup() {
  // Start high priority thread.
  chThdCreateStatic(waThread1, sizeof(waThread1),
    NORMALPRIO + 2, Thread1, NULL);

  // Start lower priority thread.
  chThdCreateStatic(waThread2, sizeof(waThread2),
    NORMALPRIO+1, Thread2, NULL);
}
//------------------------------------------------------------------------------
void setup() {
  chBegin(&chSetup);
  // chBegin() resets stacks and should never return.
  while (true) {}  
}
//------------------------------------------------------------------------------
void loop() {
  // Not used.
}
 
Sounds promising!

Just Anecdotally - that looks similar to the way PJRC does it for other vectors - not sure if there is anything special on that one that doesn't seem to be among the ones touched by PJRC with code search:
Code:
T:\arduino_1.8.10\hardware\teensy\avr\cores\teensy4\startup.c:
   ..
   63  
   64  	// set up blank interrupt & exception vector table
   65: 	for (i=0; i < NVIC_NUM_INTERRUPTS + 16; i++) _VectorsRam[i] = &unused_interrupt_vector;
   66  	for (i=0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_PRIORITY(i, 128);
   67  	SCB_VTOR = (uint32_t)_VectorsRam;
   ..
  150  static void configure_systick(void)
  151  {
[B]  152: 	_VectorsRam[14] = pendablesrvreq_isr;
  153: 	_VectorsRam[15] = systick_isr;[/B]
  154  	SYST_RVR = (SYSTICK_EXT_FREQ / 1000) - 1;
  155  	SYST_CVR = 0;
 
Status
Not open for further replies.
Back
Top