line source
;=============================================================================
;
; File tft.asm
;
; Managing the TFT screen
;
; Copyright (c) 2011, JD Gascuel, HeinrichsWeikamp, all right reserved.
;=============================================================================
; HISTORY
; 2011-05-24 : [jDG] Cleanups from initial Matthias code.
#include "hwos.inc"
#include "wait.inc"
#include "varargs.inc"
#include "external_flash.inc"
#include "tft_outputs.inc"
#include "eeprom_rs232.inc"
;=============================================================================
; TFT_frame needs to backup coordinates.
CBLOCK tmp
save_top
save_height
save_left
save_width
ds_line ; Current line (0..239).
ds_column ; Current columnx2 (0..159)
ds_pixel:2 ; Current pixel color.
ds_count ; Repetition count.
ENDC
;=============================================================================
; Basic bit-level macros
RD_H macro
bsf tft_rd,0
endm
RD_L macro
bcf tft_rd,0
endm
RS_H macro
bsf tft_rs,0
endm
RS_L macro
bcf tft_rs,0
endm
NCS_H macro
bsf tft_cs,0
endm
NCS_L macro
bcf tft_cs,0
endm
WR_H macro
bsf tft_nwr,0
endm
WR_L macro
bcf tft_nwr,0
endm
;=============================================================================
; Byte-leve macros
;
Index_out macro low_b
movlw low_b
rcall TFT_CmdWrite
endm
Parameter_out macro high_b, low_b
movlw high_b
movwf PORTA ; Upper
movlw low_b
rcall TFT_DataWrite
endm
basic CODE
;
;
;;=============================================================================
;; TFT_write_flash_image
;;
;; Inputs: FSR2 = EEPROM address / 256
;; win_left, win_top : imagte CENTER position
;; Outputs: win_height, win_width.
;; image copyed on screen.
;; Trashed: PROD, hi, lo
;;
; global TFT_write_flash_image
;TFT_write_flash_image:
; ; Get back the full 24bit EEPROM address
; clrf ext_flash_address+0
; movff FSR2L,ext_flash_address+1
; movf FSR2H,W
; iorlw 0x30
; movwf ext_flash_address+2
;
; ; Read header: width and height
; global TFT_write_flash_image_addr
;TFT_write_flash_image_addr:
; call ext_flash_read_block_start
; movff SSP2BUF,win_width+0
; movwf SSP2BUF ; Write to buffer to initiate new read
; btfss SSP2STAT, BF ; Next byte ready ?
; bra $-2 ; NO: wait...
; movff SSP2BUF,win_width+1
; movwf SSP2BUF ; Write to buffer to initiate new read
; btfss SSP2STAT, BF ; Next byte ready ?
; bra $-2 ; NO: wait...
; movff SSP2BUF,win_height
; movwf SSP2BUF ; Write to buffer to initiate new read
; btfss SSP2STAT, BF ; Next byte ready ?
; bra $-2 ; NO: wait...
; movff SSP2BUF,WREG ; drop 4th byte.
; movwf SSP2BUF ; Write to buffer to initiate new read
; btfss SSP2STAT, BF ; Next byte ready ?
; bra $-2 ; NO: wait...
;
; ; Sanity check on header to avoid badly uploaded images.
; iorwf WREG ; Check height < 256
; bnz TFT_write_flash_image_failed
; movf win_width+1,W ; Check width < 512
; andlw 0xFE
; bnz TFT_write_flash_image_failed
;
; ; Center image on win_top, win_left values
; bcf STATUS,C ; Clear carry
; rrcf win_height,W ; And get height/2
; subwf win_top,F ; top -= height/2
; rrcf win_width+1,W ; Get 9th bit into carry
; rrcf win_width+0,W ; Get width/2 (in 0..320 range)
; bcf STATUS,C
; rrcf WREG,W ; Get width/2 in 0..160 range
; subwf win_leftx2,F ; left -= width/2
;
; rcall TFT_box_write ; Inputs : win_top, win_leftx2, win_height, win_width(in 1..320 range)
;
; ; Compute number of pixels to move (result on 17 bits !)
; clrf TBLPTRU
; movf win_width+0,W
; mulwf win_height ; Result in PRODL:H
; movf win_width+1,W
; bz TFT_write_flash_image_1 ; width > 8bits ?
; movf win_height,W ; YES: add extra
; addwf PRODH,F
; rlcf TBLPTRU ; And carry into upper register.
;TFT_write_flash_image_1:
; incf PRODH,F ; Pre-condition nested loops
; incf TBLPTRU,F
;
; ; Write pixels
; Index_out 0x22 ; Frame Memory Data Write start
; RS_H ; Data
;
;TFT_write_flash_image_loop:
; btfss SSP2STAT, BF ; Buffer full?
; bra $-2 ; NO: wait...
; movff SSP2BUF,PORTH ; Read lo
; movwf SSP2BUF ; Write to buffer to initiate new read
;
; btfss SSP2STAT, BF ; Buffer full?
; bra $-2 ; NO: wait...
; movff SSP2BUF,PORTA ; And read hi
; movwf SSP2BUF ; Write to buffer to initiate new read
; WR_L
; WR_H ; Write 1 Pixel
;
; decfsz PRODL,F
; bra TFT_write_flash_image_loop
; decfsz PRODH,F
; bra TFT_write_flash_image_loop
; decfsz TBLPTRU,F
; bra TFT_write_flash_image_loop
;
; btfss SSP2STAT, BF ; Buffer full?
; bra $-2 ; No, wait
; movf SSP2BUF,W ; Read dummy byte
;
; bsf flash_ncs ; CS=1
; movlw 0x00 ; NOP, to stop window mode
; bra TFT_CmdWrite ; This routine "returns"
;
; ;---- Draw a 4x4 red square in place of missing images...
;TFT_write_flash_image_failed:
; movlw -1
; addwf win_leftx2,F
; movlw -2
; addwf win_top,F
; movlw 2
; movwf win_width+0
; clrf win_width+1
; movlw 4
; movwf win_height
; movlw color_red
; rcall TFT_set_color
; goto TFT_box
;
;;=============================================================================
;
global TFT_CmdWrite
TFT_CmdWrite:
RS_L ; Command
clrf PORTA ; Upper
movwf PORTH ; Lower
WR_L
WR_H ; Tick
return;
global TFT_DataWrite
TFT_DataWrite:
RS_H ; Data
movwf PORTH ; Lower
WR_L
WR_H ; Tick
return
;=============================================================================
;
global TFT_ClearScreen
TFT_ClearScreen:
Index_out 0x50 ; Window Horizontal Start Address
Parameter_out 0x00, 0x00 ; 0-239
Index_out 0x51 ; Window Horizontal End Address
Parameter_out 0x00, 0xEF ; 0-239
Index_out 0x52 ; Window Vertical Start Address
Parameter_out 0x00, 0x00 ; 0-319
Index_out 0x53 ; Window Vertical End Address
Parameter_out 0x01, 0x3F ; 0-319
Index_out 0x20 ; Frame Memory Horizontal Address
Parameter_out 0x00, 0x00 ; 0-239
Index_out 0x21 ; Frame Memory Vertical Address
Parameter_out 0x01, 0x3F ; 0-319
Index_out 0x22 ; Frame Memory Data Write start
RD_H ; Not Read
RS_H ; Data
NCS_L ; Not CS
clrf PORTH ; Data Lower
movlw d'10'
movwf tft_temp3
TFT_ClearScreen2:
movlw d'30'
movwf tft_temp2
TFT_ClearScreen3:
clrf tft_temp1 ; 30*10*256=76800 Pixels -> Clear complete 240*320
TFT_ClearScreen4:
WR_L
WR_H ; Tick
decfsz tft_temp1,F
bra TFT_ClearScreen4
decfsz tft_temp2,F
bra TFT_ClearScreen3
decfsz tft_temp3,F
bra TFT_ClearScreen2
return
;=============================================================================
;
global TFT_DisplayOff
TFT_DisplayOff:
clrf CCPR1L ; PWM OFF
clrf PORTA
clrf PORTH
RD_L ; LOW
nop
RS_L ; LOW
bcf tft_nwr
nop
bcf tft_cs
nop
bcf tft_nreset
WAITMS d'1'
bsf tft_power ; inverted...
bcf lightsen_power ; power-down light sensor
return
; -----------------------------
; TFT boot
; -----------------------------
global TFT_boot
TFT_boot:
clrf PORTA
clrf PORTH
RD_L ; LOW
bcf tft_nwr
nop
bcf tft_cs
nop
bcf tft_nreset
WAITMS d'1'
bcf tft_power ; inverted...
WAITMS d'1'
RD_H ; Keep high
WR_H ;
NCS_L ; Not CS
WAITMS d'2'
bsf tft_nreset
WAITMS d'150'
bsf lightsen_power ; Supply power to light sensor
; Data Transfer Synchronization
Parameter_out 0x00, 0x00
Parameter_out 0x00, 0x00
Index_out 0x00
rcall TFT_CmdRead_PROD ; Get ID into PRODL:PRODH
; 5:197 -> display0
;37:147 -> display1
movlw .5
cpfseq PRODL ; display0?
bra TFT_boot_1 ; No
movlw .197
cpfseq PRODH ; display0?
bra TFT_boot_1 ; No
; Init through config table...
movlw LOW display0_config_table
movwf TBLPTRL
movlw HIGH display0_config_table
movwf TBLPTRH
movlw UPPER display0_config_table
movwf TBLPTRU
bcf screen_type
bra TFT_boot_com
TFT_boot_1:
; Init through config table...
movlw 0x74
movwf TBLPTRL
movlw 0xF7
movwf TBLPTRH
movlw 0x01
movwf TBLPTRU
bsf screen_type
TFT_boot_com:
rcall display0_init_loop
Index_out 0x03
btfsc flip_screen ; 180° rotation ?
bra TFT_boot2 ; Yes
btfss screen_type ; display1?
bra TFT_boot1a ; no
Parameter_out 0x10, 0x00 ; display1
bra TFT_boot3
TFT_boot1a:
Parameter_out 0x50, 0x20 ; display0
bra TFT_boot3
TFT_boot2:
btfss screen_type ; display1?
bra TFT_boot2a ; no
Parameter_out 0x10, 0x30 ; display1
bra TFT_boot3
TFT_boot2a:
Parameter_out 0x50, 0x10 ; display0
TFT_boot3:
Index_out 0x22
rcall TFT_ClearScreen
Index_out 0x07
Parameter_out 0x01, 0x33
return
display0_config_table:
; Reg, Dat0, Dat1 or 0xFF,0x00,0x00 for end
db 0xA4,0x00,0x01,0xFF,.002,0x00
db 0x09,0x00,0x01,0x92,0x04,0x00
db 0x93,0x04,0x02,0x94,0x00,0x02
db 0x07,0x00,0x00,0x10,0x04,0x30
db 0x11,0x02,0x37,0x12,0x11,0x8D
db 0x13,0x11,0x00,0x01,0x01,0x00
db 0x02,0x02,0x00,0x03,0x50,0x20
db 0x0A,0x00,0x08,0x0D,0x00,0x00
db 0x0E,0x00,0x30,0xFF,.151,0x00
db 0x12,0x11,0xBD,0x20,0x00,0x00
db 0x21,0x00,0x00,0x30,0x06,0x02
db 0x31,0x56,0x0D,0x32,0x05,0x07
db 0x33,0x06,0x09,0x34,0x00,0x00
db 0x35,0x09,0x06,0x36,0x57,0x05
db 0x37,0x0D,0x06,0x38,0x02,0x06
db 0x39,0x00,0x00,0xFF,0x00,0x00
display0_init_loop:
TBLRD*+
movlw 0xFF
cpfseq TABLAT
bra display0_config_write ; Write Config pair to Display
; Delay ms or quit (return)
TBLRD*+
tstfsz TABLAT ; End of config?
bra $+4 ; No
return ; Done.
movf TABLAT,W
call WAITMSX ; Wait WREG milliseconds
TBLRD*+ ; Dummy read (Third byte of delay command)
bra display0_init_loop ; Loop
display0_config_write: ; With command in WREG
movf TABLAT,W
rcall TFT_CmdWrite ; Write command
TBLRD*+ ; Get config0
movff TABLAT,PORTA
TBLRD*+ ; Get config1
movf TABLAT,W
rcall TFT_DataWrite ; Write config
bra display0_init_loop ; Loop
;=============================================================================
; Smooth lighting-up of the display:
;
; Trashes: WREG, PRODL
; Typical usage:
; clrf CCPR1L ; Backlight off
; [draw splash screen]
; call TFT_DisplayFadeIn
;
global TFT_Display_FadeIn
TFT_Display_FadeIn:
movlw CCP1CON_VALUE ; See hwos.inc
movwf CCP1CON
bsf tft_is_dimming ; TFT is dimming, ignore ambient sensor!
clrf CCPR1L ; Backlight off - to be sure
movff max_CCPR1L,PRODL
TFT_Display_FadeIn_0:
incf CCPR1L,F ; Duty cycle
WAITMS d'2'
decfsz PRODL,F
bra TFT_Display_FadeIn_0
bcf tft_is_dimming ; dimming done.
return
;=============================================================================
; Smooth lighting-off of the display:
; Trashes: WREG, PRODL
global TFT_Display_FadeOut
TFT_Display_FadeOut:
movff max_CCPR1L,PRODL
bsf tft_is_dimming ; TFT is dimming, ignore ambient sensor!
TFT_Display_FadeOut_0:
movff PRODL,CCPR1L ; Duty cycle
WAITMS d'1'
decfsz PRODL,F
bra TFT_Display_FadeOut_0
clrf CCPR1L
return
;=============================================================================
global box_std_block, box_black_block, box_color_block
box_std_block: ; Use white color
setf WREG
bra box_common
box_black_block: ; Use black color
clrf WREG
box_common:
box_color_block:
rcall TFT_set_color
VARARGS_BEGIN
VARARGS_GET8 win_top
VARARGS_GET8 win_height
VARARGS_GET8 win_leftx2
VARARGS_GET8 win_width
VARARGS_END
bra TFT_box
;-----------------------------------------------------------------------------
global box_frame_std, box_frame_common, box_frame_color, box_frame_color16
box_frame_std:
setf WREG
rcall TFT_set_color
box_frame_common:
VARARGS_BEGIN
VARARGS_GET8 win_top
VARARGS_GET8 win_height
VARARGS_GET8 win_leftx2
VARARGS_GET8 win_width
VARARGS_END
bra TFT_frame
box_frame_color:
rcall TFT_set_color
box_frame_color16:
bra box_frame_common
;=============================================================================
; Init for half_pixel_write
; Set column register on TFT device, and current color.
; Inputs: win_leftx2
; Outputs: win_color:2
; Trashed: WREG, PROD
global init_pixel_write
init_pixel_write:
movff win_leftx2,WREG
mullw 2
rcall pixel_write_col320 ; Start Address Vertical (.0 - .319)
setf WREG
bra TFT_set_color
;-----------------------------------------------------------------------------
; Writes two half-pixels at position (win_top,win_leftx2)
; Inputs: win_leftx2, win_top, win_color:2
; Trashed: WREG, PROD
global pixel_write
pixel_write:
movff win_leftx2,WREG
mullw 2 ; win_leftx2 x 2 -> PRODH:PRODL
rcall pixel_write_col320 ; Start Address Vertical (.0 - .319)
rcall half_pixel_write ; Write this half-one.
movff win_leftx2,WREG ; Address of next one
mullw 2
infsnz PRODL ; +1
incf PRODH
rcall pixel_write_col320
bra half_pixel_write ; Note: Cmd 0x20 is mandatory, because
; of the autoincrement going vertical
global pixel_write_col320
pixel_write_col320:
btfsc screen_type ; display1?
bra pixel_write_col320_d1 ; Yes
; Display0
btfss flip_screen ; 180° rotation?
bra pixel_write_noflip_H ; No
bra pixel_write_flip_H ; Yes
pixel_write_col320_d1: ; Display1
btfsc flip_screen ; 180° rotation?
bra pixel_write_noflip_H ; Yes for d1
pixel_write_flip_H: ; Flip d0
movf PRODL,W ; 16bits 319 - PROD --> PROD
sublw LOW(.319) ; 319-W --> W
movwf PRODL
movf PRODH,W
btfss STATUS,C ; Borrow = /CARRY
incf WREG
sublw HIGH(.319)
movwf PRODH
pixel_write_noflip_H:
Index_out 0x21 ; Frame Memory Vertical Address
bra TFT_DataWrite_PROD ; and return...
;-----------------------------------------------------------------------------
; Writes one half-pixel at position (win_top,win_leftx2).
; Inputs: win_leftx2, win_top, win_color:2
; Trashed: WREG, PROD
global half_pixel_write
half_pixel_write:
movff win_top,WREG ; d'0' ... d'239'
; Variant with Y position in WREG.
half_pixel_write_1:
btfss flip_screen ; 180° rotation?
sublw .239 ; 239-Y --> Y
mullw 1 ; Copy row to PRODL (PRODH=0)
Index_out 0x20 ; Frame Memory Horizontal Address
rcall TFT_DataWrite_PROD
Index_out 0x22 ; Frame Memory Data Write start
RS_H ; Data
movff win_color1,PORTA ; Upper
movff win_color2,PORTH ; Lower
WR_L
WR_H ; Tick
return
;-----------------------------------------------------------------------------
; Writes a vertical line of half-pixel at position (win_top,win_leftx2,win_height).
; Inputs: win_leftx2, win_top, win_height, win_color:2
; Trashed: WREG, PROD, TABLAT, TBLPTRL
global half_vertical_line
half_vertical_line:
clrf TABLAT ; Loop index.
half_vertical_line_loop:
movff win_leftx2,WREG ; Init X position.
mullw 2
movf TABLAT,W ; Get loop index
andlw 1 ; Just low bit
xorwf PRODL,F ; And use it to jitter current X position
rcall pixel_write_col320 ; Start Address Vertical (.0 - .319)
movff win_height,WREG ; Index reached height (Bank0 read) ?
xorwf TABLAT,W
btfsc STATUS,Z ; Equals ?
return ; Yes: done.
movff win_top,WREG ; Y = top + index (Bank0 read)
addwf TABLAT,W
rcall half_pixel_write_1
incf TABLAT,F ; index++
bra half_vertical_line_loop
;-----------------------------------------------------------------------------
; Writes a horizontal line of half-pixel at position (win_top,win_leftx2,win_width).
; Inputs: win_leftx2, win_top, win_width, win_color:2
; Trashed: WREG, PROD, TABLAT, TBLPTRL
global half_horizontal_line
half_horizontal_line:
clrf TABLAT ; Loop index.
half_horizontal_line_loop:
movff win_leftx2,WREG ; Init X position.
mullw 2
rcall pixel_write_col320 ; Start Address Vertical (.0 - .319)
movff win_width,WREG ; Index reached height (Bank0 read) ?
xorwf TABLAT,W
btfsc STATUS,Z ; Equals ?
return ; Yes: done.
movff win_top,WREG ; Y = top + index (Bank0 read)
addwf TABLAT,W
rcall half_pixel_write_1
incf TABLAT,F ; index++
bra half_horizontal_line_loop
;-----------------------------------------------------------------------------
; TFT Data Cmd via W
;
global TFT_DataWrite_PROD
TFT_DataWrite_PROD:
; RD_H ; Keep high
RS_H ; Data
movff PRODH,PORTA ; Move high byte to PORTA
movff PRODL,PORTH ; Move low byte to PORTH
WR_L
WR_H ; Tick
return
TFT_DataRead_PROD:
Index_out 0x22 ; Frame Memory Data Read start
TFT_CmdRead_PROD:
setf TRISA ; PortA as input.
setf TRISH ; PortH as input.
RS_H ; Data
; WR_H ; Not write
RD_L ; Read!
nop
nop
nop
RD_H ; Tick
nop
nop
nop
RD_L ; Read!
nop
; nop
; nop
movff PORTA,PRODH
movff PORTH,PRODL
RD_H ; Tick
nop
clrf TRISA ; PortA as output
clrf TRISH ; PortH as output
return
;=============================================================================
; Output TFT Window Address commands.
; Inputs : win_top, win_leftx2, win_height, win_width.
; Output : PortA/PortH commands.
; Trashed: PROD
;
global TFT_box_write
TFT_box_write:
movff win_leftx2,WREG ; Compute left = 2*leftx2 --> PROD
mullw 2
global TFT_box_write_16bit_win_left
TFT_box_write_16bit_win_left: ; With column in PRODL:PRODH
btfsc screen_type ; display1?
bra TFT_box_write_16bit_win_left_d1 ; Yes
; Display0
btfsc flip_screen ; 180° rotation?
bra DISP_box_flip_H ; Yes
bra TFT_box_write_16bit_win_left_com ; No
TFT_box_write_16bit_win_left_d1: ; Display1
btfss flip_screen ; 180° rotation?
bra DISP_box_flip_H ; No for d1
; Yes for d1
TFT_box_write_16bit_win_left_com:
;---- Normal horizontal window ---------------------------------------
Index_out 0x52 ; Window Vertical Start Address
rcall TFT_DataWrite_PROD ; Output left
Index_out 0x21 ; Frame Memory Vertical Address
rcall TFT_DataWrite_PROD ; Output left
movff win_width+0,WREG ; right = left + width - 1
addwf PRODL,F
movff win_width+1,WREG
addwfc PRODH,F
decf PRODL,F ; decrement result
btfss STATUS,C
decf PRODH,F
Index_out 0x53 ; Window Vertical End Address
rcall TFT_DataWrite_PROD
bra DISP_box_noflip_H
;---- Flipped horizontal window --------------------------------------
DISP_box_flip_H:
movf PRODL,W ; 16bits 319 - PROD --> PROD
sublw LOW(.319) ; 319-W --> W
movwf PRODL
movf PRODH,W
btfss STATUS,C ; Borrow = /CARRY
incf WREG
sublw HIGH(.319)
movwf PRODH
Index_out 0x53 ; Window Vertical Start Address
rcall TFT_DataWrite_PROD ; Output left
Index_out 0x21 ; Frame Memory Vertical Address
rcall TFT_DataWrite_PROD ; Output left
movff win_width+0,WREG ; 16bits PROD - width --> PROD
subwf PRODL,F ; PRODL - WREG --> PRODL
movff win_width+1,WREG
subwfb PRODH,F
infsnz PRODL ; PROD+1 --> PROD
incf PRODH
Index_out 0x52 ; Window Vertical End Address
rcall TFT_DataWrite_PROD
DISP_box_noflip_H:
btfss flip_screen ; 180° rotation ?
bra TFT_box_noflip_V ; No.
;---- Flipped vertical window -----------------------------------------
movff win_top,PRODH ; top --> PRODH (first byte)
movff win_height,WREG
addwf PRODH,W
decf WREG
movwf PRODL ; top+height-1 --> PRODL (second byte)
Index_out 0x50 ; Window Horizontal Start Address
movf PRODH,W
rcall TFT_DataWrite ; Lower (and tick)
Index_out 0x51 ; Window Horizontal End Address
movf PRODL,W
rcall TFT_DataWrite ; Lower (and tick)
Index_out 0x20 ; Frame Memory Horizontal Address
movf PRODH,W
rcall TFT_DataWrite ; Lower (and tick)
return
TFT_box_noflip_V:
;---- Normal vertical window ----------------------------------------
movff win_top,PRODL
movff win_height,WREG
addwf PRODL,W
sublw .240 ; 240 - top - height
movwf PRODH ; First byte
movf PRODL,W
sublw .239 ; 239-top
movwf PRODL ; --> second byte.
Index_out 0x50 ; Window Horizontal Start Address
movf PRODH,W
rcall TFT_DataWrite ; Lower (and tick)
Index_out 0x51 ; Window Horizontal End Address
movf PRODL,W
rcall TFT_DataWrite ; Lower (and tick)
Index_out 0x20 ; Frame Memory Horizontal Address
movf PRODL,W
rcall TFT_DataWrite ; Lower (and tick)
return
;=============================================================================
; TFT_frame : draw a frame around current box with current color.
; Inputs: win_top, win_leftx2, win_height, win_width, win_color1, win_color2
; Outputs: (none)
; Trashed: WREG, PROD, aa_start:2, aa_end:2
global TFT_frame
TFT_frame:
movff win_top,save_top ; Backup everything.
movff win_height,save_height
movff win_leftx2,save_left
movff win_width,save_width
;---- TOP line -----------------------------------------------------------
movlw 1 ; row ~ height=1
movff WREG,win_height
rcall TFT_box
;---- BOTTOM line --------------------------------------------------------
movff save_top,PRODL ; Get back top,
movff save_height,WREG ; and height
addwf PRODL,W ; top+height
decf WREG ; top+height-1
movff WREG,win_top ; top+height-1 --> top
rcall TFT_box
;---- LEFT column --------------------------------------------------------
movff save_top,win_top ; Restore top/height.
movff save_height,win_height
movlw 1 ; column ~ width=1
movff WREG,win_width
rcall TFT_box
;---- RIGHT column -------------------------------------------------------
movff save_left,WREG
movff save_width,PRODL
addwf PRODL,W
decf WREG
movff WREG,win_leftx2
rcall TFT_box
;---- Restore everything -------------------------------------------------
movff save_left,win_leftx2
movff save_width,win_width
return
;=============================================================================
; TFT_box : fills current box with current color.
; Inputs: win_top, win_leftx2, win_height, win_width, win_color1, win_color2
; Outputs: (none)
; Trashed: WREG, PROD
global TFT_box
TFT_box:
;---- Define Window ------------------------------------------------------
movf win_width,W
bcf STATUS,C
rlcf WREG
movwf win_width+0
movlw 0
rlcf WREG
movwf win_width+1
rcall TFT_box_write ; Setup box
global TFT_box_16bit_win_left
TFT_box_16bit_win_left:
rrcf win_width+1,W ; width /= 2
rrcf win_width+0,W
movwf win_width
;---- Fill Window --------------------------------------------------------
Index_out 0x22 ; Frame Memory Data Write start
clrf PRODH ; Column counter.
RS_H ; Data
TFT_box2: ; Loop height times
movff win_height,PRODL
TFT_box3: ; loop width times
movff win_color1,PORTA ; Upper
movff win_color2,PORTH ; Lower
WR_L
WR_H ; Tick
;
; movff win_color1,PORTA ; Upper
; movff win_color2,PORTH ; Lower
WR_L
WR_H ; Tick
decfsz PRODL,F ; row loop finished ?
bra TFT_box3 ; No: continue.
incf PRODH,F ; column count ++
movff win_bargraph,WREG ; current column == bargraph ?
cpfseq PRODH
bra TFT_box4 ; No: just loop.
clrf WREG ; Yes: switch to black
movff WREG,win_color1
movff WREG,win_color2
TFT_box4:
movff win_width+0,WREG ; compare ?
xorwf PRODH,W
bnz TFT_box2 ; Loop not finished.
movlw 0x00 ; NOP, to stop window mode
rcall TFT_CmdWrite
setf WREG ; Reset bargraph mode...
movff WREG,win_bargraph
return
;=============================================================================
;Converts 8Bit RGB b'RRRGGGBB' into 16Bit RGB b'RRRRRGGGGGGBBBBB'
global TFT_set_color
TFT_set_color:
movwf tft_temp1 ; Get 8Bit RGB b'RRRGGGBB'
movwf tft_temp2 ; Copy
; Mask Bit 7,6,5,4,3,2
movlw b'00000011'
andwf tft_temp2,F
movlw b'00000000'
dcfsnz tft_temp2,F
movlw b'01010000'
dcfsnz tft_temp2,F
movlw b'10100000'
dcfsnz tft_temp2,F
movlw b'11111000'
movwf tft_temp3 ; Blue done.
movff tft_temp1, tft_temp2 ; Copy
; Mask Bit 7,6,5,1,0
movlw b'00011100'
andwf tft_temp2,F
rrncf tft_temp2,F
rrncf tft_temp2,F
movlw b'00000000'
dcfsnz tft_temp2,F
movlw b'00000100'
dcfsnz tft_temp2,F
movlw b'00001000'
dcfsnz tft_temp2,F
movlw b'00001100'
dcfsnz tft_temp2,F
movlw b'00010000'
dcfsnz tft_temp2,F
movlw b'00010100'
dcfsnz tft_temp2,F
movlw b'00100000'
dcfsnz tft_temp2,F
movlw b'00111111'
movwf tft_temp4
rrcf tft_temp4,F
rrcf tft_temp3,F
rrcf tft_temp4,F
rrcf tft_temp3,F
rrcf tft_temp4,F
rrcf tft_temp3,F ; tft_temp3 (b'GGGBBBBB') done.
movff tft_temp1, tft_temp2 ; Copy
clrf tft_temp1
rrcf tft_temp4,F
rrcf tft_temp1,F
rrcf tft_temp4,F
rrcf tft_temp1,F
rrcf tft_temp4,F
rrcf tft_temp1,F ; Green done.
; Mask Bit 4,3,2,1,0
movlw b'11100000'
andwf tft_temp2,F
rrncf tft_temp2,F
rrncf tft_temp2,F
rrncf tft_temp2,F
rrncf tft_temp2,F
rrncf tft_temp2,F
movlw b'00000000'
dcfsnz tft_temp2,F
movlw b'00000100'
dcfsnz tft_temp2,F
movlw b'00001000'
dcfsnz tft_temp2,F
movlw b'00001100'
dcfsnz tft_temp2,F
movlw b'00010000'
dcfsnz tft_temp2,F
movlw b'00010100'
dcfsnz tft_temp2,F
movlw b'00100000'
dcfsnz tft_temp2,F
movlw b'00111111'
movwf tft_temp4
rrcf tft_temp4,F
rrcf tft_temp1,F
rrcf tft_temp4,F
rrcf tft_temp1,F
rrcf tft_temp4,F
rrcf tft_temp1,F
rrcf tft_temp4,F
rrcf tft_temp1,F
rrcf tft_temp4,F
rrcf tft_temp1,F ; Red done.
movff tft_temp1,win_color1
movff tft_temp3,win_color2 ; Set Bank0 Color registers...
return
;=============================================================================
; Dump screen contents to the UART
global TFT_dump_screen
TFT_dump_screen:
bsf no_sensor_int
movlw 'l'
movwf TXREG ; Send command echo.
call rs232_wait_tx ; wait for UART
;---- Send DISPLAY box command for the full screen window -------------------
Index_out 0x50 ; Window Horizontal Start Address
Parameter_out 0x00, 0x00 ; 0-239
Index_out 0x51 ; Window Horizontal End Address
Parameter_out 0x00, 0xEF ; 0-239
Index_out 0x52 ; Window Vertical Start Address
Parameter_out 0x00, 0x00 ; 0-319
Index_out 0x53 ; Window Vertical End Address
Parameter_out 0x01, 0x3F ; 0-319
clrf ds_column
rcall dump_screen_pixel_reset
dump_screen_1:
btg LEDr ; LED activity toggle
; Dump even column
movlw .240 ; 240 lines, once.
movwf ds_line
dump_screen_2:
Index_out 0x20 ; Frame Memory Horizontal Address
movff ds_line,WREG ; d'0' ... d'239'
mullw 1 ; Copy row to PRODH:L
rcall TFT_DataWrite_PROD
movff ds_column,WREG ; Init X position.
mullw 2
rcall pixel_write_col320 ; Start Address Vertical (.0 - .319)
rcall TFT_DataRead_PROD ; read pixel
rcall dump_screen_pixel
decfsz ds_line,F
bra dump_screen_2
rcall dump_screen_pixel_flush
; Dump odd column
movlw .240 ; 240 lines, twice.
movwf ds_line
dump_screen_3:
Index_out 0x20 ; Frame Memory Horizontal Address
movff ds_line,WREG ; d'0' ... d'239'
mullw 1 ; Copy row to PRODH:L
rcall TFT_DataWrite_PROD
movff ds_column,WREG ; Init X position.
mullw 2
movlw .1
addwf PRODL,F
movlw 0
addwfc PRODH,F ; +1
rcall pixel_write_col320 ; Start Address Vertical (.0 - .319)
rcall TFT_DataRead_PROD ; read pixel
rcall dump_screen_pixel
decfsz ds_line,F
bra dump_screen_3
rcall dump_screen_pixel_flush
incf ds_column,F
movlw .160
cpfseq ds_column
bra dump_screen_1
bcf no_sensor_int
clrf RCREG1 ; Clear receive buffer
bcf RCSTA1,CREN ; Clear receiver status
bsf RCSTA1,CREN
bsf enable_screen_dumps ; =1: Ignore vin_usb, wait for "l" command (Screen dump)
return
;=============================================================================
; Pixel compression
;
; Input: PRODH:L = pixel.
; Output: Compressed stream on output.
; Compressed format:
; 0ccccccc : BLACK pixel, repeated ccccccc+1 times (1..128).
; 11cccccc : WHITE pixel, repeated cccccc+1 times (1..64).
; 10cccccc HIGH LOW : color pixel (H:L) repeated ccccc+1 times (1..64).
;
dump_screen_pixel:
movf PRODH,W ; Compare pixel-high
xorwf ds_pixel+1,W
bnz dump_screen_pixel_1 ; Different -> dump.
movf PRODL,W ; Compare pixel-low
xorwf ds_pixel+0,W
bnz dump_screen_pixel_1 ; Different -> dump.
incf ds_count,F ; Same color: just increment.
return
dump_screen_pixel_1: ; Send (pixel,count) tuple
movf ds_count,W ; Is count zero ?
bz dump_screen_pixel_2 ; Yes: skip sending.
movf ds_pixel+1,W ; This is a BLACK pixel ?
iorwf ds_pixel+0,W
bz dump_screen_pix_black ; YES.
movf ds_pixel+1,W ; This is a white pixel ?
andwf ds_pixel+0,W
incf WREG
bz dump_screen_pix_white ; YES.
; No: write the pixel itself...
movlw .64 ; Max color pixel on a single byte.
cpfsgt ds_count ; Skip if count > 64
movf ds_count,W ; W <- min(64,count)
subwf ds_count,F ; ds_count <- ds_count-W
decf WREG ; Save as 0..63
iorlw b'10000000' ; MARK as a color pixel.
movwf TXREG
call rs232_wait_tx ; wait for UART
movff ds_pixel+1,TXREG
call rs232_wait_tx ; wait for UART
movff ds_pixel+0,TXREG
call rs232_wait_tx ; wait for UART
bra dump_screen_pixel_1
dump_screen_pixel_2:
movff PRODH,ds_pixel+1 ; Save new pixel color
movff PRODL,ds_pixel+0
movlw 1
movwf ds_count ; And set count=1.
return
dump_screen_pix_black:
movlw .128 ; Max black pixel on a single byte.
cpfsgt ds_count ; Skip if count > 128
movf ds_count,W ; W <- min(128,count)
subwf ds_count,F ; ds_count <- ds_count-W
decf WREG ; Save as 0..127
dump_screen_pix_3:
movwf TXREG
call rs232_wait_tx
bra dump_screen_pixel_1 ; More to dump ?
dump_screen_pix_white:
movlw .64 ; Max white pixel on a single byte.
cpfsgt ds_count ; Skip if count > 64
movf ds_count,W ; W <- min(64,count)
subwf ds_count,F ; ds_count <- ds_count-W
decf WREG ; Save as 0..63
iorlw b'11000000' ; MARK as a compressed white.
bra dump_screen_pix_3
dump_screen_pixel_flush:
clrf PRODH
clrf PRODL
rcall dump_screen_pixel_1 ; Send it
dump_screen_pixel_reset:
clrf ds_count ; But clear count.
return
end