2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <joerg@FreeBSD.ORG> wrote this file. As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return. Joerg Wunsch
7 * ----------------------------------------------------------------------------
9 * HD44780 LCD display driver
11 * The LCD controller is used in 4-bit mode with a full bi-directional
12 * interface (i.e. R/~W is connected) so the busy flag can be read.
14 * $Id: hd44780.c 2002 2009-06-25 20:21:16Z joerg_wunsch $
17 #include "avr_hd44780_conf.h"
23 #include <util/delay.h>
25 #include "avr_hd44780.h"
27 #define GLUE(a, b) a##b
29 /* single-bit macros, used for control bits */
30 #define SET_(what, p, m) GLUE(what, p) |= (1 << (m))
31 #define CLR_(what, p, m) GLUE(what, p) &= ~(1 << (m))
32 #define GET_(/* PIN, */ p, m) GLUE(PIN, p) & (1 << (m))
33 #define SET(what, x) SET_(what, x)
34 #define CLR(what, x) CLR_(what, x)
35 #define GET(/* PIN, */ x) GET_(x)
37 /* nibble macros, used for data path */
38 #define ASSIGN_(what, p, m, v) GLUE(what, p) = (GLUE(what, p) & \
39 ~((1 << (m)) | (1 << ((m) + 1)) | \
40 (1 << ((m) + 2)) | (1 << ((m) + 3)))) | \
42 #define READ_(what, p, m) (GLUE(what, p) & ((1 << (m)) | (1 << ((m) + 1)) | \
43 (1 << ((m) + 2)) | (1 << ((m) + 3)))) >> (m)
44 #define ASSIGN(what, x, v) ASSIGN_(what, x, v)
45 #define READ(what, x) READ_(what, x)
47 #define HD44780_BUSYFLAG 0x80
50 * Send one pulse to the E signal (enable). Mind the timing
51 * constraints. If readback is set to true, read the HD44780 data
52 * pins right before the falling edge of E, and return that value.
55 hd44780_pulse_e(bool readback) __attribute__((always_inline));
58 hd44780_pulse_e(bool readback)
64 * Guarantee at least 500 ns of pulse width. For high CPU
65 * frequencies, a delay loop is used. For lower frequencies, NOPs
66 * are used, and at or below 1 MHz, the native pulse width will
67 * already be 1 us or more so no additional delays are needed.
73 * When reading back, we need one additional NOP, as the value read
74 * back from the input pin is sampled close to the beginning of a
75 * CPU clock cycle, while the previous edge on the output pin is
76 * generated towards the end of a CPU clock cycle.
79 __asm__ volatile("nop");
80 # if F_CPU > 1000000UL
81 __asm__ volatile("nop");
82 # if F_CPU > 2000000UL
83 __asm__ volatile("nop");
84 __asm__ volatile("nop");
85 # endif /* F_CPU > 2000000UL */
86 # endif /* F_CPU > 1000000UL */
89 x = READ(PIN, HD44780_D4);
98 * Send one nibble out to the LCD controller.
101 hd44780_outnibble(uint8_t n, uint8_t rs)
103 CLR(PORT, HD44780_RW);
105 SET(PORT, HD44780_RS);
107 CLR(PORT, HD44780_RS);
108 ASSIGN(PORT, HD44780_D4, n);
109 (void)hd44780_pulse_e(false);
113 * Send one byte to the LCD controller. As we are in 4-bit mode, we
114 * have to send two nibbles.
117 hd44780_outbyte(uint8_t b, uint8_t rs)
119 hd44780_outnibble(b >> 4, rs);
120 hd44780_outnibble(b & 0xf, rs);
124 * Read one nibble from the LCD controller.
127 hd44780_innibble(uint8_t rs)
131 SET(PORT, HD44780_RW);
132 ASSIGN(DDR, HD44780_D4, 0x00);
134 SET(PORT, HD44780_RS);
136 CLR(PORT, HD44780_RS);
137 x = hd44780_pulse_e(true);
138 ASSIGN(DDR, HD44780_D4, 0x0F);
139 CLR(PORT, HD44780_RW);
145 * Read one byte (i.e. two nibbles) from the LCD controller.
148 hd44780_inbyte(uint8_t rs)
152 x = hd44780_innibble(rs) << 4;
153 x |= hd44780_innibble(rs);
159 * Wait until the busy flag is cleared.
162 hd44780_wait_ready(bool longwait)
165 while (hd44780_incmd() & HD44780_BUSYFLAG) ;
175 * Initialize the LCD controller.
177 * The initialization sequence has a mandatory timing so the
178 * controller can safely recognize the type of interface desired.
179 * This is the only area where timed waits are really needed as
180 * the busy flag cannot be probed initially.
185 SET(DDR, HD44780_RS);
186 SET(DDR, HD44780_RW);
188 ASSIGN(DDR, HD44780_D4, 0x0F);
190 _delay_ms(15); /* 40 ms needed for Vcc = 2.7 V */
191 hd44780_outnibble(HD44780_FNSET(1, 0, 0) >> 4, 0);
193 hd44780_outnibble(HD44780_FNSET(1, 0, 0) >> 4, 0);
195 hd44780_outnibble(HD44780_FNSET(1, 0, 0) >> 4, 0);
196 _delay_us(40); /* 37 is too short */
198 hd44780_outnibble(HD44780_FNSET(0, 1, 0) >> 4, 0);
199 hd44780_wait_ready(false);
200 hd44780_outcmd(HD44780_FNSET(0, 1, 0));
201 hd44780_wait_ready(false);
202 hd44780_outcmd(HD44780_DISPCTL(0, 0, 0));
203 hd44780_wait_ready(false);
207 * Prepare the LCD controller pins for powerdown.
210 hd44780_powerdown(void)
212 ASSIGN(PORT, HD44780_D4, 0);
213 CLR(PORT, HD44780_RS);
214 CLR(PORT, HD44780_RW);
215 CLR(PORT, HD44780_E);