Skip to content

Commit 9ecce97

Browse files
added support for Arduino Zero and Due
1 parent 227a4f4 commit 9ecce97

File tree

7 files changed

+181
-29
lines changed

7 files changed

+181
-29
lines changed

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
66

77
## [Unreleased]
88

9-
###Changed
9+
### Changed
1010
- Refactored the image classes to have a common, templated base class. This consolidates similar logic to a single location.
1111

12+
### Added
13+
- Added support for the Arduino Zero and Due boards (and related)
1214

1315
## [1.0.1] - 2017-12-24
16+
### Changed
17+
- Adjusted the aesthetics of the classic plasma visualization example code
18+
1419
### Fixed
1520
- Corrected failure to compile for boards that can only use 6-bit color.
1621

examples/plasma-10x10/plasma-10x10.ino

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,30 +42,30 @@ void drawPlasma( unsigned long counter ) {
4242
for (int row = 0; row < leds.rows(); row++ ) {
4343
float y = ((float)row/((float)leds.rows()*SPACE_STRETCH_FACTOR)) - 0.5;
4444

45-
float v1 = sin(x*10.0+utime);
46-
float v2 = sin(10.0*(x*sin(utime/2.0) + y*cos(utime/3.0)) + utime);
45+
float v1 = sinf(x*10.0+utime);
46+
float v2 = sinf(10.0*(x*sinf(utime/2.0) + y*cosf(utime/3.0)) + utime);
4747

48-
float cx = x + 0.5*sin(utime/5.0);
49-
float cy = y + 0.5*cos(utime/3.0);
50-
float v3 = sin( sqrt(100.0*(cx*cx + cy*cy) + 1.0) + utime );
48+
float cx = x + 0.5*sinf(utime/5.0);
49+
float cy = y + 0.5*cosf(utime/3.0);
50+
float v3 = sinf( sqrtf(100.0*(cx*cx + cy*cy) + 1.0) + utime );
5151

5252
float v = v1+v2+v3;
5353

5454
int r, g, b;
5555
switch (COLOR_SCHEME) {
5656
default:
5757
case 1:
58-
r = mapSineToRange(sin(v*PI), 255);
59-
g = mapSineToRange(sin(v*PI + 2.0*PI/3.0), 255);
60-
b = mapSineToRange(sin(v*PI + 4.0*PI/3.0), 255);
58+
r = mapSineToRange(sinf(v*PI), 255);
59+
g = mapSineToRange(sinf(v*PI + 2.0*PI/3.0), 255);
60+
b = mapSineToRange(sinf(v*PI + 4.0*PI/3.0), 255);
6161
break;
6262
case 2:
6363
r = 255;
64-
g = mapSineToRange(cos(v*PI), 255);
65-
b = mapSineToRange(sin(v*PI), 255);
64+
g = mapSineToRange(cosf(v*PI), 255);
65+
b = mapSineToRange(sinf(v*PI), 255);
6666
break;
6767
case 3:
68-
r = g = b = mapSineToRange(sin(v*5.0*PI), 255);
68+
r = g = b = mapSineToRange(sinf(v*5.0*PI), 255);
6969
break;
7070
}
7171

examples/plasma-8x8/plasma-8x8.ino

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,30 +42,30 @@ void drawPlasma( unsigned long counter ) {
4242
for (int row = 0; row < leds.rows(); row++ ) {
4343
float y = ((float)row/((float)leds.rows()*SPACE_STRETCH_FACTOR)) - 0.5;
4444

45-
float v1 = sin(x*10.0+utime);
46-
float v2 = sin(10.0*(x*sin(utime/2.0) + y*cos(utime/3.0)) + utime);
45+
float v1 = sinf(x*10.0+utime);
46+
float v2 = sinf(10.0*(x*sinf(utime/2.0) + y*cosf(utime/3.0)) + utime);
4747

48-
float cx = x + 0.5*sin(utime/5.0);
49-
float cy = y + 0.5*cos(utime/3.0);
50-
float v3 = sin( sqrt(100.0*(cx*cx + cy*cy) + 1.0) + utime );
48+
float cx = x + 0.5*sinf(utime/5.0);
49+
float cy = y + 0.5*cosf(utime/3.0);
50+
float v3 = sinf( sqrtf(100.0*(cx*cx + cy*cy) + 1.0) + utime );
5151

5252
float v = v1+v2+v3;
5353

5454
int r, g, b;
5555
switch (COLOR_SCHEME) {
5656
default:
5757
case 1:
58-
r = mapSineToRange(sin(v*PI), 255);
59-
g = mapSineToRange(sin(v*PI + 2.0*PI/3.0), 255);
60-
b = mapSineToRange(sin(v*PI + 4.0*PI/3.0), 255);
58+
r = mapSineToRange(sinf(v*PI), 255);
59+
g = mapSineToRange(sinf(v*PI + 2.0*PI/3.0), 255);
60+
b = mapSineToRange(sinf(v*PI + 4.0*PI/3.0), 255);
6161
break;
6262
case 2:
6363
r = 255;
64-
g = mapSineToRange(cos(v*PI), 255);
65-
b = mapSineToRange(sin(v*PI), 255);
64+
g = mapSineToRange(cosf(v*PI), 255);
65+
b = mapSineToRange(sinf(v*PI), 255);
6666
break;
6767
case 3:
68-
r = g = b = mapSineToRange(sin(v*5.0*PI), 255);
68+
r = g = b = mapSineToRange(sinf(v*5.0*PI), 255);
6969
break;
7070
}
7171

src/BaseLEDMatrix.cpp

Lines changed: 145 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,21 @@ ICACHE_RAM_ATTR unsigned int BaseLEDMatrix::multiplier5microseconds( size_t fram
132132
return 1;
133133
}
134134

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
135150
#if (defined(__arm__) && defined(TEENSYDUINO))
136151
//
137152
// On the Teensy ARM boards, use the TimerThree library to drive scan timing
@@ -168,7 +183,7 @@ unsigned int BaseLEDMatrix::nextTimerInterval(void) const {
168183
return 5*this->multiplier5microseconds( _scanPass );
169184
}
170185

171-
186+
#pragma mark ESP8266 Handlers
172187
#elif defined ( ESP8266 )
173188

174189
//
@@ -213,9 +228,136 @@ ICACHE_RAM_ATTR unsigned int BaseLEDMatrix::nextTimerInterval(void) const {
213228
return 5*this->multiplier5microseconds( _scanPass );
214229
}
215230

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+
}
218359

360+
#pragma mark ATmega 8-bit Handlers
219361
#else
220362
//
221363
// On normal Arduino board (Uno, Nano, etc), use the timer interrupts to drive the

src/LEDImage.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ LEDImage<PixelType>::~LEDImage() {
161161
}
162162

163163

164-
#pragma mark MutableRGBImage
164+
#pragma mark MutableLEDImage
165165

166166
template <class PixelType, PixelType LEDBlackColor, PixelType LEDTransparentColor>
167167
class MutableLEDImage : public LEDImageBase<PixelType> {
@@ -193,6 +193,7 @@ class MutableLEDImage : public LEDImageBase<PixelType> {
193193

194194
void copy(const LEDImageBase<PixelType>& other);
195195

196+
using LEDImageBase<PixelType>::pixel;
196197
PixelType& pixel( int row, int column );
197198

198199
void placeImageAt( const LEDImageBase<PixelType>& image, int row, int column );

src/RGBColor.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@
2020
#include <Arduino.h>
2121

2222
#ifndef TWELVE_BIT_COLOR
23-
#define TWELVE_BIT_COLOR (defined(__arm__) && defined(TEENSYDUINO))||defined(__AVR_ATmega2560__)||defined ( ESP8266 )
23+
#define TWELVE_BIT_COLOR (defined(__arm__)&& defined(TEENSYDUINO)) \
24+
||defined(__AVR_ATmega2560__) \
25+
||defined ( ESP8266 ) \
26+
||defined(ARDUINO_SAMD_ZERO) \
27+
||defined(_SAM3XA_)
2428
#endif
2529

2630
#if TWELVE_BIT_COLOR

src/RGBLEDMatrix.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ void RGBLEDMatrix::setRowBitsForFrame(
210210
}
211211
for (unsigned int col = 0; col < this->columns(); col++) {
212212
RGBColorType rgbValue = image.pixel(row, col);
213-
213+
214214
// a form of Binary Code Modulation is used to control
215215
// the LED intensity at variou levels.
216216

0 commit comments

Comments
 (0)