4 Copyright Luki <humbell@ethz.ch>
5 Copyright 2011 Michel Pollet <buserror@gmail.com>
7 This file is part of simavr.
9 simavr 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.
14 simavr 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.
19 You should have received a copy of the GNU General Public License
20 along with simavr. If not, see <http://www.gnu.org/licenses/>.
26 #include "sim_cycle_timers.h"
34 printf("/******************\\\n");
35 const uint8_t offset[] = { 0, 0x40, 0x20, 0x60 };
36 for (int i = 0; i < b->h; i++) {
38 fwrite(b->vram + offset[i], 1, b->w, stdout);
41 printf("\\******************/\n");
46 _hd44780_reset_cursor(
50 hd44780_set_flag(b, HD44780_FLAG_DIRTY, 1);
51 avr_raise_irq(b->irq + IRQ_HD44780_ADDR, b->cursor);
55 _hd44780_clear_screen(
58 memset(b->vram, ' ', 80);
59 hd44780_set_flag(b, HD44780_FLAG_DIRTY, 1);
60 avr_raise_irq(b->irq + IRQ_HD44780_ADDR, b->cursor);
66 * This is called when the delay between operation is triggered
67 * without the AVR firmware 'reading' the status byte. It
68 * automatically clears the BUSY flag for the next command
70 static avr_cycle_count_t
73 avr_cycle_count_t when, void * param)
75 hd44780_t *b = (hd44780_t *) param;
76 // printf("%s called\n", __FUNCTION__);
77 hd44780_set_flag(b, HD44780_FLAG_BUSY, 0);
78 avr_raise_irq(b->irq + IRQ_HD44780_BUSY, 0);
86 if (hd44780_get_flag(b, HD44780_FLAG_I_D)) {
89 else if (b->cursor < 80+64-1)
92 if (b->cursor < 80 && b->cursor)
94 else if (b->cursor > 80)
96 hd44780_set_flag(b, HD44780_FLAG_DIRTY, 1);
97 avr_raise_irq(b->irq + IRQ_HD44780_ADDR, b->cursor);
102 * current data byte is ready in b->datapins
108 uint32_t delay = 37; // uS
109 b->vram[b->cursor] = b->datapins;
110 printf("hd44780_write_data %02x\n", b->datapins);
111 if (hd44780_get_flag(b, HD44780_FLAG_S_C)) { // display shift ?
112 // TODO display shift
114 hd44780_kick_cursor(b);
116 hd44780_set_flag(b, HD44780_FLAG_DIRTY, 1);
121 * current command is ready in b->datapins
124 hd44780_write_command(
127 uint32_t delay = 37; // uS
128 int top = 7; // get highest bit set'm
130 if (b->datapins & (1 << top))
133 printf("hd44780_write_command %02x\n", b->datapins);
137 case 7: // 1 ADD ADD ADD ADD ADD ADD ADD
138 b->cursor = b->datapins & 0x7f;
141 case 6: // 0 1 ADD ADD ADD ADD ADD ADD ADD
142 b->cursor = 64 + (b->datapins & 0x3f);
145 case 5: { // 0 0 1 DL N F x x
146 int four = !hd44780_get_flag(b, HD44780_FLAG_D_L);
147 hd44780_set_flag(b, HD44780_FLAG_D_L, b->datapins & 16);
148 hd44780_set_flag(b, HD44780_FLAG_N, b->datapins & 8);
149 hd44780_set_flag(b, HD44780_FLAG_F, b->datapins & 4);
150 if (!four && !hd44780_get_flag(b, HD44780_FLAG_D_L)) {
151 printf("%s activating 4 bits mode\n", __FUNCTION__);
152 hd44780_set_flag(b, HD44780_FLAG_LOWNIBBLE, 0);
155 // Cursor display shift
156 case 4: // 0 0 0 1 S/C R/L x x
157 hd44780_set_flag(b, HD44780_FLAG_S_C, b->datapins & 8);
158 hd44780_set_flag(b, HD44780_FLAG_R_L, b->datapins & 4);
160 // Display on/off control
161 case 3: // 0 0 0 0 1 D C B
162 hd44780_set_flag(b, HD44780_FLAG_D, b->datapins & 4);
163 hd44780_set_flag(b, HD44780_FLAG_C, b->datapins & 2);
164 hd44780_set_flag(b, HD44780_FLAG_B, b->datapins & 1);
165 hd44780_set_flag(b, HD44780_FLAG_DIRTY, 1);
168 case 2: // 0 0 0 0 0 1 I/D S
169 hd44780_set_flag(b, HD44780_FLAG_I_D, b->datapins & 2);
170 hd44780_set_flag(b, HD44780_FLAG_S, b->datapins & 1);
173 case 1: // 0 0 0 0 0 0 1 x
174 _hd44780_reset_cursor(b);
178 case 0: // 0 0 0 0 0 0 0 1
179 _hd44780_clear_screen(b);
186 * the E pin went low, and it's a write
189 hd44780_process_write(
192 uint32_t delay = 0; // uS
193 int four = !hd44780_get_flag(b, HD44780_FLAG_D_L);
194 int comp = four && hd44780_get_flag(b, HD44780_FLAG_LOWNIBBLE);
197 if (four) { // 4 bits !
199 b->datapins = (b->datapins & 0xf0) | ((b->pinstate >> IRQ_HD44780_D4) & 0xf);
201 b->datapins = (b->datapins & 0xf) | ((b->pinstate >> IRQ_HD44780_D4-4) & 0xf0);
203 b->flags ^= (1 << HD44780_FLAG_LOWNIBBLE);
205 b->datapins = (b->pinstate >> IRQ_HD44780_D0) & 0xff;
208 avr_raise_irq(b->irq + IRQ_HD44780_DATA_IN, b->datapins);
210 // write has 8 bits to process
212 if (hd44780_get_flag(b, HD44780_FLAG_BUSY)) {
213 printf("%s command %02x write when still BUSY\n", __FUNCTION__, b->datapins);
215 if (b->pinstate & (1 << IRQ_HD44780_RS)) // write data
216 delay = hd44780_write_data(b);
217 else // write command
218 delay = hd44780_write_command(b);
224 hd44780_process_read(
227 uint32_t delay = 0; // uS
228 int four = !hd44780_get_flag(b, HD44780_FLAG_D_L);
229 int comp = four && hd44780_get_flag(b, HD44780_FLAG_LOWNIBBLE);
230 int done = 0; // has something on the datapin we want
233 // ready the 4 final bits on the 'actual' lcd pins
236 b->flags ^= (1 << HD44780_FLAG_LOWNIBBLE);
239 if (!done) { // new read
241 if (b->pinstate & (1 << IRQ_HD44780_RS)) { // read data
243 b->readpins = b->vram[b->cursor];
244 hd44780_kick_cursor(b);
245 } else { // read 'command' ie status register
246 delay = 0; // no raising busy when reading busy !
248 // low bits are the current cursor
249 b->readpins = b->cursor < 80 ? b->cursor : b->cursor-64;
250 int busy = hd44780_get_flag(b, HD44780_FLAG_BUSY);
251 b->readpins |= busy ? 0x80 : 0;
253 // if (busy) printf("Good boy, guy's reading status byte\n");
254 // now that we're read the busy flag, clear it and clear
256 hd44780_set_flag(b, HD44780_FLAG_BUSY, 0);
257 avr_raise_irq(b->irq + IRQ_HD44780_BUSY, 0);
258 avr_cycle_timer_cancel(b->avr, _hd44780_busy_timer, b);
260 avr_raise_irq(b->irq + IRQ_HD44780_DATA_OUT, b->readpins);
264 b->flags |= (1 << HD44780_FLAG_LOWNIBBLE); // for next read
267 // now send the prepared output pins to send as IRQs
269 avr_raise_irq(b->irq + IRQ_HD44780_ALL, b->readpins >> 4);
270 for (int i = four ? 4 : 0; i < 8; i++)
271 avr_raise_irq(b->irq + IRQ_HD44780_D0 + i, (b->readpins >> i) & 1);
276 static avr_cycle_count_t
277 _hd44780_process_e_pinchange(
279 avr_cycle_count_t when, void * param)
281 hd44780_t *b = (hd44780_t *) param;
283 hd44780_set_flag(b, HD44780_FLAG_REENTRANT, 1);
286 uint16_t touch = b->oldstate ^ b->pinstate;
287 printf("LCD: %04x %04x %c %c %c %c\n", b->pinstate, touch,
288 b->pinstate & (1 << IRQ_HD44780_RW) ? 'R' : 'W',
289 b->pinstate & (1 << IRQ_HD44780_RS) ? 'D' : 'C',
290 hd44780_get_flag(b, HD44780_FLAG_LOWNIBBLE) ? 'L' : 'H',
291 hd44780_get_flag(b, HD44780_FLAG_BUSY) ? 'B' : ' ');
293 int delay = 0; // in uS
295 if (b->pinstate & (1 << IRQ_HD44780_RW)) // read !?!
296 delay = hd44780_process_read(b);
298 delay = hd44780_process_write(b);
301 hd44780_set_flag(b, HD44780_FLAG_BUSY, 1);
302 avr_raise_irq(b->irq + IRQ_HD44780_BUSY, 1);
303 avr_cycle_timer_register_usec(b->avr, delay,
304 _hd44780_busy_timer, b);
306 // b->oldstate = b->pinstate;
307 hd44780_set_flag(b, HD44780_FLAG_REENTRANT, 0);
312 hd44780_pin_changed_hook(
313 struct avr_irq_t * irq,
317 hd44780_t *b = (hd44780_t *) param;
319 uint16_t old = b->pinstate;
323 * Update all the pins in one go by calling ourselves
324 * This is a shortcut for firmware that respects the conventions
326 case IRQ_HD44780_ALL:
327 for (int i = 0; i < 4; i++)
328 hd44780_pin_changed_hook(b->irq + IRQ_HD44780_D4 + i,
329 ((value >> i) & 1), param);
330 hd44780_pin_changed_hook(b->irq + IRQ_HD44780_RS, (value >> 4), param);
331 hd44780_pin_changed_hook(b->irq + IRQ_HD44780_E, (value >> 5), param);
332 hd44780_pin_changed_hook(b->irq + IRQ_HD44780_RW, (value >> 6), param);
333 return; // job already done!
334 case IRQ_HD44780_D0 ... IRQ_HD44780_D7:
335 // don't update these pins in read mode
336 if (hd44780_get_flag(b, HD44780_FLAG_REENTRANT))
340 b->pinstate = (b->pinstate & ~(1 << irq->irq)) | (value << irq->irq);
341 int eo = old & (1 << IRQ_HD44780_E);
342 int e = b->pinstate & (1 << IRQ_HD44780_E);
343 // on the E pin rising edge, do stuff otherwise just exit
345 avr_cycle_timer_register(b->avr, 1, _hd44780_process_e_pinchange, b);
351 struct hd44780_t * b,
355 memset(b, 0, sizeof(*b));
360 * Register callbacks on all our IRQs
362 b->irq = avr_alloc_irq(0, IRQ_HD44780_COUNT);
363 for (int i = 0; i < IRQ_HD44780_INPUT_COUNT; i++)
364 avr_irq_register_notify(b->irq + i, hd44780_pin_changed_hook, b);
366 _hd44780_reset_cursor(b);
367 _hd44780_clear_screen(b);
369 printf("LCD: %duS is %d cycles for your AVR\n",
370 37, (int)avr_usec_to_cycles(avr, 37));
371 printf("LCD: %duS is %d cycles for your AVR\n",
372 1, (int)avr_usec_to_cycles(avr, 1));