Pete Zawasky - 2008-11-11

Here is an FF 3.3 driver app for the Crystalfontz CFAG14432D Graphics LCD.

73
Pete
AG7C

\ *********************************************************************
\                                                                     *
\    Filename:      graphics_lcd.txt                                  *
\    FlashForth:    3.3                                               *
\    MCU            PIC18F6527                                        *
\    Application:                                                     *
\                                                                     *
\    Author:        Pete Zawasky -- PZEF Co.                          *
\    Created:       Tuesday, October 21 2008 - 17:22  ppz             *
\    Last Edit                                ppz                     *
\                                                                     *
\ *********************************************************************
\  FlashForth is licensed acording to the GNU General Public License  *
\ *********************************************************************
\
\ Drive LCD using Port F and Port G.
\ Control contrast and backlight controlled via the I2C bus.
\ Words are defined for Crystalfontz CFAG14432D-TTI-TT.

\ PORT F   $FF85   Bidirectional data  RF<7..0> = D<7..0>
\ PORT G   $FF86   LCD Control bits
\          bit 2   LCD_RS     1=DR, 0=IR
\          bit 1   LCD_R/W    1=rd, 0=wr
\          bit 0   LCD_E      read/write occurs on falling edge of E

-lcd
marker -lcd

decimal ram

\ Needs from asm.fth
\   clrf, bcf, bsf, btfsc, btfss, movf, movwf, andwf, Sminus .
\
\ For convenience these are provided here.
\
\ microchip assembler arguments
\ f = file
\ d = destination
\ a = access
\ b = bit
\ k = literal
\
0 con w,     \ Destination W register
1 con f,     \ Destination File
0 con a,     \ Force Access Bank
1 con b,     \ Force Bank Select Register
\
$ffed con Sminus,
$14 as3 andwf,  ( f d a -- )
$50 as3 movf,   ( f d a -- )
$6e as2 movwf,  ( f a -- )
$90 as3 bcf,    ( f b a -- )
$80 as3 bsf,    ( f b a -- )
$b0 as3 btfsc,  ( f b a -- )
$a0 as3 btfss,  ( f b a -- )
$6a as2 clrf,   ( f a -- )
$0e00 as1 movlw,        ( k -- )
$0012 as0 return,       ( -- )

$ff85 con portf
$ff86 con portg
$ff97 con trisf
$ff98 con trisg
$ffc1 con adcon1

\ portg bits
0 con LCD_E            \ read/write occurs on falling edge of E
1 con LCD_R/W          \ 1=RD, 0=WR
2 con LCD_RS           \ 1=DR, 0=IR

\ *********************************************************************
\ LCD initialization

\ Initial state is RF<7..0> - output
\                  RG<2..0> - output
\                  RS=0, R/W=0, E=0
\
INIT_LCD_PORTS   ( -- )
   $0a adcon1 c!        \ RF<7..0> set to DIGITAL
   $00 portf  c!
   $00 trisf  c!        \ RF<7..0> set to OUTPUT
   $00 portg  c!        \ IR, WR
   $18 trisg  c!        \ RG<2..0> set to OUTPUT
   ;

\ *********************************************************************
\ LCD read and write timing.

\ Write to instruction register.
\
IR!           ( 8b -- )
   [ portg LCD_RS  a, bcf, ]   \ Instruction Register
   [ portg LCD_R/W a, bcf, ]   \ Write

   portf c!                    \ instruction
   [ trisf a, clrf, ]          \ Port F set to OUTPUT

   [ portg LCD_E a, bsf, ]     \ set E HIGH
   [ portg LCD_E a, bcf, ]     \ return E LOW
   ;

\ Read from instruction register.
\
IR@           ( -- 8b )
   [ $ff movlw, trisf a, movwf, ]  \ Port F set to INPUT
   [ portg LCD_RS  a, bcf, ]   \ Instruction Register
   [ portg LCD_R/W a, bsf, ]   \ Read
   [ portg LCD_E a, bsf, ]     \ set E HIGH

   portf c@                    \ read Busy Flag and Address

   [ portg LCD_E a, bcf, ]     \ return E LOW
   ;

\ Write to data register.
\
DR!           ( 8b -- )
   [ portg LCD_RS  a, bsf, ]   \ Data Register
   [ portg LCD_R/W a, bcf, ]   \ Write

   portf c!                    \ data
   [ trisf a, clrf, ]          \ Port F set to OUTPUT

   [ portg LCD_E a, bsf, ]     \ set E HIGH
   [ portg LCD_E a, bcf, ]     \ return E LOW
   ;

\ Read from data register.
\
DR@           ( -- 8b )
   [ $ff movlw, trisf a, movwf, ]  \ Port F set to INPUT
   [ portg LCD_RS  a, bsf, ]   \ Data Register
   [ portg LCD_R/W a, bsf, ]   \ Read
   [ portg LCD_E a, bsf, ]     \ set E HIGH

   portf c@                    \ read data

   [ portg LCD_E a, bcf, ]     \ return E LOW
   ;

\ *********************************************************************
\ Test Busy Flag.
\
?BF   ( -- )
   begin IR@ $80 and 0= until  ;
\ Get AC value (cursor position).
\
AC@   ( -- 8b )
   ?BF IR@ $7f and  ;

\ *********************************************************************
\ LCD Read/Write commands.

\ Send to Instruction Register.
CMD!          ( 8b -- )
   ?BF IR! ;
\ Read from Instruction Register.
CMD@          ( -- 8b )
   ?BF IR@ ;
\ Send to Data Register.
DATA!         ( 8b -- )
   ?BF DR! ;
\ Read from Data Register.
DATA@         ( -- 8b )
   ?BF DR@ ;

\ *********************************************************************
\ LCD Basic Instruction Set.

\ Clear display, AC = $00, I/D = 1.
\
CLEAR         ( -- )
   $01 CMD!   ;
\ Move cursor to line 1, position 0.
\
HOME          ( -- )
   $02 CMD!   ;
\ Entry mode set.
\ set I/D and S bits.
\   bit 2      = 1
\   bit 1  I\D = 1  Address Counter Increment
\              = 0  Address Counter Decrement
\   bit 0    S = 1  Display Shift Enabled
\                0  Cursor Shift Enabled
\
ENTRY_MODE    ( 8b -- )
   $03 and $04 or CMD!   ;
\ Display on/off.
\ set D, C, B bits
\   bit 3      = 1
\   bit 2    D = 1  Display  ON
\              = 0  Display  OFF
\   bit 1    C = 1  Cursor   ON
\              = 0  Cursor   OFF
\   bit 0    B = 1  Blinking ON
\                0  Blinking OFF
\
DISPLAY_ON/OFF   ( 8b -- )
   $07 and $08 or CMD!   ;
\ Cursor/Display Shift control.
\ set S/C, R/L bits
\   bit 4      = 1
\   bit 3  S/C = 1  Shift both cursor and display
\              = 0  Shift cursor only
\   bit 2  R/L = 1  Shift one character right
\              = 0  Shift one character left
\   bit 1/0  Don't Care
\
C/D_SHIFT    ( 8b -- )
   $0c and $10 or CMD!   ;
\ Function Set.
\  DL, RE must be set as individual commands.
\  Always set 8bit interface.
\   bit 5      = 1
\   bit 4   DL = 1  8bit interface
\   bit 3    Don't Care
\   bit 2   RE = 1  Extended Instruction Set
\              = 0  Basic Instruction Set
\   bit 1/0  Don't Care
\
FUNCTION      ( 8b -- )
   $04 and $30 or CMD!   ;
\ Set CGRAM address.
\  AC range is $00 to $3F
\  bit 6       = 1
\  bit <5..0>  = AC<5..0>
\
SET_CGRAM_ADDRESS  ( 8b -- )
   $3f and $40 or CMD!   ;
\ Set DDRAM address.
\ Send cursor to new position.
\  line = $00, $10, $20, or $30
\  pos  = $00 to $0F
\  bit 7       = 1
\  bit <6..0>  = AC<6..0>
\
SET_DDRAM    ( pos+line -- )
   $80 or CMD!   ;      \ load 7bit address into address counter
                        \ point to DDRAM
\ convenience
\
LINE1    ( pos -- )
   $00 or SET_DDRAM  ;    \ line 1 start address

LINE2    ( pos -- )
   $10 or SET_DDRAM  ;    \ line 2 start address

LINE3    ( pos -- )
   $20 or SET_DDRAM  ;    \ line 3 start address

LINE4    ( pos -- )
   $30 or SET_DDRAM  ;    \ line 4 start address

\ display viewable
\ : DISPLAY_ON    ( -- )
\    $06 DISPLAY_ON/OFF     ;   \ display ON, cursor ON, blinking OFF

\ display dark
\ : DISPLAY_OFF   ( -- )
\    $00 DISPLAY_ON/OFF     ;   \ display OFF, cursor OFF, blinking OFF

\ *********************************************************************
\ Text display words.
\ Line entry mode.

LEMIT       ( 8b -- )
   DATA!   ;             \ put new data at DDRAM address

LSPACE      ( -- )
   bl LEMIT  ;

LSPACES     ( 8b -- )
   0 max                 \ don't want negative numbers
   for
     LSPACE
   next  ;

\ *********************************************************************
\ Output formatting and string words.

LTYPE    ( addr +n -- )
   for  c@+ LEMIT next  drop  ;

L.       ( n -- )
    dup abs <# #s swap sign #>
    LTYPE LSPACE  ;

L."         ( -- )   \ usage   L." ccc"  , compile mode only
    postpone s"         \ compile literal string up to "
    postpone LTYPE  ;  immediate

TEST_LINE   ( -- )
    L." PZEF Company "  ;

\ *********************************************************************
\ LCD test words.

ASCII ( -- )
   $02 126 for dup . dup DATA! 1+ 100 ms next drop  ;

\ *********************************************************************
\ LCD Extended Instruction Set.

\ Stand By mode.
\
STAND_BY    ( -- )
   $01 CMD!   ;
\ Vertical Scroll or RAM Address Select.
\   bit 1      = 1
\   bit 0   SR = 1  Vertical Scroll Address Set
\              = 0  IRAM Address Set
\
VS/RA_SELECT   ( 8b -- )
   $01 and $02 or CMD!  ;
\ Reverse a line on the LCD.
\   bit 2      = 1
\   bit 1/0    = 0 0  Line 1
\              = 0 1  Line 2
\              = 1 0  Line 3
\              = 1 1  Line 4
\
REVERSE     ( 8b -- )
   $03 and $04 or CMD!  ;
\ Sleep mode.
\ set SL bit
\   bit 3      = 1
\   bit 2   SL = 1  Sleep Mode OFF
\              = 0             ON
\   bit 1/0    = 0
\
SLEEP   ( 8b -- )
   $04 and $08 or CMD!   ;
\ Extended Function Set.
\  DL, RE, G must be set as individual commands.
\  Always set 8bit interface.
\   bit 5      = 1
\   bit 4   DL = 1  8bit interface
\   bit 3    Don't Care
\   bit 2   RE = 1  Extended Instruction Set
\              = 0  Basic Instruction Set
\            If Extended Instructions
\   bit 1   G  = 1  Graphic Display ON
\              = 0  Graphic Display OFF
\   bit 0    Don't Care
\
\
EXT_FUNCTION      ( 8b -- )
   $06 and $30 or CMD!   ;
\ Set IRAM or SCROLL address.
\  AC range is $00 to $3F
\  bit 6       = 1
\            If SR = 1
\  bit <5..0>  = AC<5..0>  Vertical Scroll Displacement Address
\            If SR = 0
\  bit <3..0>  = AC<3..0>  ICON RAM address
\
SET_I/S_ADDRESS   ( 8b -- )
   $3f and $40 or CMD!   ;
\ Set Graphic Display RAM address.
\  Vertical address range is AC<6..0>
\  Horizontal address range is AC<3..0>
\  2 byte operation
\    Set vertical address (Y)
\    Set horizontal address (X)
\
SET_GDRAM   ( 8b -- )
   $80 or CMD!   ;      \ load 7bit/4bit address into address counter

\ *********************************************************************
\ LCD graphics

\ Enable graphics mode and display.
\
GRAPHICS   ( -- )
   $04 DISPLAY_ON/OFF   \ Cursor OFF
   $04 EXT_FUNCTION     \ RE = 1 Extended Instructions
   $06 EXT_FUNCTION     \  G = 1 graphics ON
   ;
\ Disable graphics mode and return to text mode.
TEXT   ( -- )
   $04 EXT_FUNCTION     \  G = 0 graphics OFF
   $00 EXT_FUNCTION     \ RE = 0 Basic Instructions
   $06 DISPLAY_ON/OFF   \ display ON, cursor ON, blinking OFF
   ;
\ Graphics start position - Upper Left corner
\
G_HOME  ( -- )
   $00 SET_GDRAM           \ Vertical   -- Y
   $00 SET_GDRAM           \ Horizontal -- X
   ;
\ Clear the graphics memory.
\
G_CLEAR  ( -- )
   $00            \ Horizontal -- X
   $00            \ Vertical   -- Y
                  \ total graphics area is 256x64
   64             \   but only 144x32 is visible
   for
     2dup
     SET_GDRAM    \ set Vertical address
     SET_GDRAM    \ set Horiziontal address
     16
     for          \ horizontal row
       $00 DATA!  \ high byte
       $00 DATA!  \ low byte
     next
     1+           \ step Vertical address
   next  2drop   ;

\ variables
ram
variable G_INV    \ inversion bit mask

flash

\ constants
$5000 con scn_save     \ screen save area of FLASH
                            \ allows space for 49 screens
$f300 con scn_buff     \ screen buffer area in RAM

\ Save the graphics screen.
\  addr is the starting address of RAM Buffer or FLASH Save area
\
g_save   ( addr -- )
   !p>r           \ set up pointer
   $00            \ Horizontal -- LCD X
   $00            \ Vertical   -- LCD Y
                  \ total graphics area is 256x64 bits
   32             \   but only 144x32 is visible
   for
     2dup
     SET_GDRAM    \ set Vertical address
     SET_GDRAM    \ set Horiziontal address
     DATA@ drop   \ dummy read
     18
     for          \ horizontal row
       DATA@ pc! p+  \ get byte, save in FLASH
     next
     1+           \ step Vertical address
   next  2drop
   r>p   ;
\ Save the graphics screen.
\  n is the graphics screen reference #
\  0 is RAM Buffer, 1 to 49 is FLASH Sav
\
G_SAVE   ( n -- )
   dup 0=
   if
     drop
     scn_buff
   else
     1-
     $240 *       \ 576 bytes per screen (18x32)
     scn_save +   \ offset into screen save area of FLASH
   then
   g_save  ;
\ Update the visible area of the graphics LCD
\  addr is the starting address of RAM Buffer or FLASH Save area
\
g_view   ( addr -- )
   !p>r           \ set up pointer
   $00            \ Horizontal -- LCD X
   $00            \ Vertical   -- LCD Y
                  \ total graphics area is 256x64 bits
   32             \   but only 144x32 is visible
   for
     2dup
     SET_GDRAM       \ set Vertical address
     SET_GDRAM       \ set Horiziontal address
     18
     for             \ horizontal row
       pc@ G_INV @   \ get byte and inversion mask
       xor           \ massage bits
       DATA! p+      \ send to LCD
     next
     1+              \ step Vertical address
   next  2drop
   r>p   ;
\ Restore a graphics screen
\  n is the graphics screen reference #
\  0 is RAM Buffer, 1 to 49 is FLASH Save
\
G_VIEW   ( n -- )
   dup 0=
   if
     drop
     scn_buff
   else
     1-
     $240 *       \ 576 bytes per screen (18x32)
     scn_save +   \ offset into screen save area of FLASH
   then
   g_view  ;
\ *********************************************************************
\ Reset display after power on.
\
LCD_INIT  ( -- )
   INIT_LCD_PORTS
   1 ms
   $00 FUNCTION          \ 8-bit interface, basic instructions
   1 ms
   $00 FUNCTION          \ 8-bit interface, basic instructions
   1 ms
   $06 DISPLAY_ON/OFF    \ display ON, cursor ON, blinking OFF
   1 ms
   CLEAR
   10 ms
   $02 ENTRY_MODE        \ AC increment, cursor shift right
   ;

\ *********************************************************************

ram  hex