From cb6fcbead0826fdbe54dc0b2218eb77d229c8248 Mon Sep 17 00:00:00 2001 From: Akos Kiss Date: Mon, 5 Oct 2020 18:01:40 +0200 Subject: [PATCH 1/5] Fix the virtual memory of the HD44780 part In HD44780, the DDRAM has an address space of 0x80 bytes, while CGRAM has 0x40 bytes. To ensure their proper separation, the vram should have 0x80+0x40 bytes with the CGRAM starting at 0x80. --- examples/parts/hd44780.c | 15 +++++++-------- examples/parts/hd44780.h | 4 ++-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/examples/parts/hd44780.c b/examples/parts/hd44780.c index 144cbfcec..84fb993ba 100644 --- a/examples/parts/hd44780.c +++ b/examples/parts/hd44780.c @@ -55,7 +55,7 @@ static void _hd44780_clear_screen( hd44780_t *b) { - memset(b->vram, ' ', 80); + memset(b->vram, ' ', 0x80); hd44780_set_flag(b, HD44780_FLAG_DIRTY, 1); avr_raise_irq(b->irq + IRQ_HD44780_ADDR, b->cursor); } @@ -84,14 +84,14 @@ hd44780_kick_cursor( hd44780_t *b) { if (hd44780_get_flag(b, HD44780_FLAG_I_D)) { - if (b->cursor < 79) + if (b->cursor < 0x80-1) b->cursor++; - else if (b->cursor < 80+64-1) + else if (b->cursor < 0x80+0x40-1) b->cursor++; } else { - if (b->cursor < 80 && b->cursor) + if (b->cursor < 0x80 && b->cursor) b->cursor--; - else if (b->cursor > 80) + else if (b->cursor > 0x80) b->cursor--; hd44780_set_flag(b, HD44780_FLAG_DIRTY, 1); avr_raise_irq(b->irq + IRQ_HD44780_ADDR, b->cursor); @@ -139,7 +139,7 @@ hd44780_write_command( break; // Set CGRAM address case 6: // 0 1 ADD ADD ADD ADD ADD ADD ADD - b->cursor = 64 + (b->datapins & 0x3f); + b->cursor = 0x80 + (b->datapins & 0x3f); break; // Function set case 5: { // 0 0 1 DL N F x x @@ -246,7 +246,7 @@ hd44780_process_read( delay = 0; // no raising busy when reading busy ! // low bits are the current cursor - b->readpins = b->cursor < 80 ? b->cursor : b->cursor-64; + b->readpins = b->cursor < 0x80 ? b->cursor : b->cursor-0x80; int busy = hd44780_get_flag(b, HD44780_FLAG_BUSY); b->readpins |= busy ? 0x80 : 0; @@ -391,4 +391,3 @@ hd44780_init( printf("LCD: %duS is %d cycles for your AVR\n", 1, (int)avr_usec_to_cycles(avr, 1)); } - diff --git a/examples/parts/hd44780.h b/examples/parts/hd44780.h index 39353e53a..e359e6f1f 100644 --- a/examples/parts/hd44780.h +++ b/examples/parts/hd44780.h @@ -98,7 +98,7 @@ typedef struct hd44780_t int w, h; // width and height of the LCD uint16_t cursor; // offset in vram - uint8_t vram[80 + 64]; + uint8_t vram[0x80 + 0x40]; uint16_t pinstate; // 'actual' LCd data pins (IRQ bit field) // uint16_t oldstate; /// previous pins @@ -134,4 +134,4 @@ hd44780_get_flag( return (b->flags & (1 << bit)) != 0; } -#endif +#endif From f97e7f0ee0efe49f2adee55cf21e6ff179720d79 Mon Sep 17 00:00:00 2001 From: Akos Kiss Date: Thu, 8 Oct 2020 23:04:01 +0200 Subject: [PATCH 2/5] Fix cursor handling in segmented DDRAM of HD44780 HD44780 has only 80 bytes of DDRAM, which consists of two 40 bytes long segments. The segment starting at address 0x00 contains the data for the first line of the display, while the segment starting at address 0x40 contains the data for the second line of the display. This means that there are invalid ranges in the 7-bit address space of the DDRAM (0x00+40 .. 0x3f and 0x40+40 .. 0x7f). The cursor (address counter) of the HD44780 automatically "jumps over" these regions whenever auto-incremented/decremented. This commit implements this behaviour. Moreover, this commit also fixes the 4-lines mode. When in a 4-lines setup, the first 20 bytes of the first and the second memory segments control what is displayed in the first two lines, as usual. However, the second 20 bytes of the memory segments contain the data for the third and fourth lines of the display. This means that the starting addresses of lines 3 & 4 are 0x00+20 and 0x40+20. --- examples/parts/hd44780.c | 41 ++++++++++++++++++++++++++--------- examples/parts/hd44780_glut.c | 2 +- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/examples/parts/hd44780.c b/examples/parts/hd44780.c index 84fb993ba..0be074f97 100644 --- a/examples/parts/hd44780.c +++ b/examples/parts/hd44780.c @@ -32,7 +32,7 @@ hd44780_print( hd44780_t *b) { printf("/******************\\\n"); - const uint8_t offset[] = { 0, 0x40, 0x20, 0x60 }; + const uint8_t offset[] = { 0x00, 0x40, 0x00 + 20, 0x40 + 20 }; for (int i = 0; i < b->h; i++) { printf("| "); fwrite(b->vram + offset[i], 1, b->w, stdout); @@ -83,16 +83,33 @@ static void hd44780_kick_cursor( hd44780_t *b) { - if (hd44780_get_flag(b, HD44780_FLAG_I_D)) { - if (b->cursor < 0x80-1) + if (hd44780_get_flag(b, HD44780_FLAG_I_D)) { // incrementing + if (b->cursor < 0x80) { // cursor in DDRAM b->cursor++; - else if (b->cursor < 0x80+0x40-1) - b->cursor++; - } else { - if (b->cursor < 0x80 && b->cursor) - b->cursor--; - else if (b->cursor > 0x80) - b->cursor--; + if (b->cursor >= 0x00 + 40 && b->cursor < 0x40) // jump from end of first memory segment to the start of the second segment + b->cursor = 0x40; + else if (b->cursor >= 0x40 + 40) // wrap around from the end of the second memory segment to the start of the first segment + b->cursor = 0x00; + } else { // cursor in CGRAM + if (b->cursor == 0x80 + 0x3f) // wrap around in CGRAM + b->cursor = 0x80; + else + b->cursor++; + } + } else { // decrementing + if (b->cursor < 0x80) { // cursor in DDRAM + if (b->cursor == 0x40) // fall back from the start of the second memory segment to the end of the first segment + b->cursor = 0x00 + 39; + else if (b->cursor == 0x00) // wrap around from the start of the first memory segment to the end of the second segment + b->cursor = 0x40 + 39; + else + b->cursor--; + } else { // cursor in CGRAM + if (b->cursor == 0x80) // wrap around in CGRAM + b->cursor = 0x80 + 0x3f; + else + b->cursor--; + } hd44780_set_flag(b, HD44780_FLAG_DIRTY, 1); avr_raise_irq(b->irq + IRQ_HD44780_ADDR, b->cursor); } @@ -136,6 +153,10 @@ hd44780_write_command( // Set DDRAM address case 7: // 1 ADD ADD ADD ADD ADD ADD ADD b->cursor = b->datapins & 0x7f; + if (b->cursor >= 0x00 + 40 && b->cursor < 0x40) // illegal address after the first memory segment -> set cursor to start of second segment + b->cursor = 0x40; + else if (b->cursor >= 0x40 + 40) // illegal address after the second memory segment -> set cursor to start of first segment + b->cursor = 0x00; break; // Set CGRAM address case 6: // 0 1 ADD ADD ADD ADD ADD ADD ADD diff --git a/examples/parts/hd44780_glut.c b/examples/parts/hd44780_glut.c index b1c6fb9af..77c28bcbd 100644 --- a/examples/parts/hd44780_glut.c +++ b/examples/parts/hd44780_glut.c @@ -140,7 +140,7 @@ hd44780_gl_draw( glEnd(); glColor3f(1.0f, 1.0f, 1.0f); - const uint8_t offset[] = { 0, 0x40, 0x20, 0x60 }; + const uint8_t offset[] = { 0x00, 0x40, 0x00 + 20, 0x40 + 20 }; for (int v = 0 ; v < b->h; v++) { glPushMatrix(); for (int i = 0; i < b->w; i++) { From 3e33b6fabf7b34f126e48a3dd54909cac1699cd6 Mon Sep 17 00:00:00 2001 From: Akos Kiss Date: Fri, 9 Oct 2020 01:42:15 +0200 Subject: [PATCH 3/5] Fix Clear Screen implementation of HD44780 Datasheet mandates filling DDRAM with spaces, setting address counter to DDRAM address 0, and setting entry mode I/D to 1 (increment mode). The "filling with spaces" was implemented but the rest was missing. Now added. --- examples/parts/hd44780.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/parts/hd44780.c b/examples/parts/hd44780.c index 0be074f97..a2d0177a9 100644 --- a/examples/parts/hd44780.c +++ b/examples/parts/hd44780.c @@ -56,6 +56,8 @@ _hd44780_clear_screen( hd44780_t *b) { memset(b->vram, ' ', 0x80); + b->cursor = 0; + hd44780_set_flag(b, HD44780_FLAG_I_D, 2); hd44780_set_flag(b, HD44780_FLAG_DIRTY, 1); avr_raise_irq(b->irq + IRQ_HD44780_ADDR, b->cursor); } From ed0b5d4c6f4c363e67bb4ee246f428adcbf37077 Mon Sep 17 00:00:00 2001 From: Akos Kiss Date: Tue, 13 Oct 2020 23:38:43 +0200 Subject: [PATCH 4/5] Handle the difference between 1 and 2-line displays in HD44780 If HD44780 is configured to have a single line of display, AC can be in the range of 0x00..0x00+79, while with two lines, it can be in the ranges 0x00..0x00+39 and 0x40..0x40+39. --- examples/parts/hd44780.c | 45 +++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/examples/parts/hd44780.c b/examples/parts/hd44780.c index a2d0177a9..1d0da5d7f 100644 --- a/examples/parts/hd44780.c +++ b/examples/parts/hd44780.c @@ -88,10 +88,15 @@ hd44780_kick_cursor( if (hd44780_get_flag(b, HD44780_FLAG_I_D)) { // incrementing if (b->cursor < 0x80) { // cursor in DDRAM b->cursor++; - if (b->cursor >= 0x00 + 40 && b->cursor < 0x40) // jump from end of first memory segment to the start of the second segment - b->cursor = 0x40; - else if (b->cursor >= 0x40 + 40) // wrap around from the end of the second memory segment to the start of the first segment - b->cursor = 0x00; + if (hd44780_get_flag(b, HD44780_FLAG_N)) { // 2-line display + if (b->cursor >= 0x00 + 40 && b->cursor < 0x40) // jump from end of first memory segment to the start of the second segment + b->cursor = 0x40; + else if (b->cursor >= 0x40 + 40) // wrap around from the end of the second memory segment to the start of the first segment + b->cursor = 0x00; + } else { // 1-line display + if (b->cursor >= 0x00 + 80) // wrap around from the end of the memory to the start + b->cursor = 0x00; + } } else { // cursor in CGRAM if (b->cursor == 0x80 + 0x3f) // wrap around in CGRAM b->cursor = 0x80; @@ -100,12 +105,19 @@ hd44780_kick_cursor( } } else { // decrementing if (b->cursor < 0x80) { // cursor in DDRAM - if (b->cursor == 0x40) // fall back from the start of the second memory segment to the end of the first segment - b->cursor = 0x00 + 39; - else if (b->cursor == 0x00) // wrap around from the start of the first memory segment to the end of the second segment - b->cursor = 0x40 + 39; - else - b->cursor--; + if (hd44780_get_flag(b, HD44780_FLAG_N)) { // 2-line display + if (b->cursor == 0x40) // fall back from the start of the second memory segment to the end of the first segment + b->cursor = 0x00 + 39; + else if (b->cursor == 0x00) // wrap around from the start of the first memory segment to the end of the second segment + b->cursor = 0x40 + 39; + else + b->cursor--; + } else { // 1-line display + if (b->cursor == 0x00) // wrap around from the start of the memory to the end + b->cursor = 0x00 + 79; + else + b->cursor--; + } } else { // cursor in CGRAM if (b->cursor == 0x80) // wrap around in CGRAM b->cursor = 0x80 + 0x3f; @@ -155,10 +167,15 @@ hd44780_write_command( // Set DDRAM address case 7: // 1 ADD ADD ADD ADD ADD ADD ADD b->cursor = b->datapins & 0x7f; - if (b->cursor >= 0x00 + 40 && b->cursor < 0x40) // illegal address after the first memory segment -> set cursor to start of second segment - b->cursor = 0x40; - else if (b->cursor >= 0x40 + 40) // illegal address after the second memory segment -> set cursor to start of first segment - b->cursor = 0x00; + if (hd44780_get_flag(b, HD44780_FLAG_N)) { // 2-line display + if (b->cursor >= 0x00 + 40 && b->cursor < 0x40) // illegal address after the first memory segment -> set cursor to start of second segment + b->cursor = 0x40; + else if (b->cursor >= 0x40 + 40) // illegal address after the second memory segment -> set cursor to start of first segment + b->cursor = 0x00; + } else { // 1-line display + if (b->cursor >= 0x00 + 80) // illegal address after valid memory -> set cursor to start + b->cursor = 0x00; + } break; // Set CGRAM address case 6: // 0 1 ADD ADD ADD ADD ADD ADD ADD From 03a01c70dc1b001d06729a2ad42ad2310585d32e Mon Sep 17 00:00:00 2001 From: Akos Kiss Date: Wed, 14 Oct 2020 00:11:03 +0200 Subject: [PATCH 5/5] Fix typos in comments in HD44780 --- examples/parts/hd44780.c | 10 +++++----- examples/parts/hd44780.h | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/parts/hd44780.c b/examples/parts/hd44780.c index 1d0da5d7f..7428be365 100644 --- a/examples/parts/hd44780.c +++ b/examples/parts/hd44780.c @@ -65,7 +65,7 @@ _hd44780_clear_screen( /* - * This is called when the delay between operation is triggered + * This is called when the delay between operations is triggered * without the AVR firmware 'reading' the status byte. It * automatically clears the BUSY flag for the next command */ @@ -156,7 +156,7 @@ hd44780_write_command( hd44780_t *b) { uint32_t delay = 37; // uS - int top = 7; // get highest bit set'm + int top = 7; // get highest bit set while (top) if (b->datapins & (1 << top)) break; @@ -164,7 +164,7 @@ hd44780_write_command( printf("hd44780_write_command %02x\n", b->datapins); switch (top) { - // Set DDRAM address + // Set DDRAM address case 7: // 1 ADD ADD ADD ADD ADD ADD ADD b->cursor = b->datapins & 0x7f; if (hd44780_get_flag(b, HD44780_FLAG_N)) { // 2-line display @@ -177,8 +177,8 @@ hd44780_write_command( b->cursor = 0x00; } break; - // Set CGRAM address - case 6: // 0 1 ADD ADD ADD ADD ADD ADD ADD + // Set CGRAM address + case 6: // 0 1 ACG ACG ACG ACG ACG ACG b->cursor = 0x80 + (b->datapins & 0x3f); break; // Function set diff --git a/examples/parts/hd44780.h b/examples/parts/hd44780.h index e359e6f1f..c165314c9 100644 --- a/examples/parts/hd44780.h +++ b/examples/parts/hd44780.h @@ -30,12 +30,12 @@ * + As usual, the "RW" pin is optional if you are willing to wait for the * specific number of cycles as per the datasheet (37uS between operations) * + If you decide to use the RW pin, the "busy" flag is supported and will - * be automaticly cleared on the second read, to exercisee the code a bit. - * + Cursor is supported, but now "display shift" + * be automatically cleared on the second read, to exercise the code a bit. + * + Cursor is supported, but no "display shift" * + The Character RAM is supported, but is not currently drawn. * * To interface this part, you can use the "INPUT" IRQs and hook them to the - * simavr instance, if you use the RW pins or read back frim the display, you + * simavr instance, if you use the RW pins or read back from the display, you * can hook the data pins /back/ to the AVR too. * * The "part" also provides various IRQs that are there to be placed in a VCD file @@ -77,13 +77,13 @@ enum { HD44780_FLAG_C, // 1: Cursor on HD44780_FLAG_D, // 1: Set Entire Display memory (for clear) HD44780_FLAG_S, // 1: Follow display shift - HD44780_FLAG_I_D, // 1: Increment, 0: Decrement + HD44780_FLAG_I_D, // 1: Increment, 0: Decrement /* * Internal flags, not HD44780 */ HD44780_FLAG_LOWNIBBLE, // 1: 4 bits mode, write/read low nibble - HD44780_FLAG_BUSY, // 1: Busy between instruction, 0: ready + HD44780_FLAG_BUSY, // 1: Busy between instructions, 0: ready HD44780_FLAG_REENTRANT, // 1: Do not update pins HD44780_FLAG_DIRTY, // 1: needs redisplay... @@ -100,7 +100,7 @@ typedef struct hd44780_t uint16_t cursor; // offset in vram uint8_t vram[0x80 + 0x40]; - uint16_t pinstate; // 'actual' LCd data pins (IRQ bit field) + uint16_t pinstate; // 'actual' LCD data pins (IRQ bit field) // uint16_t oldstate; /// previous pins uint8_t datapins; // composite of 4 high bits, or 8 bits uint8_t readpins;