Extended library from C12832 Lib. by Peter Drescher, Chris Styles & Mihail Stoyanov. LCD in the market such as AQM1248A (Akizuki), AD-12864-SPI (antendo), NHD-C12832 (Newhaven), ST7565 (adafruit) and so on

Dependents:   CW_Decoder_using_FFT_on_F446 LPC1114_SPI_LCD_ST7565family_test

Fork of C12832 by Components

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ST7565_SPI_LCD.cpp Source File

ST7565_SPI_LCD.cpp

00001 /*
00002     EXTEND for SPI interface LCD which is using ST7565 controller
00003         Modified by Kenji Arai / JH1PJL
00004          http://www7b.biglobe.ne.jp/~kenjia/
00005          https://os.mbed.com/users/kenjiArai/
00006             Started: September 20th, 2014
00007             Revised: December  13th, 2014
00008             Revised: August     5th, 2020
00009 
00010     original file: C12832.cpp
00011     original Library name: C12832
00012 */
00013 
00014 //---------- ORIGINAL Header ---------------------------------------------------
00015 /* mbed library for the mbed Lab Board  128*32 pixel LCD
00016  * use C12832 controller
00017  * Copyright (c) 2012 Peter Drescher - DC2PD
00018  * Released under the MIT License: http://mbed.org/license/mit
00019  *
00020  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00021  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00022  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00023  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00024  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00025  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00026  * THE SOFTWARE.
00027  */
00028 
00029 // 13.10.12    initial design
00030 // 25.10.12    add autorefresh of screen
00031 // 25.10.12    add standart font
00032 // 20.12.12    add bitmap graphics
00033 
00034 #include "ST7565_SPI_LCD.h"
00035 #include "mbed.h"
00036 #include "stdio.h"
00037 #include "Small_7.h"
00038 
00039 #define BPP     1           // Bits per pixel
00040 
00041 //#define DEBUG
00042 // Com
00043 #ifdef  DEBUG
00044 #define PRINTF(...)         printf(__VA_ARGS__)
00045 #else
00046 #define PRINTF(...)         {;}
00047 #endif
00048 
00049 ST7565::ST7565
00050 (
00051     PinName mosi, PinName sck,
00052     PinName reset,
00053     PinName a0,
00054     PinName ncs,
00055     LCDType type,
00056     const char* name
00057 ):
00058     GraphicsDisplay(name),
00059     _spi_p(new SPI(mosi,NC,sck)), _spi(*_spi_p),
00060     _reset(reset),
00061     _A0(a0),
00062     _CS(ncs)
00063 {
00064     initialize(type);
00065 }
00066 
00067 ST7565::ST7565
00068 (
00069     SPI& p_spi,
00070     PinName reset,
00071     PinName a0,
00072     PinName ncs,
00073     LCDType type,
00074     const char* name
00075 ):
00076     GraphicsDisplay(name),
00077     _spi(p_spi),
00078     _reset(reset),
00079     _A0(a0),
00080     _CS(ncs)
00081 {
00082     initialize(type);
00083 }
00084 
00085 void ST7565::initialize(LCDType type)
00086 {
00087     switch (type) {
00088         case LCD128x32:
00089             lcd_width  = 128;
00090             lcd_height = 32;
00091             break;
00092         case LCD128x48:
00093             lcd_width  = 128;
00094             lcd_height = 48;
00095             break;
00096         case LCD128x64:
00097             lcd_width  = 128;
00098             lcd_height = 64;
00099             break;
00100         default:
00101             lcd_width  = 128;
00102             lcd_height = 64;
00103     }
00104     draw_mode = NORMAL;
00105     char_x = 0;
00106     lcd_reset();
00107 }
00108 
00109 int ST7565::width()
00110 {
00111 //    PRINTF("W:%d",lcd_width);
00112     return(lcd_width);
00113 }
00114 
00115 int ST7565::height()
00116 {
00117 //    PRINTF("H:%d",lcd_height);
00118     return(lcd_height);
00119 }
00120 
00121 void ST7565::invert(unsigned int o)
00122 {
00123     if(o == 0) {
00124         wr_cmd(0xA6);
00125     } else {
00126         wr_cmd(0xA7);
00127     }
00128 }
00129 
00130 void ST7565::set_contrast(unsigned int o)
00131 {
00132     contrast = o;
00133     wr_cmd(0x23);      //  Vo voltage reg.
00134     wr_cmd(0x81);      //  set volume
00135     wr_cmd(o & 0x3F);
00136 }
00137 
00138 unsigned int ST7565::get_contrast(void)
00139 {
00140     return(contrast);
00141 }
00142 
00143 // write command to lcd controller
00144 void ST7565::wr_cmd(unsigned char cmd)
00145 {
00146     _A0 = 0;
00147     _CS = 0;
00148     _spi.write(cmd);
00149     _CS = 1;
00150 }
00151 
00152 // write data to lcd controller
00153 void ST7565::wr_dat(unsigned char dat)
00154 {
00155     _A0 = 1;
00156     _CS = 0;
00157     _spi.write(dat);
00158     _CS = 1;
00159 }
00160 
00161 // reset and init the lcd controller
00162 void ST7565::lcd_reset()
00163 {
00164     _spi.format(8,0);
00165     _spi.frequency(10000000);   // 10 MHz SPI clock
00166     _A0 = 0;
00167     _CS = 1;
00168     _reset = 0;                 // display reset
00169     wait_us(50);
00170     _reset = 1;                 // end reset
00171     ThisThread::sleep_for(5ms);
00172     // initialize sequence
00173     wr_cmd(0xaf);     // display on
00174     wr_cmd(0x2f);     // power control set
00175     wr_cmd(0x81);     // set electronic volume mode
00176     wr_cmd(0x00);     // electronic volume data 00-3f
00177     wr_cmd(0x27);     // Volatge Regulator Internal Resister Ratio Set
00178     wr_cmd(0xa2);     // LCD Bias Set ... 1/9 bias
00179     wr_cmd(0xc8);     // Common Output Mode Select ... Reverse
00180     wr_cmd(0xa0);     // ADC Select ... Norma
00181     wr_cmd(0xa4);     // Display All Points ON/OFF ... normal
00182     wr_cmd(0xa6);     // Display Normal/Reverse ... normal
00183     wr_cmd(0xac);     // Static Indicator ... off
00184     wr_cmd(0x00);     // off
00185     wr_cmd(0x40);     // Display Strat Line Set ... 0
00186     wr_cmd(0xe0);     // Write Mode Set
00187     // clear and update LCD
00188     memset(buffer,0x00,1024);  // clear display buffer
00189     copy_to_lcd();
00190     auto_up = 1;              // switch on auto update
00191     // dont do this by default. Make the user call
00192     //claim(stdout);           // redirect printf to lcd
00193     locate(0,0);
00194     set_font((unsigned char*)Small_7);  // standart font
00195 }
00196 
00197 // set one pixel in buffer
00198 void ST7565::pixel(int x, int y, int color)
00199 {
00200     // first check parameter
00201     if(x > lcd_width || y > lcd_height || x < 0 || y < 0) return;
00202     if(draw_mode == NORMAL) {
00203         if(color == 0)
00204             buffer[x + ((y/8) * 128)] &= ~(1 << (y%8));  // erase pixel
00205         else
00206             buffer[x + ((y/8) * 128)] |= (1 << (y%8));   // set pixel
00207     } else { // XOR mode
00208         if(color == 1)
00209             buffer[x + ((y/8) * 128)] ^= (1 << (y%8));   // xor pixel
00210     }
00211 }
00212 
00213 // update lcd
00214 void ST7565::copy_to_lcd(void)
00215 {
00216     int i=0;
00217 
00218     // page 0
00219     wr_cmd(0x00);      // set column low nibble 0
00220     wr_cmd(0x10);      // set column hi  nibble 0
00221     wr_cmd(0xB0);      // set page address  0
00222     _A0 = 1;
00223     for(i=0; i<128; i++) {
00224         wr_dat(buffer[i]);
00225     }
00226     // page 1
00227     wr_cmd(0x00);      // set column low nibble 0
00228     wr_cmd(0x10);      // set column hi  nibble 0
00229     wr_cmd(0xB1);      // set page address  1
00230     _A0 = 1;
00231     for(i=128; i<256; i++) {
00232         wr_dat(buffer[i]);
00233     }
00234     // page 2
00235     wr_cmd(0x00);      // set column low nibble 0
00236     wr_cmd(0x10);      // set column hi  nibble 0
00237     wr_cmd(0xB2);      // set page address  2
00238     _A0 = 1;
00239     for(i=256; i<384; i++) {
00240         wr_dat(buffer[i]);
00241     }
00242     // page 3
00243     wr_cmd(0x00);      // set column low nibble 0
00244     wr_cmd(0x10);      // set column hi  nibble 0
00245     wr_cmd(0xB3);      // set page address  3
00246     _A0 = 1;
00247     for(i=384; i<512; i++) {
00248         wr_dat(buffer[i]);
00249     }
00250     if ((lcd_height == 48) || (lcd_height == 64)) {
00251         // page 4
00252         wr_cmd(0x00);      // set column low nibble 0
00253         wr_cmd(0x10);      // set column hi  nibble 0
00254         wr_cmd(0xB4);      // set page address  4
00255         _A0 = 1;
00256         for(i=512; i<640; i++) {
00257             wr_dat(buffer[i]);
00258         }
00259         // page 5
00260         wr_cmd(0x00);      // set column low nibble 0
00261         wr_cmd(0x10);      // set column hi  nibble 0
00262         wr_cmd(0xB5);      // set page address  5
00263         _A0 = 1;
00264         for(i=640; i<768; i++) {
00265             wr_dat(buffer[i]);
00266         }
00267     }
00268     if (lcd_height == 64) {
00269         // page 6
00270         wr_cmd(0x00);      // set column low nibble 0
00271         wr_cmd(0x10);      // set column hi  nibble 0
00272         wr_cmd(0xB6);      // set page address  6
00273         _A0 = 1;
00274         for(i=768; i<896; i++) {
00275             wr_dat(buffer[i]);
00276         }
00277         // page 7
00278         wr_cmd(0x00);      // set column low nibble 0
00279         wr_cmd(0x10);      // set column hi  nibble 0
00280         wr_cmd(0xB7);      // set page address  7
00281         _A0 = 1;
00282         for(i=896; i<1024; i++) {
00283             wr_dat(buffer[i]);
00284         }
00285     }
00286     _CS = 0;
00287 }
00288 
00289 void ST7565::cls(void)
00290 {
00291     memset(buffer,0x00,1024);  // clear display buffer
00292     copy_to_lcd();
00293 }
00294 
00295 void ST7565::line(int x0, int y0, int x1, int y1, int color)
00296 {
00297     int   dx = 0, dy = 0;
00298     int   dx_sym = 0, dy_sym = 0;
00299     int   dx_x2 = 0, dy_x2 = 0;
00300     int   di = 0;
00301 
00302     dx = x1-x0;
00303     dy = y1-y0;
00304     //  if (dx == 0) {        /* vertical line */
00305     //      if (y1 > y0) vline(x0,y0,y1,color);
00306     //      else vline(x0,y1,y0,color);
00307     //      return;
00308     //  }
00309     if (dx > 0) {
00310         dx_sym = 1;
00311     } else {
00312         dx_sym = -1;
00313     }
00314     //  if (dy == 0) {        /* horizontal line */
00315     //      if (x1 > x0) hline(x0,x1,y0,color);
00316     //      else  hline(x1,x0,y0,color);
00317     //      return;
00318     //  }
00319     if (dy > 0) {
00320         dy_sym = 1;
00321     } else {
00322         dy_sym = -1;
00323     }
00324     dx = dx_sym*dx;
00325     dy = dy_sym*dy;
00326     dx_x2 = dx*2;
00327     dy_x2 = dy*2;
00328     if (dx >= dy) {
00329         di = dy_x2 - dx;
00330         while (x0 != x1) {
00331             pixel(x0, y0, color);
00332             x0 += dx_sym;
00333             if (di<0) {
00334                 di += dy_x2;
00335             } else {
00336                 di += dy_x2 - dx_x2;
00337                 y0 += dy_sym;
00338             }
00339         }
00340         pixel(x0, y0, color);
00341     } else {
00342         di = dx_x2 - dy;
00343         while (y0 != y1) {
00344             pixel(x0, y0, color);
00345             y0 += dy_sym;
00346             if (di < 0) {
00347                 di += dx_x2;
00348             } else {
00349                 di += dx_x2 - dy_x2;
00350                 x0 += dx_sym;
00351             }
00352         }
00353         pixel(x0, y0, color);
00354     }
00355     if(auto_up) {
00356         copy_to_lcd();
00357     }
00358 }
00359 
00360 void ST7565::rect(int x0, int y0, int x1, int y1, int color)
00361 {
00362     if (x1 > x0) {
00363         line(x0,y0,x1,y0,color);
00364     } else {
00365         line(x1,y0,x0,y0,color);
00366     }
00367     if (y1 > y0) {
00368         line(x0,y0,x0,y1,color);
00369     } else {
00370         line(x0,y1,x0,y0,color);
00371     }
00372     if (x1 > x0) {
00373         line(x0,y1,x1,y1,color);
00374     } else {
00375         line(x1,y1,x0,y1,color);
00376     }
00377     if (y1 > y0) {
00378         line(x1,y0,x1,y1,color);
00379     } else {
00380         line(x1,y1,x1,y0,color);
00381     }
00382     if(auto_up) {
00383         copy_to_lcd();
00384     }
00385 }
00386 
00387 void ST7565::fillrect(int x0, int y0, int x1, int y1, int color)
00388 {
00389     int l,c,i;
00390 
00391     if(x0 > x1) {
00392         i = x0;
00393         x0 = x1;
00394         x1 = i;
00395     }
00396     if(y0 > y1) {
00397         i = y0;
00398         y0 = y1;
00399         y1 = i;
00400     }
00401     for(l = x0; l<= x1; l ++) {
00402         for(c = y0; c<= y1; c++) {
00403             pixel(l,c,color);
00404         }
00405     }
00406     if(auto_up) {
00407         copy_to_lcd();
00408     }
00409 }
00410 
00411 void ST7565::circle(int x0, int y0, int r, int color)
00412 {
00413     int draw_x0, draw_y0;
00414     int draw_x1, draw_y1;
00415     int draw_x2, draw_y2;
00416     int draw_x3, draw_y3;
00417     int draw_x4, draw_y4;
00418     int draw_x5, draw_y5;
00419     int draw_x6, draw_y6;
00420     int draw_x7, draw_y7;
00421     int xx, yy;
00422     int di;
00423 
00424     //WindowMax();
00425     if (r == 0) {       /* no radius */
00426         return;
00427     }
00428     draw_x0 = draw_x1 = x0;
00429     draw_y0 = draw_y1 = y0 + r;
00430     if (draw_y0 < height()) {
00431         pixel(draw_x0, draw_y0, color);     /* 90 degree */
00432     }
00433     draw_x2 = draw_x3 = x0;
00434     draw_y2 = draw_y3 = y0 - r;
00435     if (draw_y2 >= 0) {
00436         pixel(draw_x2, draw_y2, color);    /* 270 degree */
00437     }
00438     draw_x4 = draw_x6 = x0 + r;
00439     draw_y4 = draw_y6 = y0;
00440     if (draw_x4 < width()) {
00441         pixel(draw_x4, draw_y4, color);     /* 0 degree */
00442     }
00443     draw_x5 = draw_x7 = x0 - r;
00444     draw_y5 = draw_y7 = y0;
00445     if (draw_x5>=0) {
00446         pixel(draw_x5, draw_y5, color);     /* 180 degree */
00447     }
00448     if (r == 1) {
00449         return;
00450     }
00451     di = 3 - 2*r;
00452     xx = 0;
00453     yy = r;
00454     while (xx < yy) {
00455         if (di < 0) {
00456             di += 4*xx + 6;
00457         } else {
00458             di += 4*(xx - yy) + 10;
00459             yy--;
00460             draw_y0--;
00461             draw_y1--;
00462             draw_y2++;
00463             draw_y3++;
00464             draw_x4--;
00465             draw_x5++;
00466             draw_x6--;
00467             draw_x7++;
00468         }
00469         xx++;
00470         draw_x0++;
00471         draw_x1--;
00472         draw_x2++;
00473         draw_x3--;
00474         draw_y4++;
00475         draw_y5++;
00476         draw_y6--;
00477         draw_y7--;
00478         if ((draw_x0 <= width()) && (draw_y0>=0)) {
00479             pixel(draw_x0, draw_y0, color);
00480         }
00481         if ((draw_x1 >= 0) && (draw_y1 >= 0)) {
00482             pixel(draw_x1, draw_y1, color);
00483         }
00484         if ((draw_x2 <= width()) && (draw_y2 <= height())) {
00485             pixel(draw_x2, draw_y2, color);
00486         }
00487         if ((draw_x3 >=0 ) && (draw_y3 <= height())) {
00488             pixel(draw_x3, draw_y3, color);
00489         }
00490         if ((draw_x4 <= width()) && (draw_y4 >= 0)) {
00491             pixel(draw_x4, draw_y4, color);
00492         }
00493         if ((draw_x5 >= 0) && (draw_y5 >= 0)) {
00494             pixel(draw_x5, draw_y5, color);
00495         }
00496         if ((draw_x6 <=width()) && (draw_y6 <= height())) {
00497             pixel(draw_x6, draw_y6, color);
00498         }
00499         if ((draw_x7 >= 0) && (draw_y7 <= height())) {
00500             pixel(draw_x7, draw_y7, color);
00501         }
00502     }
00503     if(auto_up) {
00504         copy_to_lcd();
00505     }
00506 }
00507 
00508 void ST7565::fillcircle(int x, int y, int r, int color)
00509 {
00510     int i,up;
00511 
00512     up = auto_up;
00513     auto_up = 0;   // off
00514     for (i = 0; i <= r; i++) {
00515         circle(x,y,i,color);
00516     }
00517     auto_up = up;
00518     if(auto_up) {
00519         copy_to_lcd();
00520     }
00521 }
00522 
00523 void ST7565::setmode(int mode)
00524 {
00525     draw_mode = mode;
00526 }
00527 
00528 void ST7565::locate(int x, int y)
00529 {
00530     char_x = x;
00531     char_y = y;
00532 }
00533 
00534 int ST7565::columns()
00535 {
00536     return width() / font[1];
00537 }
00538 
00539 int ST7565::rows()
00540 {
00541     return height() / font[2];
00542 }
00543 
00544 void ST7565::line_clear(int y)
00545 {
00546     unsigned int vert,j,i,x;
00547 
00548     // read font parameter from start of array
00549     vert = font[2];                      // get vert size of font
00550     x = 0;
00551     for (j=0; j<vert; j++) {  //  vert line
00552         for (i=0; i<width(); i++) {  //  horz line
00553             pixel(x+i,y+j,0);
00554         }
00555     }
00556 }
00557 
00558 int ST7565::_putc(int value)
00559 {
00560     if (value == 0x0d) {    // new line
00561         char_x = 0;
00562         char_y = char_y + font[2];
00563         if (char_y >= height() - font[2]) {
00564             char_y = 0;
00565         }
00566         line_clear(char_y);
00567     } else {
00568         character(char_x, char_y, value);
00569         if(auto_up) {
00570             copy_to_lcd();
00571         }
00572     }
00573     return value;
00574 }
00575 
00576 void ST7565::character(int x, int y, int c)
00577 {
00578     unsigned int hor,vert,offset,bpl,j,i,b;
00579     unsigned char* zeichen;
00580     unsigned char z,w;
00581 
00582     if ((c < 31) || (c > 127)) {
00583         return;   // test char range
00584     }
00585     // read font parameter from start of array
00586     offset = font[0];                    // bytes / char
00587     hor = font[1];                       // get hor size of font
00588     vert = font[2];                      // get vert size of font
00589     bpl = font[3];                       // bytes per line
00590     if (char_x + hor > width()) {
00591         char_x = 0;
00592         char_y = char_y + vert;
00593         if (char_y >= height() - font[2]) {
00594             char_y = 0;
00595         }
00596     }
00597     zeichen = &font[((c -32) * offset) + 4]; // start of char bitmap
00598     w = zeichen[0];                          // width of actual char
00599     // construct the char into the buffer
00600     for (j=0; j<vert; j++) {  //  vert line
00601         for (i=0; i<hor; i++) {   //  horz line
00602             z =  zeichen[bpl * i + ((j & 0xF8) >> 3)+1];
00603             b = 1 << (j & 0x07);
00604             if (( z & b ) == 0x00) {
00605                 pixel(x+i,y+j,0);
00606             } else {
00607                 pixel(x+i,y+j,1);
00608             }
00609         }
00610     }
00611     char_x += w;
00612     if(char_x >= (width() - hor)) {
00613         char_x = 0;
00614         char_y = char_y + vert;
00615         if (char_y >= height() - font[2]) {
00616             char_y = 0;
00617         }
00618         line_clear(char_y);
00619     }
00620     //PRINTF("C:%d %d %d %d %d %d\r\n",offset,hor,vert,bpl,char_x,char_y);
00621 }
00622 
00623 void ST7565::set_font(unsigned char* f)
00624 {
00625     font = f;
00626 }
00627 
00628 void ST7565::set_auto_up(unsigned int up)
00629 {
00630     if(up) {
00631         auto_up = 1;
00632     } else {
00633         auto_up = 0;
00634     }
00635 }
00636 
00637 unsigned int ST7565::get_auto_up(void)
00638 {
00639     return (auto_up);
00640 }
00641 
00642 void ST7565::print_bm(Bitmap bm, int x, int y)
00643 {
00644     int h,v,b;
00645     char d;
00646 
00647     for(v=0; v < bm.ySize; v++) {   // lines
00648         for(h=0; h < bm.xSize; h++) { // pixel
00649             if(h + x > 127) {
00650                 break;
00651             }
00652             if(v + y > 31) {
00653                 break;
00654             }
00655             d = bm.data[bm.Byte_in_Line * v + ((h & 0xF8) >> 3)];
00656             b = 0x80 >> (h & 0x07);
00657             if((d & b) == 0) {
00658                 pixel(x+h,y+v,0);
00659             } else {
00660                 pixel(x+h,y+v,1);
00661             }
00662         }
00663     }
00664 }