6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Thu May 23, 2024 6:24 am

All times are UTC




Post new topic Reply to topic  [ 32 posts ]  Go to page 1, 2, 3  Next
Author Message
 Post subject: LCD Initialisation Issue
PostPosted: Mon Sep 11, 2023 11:10 am 
Offline

Joined: Sun Sep 19, 2021 11:21 am
Posts: 23
Hi Everyone. I'm hoping someone can shed some light on an... annoyance.

I have a working breadboard SBC and my efforts have more recently been focussed on software for it rather than hardware.
It is pretty much a Ben Eater "clone" (with some personalisations) and runs at 3.6864Mhz. The 65C51 is connected to an FTDI to USB and I communicate through /dev/ttyUSB0 on my Linux box.

I have a core wozmon running with lots of additional subroutines I've added to ROM to allow my programmes to use them - my 4x20 LCD (HD44780) being one of them. The LCD runs in 4-bit mode and is attached thusly...
Code:
; Only uses PORTB
; --------------
; LCD   -> 65C22
; --------------
; DB4   ->   PB0
; DB5   ->   PB1
; DB6   ->   PB2
; DB7   ->   PB3
; RS    ->   PB4
; RW    ->   PB5
; E     ->   PB6
; FREE  ->   PB7
; --------------

At boot, part of the monitor initialisation code is to initialise the LCD module. My issue is that when I first power-up the SBC the LCD works perfectly. However, when I do a reset to the 65C02, wozmon obviously starts again but, this time, the LCD "locks". A reboot always sorts it, but a reset always locks the LCD module. When running, there is no issue with the operation of the LCD. I have a display memory buffer which I update the LCD with (whenever wozmon processes a CR) and it works a charm.

What am I overlooking?
Code:
monitor_start:
    jsr lcd_init                                          ; Initialise LCD.
    ldx #$FF                                              ; Set stack pointer to $FF.
    txs
    cld                                                   ; Clear decimal Mode.
    jsr acia_init                                         ; Initialise ACIA.


    lda #$1B                                              ; Begin with escape.
notcr:
    cmp #$08                                              ; Backspace key?
    beq backspace                                         ; Yes.
    cmp #$1B                                              ; ESC?
    beq escape                                            ; Yes.
    iny                                                   ; Advance text index.
    bpl nextchar                                          ; Auto ESC if line longer than 127.
.
.
.

Those who know wozmon will recognise most of this code.
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.

Dave


Attachments:
File comment: Image shows the LCD after power-up and then reset.
LCD screen.jpg
LCD screen.jpg [ 59.39 KiB | Viewed 6465 times ]
Top
 Profile  
Reply with quote  
PostPosted: Mon Sep 11, 2023 1:09 pm 
Offline

Joined: Fri Mar 18, 2022 6:33 pm
Posts: 449
Take a look at this page: https://web.alfredstate.edu/faculty/wei ... index.html

What you're describing sounds an awful lot like what happens when the LCD does a successful power on "internal reset" but a "soft reset" fails. In other words, take a look at your lcd_init subroutine and make sure your delays are long enough and that you're sending each command the right number of times.

Good luck!

_________________
"The key is not to let the hardware sense any fear." - Radical Brad


Top
 Profile  
Reply with quote  
PostPosted: Mon Sep 11, 2023 1:18 pm 
Offline

Joined: Sun May 13, 2018 5:49 pm
Posts: 249
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.


Attachments:
File comment: Hitachi HD44780 datasheet
HD44780.pdf [322.07 KiB]
Downloaded 84 times
Top
 Profile  
Reply with quote  
PostPosted: Mon Sep 11, 2023 3:00 pm 
Offline
User avatar

Joined: Mon Mar 06, 2023 9:26 am
Posts: 88
Location: UK
Slow initialisations are pretty much a non-issue, because under normal use you don't turn the computer on very frequently.

_________________
probably the youngest person on this forum


Top
 Profile  
Reply with quote  
PostPosted: Mon Sep 11, 2023 6:18 pm 
Offline

Joined: Sun Sep 19, 2021 11:21 am
Posts: 23
Thanks SamCoVT and Paganini - following the advice on the 4-bit initialisation flowchart from the link you posted worked! I now have an LCD that does not glitch on reset. Insight into Ben Eater's LCD initialisation not being the most robust it could be was helpful - I took it on blind faith this would be bomb-proof.

My *new* LCD initialisation code is shown below. I added code represented by the lines 45-64 and added an additional delay at line 68. My delays way exceed those minimums recommended in the article.

allisonlastname -> Like you say, the additional time taken in starting/restarting the LCD is imperceptible. Certainly a welcome trade-off for having a "behaving" LCD.
Thanks for your input, everyone :D

Code:
                               29: lcd_init:
                               30:   
                               31:   ; =============================================================
                               32:   ; Setup the 65C22 ports & pins.
                               33:   ; =============================================================
                               34:   
01:F12B A9FF                   35:   lda #%11111111              ; Set all pins on port B to output.
01:F12D 8D0260                 36:   sta DDRB
                               37:
                               38:   ; =============================================================
                               39:   ; LCD setup and test printing.
                               40:   ; =============================================================
                               41:   ;
                               42:   ; See https://web.alfredstate.edu/faculty/weimandn/lcd/lcd_initialization/lcd_initialization_index.html
                               43:   ;
                               44:   
01:F130 2085F2                 45:   jsr delay_25ms                                  ; Wait 100ms.
01:F133 2085F2                 46:   jsr delay_25ms
01:F136 2085F2                 47:   jsr delay_25ms
01:F139 2085F2                 48:   jsr delay_25ms
                               49:   
01:F13C A903                   50:   lda #%00000011                                  ; Special case of "Function Set".
01:F13E 8D0060                 51:   sta PORTB
01:F141 2085F2                 52:   jsr delay_25ms                                  ; wait 25ms.
                               53:
01:F144 A903                   54:   lda #%00000011                                  ; Do all this again...
01:F146 8D0060                 55:   sta PORTB
01:F149 2085F2                 56:   jsr delay_25ms
                               57:
01:F14C A903                   58:   lda #%00000011                                  ; Third time's a charm!
01:F14E 8D0060                 59:   sta PORTB
01:F151 2085F2                 60:   jsr delay_25ms
                               61:
01:F154 A902                   62:   lda #%00000010                                  ; Set 4-bit mode.
01:F156 8D0060                 63:   sta PORTB
01:F159 2085F2                 64:   jsr delay_25ms
                               65:
01:F15C A902                   66:   lda #%00000010                                  ; Set 4-bit mode.
01:F15E 8D0060                 67:   sta PORTB
01:F161 2085F2                 68:   jsr delay_25ms
                               69:
                               70:
01:F164 0940                   71:   ora #E
01:F166 8D0060                 72:   sta PORTB
01:F169 290F                   73:   and #%00001111
01:F16B 8D0060                 74:   sta PORTB
                               75:
01:F16E A928                   76:   lda #%00101000                                  ; Set 4-bit mode; 2-line display; 5x8 font.
01:F170 20B5F1                 77:   jsr lcd_instruction                   
                               78:
01:F173 A90C                   79:   lda #%00001100                                  ; Display on; cursor off; blink off.
01:F175 20B5F1                 80:   jsr lcd_instruction                   
                               81:
01:F178 A906                   82:   lda #%00000110                                  ; Increment and shift cursor; don't shift display.
01:F17A 20B5F1                 83:   jsr lcd_instruction                   
                               84:
                               85: lcd_clear:                   
                               86:
01:F17D A901                   87:   lda #%00000001                                  ; Clear display.
01:F17F 20B5F1                 88:   jsr lcd_instruction
                               89:
01:F182 60                     90:   rts


Top
 Profile  
Reply with quote  
PostPosted: Mon Sep 11, 2023 7:50 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8442
Location: Southern California
Yep, you have to write the function set multiple times in the initialization, something that nearly everyone misses, but you got it.  I show this in my sample code, in multiple forms, at http://wilsonminesco.com/6502primer/LCDcode.asm .  We had the problem at work even using the 8-bit interface, until an applications engineer sent us this information.  Never had a problem after that, either in 8-bit or 4-bit mode.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Mon Sep 11, 2023 11:58 pm 
Offline

Joined: Fri Mar 18, 2022 6:33 pm
Posts: 449
DRG wrote:
Thanks SamCoVT and Paganini - following the advice on the 4-bit initialisation flowchart from the link you posted worked! I now have an LCD that does not glitch on reset.
Great! Glad it's working!

Quote:
Insight into Ben Eater's LCD initialisation not being the most robust it could be was helpful - I took it on blind faith this would be bomb-proof.
Don't do that. :D This is sort of a feature of Ben's teaching style. In the videos about the LCD he only uses it in 8-bit mode. On his website he gives a schematic and some VERRRY sketchy code for 4-bit mode. You are supposed to figure it out for yourself. Discovering the problem, creating this thread, and subsequently figuring things out means you are on exactly the right track.

_________________
"The key is not to let the hardware sense any fear." - Radical Brad


Top
 Profile  
Reply with quote  
PostPosted: Tue Sep 12, 2023 1:17 pm 
Offline

Joined: Sun May 13, 2018 5:49 pm
Posts: 249
One thing I see missing is that you need to run the enable line high and then low for each %00000011 you want to send. That's the bit of code that uses ORA to turn on the "E" bit and then later uses an AND to turn off all of the control bits (E was the only one turned on).

Because you are technically sending the 8-bit command to change to 8-bit mode at the beginning, you can't use your lcd_instruction routine because that tries to send the command as two nybbles.

The change might look like:
Code:
 lcd_init:
   
   ; =============================================================
   ; Setup the 65C22 ports & pins.
   ; =============================================================
   
   lda #%11111111              ; Set all pins on port B to output.
   sta DDRB
 
   ; =============================================================
   ; LCD setup and test printing.
   ; =============================================================
   ;
   ; See https://web.alfredstate.edu/faculty/weimandn/lcd/lcd_initialization/lcd_initialization_index.html
   ;
   
   jsr delay_25ms                                  ; Wait 100ms.
   jsr delay_25ms
   jsr delay_25ms
   jsr delay_25ms
   
   lda #%00000011                                  ; Special case of "Function Set".
   sta PORTB
   ora #E
   sta PORTB
   and #%00001111
   sta PORTB
   jsr delay_25ms                                  ; wait 25ms.
 
   lda #%00000011                                  ; Do all this again...
   sta PORTB
   ora #E
   sta PORTB
   and #%00001111
   sta PORTB
   jsr delay_25ms
 
   lda #%00000011                                  ; Third time's a charm!
   sta PORTB
   ora #E
   sta PORTB
   and #%00001111
   sta PORTB
   jsr delay_25ms
 
   lda #%00000010                                  ; Set 4-bit mode (as an 8-bit command)
   sta PORTB
   ora #E
   sta PORTB
   and #%00001111
   sta PORTB
   jsr delay_25ms
 
   ; At this point you can send 4 bit commands and lcd_instruction should work properly.
 
   lda #%00101000                                  ; Set 4-bit mode; 2-line display; 5x8 font.
   jsr lcd_instruction                   
 
   lda #%00001100                                  ; Display on; cursor off; blink off.
   jsr lcd_instruction                   
 
   lda #%00000110                                  ; Increment and shift cursor; don't shift display.
   jsr lcd_instruction                   
 
 lcd_clear:                   
 
   lda #%00000001                                  ; Clear display.
   jsr lcd_instruction
 
   rts


Top
 Profile  
Reply with quote  
PostPosted: Thu Sep 14, 2023 11:39 am 
Offline

Joined: Sun Jul 11, 2021 9:12 am
Posts: 137
DRG wrote:
Insight into Ben Eater's LCD initialisation not being the most robust it could be was helpful - I took it on blind faith this would be bomb-proof.


While Ben does a fantastic job overall and has even been inspiration for some of my own projects, some short cuts are taken now and then, and other times some information is outright incorrect. Not having a go at Ben here, he is a huge credit to scene.


Top
 Profile  
Reply with quote  
PostPosted: Sat Nov 04, 2023 9:27 am 
Offline

Joined: Tue Oct 31, 2023 10:34 am
Posts: 15
Location: Germany
I have read Wilson´s excellent article on Interrupts and understand most of it I think. In the above discussion I am not able to see how the 25ms delay is achieved. I am also following the alfredstate procedure. I am trying to use the T1 timer of the 65c22 for the delay. One-shot mode seems to be the right way to go as we need to run down the clock for each delay period and so ACR is set accordingly. My understanding is that IFR bit 6 is set when the clock runs down. IER is not set as there is no interrupt handler programmed, if I understand this correctly. So when I comment out jsr lcd_init the program works perfectly and prints a message to the LCD but as with others only on powerup not on subsequent resets. If I activate the LCD initiation subroutine, the 6502 goes on vacation, but never sends picture postcards. 8 bit operation of the LCD. 4 bit drove me even more nuts. Hope someone can spot the error.

Code:

; This follows alfredstate.edu lcd initialization

PORTB = $6000
PORTA = $6001
DDRB = $6002      ; Data direction Port B
DDRA = $6003
T1CL = $6004      ; 65c22 Timer 1 register low
T1CH = $6005
T1LL = $6006
T1LH = $6007
ACR = $600B       ; Auxiliary control register of 65c22
IFR = $600D       ; Interrupt flag register of 65c22

E  = %10000000
RW = %01000000
RS = %00100000

  .org $8000

reset:
  ldx #$ff
  txs

  lda #%11111111 ; Set all pins on port B to output
  sta DDRB
  lda #%11100000 ; Set top 3 pins on port A to output
  sta DDRA
  lda #0
  sta ACR        ; Sets Auxiliary control register to 0 which is one shot mode.
 
  ; Initialise LCD by instruction
 
  jsr lcd_init

  ; Set up LCD

  lda #%00111000 ; Set 8-bit mode; 2-line display; 5x8 font
  jsr lcd_instruction
  lda #%00001110 ; Display on; cursor on; blink off
  jsr lcd_instruction
  lda #%00000110 ; Increment and shift cursor; don't shift display
  jsr lcd_instruction
  lda #%00000001 ; Clear display
  jsr lcd_instruction
  lda #%10000000 ; Set DDRAM to 0 (cursor position to left)
  jsr lcd_instruction
 
  ; Print message to show completion

  ldx #0
print:
  lda message,x
  beq loop
  jsr print_char
  inx
  jmp print

message:
  .asciiz "LCD Ready"

loop:
  jmp loop         ; Infinite loop after printing message

lcd_init:
  lda #$50        ; Initial wait of 100 ms (C350 in hex is 50000 cycles - 50ms at 1Mhz) (Step 1)
  sta T1CL
  lda #$C3
  sta T1CH
  jsr init_delay
  lda #$50        ; Repeat above to achieve 100ms
  sta T1CL
  lda #$C3
  sta T1CH
  jsr init_delay
  lda #%00110000  ; Special function set  (Step 2)
  jsr lcd_instruction_1 ; Without busy flag
  lda #$68        ; Wait 4.2 ms (Hex 1068)
  sta T1CL
  lda #$10
  sta T1CH
  jsr init_delay
  lda #%00110000  ; Special function set   (Step 3)
  jsr lcd_instruction_1 ; Without busy flag
  lda #$6E        ; Wait 110 Microseconds (Hex 6E)
  sta T1CL
  lda #$00
  sta T1CH
  jsr init_delay
  lda #%00110000  ; Special function set   (Step 4)
  jsr lcd_instruction_1 ; Without busy flag
  lda #$6E        ; Wait 110 Microseconds (Hex 6E)
  sta T1CL
  lda #$00
  sta T1CH
  jsr init_delay
  rts             ; End of initialisation

init_delay:       ; Loops until overflow flag is set
  bit IFR         ; Checks status of overflow bit 6
  bvc init_delay  ; Back to start if overflow flag is clear
  lda T1CL        ; Clears flag in IFR
  rts

lcd_instruction_1:  ; Used for initiating the LCD where busy flag can't be checked
  sta PORTB
  lda #0         ; Clear RS/RW/E bits
  sta PORTA
  lda #E         ; Set E bit to send instruction
  sta PORTA
  lda #0         ; Clear RS/RW/E bits
  sta PORTA
  rts




Last edited by Cookie13! on Sun Nov 05, 2023 12:02 pm, edited 13 times in total.

Top
 Profile  
Reply with quote  
PostPosted: Sat Nov 04, 2023 3:50 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 9:02 pm
Posts: 1687
Location: Sacramento, CA
Cookie13! wrote:
Somehow when i post the code format is lost


Use the CODE block to keep your formatting.

Code:
 ; Initialise LCD by instruction
 
  jsr lcd_init

  ; Set up LCD

  lda #%00111000 ; Set 8-bit mode; 2-line display; 5x8 font
  jsr lcd_instruction
  lda #%00001110 ; Display on; cursor on; blink off
  jsr lcd_instruction
  lda #%00000110 ; Increment and shift cursor; don't shift display
  jsr lcd_instruction
  lda #%00000001 ; Clear display
  jsr lcd_instruction
  lda #%10000000 ; Set DDRAM to 0 (cursor position to left)
  jsr lcd_instruction
 
  ; Print message to show completion

  ldx #0
print:
  lda message,x
  beq loop
  jsr print_char
  inx
  jmp print

message:
  .asciiz "LCD Ready"

loop:
  jmp loop         ; Infinite loop after printing message

lcd_init:
  lda #$50        ; Initial wait of 100 ms (C350 in hex is 50000 cycles - 50ms at 1Mhz) (Step 1)
  sta T1CL
  lda #$C3
  sta T1CH
  jsr init_delay
  lda #$50        ; Repeat above to achieve 100ms
  sta T1CL
  lda #$C3
  sta T1CH
  jsr init_delay
  lda #%00110000  ; Special function set  (Step 2)
  jsr lcd_instruction_1 ; Without busy flag
  lda #$68        ; Wait 4.2 ms (Hex 1068)
  sta T1CL
  lda #$10
  sta T1CH
  jsr init_delay
  lda #%00110000  ; Special function set   (Step 3)
  jsr lcd_instruction_1 ; Without busy flag
  lda #$6E        ; Wait 110 Microseconds (Hex 6E)
  sta T1CL
  lda #$00
  sta T1CH
  jsr init_delay
  lda #%00110000  ; Special function set   (Step 4)
  jsr lcd_instruction_1 ; Without busy flag
  lda #$6E        ; Wait 110 Microseconds (Hex 6E)
  sta T1CL
  lda #$00
  sta T1CH
  jsr init_delay
  rts             ; End of initialisation

init_delay:       ; Loops until overflow flag is set
  bit IFR         ; Checks status of overflow bit 6
  bvc init_delay  ; Back to start if overflow flag is clear
  lda T1CL        ; Clears flag in IFR
  rts

lcd_instruction_1:  ; Used for initiating the LCD where busy flag can't be checked
  sta PORTB
  lda #0         ; Clear RS/RW/E bits
  sta PORTA
  lda #E         ; Set E bit to send instruction
  sta PORTA
  lda #0         ; Clear RS/RW/E bits
  sta PORTA
  rts

_________________
Please visit my website -> https://sbc.rictor.org/


Top
 Profile  
Reply with quote  
PostPosted: Sun Nov 05, 2023 11:42 am 
Offline

Joined: Tue Oct 31, 2023 10:34 am
Posts: 15
Location: Germany
8BIT wrote:

Quote:

Use the CODE block to keep your formatting.



Thanks for the tip. It is the first time I'm using the forum and I'm obviously still incompetent. I finally got it to work, but not sure why. I copied and pasted from the code file anew instead of cutting and pasting in the original message.


Top
 Profile  
Reply with quote  
PostPosted: Sun Nov 05, 2023 3:44 pm 
Offline

Joined: Tue Oct 31, 2023 10:34 am
Posts: 15
Location: Germany
Paganini wrote:

I followed this but still struggle. See my post. BTW i sent a private message to someone but it still shows in my outbox. Not sure how the functionality of this site works.


Top
 Profile  
Reply with quote  
PostPosted: Sun Nov 05, 2023 3:51 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 9:02 pm
Posts: 1687
Location: Sacramento, CA
Cookie13! wrote:
Thanks for the tip. It is the first time I'm using the forum and I'm obviously still incompetent...


I wouldn't say incompetent, we all had to learn the forum's toolboxes. You obviously figured out how to post attachments, which others sometimes have trouble with. The CODE block is not as intuitive as you'd think.

So, welcome and best wishes with your projects!

Daryl

_________________
Please visit my website -> https://sbc.rictor.org/


Top
 Profile  
Reply with quote  
PostPosted: Sun Nov 05, 2023 5:15 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10802
Location: England
(Private messages stay in the outbox until the recipient reads them)


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 32 posts ]  Go to page 1, 2, 3  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: