diff options
| -rw-r--r-- | common_features.mk | 6 | ||||
| -rw-r--r-- | docs/feature_hd44780.md | 56 | ||||
| -rw-r--r-- | docs/features.md | 1 | ||||
| -rw-r--r-- | drivers/avr/hd44780.c | 592 | ||||
| -rw-r--r-- | drivers/avr/hd44780.h | 371 | ||||
| -rw-r--r-- | quantum/quantum.c | 4 | ||||
| -rw-r--r-- | quantum/quantum.h | 4 | ||||
| -rw-r--r-- | quantum/template/avr/config.h | 28 | ||||
| -rw-r--r-- | quantum/template/avr/rules.mk | 1 | ||||
| -rw-r--r-- | tmk_core/common/keyboard.c | 3 |
10 files changed, 1066 insertions, 0 deletions
diff --git a/common_features.mk b/common_features.mk index 0778f8e0f..b12b6ae51 100644 --- a/common_features.mk +++ b/common_features.mk | |||
| @@ -197,6 +197,12 @@ ifeq ($(strip $(USB_HID_ENABLE)), yes) | |||
| 197 | include $(TMK_DIR)/protocol/usb_hid.mk | 197 | include $(TMK_DIR)/protocol/usb_hid.mk |
| 198 | endif | 198 | endif |
| 199 | 199 | ||
| 200 | |||
| 201 | ifeq ($(strip $(HD44780_ENABLE)), yes) | ||
| 202 | SRC += drivers/avr/hd44780.c | ||
| 203 | OPT_DEFS += -DHD44780_ENABLE | ||
| 204 | endif | ||
| 205 | |||
| 200 | QUANTUM_SRC:= \ | 206 | QUANTUM_SRC:= \ |
| 201 | $(QUANTUM_DIR)/quantum.c \ | 207 | $(QUANTUM_DIR)/quantum.c \ |
| 202 | $(QUANTUM_DIR)/keymap_common.c \ | 208 | $(QUANTUM_DIR)/keymap_common.c \ |
diff --git a/docs/feature_hd44780.md b/docs/feature_hd44780.md new file mode 100644 index 000000000..e9d9e8b7b --- /dev/null +++ b/docs/feature_hd44780.md | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | # HD44780 LCD Displays | ||
| 2 | |||
| 3 | This is an integration of Peter Fleury's LCD library. This page will explain the basics. [For in depth documentation visit his page.](http://homepage.hispeed.ch/peterfleury/doxygen/avr-gcc-libraries/group__pfleury__lcd.html) | ||
| 4 | |||
| 5 | You can enable support for HD44780 Displays by setting the `HD44780_ENABLE` flag in your keyboards `rules.mk` to yes. This will use about 400 KB of extra space. | ||
| 6 | |||
| 7 | ## Configuration | ||
| 8 | |||
| 9 | You will need to configure the pins used by your display and its number of lines and collumn in your keyboards `config.h`. | ||
| 10 | |||
| 11 | Uncomment the section labled HD44780 and change the parameters as needed. | ||
| 12 | ```` | ||
| 13 | /* | ||
| 14 | * HD44780 LCD Display Configuration | ||
| 15 | */ | ||
| 16 | |||
| 17 | #define LCD_LINES 2 //< number of visible lines of the display | ||
| 18 | #define LCD_DISP_LENGTH 16 //< visibles characters per line of the display | ||
| 19 | #define LCD_IO_MODE 1 //< 0: memory mapped mode, 1: IO port mode | ||
| 20 | #if LCD_IO_MODE | ||
| 21 | #define LCD_PORT PORTB //< port for the LCD lines | ||
| 22 | #define LCD_DATA0_PORT LCD_PORT //< port for 4bit data bit 0 | ||
| 23 | #define LCD_DATA1_PORT LCD_PORT //< port for 4bit data bit 1 | ||
| 24 | #define LCD_DATA2_PORT LCD_PORT //< port for 4bit data bit 2 | ||
| 25 | #define LCD_DATA3_PORT LCD_PORT //< port for 4bit data bit 3 | ||
| 26 | #define LCD_DATA0_PIN 4 //< pin for 4bit data bit 0 | ||
| 27 | #define LCD_DATA1_PIN 5 //< pin for 4bit data bit 1 | ||
| 28 | #define LCD_DATA2_PIN 6 //< pin for 4bit data bit 2 | ||
| 29 | #define LCD_DATA3_PIN 7 //< pin for 4bit data bit 3 | ||
| 30 | #define LCD_RS_PORT LCD_PORT //< port for RS line | ||
| 31 | #define LCD_RS_PIN 3 //< pin for RS line | ||
| 32 | #define LCD_RW_PORT LCD_PORT //< port for RW line | ||
| 33 | #define LCD_RW_PIN 2 //< pin for RW line | ||
| 34 | #define LCD_E_PORT LCD_PORT //< port for Enable line | ||
| 35 | #define LCD_E_PIN 1 //< pin for Enable line | ||
| 36 | #endif | ||
| 37 | ```` | ||
| 38 | |||
| 39 | Should you need to configure other properties you can copy them from `quantum/hd44780.h` and set them in your `config.h` | ||
| 40 | |||
| 41 | ## Usage | ||
| 42 | |||
| 43 | To initialize your display call lcd_init() with one of these parameters: | ||
| 44 | ```` | ||
| 45 | LCD_DISP_OFF : display off | ||
| 46 | LCD_DISP_ON : display on, cursor off | ||
| 47 | LCD_DISP_ON_CURSOR : display on, cursor on | ||
| 48 | LCD_DISP_ON_CURSOR_BLINK : display on, cursor on flashing | ||
| 49 | ```` | ||
| 50 | This is best done in your keyboards `matrix_init_kb` or your keymaps `matrix_init_user`. | ||
| 51 | It is advised to clear the display before use. | ||
| 52 | To do so call `lcd_clrsrc()`. | ||
| 53 | |||
| 54 | To now print something to your Display you first call `lcd_gotoxy(column, line)`. To go to the start of the first line you would call `lcd_gotoxy(0, 0)` and then print a string with `lcd_puts("example string")`. | ||
| 55 | |||
| 56 | There are more posible methods to control the display. [For in depth documentation please visit the linked page.](http://homepage.hispeed.ch/peterfleury/doxygen/avr-gcc-libraries/group__pfleury__lcd.html) | ||
diff --git a/docs/features.md b/docs/features.md index 4dee486ef..d8ca3780d 100644 --- a/docs/features.md +++ b/docs/features.md | |||
| @@ -9,6 +9,7 @@ QMK has a staggering number of features for building your keyboard. It can take | |||
| 9 | * [Backlight](feature_backlight.md) - LED lighting support for your keyboard. | 9 | * [Backlight](feature_backlight.md) - LED lighting support for your keyboard. |
| 10 | * [Bootmagic](feature_bootmagic.md) - Adjust the behavior of your keyboard using hotkeys. | 10 | * [Bootmagic](feature_bootmagic.md) - Adjust the behavior of your keyboard using hotkeys. |
| 11 | * [Dynamic Macros](feature_dynamic_macros.md) - Record and playback macros from the keyboard itself. | 11 | * [Dynamic Macros](feature_dynamic_macros.md) - Record and playback macros from the keyboard itself. |
| 12 | * [HD44780 LCD Display](feature_hd44780.md) - Support for LCD character displays using the HD44780 standard. | ||
| 12 | * [Key Lock](feature_key_lock.md) - Lock a key in the "down" state. | 13 | * [Key Lock](feature_key_lock.md) - Lock a key in the "down" state. |
| 13 | * [Layouts](feature_layouts.md) - Use one keymap with any keyboard that supports your layout. | 14 | * [Layouts](feature_layouts.md) - Use one keymap with any keyboard that supports your layout. |
| 14 | * [Leader Key](feature_leader_key.md) - Tap the leader key followed by a sequence to trigger custom behavior. | 15 | * [Leader Key](feature_leader_key.md) - Tap the leader key followed by a sequence to trigger custom behavior. |
diff --git a/drivers/avr/hd44780.c b/drivers/avr/hd44780.c new file mode 100644 index 000000000..51414d8f9 --- /dev/null +++ b/drivers/avr/hd44780.c | |||
| @@ -0,0 +1,592 @@ | |||
| 1 | /**************************************************************************** | ||
| 2 | Title: HD44780U LCD library | ||
| 3 | Author: Peter Fleury <pfleury@gmx.ch> http://tinyurl.com/peterfleury | ||
| 4 | License: GNU General Public License Version 3 | ||
| 5 | File: $Id: lcd.c,v 1.15.2.2 2015/01/17 12:16:05 peter Exp $ | ||
| 6 | Software: AVR-GCC 3.3 | ||
| 7 | Target: any AVR device, memory mapped mode only for AT90S4414/8515/Mega | ||
| 8 | |||
| 9 | DESCRIPTION | ||
| 10 | Basic routines for interfacing a HD44780U-based text lcd display | ||
| 11 | |||
| 12 | Originally based on Volker Oth's lcd library, | ||
| 13 | changed lcd_init(), added additional constants for lcd_command(), | ||
| 14 | added 4-bit I/O mode, improved and optimized code. | ||
| 15 | |||
| 16 | Library can be operated in memory mapped mode (LCD_IO_MODE=0) or in | ||
| 17 | 4-bit IO port mode (LCD_IO_MODE=1). 8-bit IO port mode not supported. | ||
| 18 | |||
| 19 | Memory mapped mode compatible with Kanda STK200, but supports also | ||
| 20 | generation of R/W signal through A8 address line. | ||
| 21 | |||
| 22 | USAGE | ||
| 23 | See the C include lcd.h file for a description of each function | ||
| 24 | |||
| 25 | *****************************************************************************/ | ||
| 26 | #include <inttypes.h> | ||
| 27 | #include <avr/io.h> | ||
| 28 | #include <avr/pgmspace.h> | ||
| 29 | #include <util/delay.h> | ||
| 30 | #include "hd44780.h" | ||
| 31 | |||
| 32 | /* | ||
| 33 | ** constants/macros | ||
| 34 | */ | ||
| 35 | #define DDR(x) (*(&x - 1)) /* address of data direction register of port x */ | ||
| 36 | #if defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) | ||
| 37 | /* on ATmega64/128 PINF is on port 0x00 and not 0x60 */ | ||
| 38 | #define PIN(x) ( &PORTF==&(x) ? _SFR_IO8(0x00) : (*(&x - 2)) ) | ||
| 39 | #else | ||
| 40 | #define PIN(x) (*(&x - 2)) /* address of input register of port x */ | ||
| 41 | #endif | ||
| 42 | |||
| 43 | |||
| 44 | #if LCD_IO_MODE | ||
| 45 | #define lcd_e_delay() _delay_us(LCD_DELAY_ENABLE_PULSE) | ||
| 46 | #define lcd_e_high() LCD_E_PORT |= _BV(LCD_E_PIN); | ||
| 47 | #define lcd_e_low() LCD_E_PORT &= ~_BV(LCD_E_PIN); | ||
| 48 | #define lcd_e_toggle() toggle_e() | ||
| 49 | #define lcd_rw_high() LCD_RW_PORT |= _BV(LCD_RW_PIN) | ||
| 50 | #define lcd_rw_low() LCD_RW_PORT &= ~_BV(LCD_RW_PIN) | ||
| 51 | #define lcd_rs_high() LCD_RS_PORT |= _BV(LCD_RS_PIN) | ||
| 52 | #define lcd_rs_low() LCD_RS_PORT &= ~_BV(LCD_RS_PIN) | ||
| 53 | #endif | ||
| 54 | |||
| 55 | #if LCD_IO_MODE | ||
| 56 | #if LCD_LINES==1 | ||
| 57 | #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_1LINE | ||
| 58 | #else | ||
| 59 | #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_2LINES | ||
| 60 | #endif | ||
| 61 | #else | ||
| 62 | #if LCD_LINES==1 | ||
| 63 | #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_1LINE | ||
| 64 | #else | ||
| 65 | #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_2LINES | ||
| 66 | #endif | ||
| 67 | #endif | ||
| 68 | |||
| 69 | #if LCD_CONTROLLER_KS0073 | ||
| 70 | #if LCD_LINES==4 | ||
| 71 | |||
| 72 | #define KS0073_EXTENDED_FUNCTION_REGISTER_ON 0x2C /* |0|010|1100 4-bit mode, extension-bit RE = 1 */ | ||
| 73 | #define KS0073_EXTENDED_FUNCTION_REGISTER_OFF 0x28 /* |0|010|1000 4-bit mode, extension-bit RE = 0 */ | ||
| 74 | #define KS0073_4LINES_MODE 0x09 /* |0|000|1001 4 lines mode */ | ||
| 75 | |||
| 76 | #endif | ||
| 77 | #endif | ||
| 78 | |||
| 79 | /* | ||
| 80 | ** function prototypes | ||
| 81 | */ | ||
| 82 | #if LCD_IO_MODE | ||
| 83 | static void toggle_e(void); | ||
| 84 | #endif | ||
| 85 | |||
| 86 | /* | ||
| 87 | ** local functions | ||
| 88 | */ | ||
| 89 | |||
| 90 | |||
| 91 | /************************************************************************* | ||
| 92 | delay for a minimum of <us> microseconds | ||
| 93 | the number of loops is calculated at compile-time from MCU clock frequency | ||
| 94 | *************************************************************************/ | ||
| 95 | #define delay(us) _delay_us(us) | ||
| 96 | |||
| 97 | |||
| 98 | #if LCD_IO_MODE | ||
| 99 | /* toggle Enable Pin to initiate write */ | ||
| 100 | static void toggle_e(void) | ||
| 101 | { | ||
| 102 | lcd_e_high(); | ||
| 103 | lcd_e_delay(); | ||
| 104 | lcd_e_low(); | ||
| 105 | } | ||
| 106 | #endif | ||
| 107 | |||
| 108 | |||
| 109 | /************************************************************************* | ||
| 110 | Low-level function to write byte to LCD controller | ||
| 111 | Input: data byte to write to LCD | ||
| 112 | rs 1: write data | ||
| 113 | 0: write instruction | ||
| 114 | Returns: none | ||
| 115 | *************************************************************************/ | ||
| 116 | #if LCD_IO_MODE | ||
| 117 | static void lcd_write(uint8_t data,uint8_t rs) | ||
| 118 | { | ||
| 119 | unsigned char dataBits ; | ||
| 120 | |||
| 121 | |||
| 122 | if (rs) { /* write data (RS=1, RW=0) */ | ||
| 123 | lcd_rs_high(); | ||
| 124 | } else { /* write instruction (RS=0, RW=0) */ | ||
| 125 | lcd_rs_low(); | ||
| 126 | } | ||
| 127 | lcd_rw_low(); /* RW=0 write mode */ | ||
| 128 | |||
| 129 | if ( ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT ) | ||
| 130 | && (LCD_DATA0_PIN == 0) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) ) | ||
| 131 | { | ||
| 132 | /* configure data pins as output */ | ||
| 133 | DDR(LCD_DATA0_PORT) |= 0x0F; | ||
| 134 | |||
| 135 | /* output high nibble first */ | ||
| 136 | dataBits = LCD_DATA0_PORT & 0xF0; | ||
| 137 | LCD_DATA0_PORT = dataBits |((data>>4)&0x0F); | ||
| 138 | lcd_e_toggle(); | ||
| 139 | |||
| 140 | /* output low nibble */ | ||
| 141 | LCD_DATA0_PORT = dataBits | (data&0x0F); | ||
| 142 | lcd_e_toggle(); | ||
| 143 | |||
| 144 | /* all data pins high (inactive) */ | ||
| 145 | LCD_DATA0_PORT = dataBits | 0x0F; | ||
| 146 | } | ||
| 147 | else | ||
| 148 | { | ||
| 149 | /* configure data pins as output */ | ||
| 150 | DDR(LCD_DATA0_PORT) |= _BV(LCD_DATA0_PIN); | ||
| 151 | DDR(LCD_DATA1_PORT) |= _BV(LCD_DATA1_PIN); | ||
| 152 | DDR(LCD_DATA2_PORT) |= _BV(LCD_DATA2_PIN); | ||
| 153 | DDR(LCD_DATA3_PORT) |= _BV(LCD_DATA3_PIN); | ||
| 154 | |||
| 155 | /* output high nibble first */ | ||
| 156 | LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN); | ||
| 157 | LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN); | ||
| 158 | LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN); | ||
| 159 | LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN); | ||
| 160 | if(data & 0x80) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN); | ||
| 161 | if(data & 0x40) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN); | ||
| 162 | if(data & 0x20) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN); | ||
| 163 | if(data & 0x10) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN); | ||
| 164 | lcd_e_toggle(); | ||
| 165 | |||
| 166 | /* output low nibble */ | ||
| 167 | LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN); | ||
| 168 | LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN); | ||
| 169 | LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN); | ||
| 170 | LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN); | ||
| 171 | if(data & 0x08) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN); | ||
| 172 | if(data & 0x04) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN); | ||
| 173 | if(data & 0x02) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN); | ||
| 174 | if(data & 0x01) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN); | ||
| 175 | lcd_e_toggle(); | ||
| 176 | |||
| 177 | /* all data pins high (inactive) */ | ||
| 178 | LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN); | ||
| 179 | LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN); | ||
| 180 | LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN); | ||
| 181 | LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN); | ||
| 182 | } | ||
| 183 | } | ||
| 184 | #else | ||
| 185 | #define lcd_write(d,rs) if (rs) *(volatile uint8_t*)(LCD_IO_DATA) = d; else *(volatile uint8_t*)(LCD_IO_FUNCTION) = d; | ||
| 186 | /* rs==0 -> write instruction to LCD_IO_FUNCTION */ | ||
| 187 | /* rs==1 -> write data to LCD_IO_DATA */ | ||
| 188 | #endif | ||
| 189 | |||
| 190 | |||
| 191 | /************************************************************************* | ||
| 192 | Low-level function to read byte from LCD controller | ||
| 193 | Input: rs 1: read data | ||
| 194 | 0: read busy flag / address counter | ||
| 195 | Returns: byte read from LCD controller | ||
| 196 | *************************************************************************/ | ||
| 197 | #if LCD_IO_MODE | ||
| 198 | static uint8_t lcd_read(uint8_t rs) | ||
| 199 | { | ||
| 200 | uint8_t data; | ||
| 201 | |||
| 202 | |||
| 203 | if (rs) | ||
| 204 | lcd_rs_high(); /* RS=1: read data */ | ||
| 205 | else | ||
| 206 | lcd_rs_low(); /* RS=0: read busy flag */ | ||
| 207 | lcd_rw_high(); /* RW=1 read mode */ | ||
| 208 | |||
| 209 | if ( ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT ) | ||
| 210 | && ( LCD_DATA0_PIN == 0 )&& (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) ) | ||
| 211 | { | ||
| 212 | DDR(LCD_DATA0_PORT) &= 0xF0; /* configure data pins as input */ | ||
| 213 | |||
| 214 | lcd_e_high(); | ||
| 215 | lcd_e_delay(); | ||
| 216 | data = PIN(LCD_DATA0_PORT) << 4; /* read high nibble first */ | ||
| 217 | lcd_e_low(); | ||
| 218 | |||
| 219 | lcd_e_delay(); /* Enable 500ns low */ | ||
| 220 | |||
| 221 | lcd_e_high(); | ||
| 222 | lcd_e_delay(); | ||
| 223 | data |= PIN(LCD_DATA0_PORT)&0x0F; /* read low nibble */ | ||
| 224 | lcd_e_low(); | ||
| 225 | } | ||
| 226 | else | ||
| 227 | { | ||
| 228 | /* configure data pins as input */ | ||
| 229 | DDR(LCD_DATA0_PORT) &= ~_BV(LCD_DATA0_PIN); | ||
| 230 | DDR(LCD_DATA1_PORT) &= ~_BV(LCD_DATA1_PIN); | ||
| 231 | DDR(LCD_DATA2_PORT) &= ~_BV(LCD_DATA2_PIN); | ||
| 232 | DDR(LCD_DATA3_PORT) &= ~_BV(LCD_DATA3_PIN); | ||
| 233 | |||
| 234 | /* read high nibble first */ | ||
| 235 | lcd_e_high(); | ||
| 236 | lcd_e_delay(); | ||
| 237 | data = 0; | ||
| 238 | if ( PIN(LCD_DATA0_PORT) & _BV(LCD_DATA0_PIN) ) data |= 0x10; | ||
| 239 | if ( PIN(LCD_DATA1_PORT) & _BV(LCD_DATA1_PIN) ) data |= 0x20; | ||
| 240 | if ( PIN(LCD_DATA2_PORT) & _BV(LCD_DATA2_PIN) ) data |= 0x40; | ||
| 241 | if ( PIN(LCD_DATA3_PORT) & _BV(LCD_DATA3_PIN) ) data |= 0x80; | ||
| 242 | lcd_e_low(); | ||
| 243 | |||
| 244 | lcd_e_delay(); /* Enable 500ns low */ | ||
| 245 | |||
| 246 | /* read low nibble */ | ||
| 247 | lcd_e_high(); | ||
| 248 | lcd_e_delay(); | ||
| 249 | if ( PIN(LCD_DATA0_PORT) & _BV(LCD_DATA0_PIN) ) data |= 0x01; | ||
| 250 | if ( PIN(LCD_DATA1_PORT) & _BV(LCD_DATA1_PIN) ) data |= 0x02; | ||
| 251 | if ( PIN(LCD_DATA2_PORT) & _BV(LCD_DATA2_PIN) ) data |= 0x04; | ||
| 252 | if ( PIN(LCD_DATA3_PORT) & _BV(LCD_DATA3_PIN) ) data |= 0x08; | ||
| 253 | lcd_e_low(); | ||
| 254 | } | ||
| 255 | return data; | ||
| 256 | } | ||
| 257 | #else | ||
| 258 | #define lcd_read(rs) (rs) ? *(volatile uint8_t*)(LCD_IO_DATA+LCD_IO_READ) : *(volatile uint8_t*)(LCD_IO_FUNCTION+LCD_IO_READ) | ||
| 259 | /* rs==0 -> read instruction from LCD_IO_FUNCTION */ | ||
| 260 | /* rs==1 -> read data from LCD_IO_DATA */ | ||
| 261 | #endif | ||
| 262 | |||
| 263 | |||
| 264 | /************************************************************************* | ||
| 265 | loops while lcd is busy, returns address counter | ||
| 266 | *************************************************************************/ | ||
| 267 | static uint8_t lcd_waitbusy(void) | ||
| 268 | |||
| 269 | { | ||
| 270 | register uint8_t c; | ||
| 271 | |||
| 272 | /* wait until busy flag is cleared */ | ||
| 273 | while ( (c=lcd_read(0)) & (1<<LCD_BUSY)) {} | ||
| 274 | |||
| 275 | /* the address counter is updated 4us after the busy flag is cleared */ | ||
| 276 | delay(LCD_DELAY_BUSY_FLAG); | ||
| 277 | |||
| 278 | /* now read the address counter */ | ||
| 279 | return (lcd_read(0)); // return address counter | ||
| 280 | |||
| 281 | }/* lcd_waitbusy */ | ||
| 282 | |||
| 283 | |||
| 284 | /************************************************************************* | ||
| 285 | Move cursor to the start of next line or to the first line if the cursor | ||
| 286 | is already on the last line. | ||
| 287 | *************************************************************************/ | ||
| 288 | static inline void lcd_newline(uint8_t pos) | ||
| 289 | { | ||
| 290 | register uint8_t addressCounter; | ||
| 291 | |||
| 292 | |||
| 293 | #if LCD_LINES==1 | ||
| 294 | addressCounter = 0; | ||
| 295 | #endif | ||
| 296 | #if LCD_LINES==2 | ||
| 297 | if ( pos < (LCD_START_LINE2) ) | ||
| 298 | addressCounter = LCD_START_LINE2; | ||
| 299 | else | ||
| 300 | addressCounter = LCD_START_LINE1; | ||
| 301 | #endif | ||
| 302 | #if LCD_LINES==4 | ||
| 303 | #if KS0073_4LINES_MODE | ||
| 304 | if ( pos < LCD_START_LINE2 ) | ||
| 305 | addressCounter = LCD_START_LINE2; | ||
| 306 | else if ( (pos >= LCD_START_LINE2) && (pos < LCD_START_LINE3) ) | ||
| 307 | addressCounter = LCD_START_LINE3; | ||
| 308 | else if ( (pos >= LCD_START_LINE3) && (pos < LCD_START_LINE4) ) | ||
| 309 | addressCounter = LCD_START_LINE4; | ||
| 310 | else | ||
| 311 | addressCounter = LCD_START_LINE1; | ||
| 312 | #else | ||
| 313 | if ( pos < LCD_START_LINE3 ) | ||
| 314 | addressCounter = LCD_START_LINE2; | ||
| 315 | else if ( (pos >= LCD_START_LINE2) && (pos < LCD_START_LINE4) ) | ||
| 316 | addressCounter = LCD_START_LINE3; | ||
| 317 | else if ( (pos >= LCD_START_LINE3) && (pos < LCD_START_LINE2) ) | ||
| 318 | addressCounter = LCD_START_LINE4; | ||
| 319 | else | ||
| 320 | addressCounter = LCD_START_LINE1; | ||
| 321 | #endif | ||
| 322 | #endif | ||
| 323 | lcd_command((1<<LCD_DDRAM)+addressCounter); | ||
| 324 | |||
| 325 | }/* lcd_newline */ | ||
| 326 | |||
| 327 | |||
| 328 | /* | ||
| 329 | ** PUBLIC FUNCTIONS | ||
| 330 | */ | ||
| 331 | |||
| 332 | /************************************************************************* | ||
| 333 | Send LCD controller instruction command | ||
| 334 | Input: instruction to send to LCD controller, see HD44780 data sheet | ||
| 335 | Returns: none | ||
| 336 | *************************************************************************/ | ||
| 337 | void lcd_command(uint8_t cmd) | ||
| 338 | { | ||
| 339 | lcd_waitbusy(); | ||
| 340 | lcd_write(cmd,0); | ||
| 341 | } | ||
| 342 | |||
| 343 | |||
| 344 | /************************************************************************* | ||
| 345 | Send data byte to LCD controller | ||
| 346 | Input: data to send to LCD controller, see HD44780 data sheet | ||
| 347 | Returns: none | ||
| 348 | *************************************************************************/ | ||
| 349 | void lcd_data(uint8_t data) | ||
| 350 | { | ||
| 351 | lcd_waitbusy(); | ||
| 352 | lcd_write(data,1); | ||
| 353 | } | ||
| 354 | |||
| 355 | |||
| 356 | |||
| 357 | /************************************************************************* | ||
| 358 | Set cursor to specified position | ||
| 359 | Input: x horizontal position (0: left most position) | ||
| 360 | y vertical position (0: first line) | ||
| 361 | Returns: none | ||
| 362 | *************************************************************************/ | ||
| 363 | void lcd_gotoxy(uint8_t x, uint8_t y) | ||
| 364 | { | ||
| 365 | #if LCD_LINES==1 | ||
| 366 | lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+x); | ||
| 367 | #endif | ||
| 368 | #if LCD_LINES==2 | ||
| 369 | if ( y==0 ) | ||
| 370 | lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+x); | ||
| 371 | else | ||
| 372 | lcd_command((1<<LCD_DDRAM)+LCD_START_LINE2+x); | ||
| 373 | #endif | ||
| 374 | #if LCD_LINES==4 | ||
| 375 | if ( y==0 ) | ||
| 376 | lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+x); | ||
| 377 | else if ( y==1) | ||
| 378 | lcd_command((1<<LCD_DDRAM)+LCD_START_LINE2+x); | ||
| 379 | else if ( y==2) | ||
| 380 | lcd_command((1<<LCD_DDRAM)+LCD_START_LINE3+x); | ||
| 381 | else /* y==3 */ | ||
| 382 | lcd_command((1<<LCD_DDRAM)+LCD_START_LINE4+x); | ||
| 383 | #endif | ||
| 384 | |||
| 385 | }/* lcd_gotoxy */ | ||
| 386 | |||
| 387 | |||
| 388 | /************************************************************************* | ||
| 389 | *************************************************************************/ | ||
| 390 | int lcd_getxy(void) | ||
| 391 | { | ||
| 392 | return lcd_waitbusy(); | ||
| 393 | } | ||
| 394 | |||
| 395 | |||
| 396 | /************************************************************************* | ||
| 397 | Clear display and set cursor to home position | ||
| 398 | *************************************************************************/ | ||
| 399 | void lcd_clrscr(void) | ||
| 400 | { | ||
| 401 | lcd_command(1<<LCD_CLR); | ||
| 402 | } | ||
| 403 | |||
| 404 | |||
| 405 | /************************************************************************* | ||
| 406 | Set cursor to home position | ||
| 407 | *************************************************************************/ | ||
| 408 | void lcd_home(void) | ||
| 409 | { | ||
| 410 | lcd_command(1<<LCD_HOME); | ||
| 411 | } | ||
| 412 | |||
| 413 | |||
| 414 | /************************************************************************* | ||
| 415 | Display character at current cursor position | ||
| 416 | Input: character to be displayed | ||
| 417 | Returns: none | ||
| 418 | *************************************************************************/ | ||
| 419 | void lcd_putc(char c) | ||
| 420 | { | ||
| 421 | uint8_t pos; | ||
| 422 | |||
| 423 | |||
| 424 | pos = lcd_waitbusy(); // read busy-flag and address counter | ||
| 425 | if (c=='\n') | ||
| 426 | { | ||
| 427 | lcd_newline(pos); | ||
| 428 | } | ||
| 429 | else | ||
| 430 | { | ||
| 431 | #if LCD_WRAP_LINES==1 | ||
| 432 | #if LCD_LINES==1 | ||
| 433 | if ( pos == LCD_START_LINE1+LCD_DISP_LENGTH ) { | ||
| 434 | lcd_write((1<<LCD_DDRAM)+LCD_START_LINE1,0); | ||
| 435 | } | ||
| 436 | #elif LCD_LINES==2 | ||
| 437 | if ( pos == LCD_START_LINE1+LCD_DISP_LENGTH ) { | ||
| 438 | lcd_write((1<<LCD_DDRAM)+LCD_START_LINE2,0); | ||
| 439 | }else if ( pos == LCD_START_LINE2+LCD_DISP_LENGTH ){ | ||
| 440 | lcd_write((1<<LCD_DDRAM)+LCD_START_LINE1,0); | ||
| 441 | } | ||
| 442 | #elif LCD_LINES==4 | ||
| 443 | if ( pos == LCD_START_LINE1+LCD_DISP_LENGTH ) { | ||
| 444 | lcd_write((1<<LCD_DDRAM)+LCD_START_LINE2,0); | ||
| 445 | }else if ( pos == LCD_START_LINE2+LCD_DISP_LENGTH ) { | ||
| 446 | lcd_write((1<<LCD_DDRAM)+LCD_START_LINE3,0); | ||
| 447 | }else if ( pos == LCD_START_LINE3+LCD_DISP_LENGTH ) { | ||
| 448 | lcd_write((1<<LCD_DDRAM)+LCD_START_LINE4,0); | ||
| 449 | }else if ( pos == LCD_START_LINE4+LCD_DISP_LENGTH ) { | ||
| 450 | lcd_write((1<<LCD_DDRAM)+LCD_START_LINE1,0); | ||
| 451 | } | ||
| 452 | #endif | ||
| 453 | lcd_waitbusy(); | ||
| 454 | #endif | ||
| 455 | lcd_write(c, 1); | ||
| 456 | } | ||
| 457 | |||
| 458 | }/* lcd_putc */ | ||
| 459 | |||
| 460 | |||
| 461 | /************************************************************************* | ||
| 462 | Display string without auto linefeed | ||
| 463 | Input: string to be displayed | ||
| 464 | Returns: none | ||
| 465 | *************************************************************************/ | ||
| 466 | void lcd_puts(const char *s) | ||
| 467 | /* print string on lcd (no auto linefeed) */ | ||
| 468 | { | ||
| 469 | register char c; | ||
| 470 | |||
| 471 | while ( (c = *s++) ) { | ||
| 472 | lcd_putc(c); | ||
| 473 | } | ||
| 474 | |||
| 475 | }/* lcd_puts */ | ||
| 476 | |||
| 477 | |||
| 478 | /************************************************************************* | ||
| 479 | Display string from program memory without auto linefeed | ||
| 480 | Input: string from program memory be be displayed | ||
| 481 | Returns: none | ||
| 482 | *************************************************************************/ | ||
| 483 | void lcd_puts_p(const char *progmem_s) | ||
| 484 | /* print string from program memory on lcd (no auto linefeed) */ | ||
| 485 | { | ||
| 486 | register char c; | ||
| 487 | |||
| 488 | while ( (c = pgm_read_byte(progmem_s++)) ) { | ||
| 489 | lcd_putc(c); | ||
| 490 | } | ||
| 491 | |||
| 492 | }/* lcd_puts_p */ | ||
| 493 | |||
| 494 | |||
| 495 | /************************************************************************* | ||
| 496 | Initialize display and select type of cursor | ||
| 497 | Input: dispAttr LCD_DISP_OFF display off | ||
| 498 | LCD_DISP_ON display on, cursor off | ||
| 499 | LCD_DISP_ON_CURSOR display on, cursor on | ||
| 500 | LCD_DISP_CURSOR_BLINK display on, cursor on flashing | ||
| 501 | Returns: none | ||
| 502 | *************************************************************************/ | ||
| 503 | void lcd_init(uint8_t dispAttr) | ||
| 504 | { | ||
| 505 | #if LCD_IO_MODE | ||
| 506 | /* | ||
| 507 | * Initialize LCD to 4 bit I/O mode | ||
| 508 | */ | ||
| 509 | |||
| 510 | if ( ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT ) | ||
| 511 | && ( &LCD_RS_PORT == &LCD_DATA0_PORT) && ( &LCD_RW_PORT == &LCD_DATA0_PORT) && (&LCD_E_PORT == &LCD_DATA0_PORT) | ||
| 512 | && (LCD_DATA0_PIN == 0 ) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) | ||
| 513 | && (LCD_RS_PIN == 4 ) && (LCD_RW_PIN == 5) && (LCD_E_PIN == 6 ) ) | ||
| 514 | { | ||
| 515 | /* configure all port bits as output (all LCD lines on same port) */ | ||
| 516 | DDR(LCD_DATA0_PORT) |= 0x7F; | ||
| 517 | } | ||
| 518 | else if ( ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT ) | ||
| 519 | && (LCD_DATA0_PIN == 0 ) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) ) | ||
| 520 | { | ||
| 521 | /* configure all port bits as output (all LCD data lines on same port, but control lines on different ports) */ | ||
| 522 | DDR(LCD_DATA0_PORT) |= 0x0F; | ||
| 523 | DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN); | ||
| 524 | DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN); | ||
| 525 | DDR(LCD_E_PORT) |= _BV(LCD_E_PIN); | ||
| 526 | } | ||
| 527 | else | ||
| 528 | { | ||
| 529 | /* configure all port bits as output (LCD data and control lines on different ports */ | ||
| 530 | DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN); | ||
| 531 | DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN); | ||
| 532 | DDR(LCD_E_PORT) |= _BV(LCD_E_PIN); | ||
| 533 | DDR(LCD_DATA0_PORT) |= _BV(LCD_DATA0_PIN); | ||
| 534 | DDR(LCD_DATA1_PORT) |= _BV(LCD_DATA1_PIN); | ||
| 535 | DDR(LCD_DATA2_PORT) |= _BV(LCD_DATA2_PIN); | ||
| 536 | DDR(LCD_DATA3_PORT) |= _BV(LCD_DATA3_PIN); | ||
| 537 | } | ||
| 538 | delay(LCD_DELAY_BOOTUP); /* wait 16ms or more after power-on */ | ||
| 539 | |||
| 540 | /* initial write to lcd is 8bit */ | ||
| 541 | LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN); // LCD_FUNCTION>>4; | ||
| 542 | LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN); // LCD_FUNCTION_8BIT>>4; | ||
| 543 | lcd_e_toggle(); | ||
| 544 | delay(LCD_DELAY_INIT); /* delay, busy flag can't be checked here */ | ||
| 545 | |||
| 546 | /* repeat last command */ | ||
| 547 | lcd_e_toggle(); | ||
| 548 | delay(LCD_DELAY_INIT_REP); /* delay, busy flag can't be checked here */ | ||
| 549 | |||
| 550 | /* repeat last command a third time */ | ||
| 551 | lcd_e_toggle(); | ||
| 552 | delay(LCD_DELAY_INIT_REP); /* delay, busy flag can't be checked here */ | ||
| 553 | |||
| 554 | /* now configure for 4bit mode */ | ||
| 555 | LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN); // LCD_FUNCTION_4BIT_1LINE>>4 | ||
| 556 | lcd_e_toggle(); | ||
| 557 | delay(LCD_DELAY_INIT_4BIT); /* some displays need this additional delay */ | ||
| 558 | |||
| 559 | /* from now the LCD only accepts 4 bit I/O, we can use lcd_command() */ | ||
| 560 | #else | ||
| 561 | /* | ||
| 562 | * Initialize LCD to 8 bit memory mapped mode | ||
| 563 | */ | ||
| 564 | |||
| 565 | /* enable external SRAM (memory mapped lcd) and one wait state */ | ||
| 566 | MCUCR = _BV(SRE) | _BV(SRW); | ||
| 567 | |||
| 568 | /* reset LCD */ | ||
| 569 | delay(LCD_DELAY_BOOTUP); /* wait 16ms after power-on */ | ||
| 570 | lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */ | ||
| 571 | delay(LCD_DELAY_INIT); /* wait 5ms */ | ||
| 572 | lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */ | ||
| 573 | delay(LCD_DELAY_INIT_REP); /* wait 64us */ | ||
| 574 | lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */ | ||
| 575 | delay(LCD_DELAY_INIT_REP); /* wait 64us */ | ||
| 576 | #endif | ||
| 577 | |||
| 578 | #if KS0073_4LINES_MODE | ||
| 579 | /* Display with KS0073 controller requires special commands for enabling 4 line mode */ | ||
| 580 | lcd_command(KS0073_EXTENDED_FUNCTION_REGISTER_ON); | ||
| 581 | lcd_command(KS0073_4LINES_MODE); | ||
| 582 | lcd_command(KS0073_EXTENDED_FUNCTION_REGISTER_OFF); | ||
| 583 | #else | ||
| 584 | lcd_command(LCD_FUNCTION_DEFAULT); /* function set: display lines */ | ||
| 585 | #endif | ||
| 586 | lcd_command(LCD_DISP_OFF); /* display off */ | ||
| 587 | lcd_clrscr(); /* display clear */ | ||
| 588 | lcd_command(LCD_MODE_DEFAULT); /* set entry mode */ | ||
| 589 | lcd_command(dispAttr); /* display/cursor control */ | ||
| 590 | |||
| 591 | }/* lcd_init */ | ||
| 592 | |||
diff --git a/drivers/avr/hd44780.h b/drivers/avr/hd44780.h new file mode 100644 index 000000000..7421c8131 --- /dev/null +++ b/drivers/avr/hd44780.h | |||
| @@ -0,0 +1,371 @@ | |||
| 1 | #ifndef LCD_H | ||
| 2 | #define LCD_H | ||
| 3 | /************************************************************************* | ||
| 4 | Title : C include file for the HD44780U LCD library (lcd.c) | ||
| 5 | Author: Peter Fleury <pfleury@gmx.ch> http://tinyurl.com/peterfleury | ||
| 6 | License: GNU General Public License Version 3 | ||
| 7 | File: $Id: lcd.h,v 1.14.2.4 2015/01/20 17:16:07 peter Exp $ | ||
| 8 | Software: AVR-GCC 4.x | ||
| 9 | Hardware: any AVR device, memory mapped mode only for AVR with | ||
| 10 | memory mapped interface (AT90S8515/ATmega8515/ATmega128) | ||
| 11 | ***************************************************************************/ | ||
| 12 | |||
| 13 | /** | ||
| 14 | @mainpage | ||
| 15 | Collection of libraries for AVR-GCC | ||
| 16 | @author Peter Fleury pfleury@gmx.ch http://tinyurl.com/peterfleury | ||
| 17 | @copyright (C) 2015 Peter Fleury, GNU General Public License Version 3 | ||
| 18 | |||
| 19 | @file | ||
| 20 | @defgroup pfleury_lcd LCD library <lcd.h> | ||
| 21 | @code #include <lcd.h> @endcode | ||
| 22 | |||
| 23 | @brief Basic routines for interfacing a HD44780U-based character LCD display | ||
| 24 | |||
| 25 | LCD character displays can be found in many devices, like espresso machines, laser printers. | ||
| 26 | The Hitachi HD44780 controller and its compatible controllers like Samsung KS0066U have become an industry standard for these types of displays. | ||
| 27 | |||
| 28 | This library allows easy interfacing with a HD44780 compatible display and can be | ||
| 29 | operated in memory mapped mode (LCD_IO_MODE defined as 0 in the include file lcd.h.) or in | ||
| 30 | 4-bit IO port mode (LCD_IO_MODE defined as 1). 8-bit IO port mode is not supported. | ||
| 31 | |||
| 32 | Memory mapped mode is compatible with old Kanda STK200 starter kit, but also supports | ||
| 33 | generation of R/W signal through A8 address line. | ||
| 34 | |||
| 35 | @see The chapter <a href=" http://homepage.hispeed.ch/peterfleury/avr-lcd44780.html" target="_blank">Interfacing a HD44780 Based LCD to an AVR</a> | ||
| 36 | on my home page, which shows example circuits how to connect an LCD to an AVR controller. | ||
| 37 | |||
| 38 | @author Peter Fleury pfleury@gmx.ch http://tinyurl.com/peterfleury | ||
| 39 | |||
| 40 | @version 2.0 | ||
| 41 | |||
| 42 | @copyright (C) 2015 Peter Fleury, GNU General Public License Version 3 | ||
| 43 | |||
| 44 | */ | ||
| 45 | |||
| 46 | #include <inttypes.h> | ||
| 47 | #include <avr/pgmspace.h> | ||
| 48 | |||
| 49 | #if (__GNUC__ * 100 + __GNUC_MINOR__) < 405 | ||
| 50 | #error "This library requires AVR-GCC 4.5 or later, update to newer AVR-GCC compiler !" | ||
| 51 | #endif | ||
| 52 | |||
| 53 | |||
| 54 | /**@{*/ | ||
| 55 | |||
| 56 | /* | ||
| 57 | * LCD and target specific definitions below can be defined in a separate include file with name lcd_definitions.h instead modifying this file | ||
| 58 | * by adding -D_LCD_DEFINITIONS_FILE to the CDEFS section in the Makefile | ||
| 59 | * All definitions added to the file lcd_definitions.h will override the default definitions from lcd.h | ||
| 60 | */ | ||
| 61 | #ifdef _LCD_DEFINITIONS_FILE | ||
| 62 | #include "lcd_definitions.h" | ||
| 63 | #endif | ||
| 64 | |||
| 65 | |||
| 66 | /** | ||
| 67 | * @name Definition for LCD controller type | ||
| 68 | * Use 0 for HD44780 controller, change to 1 for displays with KS0073 controller. | ||
| 69 | */ | ||
| 70 | #ifndef LCD_CONTROLLER_KS0073 | ||
| 71 | #define LCD_CONTROLLER_KS0073 0 /**< Use 0 for HD44780 controller, 1 for KS0073 controller */ | ||
| 72 | #endif | ||
| 73 | |||
| 74 | /** | ||
| 75 | * @name Definitions for Display Size | ||
| 76 | * Change these definitions to adapt setting to your display | ||
| 77 | * | ||
| 78 | * These definitions can be defined in a separate include file \b lcd_definitions.h instead modifying this file by | ||
| 79 | * adding -D_LCD_DEFINITIONS_FILE to the CDEFS section in the Makefile. | ||
| 80 | * All definitions added to the file lcd_definitions.h will override the default definitions from lcd.h | ||
| 81 | * | ||
| 82 | */ | ||
| 83 | #ifndef LCD_LINES | ||
| 84 | #define LCD_LINES 2 /**< number of visible lines of the display */ | ||
| 85 | #endif | ||
| 86 | #ifndef LCD_DISP_LENGTH | ||
| 87 | #define LCD_DISP_LENGTH 16 /**< visibles characters per line of the display */ | ||
| 88 | #endif | ||
| 89 | #ifndef LCD_LINE_LENGTH | ||
| 90 | #define LCD_LINE_LENGTH 0x40 /**< internal line length of the display */ | ||
| 91 | #endif | ||
| 92 | #ifndef LCD_START_LINE1 | ||
| 93 | #define LCD_START_LINE1 0x00 /**< DDRAM address of first char of line 1 */ | ||
| 94 | #endif | ||
| 95 | #ifndef LCD_START_LINE2 | ||
| 96 | #define LCD_START_LINE2 0x40 /**< DDRAM address of first char of line 2 */ | ||
| 97 | #endif | ||
| 98 | #ifndef LCD_START_LINE3 | ||
| 99 | #define LCD_START_LINE3 0x14 /**< DDRAM address of first char of line 3 */ | ||
| 100 | #endif | ||
| 101 | #ifndef LCD_START_LINE4 | ||
| 102 | #define LCD_START_LINE4 0x54 /**< DDRAM address of first char of line 4 */ | ||
| 103 | #endif | ||
| 104 | #ifndef LCD_WRAP_LINES | ||
| 105 | #define LCD_WRAP_LINES 0 /**< 0: no wrap, 1: wrap at end of visibile line */ | ||
| 106 | #endif | ||
| 107 | |||
| 108 | |||
| 109 | /** | ||
| 110 | * @name Definitions for 4-bit IO mode | ||
| 111 | * | ||
| 112 | * The four LCD data lines and the three control lines RS, RW, E can be on the | ||
| 113 | * same port or on different ports. | ||
| 114 | * Change LCD_RS_PORT, LCD_RW_PORT, LCD_E_PORT if you want the control lines on | ||
| 115 | * different ports. | ||
| 116 | * | ||
| 117 | * Normally the four data lines should be mapped to bit 0..3 on one port, but it | ||
| 118 | * is possible to connect these data lines in different order or even on different | ||
| 119 | * ports by adapting the LCD_DATAx_PORT and LCD_DATAx_PIN definitions. | ||
| 120 | * | ||
| 121 | * Adjust these definitions to your target.\n | ||
| 122 | * These definitions can be defined in a separate include file \b lcd_definitions.h instead modifying this file by | ||
| 123 | * adding \b -D_LCD_DEFINITIONS_FILE to the \b CDEFS section in the Makefile. | ||
| 124 | * All definitions added to the file lcd_definitions.h will override the default definitions from lcd.h | ||
| 125 | * | ||
| 126 | */ | ||
| 127 | #define LCD_IO_MODE 1 /**< 0: memory mapped mode, 1: IO port mode */ | ||
| 128 | |||
| 129 | #if LCD_IO_MODE | ||
| 130 | |||
| 131 | #ifndef LCD_PORT | ||
| 132 | #define LCD_PORT PORTA /**< port for the LCD lines */ | ||
| 133 | #endif | ||
| 134 | #ifndef LCD_DATA0_PORT | ||
| 135 | #define LCD_DATA0_PORT LCD_PORT /**< port for 4bit data bit 0 */ | ||
| 136 | #endif | ||
| 137 | #ifndef LCD_DATA1_PORT | ||
| 138 | #define LCD_DATA1_PORT LCD_PORT /**< port for 4bit data bit 1 */ | ||
| 139 | #endif | ||
| 140 | #ifndef LCD_DATA2_PORT | ||
| 141 | #define LCD_DATA2_PORT LCD_PORT /**< port for 4bit data bit 2 */ | ||
| 142 | #endif | ||
| 143 | #ifndef LCD_DATA3_PORT | ||
| 144 | #define LCD_DATA3_PORT LCD_PORT /**< port for 4bit data bit 3 */ | ||
| 145 | #endif | ||
| 146 | #ifndef LCD_DATA0_PIN | ||
| 147 | #define LCD_DATA0_PIN 4 /**< pin for 4bit data bit 0 */ | ||
| 148 | #endif | ||
| 149 | #ifndef LCD_DATA1_PIN | ||
| 150 | #define LCD_DATA1_PIN 5 /**< pin for 4bit data bit 1 */ | ||
| 151 | #endif | ||
| 152 | #ifndef LCD_DATA2_PIN | ||
| 153 | #define LCD_DATA2_PIN 6 /**< pin for 4bit data bit 2 */ | ||
| 154 | #endif | ||
| 155 | #ifndef LCD_DATA3_PIN | ||
| 156 | #define LCD_DATA3_PIN 7 /**< pin for 4bit data bit 3 */ | ||
| 157 | #endif | ||
| 158 | #ifndef LCD_RS_PORT | ||
| 159 | #define LCD_RS_PORT LCD_PORT /**< port for RS line */ | ||
| 160 | #endif | ||
| 161 | #ifndef LCD_RS_PIN | ||
| 162 | #define LCD_RS_PIN 3 /**< pin for RS line */ | ||
| 163 | #endif | ||
| 164 | #ifndef LCD_RW_PORT | ||
| 165 | #define LCD_RW_PORT LCD_PORT /**< port for RW line */ | ||
| 166 | #endif | ||
| 167 | #ifndef LCD_RW_PIN | ||
| 168 | #define LCD_RW_PIN 2 /**< pin for RW line */ | ||
| 169 | #endif | ||
| 170 | #ifndef LCD_E_PORT | ||
| 171 | #define LCD_E_PORT LCD_PORT /**< port for Enable line */ | ||
| 172 | #endif | ||
| 173 | #ifndef LCD_E_PIN | ||
| 174 | #define LCD_E_PIN 1 /**< pin for Enable line */ | ||
| 175 | #endif | ||
| 176 | |||
| 177 | #elif defined(__AVR_AT90S4414__) || defined(__AVR_AT90S8515__) || defined(__AVR_ATmega64__) || \ | ||
| 178 | defined(__AVR_ATmega8515__)|| defined(__AVR_ATmega103__) || defined(__AVR_ATmega128__) || \ | ||
| 179 | defined(__AVR_ATmega161__) || defined(__AVR_ATmega162__) | ||
| 180 | /* | ||
| 181 | * memory mapped mode is only supported when the device has an external data memory interface | ||
| 182 | */ | ||
| 183 | #define LCD_IO_DATA 0xC000 /* A15=E=1, A14=RS=1 */ | ||
| 184 | #define LCD_IO_FUNCTION 0x8000 /* A15=E=1, A14=RS=0 */ | ||
| 185 | #define LCD_IO_READ 0x0100 /* A8 =R/W=1 (R/W: 1=Read, 0=Write */ | ||
| 186 | |||
| 187 | #else | ||
| 188 | #error "external data memory interface not available for this device, use 4-bit IO port mode" | ||
| 189 | |||
| 190 | #endif | ||
| 191 | |||
| 192 | |||
| 193 | /** | ||
| 194 | * @name Definitions of delays | ||
| 195 | * Used to calculate delay timers. | ||
| 196 | * Adapt the F_CPU define in the Makefile to the clock frequency in Hz of your target | ||
| 197 | * | ||
| 198 | * These delay times can be adjusted, if some displays require different delays.\n | ||
| 199 | * These definitions can be defined in a separate include file \b lcd_definitions.h instead modifying this file by | ||
| 200 | * adding \b -D_LCD_DEFINITIONS_FILE to the \b CDEFS section in the Makefile. | ||
| 201 | * All definitions added to the file lcd_definitions.h will override the default definitions from lcd.h | ||
| 202 | */ | ||
| 203 | #ifndef LCD_DELAY_BOOTUP | ||
| 204 | #define LCD_DELAY_BOOTUP 16000 /**< delay in micro seconds after power-on */ | ||
| 205 | #endif | ||
| 206 | #ifndef LCD_DELAY_INIT | ||
| 207 | #define LCD_DELAY_INIT 5000 /**< delay in micro seconds after initialization command sent */ | ||
| 208 | #endif | ||
| 209 | #ifndef LCD_DELAY_INIT_REP | ||
| 210 | #define LCD_DELAY_INIT_REP 64 /**< delay in micro seconds after initialization command repeated */ | ||
| 211 | #endif | ||
| 212 | #ifndef LCD_DELAY_INIT_4BIT | ||
| 213 | #define LCD_DELAY_INIT_4BIT 64 /**< delay in micro seconds after setting 4-bit mode */ | ||
| 214 | #endif | ||
| 215 | #ifndef LCD_DELAY_BUSY_FLAG | ||
| 216 | #define LCD_DELAY_BUSY_FLAG 4 /**< time in micro seconds the address counter is updated after busy flag is cleared */ | ||
| 217 | #endif | ||
| 218 | #ifndef LCD_DELAY_ENABLE_PULSE | ||
| 219 | #define LCD_DELAY_ENABLE_PULSE 1 /**< enable signal pulse width in micro seconds */ | ||
| 220 | #endif | ||
| 221 | |||
| 222 | |||
| 223 | /** | ||
| 224 | * @name Definitions for LCD command instructions | ||
| 225 | * The constants define the various LCD controller instructions which can be passed to the | ||
| 226 | * function lcd_command(), see HD44780 data sheet for a complete description. | ||
| 227 | */ | ||
| 228 | |||
| 229 | /* instruction register bit positions, see HD44780U data sheet */ | ||
| 230 | #define LCD_CLR 0 /* DB0: clear display */ | ||
| 231 | #define LCD_HOME 1 /* DB1: return to home position */ | ||
| 232 | #define LCD_ENTRY_MODE 2 /* DB2: set entry mode */ | ||
| 233 | #define LCD_ENTRY_INC 1 /* DB1: 1=increment, 0=decrement */ | ||
| 234 | #define LCD_ENTRY_SHIFT 0 /* DB2: 1=display shift on */ | ||
| 235 | #define LCD_ON 3 /* DB3: turn lcd/cursor on */ | ||
| 236 | #define LCD_ON_DISPLAY 2 /* DB2: turn display on */ | ||
| 237 | #define LCD_ON_CURSOR 1 /* DB1: turn cursor on */ | ||
| 238 | #define LCD_ON_BLINK 0 /* DB0: blinking cursor ? */ | ||
| 239 | #define LCD_MOVE 4 /* DB4: move cursor/display */ | ||
| 240 | #define LCD_MOVE_DISP 3 /* DB3: move display (0-> cursor) ? */ | ||
| 241 | #define LCD_MOVE_RIGHT 2 /* DB2: move right (0-> left) ? */ | ||
| 242 | #define LCD_FUNCTION 5 /* DB5: function set */ | ||
| 243 | #define LCD_FUNCTION_8BIT 4 /* DB4: set 8BIT mode (0->4BIT mode) */ | ||
| 244 | #define LCD_FUNCTION_2LINES 3 /* DB3: two lines (0->one line) */ | ||
| 245 | #define LCD_FUNCTION_10DOTS 2 /* DB2: 5x10 font (0->5x7 font) */ | ||
| 246 | #define LCD_CGRAM 6 /* DB6: set CG RAM address */ | ||
| 247 | #define LCD_DDRAM 7 /* DB7: set DD RAM address */ | ||
| 248 | #define LCD_BUSY 7 /* DB7: LCD is busy */ | ||
| 249 | |||
| 250 | /* set entry mode: display shift on/off, dec/inc cursor move direction */ | ||
| 251 | #define LCD_ENTRY_DEC 0x04 /* display shift off, dec cursor move dir */ | ||
| 252 | #define LCD_ENTRY_DEC_SHIFT 0x05 /* display shift on, dec cursor move dir */ | ||
| 253 | #define LCD_ENTRY_INC_ 0x06 /* display shift off, inc cursor move dir */ | ||
| 254 | #define LCD_ENTRY_INC_SHIFT 0x07 /* display shift on, inc cursor move dir */ | ||
| 255 | |||
| 256 | /* display on/off, cursor on/off, blinking char at cursor position */ | ||
| 257 | #define LCD_DISP_OFF 0x08 /* display off */ | ||
| 258 | #define LCD_DISP_ON 0x0C /* display on, cursor off */ | ||
| 259 | #define LCD_DISP_ON_BLINK 0x0D /* display on, cursor off, blink char */ | ||
| 260 | #define LCD_DISP_ON_CURSOR 0x0E /* display on, cursor on */ | ||
| 261 | #define LCD_DISP_ON_CURSOR_BLINK 0x0F /* display on, cursor on, blink char */ | ||
| 262 | |||
| 263 | /* move cursor/shift display */ | ||
| 264 | #define LCD_MOVE_CURSOR_LEFT 0x10 /* move cursor left (decrement) */ | ||
| 265 | #define LCD_MOVE_CURSOR_RIGHT 0x14 /* move cursor right (increment) */ | ||
| 266 | #define LCD_MOVE_DISP_LEFT 0x18 /* shift display left */ | ||
| 267 | #define LCD_MOVE_DISP_RIGHT 0x1C /* shift display right */ | ||
| 268 | |||
| 269 | /* function set: set interface data length and number of display lines */ | ||
| 270 | #define LCD_FUNCTION_4BIT_1LINE 0x20 /* 4-bit interface, single line, 5x7 dots */ | ||
| 271 | #define LCD_FUNCTION_4BIT_2LINES 0x28 /* 4-bit interface, dual line, 5x7 dots */ | ||
| 272 | #define LCD_FUNCTION_8BIT_1LINE 0x30 /* 8-bit interface, single line, 5x7 dots */ | ||
| 273 | #define LCD_FUNCTION_8BIT_2LINES 0x38 /* 8-bit interface, dual line, 5x7 dots */ | ||
| 274 | |||
| 275 | |||
| 276 | #define LCD_MODE_DEFAULT ((1<<LCD_ENTRY_MODE) | (1<<LCD_ENTRY_INC) ) | ||
| 277 | |||
| 278 | |||
| 279 | |||
| 280 | /** | ||
| 281 | * @name Functions | ||
| 282 | */ | ||
| 283 | |||
| 284 | |||
| 285 | /** | ||
| 286 | @brief Initialize display and select type of cursor | ||
| 287 | @param dispAttr \b LCD_DISP_OFF display off\n | ||
| 288 | \b LCD_DISP_ON display on, cursor off\n | ||
| 289 | \b LCD_DISP_ON_CURSOR display on, cursor on\n | ||
| 290 | \b LCD_DISP_ON_CURSOR_BLINK display on, cursor on flashing | ||
| 291 | @return none | ||
| 292 | */ | ||
| 293 | extern void lcd_init(uint8_t dispAttr); | ||
| 294 | |||
| 295 | |||
| 296 | /** | ||
| 297 | @brief Clear display and set cursor to home position | ||
| 298 | @return none | ||
| 299 | */ | ||
| 300 | extern void lcd_clrscr(void); | ||
| 301 | |||
| 302 | |||
| 303 | /** | ||
| 304 | @brief Set cursor to home position | ||
| 305 | @return none | ||
| 306 | */ | ||
| 307 | extern void lcd_home(void); | ||
| 308 | |||
| 309 | |||
| 310 | /** | ||
| 311 | @brief Set cursor to specified position | ||
| 312 | |||
| 313 | @param x horizontal position\n (0: left most position) | ||
| 314 | @param y vertical position\n (0: first line) | ||
| 315 | @return none | ||
| 316 | */ | ||
| 317 | extern void lcd_gotoxy(uint8_t x, uint8_t y); | ||
| 318 | |||
| 319 | |||
| 320 | /** | ||
| 321 | @brief Display character at current cursor position | ||
| 322 | @param c character to be displayed | ||
| 323 | @return none | ||
| 324 | */ | ||
| 325 | extern void lcd_putc(char c); | ||
| 326 | |||
| 327 | |||
| 328 | /** | ||
| 329 | @brief Display string without auto linefeed | ||
| 330 | @param s string to be displayed | ||
| 331 | @return none | ||
| 332 | */ | ||
| 333 | extern void lcd_puts(const char *s); | ||
| 334 | |||
| 335 | |||
| 336 | /** | ||
| 337 | @brief Display string from program memory without auto linefeed | ||
| 338 | @param progmem_s string from program memory be be displayed | ||
| 339 | @return none | ||
| 340 | @see lcd_puts_P | ||
| 341 | */ | ||
| 342 | extern void lcd_puts_p(const char *progmem_s); | ||
| 343 | |||
| 344 | |||
| 345 | /** | ||
| 346 | @brief Send LCD controller instruction command | ||
| 347 | @param cmd instruction to send to LCD controller, see HD44780 data sheet | ||
| 348 | @return none | ||
| 349 | */ | ||
| 350 | extern void lcd_command(uint8_t cmd); | ||
| 351 | |||
| 352 | |||
| 353 | /** | ||
| 354 | @brief Send data byte to LCD controller | ||
| 355 | |||
| 356 | Similar to lcd_putc(), but without interpreting LF | ||
| 357 | @param data byte to send to LCD controller, see HD44780 data sheet | ||
| 358 | @return none | ||
| 359 | */ | ||
| 360 | extern void lcd_data(uint8_t data); | ||
| 361 | |||
| 362 | |||
| 363 | /** | ||
| 364 | @brief macros for automatically storing string constant in program memory | ||
| 365 | */ | ||
| 366 | #define lcd_puts_P(__s) lcd_puts_p(PSTR(__s)) | ||
| 367 | |||
| 368 | /**@}*/ | ||
| 369 | |||
| 370 | #endif //LCD_H | ||
| 371 | |||
diff --git a/quantum/quantum.c b/quantum/quantum.c index b9934aee8..2bd2c71af 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c | |||
| @@ -1187,6 +1187,10 @@ void backlight_set(uint8_t level) {} | |||
| 1187 | 1187 | ||
| 1188 | #endif // backlight | 1188 | #endif // backlight |
| 1189 | 1189 | ||
| 1190 | #ifdef HD44780_ENABLED | ||
| 1191 | #include "hd44780.h" | ||
| 1192 | #endif | ||
| 1193 | |||
| 1190 | 1194 | ||
| 1191 | // Functions for spitting out values | 1195 | // Functions for spitting out values |
| 1192 | // | 1196 | // |
diff --git a/quantum/quantum.h b/quantum/quantum.h index 2958a0abd..223846412 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h | |||
| @@ -121,6 +121,10 @@ extern uint32_t default_layer_state; | |||
| 121 | #include "process_terminal_nop.h" | 121 | #include "process_terminal_nop.h" |
| 122 | #endif | 122 | #endif |
| 123 | 123 | ||
| 124 | #ifdef HD44780_ENABLE | ||
| 125 | #include "hd44780.h" | ||
| 126 | #endif | ||
| 127 | |||
| 124 | #define STRINGIZE(z) #z | 128 | #define STRINGIZE(z) #z |
| 125 | #define ADD_SLASH_X(y) STRINGIZE(\x ## y) | 129 | #define ADD_SLASH_X(y) STRINGIZE(\x ## y) |
| 126 | #define SYMBOL_STR(x) ADD_SLASH_X(x) | 130 | #define SYMBOL_STR(x) ADD_SLASH_X(x) |
diff --git a/quantum/template/avr/config.h b/quantum/template/avr/config.h index e739c93c9..ac3174502 100644 --- a/quantum/template/avr/config.h +++ b/quantum/template/avr/config.h | |||
| @@ -187,4 +187,32 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 187 | /* override number of MIDI tone keycodes (each octave adds 12 keycodes and allocates 12 bytes) */ | 187 | /* override number of MIDI tone keycodes (each octave adds 12 keycodes and allocates 12 bytes) */ |
| 188 | //#define MIDI_TONE_KEYCODE_OCTAVES 1 | 188 | //#define MIDI_TONE_KEYCODE_OCTAVES 1 |
| 189 | 189 | ||
| 190 | /* | ||
| 191 | * HD44780 LCD Display Configuration | ||
| 192 | */ | ||
| 193 | /* | ||
| 194 | #define LCD_LINES 2 //< number of visible lines of the display | ||
| 195 | #define LCD_DISP_LENGTH 16 //< visibles characters per line of the display | ||
| 196 | |||
| 197 | #define LCD_IO_MODE 1 //< 0: memory mapped mode, 1: IO port mode | ||
| 198 | |||
| 199 | #if LCD_IO_MODE | ||
| 200 | #define LCD_PORT PORTB //< port for the LCD lines | ||
| 201 | #define LCD_DATA0_PORT LCD_PORT //< port for 4bit data bit 0 | ||
| 202 | #define LCD_DATA1_PORT LCD_PORT //< port for 4bit data bit 1 | ||
| 203 | #define LCD_DATA2_PORT LCD_PORT //< port for 4bit data bit 2 | ||
| 204 | #define LCD_DATA3_PORT LCD_PORT //< port for 4bit data bit 3 | ||
| 205 | #define LCD_DATA0_PIN 4 //< pin for 4bit data bit 0 | ||
| 206 | #define LCD_DATA1_PIN 5 //< pin for 4bit data bit 1 | ||
| 207 | #define LCD_DATA2_PIN 6 //< pin for 4bit data bit 2 | ||
| 208 | #define LCD_DATA3_PIN 7 //< pin for 4bit data bit 3 | ||
| 209 | #define LCD_RS_PORT LCD_PORT //< port for RS line | ||
| 210 | #define LCD_RS_PIN 3 //< pin for RS line | ||
| 211 | #define LCD_RW_PORT LCD_PORT //< port for RW line | ||
| 212 | #define LCD_RW_PIN 2 //< pin for RW line | ||
| 213 | #define LCD_E_PORT LCD_PORT //< port for Enable line | ||
| 214 | #define LCD_E_PIN 1 //< pin for Enable line | ||
| 215 | #endif | ||
| 216 | */ | ||
| 217 | |||
| 190 | #endif | 218 | #endif |
diff --git a/quantum/template/avr/rules.mk b/quantum/template/avr/rules.mk index 45eb6ee37..d567544c7 100644 --- a/quantum/template/avr/rules.mk +++ b/quantum/template/avr/rules.mk | |||
| @@ -66,3 +66,4 @@ UNICODE_ENABLE = no # Unicode | |||
| 66 | BLUETOOTH_ENABLE = no # Enable Bluetooth with the Adafruit EZ-Key HID | 66 | BLUETOOTH_ENABLE = no # Enable Bluetooth with the Adafruit EZ-Key HID |
| 67 | AUDIO_ENABLE = no # Audio output on port C6 | 67 | AUDIO_ENABLE = no # Audio output on port C6 |
| 68 | FAUXCLICKY_ENABLE = no # Use buzzer to emulate clicky switches | 68 | FAUXCLICKY_ENABLE = no # Use buzzer to emulate clicky switches |
| 69 | HD44780_ENABLE = no # Enable support for HD44780 based LCDs (+400) | ||
diff --git a/tmk_core/common/keyboard.c b/tmk_core/common/keyboard.c index d3fbe2d87..13b3cb4c0 100644 --- a/tmk_core/common/keyboard.c +++ b/tmk_core/common/keyboard.c | |||
| @@ -69,6 +69,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 69 | #ifdef MIDI_ENABLE | 69 | #ifdef MIDI_ENABLE |
| 70 | # include "process_midi.h" | 70 | # include "process_midi.h" |
| 71 | #endif | 71 | #endif |
| 72 | #ifdef HD44780_ENABLE | ||
| 73 | # include "hd44780.h" | ||
| 74 | #endif | ||
| 72 | 75 | ||
| 73 | #ifdef MATRIX_HAS_GHOST | 76 | #ifdef MATRIX_HAS_GHOST |
| 74 | extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS]; | 77 | extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS]; |
