Fork of Smoothie to port to mbed non-LPC targets.

Dependencies:   mbed

Fork of Smoothie by Stéphane Cachat

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ST7565.cpp Source File

ST7565.cpp

00001 /*
00002  * ST7565.cpp
00003  *
00004  *  Created on: 21-06-2013
00005  *      Author: Wulfnor
00006  */
00007 
00008 #include "ST7565.h"
00009 #include "ST7565/glcdfont.h"
00010 #include "Kernel.h"
00011 #include "platform_memory.h"
00012 
00013 //definitions for lcd
00014 #define LCDWIDTH 128
00015 #define LCDHEIGHT 64
00016 #define LCDPAGES  (LCDHEIGHT+7)/8
00017 #define FB_SIZE LCDWIDTH*LCDPAGES
00018 #define FONT_SIZE_X 6
00019 #define FONT_SIZE_Y 8
00020 
00021 #define panel_checksum             CHECKSUM("panel")
00022 #define spi_channel_checksum       CHECKSUM("spi_channel")
00023 #define spi_cs_pin_checksum        CHECKSUM("spi_cs_pin")
00024 #define spi_frequency_checksum     CHECKSUM("spi_frequency")
00025 #define encoder_a_pin_checksum     CHECKSUM("encoder_a_pin")
00026 #define encoder_b_pin_checksum     CHECKSUM("encoder_b_pin")
00027 #define click_button_pin_checksum  CHECKSUM("click_button_pin")
00028 #define up_button_pin_checksum     CHECKSUM("up_button_pin")
00029 #define down_button_pin_checksum   CHECKSUM("down_button_pin")
00030 #define contrast_checksum          CHECKSUM("contrast")
00031 #define reverse_checksum           CHECKSUM("reverse")
00032 #define rst_pin_checksum           CHECKSUM("rst_pin")
00033 #define a0_pin_checksum            CHECKSUM("a0_pin")
00034 
00035 #define CLAMP(x, low, high) { if ( (x) < (low) ) x = (low); if ( (x) > (high) ) x = (high); } while (0);
00036 #define swap(a, b) { uint8_t t = a; a = b; b = t; }
00037 
00038 ST7565::ST7565() {
00039     //SPI com
00040 
00041    // select which SPI channel to use
00042     int spi_channel = THEKERNEL->config->value(panel_checksum, spi_channel_checksum)->by_default(0)->as_number();
00043     PinName mosi;
00044     PinName sclk;
00045     if(spi_channel == 0){
00046         mosi= P0_18; sclk= P0_15;
00047     }else if(spi_channel == 1){
00048         mosi= P0_9; sclk= P0_7;
00049     }else{
00050         mosi= P0_18; sclk= P0_15;
00051     }
00052 
00053     this->spi= new mbed::SPI(mosi,NC,sclk);
00054     this->spi->frequency(THEKERNEL->config->value(panel_checksum, spi_frequency_checksum)->by_default(1000000)->as_number()); //4Mhz freq, can try go a little lower
00055 
00056     //chip select
00057     this->cs.from_string(THEKERNEL->config->value( panel_checksum, spi_cs_pin_checksum)->by_default("0.16")->as_string())->as_output();
00058     cs.set(1);
00059 
00060     //lcd reset
00061     this->rst.from_string(THEKERNEL->config->value( panel_checksum, rst_pin_checksum)->by_default("nc")->as_string())->as_output();
00062     if(this->rst.connected()) rst.set(1);
00063 
00064     //a0
00065     this->a0.from_string(THEKERNEL->config->value( panel_checksum, a0_pin_checksum)->by_default("2.13")->as_string())->as_output();
00066     a0.set(1);
00067 
00068     this->up_pin.from_string(THEKERNEL->config->value( panel_checksum, up_button_pin_checksum )->by_default("nc")->as_string())->as_input();
00069     this->down_pin.from_string(THEKERNEL->config->value( panel_checksum, down_button_pin_checksum )->by_default("nc")->as_string())->as_input();
00070 
00071     this->click_pin.from_string(THEKERNEL->config->value( panel_checksum, click_button_pin_checksum )->by_default("nc")->as_string())->as_input();
00072     this->encoder_a_pin.from_string(THEKERNEL->config->value( panel_checksum, encoder_a_pin_checksum)->by_default("nc")->as_string())->as_input();
00073     this->encoder_b_pin.from_string(THEKERNEL->config->value( panel_checksum, encoder_b_pin_checksum)->by_default("nc")->as_string())->as_input();
00074 
00075     // contrast, mviki needs  0x018
00076     this->contrast= THEKERNEL->config->value(panel_checksum, contrast_checksum)->by_default(9)->as_number();
00077     // reverse display
00078     this->reversed= THEKERNEL->config->value(panel_checksum, reverse_checksum)->by_default(false)->as_bool();
00079 
00080     framebuffer= (uint8_t *)AHB0.alloc(FB_SIZE); // grab some memoery from USB_RAM
00081     if(framebuffer == NULL) {
00082         THEKERNEL->streams->printf("Not enough memory available for frame buffer");
00083     }
00084 }
00085 
00086 ST7565::~ST7565() {
00087     delete this->spi;
00088     AHB0.dealloc(framebuffer);
00089 }
00090 
00091 //send commands to lcd
00092 void ST7565::send_commands(const unsigned char* buf, size_t size){
00093     cs.set(0);
00094     a0.set(0);
00095     while(size-- >0){
00096         spi->write(*buf++);
00097     }
00098     cs.set(1);
00099 }
00100 
00101 //send data to lcd
00102 void ST7565::send_data(const unsigned char* buf, size_t size){
00103     cs.set(0);
00104     a0.set(1);
00105     while(size-- >0){
00106         spi->write(*buf++);
00107     }
00108     cs.set(1);
00109     a0.set(0);
00110 }
00111 
00112 //clearing screen
00113 void ST7565::clear(){
00114     memset(framebuffer, 0, FB_SIZE);
00115     this->tx=0;
00116     this->ty=0;
00117 }
00118 
00119 void ST7565::send_pic(const unsigned char* data){
00120     for (int i=0; i<LCDPAGES; i++)
00121     {
00122         set_xy(0, i);
00123         send_data(data + i*LCDWIDTH, LCDWIDTH);
00124     }
00125 }
00126 
00127 // set column and page number
00128 void ST7565::set_xy(int x, int y)
00129 {
00130     CLAMP(x, 0, LCDWIDTH-1);
00131     CLAMP(y, 0, LCDPAGES-1);
00132     unsigned char cmd[3];
00133     cmd[0] = 0xb0 | (y & 0x07);
00134     cmd[1] = 0x10 | (x >> 4);
00135     cmd[2] = 0x00 | (x & 0x0f);
00136     send_commands(cmd, 3);
00137 }
00138 
00139 void ST7565::setCursor(uint8_t col, uint8_t row){
00140   this->tx=col*6;
00141   this->ty=row*8;
00142 }
00143 
00144 void ST7565::home(){
00145     this->tx=0;
00146     this->ty=0;
00147 }
00148 
00149 void ST7565::display(){
00150     ///nothing
00151 }
00152 
00153 void ST7565::init(){
00154     const unsigned char init_seq[] = {
00155       0x40,    //Display start line 0
00156       (unsigned char)(reversed?0xa0:0xa1), // ADC
00157       (unsigned char)(reversed?0xc8:0xc0), // COM select
00158       0xa6,    //Display normal
00159       0xa2,    //Set Bias 1/9 (Duty 1/65)
00160       0x2f,    //Booster, Regulator and Follower On
00161       0xf8,    //Set internal Booster to 4x
00162       0x00,
00163       0x27,    //Contrast set
00164       0x81,
00165       this->contrast,    //contrast value
00166       0xac,    //No indicator
00167       0x00,
00168       0xaf,    //Display on
00169   };
00170   //rst.set(0);
00171   if(this->rst.connected()) rst.set(1);
00172   send_commands(init_seq, sizeof(init_seq));
00173   clear();
00174 }
00175 int ST7565::drawChar(int x, int y, unsigned char c, int color){
00176     int retVal=-1;
00177       if(c=='\n'){
00178         this->ty+=8;
00179         retVal= -tx;
00180       }
00181       if(c=='\r'){
00182           retVal= -tx;
00183       }
00184       else{
00185         for (uint8_t i =0; i<5; i++ ) {
00186           if(color==0){
00187             framebuffer[x + (y/8*128) ] = ~(glcd_font[(c*5)+i]<< y%8);
00188             if(y+8<63){
00189               framebuffer[x + ((y+8)/8*128) ] = ~(glcd_font[(c*5)+i] >>(8-(y%8)));
00190             }
00191           }
00192           if(color==1){
00193             framebuffer[x + ((y)/8*128) ] = glcd_font[(c*5)+i] <<(y%8);
00194             if(y+8<63){
00195                 framebuffer[x + ((y+8)/8*128) ] = glcd_font[(c*5)+i] >>(8-(y%8));
00196             }
00197           }
00198           x++;
00199         }
00200         retVal= 6;
00201         this->tx+=6;
00202       }
00203 
00204     return retVal;
00205 }
00206 
00207 //write single char to screen
00208 void ST7565::write_char(char value){
00209     drawChar(this->tx, this->ty,value,1);
00210 }
00211 
00212 void ST7565::write(const char* line, int len){
00213     for (int i = 0; i < len; ++i) {
00214         write_char(line[i]);
00215     }
00216 }
00217 //refreshing screen
00218 
00219 void ST7565::on_refresh(bool now){
00220     static int refresh_counts = 0;
00221     refresh_counts++;
00222     // 10Hz refresh rate
00223     if(now || refresh_counts % 2 == 0 ){
00224         send_pic(framebuffer);
00225     }
00226 }
00227 
00228 //reading button state
00229 uint8_t ST7565::readButtons(void) {
00230     uint8_t state= 0;
00231     state |= (this->click_pin.get() ? BUTTON_SELECT : 0);
00232     if(this->up_pin.connected()) {
00233         state |= (this->up_pin.get() ? BUTTON_UP : 0);
00234         state |= (this->down_pin.get() ? BUTTON_DOWN : 0);
00235     }
00236     return state;
00237 }
00238 
00239 int ST7565::readEncoderDelta() {
00240     static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
00241     static uint8_t old_AB = 0;
00242     if(this->encoder_a_pin.connected()) {
00243         // mviki
00244         old_AB <<= 2;                   //remember previous state
00245         old_AB |= ( this->encoder_a_pin.get() + ( this->encoder_b_pin.get() * 2 ) );  //add current state
00246         return  enc_states[(old_AB&0x0f)];
00247 
00248     }else{
00249         return 0;
00250     }
00251 }
00252 
00253 void ST7565::bltGlyph(int x, int y, int w, int h, const uint8_t *glyph, int span, int x_offset, int y_offset) {
00254     if(x_offset == 0 && y_offset == 0 && span == 0) {
00255         // blt the whole thing
00256         renderGlyph(x, y, glyph, w, h);
00257 
00258     }else{
00259         // copy portion of glyph into g where x_offset is left byte aligned
00260         // Note currently the x_offset must be byte aligned
00261         int n= w/8; // bytes per line to copy
00262         if(w%8 != 0) n++; // round up to next byte
00263         uint8_t g[n*h];
00264         uint8_t *dst= g;
00265         const uint8_t *src= &glyph[y_offset*span + x_offset/8];
00266         for (int i = 0; i < h; ++i) {
00267             memcpy(dst, src, n);
00268             dst+=n;
00269             src+= span;
00270         }
00271         renderGlyph(x, y, g, w, h);
00272     }
00273 }
00274 
00275 void ST7565::renderGlyph(int x, int y, const uint8_t *g, int w, int h) {
00276     CLAMP(x, 0, LCDWIDTH-1);
00277     CLAMP(y, 0, LCDHEIGHT-1);
00278     CLAMP(w, 0, LCDWIDTH - x);
00279     CLAMP(h, 0, LCDHEIGHT - y);
00280 
00281     for(int i=0; i<w; i++){
00282         for(int j=0; j<h; j++){
00283          pixel(x+i,y+j,g[(i/8)+ j*((w-1)/8 +1)] & (1<<(7-i%8)));
00284         }
00285     }
00286 }
00287 
00288 void ST7565::pixel(int x, int y, int colour)
00289 {
00290     int page = y / 8;
00291     unsigned char mask = 1<<(y%8);
00292     unsigned char *byte = &framebuffer[page*LCDWIDTH + x];
00293     if ( colour == 0 )
00294         *byte &= ~mask; // clear pixel
00295     else
00296         *byte |= mask; // set pixel
00297 }