@@ -132,6 +132,21 @@ ICACHE_RAM_ATTR unsigned int BaseLEDMatrix::multiplier5microseconds( size_t fram
132
132
return 1 ;
133
133
}
134
134
135
+ /*
136
+ * Interrupt Handlers
137
+ *
138
+ * Here, different interrupt handlers are implemented for each kind of micro-controller.
139
+ * Pull requests for more microcontroller types are encouraged!
140
+ *
141
+ * The basic goal of the handlers is to fire the next interrupt N*5 microseconds after
142
+ * the last one interrupt ended, where N is multiple determine by the scan count. This
143
+ * requires stopping then starting the interrupts within the handler and ensure what
144
+ * happens while interrupts are off takes a consistent number of clock cycles, otherwise
145
+ * the LEDs will have uneven brightness.
146
+ *
147
+ */
148
+
149
+ #pragma mark Teensy Handlers
135
150
#if (defined(__arm__) && defined(TEENSYDUINO))
136
151
//
137
152
// On the Teensy ARM boards, use the TimerThree library to drive scan timing
@@ -168,7 +183,7 @@ unsigned int BaseLEDMatrix::nextTimerInterval(void) const {
168
183
return 5 *this ->multiplier5microseconds ( _scanPass );
169
184
}
170
185
171
-
186
+ # pragma mark ESP8266 Handlers
172
187
#elif defined ( ESP8266 )
173
188
174
189
//
@@ -213,9 +228,136 @@ ICACHE_RAM_ATTR unsigned int BaseLEDMatrix::nextTimerInterval(void) const {
213
228
return 5 *this ->multiplier5microseconds ( _scanPass );
214
229
}
215
230
216
- #elif defined(ARDUINO_SAMD_ZERO)||defined(_SAM3XA_)
217
- // no timer code for the Due or Zero yet
231
+ #pragma mark Arduino Due Handlers
232
+ #elif defined(_SAM3XA_) // Arduino Due
233
+
234
+ void BaseLEDMatrix::startScanning (void ) {
235
+ this ->setup ();
236
+
237
+ /* turn on the timer clock in the power management controller */
238
+ pmc_set_writeprotect (false ); // disable write protection for pmc registers
239
+ pmc_enable_periph_clk (ID_TC7); // enable peripheral clock TC7
240
+
241
+ /* we want wavesel 01 with RC */
242
+ TC_Configure (/* clock */ TC2,/* channel */ 1 , TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK2);
243
+ TC_SetRC (TC2, 1 , 1000 );
244
+ TC_Start (TC2, 1 );
245
+
246
+ // enable timer interrupts on the timer
247
+ TC2->TC_CHANNEL [1 ].TC_IER =TC_IER_CPCS; // IER = interrupt enable register
248
+ TC2->TC_CHANNEL [1 ].TC_IDR =~TC_IER_CPCS; // IDR = interrupt disable register
249
+
250
+ /* Enable the interrupt in the nested vector interrupt controller */
251
+ /* TC4_IRQn where 4 is the timer number * timer channels (3) + the channel number (=(1*3)+1) for timer1 channel1 */
252
+ NVIC_EnableIRQ (TC7_IRQn);
253
+
254
+ }
255
+
256
+ unsigned int BaseLEDMatrix::nextTimerInterval (void ) const {
257
+ // Calculates the microseconds for each scan
258
+ // The base interval is set to 55, which for the
259
+ // 10.5MHz CLOCK2 yields a ~5 micro second interval.
260
+ return 55 *this ->multiplier5microseconds ( _scanPass );
261
+ }
262
+
263
+ void BaseLEDMatrix::stopScanning (void ) {
264
+ NVIC_DisableIRQ (TC7_IRQn);
265
+ TC_Stop (TC2, 1 );
266
+ }
267
+
268
+ void TC7_Handler () {
269
+
270
+ TC_GetStatus (TC2, 1 );
271
+ NVIC_DisableIRQ (TC7_IRQn);
272
+ TC_Stop (TC2, 1 );
273
+
274
+ gSingleton ->shiftOutCurrentRow ();
275
+
276
+ TC_SetRC (TC2, 1 , gSingleton ->nextTimerInterval ());
277
+
278
+ NVIC_ClearPendingIRQ (TC7_IRQn);
279
+ NVIC_EnableIRQ (TC7_IRQn);
280
+ TC_Start (TC2, 1 );
281
+
282
+ gSingleton ->incrementScanRow ();
283
+ }
284
+
285
+ #pragma mark Arduino Zero Handlers
286
+ #elif defined(ARDUINO_SAMD_ZERO) // Arduino Zero
287
+
288
+ void BaseLEDMatrix::startScanning (void ) {
289
+ this ->setup ();
290
+ REG_GCLK_CLKCTRL = (uint16_t ) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID_TCC2_TC3) ;
291
+ while ( GCLK->STATUS .bit .SYNCBUSY == 1 ); // wait for sync
292
+
293
+ // The type cast must fit with the selected timer mode
294
+ TcCount16* TC = (TcCount16*) TC3; // get timer struct
295
+
296
+ TC->CTRLA .reg &= ~TC_CTRLA_ENABLE; // Disable TC
297
+ while (TC->STATUS .bit .SYNCBUSY == 1 ); // wait for sync
298
+
299
+ TC->CTRLA .reg |= TC_CTRLA_MODE_COUNT16; // Set Timer counter Mode to 16 bits
300
+ while (TC->STATUS .bit .SYNCBUSY == 1 ); // wait for sync
301
+ TC->CTRLA .reg |= TC_CTRLA_WAVEGEN_NFRQ; // Set TC as match mode
302
+ while (TC->STATUS .bit .SYNCBUSY == 1 ); // wait for sync
303
+
304
+ TC->CTRLA .reg |= TC_CTRLA_PRESCALER_DIV4; // Set perscaler
305
+ while (TC->STATUS .bit .SYNCBUSY == 1 ); // wait for sync
306
+
307
+ TC->CC [0 ].reg = 0xFFFF ;
308
+ while (TC->STATUS .bit .SYNCBUSY == 1 ); // wait for sync
309
+
310
+ // Interrupts
311
+ TC->INTENSET .reg = 0 ; // disable all interrupts
312
+ TC->INTENSET .bit .MC0 = 1 ; // enable compare match to CC0
313
+
314
+ // Enable InterruptVector
315
+ NVIC_EnableIRQ (TC3_IRQn);
316
+
317
+ // Enable TC
318
+ TC->CTRLA .reg |= TC_CTRLA_ENABLE;
319
+ while (TC->STATUS .bit .SYNCBUSY == 1 ); // wait for sync
320
+ }
321
+
322
+ unsigned int BaseLEDMatrix::nextTimerInterval (void ) const {
323
+ // Calculates the microseconds for each scan
324
+ // The base interval is set to 59, which with a /4
325
+ // prescaler should yield a 5 ms interval.
326
+ return 59 *this ->multiplier5microseconds ( _scanPass );
327
+ }
328
+
329
+ void BaseLEDMatrix::stopScanning (void ) {
330
+ TcCount16* TC = (TcCount16*) TC3; // get timer struct
331
+ TC->CTRLA .reg &= ~TC_CTRLA_ENABLE; // Disable TC
332
+ while (TC->STATUS .bit .SYNCBUSY == 1 ); // wait for sync
333
+ }
334
+
335
+ void TC3_Handler () // Interrupt Service Routine (ISR) for timer TC4
336
+ {
337
+ // Serial.println("ARDUINO_SAMD_ZERO TC3_Handler()");
338
+
339
+ TcCount16* TC = (TcCount16*) TC3; // get timer struct
340
+
341
+ TC->CTRLA .reg &= ~TC_CTRLA_ENABLE; // Disable TC
342
+ while (TC->STATUS .bit .SYNCBUSY == 1 ); // wait for sync
343
+
344
+ // shift out next row
345
+ gSingleton ->shiftOutCurrentRow ();
346
+ // reload the timer
347
+ TC->CC [0 ].reg = gSingleton ->nextTimerInterval ();
348
+ while (TC->STATUS .bit .SYNCBUSY == 1 ); // wait for sync
349
+
350
+ TC->INTFLAG .bit .MC0 = 1 ;
351
+
352
+ TC->CTRLA .reg |= TC_CTRLA_ENABLE;
353
+ while (TC->STATUS .bit .SYNCBUSY == 1 ); // wait for sync
354
+
355
+ // update scan row. Done outside of interrupt stoppage since execution time can
356
+ // be inconsistent, which would lead to vary brightness in rows.
357
+ gSingleton ->incrementScanRow ();
358
+ }
218
359
360
+ #pragma mark ATmega 8-bit Handlers
219
361
#else
220
362
//
221
363
// On normal Arduino board (Uno, Nano, etc), use the timer interrupts to drive the
0 commit comments