Fork of Smoothie to port to mbed non-LPC targets.
Fork of Smoothie by
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 }
Generated on Tue Jul 12 2022 20:09:02 by 1.7.2