mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 05:12:57 +01:00
atmega: use software interrupt for context swap
Fixes #5745 For AVR based boards, three defines must be defined AVR_CONTEXT_SWAP_INIT, AVR_CONTEXT_SWAP_INTERRUPT_VECT, and AVR_CONTEXT_SWAP_TRIGGER. These defines are used to trigger a software interrupt used for context switching. When AVR_CONTEXT_SWAP_INTERRUPT_VECT is handled, the scheduler is run and a context swap will happen if necessary, with the resulting thread starting following the reti instruction. This results in threads running at normal priority instead of at interrupt priority. Atmega devices do provide a pure software interrupt. The method used here for waspmote-pro and arduino-mega2560 is to use pin change interrupts, set the pin to act as an output, and toggle the value to simulate a software interrupt. The main limitation here is that a physical pin is now occupied and must be defined for each board supported by RIOT. On the plus side, it provides an easy method for detecting context swaps with an oscilloscope.
This commit is contained in:
parent
3f82b530ad
commit
e0365e0bf9
@ -52,6 +52,22 @@ extern "C" {
|
||||
#define LED0_TOGGLE (PORTB ^= LED0_MASK)
|
||||
/** @} */
|
||||
|
||||
|
||||
/**
|
||||
* Context swap defines
|
||||
* Setup to use PJ6 which is pin change interrupt 15 (PCINT15)
|
||||
* This emulates a software triggered interrupt
|
||||
**/
|
||||
#define AVR_CONTEXT_SWAP_INIT do { \
|
||||
DDRJ |= (1 << PJ6); \
|
||||
PCICR |= (1 << PCIE1); \
|
||||
PCMSK1 |= (1 << PCINT15); \
|
||||
} while (0)
|
||||
#define AVR_CONTEXT_SWAP_INTERRUPT_VECT PCINT1_vect
|
||||
#define AVR_CONTEXT_SWAP_TRIGGER PORTJ ^= (1 << PJ6)
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief xtimer configuration values
|
||||
* @{
|
||||
|
@ -150,6 +150,19 @@ extern "C" {
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* Context swap defines
|
||||
* Setup to use PB5 which is pin change interrupt 5
|
||||
* This emulates a software triggered interrupt
|
||||
**/
|
||||
#define AVR_CONTEXT_SWAP_INIT do { \
|
||||
DDRB |= (1 << PB5); \
|
||||
PCICR |= (1 << PCIE0); \
|
||||
PCMSK0 |= (1 << PCINT5); \
|
||||
} while (0)
|
||||
#define AVR_CONTEXT_SWAP_INTERRUPT_VECT PCINT0_vect
|
||||
#define AVR_CONTEXT_SWAP_TRIGGER PORTB ^= (1 << PB5)
|
||||
|
||||
/**
|
||||
* @brief xtimer configuration values
|
||||
* @{
|
||||
|
@ -25,11 +25,37 @@
|
||||
#include "sched.h"
|
||||
#include "irq.h"
|
||||
#include "cpu.h"
|
||||
#include "board.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief AVR_CONTEXT_SWAP_INIT intialize the context swap trigger
|
||||
* Called when threading is first started.
|
||||
*/
|
||||
#ifndef AVR_CONTEXT_SWAP_INIT
|
||||
#error AVR_CONTEXT_SWAP_INIT must be defined in board.h
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief AVR_CONTEXT_SWAP_INTERRUPT_VECT Name of the ISR to use for context swapping
|
||||
*/
|
||||
#ifndef AVR_CONTEXT_SWAP_INTERRUPT_VECT
|
||||
#error AVR_CONTEXT_SWAP_INTERRUPT_VECT must be defined in board.h
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief AVR_CONTEXT_SWAP_TRIGGER executed to start the context swap
|
||||
* When executed, this should result in the interrupt named in
|
||||
* AVR_CONTEXT_SWAP_INTERRUPT_VECT being called
|
||||
*/
|
||||
#ifndef AVR_CONTEXT_SWAP_TRIGGER
|
||||
#error ARV_CONTEXT_SWAP_TRIGGER must be defined in board.h
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* local function declarations (prefixed with __)
|
||||
*/
|
||||
|
||||
static void __context_save(void);
|
||||
static void __context_restore(void);
|
||||
static void __enter_thread_mode(void);
|
||||
@ -122,7 +148,6 @@ char *thread_arch_stack_init(thread_task_func_t task_func, void *arg,
|
||||
stk--;
|
||||
*stk = (uint8_t) 0x00;
|
||||
#endif
|
||||
|
||||
#if defined(RAMPZ)
|
||||
stk--;
|
||||
*stk = (uint8_t) 0x00;
|
||||
@ -221,6 +246,7 @@ void thread_arch_start_threading(void) __attribute__((naked));
|
||||
void thread_arch_start_threading(void)
|
||||
{
|
||||
sched_run();
|
||||
AVR_CONTEXT_SWAP_INIT;
|
||||
__enter_thread_mode();
|
||||
}
|
||||
|
||||
@ -238,17 +264,17 @@ void NORETURN __enter_thread_mode(void)
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void thread_arch_yield(void) __attribute__((naked));
|
||||
void thread_arch_yield(void)
|
||||
{
|
||||
void thread_arch_yield(void) {
|
||||
AVR_CONTEXT_SWAP_TRIGGER;
|
||||
}
|
||||
|
||||
|
||||
// Use this interrupt to perform all context switches
|
||||
ISR(AVR_CONTEXT_SWAP_INTERRUPT_VECT, ISR_NAKED) {
|
||||
__context_save();
|
||||
|
||||
/* irq_disable(); */ /* gets already disabled during __context_save() */
|
||||
sched_run();
|
||||
irq_enable();
|
||||
|
||||
__context_restore();
|
||||
__asm__ volatile("ret");
|
||||
__asm__ volatile("reti");
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user