DRG wrote:
It seems initialising an already initialised LCD creates the problem. Could this be a 4-bit operation problem? Is there a software solution, a hardware fix?
Any pointers of what the issue could be or where to look (hardware or software) would be appreciated.
Hello Dave,
There are some subtle quirks when using HD44780 or equivalent based LCD modules. This likely can be resolved with a software change.
One of the things to consider is that, when in 4-bit mode, it is possible to be
mid-write where the LCD thinks a nybble (half of the byte) might be sent already. During a reset condition, if the 6522 (I'm assuming you used a 6522 because of your reference to PB bits) is also reset, then the RW and E lines are left floating until the CPU starts running again and your code makes them outputs again. Even your initialization routine might accidentally enable the LCD for a split second while you set up PORTB, causing a half-write. To get around this, it is recommended to first initialize to 8-bit mode (which you can do with only the 4 bits you have connected) and then re-initialize to 4-bit mode.
Can you post your code for
lcd_init? Have you referenced Hitachi's software initialization (called "Initialization by Instruction" in the datasheet) in Figure 24 (for 4-bit mode) on page 46 (attached for your reference).
Edit: It looks like Paganini beat me to it. His link looks good, but make sure you scroll down to the 4-bit section - it's near the bottom. I also looked up Ben Eater's LCD init routine as found in keyboard.s on his web site. I don't want to be unkind, so I don't have much to say about it, other than that it is exceptionally short. It's sad that he missed the software initialization routine that is given right in the datasheet that generally works reliably every time. You are not the only one to use his software and run into this issue (LCD messes up on reset).
Also, there are several delays given in that routine. Note that you need to wait
at least the amount of time given. I make this easy on myself by writing only a 100ms delay and using that one delay routine everywhere. It's a bit slower to initialize, but still under a second.