Library for Sure Electronics HT1632 based LED matrix displays. Supports multiple displays connected together.
Dependents: HT1632MsgScroller SMS_LEDMatrixPrinter
HT1632_LedMatrix.cpp
- Committer:
- SomeRandomBloke
- Date:
- 2012-11-20
- Revision:
- 6:80f554fd77a0
- Parent:
- 5:33b2bfce06b7
- Child:
- 8:61130f9b5b79
File content as of revision 6:80f554fd77a0:
/** Library for Holtek HT1632 LED driver chip, * As implemented on the Sure Electronics DE-DP10X display board * 8 x 32 dot matrix LED module.) * * Original code by: * Nov, 2008 by Bill Westfield ("WestfW") * Copyrighted and distributed under the terms of the Berkely license * (copy freely, but include this notice of original author.) * * Adapted for 8x32 display by FlorinC. * * Arduino Library Created and updated by Andrew Lindsay October/November 2009 * * Ported to Mbed platform by Andrew Lindsay, November 2012 * * @author Andrew Lindsay * * @section LICENSE * * Copyright (c) 2012 Andrew Lindsay (andrew [at] thiseldo [dot] co [dot] uk) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * @section DESCRIPTION * Functions to drive displays * */ #include "mbed.h" #include "HT1632_LedMatrix.h" #include "font_5x7_p.h" #define HIGH 1 #define LOW 0 /* * Set these constants to the values of the pins connected to the SureElectronics Module * For mbed, use WR=p7, DATA=p5, cs1=p17, cs2=p18, cs3=p19, cs4=p20 */ DigitalOut ht1632_wrclk(p7); DigitalOut ht1632_data(p5); DigitalOut ht1632_cs1(p17); DigitalOut ht1632_cs2(p18); DigitalOut ht1632_cs3(p19); DigitalOut ht1632_cs4(p20); // CS pins 17, 18, 19, 20 used. DigitalOut ht1632_cs[4] = {p17, p18, p19, p20}; // Chip Select (1, 2, 3, 4) // helper macros #define chip_number(x,y) (x >> 5) + (y >> 3)*numYDevices #define chip_nibble_address(x,y) ((x%32)<<1) + ((y%8)>>2); #define chip_byte_address(x,y) ((x%32)<<1); #define max(a, b) (((a) > (b)) ? (a) : (b)) // Display size and configuration, defaul is for a single 8x32 display uint8_t numDevices = 1; // Total number of devices uint8_t numXDevices = 1; // Number of horizontal devices uint8_t numYDevices = 1; // Number of vertical devices uint8_t xMax = 32 * numXDevices-1; uint8_t yMax = 8 * numYDevices-1; // Variables used to keep track of cursor position int cursorX = 0; int cursorY = 0; /* * we keep a copy of the display controller contents so that we can * know which bits are on without having to (slowly) read the device. */ // 4 boards at 32 bytes per board + 1 byte means we don't need to check overwrite in putChar uint8_t shadowram[129]; // our copy of the display's RAM // Custom character buffers - 8 characters available // 6 cols * 8 rows - first byte of each char is the number of columns used // Bits are aranged in columns with LSB at top uint8_t cgram [8][7] = { { 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }; // Default constructor HT1632_LedMatrix::HT1632_LedMatrix( void ) { } void HT1632_LedMatrix::init( uint8_t xDevices, uint8_t yDevices ) { // Set up the display size based on number of devices both horizontal and vertical numXDevices = xDevices; xMax = 32 * numXDevices-1; numYDevices = yDevices; yMax = 8 * numYDevices-1; numDevices = numXDevices * numYDevices; // Disable all display CS lines by taking high for( uint8_t i = 0; i < 4; i++ ) ht1632_cs[i] = HIGH; for (uint8_t chipno=0; chipno<4; chipno++) { chipfree(chipno); // unselect it sendcmd(chipno, HT1632_CMD_SYSDIS); // Disable system sendcmd(chipno, HT1632_CMD_COMS10); // 08*32, PMOS drivers sendcmd(chipno, HT1632_CMD_MSTMD); // Master Mode sendcmd(chipno, HT1632_CMD_SYSON); // System on sendcmd(chipno, HT1632_CMD_LEDON); // LEDs on sendcmd(chipno, HT1632_CMD_PWM | 0x0c); // PWM Duty for (uint8_t i=0; i<96; i++) senddata(chipno, i, 0); // clear the display wait(0.1); } cursorX = 0; cursorY = 0; } void HT1632_LedMatrix::displayOff( void ) { for (uint8_t chipno=0; chipno<4; chipno++) { chipfree(chipno); // unselect it sendcmd(chipno, HT1632_CMD_LEDOFF); // LEDs on } } void HT1632_LedMatrix::displayOn( void ) { for (uint8_t chipno=0; chipno<4; chipno++) { chipfree(chipno); // unselect it sendcmd(chipno, HT1632_CMD_LEDON); // LEDs on } } /*********************************************************************** * chipselect / chipfree * Select or de-select a particular ht1632 chip. * De-selecting a chip ends the commands being sent to a chip. * CD pins are active-low; writing 0 to the pin selects the chip. ***********************************************************************/ void HT1632_LedMatrix::chipselect(uint8_t chipno) { ht1632_cs[chipno] = LOW; } void HT1632_LedMatrix::chipfree(uint8_t chipno) { ht1632_cs[chipno] = HIGH; } /* * writebits * Write bits to h1632 on pins HT1632_DATA, HT1632_WRCLK * Chip is assumed to already be chip-selected * Bits are shifted out from MSB to LSB, with the first bit sent * being (bits & firstbit), shifted till firsbit is zero. */ void HT1632_LedMatrix::writebits (uint8_t bits, uint8_t firstbit) { while (firstbit) { ht1632_wrclk = LOW; if (bits & firstbit) { ht1632_data = HIGH; } else { ht1632_data = LOW; } ht1632_wrclk = HIGH; firstbit >>= 1; } } /* * writedatabits * Write databits to h1632 on pins HT1632_DATA, HT1632_WRCLK * Chip is assumed to already be chip-selected * Bits are shifted out from LSB to MSB */ void HT1632_LedMatrix::writedatabits (uint8_t bits, uint8_t count) { while (count) { ht1632_wrclk = LOW; ht1632_data = bits & 1; ht1632_wrclk = HIGH; count--; bits >>= 1; } } /* * sendcmd * Send a command to the ht1632 chip. * A command consists of a 3-bit "CMD" ID, an 8bit command, and * one "don't care bit". * Select 1 0 0 c7 c6 c5 c4 c3 c2 c1 c0 xx Free */ void HT1632_LedMatrix::sendcmd (uint8_t chipno, uint8_t command) { chipselect(chipno); // Select chip writebits(HT1632_ID_CMD, 0x04); // send 3 bits of id: COMMMAND writebits(command, 0x80); // send the actual command writebits(0, 1); // one extra dont-care bit in commands. chipfree(chipno); //done } /* * clear * clear the display, and the shadow memory, and the snapshot * memory. This uses the "write multiple words" capability of * the chipset by writing all 96 words of memory without raising * the chipselect signal. */ void HT1632_LedMatrix::clear() { char i; for (uint8_t chipno=0; chipno<numDevices; chipno++) { chipselect(chipno); // Select chip writebits(HT1632_ID_WR, 0x04); // send ID: WRITE to RAM writebits(0, 0x40); // Send address for (i = 0; i < 32; i++) // Clear entire display writedatabits(0, 8); // send 8 bits of data chipfree(chipno); // done for (i=0; i < 64; i++) shadowram[i+64*chipno] = 0; } cursorX = 0; cursorY = 0; } // Brighness is from 0 to 15 void HT1632_LedMatrix::setBrightness( unsigned char brightness ) { for (uint8_t chipno=0; chipno<numDevices; chipno++) { sendcmd(chipno, HT1632_CMD_PWM | (brightness & 0x0F )); } } /* * senddata * send a nibble (4 bits) of data to a particular memory location of the * ht1632. The command has 3 bit ID, 7 bits of address, and 4 bits of data. * Select 1 0 1 A6 A5 A4 A3 A2 A1 A0 D0 D1 D2 D3 Free * Note that the address is sent MSB first, while the data is sent LSB first! * This means that somewhere a bit reversal will have to be done to get * zero-based addressing of words and dots within words. */ void HT1632_LedMatrix::senddata (uint8_t chipno, uint8_t address, uint8_t data) { chipselect(chipno); // Select chip writebits(HT1632_ID_WR, 0x04); // send ID: WRITE to RAM writebits(address, 0x40); // Send address writedatabits(data, 4); // send 4 bits of data chipfree(chipno); // done } /* * sendcol * send a byte of data to a particular memory location of the * ht1632. The command has 3 bit ID, 7 bits of address, and 8 bits of data. * Select 1 0 1 A6 A5 A4 A3 A2 A1 A0 D0 D1 D2 D3 D4 D5 D6 D7 D8 Free * Note that the address is sent MSB first, while the data is sent LSB first! * This means that somewhere a bit reversal will have to be done to get * zero-based addressing of words and dots within words. */ void HT1632_LedMatrix::sendcol (uint8_t chipno, uint8_t address, uint8_t data) { chipselect(chipno); // Select chip writebits(HT1632_ID_WR, 0x04); // send ID: WRITE to RAM writebits(address, 0x40); // Send address writedatabits(data, 8); // send 8 bits of data chipfree(chipno); // done } // Write a string at the position specified // x and y start from 0 and count number of pixels, 2nd row on a 2 row display is y=8 void HT1632_LedMatrix::putString(int x, int y, char *str) { cursorX = x; cursorY = y; while( *str ) { putChar( cursorX, y, *str++ ); } } /* * Copy a character glyph from the smallFont data structure to * display memory, with its upper left at the given coordinate * This is unoptimized and simply uses plot() to draw each dot. */ void HT1632_LedMatrix::write( uint8_t c) { putChar( cursorX, cursorY, (char)c ); } /* * Copy a character glyph from the myfont data structure to * display memory, with its upper left at the given coordinate * This is unoptimized and simply uses plot() to draw each dot. * returns number of columns that didn't fit */ uint8_t HT1632_LedMatrix::putChar(int x, int y, char c) { // fonts defined for ascii 32 and beyond (index 0 in font array is ascii 32); // CGRAM characters are in range 0 to 15 with 8-15 being repeat of 0-7 // note we force y to be modulo 8 - we do not support writing character to partial y values. uint8_t charIndex; uint8_t colData; uint8_t numCols; uint8_t chipno; uint8_t addr; uint8_t colsLeft = 0; // cols that didn't fit if( c > 15 ) { // Regular characters // replace undisplayable characters with blank; if (c < 32 || c > 126) { charIndex = 0; } else { charIndex = c - 32; } // move character definition, pixel by pixel, onto the display; // fonts are defined as one byte per col; numCols=smallFont[charIndex][6]; // get the number of columns this character uses for (uint8_t col=0; col<numCols; col++) { colData = smallFont[charIndex][col]; chipno = chip_number(x,y); addr = chip_byte_address(x,y); // compute which memory byte this is in if (x <= xMax && y <= yMax) { shadowram[(addr>>1)+32*chipno] = colData; sendcol(chipno,addr,colData); x++; } else { colsLeft++; } } } else { // CGRAM Characters charIndex = c & 0x07; // Only low 3 bits count numCols=cgram[charIndex][0]; // get the number of columns this character uses // fonts are defined as one byte per col; for (uint8_t col=1; col<=numCols; col++) { colData = cgram[charIndex][col]; chipno = chip_number(x,y); addr = chip_byte_address(x,y); // compute which memory byte this is in if (x <= xMax && y <= yMax) { shadowram[(addr>>1)+32*chipno] = colData; sendcol(chipno,addr,colData); x++; } else { colsLeft++; } } } cursorX = x; cursorY = y; return colsLeft; } // Set position of cursor for writing void HT1632_LedMatrix::gotoXY(int x, int y) { cursorX = x; cursorY = y; } void HT1632_LedMatrix::getXY(int* x, int* y) { *x = cursorX; *y = cursorY; } void HT1632_LedMatrix::getXYMax(int* x, int* y) { *x = xMax; *y = yMax; } // Shift cursor X position a number of positions either left or right. void HT1632_LedMatrix::shiftCursorX(int xinc) { cursorX += xinc; } /* * plot a point on the display, with the upper left hand corner * being (0,0), and the lower right hand corner being (xMax-1, yMax-1). * Note that Y increases going "downward" in contrast with most * mathematical coordiate systems, but in common with many displays * basic bounds checking used. */ void HT1632_LedMatrix::plot (int x, int y, char val) { if (x<0 || x>xMax || y<0 || y>yMax) return; uint8_t chipno = chip_number(x,y); char addr = chip_byte_address(x,y); // compute which memory word this is in char shadowAddress = addr >>1; char bitval = 1<<(y&7); // compute which bit will need set if (val) { // Modify the shadow memory shadowram[shadowAddress +32*chipno] |= bitval; } else { shadowram[shadowAddress +32*chipno] &= ~bitval; } // Now copy the new memory value to the display sendcol(chipno, addr, shadowram[shadowAddress +32*chipno]); } void HT1632_LedMatrix::setCustomChar( int charNum, unsigned char cgchar[] ) { for(int i=1; i<7; i++ ) { cgram[charNum][i] = (uint8_t)cgchar[i]; } cgram[charNum][6] = 0; cgram[charNum][0] = 6; } void HT1632_LedMatrix::setCustomChar( int charNum, unsigned char cgchar[], uint8_t numCols ) { numCols = max(numCols, 6 ); for(int i=1; i<=numCols; i++ ) { cgram[charNum][i] = (uint8_t)cgchar[i]; } cgram[charNum][0] = numCols; cgram[charNum][numCols] = 0; } void HT1632_LedMatrix::scrollLeft(uint8_t numberCols, uint8_t lineNum ) { for (int i=0; i<xMax-numberCols; i++) { shadowram[i]=shadowram[i+numberCols]; } for (int i=xMax-numberCols; i<xMax; i++) { shadowram[i]=0; } /* for (int i=0; i<128-numberCols-1; i++) { shadowram[i]=shadowram[i+numberCols]; } for (int i=128-numberCols; i<128; i++) { shadowram[i]=0; } */ cursorX -= numberCols; if (cursorX < 0 ) cursorX = 0; } void HT1632_LedMatrix::putShadowRam() { for (int chipno=0; chipno<numDevices; chipno++) putShadowRam(chipno); } void HT1632_LedMatrix::putShadowRam(uint8_t chipno) { for (int i=0; i<64; i+=2) { sendcol(chipno,i,shadowram[(i>>1)+32*chipno]); } } #ifdef USE_GRAPHIC /* * Name : drawLine * Description : Draws a line between two points on the display. * Argument(s) : x1, y1 - Absolute pixel coordinates for line origin. * x2, y2 - Absolute pixel coordinates for line end. * c - either PIXEL_ON, PIXEL_OFF * Return value : none */ void HT1632_LedMatrix::drawLine(unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2, unsigned char c) { int dx, dy, stepx, stepy, fraction; /* Calculate differential form */ /* dy y2 - y1 */ /* -- = ------- */ /* dx x2 - x1 */ /* Take differences */ dy = y2 - y1; dx = x2 - x1; /* dy is negative */ if ( dy < 0 ) { dy = -dy; stepy = -1; } else { stepy = 1; } /* dx is negative */ if ( dx < 0 ) { dx = -dx; stepx = -1; } else { stepx = 1; } dx <<= 1; dy <<= 1; /* Draw initial position */ plot( x1, y1, c ); /* Draw next positions until end */ if ( dx > dy ) { /* Take fraction */ fraction = dy - ( dx >> 1); while ( x1 != x2 ) { if ( fraction >= 0 ) { y1 += stepy; fraction -= dx; } x1 += stepx; fraction += dy; /* Draw calculated point */ plot( x1, y1, c ); } } else { /* Take fraction */ fraction = dx - ( dy >> 1); while ( y1 != y2 ) { if ( fraction >= 0 ) { x1 += stepx; fraction -= dy; } y1 += stepy; fraction += dx; /* Draw calculated point */ plot( x1, y1, c ); } } } /* * Name : drawRectangle * Description : Draw a rectangle given to top left and bottom right points * Argument(s) : x1, y1 - Absolute pixel coordinates for top left corner * x2, y2 - Absolute pixel coordinates for bottom right corner * c - either PIXEL_ON, PIXEL_OFF * Return value : none */ void HT1632_LedMatrix::drawRectangle(unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2, unsigned char c) { drawLine( x1, y1, x2, y1, c ); drawLine( x1, y1, x1, y2, c ); drawLine( x1, y2, x2, y2, c ); drawLine( x2, y1, x2, y2, c ); } /* * Name : drawFilledRectangle * Description : Draw a filled rectangle given to top left and bottom right points * just simply draws horizontal lines where the rectangle would be * Argument(s) : x1, y1 - Absolute pixel coordinates for top left corner * x2, y2 - Absolute pixel coordinates for bottom right corner * c - either PIXEL_ON, PIXEL_OFF * Return value : none */ void HT1632_LedMatrix::drawFilledRectangle(unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2, unsigned char c) { for(int i=y1; i <= y2; i++ ) { drawLine( x1, i, x2, i, c ); } } /* * Name : drawCircle * Description : Draw a circle using Bresenham's algorithm. * Some small circles will look like squares!! * Argument(s) : xc, yc - Centre of circle * r - Radius * c - either PIXEL_ON, PIXEL_OFF * Return value : None */ void HT1632_LedMatrix::drawCircle(unsigned char xc, unsigned char yc, unsigned char r, unsigned char c) { int x=0; int y=r; int p=3-(2*r); plot( xc+x,yc-y, c); for(x=0; x<=y; x++) { if (p<0) { y=y; p=(p+(4*x)+6); } else { y=y-1; p=p+((4*(x-y)+10)); } plot(xc+x,yc-y, c); plot(xc-x,yc-y, c); plot(xc+x,yc+y, c); plot(xc-x,yc+y, c); plot(xc+y,yc-x, c); plot(xc-y,yc-x, c); plot(xc+y,yc+x, c); plot(xc-y,yc+x, c); } } #endif // The end!