Browse Source

Use assembly for AVR ISR vectors

Co-Authored-By: ejtagle <ejtagle@hotmail.com>
Scott Lahteine 7 years ago
parent
commit
c2fb2f54a1
1 changed files with 142 additions and 18 deletions
  1. 142
    18
      Marlin/src/HAL/HAL_AVR/HAL.h

+ 142
- 18
Marlin/src/HAL/HAL_AVR/HAL.h View File

@@ -162,24 +162,148 @@ extern "C" {
162 162
  * (otherwise, characters will be lost due to UART overflow).
163 163
  * Then: Stepper, Endstops, Temperature, and -finally- all others.
164 164
  */
165
-#define HAL_timer_isr_prologue_0 do{ DISABLE_TEMPERATURE_INTERRUPT(); sei(); }while(0)
166
-#define HAL_timer_isr_epilogue_0 do{ cli(); ENABLE_TEMPERATURE_INTERRUPT(); }while(0)
167
-
168
-#define HAL_timer_isr_prologue_1 \
169
-  const bool temp_isr_was_enabled = TEMPERATURE_ISR_ENABLED(); \
170
-  do{ \
171
-    DISABLE_TEMPERATURE_INTERRUPT(); \
172
-    DISABLE_STEPPER_DRIVER_INTERRUPT(); \
173
-    sei(); \
174
-  }while(0)
175
-
176
-#define HAL_timer_isr_epilogue_1 do{ cli(); ENABLE_STEPPER_DRIVER_INTERRUPT(); if (temp_isr_was_enabled) ENABLE_TEMPERATURE_INTERRUPT(); }while(0)
177
-
178
-#define HAL_timer_isr_prologue(TIMER_NUM) _CAT(HAL_timer_isr_prologue_, TIMER_NUM)
179
-#define HAL_timer_isr_epilogue(TIMER_NUM) _CAT(HAL_timer_isr_epilogue_, TIMER_NUM)
180
-
181
-#define HAL_STEP_TIMER_ISR ISR(TIMER1_COMPA_vect)
182
-#define HAL_TEMP_TIMER_ISR ISR(TIMER0_COMPB_vect)
165
+#define HAL_timer_isr_prologue(TIMER_NUM)
166
+#define HAL_timer_isr_epilogue(TIMER_NUM)
167
+
168
+/* 18 cycles maximum latency */
169
+#define HAL_STEP_TIMER_ISR \
170
+extern "C" void TIMER1_COMPA_vect (void) __attribute__ ((signal, naked, used, externally_visible)); \
171
+extern "C" void TIMER1_COMPA_vect_bottom (void) asm ("TIMER1_COMPA_vect_bottom") __attribute__ ((used, externally_visible, noinline)); \
172
+void TIMER1_COMPA_vect (void) { \
173
+  __asm__ __volatile__ ( \
174
+    A("push r16")                      /* 2 Save R16 */ \
175
+    A("in r16, __SREG__")              /* 1 Get SREG */ \
176
+    A("push r16")                      /* 2 Save SREG into stack */ \
177
+    A("lds r16, %[timsk0]")            /* 2 Load into R0 the Temperature timer Interrupt mask register */ \
178
+    A("push r16")                      /* 2 Save TIMSK0 into the stack */ \
179
+    A("andi r16,~%[msk0]")             /* 1 Disable the temperature ISR */ \
180
+    A("sts %[timsk0], r16")            /* 2 And set the new value */ \
181
+    A("lds r16, %[timsk1]")            /* 2 Load into R0 the stepper timer Interrupt mask register [TIMSK1] */ \
182
+    A("andi r16,~%[msk1]")             /* 1 Disable the stepper ISR */ \
183
+    A("sts %[timsk1], r16")            /* 2 And set the new value */ \
184
+    A("sei")                           /* 1 Enable global interrupts - stepper and temperature ISRs are disabled, so no risk of reentry or being preempted by the temperature ISR */    \
185
+    A("push r16")                      /* 2 Save TIMSK1 into stack */ \
186
+    A("in r16, 0x3B")                  /* 1 Get RAMPZ register */ \
187
+    A("push r16")                      /* 2 Save RAMPZ into stack */ \
188
+    A("in r16, 0x3C")                  /* 1 Get EIND register */ \
189
+    A("push r0")                       /* C runtime can modify all the following registers without restoring them */ \
190
+    A("push r1")                       \
191
+    A("push r18")                      \
192
+    A("push r19")                      \
193
+    A("push r20")                      \
194
+    A("push r21")                      \
195
+    A("push r22")                      \
196
+    A("push r23")                      \
197
+    A("push r24")                      \
198
+    A("push r25")                      \
199
+    A("push r26")                      \
200
+    A("push r27")                      \
201
+    A("push r30")                      \
202
+    A("push r31")                      \
203
+    A("clr r1")                        /* C runtime expects this register to be 0 */ \
204
+    A("call TIMER1_COMPA_vect_bottom") /* Call the bottom handler - No inlining allowed, otherwise registers used are not saved */   \
205
+    A("pop r31")                       \
206
+    A("pop r30")                       \
207
+    A("pop r27")                       \
208
+    A("pop r26")                       \
209
+    A("pop r25")                       \
210
+    A("pop r24")                       \
211
+    A("pop r23")                       \
212
+    A("pop r22")                       \
213
+    A("pop r21")                       \
214
+    A("pop r20")                       \
215
+    A("pop r19")                       \
216
+    A("pop r18")                       \
217
+    A("pop r1")                        \
218
+    A("pop r0")                        \
219
+    A("out 0x3C, r16")                 /* 1 Restore EIND register */ \
220
+    A("pop r16")                       /* 2 Get the original RAMPZ register value */ \
221
+    A("out 0x3B, r16")                 /* 1 Restore RAMPZ register to its original value */ \
222
+    A("pop r16")                       /* 2 Get the original TIMSK1 value but with stepper ISR disabled */ \
223
+    A("ori r16,%[msk1]")               /* 1 Reenable the stepper ISR */ \
224
+    A("cli")                           /* 1 Disable global interrupts - Reenabling Stepper ISR can reenter amd temperature can reenter, and we want that, if it happens, after this ISR has ended */ \
225
+    A("sts %[timsk1], r16")            /* 2 And restore the old value - This reenables the stepper ISR */ \
226
+    A("pop r16")                       /* 2 Get the temperature timer Interrupt mask register [TIMSK0] */ \
227
+    A("sts %[timsk0], r16")            /* 2 And restore the old value - This reenables the temperature ISR */ \
228
+    A("pop r16")                       /* 2 Get the old SREG value */ \
229
+    A("out __SREG__, r16")             /* 1 And restore the SREG value */ \
230
+    A("pop r16")                       /* 2 Restore R16 value */ \
231
+    A("reti")                          /* 4 Return from interrupt */ \
232
+    :                                   \
233
+    : [timsk0] "i" ((uint16_t)&TIMSK0), \
234
+      [timsk1] "i" ((uint16_t)&TIMSK1), \
235
+      [msk0] "M" ((uint8_t)(1<<OCIE0B)),\
236
+      [msk1] "M" ((uint8_t)(1<<OCIE1A)) \
237
+    : \
238
+  ); \
239
+} \
240
+void TIMER1_COMPA_vect_bottom(void)
241
+
242
+/* 14 cycles maximum latency */
243
+#define HAL_TEMP_TIMER_ISR \
244
+extern "C" void TIMER0_COMPB_vect (void) __attribute__ ((signal, naked, used, externally_visible)); \
245
+extern "C" void TIMER0_COMPB_vect_bottom(void)  asm ("TIMER0_COMPB_vect_bottom") __attribute__ ((used, externally_visible, noinline)); \
246
+void TIMER0_COMPB_vect (void) { \
247
+  __asm__ __volatile__ ( \
248
+    A("push r16")                       /* 2 Save R16 */ \
249
+    A("in r16, __SREG__")               /* 1 Get SREG */ \
250
+    A("push r16")                       /* 2 Save SREG into stack */ \
251
+    A("lds r16, %[timsk0]")             /* 2 Load into R0 the Temperature timer Interrupt mask register */ \
252
+    A("andi r16,~%[msk0]")              /* 1 Disable the temperature ISR */ \
253
+    A("sts %[timsk0], r16")             /* 2 And set the new value */ \
254
+    A("sei")                            /* 1 Enable global interrupts - It is safe, as the temperature ISR is disabled, so we cannot reenter it */    \
255
+    A("push r16")                       /* 2 Save TIMSK0 into stack */ \
256
+    A("in r16, 0x3B")                   /* 1 Get RAMPZ register */ \
257
+    A("push r16")                       /* 2 Save RAMPZ into stack */ \
258
+    A("in r16, 0x3C")                   /* 1 Get EIND register */ \
259
+    A("push r0")                        /* C runtime can modify all the following registers without restoring them */ \
260
+    A("push r1")                        \
261
+    A("push r18")                       \
262
+    A("push r19")                       \
263
+    A("push r20")                       \
264
+    A("push r21")                       \
265
+    A("push r22")                       \
266
+    A("push r23")                       \
267
+    A("push r24")                       \
268
+    A("push r25")                       \
269
+    A("push r26")                       \
270
+    A("push r27")                       \
271
+    A("push r30")                       \
272
+    A("push r31")                       \
273
+    A("clr r1")                         /* C runtime expects this register to be 0 */ \
274
+    A("call TIMER0_COMPB_vect_bottom")  /* Call the bottom handler - No inlining allowed, otherwise registers used are not saved */   \
275
+    A("pop r31")                        \
276
+    A("pop r30")                        \
277
+    A("pop r27")                        \
278
+    A("pop r26")                        \
279
+    A("pop r25")                        \
280
+    A("pop r24")                        \
281
+    A("pop r23")                        \
282
+    A("pop r22")                        \
283
+    A("pop r21")                        \
284
+    A("pop r20")                        \
285
+    A("pop r19")                        \
286
+    A("pop r18")                        \
287
+    A("pop r1")                         \
288
+    A("pop r0")                         \
289
+    A("out 0x3C, r16")                  /* 1 Restore EIND register */ \
290
+    A("pop r16")                        /* 2 Get the original RAMPZ register value */ \
291
+    A("out 0x3B, r16")                  /* 1 Restore RAMPZ register to its original value */ \
292
+    A("pop r16")                        /* 2 Get the original TIMSK0 value but with temperature ISR disabled */ \
293
+    A("ori r16,%[msk0]")                /* 1 Enable temperature ISR */ \
294
+    A("cli")                            /* 1 Disable global interrupts - We must do this, as we will reenable the temperature ISR, and we don´t want to reenter this handler until the current one is done */ \
295
+    A("sts %[timsk0], r16")             /* 2 And restore the old value */ \
296
+    A("pop r16")                        /* 2 Get the old SREG */ \
297
+    A("out __SREG__, r16")              /* 1 And restore the SREG value */ \
298
+    A("pop r16")                        /* 2 Restore R16 */ \
299
+    A("reti")                           /* 4 Return from interrupt */ \
300
+    :                                   \
301
+    : [timsk0] "i"((uint16_t)&TIMSK0),  \
302
+      [msk0] "M" ((uint8_t)(1<<OCIE0B)) \
303
+    : \
304
+  ); \
305
+} \
306
+void TIMER0_COMPB_vect_bottom(void)
183 307
 
184 308
 // ADC
185 309
 #ifdef DIDR2

Loading…
Cancel
Save