Steve Jeong | 8a77459 | 2023-06-01 18:36:00 +0900 | [diff] [blame] | 1 | /* |
| 2 | * i2c_lcd.c: |
| 3 | * Standard "i2c_lcd" program in wiringPi. |
| 4 | * Supports 16x2 and 20x4 screens. |
| 5 | * reference: lcd_i2c.py (https://bitbucket.org/MattHawkinsUK/rpispy-misc/raw/master/python/lcd_i2c.py) |
| 6 | * |
| 7 | * Copyright (C) 2023 Steve Jeong |
| 8 | * |
| 9 | * This program is free software: you can redistribute it and/or modify |
| 10 | * it under the terms of the GNU General Public License as published by |
| 11 | * the Free Software Foundation, either version 3 of the License, or |
| 12 | * (at your option) any later version. |
| 13 | * |
| 14 | * This program is distributed in the hope that it will be useful, |
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 17 | * GNU General Public License for more details. |
| 18 | * |
| 19 | * You should have received a copy of the GNU General Public License |
| 20 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 21 | */ |
| 22 | |
| 23 | #include <wiringPiI2C.h> |
| 24 | #include <wiringPi.h> |
| 25 | #include <stdlib.h> |
| 26 | #include <string.h> |
| 27 | #include <stdio.h> |
| 28 | |
| 29 | // Define some device parameters |
| 30 | #define I2C_ADDR 0x3f // I2C device address |
Steve Jeong | 8a77459 | 2023-06-01 18:36:00 +0900 | [diff] [blame] | 31 | |
| 32 | // Define some device constants |
| 33 | #define LCD_CHR 1 // Mode - Sending data |
| 34 | #define LCD_CMD 0 // Mode - Sending command |
| 35 | |
| 36 | #define LINE1 0x80 // 1st line |
| 37 | #define LINE2 0xC0 // 2nd line |
| 38 | #define LINE3 0x94 // 3rd line |
| 39 | #define LINE4 0xD4 // 4th line |
| 40 | |
| 41 | #define LCD_BACKLIGHT 0x08 // On |
Steve Jeong | 18668e8 | 2023-06-02 11:43:29 +0900 | [diff] [blame] | 42 | // #define LCD_BACKLIGHT 0x00 // Off |
Steve Jeong | 8a77459 | 2023-06-01 18:36:00 +0900 | [diff] [blame] | 43 | |
| 44 | #define ENABLE 0b00000100 // Enable bit |
| 45 | |
| 46 | void lcd_init(void); |
| 47 | void lcd_byte(int bits, int mode); |
| 48 | void lcd_toggle_enable(int bits); |
| 49 | void display_string(const char *string, int line); |
| 50 | |
| 51 | int fd; |
Steve Jeong | 18668e8 | 2023-06-02 11:43:29 +0900 | [diff] [blame] | 52 | char *bus = "0"; /* /dev/i2c-0 ~ /dev/i2c-9 */ |
| 53 | int address = 0x3f; |
Steve Jeong | 8a77459 | 2023-06-01 18:36:00 +0900 | [diff] [blame] | 54 | |
| 55 | int main(int argc, char *argv[]) { |
| 56 | |
Steve Jeong | 18668e8 | 2023-06-02 11:43:29 +0900 | [diff] [blame] | 57 | char device[12]; |
Steve Jeong | 8a77459 | 2023-06-01 18:36:00 +0900 | [diff] [blame] | 58 | |
| 59 | if (wiringPiSetup () == -1) |
| 60 | exit (1); |
| 61 | |
| 62 | if (argc > 1) |
| 63 | address = strtoul(argv[1], NULL, 16); |
| 64 | |
| 65 | if (argc > 2) { |
| 66 | bus = argv[1]; |
| 67 | address = strtoul(argv[2], NULL, 16); |
| 68 | } |
| 69 | |
Steve Jeong | 18668e8 | 2023-06-02 11:43:29 +0900 | [diff] [blame] | 70 | snprintf(device, 11, "%s%s", "/dev/i2c-", bus); |
Steve Jeong | 8a77459 | 2023-06-01 18:36:00 +0900 | [diff] [blame] | 71 | fd = wiringPiI2CSetupInterface(device, address); |
| 72 | |
| 73 | lcd_init(); // setup LCD |
| 74 | |
| 75 | while (1) { |
Steve Jeong | 18668e8 | 2023-06-02 11:43:29 +0900 | [diff] [blame] | 76 | display_string("HardKernel", LINE1); |
Steve Jeong | 8a77459 | 2023-06-01 18:36:00 +0900 | [diff] [blame] | 77 | display_string("Hello ODROID", LINE2); |
| 78 | } |
| 79 | |
| 80 | return 0; |
Steve Jeong | 8a77459 | 2023-06-01 18:36:00 +0900 | [diff] [blame] | 81 | } |
| 82 | |
| 83 | void display_string(const char *string, int line) { |
| 84 | // go to location on LCD |
| 85 | lcd_byte(line, LCD_CMD); |
| 86 | |
Steve Jeong | 18668e8 | 2023-06-02 11:43:29 +0900 | [diff] [blame] | 87 | while (*string) { |
| 88 | lcd_byte(*(string++), LCD_CHR); |
Steve Jeong | 8a77459 | 2023-06-01 18:36:00 +0900 | [diff] [blame] | 89 | } |
| 90 | |
Steve Jeong | 8a77459 | 2023-06-01 18:36:00 +0900 | [diff] [blame] | 91 | } |
| 92 | |
| 93 | void lcd_byte(int bits, int mode) { |
| 94 | |
| 95 | //Send byte to data pins |
| 96 | // bits = the data |
| 97 | // mode = 1 for data, 0 for command |
| 98 | int bits_high; |
| 99 | int bits_low; |
| 100 | // uses the two half byte writes to LCD |
Steve Jeong | 18668e8 | 2023-06-02 11:43:29 +0900 | [diff] [blame] | 101 | bits_high = mode | (bits & 0xf0) | LCD_BACKLIGHT; |
| 102 | bits_low = mode | ((bits << 4) & 0xf0) | LCD_BACKLIGHT; |
Steve Jeong | 8a77459 | 2023-06-01 18:36:00 +0900 | [diff] [blame] | 103 | |
| 104 | // High bits |
| 105 | wiringPiI2CReadReg8(fd, bits_high); |
| 106 | lcd_toggle_enable(bits_high); |
| 107 | |
| 108 | // Low bits |
| 109 | wiringPiI2CReadReg8(fd, bits_low); |
| 110 | lcd_toggle_enable(bits_low); |
| 111 | } |
| 112 | |
Steve Jeong | 18668e8 | 2023-06-02 11:43:29 +0900 | [diff] [blame] | 113 | void lcd_toggle_enable(int bits) { |
Steve Jeong | 8a77459 | 2023-06-01 18:36:00 +0900 | [diff] [blame] | 114 | // Toggle enable pin on LCD display |
| 115 | delayMicroseconds(500); |
| 116 | wiringPiI2CReadReg8(fd, (bits | ENABLE)); |
| 117 | delayMicroseconds(500); |
| 118 | wiringPiI2CReadReg8(fd, (bits & ~ENABLE)); |
| 119 | delayMicroseconds(500); |
| 120 | } |
| 121 | |
Steve Jeong | 18668e8 | 2023-06-02 11:43:29 +0900 | [diff] [blame] | 122 | void lcd_init() { |
Steve Jeong | 8a77459 | 2023-06-01 18:36:00 +0900 | [diff] [blame] | 123 | // Initialise display |
| 124 | lcd_byte(0x33, LCD_CMD); // Initialise |
| 125 | lcd_byte(0x32, LCD_CMD); // Initialise |
| 126 | lcd_byte(0x06, LCD_CMD); // Cursor move direction |
| 127 | lcd_byte(0x0C, LCD_CMD); // 0x0F On, Blink Off |
| 128 | lcd_byte(0x28, LCD_CMD); // Data length, number of lines, font size |
| 129 | lcd_byte(0x01, LCD_CMD); // Clear display |
| 130 | delayMicroseconds(1000); |
| 131 | } |