D:/DRISSI/arduino-0022/arduino-0022/libraries/Matrix/Matrix.cpp
00001 /*
00002   Matrix.cpp - Max7219 LED Matrix library for Arduino & Wiring
00003   Copyright (c) 2006 Nicholas Zambetti.  All right reserved.
00004 
00005   This library is free software; you can redistribute it and/or
00006   modify it under the terms of the GNU Lesser General Public
00007   License as published by the Free Software Foundation; either
00008   version 2.1 of the License, or (at your option) any later version.
00009 
00010   This library is distributed in the hope that it will be useful,
00011   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013   Lesser General Public License for more details.
00014 
00015   You should have received a copy of the GNU Lesser General Public
00016   License along with this library; if not, write to the Free Software
00017   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018 */
00019 
00020 // TODO: Support segment displays in api?
00021 // TODO: Support varying vendor layouts?
00022 
00023 /******************************************************************************
00024  * Includes
00025  ******************************************************************************/
00026 
00027 extern "C" {
00028   // AVR LibC Includes
00029   #include <inttypes.h>
00030   #include <stdlib.h>
00031 
00032   // Wiring Core Includes
00033   #undef abs
00034   #include "WConstants.h"
00035 
00036   // Wiring Core Prototypes
00037   //void pinMode(uint8_t, uint8_t);
00038   //void digitalWrite(int, uint8_t);
00039 }
00040 
00041 #include "Sprite.h"
00042 #include "Matrix.h"
00043 
00044 /******************************************************************************
00045  * Definitions
00046  ******************************************************************************/
00047 
00048 // Matrix registers
00049 #define REG_NOOP   0x00
00050 #define REG_DIGIT0 0x01
00051 #define REG_DIGIT1 0x02
00052 #define REG_DIGIT2 0x03
00053 #define REG_DIGIT3 0x04
00054 #define REG_DIGIT4 0x05
00055 #define REG_DIGIT5 0x06
00056 #define REG_DIGIT6 0x07
00057 #define REG_DIGIT7 0x08
00058 #define REG_DECODEMODE  0x09
00059 #define REG_INTENSITY   0x0A
00060 #define REG_SCANLIMIT   0x0B
00061 #define REG_SHUTDOWN    0x0C
00062 #define REG_DISPLAYTEST 0x0F
00063 
00064 /******************************************************************************
00065  * Constructors
00066  ******************************************************************************/
00067 
00068 Matrix::Matrix(uint8_t data, uint8_t clock, uint8_t load, uint8_t screens /* = 1 */)
00069 {
00070   // record pins for sw spi
00071   _pinData = data;
00072   _pinClock = clock;
00073   _pinLoad = load;
00074 
00075   // set ddr for sw spi pins
00076   pinMode(_pinClock, OUTPUT);
00077   pinMode(_pinData, OUTPUT);
00078   pinMode(_pinLoad, OUTPUT);
00079 
00080   // allocate screenbuffers
00081   _screens = screens;
00082   _buffer = (uint8_t*)calloc(_screens, 64);
00083   _maximumX = (_screens * 8);
00084 
00085   // initialize registers
00086   clear();             // clear display
00087   setScanLimit(0x07);  // use all rows/digits
00088   setBrightness(0x0F); // maximum brightness
00089   setRegister(REG_SHUTDOWN, 0x01);    // normal operation
00090   setRegister(REG_DECODEMODE, 0x00);  // pixels not integers
00091   setRegister(REG_DISPLAYTEST, 0x00); // not in test mode
00092 }
00093 
00094 /******************************************************************************
00095  * MAX7219 SPI
00096  ******************************************************************************/
00097 
00098 // sends a single byte by sw spi (no latching)
00099 void Matrix::putByte(uint8_t data)
00100 {
00101   uint8_t i = 8;
00102   uint8_t mask;
00103   while(i > 0) {
00104     mask = 0x01 << (i - 1);         // get bitmask
00105     digitalWrite(_pinClock, LOW);   // tick
00106     if (data & mask){               // choose bit
00107       digitalWrite(_pinData, HIGH); // set 1
00108     }else{
00109       digitalWrite(_pinData, LOW);  // set 0
00110     }
00111     digitalWrite(_pinClock, HIGH);  // tock
00112     --i;                            // move to lesser bit
00113   }
00114 }
00115 
00116 // sets register to a byte value for all screens
00117 void Matrix::setRegister(uint8_t reg, uint8_t data)
00118 {
00119   digitalWrite(_pinLoad, LOW); // begin
00120   for(uint8_t i = 0; i < _screens; ++i){
00121     putByte(reg);  // specify register
00122     putByte(data); // send data
00123   }
00124   digitalWrite(_pinLoad, HIGH);  // latch in data
00125   digitalWrite(_pinLoad, LOW); // end
00126 }
00127 
00128 // syncs row of display with buffer
00129 void Matrix::syncRow(uint8_t row)
00130 {
00131   if (!_buffer) return;
00132   
00133   // uint8_t's can't be negative, so don't test for negative row
00134   if (row >= 8) return;
00135   digitalWrite(_pinLoad, LOW); // begin
00136   for(uint8_t i = 0; i < _screens; ++i){
00137     putByte(8 - row);                // specify register
00138     putByte(_buffer[row + (8 * i)]); // send data
00139   }
00140   digitalWrite(_pinLoad, HIGH);  // latch in data
00141   digitalWrite(_pinLoad, LOW); // end
00142 }
00143 
00144 /******************************************************************************
00145  * MAX7219 Configuration
00146  ******************************************************************************/
00147 
00148 // sets how many digits are displayed
00149 void Matrix::setScanLimit(uint8_t value)
00150 {
00151   setRegister(REG_SCANLIMIT, value & 0x07);
00152 }
00153 
00154 // sets brightness of the display
00155 void Matrix::setBrightness(uint8_t value)
00156 {
00157   setRegister(REG_INTENSITY, value & 0x0F);
00158 }
00159 
00160 /******************************************************************************
00161  * Helper Functions
00162  ******************************************************************************/
00163 
00164 void Matrix::buffer(uint8_t x, uint8_t y, uint8_t value)
00165 {
00166   if (!_buffer) return;
00167   
00168   // uint8_t's can't be negative, so don't test for negative x and y.
00169   if (x >= _maximumX || y >= 8) return;
00170 
00171   uint8_t offset = x; // record x
00172   x %= 8;             // make x relative to a single matrix
00173   offset -= x;        // calculate buffer offset
00174 
00175   // wrap shift relative x for nexus module layout
00176   if (x == 0){
00177     x = 8;
00178   }
00179   --x;
00180 
00181   // record value in buffer
00182   if(value){
00183     _buffer[y + offset] |= 0x01 << x;
00184   }else{
00185     _buffer[y + offset] &= ~(0x01 << x);
00186   }
00187 }
00188 
00189 /******************************************************************************
00190  * User API
00191  ******************************************************************************/
00192 
00193 // buffers and writes to screen
00194 void Matrix::write(uint8_t x, uint8_t y, uint8_t value)
00195 {
00196   buffer(x, y, value);
00197   
00198   // update affected row
00199   syncRow(y);
00200 }
00201 
00202 void Matrix::write(uint8_t x, uint8_t y, Sprite sprite)
00203 {
00204   for (uint8_t i = 0; i < sprite.height(); i++){
00205     for (uint8_t j = 0; j < sprite.width(); j++)
00206       buffer(x + j, y + i, sprite.read(j, i));
00207       
00208     syncRow(y + i);
00209   }
00210 }
00211 
00212 // clears screens and buffers
00213 void Matrix::clear(void)
00214 {
00215   if (!_buffer) return;
00216 
00217   // clear buffer
00218   for(uint8_t i = 0; i < 8; ++i){
00219     for(uint8_t j = 0; j < _screens; ++j){
00220       _buffer[i + (8 * j)] = 0x00;
00221     }
00222   }
00223 
00224   // clear registers
00225   for(uint8_t i = 0; i < 8; ++i){
00226     syncRow(i);
00227   }
00228 }
00229