lcm1602: add 4-bit gpio support with RS and Enable pins

In addition, move the command/data sending methods into the protected
block so that derived classes can use them if need be.

Signed-off-by: Jon Trulson <jtrulson@ics.com>
Signed-off-by: Mihai Tudor Panu <mihai.tudor.panu@intel.com>
This commit is contained in:
Jon Trulson 2015-07-09 16:13:51 -06:00 committed by Mihai Tudor Panu
parent 8462e8ce52
commit 5a6fb122ec
2 changed files with 186 additions and 18 deletions

View File

@ -7,6 +7,8 @@
* Author: Thomas Ingleby <thomas.c.ingleby@intel.com>
* Copyright (c) 2014 Intel Corporation.
*
* Contributions: Jon Trulson <jtrulson@ics.com>
*
* 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;
}

View File

@ -7,6 +7,8 @@
* Author: Thomas Ingleby <thomas.c.ingleby@intel.com>
* Copyright (c) 2014 Intel Corporation.
*
* Contributions: Jon Trulson <jtrulson@ics.com>
*
* 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 <string>
#include <mraa/i2c.hpp>
#include <mraa/gpio.hpp>
#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;
};
}