qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

hd44780.c (7180B)


      1 /*
      2 Copyright 2022
      3 
      4 This program is free software: you can redistribute it and/or modify
      5 it under the terms of the GNU General Public License as published by
      6 the Free Software Foundation, either version 2 of the License, or
      7 (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 GNU General Public License for more details.
     13 
     14 You should have received a copy of the GNU General Public License
     15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
     16 */
     17 
     18 #include "hd44780.h"
     19 #include "gpio.h"
     20 #include "progmem.h"
     21 #include "wait.h"
     22 
     23 #ifndef HD44780_DATA_PINS
     24 #    error hd44780: no data pins defined!
     25 #endif
     26 
     27 #ifndef HD44780_RS_PIN
     28 #    error hd44780: no RS pin defined!
     29 #endif
     30 
     31 #ifndef HD44780_RW_PIN
     32 #    error hd44780: no R/W pin defined!
     33 #endif
     34 
     35 #ifndef HD44780_E_PIN
     36 #    error hd44780: no E pin defined!
     37 #endif
     38 
     39 static const pin_t data_pins[4] = HD44780_DATA_PINS;
     40 
     41 #ifndef HD44780_DISPLAY_COLS
     42 #    define HD44780_DISPLAY_COLS 16
     43 #endif
     44 
     45 #ifndef HD44780_DISPLAY_LINES
     46 #    define HD44780_DISPLAY_LINES 2
     47 #endif
     48 
     49 #ifndef HD44780_DDRAM_LINE0_ADDR
     50 #    define HD44780_DDRAM_LINE0_ADDR 0x00
     51 #endif
     52 #ifndef HD44780_DDRAM_LINE1_ADDR
     53 #    define HD44780_DDRAM_LINE1_ADDR 0x40
     54 #endif
     55 
     56 #define HD44780_INIT_DELAY_MS 16
     57 #define HD44780_ENABLE_DELAY_US 1
     58 
     59 static void hd44780_latch(void) {
     60     gpio_write_pin_high(HD44780_E_PIN);
     61     wait_us(HD44780_ENABLE_DELAY_US);
     62     gpio_write_pin_low(HD44780_E_PIN);
     63 }
     64 
     65 void hd44780_write(uint8_t data, bool isData) {
     66     gpio_write_pin(HD44780_RS_PIN, isData);
     67     gpio_write_pin_low(HD44780_RW_PIN);
     68 
     69     for (int i = 0; i < 4; i++) {
     70         gpio_set_pin_output(data_pins[i]);
     71     }
     72 
     73     // Write high nibble
     74     for (int i = 0; i < 4; i++) {
     75         gpio_write_pin(data_pins[i], (data >> 4) & (1 << i));
     76     }
     77     hd44780_latch();
     78 
     79     // Write low nibble
     80     for (int i = 0; i < 4; i++) {
     81         gpio_write_pin(data_pins[i], data & (1 << i));
     82     }
     83     hd44780_latch();
     84 
     85     for (int i = 0; i < 4; i++) {
     86         gpio_write_pin_high(data_pins[i]);
     87     }
     88 }
     89 
     90 uint8_t hd44780_read(bool isData) {
     91     uint8_t data = 0;
     92 
     93     gpio_write_pin(HD44780_RS_PIN, isData);
     94     gpio_write_pin_high(HD44780_RW_PIN);
     95 
     96     for (int i = 0; i < 4; i++) {
     97         gpio_set_pin_input(data_pins[i]);
     98     }
     99 
    100     gpio_write_pin_high(HD44780_E_PIN);
    101     wait_us(HD44780_ENABLE_DELAY_US);
    102 
    103     // Read high nibble
    104     for (int i = 0; i < 4; i++) {
    105         data |= (gpio_read_pin(data_pins[i]) << i);
    106     }
    107 
    108     data <<= 4;
    109 
    110     gpio_write_pin_low(HD44780_E_PIN);
    111     wait_us(HD44780_ENABLE_DELAY_US);
    112     gpio_write_pin_high(HD44780_E_PIN);
    113     wait_us(HD44780_ENABLE_DELAY_US);
    114 
    115     // Read low nibble
    116     for (int i = 0; i < 4; i++) {
    117         data |= (gpio_read_pin(data_pins[i]) << i);
    118     }
    119 
    120     gpio_write_pin_low(HD44780_E_PIN);
    121 
    122     return data;
    123 }
    124 
    125 bool hd44780_busy(void) {
    126     return hd44780_read(false) & HD44780_BUSY_FLAG;
    127 }
    128 
    129 void hd44780_command(uint8_t command) {
    130     while (hd44780_busy())
    131         ;
    132     hd44780_write(command, false);
    133 }
    134 
    135 void hd44780_data(uint8_t data) {
    136     while (hd44780_busy())
    137         ;
    138     hd44780_write(data, true);
    139 }
    140 
    141 void hd44780_clear(void) {
    142     hd44780_command(HD44780_CMD_CLEAR_DISPLAY);
    143 }
    144 
    145 void hd44780_home(void) {
    146     hd44780_command(HD44780_CMD_RETURN_HOME);
    147 }
    148 
    149 void hd44780_on(bool cursor, bool blink) {
    150     if (cursor) {
    151         if (blink) {
    152             hd44780_command(HD44780_CMD_DISPLAY | HD44780_DISPLAY_ON | HD44780_DISPLAY_CURSOR | HD44780_DISPLAY_BLINK);
    153         } else {
    154             hd44780_command(HD44780_CMD_DISPLAY | HD44780_DISPLAY_ON | HD44780_DISPLAY_CURSOR);
    155         }
    156     } else {
    157         hd44780_command(HD44780_CMD_DISPLAY | HD44780_DISPLAY_ON);
    158     }
    159 }
    160 
    161 void hd44780_off(void) {
    162     hd44780_command(HD44780_CMD_DISPLAY);
    163 }
    164 
    165 void hd44780_set_cgram_address(uint8_t address) {
    166     hd44780_command(HD44780_CMD_SET_CGRAM_ADDRESS + (address & 0x3F));
    167 }
    168 
    169 void hd44780_set_ddram_address(uint8_t address) {
    170     hd44780_command(HD44780_CMD_SET_DDRAM_ADDRESS + (address & 0x7F));
    171 }
    172 
    173 void hd44780_init(bool cursor, bool blink) {
    174     gpio_set_pin_output(HD44780_RS_PIN);
    175     gpio_set_pin_output(HD44780_RW_PIN);
    176     gpio_set_pin_output(HD44780_E_PIN);
    177 
    178     for (int i = 0; i < 4; i++) {
    179         gpio_set_pin_output(data_pins[i]);
    180     }
    181 
    182     wait_ms(HD44780_INIT_DELAY_MS);
    183 
    184     // Manually configure for 4-bit mode - can't use hd44780_command() yet
    185     // HD44780U datasheet, Fig. 24 (p46)
    186     gpio_write_pin_high(data_pins[0]); // Function set
    187     gpio_write_pin_high(data_pins[1]); // DL = 1
    188     hd44780_latch();
    189     wait_ms(5);
    190     // Send again
    191     hd44780_latch();
    192     wait_us(64);
    193     // And again (?)
    194     hd44780_latch();
    195     wait_us(64);
    196 
    197     gpio_write_pin_low(data_pins[0]); // DL = 0
    198     hd44780_latch();
    199     wait_us(64);
    200 
    201 #if HD44780_DISPLAY_LINES == 1
    202     hd44780_command(HD44780_CMD_FUNCTION); // 4 bit, 1 line, 5x8 dots
    203 #else
    204     hd44780_command(HD44780_CMD_FUNCTION | HD44780_FUNCTION_2_LINES); // 4 bit, 2 lines, 5x8 dots
    205 #endif
    206     hd44780_on(cursor, blink);
    207     hd44780_clear();
    208     hd44780_home();
    209     hd44780_command(HD44780_CMD_ENTRY_MODE | HD44780_ENTRY_MODE_INC);
    210 }
    211 
    212 void hd44780_set_cursor(uint8_t col, uint8_t line) {
    213     register uint8_t address = col;
    214 
    215 #if HD44780_DISPLAY_LINES == 1
    216     address += HD44780_DDRAM_LINE0_ADDR;
    217 #elif HD44780_DISPLAY_LINES == 2
    218     if (line == 0) {
    219         address += HD44780_DDRAM_LINE0_ADDR;
    220     } else {
    221         address += HD44780_DDRAM_LINE1_ADDR;
    222     }
    223 #endif
    224 
    225     hd44780_set_ddram_address(address);
    226 }
    227 
    228 void hd44780_define_char(uint8_t index, uint8_t *data) {
    229     hd44780_set_cgram_address((index & 0x7) << 3);
    230     for (uint8_t i = 0; i < 8; i++) {
    231         hd44780_data(data[i]);
    232     }
    233 }
    234 
    235 void hd44780_putc(char c) {
    236     while (hd44780_busy())
    237         ;
    238     uint8_t current_position = hd44780_read(false);
    239 
    240     if (c == '\n') {
    241         hd44780_set_cursor(0, current_position < HD44780_DDRAM_LINE1_ADDR ? 1 : 0);
    242     } else {
    243 #if defined(HD44780_WRAP_LINES)
    244 #    if HD44780_DISPLAY_LINES == 1
    245         if (current_position == HD44780_DDRAM_LINE0_ADDR + HD44780_DISPLAY_COLS) {
    246             // Go to start of line
    247             hd44780_set_cursor(0, 0);
    248         }
    249 #    elif HD44780_DISPLAY_LINES == 2
    250         if (current_position == HD44780_DDRAM_LINE0_ADDR + HD44780_DISPLAY_COLS) {
    251             // Go to start of second line
    252             hd44780_set_cursor(0, 1);
    253         } else if (current_position == HD44780_DDRAM_LINE1_ADDR + HD44780_DISPLAY_COLS) {
    254             // Go to start of first line
    255             hd44780_set_cursor(0, 0);
    256         }
    257 #    endif
    258 #endif
    259         hd44780_data(c);
    260     }
    261 }
    262 
    263 void hd44780_puts(const char *s) {
    264     register char c;
    265     while ((c = *s++)) {
    266         hd44780_putc(c);
    267     }
    268 }
    269 
    270 #if defined(__AVR__)
    271 void hd44780_define_char_P(uint8_t index, const uint8_t *data) {
    272     hd44780_set_cgram_address(index << 3);
    273     for (uint8_t i = 0; i < 8; i++) {
    274         hd44780_data(pgm_read_byte(data++));
    275     }
    276 }
    277 
    278 void hd44780_puts_P(const char *s) {
    279     register char c;
    280     while ((c = pgm_read_byte(s++))) {
    281         hd44780_putc(c);
    282     }
    283 }
    284 #endif