Fork of Chris Styles' C12832 LCD driver

Dependents:   co657_lcdplay co657_nrf52_beacons door_lock co657_IoT

Fork of C12832 by Chris Styles

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers C12832.cpp Source File

C12832.cpp

00001 /* mbed library for the mbed Lab Board  128*32 pixel LCD
00002  * use C12832 controller
00003  * Copyright (c) 2012 Peter Drescher - DC2PD
00004  * Released under the MIT License: http://mbed.org/license/mit
00005  *
00006  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00007  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00008  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00009  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00010  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00011  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00012  * THE SOFTWARE.
00013  */
00014 
00015 // 13.10.12    initial design
00016 // 25.10.12    add autorefresh of screen
00017 // 25.10.12    add standart font
00018 // 20.12.12    add bitmap graphics
00019 
00020 // Assorted changes/updates by Fred Barnes, University of Kent <frmb@kent.ac.uk>
00021 // 31.10.15    minor bugfixes, some drawing optimisation
00022 
00023 // optional defines :
00024 // #define debug_lcd  1
00025 
00026 #include "C12832.h"
00027 #include "mbed.h"
00028 #include "stdio.h"
00029 #include "Small_7.h"
00030 
00031 #define BPP    1       // Bits per pixel
00032 
00033 
00034 C12832::C12832(PinName mosi, PinName sck, PinName reset, PinName a0, PinName ncs, const char* name)
00035     : _spi(mosi,NC,sck),_reset(reset),_A0(a0),_CS(ncs),GraphicsDisplay(name)
00036 {
00037     orientation = 1;
00038     draw_mode = NORMAL;
00039     char_x = 0;
00040     lcd_reset();
00041 }
00042 
00043 
00044 int C12832::width()
00045 {
00046     if (orientation == 0 || orientation == 2) return 32;
00047     else return 128;
00048 }
00049 
00050 int C12832::height()
00051 {
00052     if (orientation == 0 || orientation == 2) return 128;
00053     else return 32;
00054 }
00055 
00056 
00057 void C12832::invert(unsigned int o)
00058 {
00059     if(o == 0) wr_cmd(0xA6);
00060     else wr_cmd(0xA7);
00061 }
00062 
00063 
00064 void C12832::set_contrast(unsigned int o)
00065 {
00066     contrast = o;
00067     wr_cmd(0x81);      //  set volume
00068     wr_cmd(o & 0x3F);
00069 }
00070 
00071 unsigned int C12832::get_contrast(void)
00072 {
00073     return(contrast);
00074 }
00075 
00076 
00077 // write command to lcd controller
00078 
00079 void C12832::wr_cmd(unsigned char cmd)
00080 {
00081     _A0 = 0;
00082     _CS = 0;
00083     _spi.write(cmd);
00084     _CS = 1;
00085 }
00086 
00087 // write data to lcd controller
00088 
00089 void C12832::wr_dat(unsigned char dat)
00090 {
00091     _A0 = 1;
00092     _CS = 0;
00093     _spi.write(dat);
00094     _CS = 1;
00095 }
00096 
00097 // reset and init the lcd controller
00098 
00099 void C12832::lcd_reset()
00100 {
00101 
00102     _spi.format(8,3);                 // 8 bit spi mode 3
00103     _spi.frequency(20000000);          // 19,2 Mhz SPI clock
00104     _A0 = 0;
00105     _CS = 1;
00106     _reset = 0;                        // display reset
00107     wait_us(50);
00108     _reset = 1;                       // end reset
00109     wait_ms(5);
00110 
00111     /* Start Initial Sequence ----------------------------------------------------*/
00112 
00113     wr_cmd(0xAE);   //  display off
00114     wr_cmd(0xA2);   //  bias voltage
00115 
00116     wr_cmd(0xA0);
00117     wr_cmd(0xC8);   //  colum normal
00118 
00119     wr_cmd(0x22);   //  voltage resistor ratio
00120     wr_cmd(0x2F);   //  power on
00121     //wr_cmd(0xA4);   //  LCD display ram
00122     wr_cmd(0x40);   // start line = 0
00123     wr_cmd(0xAF);     // display ON
00124 
00125     wr_cmd(0x81);   //  set contrast
00126     wr_cmd(0x17);   //  set contrast
00127 
00128     wr_cmd(0xA6);     // display normal
00129 
00130 
00131     // clear and update LCD
00132     memset(buffer,0x00,512);  // clear display buffer
00133     copy_to_lcd();
00134     auto_up = 1;              // switch on auto update
00135     // dont do this by default. Make the user call
00136     //claim(stdout);           // redirekt printf to lcd
00137     locate(0,0);
00138     set_font((unsigned char*)Small_7);  // standart font
00139 }
00140 
00141 // set one pixel in buffer
00142 
00143 void C12832::pixel (int x, int y, int color)
00144 {
00145     if ((x >= 128) || (y >= 32) || (x < 0) || (y < 0)) {
00146         /* out of bounds */
00147         return;
00148     }
00149 
00150     if (draw_mode == NORMAL) {
00151         if (color == 0) {
00152             buffer[x + ((y & ~7) << 4)] &= ~(1 << (y & 0x07));  // erase pixel
00153         } else {
00154             buffer[x + ((y & ~7) << 4)] |= (1 << (y & 0x07));   // set pixel
00155         }
00156     } else { // XOR mode
00157         if (color == 1) {
00158             buffer[x + ((y & ~7) << 4)] ^= (1 << (y & 0x07));   // xor pixel
00159         }
00160     }
00161 }
00162 
00163 /* plots a pixel, but without bounds checking (assumed to be done elsewhere) */
00164 void C12832::pixel_nochk (int x, int y, int colour)
00165 {
00166     if (draw_mode == NORMAL) {
00167         if (colour == 0) {
00168             buffer[x + ((y & ~7) << 4)] &= ~(1 << (y & 0x07));  // erase pixel
00169         } else {
00170             buffer[x + ((y & ~7) << 4)] |= (1 << (y & 0x07));   // set pixel
00171         }
00172     } else { // XOR mode
00173         if (colour == 1) {
00174             buffer[x + ((y & ~7) << 4)] ^= (1 << (y & 0x07));   // xor pixel
00175         }
00176     }
00177 }
00178 
00179 // update lcd
00180 
00181 void C12832::copy_to_lcd(void)
00182 {
00183     
00184     int i=0;
00185     
00186     //page 0
00187     wr_cmd(0x00);      // set column low nibble 0
00188     wr_cmd(0x10);      // set column hi  nibble 0
00189     wr_cmd(0xB0);      // set page address  0
00190     _A0 = 1;
00191     for(i=0; i<128; i++) {
00192         wr_dat(buffer[i]);
00193     }
00194 
00195     // page 1
00196     wr_cmd(0x00);      // set column low nibble 0
00197     wr_cmd(0x10);      // set column hi  nibble 0
00198     wr_cmd(0xB1);      // set page address  1
00199     _A0 = 1;
00200     for(i=128; i<256; i++) {
00201         wr_dat(buffer[i]);
00202     }
00203 
00204     //page 2
00205     wr_cmd(0x00);      // set column low nibble 0
00206     wr_cmd(0x10);      // set column hi  nibble 0
00207     wr_cmd(0xB2);      // set page address  2
00208     _A0 = 1;
00209     for(i=256; i<384; i++) {
00210         wr_dat(buffer[i]);
00211     }
00212 
00213     //page 3
00214     wr_cmd(0x00);      // set column low nibble 0
00215     wr_cmd(0x10);      // set column hi  nibble 0
00216     wr_cmd(0xB3);      // set page address  3
00217     _A0 = 1;
00218 
00219     _CS = 0;
00220     
00221     for(i=384; i<512; i++) {
00222         wr_dat(buffer[i]);
00223     }
00224 
00225 }
00226 
00227 void C12832::cls (void)
00228 {
00229     memset (buffer, 0x00, 512);  // clear display buffer
00230     if (auto_up) {
00231         copy_to_lcd();
00232     }
00233 }
00234 
00235 /*
00236  *  based on Foley and van Dam, Computer Graphics Principles and Practice,
00237  *  Second edition in C, Fig 3.8
00238  *
00239  *  Adapted back into C from David Wood's occam implementation (line.occ).
00240  */
00241 void C12832::line (int x0, int y0, int x1, int y1, int colour)
00242 {
00243     int dx = x1 - x0;
00244     int dy = y1 - y0;
00245     int x, y, a_dx, s_x, a_dy, s_y;
00246     int d, strt, diag;
00247 
00248     
00249     if (dx == 0) {
00250         /* vertical line */
00251         if (y0 > y1) {
00252             vline (x0, y1, y0, colour);
00253         } else {
00254             vline (x0, y0, y1, colour);
00255         }
00256         return;
00257     }
00258     if (dy == 0) {
00259         /* horizontal line */
00260         if (x0 > x1) {
00261             hline (x1, y0, x0, colour);
00262         } else {
00263             hline (x0, y0, x1, colour);
00264         }
00265         return;
00266     }
00267     
00268     if ((x0 >= 128) || (x0 < 0) || (y0 >= 32) || (y0 < 0)) {
00269         /* starts outside raster, so abort */
00270         return;
00271     }
00272     
00273     x = x0;
00274     y = y0;
00275     if (dx > 0) {
00276         a_dx = dx;  s_x = 1;
00277     } else {
00278         a_dx = -dx; s_x = -1;
00279     }
00280     if (dy > 0) {
00281         a_dy = dy;  s_y = 1;
00282     } else {
00283         a_dy = -dy; s_y = -1;
00284     }
00285     
00286     if (a_dx > a_dy) {
00287         strt = a_dy * 2;            /* straight */
00288         diag = strt - (2 * a_dx);   /* diagonal */
00289         d = strt - a_dx;
00290 
00291         while ((a_dx >= 0) && (x >= 0) && (x < 128)) {
00292             pixel_nochk (x, y, colour);
00293             x += s_x;
00294             a_dx--;
00295             
00296             if (d <= 0) {
00297                 d += strt;
00298             } else {
00299                 d += diag;
00300                 y += s_y;
00301                 if ((y < 0) || (y >= 32)) {
00302                     break;          /* while() */
00303                 }
00304             }
00305         }
00306     } else {
00307         strt = a_dx * 2;            /* straight */
00308         diag = strt - (2 * a_dy);   /* diagonal */
00309         d = strt - a_dy;
00310 
00311         while ((a_dy >= 0) && (y >= 0) && (y < 32)) {
00312             pixel_nochk (x, y, colour);
00313             y += s_y;
00314             a_dy--;
00315             
00316             if (d <= 0) {
00317                 d += strt;
00318             } else {
00319                 d += diag;
00320                 x += s_x;
00321                 if ((x < 0) || (x >= 128)) {
00322                     break;          /* while() */
00323                 }
00324             }
00325         }
00326     }
00327 
00328     if (auto_up) {
00329         copy_to_lcd ();
00330     }
00331 }
00332 
00333 /* Note: x1 >= x0 */
00334 void C12832::hline (int x0, int y0, int x1, int colour)
00335 {
00336     int x;
00337     int yoff;
00338     uint8_t ybit;
00339 
00340     if (((x0 < 0) && (x1 < 0)) || ((x0 >= 128) && (x1 >= 128)) || (y0 < 0) || (y0 >= 32)) {
00341         return;                 /* completely outside */
00342     }
00343     if (x0 < 0) {
00344         x0 = 0;
00345     } else if (x1 >= 128) {
00346         x1 = 127;
00347     }
00348 
00349     yoff = ((y0 & ~7) << 4);
00350     ybit = (1 << (y0 & 0x07));
00351     
00352     if (draw_mode == NORMAL) {
00353         if (colour == 0) {
00354             for (x=x0; x<=x1; x++) {
00355                 buffer[x + yoff] &= ~ybit;  // erase pixel
00356             }
00357         } else {
00358             for (x=x0; x<=x1; x++) {
00359                 buffer[x + yoff] |= ybit;   // set pixel
00360             }
00361         }
00362     } else { // XOR mode
00363         if (colour == 1) {
00364             for (x=x0; x<=x1; x++) {
00365                 buffer[x + yoff] ^= ybit;   // xor pixel
00366             }
00367         }
00368     }
00369 
00370     if (auto_up) {
00371         copy_to_lcd ();
00372     }
00373 }
00374 
00375 /* Note: y1 >= y0 */
00376 void C12832::vline (int x0, int y0, int y1, int colour)
00377 {
00378     if (((y0 < 0) && (y1 < 0)) || ((y0 >= 32) && (y1 >= 32)) || (x0 < 0) || (x0 >= 128)) {
00379         return;                 /* completely outside */
00380     }
00381     if (y0 < 0) {
00382         y0 = 0;
00383     } else if (y1 >= 32) {
00384         y1 = 31;
00385     }
00386 
00387     if ((y0 & ~0x07) == (y1 & ~0x07)) {
00388         /* first and last pixels are in the same byte */
00389         uint8_t ybits = ((1 << ((y1 & 0x07) + 1)) - 1) ^ ((1 << (y0 & 0x07)) - 1);
00390         int yoff = (y0 & ~7) << 4;      /* same as y1 */
00391         
00392         if (draw_mode == NORMAL) {
00393             if (colour == 1) {
00394                 buffer[x0 + yoff] |= ybits;
00395             } else {
00396                 buffer[x0 + yoff] &= ~ybits;
00397             }
00398         } else {    /* XOR mode */
00399             buffer[x0 + yoff] ^= ybits;
00400         }
00401     } else {
00402         uint8_t st_ybits = (0xff << (y0 & 0x07));
00403         uint8_t sp_ybits = ((1 << ((y1 & 0x07) + 1)) - 1);
00404         int st_yoff = (y0 & ~7) << 4;
00405         int sp_yoff = (y1 & ~7) << 4;
00406         
00407         /* fill in first byte */
00408         if (draw_mode == NORMAL) {
00409             if (colour == 1) {
00410                 buffer[x0 + st_yoff] |= st_ybits;
00411             } else {
00412                 buffer[x0 + st_yoff] &= ~st_ybits;
00413             }
00414         } else {    /* XOR mode */
00415             buffer[x0 + st_yoff] ^= st_ybits;
00416         }
00417         for (st_yoff += 128; st_yoff < sp_yoff; st_yoff += 128) {
00418             /* intervening bytes 0xff */
00419             if (draw_mode == NORMAL) {
00420                 if (colour == 1) {
00421                     buffer[x0 + st_yoff] = 0xff;
00422                 } else {
00423                     buffer[x0 + st_yoff] = 0x00;
00424                 }
00425             } else {    /* XOR mode */
00426                 buffer[x0 + st_yoff] ^= 0xff;
00427             }
00428         }
00429         /* and the last byte */
00430         if (draw_mode == NORMAL) {
00431             if (colour == 1) {
00432                 buffer[x0 + sp_yoff] |= sp_ybits;
00433             } else {
00434                 buffer[x0 + sp_yoff] &= ~sp_ybits;
00435             }
00436         } else {    /* XOR mode */
00437             buffer[x0 + sp_yoff] ^= sp_ybits;
00438         }
00439     }
00440         
00441     if (auto_up) {
00442         copy_to_lcd ();
00443     }
00444 }
00445 
00446 void C12832::rect(int x0, int y0, int x1, int y1, int color)
00447 {
00448 
00449     if (x1 > x0) line(x0,y0,x1,y0,color);
00450     else  line(x1,y0,x0,y0,color);
00451 
00452     if (y1 > y0) line(x0,y0,x0,y1,color);
00453     else line(x0,y1,x0,y0,color);
00454 
00455     if (x1 > x0) line(x0,y1,x1,y1,color);
00456     else  line(x1,y1,x0,y1,color);
00457 
00458     if (y1 > y0) line(x1,y0,x1,y1,color);
00459     else line(x1,y1,x1,y0,color);
00460 
00461     if(auto_up) copy_to_lcd();
00462 }
00463 
00464 void C12832::fillrect(int x0, int y0, int x1, int y1, int color)
00465 {
00466     int l,i;
00467     if(x0 > x1) {
00468         i = x0;
00469         x0 = x1;
00470         x1 = i;
00471     }
00472 
00473     if(y0 > y1) {
00474         i = y0;
00475         y0 = y1;
00476         y1 = i;
00477     }
00478 
00479     for(l = x0; l<= x1; l ++) {
00480         vline (l, y0, y1, color);
00481     }
00482     if(auto_up) copy_to_lcd();
00483 }
00484 
00485 
00486 
00487 void C12832::circle(int x0, int y0, int r, int color)
00488 {
00489 
00490     int draw_x0, draw_y0;
00491     int draw_x1, draw_y1;
00492     int draw_x2, draw_y2;
00493     int draw_x3, draw_y3;
00494     int draw_x4, draw_y4;
00495     int draw_x5, draw_y5;
00496     int draw_x6, draw_y6;
00497     int draw_x7, draw_y7;
00498     int xx, yy;
00499     int di;
00500     //WindowMax();
00501     if (r == 0) {       /* no radius */
00502         return;
00503     }
00504 
00505     draw_x0 = draw_x1 = x0;
00506     draw_y0 = draw_y1 = y0 + r;
00507     if (draw_y0 < height()) {
00508         pixel(draw_x0, draw_y0, color);     /* 90 degree */
00509     }
00510 
00511     draw_x2 = draw_x3 = x0;
00512     draw_y2 = draw_y3 = y0 - r;
00513     if (draw_y2 >= 0) {
00514         pixel(draw_x2, draw_y2, color);    /* 270 degree */
00515     }
00516 
00517     draw_x4 = draw_x6 = x0 + r;
00518     draw_y4 = draw_y6 = y0;
00519     if (draw_x4 < width()) {
00520         pixel(draw_x4, draw_y4, color);     /* 0 degree */
00521     }
00522 
00523     draw_x5 = draw_x7 = x0 - r;
00524     draw_y5 = draw_y7 = y0;
00525     if (draw_x5>=0) {
00526         pixel(draw_x5, draw_y5, color);     /* 180 degree */
00527     }
00528 
00529     if (r == 1) {
00530         return;
00531     }
00532 
00533     di = 3 - 2*r;
00534     xx = 0;
00535     yy = r;
00536     while (xx < yy) {
00537 
00538         if (di < 0) {
00539             di += 4*xx + 6;
00540         } else {
00541             di += 4*(xx - yy) + 10;
00542             yy--;
00543             draw_y0--;
00544             draw_y1--;
00545             draw_y2++;
00546             draw_y3++;
00547             draw_x4--;
00548             draw_x5++;
00549             draw_x6--;
00550             draw_x7++;
00551         }
00552         xx++;
00553         draw_x0++;
00554         draw_x1--;
00555         draw_x2++;
00556         draw_x3--;
00557         draw_y4++;
00558         draw_y5++;
00559         draw_y6--;
00560         draw_y7--;
00561 
00562         if ( (draw_x0 <= width()) && (draw_y0>=0) ) {
00563             pixel(draw_x0, draw_y0, color);
00564         }
00565 
00566         if ( (draw_x1 >= 0) && (draw_y1 >= 0) ) {
00567             pixel(draw_x1, draw_y1, color);
00568         }
00569 
00570         if ( (draw_x2 <= width()) && (draw_y2 <= height()) ) {
00571             pixel(draw_x2, draw_y2, color);
00572         }
00573 
00574         if ( (draw_x3 >=0 ) && (draw_y3 <= height()) ) {
00575             pixel(draw_x3, draw_y3, color);
00576         }
00577 
00578         if ( (draw_x4 <= width()) && (draw_y4 >= 0) ) {
00579             pixel(draw_x4, draw_y4, color);
00580         }
00581 
00582         if ( (draw_x5 >= 0) && (draw_y5 >= 0) ) {
00583             pixel(draw_x5, draw_y5, color);
00584         }
00585         if ( (draw_x6 <=width()) && (draw_y6 <= height()) ) {
00586             pixel(draw_x6, draw_y6, color);
00587         }
00588         if ( (draw_x7 >= 0) && (draw_y7 <= height()) ) {
00589             pixel(draw_x7, draw_y7, color);
00590         }
00591     }
00592     if(auto_up) copy_to_lcd();
00593 }
00594 
00595 void C12832::fillcircle(int x, int y, int r, int color)
00596 {
00597     int i,up;
00598     up = auto_up;
00599     auto_up = 0;   // off
00600     for (i = 0; i <= r; i++)
00601         circle(x,y,i,color);
00602     auto_up = up;
00603     if(auto_up) copy_to_lcd();
00604 }
00605 
00606 void C12832::setmode(int mode)
00607 {
00608     draw_mode = mode;
00609 }
00610 
00611 void C12832::locate(int x, int y)
00612 {
00613     char_x = x;
00614     char_y = y;
00615 }
00616 
00617 
00618 
00619 int C12832::columns()
00620 {
00621     return width() / font[1];
00622 }
00623 
00624 
00625 
00626 int C12832::rows()
00627 {
00628     return height() / font[2];
00629 }
00630 
00631 
00632 
00633 int C12832::_putc(int value)
00634 {
00635     if (value == '\n') {    // new line
00636         char_x = 0;
00637         char_y = char_y + font[2];
00638         if (char_y >= height() - font[2]) {
00639             char_y = 0;
00640         }
00641     } else {
00642         character(char_x, char_y, value);
00643         if(auto_up) copy_to_lcd();
00644     }
00645     return value;
00646 }
00647 
00648 void C12832::character(int x, int y, int c)
00649 {
00650     unsigned int hor,vert,offset,bpl,j,i,b;
00651     unsigned char* zeichen;
00652     unsigned char z,w;
00653 
00654     if ((c < 31) || (c > 127)) return;   // test char range
00655 
00656     // read font parameter from start of array
00657     offset = font[0];                    // bytes / char
00658     hor = font[1];                       // get hor size of font
00659     vert = font[2];                      // get vert size of font
00660     bpl = font[3];                       // bytes per line
00661 
00662     if (char_x + hor > width()) {
00663         char_x = 0;
00664         char_y = char_y + vert;
00665         if (char_y >= height() - font[2]) {
00666             char_y = 0;
00667         }
00668     }
00669 
00670     zeichen = &font[((c -32) * offset) + 4]; // start of char bitmap
00671     w = zeichen[0];                          // width of actual char
00672     // construct the char into the buffer
00673     for (j=0; j<vert; j++) {  //  vert line
00674         for (i=0; i<hor; i++) {   //  horz line
00675             z =  zeichen[bpl * i + ((j & 0xF8) >> 3)+1];
00676             b = 1 << (j & 0x07);
00677             if (( z & b ) == 0x00) {
00678                 pixel(x+i,y+j,0);
00679             } else {
00680                 pixel(x+i,y+j,1);
00681             }
00682 
00683         }
00684     }
00685 
00686     char_x += w;
00687 }
00688 
00689 
00690 void C12832::set_font(unsigned char* f)
00691 {
00692     font = f;
00693 }
00694 
00695 void C12832::set_auto_up(unsigned int up)
00696 {
00697     if(up ) auto_up = 1;
00698     else auto_up = 0;
00699 }
00700 
00701 unsigned int C12832::get_auto_up(void)
00702 {
00703     return (auto_up);
00704 }
00705 
00706 void C12832::print_bm(Bitmap bm, int x, int y)
00707 {
00708     int h,v,b;
00709     char d;
00710 
00711     for(v=0; v < bm.ySize; v++) {   // lines
00712         for(h=0; h < bm.xSize; h++) { // pixel
00713             if(h + x > 127) break;
00714             if(v + y > 31) break;
00715             d = bm.data[bm.Byte_in_Line * v + ((h & 0xF8) >> 3)];
00716             b = 0x80 >> (h & 0x07);
00717             if((d & b) == 0) {
00718                 pixel(x+h,y+v,0);
00719             } else {
00720                 pixel(x+h,y+v,1);
00721             }
00722         }
00723     }
00724 
00725 }
00726 
00727