I2C/MCP23017 version
// I2C/MCP23017 version, 2016-09-17
include <stdio.h>
include <stdlib.h>
include <linux/i2c-dev.h>
include <error.h>
include <sys/types.h>
include <sys/stat.h>
include <fcntl.h>
include <unistd.h>
int addr = 0x26; / 23017 chip I2C addr /
char *i2cbus= "/dev/i2c-0";
define D4 1 // 23017 GPB0
define D5 2 // 23017 GPB1
define D6 4 // 23017 GPB2
define D7 8 // 23017 GPB3
define BK_R 16 // 23017 GPB4
define BK_G 32 // 23017 GPB5
define BK_B 64 // 23017 GPB6
define RS 128 // 23017 GPB7
define EN_HI 0xFF // 23017 GPA7
define EN_LO 0x7F // 23017 GPA7
define IODIRA 0x00 // 23017 bit directions for GPIO-A
define IODIRB 0x01 // 23017 bit directions for GPIO-A
define OLATA 0x14 // 23017 output latch: GPIO-A
define OLATB 0x15 // 23017 output latch: GPIO-B
// commands
define LCD_CLEARDISPLAY 0x01
define LCD_RETURNHOME 0x02
define LCD_ENTRYMODESET 0x04
define LCD_DISPLAYCONTROL 0x08
define LCD_CURSORSHIFT 0x10
define LCD_FUNCTIONSET 0x20
define LCD_SETCGRAMADDR 0x40
define LCD_SETDDRAMADDR 0x80
// flags for display entry mode ( | LCD_ENTRYMODESET = 0x04 );
define LCD_ENTRYRIGHT 0x00
define LCD_ENTRYLEFT 0x02
define LCD_ENTRYSHIFTINCREMENT 0x01
define LCD_ENTRYSHIFTDECREMENT 0x00
// flags for display on/off control ( | DISPLAYCONTROL = 0x08 )
define LCD_DISPLAYON 0x04
define LCD_DISPLAYOFF 0x00
define LCD_CURSORON 0x02
define LCD_CURSOROFF 0x00
define LCD_BLINKON 0x01
define LCD_BLINKOFF 0x00
// flags for display/cursor shift ( | LCD_CURSORSHIFT = 0x10 )
define LCD_DISPLAYMOVE 0x08
define LCD_CURSORMOVE 0x00
define LCD_MOVERIGHT 0x04
define LCD_MOVELEFT 0x00
// flags for function set ( | LCD_FUNCTIONSET = 0x20 )
define LCD_8BITMODE 0x10
define LCD_4BITMODE 0x00
define LCD_2LINE 0x08
define LCD_1LINE 0x00
define LCD_5x10DOTS 0x04
define LCD_5x8DOTS 0x00
int i2c_fd, gpb, bklt=0;
unsigned char displaycontrol=0, displayfunction=0, displaymode=0;
wr_reg(unsigned char reg, unsigned char val) {
unsigned char buf[4];
buf[0]=reg;
buf[1]=val;
if ((write(i2c_fd, buf, 2)) != 2) {
fprintf(stderr,"Error writing 0x%x to reg 0x%x @ addr 0x%x on %sn",val,reg,addr,i2cbus);
exit(1);
}
}
pulse_en () {
wr_reg(OLATA,EN_HI);
usleep(2);
wr_reg(OLATA,EN_LO);
usleep(1);
wr_reg(OLATA,EN_HI);
usleep(2);
}
write1nibble(unsigned char nib) {
wr_reg(OLATB,(bklt | (nib & 0xF)) ); // RS=high-bit => 0
usleep(20);
pulse_en();
usleep(40);
}
writenibbles(unsigned char value, char mode) {
unsigned char nib;
//fprintf(stderr,"sending %X / %d]\n",value, mode);
/* high nibble first */
nib = (value >> 4);
wr_reg(OLATB,(bklt | (nib & 0xF) | (mode ? 0x80 : 0x00)) );
usleep(20);
pulse_en();
usleep(20);
nib = (value & 0x0f);
wr_reg(OLATB,(bklt | (nib & 0xF) | (mode ? 0x80 : 0x00)) );
usleep(20);
pulse_en();
usleep(100);
}
message (char *msg) {
int j;
for (j=0; (msg[j]!=0); j++) {
if ((msg[j] == 'n' || msg[j] == 'r'))
writenibbles(0xC0,0); /* next line */
else writenibbles(msg[j],1);
}
}
main(int argc, char **argv) {
int i,s;
if (argc < 2) {
fprintf(stderr,"usage: %s <bkcolor>\n",argv[0]);
fprintf(stderr,"usage: %s <bkcolor> \"message\"\n",argv[0]);
fprintf(stderr," -OR- %s <bkcolor> <charnum1> <param2>...\n",argv[0]);
exit(1);
}
bklt=((7 ^ atoi(argv[1])) << 4);
if ((i2c_fd = open(i2cbus, O_RDWR)) < 0) {
fprintf(stderr,"Failed to open i2c port %s\n",i2cbus);
exit(1);
}
if (ioctl(i2c_fd, I2C_SLAVE, addr) < 0) {
fprintf(stderr,"Unable to get bus access to talk to addr %x on %s\n",addr,i2cbus);
exit(1);
}
wr_reg (IODIRA,0x7F); // 0xFF & ~EN;
wr_reg (IODIRB,0x00); // all GPIO-B pins to output
if (argc == 2) {
wr_reg(OLATB,bklt);
exit(0);
}
/ init: enter & exit 8-bit mode to reset possible nibble misalignment... /
write1nibble(0x3);
usleep(5000);
write1nibble(0x3);
usleep(5000);
write1nibble(0x3);
usleep(1000);
write1nibble(0x2);
usleep(1000);
writenibbles(LCD_FUNCTIONSET | LCD_4BITMODE | LCD_2LINE | LCD_5x8DOTS,0);
usleep(50);
writenibbles(LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF,0); // 0x0C
usleep(50);
writenibbles(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT,0); // 0x06
usleep(50);
writenibbles(LCD_CLEARDISPLAY,0);
usleep(3200);
if (argc > 3) {
s=atoi(argv[2]);
for (i=s;i<(s+16);i++) writenibbles(i,1);
writenibbles(0xC0,0);
for (i=(s+16);i<(s+32);i++) writenibbles(i,1);
}
else
message (argv[2]);
close(i2c_fd);
return 0;
}