diff --git a/CHANGES.txt b/CHANGES.txt new file mode 100644 index 0000000..048f11e --- /dev/null +++ b/CHANGES.txt @@ -0,0 +1,5 @@ +Version 1 + +- initial release. + High speed SPI direct connection mode with many support functions, two example projects included, dmd_demo and dmd_clock_readout + diff --git a/DMD.cpp b/DMD.cpp new file mode 100644 index 0000000..62952bc --- /dev/null +++ b/DMD.cpp @@ -0,0 +1,488 @@ +/*-------------------------------------------------------------------------------------- + + DMD.cpp - Function and support library for the Freetronics DMD, a 512 LED matrix display + panel arranged in a 32 x 16 layout. + + Copyright (C) 2011 Marc Alexander (info freetronics com) + + Note that the DMD library uses the SPI port for the fastest, low overhead writing to the + display. Keep an eye on conflicts if there are any other devices running from the same + SPI port, and that the chip select on those devices is correctly set to be inactive + when the DMD is being written to. + + --- + + This program is free software: you can redistribute it and/or modify it under the terms + of the version 3 GNU General Public License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program. + If not, see . + +--------------------------------------------------------------------------------------*/ +#include "DMD.h" +// DMD Library fonts +#include "DMD_Fonts.c" + +/*-------------------------------------------------------------------------------------- + Setup and instantiation of DMD library + Note this currently uses the SPI port for the fastest performance to the DMD, be + careful of possible conflicts with other SPI port devices +--------------------------------------------------------------------------------------*/ +DMD::DMD() +{ + uint16_t ui; + + // initialize the SPI port + SPI.begin(); // probably don't need this since it inits the port pins only, which we do just below with the appropriate DMD interface setup + SPI.setBitOrder(MSBFIRST); // + SPI.setDataMode(SPI_MODE0); // CPOL=0, CPHA=0 + SPI.setClockDivider(SPI_CLOCK_DIV128); // system clock / 2 = 8MHz SPI CLK to shift registers + + digitalWrite( PIN_DMD_A, LOW ); // + digitalWrite( PIN_DMD_B, LOW ); // + digitalWrite( PIN_DMD_CLK, LOW ); // + digitalWrite( PIN_DMD_SCLK, LOW ); // + digitalWrite( PIN_DMD_R_DATA, HIGH ); // + digitalWrite( PIN_DMD_nOE, LOW ); // + + pinMode( PIN_DMD_A, OUTPUT ); // + pinMode( PIN_DMD_B, OUTPUT ); // + pinMode( PIN_DMD_CLK, OUTPUT ); // + pinMode( PIN_DMD_SCLK, OUTPUT ); // + pinMode( PIN_DMD_R_DATA, OUTPUT ); // + pinMode( PIN_DMD_nOE, OUTPUT ); // + + clearScreen( true ); + + // init the scan line/ram pointer to the required start point + bDMDByte = 48; +} +//DMD::~DMD() +//{ +// // nothing needed here +//} + +/*-------------------------------------------------------------------------------------- + Set or clear a pixel at the x and y location (0,0 is the top left corner) +--------------------------------------------------------------------------------------*/ +void DMD::writePixel( byte bX, byte bY, byte bGraphicsMode, byte bPixel ) +{ + unsigned int uiDMDRAMPointer; + + //set pointer to DMD RAM byte to be modified + uiDMDRAMPointer = (bX >> 3) + // /8 pixels per byte + (bY << 2); // x4 bytes for X + + switch( bGraphicsMode ) + { + case GRAPHICS_NORMAL: + { + if( bPixel == true ) + bDMDScreenRAM[uiDMDRAMPointer] &= ~(bPixelLookupTable[ bX & 0x07 ]); // zero bit is pixel on + else + bDMDScreenRAM[uiDMDRAMPointer] |= (bPixelLookupTable[ bX & 0x07 ]); // one bit is pixel off + break; + } + case GRAPHICS_INVERSE: + { + if( bPixel == false ) + bDMDScreenRAM[uiDMDRAMPointer] &= ~(bPixelLookupTable[ bX & 0x07 ]); // zero bit is pixel on + else + bDMDScreenRAM[uiDMDRAMPointer] |= (bPixelLookupTable[ bX & 0x07 ]); // one bit is pixel off + break; + } + case GRAPHICS_TOGGLE: + { + if( bPixel == true ) + { + if( (bDMDScreenRAM[uiDMDRAMPointer] & (bPixelLookupTable[ bX & 0x07 ])) == 0 ) + bDMDScreenRAM[uiDMDRAMPointer] |= (bPixelLookupTable[ bX & 0x07 ]);// one bit is pixel off + else + bDMDScreenRAM[uiDMDRAMPointer] &= ~(bPixelLookupTable[ bX & 0x07 ]);// one bit is pixel off + } + break; + } + case GRAPHICS_OR: + { + //only set pixels on + if( bPixel == true ) + bDMDScreenRAM[uiDMDRAMPointer] &= ~(bPixelLookupTable[ bX & 0x07 ]); // zero bit is pixel on + break; + } + case GRAPHICS_NOR: + { + //only clear on pixels + if( ( bPixel == true ) && ( (bDMDScreenRAM[uiDMDRAMPointer] & (bPixelLookupTable[ bX & 0x07 ])) == 0 ) ) + bDMDScreenRAM[uiDMDRAMPointer] |= (bPixelLookupTable[ bX & 0x07 ]); // one bit is pixel off + break; + } + } + +} + +/*-------------------------------------------------------------------------------------- + Draw a character with the 5 x 7 font table at the x and y location. bSet true is on, false is inverted +--------------------------------------------------------------------------------------*/ +void DMD::drawCharacter_5x7( byte bX, byte bY, byte bChar, byte bGraphicsMode ) +{ + byte x, y, w; + + w = FONT5X7WIDTH; + for( y = 0 ; y < FONT5X7HEIGHT ; y++ ) + { + for( x = 0 ; x < FONT5X7WIDTH ; x++ ) + { + w--; + if( ((( pgm_read_byte( &bDMDFont_5x7[((bChar-0x20)*FONT5X7HEIGHT)+y] ) ) >> w) & 0x01) != 0 ) + { + // pixel is on in font table + writePixel( bX+x, bY+y, bGraphicsMode, true ); + } + else + { + // pixel is off in font table + writePixel( bX+x, bY+y, bGraphicsMode, false ); + } + if( w == 0 ) + w = FONT5X7WIDTH; + } + } +} + +/*-------------------------------------------------------------------------------------- + Draw a character with the 6 x 16 font table at the x and y location. bSet true is on, false is inverted + The 6 x 16 font table is designed to be good for large clock and 4 digit number displays with a colon in the centre +--------------------------------------------------------------------------------------*/ +void DMD::drawCharacter_6x16( byte bX, byte bY, byte bChar, byte bGraphicsMode ) +{ + byte x, y, w; + + w = FONT6X16WIDTH; + for( y = 0 ; y < FONT6X16HEIGHT ; y++ ) + { + for( x = 0 ; x < FONT6X16WIDTH ; x++ ) + { + w--; + if( ((( pgm_read_byte( &bDMDFont_6x16[((bChar-0x2B)*FONT6X16HEIGHT)+y] ) ) >> w) & 0x01) != 0 ) + { + // pixel is on in font table + writePixel( bX+x, bY+y, bGraphicsMode, true ); + } + else + { + // pixel is off in font table + writePixel( bX+x, bY+y, bGraphicsMode, false ); + } + if( w == 0 ) + w = FONT6X16WIDTH; + } + } +} + +/*-------------------------------------------------------------------------------------- + Clear the screen in DMD RAM +--------------------------------------------------------------------------------------*/ +void DMD::clearScreen( byte bNormal ) +{ + unsigned int ui; + byte b; + + if( bNormal ) + b = 0xFF; // clear all pixels + else + b = 0x00; // set all pixels + + //initialise the DMD RAM with all pixels off (0xFF) + for( ui = 0 ; ui < DMD_RAM_SIZE_BYTES ; ui++ ) + { + bDMDScreenRAM[ui] = b; // Note: 0x00 is all pixels ON, 0xFF is all pixels OFF. + } + +} + +/*-------------------------------------------------------------------------------------- + Draw or clear a line from x1,y1 to x2,y2 +--------------------------------------------------------------------------------------*/ +void DMD::drawLine( byte x1, byte y1, byte x2, byte y2, byte bGraphicsMode ) +{ + int dy = y2 - y1; + int dx = x2 - x1; + int stepx, stepy; + + if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; } + if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; } + dy <<= 1; // dy is now 2*dy + dx <<= 1; // dx is now 2*dx + + writePixel( x1, y1, bGraphicsMode, true ); + if (dx > dy) + { + int fraction = dy - (dx >> 1); // same as 2*dy - dx + while (x1 != x2) + { + if (fraction >= 0) + { + y1 += stepy; + fraction -= dx; // same as fraction -= 2*dx + } + x1 += stepx; + fraction += dy; // same as fraction -= 2*dy + writePixel( x1, y1, bGraphicsMode, true ); + } + } + else + { + int fraction = dx - (dy >> 1); + while (y1 != y2) + { + if (fraction >= 0) + { + x1 += stepx; + fraction -= dy; + } + y1 += stepy; + fraction += dx; + writePixel( x1, y1, bGraphicsMode, true ); + } + } +} + +/*-------------------------------------------------------------------------------------- + Draw or clear a circle of radius r at x,y centre +--------------------------------------------------------------------------------------*/ +void DMD::drawCircle( int xCenter, int yCenter, int radius, byte bGraphicsMode ) +{ + int x = 0; + int y = radius; + int p = (5 - radius*4)/4; + + drawCircleSub( xCenter, yCenter, x, y, bGraphicsMode ); + while (x < y) + { + x++; + if (p < 0) + { + p += 2*x+1; + } + else + { + y--; + p += 2*(x-y)+1; + } + drawCircleSub( xCenter, yCenter, x, y, bGraphicsMode ); + } +} +void DMD::drawCircleSub( int cx, int cy, int x, int y, byte bGraphicsMode ) +{ + + if (x == 0) + { + writePixel( cx, cy + y, bGraphicsMode, true ); + writePixel( cx, cy - y, bGraphicsMode, true ); + writePixel( cx + y, cy, bGraphicsMode, true ); + writePixel( cx - y, cy, bGraphicsMode, true ); + } + else if (x == y) + { + writePixel( cx + x, cy + y, bGraphicsMode, true ); + writePixel( cx - x, cy + y, bGraphicsMode, true ); + writePixel( cx + x, cy - y, bGraphicsMode, true ); + writePixel( cx - x, cy - y, bGraphicsMode, true ); + } + else if (x < y) + { + writePixel( cx + x, cy + y, bGraphicsMode, true ); + writePixel( cx - x, cy + y, bGraphicsMode, true ); + writePixel( cx + x, cy - y, bGraphicsMode, true ); + writePixel( cx - x, cy - y, bGraphicsMode, true ); + writePixel( cx + y, cy + x, bGraphicsMode, true ); + writePixel( cx - y, cy + x, bGraphicsMode, true ); + writePixel( cx + y, cy - x, bGraphicsMode, true ); + writePixel( cx - y, cy - x, bGraphicsMode, true ); + } +} + +/*-------------------------------------------------------------------------------------- + Draw or clear a box(rectangle) with a single pixel border +--------------------------------------------------------------------------------------*/ +void DMD::drawBox( byte x1, byte y1, byte x2, byte y2, byte bGraphicsMode ) +{ + drawLine( x1, y1, x2, y1, bGraphicsMode ); + drawLine( x2, y1, x2, y2, bGraphicsMode ); + drawLine( x2, y2, x1, y2, bGraphicsMode ); + drawLine( x1, y2, x1, y1, bGraphicsMode ); +} + +/*-------------------------------------------------------------------------------------- + Draw or clear a filled box(rectangle) with a single pixel border +--------------------------------------------------------------------------------------*/ +void DMD::drawFilledBox( byte x1, byte y1, byte x2, byte y2, byte bGraphicsMode ) +{ + byte b; + + for( b = x1 ; b <= x2 ; b++ ) + { + drawLine( b, y1, b, y2, bGraphicsMode ); + } +} + +/*-------------------------------------------------------------------------------------- + Draw the selected test pattern +--------------------------------------------------------------------------------------*/ +void DMD::drawTestPattern( byte bPattern ) +{ + unsigned int ui; + + for( ui = 0 ; ui < 512 ; ui++ ) + { + //512 pixels + switch( bPattern ) + { + case PATTERN_ALT_0: // every alternate pixel, first pixel on + { + if( (ui & 1) == 0 ) + { + //even pixel + if( (ui & 32) == 0 ) + //even row + writePixel( (ui & 31), ((ui & ~31) / 32), GRAPHICS_NORMAL, true ); + else + //odd row + writePixel( (ui & 31), ((ui & ~31) / 32), GRAPHICS_NORMAL, false ); + } + else + { + //odd pixel + if( (ui & 32) == 0 ) + //even row + writePixel( (ui & 31), ((ui & ~31) / 32), GRAPHICS_NORMAL, false ); + else + //odd row + writePixel( (ui & 31), ((ui & ~31) / 32), GRAPHICS_NORMAL, true ); + } + break; + } + case PATTERN_ALT_1: // every alternate pixel, first pixel off + { + if( (ui & 1) == 0 ) + { + //even pixel + if( (ui & 32) == 0 ) + //even row + writePixel( (ui & 31), ((ui & ~31) / 32), GRAPHICS_NORMAL, false ); + else + //odd row + writePixel( (ui & 31), ((ui & ~31) / 32), GRAPHICS_NORMAL, true ); + } + else + { + //odd pixel + if( (ui & 32) == 0 ) + //even row + writePixel( (ui & 31), ((ui & ~31) / 32), GRAPHICS_NORMAL, true ); + else + //odd row + writePixel( (ui & 31), ((ui & ~31) / 32), GRAPHICS_NORMAL, false ); + } + break; + } + case PATTERN_STRIPE_0: // vertical stripes, first stripe on + { + if( (ui & 1) == 0 ) + //even pixel + writePixel( (ui & 31), ((ui & ~31) / 32), GRAPHICS_NORMAL, true ); + else + //odd pixel + writePixel( (ui & 31), ((ui & ~31) / 32), GRAPHICS_NORMAL, false ); + break; + } + case PATTERN_STRIPE_1: // vertical stripes, first stripe off + { + if( (ui & 1) == 0 ) + //even pixel + writePixel( (ui & 31), ((ui & ~31) / 32), GRAPHICS_NORMAL, false ); + else + //odd pixel + writePixel( (ui & 31), ((ui & ~31) / 32), GRAPHICS_NORMAL, true ); + break; + } + } + } +} + +/*-------------------------------------------------------------------------------------- + Scan the dot matrix LED panel display, from the RAM mirror out to the display hardware. + Call 4 times to scan the whole display which is made up of 4 interleaved rows within the 16 total rows. + Insert the calls to this function into the main loop for the highest call rate, or from a timer interrupt +--------------------------------------------------------------------------------------*/ +void DMD::scanDisplayBySPI() +{ + //if PIN_OTHER_SPI_nCS is in use during a DMD scan request then scanDisplayBySPI() will exit without conflict! (and skip that scan) + //if( digitalRead( PIN_OTHER_SPI_nCS ) == HIGH ) + //{ + //SPI transfer 128 pixels to the display hardware shift registers + SPI.transfer( bDMDScreenRAM[ bDMDByte ] ); + SPI.transfer( bDMDScreenRAM[ bDMDByte-16 ] ); + SPI.transfer( bDMDScreenRAM[ bDMDByte-32 ] ); + SPI.transfer( bDMDScreenRAM[ bDMDByte-48 ] ); + + SPI.transfer( bDMDScreenRAM[ bDMDByte+1 ] ); + SPI.transfer( bDMDScreenRAM[ bDMDByte+1-16 ] ); + SPI.transfer( bDMDScreenRAM[ bDMDByte+1-32 ] ); + SPI.transfer( bDMDScreenRAM[ bDMDByte+1-48 ] ); + + SPI.transfer( bDMDScreenRAM[ bDMDByte+2 ] ); + SPI.transfer( bDMDScreenRAM[ bDMDByte+2-16 ] ); + SPI.transfer( bDMDScreenRAM[ bDMDByte+2-32 ] ); + SPI.transfer( bDMDScreenRAM[ bDMDByte+2-48 ] ); + + SPI.transfer( bDMDScreenRAM[ bDMDByte+3 ] ); + SPI.transfer( bDMDScreenRAM[ bDMDByte+3-16 ] ); + SPI.transfer( bDMDScreenRAM[ bDMDByte+3-32 ] ); + SPI.transfer( bDMDScreenRAM[ bDMDByte+3-48 ] ); + + switch( bDMDByte ) + { + case 48: // row 1, 5, 9, 13 were clocked out + { + OE_DMD_ROWS_OFF(); + LATCH_DMD_SHIFT_REG_TO_OUTPUT(); + LIGHT_DMD_ROW_01_05_09_13(); + OE_DMD_ROWS_ON(); + bDMDByte = 52; //do row 2 next time + break; + } + case 52: // row 2, 6, 10, 14 were clocked out + { + OE_DMD_ROWS_OFF(); + LATCH_DMD_SHIFT_REG_TO_OUTPUT(); + LIGHT_DMD_ROW_02_06_10_14(); + OE_DMD_ROWS_ON(); + bDMDByte = 56; //do row 3 next time + break; + } + case 56: // row 3, 7, 11, 15 were clocked out + { + OE_DMD_ROWS_OFF(); + LATCH_DMD_SHIFT_REG_TO_OUTPUT(); + LIGHT_DMD_ROW_03_07_11_15(); + OE_DMD_ROWS_ON(); + bDMDByte = 60; //do row 4 next time + break; + } + case 60: // row 4, 8, 12, 16 were clocked out + { + OE_DMD_ROWS_OFF(); + LATCH_DMD_SHIFT_REG_TO_OUTPUT(); + LIGHT_DMD_ROW_04_08_12_16(); + OE_DMD_ROWS_ON(); + bDMDByte = 48; //back to row 1 next time + break; + } + } + //} +} diff --git a/DMD.h b/DMD.h new file mode 100644 index 0000000..5fcaba2 --- /dev/null +++ b/DMD.h @@ -0,0 +1,164 @@ +/*-------------------------------------------------------------------------------------- + + DMD.h - Function and support library for the Freetronics DMD, a 512 LED matrix display + panel arranged in a 32 x 16 layout. + + Copyright (C) 2011 Marc Alexander (info freetronics com) + + Note that the DMD library uses the SPI port for the fastest, low overhead writing to the + display. Keep an eye on conflicts if there are any other devices running from the same + SPI port, and that the chip select on those devices is correctly set to be inactive + when the DMD is being written to. + + +LED Panel Layout in RAM + 32 pixels (4 bytes) + top left ---------------------------------------- + | | + Screen 1 | 512 pixels (64 bytes) | 16 pixels + | | + ---------------------------------------- bottom right + + --- + + This program is free software: you can redistribute it and/or modify it under the terms + of the version 3 GNU General Public License as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program. + If not, see . + +--------------------------------------------------------------------------------------*/ +#ifndef DMD_H_ +#define DMD_H_ + +//Arduino toolchain header, version dependent +#if defined(ARDUINO) && ARDUINO >= 100 + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +//SPI library must be included for the SPI scanning/connection method to the DMD +#include "pins_arduino.h" +#include +#include + +// ###################################################################################################################### +// ###################################################################################################################### +#warning CHANGE THESE TO SEMI-ADJUSTABLE PIN DEFS! +//Arduino pins used for the display connection +#define PIN_DMD_nOE 9 // D9 active low Output Enable, setting this low lights all the LEDs in the selected rows. Can pwm it at very high frequency for brightness control. +#define PIN_DMD_A 6 // D6 +#define PIN_DMD_B 7 // D7 +#define PIN_DMD_CLK 13 // D13_SCK is SPI Clock if SPI is used +#define PIN_DMD_SCLK 8 // D8 +#define PIN_DMD_R_DATA 11 // D11_MOSI is SPI Master Out if SPI is used +//Define this chip select pin that the Ethernet W5100 IC or other SPI device uses +//if it is in use during a DMD scan request then scanDisplayBySPI() will exit without conflict! (and skip that scan) +//#define PIN_OTHER_SPI_nCS 10 +// ###################################################################################################################### +// ###################################################################################################################### + +//Handy defines +#define ASCIINUMBASE 0x30 //base value for ascii number '0' +#define CHAR_CR 0x0D //carriage return character +#define CHAR_LF 0x0A //line feed character + +//DMD I/O pin macros +#define LIGHT_DMD_ROW_01_05_09_13() { digitalWrite( PIN_DMD_B, LOW ); digitalWrite( PIN_DMD_A, LOW ); } +#define LIGHT_DMD_ROW_02_06_10_14() { digitalWrite( PIN_DMD_B, LOW ); digitalWrite( PIN_DMD_A, HIGH ); } +#define LIGHT_DMD_ROW_03_07_11_15() { digitalWrite( PIN_DMD_B, HIGH ); digitalWrite( PIN_DMD_A, LOW ); } +#define LIGHT_DMD_ROW_04_08_12_16() { digitalWrite( PIN_DMD_B, HIGH ); digitalWrite( PIN_DMD_A, HIGH ); } +#define LATCH_DMD_SHIFT_REG_TO_OUTPUT() { digitalWrite( PIN_DMD_SCLK, HIGH ); digitalWrite( PIN_DMD_SCLK, LOW ); } +#define OE_DMD_ROWS_OFF() { digitalWrite( PIN_DMD_nOE, LOW ); } +#define OE_DMD_ROWS_ON() { digitalWrite( PIN_DMD_nOE, HIGH ); } + +//Pixel/graphics writing modes (bGraphicsMode) +#define GRAPHICS_NORMAL 0 +#define GRAPHICS_INVERSE 1 +#define GRAPHICS_TOGGLE 2 +#define GRAPHICS_OR 3 +#define GRAPHICS_NOR 4 + +//drawTestPattern Patterns +#define PATTERN_ALT_0 0 +#define PATTERN_ALT_1 1 +#define PATTERN_STRIPE_0 2 +#define PATTERN_STRIPE_1 3 + +//display screen (and subscreen) sizing +#define DMD_PIXELS_ACROSS 32 //pixels across x axis (base 2 size expected) +#define DMD_PIXELS_DOWN 16 //pixels down y axis +#define DMD_BITSPERPIXEL 1 //1 bit per pixel, use more bits to allow for pwm screen brightness control +#define DMD_RAM_SIZE_BYTES ((DMD_PIXELS_ACROSS*DMD_BITSPERPIXEL/8)*DMD_PIXELS_DOWN) + // (32x * 1 / 8) = 4 bytes, * 16y = 64 bytes per screen here. +//lookup table for DMD::writePixel to make the pixel indexing routine faster +static byte bPixelLookupTable[8] = +{ + 0x80, //0, bit 7 + 0x40, //1, bit 6 + 0x20, //2. bit 5 + 0x10, //3, bit 4 + 0x08, //4, bit 3 + 0x04, //5, bit 2 + 0x02, //6, bit 1 + 0x01 //7, bit 0 +}; + +//The main class of DMD library functions +class DMD +{ + public: + //Instantiate the DMD + DMD(); + //virtual ~DMD(); + + //Set or clear a pixel at the x and y location (0,0 is the top left corner) + void writePixel( byte bX, byte bY, byte bGraphicsMode, byte bPixel ); + + //Draw a character with the 5 x 7 font table at the x and y location. bSet true is on, false is inverted + void drawCharacter_5x7( byte bX, byte bY, byte bChar, byte bGraphicsMode ); + + //Draw a character with the 6 x 16 font table at the x and y location. bSet true is on, false is inverted + //The 6 x 16 font table is designed to be good for large clock and 4 digit number displays with a colon in the centre + void drawCharacter_6x16( byte bX, byte bY, byte bChar, byte bGraphicsMode ); + + //Clear the screen in DMD RAM + void clearScreen( byte bNormal ); + + //Draw or clear a line from x1,y1 to x2,y2 + void drawLine( byte x1, byte y1, byte x2, byte y2, byte bGraphicsMode ); + + //Draw or clear a circle of radius r at x,y centre + void drawCircle( int xCenter, int yCenter, int radius, byte bGraphicsMode ); + + //Draw or clear a box(rectangle) with a single pixel border + void drawBox( byte x1, byte y1, byte x2, byte y2, byte bGraphicsMode ); + + //Draw or clear a filled box(rectangle) with a single pixel border + void drawFilledBox( byte x1, byte y1, byte x2, byte y2, byte bGraphicsMode ); + + //Draw the selected test pattern + void drawTestPattern( byte bPattern ); + + //Scan the dot matrix LED panel display, from the RAM mirror out to the display hardware. + //Call 4 times to scan the whole display which is made up of 4 interleaved rows within the 16 total rows. + //Insert the calls to this function into the main loop for the highest call rate, or from a timer interrupt + void scanDisplayBySPI(); + + private: + void drawCircleSub( int cx, int cy, int x, int y, byte bGraphicsMode ); + + //Mirror of DMD pixels in RAM, ready to be clocked out by the main loop or high speed timer calls + byte bDMDScreenRAM[DMD_RAM_SIZE_BYTES]; + + //scanning pointer into bDMDScreenRAM, setup init @ 48 for the first valid scan + volatile byte bDMDByte; + +}; + +#endif /* DMD_H_ */ diff --git a/DMD_Fonts.c b/DMD_Fonts.c new file mode 100644 index 0000000..f1ce116 --- /dev/null +++ b/DMD_Fonts.c @@ -0,0 +1,202 @@ +#include +#include + +#ifndef DMD_FONTS_H_ +#define DMD_FONTS_H_ +/*-------------------------------------------------------------------------------------- + DMD_fonts.h - Library fonts created for the Freetronics DMD, a 512 LED matrix display + panel arranged in a 32 x 16 layout. + + Copyright (C) 2011 Marc Alexander (info freetronics com) + + These fonts are stored in flash memory (PROGMEM) + Note that to access flash/progmem stored values, accessors like pgm_read_byte and + pgm_read_word must be used. + +( ADD PUBLIC DOMAIN LICENSE INFO HERE ) + +--------------------------------------------------------------------------------------*/ + +//====================================================================================== +// Character data for a 5x7 font set, ASCII codes 20 hex to 7E hex +// horizontally striped, top 3 bits are don't care. +// +// Example of '4' shown: +// 0x02, 0x06, 0x0A, 0x12, 0x1F, 0x02, 0x02, // 4 0x34 +// +// bit 7 6 5 4 3 2 1 0 +// ------------------------- +// byte 0 - - - . . . 1 . 0x02 (top row) +// byte 1 - - - . . 1 1 . 0x06 +// byte 2 - - - . 1 . 1 . 0x0A +// byte 3 - - - 1 . . 1 . 0x12 +// byte 4 - - - 1 1 1 1 1 0x1F +// byte 5 - - - . . . 1 . 0x02 +// byte 6 - - - . . . 1 . 0x02 (bottom row) +// +// Note that this is an LCD style font set and some of the special characters +// may not be what is shown as an example on the right +// +#define FONT5X7WIDTH 5 /* font width in pixels */ +#define FONT5X7HEIGHT 7 /* font height in pixels */ +static unsigned char bDMDFont_5x7[] PROGMEM = +{ +/* byte 0 1 2 3 4 5 6 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 + 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x04, // ! 0x21 + 0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, // " 0x22 + 0x0A, 0x0A, 0x1F, 0x0A, 0x1F, 0x0A, 0x0A, // # 0x23 + 0x04, 0x0F, 0x14, 0x0E, 0x05, 0x1E, 0x04, // $ 0x24 + 0x18, 0x19, 0x02, 0x04, 0x08, 0x13, 0x03, // % 0x25 + 0x0C, 0x12, 0x12, 0x0C, 0x15, 0x12, 0x0D, // & 0x26 + 0x0C, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, // ' 0x27 + 0x02, 0x04, 0x08, 0x08, 0x08, 0x04, 0x02, // ( 0x28 + 0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08, // ) 0x29 + 0x00, 0x04, 0x15, 0x0E, 0x15, 0x04, 0x00, // * 0x2A + 0x00, 0x04, 0x04, 0x1F, 0x04, 0x04, 0x00, // + 0x2B + 0x00, 0x00, 0x00, 0x00, 0x18, 0x08, 0x10, // , 0x2C + 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, // - 0x2D + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, // . 0x2E + 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x00, // / 0x2F + 0x0E, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0E, // 0 0x30 + 0x04, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x0E, // 1 0x31 + 0x0E, 0x11, 0x01, 0x02, 0x04, 0x08, 0x1F, // 2 0x32 + 0x1F, 0x02, 0x04, 0x02, 0x01, 0x11, 0x0E, // 3 0x33 + 0x02, 0x06, 0x0A, 0x12, 0x1F, 0x02, 0x02, // 4 0x34 + 0x1F, 0x10, 0x1E, 0x01, 0x01, 0x11, 0x0E, // 5 0x35 + 0x06, 0x08, 0x10, 0x1E, 0x11, 0x11, 0x0E, // 6 0x36 + 0x1F, 0x01, 0x02, 0x04, 0x08, 0x08, 0x08, // 7 0x37 + 0x0E, 0x11, 0x11, 0x0E, 0x11, 0x11, 0x0E, // 8 0x38 + 0x0E, 0x11, 0x11, 0x0F, 0x01, 0x02, 0x0C, // 9 0x39 + 0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x00, // : 0x3A + 0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x04, 0x08, // ; 0x3B + 0x02, 0x04, 0x08, 0x10, 0x08, 0x04, 0x02, // < 0x3C + 0x00, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x00, // = 0x3D + 0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, // > 0x3E + 0x0E, 0x11, 0x01, 0x02, 0x04, 0x00, 0x04, // ? 0x3F + 0x0E, 0x11, 0x01, 0x0D, 0x15, 0x15, 0x0E, // @ 0x40 + 0x04, 0x0A, 0x11, 0x11, 0x1F, 0x11, 0x11, // A 0x41 + 0x1E, 0x11, 0x11, 0x1E, 0x11, 0x11, 0x1E, // B 0x42 + 0x0E, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0E, // C 0x43 + 0x1C, 0x12, 0x11, 0x11, 0x11, 0x12, 0x1C, // D 0x44 + 0x1F, 0x10, 0x10, 0x1C, 0x10, 0x10, 0x1F, // E 0x45 + 0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x10, // F 0x46 + 0x0E, 0x11, 0x10, 0x17, 0x11, 0x11, 0x0E, // G 0x47 + 0x11, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11, // H 0x48 + 0x0E, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E, // I 0x49 + 0x07, 0x02, 0x02, 0x02, 0x02, 0x12, 0x0C, // J 0x4A + 0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11, // K 0x4B + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1F, // L 0x4C + 0x11, 0x1B, 0x15, 0x11, 0x11, 0x11, 0x11, // M 0x4D + 0x11, 0x11, 0x19, 0x15, 0x13, 0x11, 0x11, // N 0x4E + 0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E, // O 0x4F + 0x1E, 0x11, 0x11, 0x1E, 0x10, 0x10, 0x10, // P 0x50 + 0x0E, 0x11, 0x11, 0x11, 0x15, 0x12, 0x0D, // Q 0x51 + 0x1E, 0x11, 0x11, 0x1E, 0x14, 0x12, 0x11, // R 0x52 + 0x0E, 0x11, 0x10, 0x0E, 0x01, 0x11, 0x0E, // S 0x53 + 0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, // T 0x54 + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E, // U 0x55 + 0x11, 0x11, 0x11, 0x11, 0x11, 0x0A, 0x04, // V 0x56 + 0x11, 0x11, 0x11, 0x11, 0x15, 0x15, 0x0A, // W 0x57 + 0x11, 0x11, 0x0A, 0x04, 0x0A, 0x11, 0x11, // X 0x58 + 0x11, 0x11, 0x11, 0x0A, 0x04, 0x04, 0x04, // Y 0x59 + 0x1F, 0x01, 0x02, 0x04, 0x08, 0x10, 0x1F, // Z 0x5A + 0x0E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0E, // [ 0x5B + 0x00, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, // \ 0x5C + 0x0E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0E, // ] 0x5D + 0x04, 0x0A, 0x11, 0x00, 0x00, 0x00, 0x00, // ^ 0x5E + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, // _ 0x5F + 0x08, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, // ` 0x60 + 0x00, 0x00, 0x0E, 0x01, 0x0F, 0x11, 0x0F, // a 0x61 + 0x10, 0x10, 0x10, 0x1E, 0x11, 0x11, 0x1E, // b 0x62 + 0x00, 0x00, 0x0F, 0x10, 0x10, 0x10, 0x0F, // c 0x63 + 0x01, 0x01, 0x01, 0x0F, 0x11, 0x11, 0x0F, // d 0x64 + 0x00, 0x00, 0x0E, 0x11, 0x1F, 0x10, 0x0F, // e 0x65 + 0x04, 0x0A, 0x08, 0x1C, 0x08, 0x08, 0x08, // f 0x66 + 0x00, 0x00, 0x0F, 0x11, 0x0F, 0x01, 0x1E, // g 0x67 + 0x10, 0x10, 0x10, 0x1E, 0x11, 0x11, 0x11, // h 0x68 + 0x00, 0x04, 0x00, 0x04, 0x04, 0x04, 0x04, // i 0x69 + 0x02, 0x00, 0x02, 0x02, 0x02, 0x12, 0x0C, // j 0x6A + 0x10, 0x10, 0x12, 0x14, 0x18, 0x14, 0x12, // k 0x6B + 0x0C, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E, // l 0x6C + 0x00, 0x00, 0x1B, 0x15, 0x15, 0x11, 0x11, // m 0x6D + 0x00, 0x00, 0x16, 0x19, 0x11, 0x11, 0x11, // n 0x6E + 0x00, 0x00, 0x0E, 0x11, 0x11, 0x11, 0x0E, // o 0x6F + 0x00, 0x00, 0x1E, 0x11, 0x1E, 0x10, 0x10, // p 0x70 + 0x00, 0x00, 0x0F, 0x11, 0x0F, 0x01, 0x01, // q 0x71 + 0x00, 0x00, 0x16, 0x19, 0x10, 0x10, 0x10, // r 0x72 + 0x00, 0x00, 0x0F, 0x10, 0x0E, 0x01, 0x1E, // s 0x73 + 0x08, 0x08, 0x1C, 0x08, 0x08, 0x0A, 0x04, // t 0x74 + 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x0E, // u 0x75 + 0x00, 0x00, 0x11, 0x11, 0x11, 0x0A, 0x04, // v 0x76 + 0x00, 0x00, 0x11, 0x11, 0x15, 0x15, 0x0A, // w 0x77 + 0x00, 0x00, 0x11, 0x0A, 0x04, 0x0A, 0x11, // x 0x78 + 0x00, 0x00, 0x11, 0x0A, 0x04, 0x04, 0x08, // y 0x79 + 0x00, 0x00, 0x1F, 0x02, 0x04, 0x08, 0x1F, // z 0x7A + 0x06, 0x08, 0x08, 0x10, 0x08, 0x08, 0x06, // { 0x7B + 0x06, 0x09, 0x08, 0x1C, 0x08, 0x08, 0x1F, // | 0x7C + 0x0C, 0x02, 0x02, 0x01, 0x02, 0x02, 0x0C, // } 0x7D + 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ~ 0x7E + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, //  0x7F + 0x04, 0x0E, 0x1F, 0x04, 0x04, 0x04, 0x00, // up arrow 0x80 + 0x00, 0x04, 0x04, 0x04, 0x1F, 0x0E, 0x04, // down arrow 0x81 + 0x02, 0x06, 0x0E, 0x1E, 0x0E, 0x06, 0x02, // left arrow 0x82 + 0x08, 0x0C, 0x0E, 0x0F, 0x0E, 0x0C, 0x08 // right arrow 0x83 +}; + +//====================================================================================== +// Character data for a 6x16 numerical font set, ASCII codes 2B hex to 3E hex +// horizontally striped, top 2 bits are don't care. +// +// Very useful for large number displays and clocks! +// +// Example of '3' shown: +// 0x0C, 0x1E, 0x3F, 0x33, 0x33, 0x03, 0x03, 0x0E, 0x0E, 0x03, 0x03, 0x33, 0x33, 0x3F, 0x1E, 0x0C, // '3' 0x33 +// +// bit 7 6 5 4 3 2 1 0 +// ------------------------- +// byte 0 - - . . 1 1 . . 0x0C (top row) +// byte 1 - - . 1 1 1 1 . 0x1E +// byte 2 - - 1 1 1 1 1 1 0x3F +// byte 3 - - 1 1 . . 1 1 0x33 +// byte 4 - - 1 1 . . 1 1 0x33 +// byte 5 - - . . . . 1 1 0x03 +// byte 6 - - . . . . 1 1 0x03 +// byte 7 - - . . 1 1 1 . 0x0E +// byte 8 - - . . 1 1 1 . 0x0E +// byte 9 - - . . . . 1 1 0x03 +// byte 10 - - . . . . 1 1 0x03 +// byte 11 - - 1 1 . . 1 1 0x33 +// byte 12 - - 1 1 . . 1 1 0x33 +// byte 13 - - 1 1 1 1 1 1 0x3F +// byte 14 - - . 1 1 1 1 . 0x1E +// byte 15 - - . . 1 1 . . 0x0C (bottom row) +// +#define FONT6X16WIDTH 6 // font width in pixels +#define FONT6X16HEIGHT 16 // font height in pixels +static unsigned char bDMDFont_6x16[] PROGMEM = +{ +// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 (byte index) + 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x3F, 0x0C, 0x0C, 0x0C, 0x0C, 0x00, 0x00, 0x00, // '+' 0x2B + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x04, 0x08, // ',' 0x2C + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // '-' 0x2D + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x0C, // '.' 0x2E + 0x03, 0x03, 0x03, 0x06, 0x06, 0x06, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x18, 0x18, 0x30, 0x30, 0x30, // '/' 0x2F + 0x1E, 0x3F, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x1E, // '0' 0x30 + 0x0C, 0x1C, 0x3C, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x3F, // '1' 0x31 + 0x0C, 0x1E, 0x3F, 0x33, 0x33, 0x33, 0x03, 0x07, 0x0E, 0x1C, 0x18, 0x38, 0x30, 0x30, 0x3F, 0x3F, // '2' 0x32 + 0x0C, 0x1E, 0x3F, 0x33, 0x33, 0x03, 0x03, 0x0E, 0x0E, 0x03, 0x03, 0x33, 0x33, 0x3F, 0x1E, 0x0C, // '3' 0x33 + 0x06, 0x06, 0x0E, 0x0E, 0x1E, 0x1E, 0x36, 0x36, 0x36, 0x3F, 0x3F, 0x06, 0x06, 0x06, 0x06, 0x06, // '4' 0x34 + 0x3F, 0x3F, 0x30, 0x30, 0x30, 0x30, 0x3E, 0x3F, 0x33, 0x03, 0x03, 0x03, 0x33, 0x33, 0x3F, 0x1E, // '5' 0x35 + 0x1E, 0x3F, 0x33, 0x33, 0x30, 0x30, 0x3E, 0x3F, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x1E, // '6' 0x36 + 0x3F, 0x3F, 0x33, 0x03, 0x03, 0x03, 0x03, 0x06, 0x06, 0x0C, 0x0C, 0x18, 0x18, 0x18, 0x18, 0x18, // '7' 0x37 + 0x1E, 0x3F, 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x1E, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x1E, // '8' 0x38 + 0x1E, 0x3F, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x1F, 0x03, 0x03, 0x03, 0x33, 0x33, 0x3F, 0x1E, // '9' 0x39 + 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x0C, 0x00, 0x00, 0x00, // ':' 0x3A + 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x04, 0x08, 0x00, 0x00, // ';' 0x3B + 0x00, 0x00, 0x01, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00, 0x00, // '<' 0x3C + 0x00, 0x00, 0x00, 0x00, 0x1E, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x1E, 0x00, 0x00, 0x00, 0x00, // '=' 0x3D + 0x00, 0x00, 0x20, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x20, 0x00, 0x00 // '>' 0x3E +}; + +#endif /* DMD_FONTS_H_ */ diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..7cfc9d9 --- /dev/null +++ b/README.txt @@ -0,0 +1,43 @@ +DMD library +-------------- +Marc Alexander, Freetronics +Email: info (at) freetronics.com +URL: http://www.freetronics.com/dmd-library + +A library for driving the Freetronics 512 pixel dot matrix LED display "DMD", a 32 x 16 layout. + +Includes: +- High speed display connection straight to SPI port and pins. +- A full 5 x 7 pixel font set and character routines for display. +- A numerical and symbol 6 x 16 font set with a colon especially for clocks and other fun large displays. +- Special graphics modes: Normal, Inverse, Toggle, OR and NOR! +- Clear screen with all pixels off or on. +- Point to point line drawing. +- Circle drawing. +- Box (rectangle) drawing, border and filled versions. +- Test pattern generation. + +For the DMD panel see: http://www.freetronics.com/dmd + +USAGE NOTES +----------- + +- Place the DMD library folder into the "arduino/libraries/" folder of your Arduino installation. +- Get the TimerOne library from here: http://code.google.com/p/arduino-timerone/downloads/list + or download the local copy from the DMD library page (which may be older but was used for this creation) + and place the TimerOne library folder into the "arduino/libraries/" folder of your Arduino installation. +- Restart the IDE. +- In the Arduino IDE, you can open File > Examples > DMD > dmd_demo, or dmd_clock_readout, and get it + running straight away! + +* The DMD comes with a pre-made data cable and DMDCON connector board so you can plug-and-play straight + into any regular size Arduino Board (Uno, Freetronics Eleven, EtherTen, USBDroid, etc) + +* Please note that the Mega boards have SPI on different pins, so this library does not currently support + the DMDCON connector board for direct connection to Mega's, please jumper the DMDCON pins to the + matching SPI pins on the other header on the Mega boards. + +PROJECT HOME +------------ + +http://www.freetronics.com/dmd-library diff --git a/examples/dmd_clock_readout/dmd_clock_readout.pde b/examples/dmd_clock_readout/dmd_clock_readout.pde new file mode 100644 index 0000000..ea26b3f --- /dev/null +++ b/examples/dmd_clock_readout/dmd_clock_readout.pde @@ -0,0 +1,118 @@ +/*-------------------------------------------------------------------------------------- + + dmd_clock_readout.cpp + Example clock readout project for the Freetronics DMD, a 512 LED matrix display + panel arranged in a 32 x 16 layout. + + Copyright (C) 2011 Marc Alexander (info freetronics com) + + See http://www.freetronics.com/dmd for resources and a getting started guide. + + Note that the DMD library uses the SPI port for the fastest, low overhead writing to the + display. Keep an eye on conflicts if there are any other devices running from the same + SPI port, and that the chip select on those devices is correctly set to be inactive + when the DMD is being written to. + + USAGE NOTES + ----------- + + - Place the DMD library folder into the "arduino/libraries/" folder of your Arduino installation. + - Get the TimerOne library from here: http://code.google.com/p/arduino-timerone/downloads/list + or download the local copy from the DMD library page (which may be older but was used for this creation) + and place the TimerOne library folder into the "arduino/libraries/" folder of your Arduino installation. + - Restart the IDE. + - In the Arduino IDE, you can open File > Examples > DMD > dmd_demo, or dmd_clock_readout, and get it + running straight away! + + * The DMD comes with a pre-made data cable and DMDCON connector board so you can plug-and-play straight + into any regular size Arduino Board (Uno, Freetronics Eleven, EtherTen, USBDroid, etc) + + * Please note that the Mega boards have SPI on different pins, so this library does not currently support + the DMDCON connector board for direct connection to Mega's, please jumper the DMDCON pins to the + matching SPI pins on the other header on the Mega boards. + + This example code is in the public domain. + The DMD library is open source (GPL), for more see DMD.cpp and DMD.h + +--------------------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------------------- + Includes +--------------------------------------------------------------------------------------*/ +#include //SPI.h must be included as DMD is written by SPI (the IDE complains otherwise) +#include // +#include // + +//Fire up the DMD library as dmd +DMD dmd; + +/*-------------------------------------------------------------------------------------- + Interrupt handler for Timer1 (TimerOne) driven DMD refresh scanning, this gets + called at the period set in Timer1.initialize(); +--------------------------------------------------------------------------------------*/ +void ScanDMD() +{ + dmd.scanDisplayBySPI(); +} + +/*-------------------------------------------------------------------------------------- + Show clock numerals on the screen from a 4 digit time value, and select whether the + flashing colon is on or off +--------------------------------------------------------------------------------------*/ +void ShowClockNumbers( unsigned int uiTime, byte bColonOn ) +{ + dmd.drawCharacter_6x16( 0, 0, '0'+((uiTime%10000)/1000), GRAPHICS_NORMAL ); // thousands + dmd.drawCharacter_6x16( 8, 0, '0'+((uiTime%1000) /100), GRAPHICS_NORMAL ); // hundreds + dmd.drawCharacter_6x16( 18, 0, '0'+((uiTime%100) /10), GRAPHICS_NORMAL ); // tens + dmd.drawCharacter_6x16( 26, 0, '0'+ (uiTime%10), GRAPHICS_NORMAL ); // units + if( bColonOn ) + dmd.drawCharacter_6x16( 13, 0, ':', GRAPHICS_OR ); // clock colon overlay on + else + dmd.drawCharacter_6x16( 13, 0, ':', GRAPHICS_NOR ); // clock colon overlay off +} + +/*-------------------------------------------------------------------------------------- + setup + Called by the Arduino architecture before the main loop begins +--------------------------------------------------------------------------------------*/ +void setup(void) +{ + + //initialize TimerOne's interrupt/CPU usage used to scan and refresh the display + Timer1.initialize( 5000 ); //period in microseconds to call ScanDMD. Anything longer than 5000 (5ms) and you can see flicker. + Timer1.attachInterrupt( ScanDMD ); //attach the Timer1 interrupt to ScanDMD which goes to dmd.scanDisplayBySPI() + + //clear/init the DMD pixels held in RAM + dmd.clearScreen( true ); //true is normal (all pixels off), false is negative (all pixels on) + +} + +/*-------------------------------------------------------------------------------------- + loop + Arduino architecture main loop +--------------------------------------------------------------------------------------*/ +void loop(void) +{ + unsigned int ui; + + // 6 x 16 font clock, including demo of OR and NOR modes for pixels so that the flashing colon can be overlayed + ui = 1234; + ShowClockNumbers( ui, true ); + delay( 1000 ); + ShowClockNumbers( ui, false ); + delay( 1000 ); + ShowClockNumbers( ui, true ); + delay( 1000 ); + ShowClockNumbers( ui, false ); + delay( 1000 ); + + ui = 2345; + ShowClockNumbers( ui, true ); + delay( 1000 ); + ShowClockNumbers( ui, false ); + delay( 1000 ); + ShowClockNumbers( ui, true ); + delay( 1000 ); + ShowClockNumbers( ui, false ); + delay( 1000 ); +} \ No newline at end of file diff --git a/examples/dmd_demo/dmd_demo.pde b/examples/dmd_demo/dmd_demo.pde new file mode 100644 index 0000000..9238cf0 --- /dev/null +++ b/examples/dmd_demo/dmd_demo.pde @@ -0,0 +1,148 @@ +/*-------------------------------------------------------------------------------------- + + dmd_test.cpp + Demo and example project for the Freetronics DMD, a 512 LED matrix display + panel arranged in a 32 x 16 layout. + + Copyright (C) 2011 Marc Alexander (info freetronics com) + + See http://www.freetronics.com/dmd for resources and a getting started guide. + + Note that the DMD library uses the SPI port for the fastest, low overhead writing to the + display. Keep an eye on conflicts if there are any other devices running from the same + SPI port, and that the chip select on those devices is correctly set to be inactive + when the DMD is being written to. + + USAGE NOTES + ----------- + + - Place the DMD library folder into the "arduino/libraries/" folder of your Arduino installation. + - Get the TimerOne library from here: http://code.google.com/p/arduino-timerone/downloads/list + or download the local copy from the DMD library page (which may be older but was used for this creation) + and place the TimerOne library folder into the "arduino/libraries/" folder of your Arduino installation. + - Restart the IDE. + - In the Arduino IDE, you can open File > Examples > DMD > dmd_demo, or dmd_clock_readout, and get it + running straight away! + + * The DMD comes with a pre-made data cable and DMDCON connector board so you can plug-and-play straight + into any regular size Arduino Board (Uno, Freetronics Eleven, EtherTen, USBDroid, etc) + + * Please note that the Mega boards have SPI on different pins, so this library does not currently support + the DMDCON connector board for direct connection to Mega's, please jumper the DMDCON pins to the + matching SPI pins on the other header on the Mega boards. + + This example code is in the public domain. + The DMD library is open source (GPL), for more see DMD.cpp and DMD.h + +--------------------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------------------- + Includes +--------------------------------------------------------------------------------------*/ +#include //SPI.h must be included as DMD is written by SPI (the IDE complains otherwise) +#include // +#include // + +//Fire up the DMD library as dmd +DMD dmd; + +/*-------------------------------------------------------------------------------------- + Interrupt handler for Timer1 (TimerOne) driven DMD refresh scanning, this gets + called at the period set in Timer1.initialize(); +--------------------------------------------------------------------------------------*/ +void ScanDMD() +{ + dmd.scanDisplayBySPI(); +} + +/*-------------------------------------------------------------------------------------- + setup + Called by the Arduino architecture before the main loop begins +--------------------------------------------------------------------------------------*/ +void setup(void) +{ + + //initialize TimerOne's interrupt/CPU usage used to scan and refresh the display + Timer1.initialize( 5000 ); //period in microseconds to call ScanDMD. Anything longer than 5000 (5ms) and you can see flicker. + Timer1.attachInterrupt( ScanDMD ); //attach the Timer1 interrupt to ScanDMD which goes to dmd.scanDisplayBySPI() + + //clear/init the DMD pixels held in RAM + dmd.clearScreen( true ); //true is normal (all pixels off), false is negative (all pixels on) + +} + +/*-------------------------------------------------------------------------------------- + loop + Arduino architecture main loop +--------------------------------------------------------------------------------------*/ +void loop(void) +{ + byte b; + + // 6 x 16 font clock, including demo of OR and NOR modes for pixels so that the flashing colon can be overlayed + dmd.clearScreen( true ); + dmd.drawCharacter_6x16( 0, 0, '2', GRAPHICS_NORMAL ); + dmd.drawCharacter_6x16( 8, 0, '3', GRAPHICS_NORMAL ); + dmd.drawCharacter_6x16( 18, 0, '4', GRAPHICS_NORMAL ); + dmd.drawCharacter_6x16( 26, 0, '5', GRAPHICS_NORMAL ); + dmd.drawCharacter_6x16( 13, 0, ':', GRAPHICS_OR ); // clock colon overlay on + delay( 1000 ); + dmd.drawCharacter_6x16( 13, 0, ':', GRAPHICS_NOR ); // clock colon overlay off + delay( 1000 ); + dmd.drawCharacter_6x16( 13, 0, ':', GRAPHICS_OR ); // clock colon overlay on + delay( 1000 ); + dmd.drawCharacter_6x16( 13, 0, ':', GRAPHICS_NOR ); // clock colon overlay off + delay( 1000 ); + dmd.drawCharacter_6x16( 13, 0, ':', GRAPHICS_OR ); // clock colon overlay on + delay( 1000 ); + + // half the pixels on + dmd.drawTestPattern( PATTERN_ALT_0 ); + delay( 1000 ); + + // the other half on + dmd.drawTestPattern( PATTERN_ALT_1 ); + delay( 1000 ); + + // display some text + dmd.clearScreen( true ); + dmd.drawCharacter_5x7( 0+2, 0, 'f', GRAPHICS_NORMAL ); + dmd.drawCharacter_5x7( 6+2, 0, 'r', GRAPHICS_NORMAL ); + dmd.drawCharacter_5x7( 12+2, 0, 'e', GRAPHICS_NORMAL ); + dmd.drawCharacter_5x7( 18+2, 0, 'e', GRAPHICS_NORMAL ); + dmd.drawCharacter_5x7( 24+2, 0, 't', GRAPHICS_NORMAL ); + dmd.drawCharacter_5x7( 0+2, 8, 'r', GRAPHICS_NORMAL ); + dmd.drawCharacter_5x7( 6+2, 8, 'o', GRAPHICS_NORMAL ); + dmd.drawCharacter_5x7( 12+2, 8, 'n', GRAPHICS_NORMAL ); + dmd.drawCharacter_5x7( 18+2, 8, 'i', GRAPHICS_NORMAL ); + dmd.drawCharacter_5x7( 24+2, 8, 'c', GRAPHICS_NORMAL ); + delay( 2000 ); + + // draw a border rectangle around the outside of the display + dmd.clearScreen( true ); + dmd.drawBox( 0, 0, 31, 15, GRAPHICS_NORMAL ); + delay( 1000 ); + + // draw an X + dmd.drawLine( 0, 0, 11, 15, GRAPHICS_NORMAL ); + dmd.drawLine( 0, 15, 11, 0, GRAPHICS_NORMAL ); + delay( 1000 ); + + // draw a circle + dmd.drawCircle( 16, 8, 5, GRAPHICS_NORMAL ); + delay( 1000 ); + + // draw a filled box + dmd.drawFilledBox( 24, 3, 29, 13, GRAPHICS_NORMAL ); + delay( 1000 ); + + // stripe chaser + for( b = 0 ; b < 20 ; b++ ) + { + dmd.drawTestPattern( (b&1)+PATTERN_STRIPE_0 ); + delay( 200 ); + } + delay( 200 ); + +} + diff --git a/keywords.txt b/keywords.txt new file mode 100644 index 0000000..8535b37 --- /dev/null +++ b/keywords.txt @@ -0,0 +1,39 @@ +####################################### +# Syntax Coloring Map For DMD Library +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +DMD KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +writePixel KEYWORD2 +drawCharacter_5x7 KEYWORD2 +drawCharacter_6x16 KEYWORD2 +clearScreen KEYWORD2 +drawLine KEYWORD2 +drawCircle KEYWORD2 +drawBox KEYWORD2 +drawFilledBox KEYWORD2 +drawTestPattern KEYWORD2 +scanDisplayBySPI KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +GRAPHICS_NORMAL LITERAL1 +GRAPHICS_INVERSE LITERAL1 +GRAPHICS_TOGGLE LITERAL1 +GRAPHICS_OR LITERAL1 +GRAPHICS_NOR LITERAL1 + +PATTERN_ALT_0 LITERAL1 +PATTERN_ALT_1 LITERAL1 +PATTERN_STRIPE_0 LITERAL1 +PATTERN_STRIPE_1 LITERAL1