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 I2CLCD.h Source File

I2CLCD.h

00001 /*  
00002       This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
00003       Smoothie is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
00004       Smoothie is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
00005       You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>. 
00006 */
00007 #ifndef I2CLCD_H
00008 #define I2CLCD_H
00009 
00010 #include "LcdBase.h"
00011 
00012 #include "I2C.h" // mbed.h lib
00013 #include "wait_api.h" // mbed.h lib
00014 #include "libs/Config.h"
00015 
00016 using namespace std;
00017 #include <vector>
00018 #include <string>
00019 #include <cstdio>
00020 #include <cstdarg>
00021 
00022 // commands
00023 #define LCD_CLEARDISPLAY 0x01
00024 #define LCD_RETURNHOME 0x02
00025 #define LCD_ENTRYMODESET 0x04
00026 #define LCD_DISPLAYCONTROL 0x08
00027 #define LCD_CURSORSHIFT 0x10
00028 #define LCD_FUNCTIONSET 0x20
00029 #define LCD_SETCGRAMADDR 0x40
00030 #define LCD_SETDDRAMADDR 0x80
00031 
00032 // flags for display entry mode
00033 #define LCD_ENTRYRIGHT 0x00
00034 #define LCD_ENTRYLEFT 0x02
00035 #define LCD_ENTRYSHIFTINCREMENT 0x01
00036 #define LCD_ENTRYSHIFTDECREMENT 0x00
00037 
00038 // flags for display on/off control
00039 #define LCD_DISPLAYON 0x04
00040 #define LCD_DISPLAYOFF 0x00
00041 #define LCD_CURSORON 0x02
00042 #define LCD_CURSOROFF 0x00
00043 #define LCD_BLINKON 0x01
00044 #define LCD_BLINKOFF 0x00
00045 
00046 // flags for display/cursor shift
00047 #define LCD_DISPLAYMOVE 0x08
00048 #define LCD_CURSORMOVE 0x00
00049 #define LCD_MOVERIGHT 0x04
00050 #define LCD_MOVELEFT 0x00
00051 
00052 // flags for function set
00053 #define LCD_8BITMODE 0x10
00054 #define LCD_4BITMODE 0x00
00055 #define LCD_2LINE 0x08
00056 #define LCD_1LINE 0x00
00057 #define LCD_5x10DOTS 0x04
00058 #define LCD_5x8DOTS 0x00
00059 
00060 // flags for backlight control
00061 #define LCD_BACKLIGHT 0x08
00062 #define LCD_NOBACKLIGHT 0x00
00063 
00064 #define En 1<<2 // Enable bit
00065 #define Rw 1<<1 // Read/Write bit
00066 #define Rs 1<<0 // Register select bit
00067 
00068 // config settings
00069 #define panel_checksum             CHECKSUM("panel")
00070 #define encoder_a_pin_checksum     CHECKSUM("encoder_a_pin")
00071 #define encoder_b_pin_checksum     CHECKSUM("encoder_b_pin")
00072 #define up_button_pin_checksum     CHECKSUM("up_button_pin")
00073 #define down_button_pin_checksum   CHECKSUM("down_button_pin")
00074 #define click_button_pin_checksum  CHECKSUM("click_button_pin")
00075 
00076 class I2CLCD : public LcdBase {
00077     public:
00078         I2CLCD() {
00079             // Default values
00080             this->i2c_address      = 0x27;
00081             this->backlightval     = 0x00;
00082             this->displaycontrol   = 0x00;
00083             this->displayfunction  = 0x00;
00084             this->displaymode      = 0x00;
00085 
00086             // I2C com
00087             this->i2c = new mbed::I2C(P0_27, P0_28);   
00088         
00089             // configure the pins to use
00090             this->encoder_a_pin.from_string(THEKERNEL->config->value( panel_checksum, encoder_a_pin_checksum)->by_default("nc")->as_string())->as_input()->pull_up();
00091             this->encoder_b_pin.from_string(THEKERNEL->config->value( panel_checksum, encoder_b_pin_checksum)->by_default("nc")->as_string())->as_input()->pull_up();
00092             this->click_pin.from_string(THEKERNEL->config->value( panel_checksum, click_button_pin_checksum )->by_default("nc")->as_string())->as_input()->pull_up();
00093             this->up_pin.from_string(THEKERNEL->config->value( panel_checksum, up_button_pin_checksum)->by_default("nc")->as_string())->as_input()->pull_up();
00094             this->down_pin.from_string(THEKERNEL->config->value( panel_checksum, down_button_pin_checksum)->by_default("nc")->as_string())->as_input()->pull_up();
00095 
00096         }
00097         virtual ~I2CLCD() {
00098             delete this->i2c;
00099         }
00100 
00101         int getEncoderResolution() {
00102             return 1;
00103         }
00104         
00105         uint8_t readButtons() {
00106             uint8_t state= 0;
00107             state |= (this->click_pin.get() ? BUTTON_SELECT : 0);
00108             state |= (this->up_pin.get() ? BUTTON_UP : 0);
00109             state |= (this->down_pin.get() ? BUTTON_DOWN : 0);
00110             return state;
00111         }
00112 
00113         int readEncoderDelta() { 
00114             static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
00115             static uint8_t old_AB = 0;
00116             old_AB <<= 2;                   //remember previous state
00117             old_AB |= ( this->encoder_a_pin.get() + ( this->encoder_b_pin.get() * 2 ) );  //add current state 
00118             return  enc_states[(old_AB&0x0f)];
00119         }
00120 
00121         void expanderWrite(char data){
00122             this->i2c->start();
00123             this->i2c->write(this->i2c_address<<1); 
00124             this->i2c->write((char)((char)data | (char)backlightval));
00125             this->i2c->stop();
00126         }
00127 
00128         void pulseEnable(char data){
00129             this->expanderWrite(data | En);      // En high
00130             wait_us(1);                          // enable pulse must be >450ns
00131             this->expanderWrite(data & ~En);     // En low
00132             wait_us(50);                         // commands need > 37us to settle
00133         } 
00134 
00135         void write4bits(char value) {
00136             this->expanderWrite(value);
00137             this->pulseEnable(value);
00138         }
00139 
00140         void send(char value, char mode) {
00141             uint8_t highnib=value&0xf0;
00142             uint8_t lownib=(value<<4)&0xf0;
00143             this->write4bits((highnib)|mode);
00144             this->write4bits((lownib)|mode); 
00145         }
00146 
00147         void command(char value) {
00148             this->send(value, 0);
00149         }
00150 
00151         void write(const char* line, int len) {
00152             for (int i = 0; i < len; ++i) {
00153                 this->send(*line++, Rs);
00154             }
00155         }      
00156         
00157         void home(){
00158             this->command(LCD_RETURNHOME);  // set cursor position to zero
00159             wait_us(2000);            // this command takes a long time!
00160         }
00161 
00162         void clear(){
00163             this->command(LCD_CLEARDISPLAY);  // clear display, set cursor position to zero
00164             wait_us(2000);              // this command takes a long time!
00165         }
00166 
00167         void display() {
00168             this->displaycontrol |= LCD_DISPLAYON;
00169             this->command(LCD_DISPLAYCONTROL | this->displaycontrol);
00170         }
00171 
00172         void setCursor(uint8_t col, uint8_t row){
00173             int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
00174             if ( row > 4 ) {
00175                 row = 4-1;    // we count rows starting w/0
00176             }
00177             this->command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
00178         }
00179 
00180         void init(){
00181             // Setup
00182             this->displayfunction = LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS;
00183             this->backlightval = LCD_NOBACKLIGHT;
00184             
00185             // Now we pull both RS and R/W low to begin commands
00186             wait_ms(50);
00187             this->expanderWrite(this->backlightval);
00188             wait_ms(1000);
00189             
00190             // we start in 8bit mode, try to set 4 bit mode
00191             for( char i=0;i<3;i++){ 
00192                 this->write4bits(0x03 << 4);
00193                 wait_us(4500);
00194             }  
00195             
00196             // finally, set to 4-bit interface
00197             this->write4bits(0x02 << 4); 
00198             
00199             // set # lines, font size, etc.
00200             this->command(LCD_FUNCTIONSET | this->displayfunction);  
00201             
00202             // turn the display on with no cursor or blinking default
00203             this->displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
00204             this->display();
00205             
00206             // clear it off
00207             this->clear();
00208             
00209             // Initialize to default text direction (for roman languages)
00210             this->displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
00211             
00212             // set the entry mode
00213             this->command(LCD_ENTRYMODESET | displaymode);
00214             
00215             this->home();
00216             wait(0.1);
00217 
00218             this->backlightval=LCD_BACKLIGHT;
00219             expanderWrite(0);
00220 
00221         }
00222 
00223     private:
00224         char displaymode;
00225         char displayfunction;
00226         char displaycontrol;
00227         char i2c_address;
00228         char backlightval;
00229 
00230         mbed::I2C* i2c;
00231 
00232         Pin encoder_a_pin;
00233         Pin encoder_b_pin;    
00234         Pin click_pin;
00235         Pin up_pin;
00236         Pin down_pin;
00237 };
00238 
00239 
00240 #endif