I'm building a breadboard Z80-based computer. As now, I have the CPU hooked up to an EEPROM and an I/O device (an HD44780 character display) with appropriate decoding logic.
The ROM chip starts at address 0x0000 while the I/O device exposes two registers at addresses 0x00 and 0x01 when the IORQ pin is active (low).
I wrote the following program:
;HD44780 LCD test procedure LCD_INSTR_REG: EQU %00000000 LCD_DATA_REG: EQU %00000001 ;Reset procedure ld a,%00111000 out (LCD_INSTR_REG),a ld a,%00001000 out (LCD_INSTR_REG),a ld a,%00000001 out (LCD_INSTR_REG),a ;Init procedure ld a,%00111000 out (LCD_INSTR_REG),a ld a,%00001110 out (LCD_INSTR_REG),a ;Write characters to display ld a,%01000100 out (LCD_DATA_REG),a ld a,%01100001 out (LCD_DATA_REG),a ld a,%01101110 out (LCD_DATA_REG),a ld a,%01101001 out (LCD_DATA_REG),a ld a,%01100101 out (LCD_DATA_REG),a ld a,%01101100 out (LCD_DATA_REG),a ld a,%01100101 out (LCD_DATA_REG),a ld a,%00100001 out (LCD_DATA_REG),a halt
That, once compiled with GNU z80asm, translates to the following code:
You can see several 3E
instructions that load an immediate value to register A, interleaved by D3
instructions that load to I/O register 00 (and then 01) the value present in register A. The last instruction (76
) is the halt instruction.
The execution of the code causes the following bytes to appear on data bus (picked up with an Arduino used as a poor man's logic analyzer):
HD44780 debugger DATA BUS HEX RS 00000000 0x00 I 00000000 0x00 I 00000000 0x00 I 00000000 0x00 I 00000000 0x00 I 00000000 0x00 D 00000000 0x00 D 00000000 0x00 D 00000000 0x00 D 00000000 0x00 D 00000000 0x00 D 00000000 0x00 D 00000000 0x00 D
Every line is the bus state at the IORQ descending edge (but I obtain the same result if I trigger my code on the rising edge).
You can see, from left to right: the value of the single data bus bits, the same value in hex, the value of A0, that select the I/O device register (instruction is LOW and data is HIGH).
As you can see, while the correct addresses are set, the CPU is writing all zeroes to the data bus. Did I misunderstand the way the OUT
instruction works? Otherwise, what could be the problem in my code?
Update
I decided to accept the answer from Spektre as it is complete and argumentative. By the way, note that in my case the problem was not due to timings, but two swapped lines in the address bus (so the CPU was reading in a whole different memory address, probably reading NOPs or garbage). My CPU was running at 140 Hz and I'd like to point out that, after fixing the addr bus pins, the LCD screen worked perfectly up to 14 kHz without needing to check the BUSY bit.
Over a certain frequency, BTW, adding delays as proposed by Spektre was not enough, as the signal was not kept on the data bus long enough for the LCD to read it. As far as I can understand, the only way to make the LCD work at frequencies in the MHz range is to use some kind of latched buffers/transceivers to decouple the LCD EN frequency from the CPU frequency.