/* Tinct firmware, version ??? (no version number scheme yet) Written by Jonathan M. Guberman jonathan@upwardnotnorthward.com www.upwardnotnorthward.com Released under a Creative Commons Attribution-Noncommercial-Sharealike license Can be used and adapted for noncommercial purposes, as long as proper credit is given to the original author, and any derivatives works are released under a similar license. */ //Debugging definitions: uncomment the relevant line to turn it on //#define REDALERT 100 //Draw colour is forced to red if the serial receive buffer has more than the specified number of characters in it //#define REPORTBUFFER -1 //Sends out the current size of the Serial buffer using command ID 15 if the buffer size is greater than the defined value. Set to -1 to always report. // Serial data transfer rate #define BAUD 115200 /* Size of the serial buffer before the Tinct is forced to parse it continually. The buffer size is 128 bytes, and if it gets there the Tinct can (and will) crash. The largest command size is 9 bytes, so 119 is an absolute maximum value. Set it lower than this to be safe. If the Tinct hits this limit, it will start to flicker, and might miss commands, but it won't crash. Probably. */ #define TOOFULL 100 //TLC5940NT pin definitions #define VPRG 2 #define SIN 11 // MOSI - Hardware SPI, can't be changed #define SCLK 13 // SCK - Hardware SPI, can't be changed #define XLAT 4 #define BLANK 5 #define DCPRG 6 #define GSCLK 7 /* These pins are from the Hardware SPI, but aren't connected to the TLC5940 These definitions are only here for clarity, and aren't used. MISO can not be used for anything else, while SS can be used for any OUTPUT. It can NOT be used for an input. Currently, it is used for INCLOCKPIN, the 165's clock pin setting. */ #define MISO 12 //MISO - Hardware SPI, can't be changed (not connected, can't be used for anything other than MISO) #define SS 10 //SS - Hardware SPI, not used and therefore can be used for something else, but ONLY AS AN OUTPUT!! // Default draw colour. Each channel can be between 0 and 4095. int red = 0; /*This is the mapping of the physical position of the boards to the correct output of the TLC5940s. The left halves are rotated to correspond to the orientation of the boards*/ const byte remap[7][5] = { {6,17,24,35,42}, {5,16,23,34,41}, {4,11,22,33,40}, {3,10,21,32,39}, {2,9,20,27,38}, {1,8,19,26,37}, {0,7,18,25,36}, }; boolean A[7][5] = { {0,1,1,1,0}, {1,0,0,0,1}, {1,1,1,1,1}, {1,0,0,0,1}, {1,0,0,0,1}, {1,0,0,0,1}, {1,0,0,0,1}, }; boolean B[7][5] = { {1,1,1,1,0}, {1,0,0,0,1}, {1,1,1,1,0}, {1,0,0,0,1}, {1,0,0,0,1}, {1,0,0,0,1}, {1,1,1,1,0}, }; boolean C[7][5] = { {0,1,1,1,0}, {1,0,0,0,1}, {1,0,0,0,0}, {1,0,0,0,0}, {1,0,0,0,0}, {1,0,0,0,1}, {0,1,1,1,0}, }; boolean D[7][5] = { {1,1,1,1,0}, {1,0,0,0,1}, {1,0,0,0,1}, {1,0,0,0,1}, {1,0,0,0,1}, {1,0,0,0,1}, {1,1,1,1,0}, }; boolean E[7][5] = { {0,1,1,1,1}, {1,0,0,0,0}, {1,1,1,1,1}, {1,0,0,0,0}, {1,0,0,0,0}, {1,0,0,0,0}, {0,1,1,1,1}, }; boolean F[7][5] = { {0,1,1,1,0}, {1,0,0,0,1}, {1,1,1,1,1}, {1,0,0,0,1}, {1,0,0,0,1}, {1,0,0,0,1}, {1,0,0,0,1}, }; boolean G[7][5] = { {0,1,1,1,0}, {1,0,0,0,1}, {1,1,1,1,1}, {1,0,0,0,1}, {1,0,0,0,1}, {1,0,0,0,1}, {1,0,0,0,1}, }; boolean H[7][5] = { {0,1,1,1,0}, {1,0,0,0,1}, {1,1,1,1,1}, {1,0,0,0,1}, {1,0,0,0,1}, {1,0,0,0,1}, {1,0,0,0,1}, }; // Holds the current colour level for each of the buttons int levelR[64] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Variables for interpreting the serial commands byte tempR; byte tempC; byte lastread; byte command = 0; byte ready = true; // For interrupt timing; needed only to do intermediate clock speeds /* Divide interrupt frequency by a factor of FREQ. It is preferable to keep FREQ as small as possible, and control the frequency of the interrupts using the hardware clock. Setting it to 1 disables this entirely, which, if it works, is ideal; this should be the same as commenting out the "#define FREQ" statement entirely. */ #define FREQ 1 // How many interrupts occur before the serial commands are read #if FREQ > 1 byte int_counter = 0; #endif // Transfer a character out over hardware SPI char spi_transfer(volatile byte data) { SPDR = data; // Start the transmission while (!(SPSR & (1<=0; i--){ spi_transfer( (levelR[2*i+1] & 0x0FF0) >> 4 ); spi_transfer( ((levelR[2*i+1] & 0xF) << 4) | ((levelR[2*i] & 0x0F00) >> 8) ); spi_transfer( levelR[2*i] & 0xFF); } digitalWrite(XLAT,HIGH); digitalWrite(XLAT,LOW); digitalWrite(BLANK, LOW); } void feedPorts() { // Clock for TLC5940's PWM digitalWrite(BLANK, HIGH); digitalWrite(BLANK, LOW); //=all outputs ON, start PWM cycle for (int i=0; i<4096; i++) { pulseGSCLK(); } } void pulseGSCLK() { //ultra fast pulse trick, using digitalWrite caused flickering PORTD |= 0x80 ; // bring pin 7 high, but don't touch any of the other pins in PORTB //16 nanosecs is the min pulse width for the 5940, but no pause seems needed here PORTD &= 0x7F; // bring pin 7 low without touching the other pins in PORTB } void letra(boolean let[7][5] ) { for(byte x = 0; x < 7; ++x){ for(byte y = 0; y <5; ++y){ //levelR[remap[x][y]] = 4095; if (let[x][y]) levelR[remap[x][y]] = 500; else levelR[remap[x][y]] = 0; } } }