SIMPLER GLCD CODING Dear EPE, Thank you for running your PIC Tutorial V2, it has lots more useful information and is well worth reading over and over. Under the I2C section I notice you haven't used this format on PICs other than the 16F87x. In the 16F84 to glcd routine I sent you and which you put on your ftp site, there is an I2C routine that should run on most PICs, but may need tidying. Also, a long while back, I read John Becker's Using Graphics L.C.D.s and experimented with another glcd device. I also sent John an ASM listing for running a graphics l.c.d. (glcd) via shift registers and said I would apply my findings to a normal glcd hook-up. I have found that status checks are not necessary on glcds and simple timing delays work even at a 20MHz PIC clock. This means a large-ish saving in code space and eases the learning curve a bit. Part of getting to grips with glcds was learning more about "normal" text l.c.d.s. Using a shift register interface, I ended up with a routine that will setup an alphanumeric l.c.d., with timing, s/r, command, character and number sub-routines, in 35 PIC commands. This too will run at 20MHz. As it only uses any three I/O pins (two of which could be used as inputs when no l.c.d. work is in progress) you might find it useful in prog development when I/O pins are in short supply. I include here my "timing" routine for glcds based around John's SENDCMD subroutine. I had a little trouble understanding the original SENDCMD and particularly OUTDATA subs, but then I realised that any change to D0-D7, CD, RD and WR had no effect until CE is clocked low. This simplistic view was applied to the following subs in which CE is the key. Finding the timing was simply a matter of counting passes through BTFSC in the CHECK subs in his GEPE456 prog. The T6963 chip (as in John's glcd example) is a lot faster than the HD4470 used in some other l.c.d.s and approximately 8us delay is used with a built in safety margin and only applied to command data. PICs don't appear to run fast enough to "overload" on auto write data input. Interestingly, the first call to PAUSIT isn't needed! I didn't even change INTCON settings. I appreciate John's efforts in getting glcds to work, especially with the limited data available, and understand any reluctance to change tack. It gave me something to tune ( I don't make engines, I rebuild, modify and tune them ). Here's my code for the 20MHz glcd version, which will also work with any slower crystal rate. Change CLKCNT BSF values if time is at a premium Replace the existing SENDCMD and OUTDATA subroutines with the following Also rem out all calls for CHECKS 3, 6, 8, and . replace all calls to AUTOWRITE with CALL OUTDATA. SENDCMD: movwf PORTD ; place word on D0-D7 bsf CLKCNT,5 ; value is nearest Xtal whole number * 1.5 SC: decfsz CLKCNT,f ; rough timer to give over 8us goto SC movlw %00011010 movwf PORTC ; set CE, WR low goto DWELL ; wait for port to stabilise OUTDATA: movwf PORTD ; place word on D0-D7 movlw %00010010 ; 1 0 0 1 0 movwf PORTC ; set CD, CE, WR low DWELL: bsf CLKCNT,3 ; use bsf temp,3 above 15MHz, 2 above 10MHz, ; 1 above 5MHZ & 0 under 5MHz TIME: decfsz CLKCNT,f ; rough timer to give about 2us goto TIME bsf PORTC,2 ; data & control line words "clocked in" return Graham Card, via email Interesting that you've got round the check situation - well done Graham. I have put your above code into PIC Tricks on our ftp site, together with the longer example program you sent, and its additional notes. Of course, using a timing delay will be familiar to anyone using alphanumeric displays as the this is the only technique is use with these devices in EPE projects. Regarding PAUSIT, have you checked that the glcd will initialise immediately power is switched on, even with a power supply that have as slow rise-time for its final regulated voltage? I haven't yet had the need for I2C on an F84 but I'll keep your previous code in mind should I do so, thanks for it. Continue enjoying your PICing! *********************** ADDITIONAL INFORMATION FROM GRAHAM NOT PUBLISHED IN READOUT John, as you are posting my glcd timing code on the FTP site perhaps you might include the following notes on how I arrived at the end result. Also I used CLKCNT as I didn't need it for anything else. It might mess up a clock routine if anyone should try it. Have added TEMP instead. I have included a compressed setup routine, initialisation routines are done on run-through, all others called as required. The notes are guesswork only. All I really know is that it works. Toshiba's data sheet gives a 200ns timing for data, but warns of hardware lockout if MSB = 0. (MSBit or MSByte?). A finite time should be taken for such lockout & worst case was approx 5us. Have allowed approx 8us but on commands only. 8 bit data entry (autowrite) is dependant on risetime on CE pin. PIC risetime seems a little slow, needing 2us to clock CE high (or to allow glcd time to swallow data). Given 200ns timing I can't see a PIC overrunning data entry on autowrite. Toshiba data sheet also gives a 2us "bootup" timing, so by the time the PIC has woken up & run through basic settings, glcd is ready for action. Initial "pausit" routine is not needed. Complete setup & user routines. Call SETUP to use, will return as normal 20MHz version, will work with any slower xtal. Change TEMP bsf values if time is at a premium. Replace these subs & rem out all calls for CHECKS 3,6 & 8. Replace all calls for AUTOWRITE with "call OUTDATA". Remove AWRON & AWROFF Equates. Replace all "movlw AWRON call SENDCMD" & "movlw AWROFF call SENDCMD" with "call AWRON & call AWROFF" respectively. BITWRITE: movwf BITVAL call SCREENADR ; set screen write address movf BITVAL,W call SENDCMD ; send command return ; ONEWRITE: movwf ATTRIB ; temp store val brought in on W call SCREENADR ; set screen write address - vals preset ; at call call AWRON ; AUTO WRITE ON movf ATTRIB,W call OUTDATA call AWROFF ; AUTO WRITE OFF return CMDADR: movf ADRLSB,W ; WRITE DATA D1 call OUTDATA ; movf ADRMSB,W ; WRITE DATA D2 call OUTDATA ; retlw $22 ; offset command (setup only) SCREENADR: call CMDADR ; movlw ADPSET ; SET ADDRESS POINTER call SENDCMD ; send command return ; TEXTHOME: clrf ADRMSB ; TEXT HOME ADDRESS $0000 clrf ADRLSB ; call CMDADR ; send command address movlw TXHOME ; call SENDCMD ; send command return GRAPHHOME: movlw $02 ; GRAPHIC HOME ADDRESS $0200 movwf ADRMSB clrf ADRLSB call CMDADR ; send command address movlw GRHOME ; call SENDCMD ; send command return TEXTAREA: clrf ADRMSB ; movf COLUMN,W ; columns length movwf ADRLSB ; call CMDADR ; send command address movlw TXAREA ; text area command call SENDCMD ; send command return GRAPHAREA: clrf ADRMSB ; movf COLUMN,W ; columns length movwf ADRLSB ; call CMDADR ; send command address movlw GRAREA ; graphic area command call SENDCMD ; send command retlw %10000000 ; set mode value (SETUP routine only) CSRADR: call CMDADR ; send command address movlw CSRPOS ; cursor position command call SENDCMD ; send command return SETUP: call TEXTHOME ; SET TEXT HOME ADDRESS call GRAPHHOME ; SET GRAPHIC HOME ADDRESS call TEXTAREA ; SET TEXT AREA call GRAPHAREA ; SET GRAPHIC AREA call SENDCMD ; SET MODE (INT/EXT/AND-OR-XOR etc) ; see grapharea retlw movlw 2 ; SET OFFSET (see EPE text) ADRMSB cleared ; earlier (SETUP routine only) movwf ADRLSB ; call CMDADR ; send command address (return with OFFSET ; ($22) in W) (SETUP routine only) call SENDCMD ; send command movlw %10011111 ; display mode setting (SETUP routine only) call SENDCMD ; DISPLAY MODE (text, graph on/off etc) call CLRTXT ; WRITE TEXT BLANK CODE $0000 call CLRGRAPH ; WRITE GRAPH BLANK CODE $0200, then default ; to CLRCG CLRCG: movlw $14 ; * CLEAR CG AREA * last op of setup goto CG CLRGRAPH: movlw $02 ; ** CLEAR GRAPH AREA ($0200) ** CG: movwf ADRMSB ; clrf ADRLSB ; call SCREENADR ; set screen write address call AWRON ; AUTO WRITE ON movlw 64 ; number of lines movwf LOOPC goto CLR CLRTXT: clrf ADRMSB ; clear all text screen lines, length as set clrf ADRLSB ; call SCREENADR ; set screen write address call AWRON ; AUTO WRITE ON movlw 8 ; number of lines movwf LOOPC CLR: movf COLUMN,W ; column length movwf LOOPB ; CLR1: movlw 0 ; write 0 call OUTDATA ; decfsz LOOPB,F ; goto CLR1 ; decfsz LOOPC,F ; goto CLR ; call AWROFF ; AUTO WRITE OFF return SETCG: movlw $14 ; CG RAM start address 1400H movwf ADRMSB ; clrf ADRLSB ; call SCREENADR ; set screen write address return SETATTR: call SCREENADR ; set screen write address - vals preset ; at call call AWRON ; AUTO WRITE ON SETAT: movf ATTRIB,W ; val to be sent preset at call call OUTDATA ; decfsz LOOPC,F ; LOOPC val specified by calling routine goto SETAT ; call AWROFF ; AUTO WRITE OFF return AWRON: movlw 176 ; AUTO WRITE ON goto SENDCMD ; send command AWROFF: movlw 178 ; AUTO RESET put here to default to SENDCMD SENDCMD: movwf PORTD ; place word on D0-D7 bsf TEMP,2 ; value is nearest Xtal whole number * 1.5 SC: decfsz TEMP,f ; rough timer to give over 8 u/s goto SC movlw %00011010 movwf PORTC ; set CE, WR low goto DWELL ; wait for port to stabilise OUTDATA: movwf PORTD ; place word on D0-D7 movlw %00010010 ; 1 0 0 1 0 movwf PORTC ; set CD, CE, WR low DWELL: bsf TEMP,0 ; use bsf temp,3 above 15 MHz ,2 ; above 10MHz ,1 above 5MHZ & ,0 under 5 MHz TIME: decfsz TEMP,f ; rough timer to give about 2 u/s goto TIME bsf PORTC,2 ; data & control line words "clocked in" return