diff --git a/src/lcd/lcm1602.cxx b/src/lcd/lcm1602.cxx index 012b5d46..7e5e3e99 100644 --- a/src/lcd/lcm1602.cxx +++ b/src/lcd/lcm1602.cxx @@ -7,6 +7,8 @@ * Author: Thomas Ingleby * Copyright (c) 2014 Intel Corporation. * + * Contributions: Jon Trulson + * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to @@ -33,14 +35,18 @@ using namespace upm; -Lcm1602::Lcm1602(int bus_in, int addr_in) : m_i2c_lcd_control(bus_in) +Lcm1602::Lcm1602(int bus_in, int addr_in) : + m_i2c_lcd_control(new mraa::I2c(bus_in)), + m_gpioRS(0), m_gpioEnable(0), m_gpioD0(0), + m_gpioD1(0), m_gpioD2(0), m_gpioD3(0) { mraa_result_t error = MRAA_SUCCESS; m_name = "Lcm1602 (I2C)"; + m_isI2C = true; m_lcd_control_address = addr_in; - error = m_i2c_lcd_control.address(m_lcd_control_address); + error = m_i2c_lcd_control->address(m_lcd_control_address); if (error != MRAA_SUCCESS) { fprintf(stderr, "Failed to initialize i2c bus\n"); return; @@ -71,8 +77,83 @@ Lcm1602::Lcm1602(int bus_in, int addr_in) : m_i2c_lcd_control(bus_in) home(); } +Lcm1602::Lcm1602(uint8_t rs, uint8_t enable, uint8_t d0, + uint8_t d1, uint8_t d2, uint8_t d3) : + m_i2c_lcd_control(0), + m_gpioRS(new mraa::Gpio(rs)), m_gpioEnable(new mraa::Gpio(enable)), + m_gpioD0(new mraa::Gpio(d0)), m_gpioD1(new mraa::Gpio(d1)), + m_gpioD2(new mraa::Gpio(d2)), m_gpioD3(new mraa::Gpio(d3)) +{ + mraa_result_t error = MRAA_SUCCESS; + m_name = "Lcm1602 (4-bit GPIO)"; + m_isI2C = false; + + // setup our gpios + + m_gpioRS->dir(mraa::DIR_OUT); + m_gpioEnable->dir(mraa::DIR_OUT); + + m_gpioD0->dir(mraa::DIR_OUT); + m_gpioD1->dir(mraa::DIR_OUT); + m_gpioD2->dir(mraa::DIR_OUT); + m_gpioD3->dir(mraa::DIR_OUT); + + + // set RS and Enable low to begin issuing commands + m_gpioRS->write(0); + m_gpioEnable->write(0); + + // wait to stabilize + usleep(100000); + + // set 4bit mode + + // These steps are adapted from the HD44780 datasheet, figure 24 + + // try 1 + write4bits(0x03); + usleep(4500); + + // try 2 + write4bits(0x03); + usleep(4500); + + // try 3 + write4bits(0x03); + usleep(150); + + // Finally, put into 4 bit mode + write4bits(0x02); + + // Set number of lines + send(LCD_FUNCTIONSET | LCD_2LINE | LCD_4BITMODE | LCD_5x8DOTS, 0); + send(LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF, 0); + usleep(2000); + clear(); + + // Set entry mode. + send(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT, 0); + + home(); +} + Lcm1602::~Lcm1602() { + // clean up after ourselves + if (m_isI2C) + { + delete m_i2c_lcd_control; + } + else + { + delete m_gpioRS; + delete m_gpioEnable; + + delete m_gpioD0; + delete m_gpioD1; + delete m_gpioD2; + delete m_gpioD3; + } } /* @@ -104,13 +185,19 @@ Lcm1602::setCursor(int row, int column) mraa_result_t Lcm1602::clear() { - return send(LCD_CLEARDISPLAY, 0); + mraa_result_t ret; + ret = send(LCD_CLEARDISPLAY, 0); + usleep(2000); // this command takes awhile + return ret; } mraa_result_t Lcm1602::home() { - return send(LCD_RETURNHOME, 0); + mraa_result_t ret; + ret = send(LCD_RETURNHOME, 0); + usleep(2000); // this command takes awhile + return ret; } mraa_result_t @@ -118,10 +205,10 @@ Lcm1602::createChar(uint8_t charSlot, uint8_t charData[]) { mraa_result_t error = MRAA_SUCCESS; charSlot &= 0x07; // only have 8 positions we can set - error = m_i2c_lcd_control.writeReg(LCD_CMD, LCD_SETCGRAMADDR | (charSlot << 3)); + error = send(LCD_SETCGRAMADDR | (charSlot << 3), 0); if (error == MRAA_SUCCESS) { for (int i = 0; i < 8; i++) { - error = m_i2c_lcd_control.writeReg(LCD_DATA, charData[i]); + error = send(charData[i], LCD_RS); } } @@ -137,10 +224,28 @@ mraa_result_t Lcm1602::send(uint8_t value, int mode) { mraa_result_t ret = MRAA_SUCCESS; - uint8_t h = value & 0xf0; - uint8_t l = (value << 4) & 0xf0; - ret = write4bits(h | mode); - ret = write4bits(l | mode); + uint8_t h; + uint8_t l; + + if (m_isI2C) + { + h = value & 0xf0; + l = (value << 4) & 0xf0; + ret = write4bits(h | mode); + ret = write4bits(l | mode); + return ret; + } + + // else, gpio (4 bit) + + // register select + m_gpioRS->write(mode); + + h = value >> 4; + l = value & 0x0f; + + ret = write4bits(h); + ret = write4bits(l); return ret; } @@ -148,25 +253,58 @@ mraa_result_t Lcm1602::write4bits(uint8_t value) { mraa_result_t ret = MRAA_SUCCESS; - ret = expandWrite(value); - ret = pulseEnable(value); + + if (m_isI2C) + { + ret = expandWrite(value); + ret = pulseEnable(value); + return ret; + } + + // else gpio + ret = m_gpioD0->write( ((value >> 0) & 0x01) ); + ret = m_gpioD1->write( ((value >> 1) & 0x01) ); + ret = m_gpioD2->write( ((value >> 2) & 0x01) ); + ret = m_gpioD3->write( ((value >> 3) & 0x01) ); + + ret = pulseEnable(value); // value is ignored here for gpio + return ret; } mraa_result_t Lcm1602::expandWrite(uint8_t value) { + // invalid for gpio + if (!m_isI2C) + return MRAA_ERROR_INVALID_RESOURCE; + uint8_t buffer = value | LCD_BACKLIGHT; - return m_i2c_lcd_control.writeByte(buffer); + return m_i2c_lcd_control->writeByte(buffer); } mraa_result_t Lcm1602::pulseEnable(uint8_t value) { mraa_result_t ret = MRAA_SUCCESS; - ret = expandWrite(value | LCD_EN); + + if (m_isI2C) + { + ret = expandWrite(value | LCD_EN); + usleep(1); + ret = expandWrite(value & ~LCD_EN); + usleep(50); + return ret; + } + + // else gpio + + ret = m_gpioEnable->write(0); usleep(1); - ret = expandWrite(value & ~LCD_EN); - usleep(50); + ret = m_gpioEnable->write(1); + usleep(1); // must be > 450ns + ret = m_gpioEnable->write(0); + usleep(100); // must be >37us + return ret; } diff --git a/src/lcd/lcm1602.h b/src/lcd/lcm1602.h index e34537bc..aaec7da9 100644 --- a/src/lcd/lcm1602.h +++ b/src/lcd/lcm1602.h @@ -7,6 +7,8 @@ * Author: Thomas Ingleby * Copyright (c) 2014 Intel Corporation. * + * Contributions: Jon Trulson + * * Permission is hereby granted, free of uint8_tge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to @@ -29,6 +31,7 @@ #include #include +#include #include "lcd.h" namespace upm @@ -63,6 +66,22 @@ class Lcm1602 : public LCD * @param address the slave address the lcd is registered on */ Lcm1602(int bus, int address); + + /** + * Lcm1602 alternate constructor, used for GPIO based hd44780 + * controllers supporting RS, Enable, and 4 data pins in 4-bit + * mode. + * + * @param rs register select pin + * @param enable enable pin + * @param d0 data 0 pin + * @param d1 data 1 pin + * @param d2 data 2 pin + * @param d3 data 3 pin + */ + Lcm1602(uint8_t rs, uint8_t enable, + uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3); + /** * Lcm1602 Destructor */ @@ -105,14 +124,25 @@ class Lcm1602 : public LCD */ mraa_result_t createChar(uint8_t charSlot, uint8_t charData[]); - private: + protected: mraa_result_t send(uint8_t value, int mode); mraa_result_t write4bits(uint8_t value); mraa_result_t expandWrite(uint8_t value); mraa_result_t pulseEnable(uint8_t value); + private: int m_lcd_control_address; - mraa::I2c m_i2c_lcd_control; + mraa::I2c* m_i2c_lcd_control; + // true if using i2c, false otherwise (gpio) + bool m_isI2C; + + // gpio operation + mraa::Gpio* m_gpioRS; + mraa::Gpio* m_gpioEnable; + mraa::Gpio* m_gpioD0; + mraa::Gpio* m_gpioD1; + mraa::Gpio* m_gpioD2; + mraa::Gpio* m_gpioD3; }; }