parent
9f840e5ce0
commit
950cc7012a
@ -0,0 +1,222 @@ |
||||
#include "Grove_LCD_rgb_V2.0.h" |
||||
#include <linux/init.h> |
||||
#include <linux/module.h> |
||||
#include <linux/i2c.h> |
||||
#include <linux/delay.h> |
||||
|
||||
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]); |
||||
} |
||||
|
||||
|
@ -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_ */ |
@ -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
|
@ -0,0 +1,204 @@ |
||||
#include <linux/init.h> |
||||
#include <linux/module.h> |
||||
#include <linux/i2c.h> |
||||
#include <linux/slab.h> |
||||
#include <linux/fs.h> |
||||
#include <asm/uaccess.h> |
||||
|
||||
#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<len-1; i++) |
||||
{ |
||||
lcd_write(buff[i]); |
||||
} |
||||
//printk(" --- buf: %s", buff);
|
||||
return len; |
||||
} |
||||
|
||||
static ssize_t device_read( struct file *filp, char *buffer, size_t length, loff_t * offset ) |
||||
{ |
||||
char ch[] = "Grove-LCD: Pleas print IN display.\n";
|
||||
printk (ch); |
||||
//copy_to_user(buffer, ch, sizeof(ch));
|
||||
return 0; |
||||
} |
||||
|
||||
static struct file_operations fops = |
||||
{ |
||||
.read = device_read, |
||||
.write = device_write, |
||||
.open = device_open, |
||||
.release = device_release |
||||
}; |
||||
|
||||
// --- Init module -----------------------------------------------
|
||||
|
||||
|
||||
static int __init grove_lcd_init(void) { |
||||
printk("Grove-LCD: display modele - start.\n"); |
||||
majorNumber = register_chrdev(0, DEVICE_NAME, &fops); |
||||
if (majorNumber<0){ |
||||
printk(KERN_ALERT "Grove-LCD: failed to register a major number\n"); |
||||
return majorNumber; |
||||
} |
||||
printk(KERN_INFO "Grove-LCD: registered correctly with major number %d\n", majorNumber); |
||||
|
||||
grove_lcd_class = class_create(THIS_MODULE, CLASS_NAME); |
||||
if (IS_ERR(grove_lcd_class)){ |
||||
unregister_chrdev(majorNumber, DEVICE_NAME); |
||||
printk(KERN_ALERT "Grove-LCD: Failed to register device class\n"); |
||||
return PTR_ERR(grove_lcd_class); |
||||
} |
||||
printk(KERN_INFO "Grove-LCD: device class registered correctly\n"); |
||||
|
||||
grove_lcd_device = device_create(grove_lcd_class, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME); |
||||
if (IS_ERR(grove_lcd_device)){
|
||||
class_destroy(grove_lcd_class); |
||||
unregister_chrdev(majorNumber, DEVICE_NAME); |
||||
printk(KERN_ALERT "Grove-LCD: Failed to create the device\n"); |
||||
return PTR_ERR(grove_lcd_device); |
||||
} |
||||
printk("Grove-LCD: device class created correctly\n"); |
||||
|
||||
i2c_add_driver(&grove_lcd_driver); |
||||
i2c_add_driver(&grove_rgb_driver); |
||||
return 0; |
||||
} |
||||
static void __exit grove_lcd_exit(void) { |
||||
|
||||
device_destroy(grove_lcd_class, MKDEV(majorNumber, 0)); |
||||
class_unregister(grove_lcd_class); |
||||
class_destroy(grove_lcd_class); |
||||
unregister_chrdev(majorNumber, DEVICE_NAME); |
||||
|
||||
i2c_del_driver(&grove_lcd_driver); |
||||
i2c_del_driver(&grove_rgb_driver); |
||||
printk("Grove-LCD: display modele - kill.\n"); |
||||
} |
||||
|
||||
|
||||
module_init(grove_lcd_init); |
||||
module_exit(grove_lcd_exit); |
||||
|
||||
|
||||
|
||||
MODULE_LICENSE("GPL"); |
||||
MODULE_AUTHOR("ZEN");
|
@ -0,0 +1,6 @@ |
||||
#!/bin/bash |
||||
|
||||
make |
||||
sudo insmod modq.ko |
||||
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 |
@ -0,0 +1,4 @@ |
||||
#!/bin/bash |
||||
echo 0x62 | sudo tee /sys/class/i2c-adapter/i2c-1/delete_device |
||||
echo 0x3e | sudo tee /sys/class/i2c-adapter/i2c-1/delete_device |
||||
sudo rmmod modq.ko |
@ -0,0 +1,24 @@ |
||||
#!/bin/bash |
||||
|
||||
sudo insmod modq.ko |
||||
echo grove_lcd 0x3e | sudo tee /sys/class/i2c-adapter/i2c-1/new_device > /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 |
Loading…
Reference in new issue