Browse Source

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/)
etagle 7 years ago
parent
commit
0566badcef

+ 5
- 0
Marlin/src/HAL/HAL_DUE/DebugMonitor_Due.cpp View File

46
   // Disable UART interrupt in NVIC
46
   // Disable UART interrupt in NVIC
47
   NVIC_DisableIRQ( UART_IRQn );
47
   NVIC_DisableIRQ( UART_IRQn );
48
 
48
 
49
+  // We NEED memory barriers to ensure Interrupts are actually disabled!
50
+  // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
51
+  __DSB();
52
+  __ISB();
53
+
49
   // Disable clock
54
   // Disable clock
50
   pmc_disable_periph_clk( ID_UART );
55
   pmc_disable_periph_clk( ID_UART );
51
 
56
 

+ 10
- 0
Marlin/src/HAL/HAL_DUE/HAL_timers_Due.cpp View File

99
   // Disable interrupt, just in case it was already enabled
99
   // Disable interrupt, just in case it was already enabled
100
   NVIC_DisableIRQ(irq);
100
   NVIC_DisableIRQ(irq);
101
 
101
 
102
+  // We NEED memory barriers to ensure Interrupts are actually disabled!
103
+  // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
104
+  __DSB();
105
+  __ISB();
106
+
102
   // Disable timer interrupt
107
   // Disable timer interrupt
103
   tc->TC_CHANNEL[channel].TC_IDR = TC_IDR_CPCS;
108
   tc->TC_CHANNEL[channel].TC_IDR = TC_IDR_CPCS;
104
 
109
 
133
 void HAL_timer_disable_interrupt(const uint8_t timer_num) {
138
 void HAL_timer_disable_interrupt(const uint8_t timer_num) {
134
   IRQn_Type irq = TimerConfig[timer_num].IRQ_Id;
139
   IRQn_Type irq = TimerConfig[timer_num].IRQ_Id;
135
   NVIC_DisableIRQ(irq);
140
   NVIC_DisableIRQ(irq);
141
+
142
+  // We NEED memory barriers to ensure Interrupts are actually disabled!
143
+  // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
144
+  __DSB();
145
+  __ISB();
136
 }
146
 }
137
 
147
 
138
 // missing from CMSIS: Check if interrupt is enabled or not
148
 // missing from CMSIS: Check if interrupt is enabled or not

+ 10
- 0
Marlin/src/HAL/HAL_DUE/MarlinSerial_Due.cpp View File

245
     // Disable UART interrupt in NVIC
245
     // Disable UART interrupt in NVIC
246
     NVIC_DisableIRQ( HWUART_IRQ );
246
     NVIC_DisableIRQ( HWUART_IRQ );
247
 
247
 
248
+    // We NEED memory barriers to ensure Interrupts are actually disabled!
249
+    // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
250
+    __DSB();
251
+    __ISB();
252
+
248
     // Disable clock
253
     // Disable clock
249
     pmc_disable_periph_clk( HWUART_IRQ_ID );
254
     pmc_disable_periph_clk( HWUART_IRQ_ID );
250
 
255
 
290
     // Disable UART interrupt in NVIC
295
     // Disable UART interrupt in NVIC
291
     NVIC_DisableIRQ( HWUART_IRQ );
296
     NVIC_DisableIRQ( HWUART_IRQ );
292
 
297
 
298
+    // We NEED memory barriers to ensure Interrupts are actually disabled!
299
+    // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
300
+    __DSB();
301
+    __ISB();
302
+
293
     pmc_disable_periph_clk( HWUART_IRQ_ID );
303
     pmc_disable_periph_clk( HWUART_IRQ_ID );
294
   }
304
   }
295
 
305
 

+ 5
- 0
Marlin/src/HAL/HAL_DUE/watchdog_Due.cpp View File

68
       // Disable WDT interrupt (just in case, to avoid triggering it!)
68
       // Disable WDT interrupt (just in case, to avoid triggering it!)
69
       NVIC_DisableIRQ(WDT_IRQn);
69
       NVIC_DisableIRQ(WDT_IRQn);
70
 
70
 
71
+      // We NEED memory barriers to ensure Interrupts are actually disabled!
72
+      // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
73
+      __DSB();
74
+      __ISB();
75
+
71
       // Initialize WDT with the given parameters
76
       // Initialize WDT with the given parameters
72
       WDT_Enable(WDT, value);
77
       WDT_Enable(WDT, value);
73
 
78
 

+ 5
- 0
Marlin/src/HAL/HAL_LPC1768/HAL_timers.h View File

143
     case 0: NVIC_DisableIRQ(TIMER0_IRQn); // Disable interrupt handler
143
     case 0: NVIC_DisableIRQ(TIMER0_IRQn); // Disable interrupt handler
144
     case 1: NVIC_DisableIRQ(TIMER1_IRQn); // Disable interrupt handler
144
     case 1: NVIC_DisableIRQ(TIMER1_IRQn); // Disable interrupt handler
145
   }
145
   }
146
+
147
+  // We NEED memory barriers to ensure Interrupts are actually disabled!
148
+  // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
149
+  __DSB();
150
+  __ISB();
146
 }
151
 }
147
 
152
 
148
 // This function is missing from CMSIS
153
 // This function is missing from CMSIS

+ 21
- 0
Marlin/src/HAL/HAL_LPC1768/LPC1768_PWM.cpp View File

258
                                  // OK to update the active table because the
258
                                  // OK to update the active table because the
259
                                  // ISR doesn't use any of the changed items
259
                                  // ISR doesn't use any of the changed items
260
 
260
 
261
+  // We NEED memory barriers to ensure Interrupts are actually disabled!
262
+  // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
263
+  __DSB();
264
+  __ISB();
265
+
261
   if (ISR_table_update) //use work table if that's the newest
266
   if (ISR_table_update) //use work table if that's the newest
262
     temp_table = work_table;
267
     temp_table = work_table;
263
   else
268
   else
342
 ////  interrupt controlled PWM code
347
 ////  interrupt controlled PWM code
343
   NVIC_DisableIRQ(HAL_PWM_TIMER_IRQn);
348
   NVIC_DisableIRQ(HAL_PWM_TIMER_IRQn);
344
 
349
 
350
+  // We NEED memory barriers to ensure Interrupts are actually disabled!
351
+  // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
352
+  __DSB();
353
+  __ISB();
354
+
345
   if (ISR_table_update) {
355
   if (ISR_table_update) {
346
     ISR_table_update = false;    // don't update yet - have another update to do
356
     ISR_table_update = false;    // don't update yet - have another update to do
347
     NVIC_EnableIRQ(HAL_PWM_TIMER_IRQn);  // re-enable PWM interrupts
357
     NVIC_EnableIRQ(HAL_PWM_TIMER_IRQn);  // re-enable PWM interrupts
428
 
438
 
429
 ////  interrupt controlled PWM code
439
 ////  interrupt controlled PWM code
430
   NVIC_DisableIRQ(HAL_PWM_TIMER_IRQn);
440
   NVIC_DisableIRQ(HAL_PWM_TIMER_IRQn);
441
+
442
+  // We NEED memory barriers to ensure Interrupts are actually disabled!
443
+  // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
444
+  __DSB();
445
+  __ISB();
446
+
431
   if (!ISR_table_update)   // use the most up to date table
447
   if (!ISR_table_update)   // use the most up to date table
432
     COPY_ACTIVE_TABLE;  // copy active table into work table
448
     COPY_ACTIVE_TABLE;  // copy active table into work table
433
 
449
 
456
 
472
 
457
   NVIC_DisableIRQ(HAL_PWM_TIMER_IRQn);
473
   NVIC_DisableIRQ(HAL_PWM_TIMER_IRQn);
458
 
474
 
475
+  // We NEED memory barriers to ensure Interrupts are actually disabled!
476
+  // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
477
+  __DSB();
478
+  __ISB();
479
+
459
   bool return_flag = false;
480
   bool return_flag = false;
460
   for (uint8_t i = 0; i < NUM_ISR_PWMS; i++)         // see if it's already setup
481
   for (uint8_t i = 0; i < NUM_ISR_PWMS; i++)         // see if it's already setup
461
     if (active_table[i].pin == pin) return_flag = true;
482
     if (active_table[i].pin == pin) return_flag = true;

+ 5
- 0
Marlin/src/HAL/HAL_STM32F4/HAL_timers_STM32F4.cpp View File

123
 
123
 
124
 void HAL_timer_disable_interrupt(const uint8_t timer_num) {
124
 void HAL_timer_disable_interrupt(const uint8_t timer_num) {
125
   HAL_NVIC_DisableIRQ(timerConfig[timer_num].IRQ_Id);
125
   HAL_NVIC_DisableIRQ(timerConfig[timer_num].IRQ_Id);
126
+
127
+  // We NEED memory barriers to ensure Interrupts are actually disabled!
128
+  // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
129
+  __DSB();
130
+  __ISB();
126
 }
131
 }
127
 
132
 
128
 hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) {
133
 hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) {

+ 5
- 0
Marlin/src/HAL/HAL_STM32F7/HAL_timers_STM32F7.cpp View File

127
 
127
 
128
 void HAL_timer_disable_interrupt(const uint8_t timer_num) {
128
 void HAL_timer_disable_interrupt(const uint8_t timer_num) {
129
   HAL_NVIC_DisableIRQ(timerConfig[timer_num].IRQ_Id);
129
   HAL_NVIC_DisableIRQ(timerConfig[timer_num].IRQ_Id);
130
+
131
+  // We NEED memory barriers to ensure Interrupts are actually disabled!
132
+  // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
133
+  __DSB();
134
+  __ISB();
130
 }
135
 }
131
 
136
 
132
 hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) {
137
 hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) {

+ 21
- 0
Marlin/src/HAL/HAL_TEENSY35_36/HAL_timers_Teensy.cpp View File

29
 #include "HAL.h"
29
 #include "HAL.h"
30
 #include "HAL_timers_Teensy.h"
30
 #include "HAL_timers_Teensy.h"
31
 
31
 
32
+/** \brief Instruction Synchronization Barrier
33
+  Instruction Synchronization Barrier flushes the pipeline in the processor,
34
+  so that all instructions following the ISB are fetched from cache or
35
+  memory, after the instruction has been completed.
36
+*/
37
+FORCE_INLINE static void __ISB(void) {
38
+  __asm__ __volatile__("isb 0xF":::"memory");
39
+}
40
+
41
+/** \brief Data Synchronization Barrier
42
+  This function acts as a special kind of Data Memory Barrier.
43
+  It completes when all explicit memory accesses before this instruction complete.
44
+*/
45
+FORCE_INLINE static void __DSB(void) {
46
+  __asm__ __volatile__("dsb 0xF":::"memory");
47
+}
32
 
48
 
33
 void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
49
 void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
34
   switch (timer_num) {
50
   switch (timer_num) {
65
     case 0: NVIC_DISABLE_IRQ(IRQ_FTM0); break;
81
     case 0: NVIC_DISABLE_IRQ(IRQ_FTM0); break;
66
     case 1: NVIC_DISABLE_IRQ(IRQ_FTM1); break;
82
     case 1: NVIC_DISABLE_IRQ(IRQ_FTM1); break;
67
   }
83
   }
84
+
85
+  // We NEED memory barriers to ensure Interrupts are actually disabled!
86
+  // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
87
+  __DSB();
88
+  __ISB();
68
 }
89
 }
69
 
90
 
70
 bool HAL_timer_interrupt_enabled(const uint8_t timer_num) {
91
 bool HAL_timer_interrupt_enabled(const uint8_t timer_num) {

+ 0
- 4
Marlin/src/feature/Max7219_Debug_LEDs.cpp View File

73
 #endif
73
 #endif
74
 
74
 
75
 void Max7219_PutByte(uint8_t data) {
75
 void Max7219_PutByte(uint8_t data) {
76
-  CRITICAL_SECTION_START;
77
   for (uint8_t i = 8; i--;) {
76
   for (uint8_t i = 8; i--;) {
78
     SIG_DELAY();
77
     SIG_DELAY();
79
     WRITE(MAX7219_CLK_PIN, LOW);       // tick
78
     WRITE(MAX7219_CLK_PIN, LOW);       // tick
84
     SIG_DELAY();
83
     SIG_DELAY();
85
     data <<= 1;
84
     data <<= 1;
86
   }
85
   }
87
-  CRITICAL_SECTION_END;
88
 }
86
 }
89
 
87
 
90
 void Max7219(const uint8_t reg, const uint8_t data) {
88
 void Max7219(const uint8_t reg, const uint8_t data) {
91
   SIG_DELAY();
89
   SIG_DELAY();
92
-  CRITICAL_SECTION_START;
93
   WRITE(MAX7219_LOAD_PIN, LOW);  // begin
90
   WRITE(MAX7219_LOAD_PIN, LOW);  // begin
94
   SIG_DELAY();
91
   SIG_DELAY();
95
   Max7219_PutByte(reg);          // specify register
92
   Max7219_PutByte(reg);          // specify register
99
   WRITE(MAX7219_LOAD_PIN, LOW);  // and tell the chip to load the data
96
   WRITE(MAX7219_LOAD_PIN, LOW);  // and tell the chip to load the data
100
   SIG_DELAY();
97
   SIG_DELAY();
101
   WRITE(MAX7219_LOAD_PIN, HIGH);
98
   WRITE(MAX7219_LOAD_PIN, HIGH);
102
-  CRITICAL_SECTION_END;
103
   SIG_DELAY();
99
   SIG_DELAY();
104
 }
100
 }
105
 
101
 

+ 0
- 2
Marlin/src/module/temperature.cpp View File

1085
     watchdog_reset();
1085
     watchdog_reset();
1086
   #endif
1086
   #endif
1087
 
1087
 
1088
-  CRITICAL_SECTION_START;
1089
   temp_meas_ready = false;
1088
   temp_meas_ready = false;
1090
-  CRITICAL_SECTION_END;
1091
 }
1089
 }
1092
 
1090
 
1093
 
1091
 

Loading…
Cancel
Save