diff --git a/Grove_LCD_rgb_V2.0.c b/Grove_LCD_rgb_V2.0.c new file mode 100644 index 0000000..f751840 --- /dev/null +++ b/Grove_LCD_rgb_V2.0.c @@ -0,0 +1,222 @@ +#include "Grove_LCD_rgb_V2.0.h" +#include +#include +#include +#include + +static int _displayfunction = 0; +static int _displaycontrol = 0; +static int _displaymode = 0; + +extern struct i2c_client *i2c_client_lcd; +extern struct i2c_client *i2c_client_rgb; + +//--- Mid level commands, for sending data/cmds -------- +inline void lcd_command(int value) +{ + i2c_smbus_write_byte_data(i2c_client_lcd, 0x80, value); +} + +// send data +int lcd_write(char value) +{ + i2c_smbus_write_byte_data(i2c_client_lcd, 0x40, value); + return 0; +} + +void lcd_setReg(unsigned char addr, unsigned char dta) +{ + i2c_smbus_write_byte_data(i2c_client_rgb, addr, dta); +} + +void lcd_setRGB(unsigned char r, unsigned char g, unsigned char b) +{ + lcd_setReg(REG_RED, r); + lcd_setReg(REG_GREEN, g); + lcd_setReg(REG_BLUE, b); +} + +void lcd_setColor(enum color c) +{ + lcd_setRGB((c &0xFF0000)>>16, (c &0x00FF00)>>8, c &0x0000FF); +} + + +//--- high level commands, for the user! --------------------- +void lcd_clear(void) +{ + lcd_command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero + mdelay(2); // this command takes a long time! +} + +void lcd_home(void) +{ + lcd_command(LCD_RETURNHOME); // set cursor position to zero + mdelay(2); // this command takes a long time! +} + +void lcd_setCursor(int col, int row) +{ + col = (row == 0 ? col|0x80 : col|0xc0); + i2c_smbus_write_byte_data(i2c_client_lcd, 0x80, col); +} + +// Turn the display on/off (quickly) +void lcd_noDisplay(void) +{ + _displaycontrol &= ~LCD_DISPLAYON; + lcd_command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +void lcd_display(void) +{ + _displaycontrol |= LCD_DISPLAYON; + lcd_command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +// Turns the underline cursor on/off +void lcd_noCursor(void) +{ + _displaycontrol &= ~LCD_CURSORON; + lcd_command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +void lcd_cursor(void) { + _displaycontrol |= LCD_CURSORON; + lcd_command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +// Turn on and off the blinking cursor +void lcd_noBlink(void) +{ + _displaycontrol &= ~LCD_BLINKON; + lcd_command(LCD_DISPLAYCONTROL | _displaycontrol); +} +void lcd_blink(void) +{ + _displaycontrol |= LCD_BLINKON; + lcd_command(LCD_DISPLAYCONTROL | _displaycontrol); +} + +// These commands scroll the display without changing the RAM +void lcd_scrollDisplayLeft(void) +{ + lcd_command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT); +} +void lcd_scrollDisplayRight(void) +{ + lcd_command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT); +} + +// This is for text that flows Left to Right +void lcd_leftToRight(void) +{ + _displaymode |= LCD_ENTRYLEFT; + lcd_command(LCD_ENTRYMODESET | _displaymode); +} + +// This is for text that flows Right to Left +void lcd_rightToLeft(void) +{ + _displaymode &= ~LCD_ENTRYLEFT; + lcd_command(LCD_ENTRYMODESET | _displaymode); +} + +// This will 'right justify' text from the cursor +void lcd_autoscroll(void) +{ + _displaymode |= LCD_ENTRYSHIFTINCREMENT; + lcd_command(LCD_ENTRYMODESET | _displaymode); +} + +// This will 'left justify' text from the cursor +void lcd_noAutoscroll(void) +{ + _displaymode &= ~LCD_ENTRYSHIFTINCREMENT; + lcd_command(LCD_ENTRYMODESET | _displaymode); +} + +// Allows us to fill the first 8 CGRAM locations +// with custom characters +void lcd_createChar(int location, int charmap[]) +{ + unsigned char dta[8]; + int i; + + location &= 0x7; // we only have 8 locations 0-7 + lcd_command(LCD_SETCGRAMADDR | (location << 3)); + + for(i=0; i<8; i++) + { + dta[i] = charmap[i]; + } + i2c_smbus_write_block_data(i2c_client_lcd, 0x40, 8, dta); +} + +// Control the backlight LED blinking +void lcd_blinkLED(void) +{ + lcd_setReg(0x07, 0x17); // blink every second + lcd_setReg(0x06, 0x7f); // half on, half off +} + +void lcd_noBlinkLED(void) +{ + lcd_setReg(0x07, 0x00); + lcd_setReg(0x06, 0xff); +} + +void lcd_begin(void) +{ + _displayfunction |= LCD_5x8DOTS; + _displayfunction |= LCD_2LINE; + + + // Send function set command sequence + lcd_command(LCD_FUNCTIONSET | _displayfunction); + mdelay(5); // wait more than 4.1ms + + // second try + lcd_command(LCD_FUNCTIONSET | _displayfunction); + mdelay(1); + + // third go + lcd_command(LCD_FUNCTIONSET | _displayfunction); + + + // finally, set # lines, font size, etc. + lcd_command(LCD_FUNCTIONSET | _displayfunction); + + // turn the display on with no cursor or blinking default + _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; + lcd_display(); + + // clear it off + lcd_clear(); + + // Initialize to default text direction (for romance languages) + _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT; + // set the entry mode + lcd_command(LCD_ENTRYMODESET | _displaymode); + + + // backlight init + lcd_setReg(REG_MODE1, 0); + // set LEDs controllable by both PWM and GRPPWM registers + lcd_setReg(REG_OUTPUT, 0xFF); + // set MODE2 values + // 0010 0000 -> 0x20 (DMBLNK to 1, ie blinky mode) + lcd_setReg(REG_MODE2, 0x20); + + lcd_setColor(WHITE); + +} + +//--- Comand for printing ------------------------------- +void lcd_print(char c[]) +{ + int n; + for (n=0; c[n] != '\0'; n++) lcd_write(c[n]); +} + + diff --git a/Grove_LCD_rgb_V2.0.h b/Grove_LCD_rgb_V2.0.h new file mode 100644 index 0000000..f676097 --- /dev/null +++ b/Grove_LCD_rgb_V2.0.h @@ -0,0 +1,99 @@ +#ifndef GROVE_LCD_H_ +#define GROVE_LCD_H_ + +// Device I2C Arress +#define LCD_ADDRESS 0x7c +#define RGB_ADDRESS 0xc4 + +// Set colors +enum color { + AQUA = 0x00FFFF, + BLACK = 0x000000, + BLUE = 0x0000FF, + PURPLE = 0xFF00FF, + GREEN = 0x00FF00, + RED = 0xFF0000, + WHITE = 0xFFFFFF, + YELLOW = 0xFFFF00 +}; + +#define REG_RED 0x04 // pwm2 +#define REG_GREEN 0x03 // pwm1 +#define REG_BLUE 0x02 // pwm0 + +#define REG_MODE1 0x00 +#define REG_MODE2 0x01 +#define REG_OUTPUT 0x08 + +// 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 +#define LCD_ENTRYRIGHT 0x00 +#define LCD_ENTRYLEFT 0x02 +#define LCD_ENTRYSHIFTINCREMENT 0x01 +#define LCD_ENTRYSHIFTDECREMENT 0x00 + +// flags for display on/off control +#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 +#define LCD_DISPLAYMOVE 0x08 +#define LCD_CURSORMOVE 0x00 +#define LCD_MOVERIGHT 0x04 +#define LCD_MOVELEFT 0x00 + +// flags for function set +#define LCD_8BITMODE 0x10 +#define LCD_4BITMODE 0x00 +#define LCD_2LINE 0x08 +#define LCD_5x8DOTS 0x00 + +void lcd_print(char c[]); +int lcd_write(char value); +// TODO may be. +// void lcd_print_DEC(int i); +// void lcd_print_HEX(int i); +// void lcd_print_OCT(int i); +// void lcd_print_BIN(int i); +void lcd_begin(void); +void lcd_clear(void); +void lcd_home(void); + +void lcd_noDisplay(void); +void lcd_display(void); +void lcd_noBlink(void); +void lcd_blink(void); +void lcd_noCursor(void); +void lcd_cursor(void); +void lcd_scrollDisplayLeft(void); +void lcd_scrollDisplayRight(void); +void lcd_leftToRight(void); +void lcd_rightToLeft(void); +void lcd_autoscroll(void); +void lcd_noAutoscroll(void); + +void lcd_createChar(int, int[]); +void lcd_setCursor(int, int); + +// color control +void lcd_setRGB(unsigned char r, unsigned char g, unsigned char b);// set rgb +void lcd_setColor(enum color c); + +// blink the LED backlight +void lcd_blinkLED(void); +void lcd_noBlinkLED(void); + +#endif /* GROVE_LCD_H_ */ \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..921b35e --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +obj-m += modq.o +modq-objs := mod.o Grove_LCD_rgb_V2.0.o +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean diff --git a/mod.c b/mod.c new file mode 100644 index 0000000..9009b22 --- /dev/null +++ b/mod.c @@ -0,0 +1,204 @@ +#include +#include +#include +#include +#include +#include + +#include "Grove_LCD_rgb_V2.0.h" + +// ADD device i2c +// echo grove_lcd 0x3e | sudo tee /sys/class/i2c-adapter/i2c-1/new_device +// echo grove_rgb 0x62 | sudo tee /sys/class/i2c-adapter/i2c-1/new_device +// Delete i2c device +// echo 0x3e | sudo tee /sys/class/i2c-adapter/i2c-1/delete_device +// echo 0x62 | sudo tee /sys/class/i2c-adapter/i2c-1/delete_device +// Test i2c +// i2cdetect -y 1 + +struct i2c_client *i2c_client_lcd; +struct i2c_client *i2c_client_rgb; + +#define DEVICE_NAME "grove_lcd" +#define CLASS_NAME "grove_lcd_lcd" +static int majorNumber; +static struct class* grove_lcd_class = NULL; +static struct device* grove_lcd_device = NULL; +static int is_device_open = 0; + + + +// --- Driver for display (grove_lcd) ---------------------------- +static const struct i2c_device_id grove_lcd_id[] = { + { "grove_lcd", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, grove_lcd_id); + +static int grove_lcd_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + + i2c_client_lcd = client; + return 0; +} + +static int grove_lcd_remove(struct i2c_client *client) +{ + return 0; +} + +static struct i2c_driver grove_lcd_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "grove_lcd", + }, + .probe = grove_lcd_probe, + .remove = grove_lcd_remove, + .id_table = grove_lcd_id, +}; + +// --- Driver for LED (grove_rgb) -------------------------------- +static const struct i2c_device_id grove_rgb_id[] = { + { "grove_rgb", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, grove_rgb_id); + +static int grove_rgb_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + i2c_client_rgb = client; + lcd_begin(); + lcd_print("Grove_LCD start!"); + return 0; +} + +static int grove_rgb_remove(struct i2c_client *client) +{ + return 0; +} + +static struct i2c_driver grove_rgb_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "grove_rgb", + }, + .probe = grove_rgb_probe, + .remove = grove_rgb_remove, + .id_table = grove_rgb_id, +}; + +// --- Device ---------------------------------------------------- + +static int device_open( struct inode *inode, struct file *file ) +{ + if ( is_device_open ) return -EBUSY; + is_device_open++; + return 0; +} + +static int device_release( struct inode *inode, struct file *file ) +{ + is_device_open--; + return 0; +} + +static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t * offset) +{ + int i; + if (buff[0] == '@') + { + if (buff[1] == 'A') lcd_setColor(AQUA); + if (buff[1] == 'B') lcd_setColor(BLUE); + if (buff[1] == 'P') lcd_setColor(PURPLE); + if (buff[1] == 'G') lcd_setColor(GREEN); + if (buff[1] == 'R') lcd_setColor(RED); + if (buff[1] == 'W') lcd_setColor(WHITE); + if (buff[1] == 'Y') lcd_setColor(YELLOW); + + if (buff[1] == 'L') + { + if (buff[1] == '1') lcd_setCursor(0,1); + if (buff[1] == '0') lcd_setCursor(0,0); + } + + if (buff[1] == 'H') lcd_home(); + if (buff[1] == 'C') lcd_clear(); + return len; + } + for (i=0; i /dev/nul +echo grove_rgb 0x62 | sudo tee /sys/class/i2c-adapter/i2c-1/new_device > /dev/nul + +while [ "$B" != "exid" ] +do + echo "Enter print string:" + read B + if [ "$B" != "exid" ] + then + sudo echo "@C" | sudo tee /dev/grove_lcd > /dev/nul + fi + if [ "$B" != "exid" ] + then + sudo echo $B | sudo tee /dev/grove_lcd > /dev/nul + fi +done +echo "Close display menager." + +echo 0x62 | sudo tee /sys/class/i2c-adapter/i2c-1/delete_device > /dev/nul +echo 0x3e | sudo tee /sys/class/i2c-adapter/i2c-1/delete_device > /dev/nul +sudo rmmod modq.ko \ No newline at end of file