Add memory barrier, optimal interrupt on-off
Disabling an ISR on ARM has 3 instructions of latency. A Memory barrier is REQUIRED to ensure proper and predictable disabling. Memory barriers are expensive, so avoid disabling if already disabled (See https://mcuoneclipse.com/2015/10/16/nvic-disabling-interrupts-on-arm-cortex-m-and-the-need-for-a-memory-barrier-instruction/)
This commit is contained in:
parent
c2fb2f54a1
commit
0566badcef
@ -46,6 +46,11 @@ static void TXBegin(void) {
|
|||||||
// Disable UART interrupt in NVIC
|
// Disable UART interrupt in NVIC
|
||||||
NVIC_DisableIRQ( UART_IRQn );
|
NVIC_DisableIRQ( UART_IRQn );
|
||||||
|
|
||||||
|
// We NEED memory barriers to ensure Interrupts are actually disabled!
|
||||||
|
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
|
||||||
|
__DSB();
|
||||||
|
__ISB();
|
||||||
|
|
||||||
// Disable clock
|
// Disable clock
|
||||||
pmc_disable_periph_clk( ID_UART );
|
pmc_disable_periph_clk( ID_UART );
|
||||||
|
|
||||||
|
@ -99,6 +99,11 @@ void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
|
|||||||
// Disable interrupt, just in case it was already enabled
|
// Disable interrupt, just in case it was already enabled
|
||||||
NVIC_DisableIRQ(irq);
|
NVIC_DisableIRQ(irq);
|
||||||
|
|
||||||
|
// We NEED memory barriers to ensure Interrupts are actually disabled!
|
||||||
|
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
|
||||||
|
__DSB();
|
||||||
|
__ISB();
|
||||||
|
|
||||||
// Disable timer interrupt
|
// Disable timer interrupt
|
||||||
tc->TC_CHANNEL[channel].TC_IDR = TC_IDR_CPCS;
|
tc->TC_CHANNEL[channel].TC_IDR = TC_IDR_CPCS;
|
||||||
|
|
||||||
@ -133,6 +138,11 @@ void HAL_timer_enable_interrupt(const uint8_t timer_num) {
|
|||||||
void HAL_timer_disable_interrupt(const uint8_t timer_num) {
|
void HAL_timer_disable_interrupt(const uint8_t timer_num) {
|
||||||
IRQn_Type irq = TimerConfig[timer_num].IRQ_Id;
|
IRQn_Type irq = TimerConfig[timer_num].IRQ_Id;
|
||||||
NVIC_DisableIRQ(irq);
|
NVIC_DisableIRQ(irq);
|
||||||
|
|
||||||
|
// We NEED memory barriers to ensure Interrupts are actually disabled!
|
||||||
|
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
|
||||||
|
__DSB();
|
||||||
|
__ISB();
|
||||||
}
|
}
|
||||||
|
|
||||||
// missing from CMSIS: Check if interrupt is enabled or not
|
// missing from CMSIS: Check if interrupt is enabled or not
|
||||||
|
@ -245,6 +245,11 @@
|
|||||||
// Disable UART interrupt in NVIC
|
// Disable UART interrupt in NVIC
|
||||||
NVIC_DisableIRQ( HWUART_IRQ );
|
NVIC_DisableIRQ( HWUART_IRQ );
|
||||||
|
|
||||||
|
// We NEED memory barriers to ensure Interrupts are actually disabled!
|
||||||
|
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
|
||||||
|
__DSB();
|
||||||
|
__ISB();
|
||||||
|
|
||||||
// Disable clock
|
// Disable clock
|
||||||
pmc_disable_periph_clk( HWUART_IRQ_ID );
|
pmc_disable_periph_clk( HWUART_IRQ_ID );
|
||||||
|
|
||||||
@ -290,6 +295,11 @@
|
|||||||
// Disable UART interrupt in NVIC
|
// Disable UART interrupt in NVIC
|
||||||
NVIC_DisableIRQ( HWUART_IRQ );
|
NVIC_DisableIRQ( HWUART_IRQ );
|
||||||
|
|
||||||
|
// We NEED memory barriers to ensure Interrupts are actually disabled!
|
||||||
|
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
|
||||||
|
__DSB();
|
||||||
|
__ISB();
|
||||||
|
|
||||||
pmc_disable_periph_clk( HWUART_IRQ_ID );
|
pmc_disable_periph_clk( HWUART_IRQ_ID );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +68,11 @@ void watchdogSetup(void) {
|
|||||||
// Disable WDT interrupt (just in case, to avoid triggering it!)
|
// Disable WDT interrupt (just in case, to avoid triggering it!)
|
||||||
NVIC_DisableIRQ(WDT_IRQn);
|
NVIC_DisableIRQ(WDT_IRQn);
|
||||||
|
|
||||||
|
// We NEED memory barriers to ensure Interrupts are actually disabled!
|
||||||
|
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
|
||||||
|
__DSB();
|
||||||
|
__ISB();
|
||||||
|
|
||||||
// Initialize WDT with the given parameters
|
// Initialize WDT with the given parameters
|
||||||
WDT_Enable(WDT, value);
|
WDT_Enable(WDT, value);
|
||||||
|
|
||||||
|
@ -143,6 +143,11 @@ FORCE_INLINE static void HAL_timer_disable_interrupt(const uint8_t timer_num) {
|
|||||||
case 0: NVIC_DisableIRQ(TIMER0_IRQn); // Disable interrupt handler
|
case 0: NVIC_DisableIRQ(TIMER0_IRQn); // Disable interrupt handler
|
||||||
case 1: NVIC_DisableIRQ(TIMER1_IRQn); // Disable interrupt handler
|
case 1: NVIC_DisableIRQ(TIMER1_IRQn); // Disable interrupt handler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We NEED memory barriers to ensure Interrupts are actually disabled!
|
||||||
|
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
|
||||||
|
__DSB();
|
||||||
|
__ISB();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function is missing from CMSIS
|
// This function is missing from CMSIS
|
||||||
|
@ -258,6 +258,11 @@ bool LPC1768_PWM_attach_pin(pin_t pin, uint32_t min /* = 1 */, uint32_t max /* =
|
|||||||
// OK to update the active table because the
|
// OK to update the active table because the
|
||||||
// ISR doesn't use any of the changed items
|
// ISR doesn't use any of the changed items
|
||||||
|
|
||||||
|
// We NEED memory barriers to ensure Interrupts are actually disabled!
|
||||||
|
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
|
||||||
|
__DSB();
|
||||||
|
__ISB();
|
||||||
|
|
||||||
if (ISR_table_update) //use work table if that's the newest
|
if (ISR_table_update) //use work table if that's the newest
|
||||||
temp_table = work_table;
|
temp_table = work_table;
|
||||||
else
|
else
|
||||||
@ -342,6 +347,11 @@ bool LPC1768_PWM_detach_pin(pin_t pin) {
|
|||||||
//// interrupt controlled PWM code
|
//// interrupt controlled PWM code
|
||||||
NVIC_DisableIRQ(HAL_PWM_TIMER_IRQn);
|
NVIC_DisableIRQ(HAL_PWM_TIMER_IRQn);
|
||||||
|
|
||||||
|
// We NEED memory barriers to ensure Interrupts are actually disabled!
|
||||||
|
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
|
||||||
|
__DSB();
|
||||||
|
__ISB();
|
||||||
|
|
||||||
if (ISR_table_update) {
|
if (ISR_table_update) {
|
||||||
ISR_table_update = false; // don't update yet - have another update to do
|
ISR_table_update = false; // don't update yet - have another update to do
|
||||||
NVIC_EnableIRQ(HAL_PWM_TIMER_IRQn); // re-enable PWM interrupts
|
NVIC_EnableIRQ(HAL_PWM_TIMER_IRQn); // re-enable PWM interrupts
|
||||||
@ -428,6 +438,12 @@ bool LPC1768_PWM_write(pin_t pin, uint32_t value) {
|
|||||||
|
|
||||||
//// interrupt controlled PWM code
|
//// interrupt controlled PWM code
|
||||||
NVIC_DisableIRQ(HAL_PWM_TIMER_IRQn);
|
NVIC_DisableIRQ(HAL_PWM_TIMER_IRQn);
|
||||||
|
|
||||||
|
// We NEED memory barriers to ensure Interrupts are actually disabled!
|
||||||
|
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
|
||||||
|
__DSB();
|
||||||
|
__ISB();
|
||||||
|
|
||||||
if (!ISR_table_update) // use the most up to date table
|
if (!ISR_table_update) // use the most up to date table
|
||||||
COPY_ACTIVE_TABLE; // copy active table into work table
|
COPY_ACTIVE_TABLE; // copy active table into work table
|
||||||
|
|
||||||
@ -456,6 +472,11 @@ bool useable_hardware_PWM(pin_t pin) {
|
|||||||
|
|
||||||
NVIC_DisableIRQ(HAL_PWM_TIMER_IRQn);
|
NVIC_DisableIRQ(HAL_PWM_TIMER_IRQn);
|
||||||
|
|
||||||
|
// We NEED memory barriers to ensure Interrupts are actually disabled!
|
||||||
|
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
|
||||||
|
__DSB();
|
||||||
|
__ISB();
|
||||||
|
|
||||||
bool return_flag = false;
|
bool return_flag = false;
|
||||||
for (uint8_t i = 0; i < NUM_ISR_PWMS; i++) // see if it's already setup
|
for (uint8_t i = 0; i < NUM_ISR_PWMS; i++) // see if it's already setup
|
||||||
if (active_table[i].pin == pin) return_flag = true;
|
if (active_table[i].pin == pin) return_flag = true;
|
||||||
|
@ -123,6 +123,11 @@ void HAL_timer_enable_interrupt(const uint8_t timer_num) {
|
|||||||
|
|
||||||
void HAL_timer_disable_interrupt(const uint8_t timer_num) {
|
void HAL_timer_disable_interrupt(const uint8_t timer_num) {
|
||||||
HAL_NVIC_DisableIRQ(timerConfig[timer_num].IRQ_Id);
|
HAL_NVIC_DisableIRQ(timerConfig[timer_num].IRQ_Id);
|
||||||
|
|
||||||
|
// We NEED memory barriers to ensure Interrupts are actually disabled!
|
||||||
|
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
|
||||||
|
__DSB();
|
||||||
|
__ISB();
|
||||||
}
|
}
|
||||||
|
|
||||||
hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) {
|
hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) {
|
||||||
|
@ -127,6 +127,11 @@ void HAL_timer_enable_interrupt(const uint8_t timer_num) {
|
|||||||
|
|
||||||
void HAL_timer_disable_interrupt(const uint8_t timer_num) {
|
void HAL_timer_disable_interrupt(const uint8_t timer_num) {
|
||||||
HAL_NVIC_DisableIRQ(timerConfig[timer_num].IRQ_Id);
|
HAL_NVIC_DisableIRQ(timerConfig[timer_num].IRQ_Id);
|
||||||
|
|
||||||
|
// We NEED memory barriers to ensure Interrupts are actually disabled!
|
||||||
|
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
|
||||||
|
__DSB();
|
||||||
|
__ISB();
|
||||||
}
|
}
|
||||||
|
|
||||||
hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) {
|
hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) {
|
||||||
|
@ -29,6 +29,22 @@
|
|||||||
#include "HAL.h"
|
#include "HAL.h"
|
||||||
#include "HAL_timers_Teensy.h"
|
#include "HAL_timers_Teensy.h"
|
||||||
|
|
||||||
|
/** \brief Instruction Synchronization Barrier
|
||||||
|
Instruction Synchronization Barrier flushes the pipeline in the processor,
|
||||||
|
so that all instructions following the ISB are fetched from cache or
|
||||||
|
memory, after the instruction has been completed.
|
||||||
|
*/
|
||||||
|
FORCE_INLINE static void __ISB(void) {
|
||||||
|
__asm__ __volatile__("isb 0xF":::"memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Data Synchronization Barrier
|
||||||
|
This function acts as a special kind of Data Memory Barrier.
|
||||||
|
It completes when all explicit memory accesses before this instruction complete.
|
||||||
|
*/
|
||||||
|
FORCE_INLINE static void __DSB(void) {
|
||||||
|
__asm__ __volatile__("dsb 0xF":::"memory");
|
||||||
|
}
|
||||||
|
|
||||||
void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
|
void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
|
||||||
switch (timer_num) {
|
switch (timer_num) {
|
||||||
@ -65,6 +81,11 @@ void HAL_timer_disable_interrupt(const uint8_t timer_num) {
|
|||||||
case 0: NVIC_DISABLE_IRQ(IRQ_FTM0); break;
|
case 0: NVIC_DISABLE_IRQ(IRQ_FTM0); break;
|
||||||
case 1: NVIC_DISABLE_IRQ(IRQ_FTM1); break;
|
case 1: NVIC_DISABLE_IRQ(IRQ_FTM1); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We NEED memory barriers to ensure Interrupts are actually disabled!
|
||||||
|
// ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
|
||||||
|
__DSB();
|
||||||
|
__ISB();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HAL_timer_interrupt_enabled(const uint8_t timer_num) {
|
bool HAL_timer_interrupt_enabled(const uint8_t timer_num) {
|
||||||
|
@ -73,7 +73,6 @@ static uint8_t LEDs[8] = { 0 };
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void Max7219_PutByte(uint8_t data) {
|
void Max7219_PutByte(uint8_t data) {
|
||||||
CRITICAL_SECTION_START;
|
|
||||||
for (uint8_t i = 8; i--;) {
|
for (uint8_t i = 8; i--;) {
|
||||||
SIG_DELAY();
|
SIG_DELAY();
|
||||||
WRITE(MAX7219_CLK_PIN, LOW); // tick
|
WRITE(MAX7219_CLK_PIN, LOW); // tick
|
||||||
@ -84,12 +83,10 @@ void Max7219_PutByte(uint8_t data) {
|
|||||||
SIG_DELAY();
|
SIG_DELAY();
|
||||||
data <<= 1;
|
data <<= 1;
|
||||||
}
|
}
|
||||||
CRITICAL_SECTION_END;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Max7219(const uint8_t reg, const uint8_t data) {
|
void Max7219(const uint8_t reg, const uint8_t data) {
|
||||||
SIG_DELAY();
|
SIG_DELAY();
|
||||||
CRITICAL_SECTION_START;
|
|
||||||
WRITE(MAX7219_LOAD_PIN, LOW); // begin
|
WRITE(MAX7219_LOAD_PIN, LOW); // begin
|
||||||
SIG_DELAY();
|
SIG_DELAY();
|
||||||
Max7219_PutByte(reg); // specify register
|
Max7219_PutByte(reg); // specify register
|
||||||
@ -99,7 +96,6 @@ void Max7219(const uint8_t reg, const uint8_t data) {
|
|||||||
WRITE(MAX7219_LOAD_PIN, LOW); // and tell the chip to load the data
|
WRITE(MAX7219_LOAD_PIN, LOW); // and tell the chip to load the data
|
||||||
SIG_DELAY();
|
SIG_DELAY();
|
||||||
WRITE(MAX7219_LOAD_PIN, HIGH);
|
WRITE(MAX7219_LOAD_PIN, HIGH);
|
||||||
CRITICAL_SECTION_END;
|
|
||||||
SIG_DELAY();
|
SIG_DELAY();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1085,9 +1085,7 @@ void Temperature::updateTemperaturesFromRawValues() {
|
|||||||
watchdog_reset();
|
watchdog_reset();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CRITICAL_SECTION_START;
|
|
||||||
temp_meas_ready = false;
|
temp_meas_ready = false;
|
||||||
CRITICAL_SECTION_END;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user