Twisty
Newbie level 4
Interfacing HD77480 to PIC16f648A-I/P
Please help. I appreciate this is a very newbie post, however I have spent a long time trying to fix this myself and as I am now at the end of my tether and really would appreciate some guidance.
I've pasted the code below and would be thankful for any pointers on I would go about debugging my problem.
I am trying to interface a Displaytech 204A LCD (20x4, apparantly HD77480 compatable) with a PIC16f648A-I/P.
I'm running 8 bit mode with data lines connected to PortB. E to RA3, RW to RA5, RS to RA4
I'm using MPLAB v8.92, compiling with MPASM.
I am programming with an OLIMEX-PIC-MCP-USB (i.e. Picstart+) in the ZIF socket.
I am managing to compile code and program it to the chip.
I am getting some 'Register in operand not in bank 0' warnings, which just seem to be something the compiler spits out when it sees operations outside of bank 0, or maybe it is more significant than that.
Right now I'd be very happy to just initialise the display but I am getting nothing
I also installed XC8 and adapted/compiled some other C code, but I've got the same result. It seems that most C code is for the 18F so it looks like I should stick with assembly for the 16F?
Please help. I appreciate this is a very newbie post, however I have spent a long time trying to fix this myself and as I am now at the end of my tether and really would appreciate some guidance.
I've pasted the code below and would be thankful for any pointers on I would go about debugging my problem.
I am trying to interface a Displaytech 204A LCD (20x4, apparantly HD77480 compatable) with a PIC16f648A-I/P.
I'm running 8 bit mode with data lines connected to PortB. E to RA3, RW to RA5, RS to RA4
I'm using MPLAB v8.92, compiling with MPASM.
I am programming with an OLIMEX-PIC-MCP-USB (i.e. Picstart+) in the ZIF socket.
I am managing to compile code and program it to the chip.
I am getting some 'Register in operand not in bank 0' warnings, which just seem to be something the compiler spits out when it sees operations outside of bank 0, or maybe it is more significant than that.
Right now I'd be very happy to just initialise the display but I am getting nothing
I also installed XC8 and adapted/compiled some other C code, but I've got the same result. It seems that most C code is for the 18F so it looks like I should stick with assembly for the 16F?
Code:
;*****************************************************************************
; This program should interface to a Hitachi HD77480-based LC-Display
; Currently a 4 line * 20 characters display module.
;
; This program should assemble for an 8-bit data interface.
; See AN587 for 4-bit and 8-bit interfaces.
;
; Program LCD.ASM
;
; Original Author Peter Ouwehand Last update 96-01-12
;*Edited for a PIC16F648A and LCD control lines pinout
;*****************************************************************************
;* LIST P=16C84, F=INHX8M
;* __CONFIG _CP_OFF & _WDT_OFF & _XT_OSC
;* include <c:\pic\asm\p16c84.inc>
list p=16f648A ; list directive to define processor
#include <p16F648A.inc> ; processor specific variable definitions
__CONFIG _CP_OFF & _CPD_OFF & _LVP_OFF & _BOREN_ON & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTOSC_OSC_NOCLKOUT
; errorlevel -302 ; suppress message 302 from list file ; commented out at the moment
;*****************************************************************************
; Fosc = 4MHz
; Cycle_time = 1/Fosc / 4
; = 1/(4*10^6) / 4
; = 1uSec
;*****************************************************************************
;*****************************************************************************
; Equates, I/O, vars
;*****************************************************************************
RESET_V EQU 0x0000 ; Address of RESET Vector
ISR_V EQU 0x0004 ; Address of Interrupt Vector
OSC_FREQ EQU D'4000000' ; Oscillator Frequency is 4 MHz
LCD_DATA EQU PORTB ; LCD data lines interface
LCD_DATA_TRIS EQU TRISB
LCD_CTRL EQU PORTA ; LCD control lines interface
LCD_LINE0 EQU 0x000
LCD_LINE1 EQU 0x040
LCD_LINE2 EQU 0x014
LCD_LINE3 EQU 0x054
; PORTA bits
LCD_E EQU 3 ;* LCD Enable control line connected to RA3
LCD_RW EQU 5 ;* LCD Read/Write control line connected to RA5
LCD_RS EQU 4 ;* LCD Register-Select control line connected to RA4
; PORTB bits
DB7 EQU 7 ; LCD dataline 7 (MSB)
DB6 EQU 6 ; LCD dataline 6
DB5 EQU 5 ; LCD dataline 5
DB4 EQU 4 ; LCD dataline 4
DB3 EQU 3 ; LCD dataline 3
DB2 EQU 2 ; LCD dataline 2
DB1 EQU 1 ; LCD dataline 1
DB0 EQU 0 ; LCD dataline 0 (LSB)
; misc.
LCD_TEMP EQU 0x020 ; LCD subroutines internal use
TABLE_INDEX EQU 0x021 ; Index to table strings
COUNT EQU 0x022 ; A counter
DELAY equ 0x023 ; Used in DELAYxxx routines
X_DELAY equ 0x024 ; Used in X_DELAYxxx routines
;*****************************************************************************
; Program start
;*****************************************************************************
ORG RESET_V ; RESET vector location
RESET GOTO START
;*****************************************************************************
; This is the Periperal Interrupt routine. Should NOT get here
;*****************************************************************************
ORG ISR_V ; Interrupt vector location
INTERRUPT BCF STATUS, RP0 ; Select bank 0
GOTO INTERRUPT
;*****************************************************************************
; Initialize processor registers
;*****************************************************************************
START ; POWER_ON Reset (Beginning of program)
CLRF STATUS ; Do initialization, Select bank 0
CLRF INTCON ; Clear int-flags, Disable interrupts
CLRF PCLATH ; Keep in lower 2KByte
;* I had originally edited the original assembly for initialising
;* Then I changed to bankssel with I was getting error code 302
; BCF STATUS, RP0 ; Select bank 0
; CLRF PORTA ;Initialize PORTA by setting output data latches
; MOVLW 0x07 ;Turn comparators off and
; MOVWF CMCON ;enable pins for I/O functions
; CLRF PORTB
; BCF STATUS, RP1
; BSF STATUS, RP0 ;Select Bank1
; MOVLW b'11000111' ;Value used to initialize data direction
; MOVWF TRISA ;Set RA<2:0> as inputs RA<5:3> as outputs RA<7:6> as inputs
; MOVLW 0x000 ; RB7-0 outputs
; MOVWF TRISB
; BSF OPTION_REG, NOT_RBPU ; Disable PORTB pull-ups
;
; BCF STATUS, RP0 ; Select bank 0
;* Using banksel to select relevant banks for initilising
banksel PORTA
clrf PORTA
MOVLW 0x07 ;Turn comparators off and
movwf PORTA
banksel PORTB
clrf PORTB
banksel TRISA
MOVLW b'11000111' ;Value used to initialize data direction
MOVWF TRISA ;<compile warning 302 Register in operand not in bank 0. Ensure that bank bits are correct!
;Set RA<2:0> as inputs RA<5:3> as outputs RA<7:6> as inputs
banksel TRISB
MOVLW 0x000 ; RB7-0 outputs
MOVWF TRISB ;< compile warning 302 Register in operand not in bank 0. Ensure that bank bits are correct.
CALL LCDINIT ; Initialize LCDisplay
;*****************************************************************************
; Display some lines, here
; ----------------------
; |This is on line : 0|
; |This is on line : 1|
; |This is on line : 2|
; |This is on line : 3|
; ----------------------
; OK
;*****************************************************************************
MOVLW 0x030 ; ASCII '0'
MOVWF COUNT
MOVLW LCD_LINE0
CALL LCDSDDA ; Position cursor leftmost on first line
CALL TABLE_MSG ; Display message
MOVLW LCD_LINE0 + 0x013
CALL LCDSDDA ; Position cursor
MOVF COUNT, W
CALL LCDPUTCHAR ; Display line number
INCF COUNT, F
MOVLW LCD_LINE1
CALL LCDSDDA
CALL TABLE_MSG
MOVLW LCD_LINE1 + 0x013
CALL LCDSDDA
MOVF COUNT, W
CALL LCDPUTCHAR
INCF COUNT, F
MOVLW LCD_LINE2
CALL LCDSDDA
CALL TABLE_MSG
MOVLW LCD_LINE2 + 0x013
CALL LCDSDDA
MOVF COUNT, W
CALL LCDPUTCHAR
INCF COUNT, F
MOVLW LCD_LINE3
CALL LCDSDDA
CALL TABLE_MSG
MOVLW LCD_LINE3 + 0x013
CALL LCDSDDA
MOVF COUNT, W
CALL LCDPUTCHAR
;*****************************************************************************
; Program ends here
; OK
;*****************************************************************************
LOOP
GOTO LOOP ; Stay here forever
;*****************************************************************************
; Send a message using a table to output a message
; OK
;*****************************************************************************
TABLE_MSG
MOVLW 0 ; Startindex of table message
DISP_MSG
MOVWF TABLE_INDEX ; Holds message address
CALL MSG1
ANDLW 0x0FF ; Check if at end of message
BTFSC STATUS, Z ; (zero returned at end)
GOTO TABLE_MSG_END
CALL LCDPUTCHAR ; Display character
MOVF TABLE_INDEX, W ; Point to next character
ADDLW 1
GOTO DISP_MSG
TABLE_MSG_END RETURN
;*****************************************************************************
; LCD Module Subroutines
;*****************************************************************************
;
;=============================================================================
; LCDINIT
; Initilize LC-Display Module
; Should be modified to your needs (i.e. display type, cursor on/off, etc.)
; OK
;=============================================================================
LCDINIT
; Busy-flag is not yet valid
CLRF LCD_CTRL ; ALL PORT output should output Low.
; power-up delay
MOVLW 0x01E
CALL X_DELAY500 ; 30 * 0.5mS = 15mS
; Busy Flag should be valid from here
MOVLW 0x038 ; 8-bit-interface, 2-lines
CALL LCDPUTCMD
MOVLW 0x000 ; disp.off, curs.off, no-blink
CALL LCDDMODE
CALL LCDCLEAR
MOVLW 0x004 ; disp.on, curs.off
CALL LCDDMODE
MOVLW 0x002 ; auto-inc (shift-cursor)
CALL LCDEMODE
RETURN
;=============================================================================
; LCD_ENABLE
; Pulses LCD enable pin
; OK
;=============================================================================
LCD_ENABLE
BSF LCD_CTRL, LCD_E ; LCD E-line High
BCF LCD_CTRL, LCD_E ; LCD E-line Low
RETURN
;=============================================================================
; LCDBUSY
; Returns when LCD busy-flag is inactive
; OK
;=============================================================================
LCDBUSY
BSF STATUS,RP0 ; Select Register page 1
MOVLW 0x0FF ; Set PORTB for input
MOVWF LCD_DATA_TRIS ;< compile warning 302 Register in operand not in bank 0. Ensure that bank bits are correct.
BCF STATUS, RP0 ; Select Register page 0
BCF LCD_CTRL, LCD_RS; Set LCD for command mode
BSF LCD_CTRL, LCD_RW; Setup to read busy flag
BSF LCD_CTRL, LCD_E ; LCD E-line High
MOVF LCD_DATA, W ; Read busy flag + DDram address
BCF LCD_CTRL, LCD_E ; LCD E-line Low
ANDLW 0x80 ; Check Busy flag, High = Busy
BTFSS STATUS, Z
GOTO LCDBUSY
LCDNOTBUSY BCF LCD_CTRL, LCD_RW
BSF STATUS, RP0 ; Select Register page 1
MOVLW 0x000
MOVWF LCD_DATA_TRIS ; Set PORTB for output ;< compile warning 302 Register in operand not in bank 0. Ensure that bank bits are correct.
BCF STATUS, RP0 ; Select Register page 0
RETURN
;=============================================================================
; LCDCLEAR
; Clears display and returns cursor to home position (upper-left corner).
;
;=============================================================================
LCDCLEAR
MOVLW 0x001
CALL LCDPUTCMD
RETURN
;=============================================================================
; LCDHOME
; Returns cursor to home position.
; Returns display to original position (when shifted).
;
;=============================================================================
LCDHOME
MOVLW 0x002
CALL LCDPUTCMD
RETURN
;=============================================================================
; LCDEMODE
; Sets entry mode of display.
; Required entry mode must be set in W
; b0 : 0 = no display shift 1 = display shift
; b1 : 0 = auto-decrement 1 = auto-increment
; b2-7 : don't care
; OK
;=============================================================================
LCDEMODE
ANDLW 0x003 ; Strip upper bits
IORLW 0x004 ; Function set
CALL LCDPUTCMD
RETURN
;=============================================================================
; LCDDMODE
; Sets display control.
; Required display mode must be set in W
; b0 : 0 = cursor blink off 1 = cursor blink on
; b1 : 0 = cursor off 1 = cursor on
; b2 : 0 = display off 1 = display on (display data remains in DDRAM)
; b3-7 : don't care
; OK
;=============================================================================
LCDDMODE
ANDLW 0x007 ; Strip upper bits
IORLW 0x008 ; Function set
CALL LCDPUTCMD
RETURN
;=============================================================================
; LCDSCGA
; Sets Character-Generator-RAM address. CGRAM is read/written after
; this setting.
; Required CGRAM address must be set in W
; b0-5 : required CGRAM address
; b6-7 : don't care
;
;=============================================================================
LCDSCGA
ANDLW 0x03F ; Strip upper bits
IORLW 0x040 ; Function set
CALL LCDPUTCMD
RETURN
;=============================================================================
; LCDSDDA
; Sets the Display-Data-RAM address. DDRAM data is read/written after
; this setting.
; Required DDRAM address must be set in W
; b0-6 : required DDRAM address
; b7 : don't care
; OK
;=============================================================================
LCDSDDA
IORLW 0x080 ; Function set
CALL LCDPUTCMD
RETURN
;=============================================================================
; LCDGADDR
; Returns address counter contents, used for both DDRAM and CGRAM.
; RAM address is returned in W
;
;=============================================================================
LCDGADDR
BSF STATUS,RP0 ; Select Register page 1
MOVLW 0x0FF ; Set PORTB for input
MOVWF LCD_DATA_TRIS ;< compile warning 302 Register in operand not in bank 0. Ensure that bank bits are correct.
BCF STATUS, RP0 ; Select Register page 0
BCF LCD_CTRL, LCD_RS; Set LCD for command mode
BSF LCD_CTRL, LCD_RW; Setup to read busy flag
BSF LCD_CTRL, LCD_E ; LCD E-line High
MOVF LCD_DATA, W ; Read busy flag + RAM address
BCF LCD_CTRL, LCD_E ; LCD E-line Low
ANDLW 0x07F ; Strip upper bit
BCF LCD_CTRL, LCD_RW
BSF STATUS, RP0 ; Select Register page 1
MOVLW 0x000
MOVWF LCD_DATA_TRIS ; Set PORTB for output getting ;< compile warning 302 Register in operand not in bank 0. Ensure that bank bits are correct.
BCF STATUS, RP0 ; Select Register page 0
RETURN
;=============================================================================
; LCDPUTCHAR
; Sends character to LCD
; Required character must be in W
; OK
;=============================================================================
LCDPUTCHAR
MOVWF LCD_TEMP ; Character to be sent is in W
CALL LCDBUSY ; Wait for LCD to be ready
BCF LCD_CTRL, LCD_RW; Set LCD in read mode
BSF LCD_CTRL, LCD_RS; Set LCD in data mode
BSF LCD_CTRL, LCD_E ; LCD E-line High
MOVF LCD_TEMP, W
MOVWF LCD_DATA ; Send data to LCD
BCF LCD_CTRL, LCD_E ; LCD E-line Low
RETURN
;=============================================================================
; LCDPUTCMD
; Sends command to LCD
; Required command must be in W
; OK
;=============================================================================
LCDPUTCMD
MOVWF LCD_TEMP ; Command to be sent is in W
CALL LCDBUSY ; Wait for LCD to be ready
BCF LCD_CTRL, LCD_RW; Set LCD in read mode
BCF LCD_CTRL, LCD_RS; Set LCD in command mode
BSF LCD_CTRL, LCD_E ; LCD E-line High
MOVF LCD_TEMP, W
MOVWF LCD_DATA ; Send data to LCD
BCF LCD_CTRL, LCD_E ; LCD E-line Low
RETURN
;*****************************************************************************
; Delay_time = ((DELAY_value * 3) + 4) * Cycle_time
; DELAY_value = (Delay_time - (4 * Cycle_time)) / (3 * Cycle_time)
;
; i.e. (@ 4MHz crystal)
; Delay_time = ((32 * 3) + 4) * 1uSec
; = 100uSec
; DELAY_value = (500uSec - 4) / 3
; = 165.33
; = 165
;*****************************************************************************
DELAY500 MOVLW D'240' ; +1 1 cycle * increased to 240 just in case
MOVWF DELAY ; +2 1 cycle
DELAY500_LOOP DECFSZ DELAY, F ; step 1 1 cycle
GOTO DELAY500_LOOP ; step 2 2 cycles
DELAY500_END RETURN ; +3 2 cycles
;
;
X_DELAY500 MOVWF X_DELAY ; +1 1 cycle
X_DELAY500_LOOP CALL DELAY500 ; step1 wait 500uSec
DECFSZ X_DELAY, F ; step2 1 cycle
GOTO X_DELAY500_LOOP ; step3 2 cycles
X_DELAY500_END RETURN ; +2 2 cycles
;=============================================================================
; Table message to display
;=============================================================================
MSG1
addwf PCL ,F ;Jump to char pointed to in W reg
retlw 'T'
retlw 'h'
retlw 'i'
retlw 's'
retlw ' '
retlw 'i'
retlw 's'
retlw ' '
retlw 'o'
retlw 'n'
retlw ' '
retlw 'l'
retlw 'i'
retlw 'n'
retlw 'e'
retlw ' '
retlw ':'
retlw ' '
retlw ' '
retlw '#'
MSG1_END
retlw 0
;
; IF ( (MSG1 & 0x0FF) >= (MSG1_END & 0x0FF) )
; MESSG "Warning - User Definded: Table 'MSG1' crosses page boundry in computed jump"
; ENDIF
END ; End of program