Skip to content

Commit 7c4afd1

Browse files
authored
Merge pull request buserror#406 from akosthekiss/fix-hd44780-memory
Fixes to HD44780
2 parents 4d1750b + 03a01c7 commit 7c4afd1

File tree

3 files changed

+67
-28
lines changed

3 files changed

+67
-28
lines changed

examples/parts/hd44780.c

Lines changed: 58 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ hd44780_print(
3232
hd44780_t *b)
3333
{
3434
printf("/******************\\\n");
35-
const uint8_t offset[] = { 0, 0x40, 0x20, 0x60 };
35+
const uint8_t offset[] = { 0x00, 0x40, 0x00 + 20, 0x40 + 20 };
3636
for (int i = 0; i < b->h; i++) {
3737
printf("| ");
3838
fwrite(b->vram + offset[i], 1, b->w, stdout);
@@ -55,15 +55,17 @@ static void
5555
_hd44780_clear_screen(
5656
hd44780_t *b)
5757
{
58-
memset(b->vram, ' ', 80);
58+
memset(b->vram, ' ', 0x80);
59+
b->cursor = 0;
60+
hd44780_set_flag(b, HD44780_FLAG_I_D, 2);
5961
hd44780_set_flag(b, HD44780_FLAG_DIRTY, 1);
6062
avr_raise_irq(b->irq + IRQ_HD44780_ADDR, b->cursor);
6163
}
6264

6365

6466

6567
/*
66-
* This is called when the delay between operation is triggered
68+
* This is called when the delay between operations is triggered
6769
* without the AVR firmware 'reading' the status byte. It
6870
* automatically clears the BUSY flag for the next command
6971
*/
@@ -83,16 +85,45 @@ static void
8385
hd44780_kick_cursor(
8486
hd44780_t *b)
8587
{
86-
if (hd44780_get_flag(b, HD44780_FLAG_I_D)) {
87-
if (b->cursor < 79)
88-
b->cursor++;
89-
else if (b->cursor < 80+64-1)
88+
if (hd44780_get_flag(b, HD44780_FLAG_I_D)) { // incrementing
89+
if (b->cursor < 0x80) { // cursor in DDRAM
9090
b->cursor++;
91-
} else {
92-
if (b->cursor < 80 && b->cursor)
93-
b->cursor--;
94-
else if (b->cursor > 80)
95-
b->cursor--;
91+
if (hd44780_get_flag(b, HD44780_FLAG_N)) { // 2-line display
92+
if (b->cursor >= 0x00 + 40 && b->cursor < 0x40) // jump from end of first memory segment to the start of the second segment
93+
b->cursor = 0x40;
94+
else if (b->cursor >= 0x40 + 40) // wrap around from the end of the second memory segment to the start of the first segment
95+
b->cursor = 0x00;
96+
} else { // 1-line display
97+
if (b->cursor >= 0x00 + 80) // wrap around from the end of the memory to the start
98+
b->cursor = 0x00;
99+
}
100+
} else { // cursor in CGRAM
101+
if (b->cursor == 0x80 + 0x3f) // wrap around in CGRAM
102+
b->cursor = 0x80;
103+
else
104+
b->cursor++;
105+
}
106+
} else { // decrementing
107+
if (b->cursor < 0x80) { // cursor in DDRAM
108+
if (hd44780_get_flag(b, HD44780_FLAG_N)) { // 2-line display
109+
if (b->cursor == 0x40) // fall back from the start of the second memory segment to the end of the first segment
110+
b->cursor = 0x00 + 39;
111+
else if (b->cursor == 0x00) // wrap around from the start of the first memory segment to the end of the second segment
112+
b->cursor = 0x40 + 39;
113+
else
114+
b->cursor--;
115+
} else { // 1-line display
116+
if (b->cursor == 0x00) // wrap around from the start of the memory to the end
117+
b->cursor = 0x00 + 79;
118+
else
119+
b->cursor--;
120+
}
121+
} else { // cursor in CGRAM
122+
if (b->cursor == 0x80) // wrap around in CGRAM
123+
b->cursor = 0x80 + 0x3f;
124+
else
125+
b->cursor--;
126+
}
96127
hd44780_set_flag(b, HD44780_FLAG_DIRTY, 1);
97128
avr_raise_irq(b->irq + IRQ_HD44780_ADDR, b->cursor);
98129
}
@@ -125,21 +156,30 @@ hd44780_write_command(
125156
hd44780_t *b)
126157
{
127158
uint32_t delay = 37; // uS
128-
int top = 7; // get highest bit set'm
159+
int top = 7; // get highest bit set
129160
while (top)
130161
if (b->datapins & (1 << top))
131162
break;
132163
else top--;
133164
printf("hd44780_write_command %02x\n", b->datapins);
134165

135166
switch (top) {
136-
// Set DDRAM address
167+
// Set DDRAM address
137168
case 7: // 1 ADD ADD ADD ADD ADD ADD ADD
138169
b->cursor = b->datapins & 0x7f;
170+
if (hd44780_get_flag(b, HD44780_FLAG_N)) { // 2-line display
171+
if (b->cursor >= 0x00 + 40 && b->cursor < 0x40) // illegal address after the first memory segment -> set cursor to start of second segment
172+
b->cursor = 0x40;
173+
else if (b->cursor >= 0x40 + 40) // illegal address after the second memory segment -> set cursor to start of first segment
174+
b->cursor = 0x00;
175+
} else { // 1-line display
176+
if (b->cursor >= 0x00 + 80) // illegal address after valid memory -> set cursor to start
177+
b->cursor = 0x00;
178+
}
139179
break;
140-
// Set CGRAM address
141-
case 6: // 0 1 ADD ADD ADD ADD ADD ADD ADD
142-
b->cursor = 64 + (b->datapins & 0x3f);
180+
// Set CGRAM address
181+
case 6: // 0 1 ACG ACG ACG ACG ACG ACG
182+
b->cursor = 0x80 + (b->datapins & 0x3f);
143183
break;
144184
// Function set
145185
case 5: { // 0 0 1 DL N F x x
@@ -246,7 +286,7 @@ hd44780_process_read(
246286
delay = 0; // no raising busy when reading busy !
247287

248288
// low bits are the current cursor
249-
b->readpins = b->cursor < 80 ? b->cursor : b->cursor-64;
289+
b->readpins = b->cursor < 0x80 ? b->cursor : b->cursor-0x80;
250290
int busy = hd44780_get_flag(b, HD44780_FLAG_BUSY);
251291
b->readpins |= busy ? 0x80 : 0;
252292

@@ -391,4 +431,3 @@ hd44780_init(
391431
printf("LCD: %duS is %d cycles for your AVR\n",
392432
1, (int)avr_usec_to_cycles(avr, 1));
393433
}
394-

examples/parts/hd44780.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@
3030
* + As usual, the "RW" pin is optional if you are willing to wait for the
3131
* specific number of cycles as per the datasheet (37uS between operations)
3232
* + If you decide to use the RW pin, the "busy" flag is supported and will
33-
* be automaticly cleared on the second read, to exercisee the code a bit.
34-
* + Cursor is supported, but now "display shift"
33+
* be automatically cleared on the second read, to exercise the code a bit.
34+
* + Cursor is supported, but no "display shift"
3535
* + The Character RAM is supported, but is not currently drawn.
3636
*
3737
* To interface this part, you can use the "INPUT" IRQs and hook them to the
38-
* simavr instance, if you use the RW pins or read back frim the display, you
38+
* simavr instance, if you use the RW pins or read back from the display, you
3939
* can hook the data pins /back/ to the AVR too.
4040
*
4141
* The "part" also provides various IRQs that are there to be placed in a VCD file
@@ -77,13 +77,13 @@ enum {
7777
HD44780_FLAG_C, // 1: Cursor on
7878
HD44780_FLAG_D, // 1: Set Entire Display memory (for clear)
7979
HD44780_FLAG_S, // 1: Follow display shift
80-
HD44780_FLAG_I_D, // 1: Increment, 0: Decrement
80+
HD44780_FLAG_I_D, // 1: Increment, 0: Decrement
8181

8282
/*
8383
* Internal flags, not HD44780
8484
*/
8585
HD44780_FLAG_LOWNIBBLE, // 1: 4 bits mode, write/read low nibble
86-
HD44780_FLAG_BUSY, // 1: Busy between instruction, 0: ready
86+
HD44780_FLAG_BUSY, // 1: Busy between instructions, 0: ready
8787
HD44780_FLAG_REENTRANT, // 1: Do not update pins
8888

8989
HD44780_FLAG_DIRTY, // 1: needs redisplay...
@@ -98,9 +98,9 @@ typedef struct hd44780_t
9898
int w, h; // width and height of the LCD
9999

100100
uint16_t cursor; // offset in vram
101-
uint8_t vram[80 + 64];
101+
uint8_t vram[0x80 + 0x40];
102102

103-
uint16_t pinstate; // 'actual' LCd data pins (IRQ bit field)
103+
uint16_t pinstate; // 'actual' LCD data pins (IRQ bit field)
104104
// uint16_t oldstate; /// previous pins
105105
uint8_t datapins; // composite of 4 high bits, or 8 bits
106106
uint8_t readpins;
@@ -134,4 +134,4 @@ hd44780_get_flag(
134134
return (b->flags & (1 << bit)) != 0;
135135
}
136136

137-
#endif
137+
#endif

examples/parts/hd44780_glut.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ hd44780_gl_draw(
140140
glEnd();
141141

142142
glColor3f(1.0f, 1.0f, 1.0f);
143-
const uint8_t offset[] = { 0, 0x40, 0x20, 0x60 };
143+
const uint8_t offset[] = { 0x00, 0x40, 0x00 + 20, 0x40 + 20 };
144144
for (int v = 0 ; v < b->h; v++) {
145145
glPushMatrix();
146146
for (int i = 0; i < b->w; i++) {

0 commit comments

Comments
 (0)