Skip to content

Commit

Permalink
Merge pull request #406 from akosthekiss/fix-hd44780-memory
Browse files Browse the repository at this point in the history
Fixes to HD44780
  • Loading branch information
buserror committed Apr 11, 2022
2 parents 4d1750b + 03a01c7 commit 7c4afd1
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 28 deletions.
77 changes: 58 additions & 19 deletions examples/parts/hd44780.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -55,15 +55,17 @@ static void
_hd44780_clear_screen(
hd44780_t *b)
{
memset(b->vram, ' ', 80);
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);
}



/*
* 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
*/
Expand All @@ -83,16 +85,45 @@ static void
hd44780_kick_cursor(
hd44780_t *b)
{
if (hd44780_get_flag(b, HD44780_FLAG_I_D)) {
if (b->cursor < 79)
b->cursor++;
else if (b->cursor < 80+64-1)
if (hd44780_get_flag(b, HD44780_FLAG_I_D)) { // incrementing
if (b->cursor < 0x80) { // cursor in DDRAM
b->cursor++;
} else {
if (b->cursor < 80 && b->cursor)
b->cursor--;
else if (b->cursor > 80)
b->cursor--;
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;
else
b->cursor++;
}
} else { // decrementing
if (b->cursor < 0x80) { // cursor in DDRAM
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;
else
b->cursor--;
}
hd44780_set_flag(b, HD44780_FLAG_DIRTY, 1);
avr_raise_irq(b->irq + IRQ_HD44780_ADDR, b->cursor);
}
Expand Down Expand Up @@ -125,21 +156,30 @@ 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;
else top--;
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
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
b->cursor = 64 + (b->datapins & 0x3f);
// Set CGRAM address
case 6: // 0 1 ACG ACG ACG ACG ACG ACG
b->cursor = 0x80 + (b->datapins & 0x3f);
break;
// Function set
case 5: { // 0 0 1 DL N F x x
Expand Down Expand Up @@ -246,7 +286,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;

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

16 changes: 8 additions & 8 deletions examples/parts/hd44780.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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...
Expand All @@ -98,9 +98,9 @@ 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 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;
Expand Down Expand Up @@ -134,4 +134,4 @@ hd44780_get_flag(
return (b->flags & (1 << bit)) != 0;
}

#endif
#endif
2 changes: 1 addition & 1 deletion examples/parts/hd44780_glut.c
Original file line number Diff line number Diff line change
Expand Up @@ -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++) {
Expand Down

0 comments on commit 7c4afd1

Please sign in to comment.