; Program: PIC 18F2550 BOLT program to drive a 1.8 inch TFT LCD display. ; Author: Joe Watson, Cedarville, Ohio ; Date: 2014-05-30 ; Notice: This work is in the public domain. ; ; LIST p=18F2550, r=DEC ;NOTE: I like to use decimal as default Include ; ; ; +------------\___/------------+ ; |O | ; | 18F2550 | ; _____ 1| |28 ; Reset---|MCLR RB7|--- ; | | ; | | ; 2| |27 ; ---|RA0 RB6|--- ; | | ; | | ; 3| |26 ; ---|RA1 RB5|--- ; | | ; | | ; 4| |25 ; ---|RA2 RB4|--- ; | | ; | | ; 5| |24 ; ---|RA3 RB3|--- ; | | ; | | ; 6| |23 ; ---|RA4 RB2|--- ; | | ; | | ; 7| |22 ; ---|RA5 RB1|--- ; | | ; | | ; 8| |21 ; ---|Gnd RB0|--- ; | | ; | | ; 9| |20 ; ---|Xtal +5V|--- ; | | ; | | ; 10| |19 ; ---|Xtal Gnd|--- ; | | ; | | ; 11| |18 ; LCD_RS---|RC0 RC7/RX...|---LCD_SDO ; | | ; | | ; _________ 12| |17 ; LCD_Reset---|RC1 RC6/TX...|---LCD_SCK ; | | ; | | ; 13| |16 ; ---|RC2 RC5/USB.D+|---USB D+ ; | | ; | | ; 14| |15 ; USB Cap---|Vusb RC4/USB.D-|---USB D- ; | | ; | | ; | | ; +-----------------------------+ ; ; ; ; ; +-- SD Card Signals ; / (Not used in ; CS MOSI MISO SCK <--+ this project) ; +--------------------------------------------------+ ; | o o o o | ; | | ; | 0,0 127,0 | ; | +--------------------------------------------+ | ; | | | | ; | | | | ; | | | | ; | | | | ; | | | | ; | | | | ; | | | | ; | | | | ; | | | | ; | | | | ; | | | | ; | | | | ; | | 1.8 inch | | ; | | TFT LCD Display | | ; | | 128 x 160 pixels | | ; | | | | ; | | (with SD card | | ; | | slot on back) | | ; | | | | ; | | | | ; | | | | ; | | | | ; | | | | ; | | | | ; | | | | ; | | | | ; | | | | ; | | | | ; | | | | ; | | | | ; | | | | ; | +--------------------------------------------+ | ; | 0,159 127,159 | ; | | ; | o o o o o o o o | ; +--------------------------------------------------+ ; VCC GND CS RESET A0 SDA SCK LED ; | | | | | | | | ; | | | | | | | | 220 ohms ; | | | | | | | +--/\/\/\--- +5V ; | | | | | | | ; | | | | | | | 240 ohms ; | | | | | | O-------/\/\/\--- LCD_SCK ; | | | | | | | ; | | | | | | | 240 ohms ; | | | | | O------------/\/\/\--- LCD_SDO ; | | | | | | | ; | | | | | | | 240 ohms ; | | | | O-----------------/\/\/\--- LCD_RS ; | | | | | | | ; | | | | | | | 240 ohms _________ ; | | | O----------------------/\/\/\--- LCD_Reset ; | | | | | | | ; | | | | | | | ; | | \ \ \ \ \ ; | | / / / / / ; | | \ \ \ \ \ 470 ohms ; | | / / / / / x5 ; | | \ \ \ \ \ ; | | | | | | | ; | | | | | | | ; | +----O----O----O----O----o---------------- GND ; | ; +---------------------------------------------- +5V ; ; ;The LCD display uses a COG (Controller On Glass) ST7735S LCD Controller ;chip which determines the protocol used to communicate with the display. ; ;The SD card slot on the back is not used in this project. ; ;SPI communication is carried out only with the LCD display. Therefore, ;the LCD's CS signal is not connected to the PIC processor at all. Being ;held low all the time by its associated resistor simply means that the ;LCD is always enabled for communication. ; ;Although the LCD controller is capable of sending data to the PIC ;microcontroller, that capability is not being used in this project. ;All communication is going from the PIC to the LCD. ; ;The circuit board holding the LCD display and SD card slot also has ;a voltage regulator which provides appropriate 3 volt power to both ;the SD card slot as well as the ST7735S LCD controller. Therefore, ;it is perfectly alright to power this board with +5 volt power. ;However, the logic signals to/from the ST7735S are not conditioned ;in any way on the board. The ST7735S is not intended to operate from ;5-volt logic signals. It needs 3-volt (or mayber 3.3-volt?) logic ;signals. I did not recognize this when I first started experimenting ;with this LCD and was sending it 5-volt logic levels for a short time. ;I am glad to report that it survived but I quickly added the resistor ;networks to reduce the voltage levels when I realized my error. ; ;Although I show a 220-ohm resistor used to limit the current to the ;LCD's LED backlight, I could find no information on the intended ;resistor size or LED current. So I started with a larger resistor ;and tried lower and lower values until the display seemed bright ;enough to be usable. Perhaps others would like to use a lower value ;than 220 ohms. Just remember that lower resistance means higher ;current through the LED backlight and higher current means shorter ;LED life. ;=======================================; ; DEFINITONS ; ;=======================================; ;Define the screen dimensions (128 pixels wide by 160 pixels high). #Define ScrnWdth 128 #Define ScrnHght 160 ;Define ST7735S LCD driver/controller command codes. #Define LCD_SWReset 0x01 ;Software Reset #Define LCD_RDDID 0x04 ;Read Display ID #Define LCD_SLPOUT 0x11 ;Sleep Out #Define LCD_NORON 0x13 ;Normal Display Mode On #Define LCD_INVOFF 0x20 ;Display Inversion Off #Define LCD_INVON 0x21 ;Display Inversion On #Define LCD_DISPOFF 0x28 ;Display Off #Define LCD_DISPON 0x29 ;Display On #Define LCD_CASET 0x2A ;Column Address Set #Define LCD_RASET 0x2B ;Row Address Set #Define LCD_RAMWR 0x2C ;Memory Write (i.e., enable writing of image data) #Define LCD_RAMRD 0x2E ;Memory Read #Define LCD_MADCTL 0x36 ;Memory Data Access Control #Define LCD_COLMOD 0x3A ;Interface Pixel Format #Define LCD_FRMCTR1 0xB1 ;Frame Rate Control (In normal mode/full colors) #Define LCD_FRMCTR2 0xB2 ;Frame Rate Control (In Idle mode/8 colors) #Define LCD_FRMCTR3 0xB3 ;Frame Rate Control (In Partial mode/8 colors) #Define LCD_INVCTR 0xB4 ;Display Inversion Control #Define LCD_PWCTR1 0xC0 ;Power Control 1 #Define LCD_PWCTR2 0xC1 ;Power Control 2 #Define LCD_PWCTR3 0xC2 ;Power Control 3 (In Normal mode/full colors) #Define LCD_PWCTR4 0xC3 ;Power Control 4 (In Idle mode/8 colors) #Define LCD_PWCTR5 0xC4 ;Power Control 5 (In Partial mode/full colors) #Define LCD_VMCTR1 0xC5 ;VCOM Control 1 #Define LCD_GMCTRP1 0xE0 ;Gamma '+' polarity Correction Characteristics Setting #Define LCD_GMCTRN1 0xE1 ;Gamma '-' polarity Correction Characteristics Setting ;LCD Interface lines #Define LCD_RESET LatC,1 ;Reset (Pulse low to reset LCD controller) #Define LCD_RS LatC,0 ;Data or command (high for data, low for command) #Define LCD_SCK LatC,6 ;SPI Clock, for bit-bang SPI #Define LCD_SDO LatC,7 ;SPI Data, for bit-bang SPI ;======================================; ; VARIABLE STORAGE ; ;======================================; Flags equ 0x00 ;Up to 8 gen purpose flag bits #Define SteepFlg Flags,0 ;Used in LCDDrwLn sub. #Define Spare1 Flags,1 #Define Spare2 Flags,2 #Define Spare3 Flags,3 #Define Spare4 Flags,4 #Define Spare5 Flags,5 #Define Spare6 Flags,6 #Define Spare7 Flags,7 DlyCnt equ 0x01 ;Counter for DlyWx10us subroutine X0 equ 0x02 ;Used in LCDDrwLn sub Y0 equ 0x03 ;Used in LCDDrwLn sub X1 equ 0x04 ;Used in LCDDrwLn sub Y1 equ 0x05 ;Used in LCDDrwLn sub X equ 0x06 ;Current pixel location. Used when drawing Y equ 0x07 ;a pixel or as start coord when drawing a line. XT equ 0x08 ;X target when drawing a line YT equ 0x09 ;Y target when drawing a line ColorL equ 0x0A ; rrrrrggg Current color setting in ColorH equ 0x0B ; gggbbbbb 16-bit format. DatCntrL equ 0x0C ;16-bit counter in LCDCls sub DatCntrH equ 0x0D DX equ 0x0E ;\ DY equ 0x0F ; \ ER equ 0x10 ; \ Temp equ 0x11 ; \ Working vars in LCDDrwLn sub XDif equ 0x12 ; / YStep equ 0x13 ; / XPt equ 0x14 ; / YPt equ 0x15 ;/ StrCntr equ 0x16 ;Counter for LCDStar routine. ;--------------------------------------------------------------------------------- ;=============================================; ; CODE BEGINS HERE ; ;=============================================; ; ;NOTE that I use a PIC development board that uses a bootloader for programming ;the PIC's Flash memory. Consequently, the reset and interrupt vectors are moved ;up in Flash by 0x800 addresses. Org 0x0800 ;Code starts after the bootloader BRA Begin Org 0x0808 ;Interrupt vector is relocated here by the bootloader RETFIE ;If by some chance an interrupt occurs, just return. Begin: RCall InitPorts ;Set up ports for operation ; RCall InitLCD ;Initialize the LCD display ; ; LCDStar: ;Here, for purposes of demonstration, is a routine to draw a series ;of lines radiating from a center point out to targets near the outer ;edges of the LCD display. ; ;Draw 11 white lines from center (X=65,Y=80) to a series ;of targets (X=10,20,...,110, Y=10) across the top of screen. RCall White ;Set color to white ; MOVLW 11 ;11 targets MOVWF StrCntr,A ; MOVLW 10 ;Initial X target = 10 MOVWF XT,A ; MOVLW 10 ;Y target for all 11 lines is 10 MOVWF YT,A ; StrLp1: ; MOVLW 65 ;Set the start point at X=65,Y=80 MOVWF X,A MOVLW 80 MOVWF Y,A ; RCall LCDDrwLn ;Draw the line ; MOVLW 10 ADDWF XT,F,A ;XT=XT+10 to create next target ; DECFSZ StrCntr,F,A;See if we are done. BRA StrLp1 ;Not done. Loop for more. ; ;Draw 14 red lines from center (X=65,Y=80) to a series of ;targets (X=120, Y=10,20,...,140) along right side of screen. RCall Red ;Select red color ; MOVLW 14 ;14 targets MOVWF StrCntr,A ; MOVLW 120 ;X target for all 14 lines is 120 MOVWF XT,A ; MOVLW 10 ;Initial Y target = 10 MOVWF YT,A ; StrLp2: ; MOVLW 65 ;Set the start point at X=65,Y=80 MOVWF X,A MOVLW 80 MOVWF Y,A ; RCall LCDDrwLn ;Draw the line ; MOVLW 10 ADDWF YT,F,A ;YT=YT+10 to create next target ; DECFSZ StrCntr,F,A;See if we are done. BRA StrLp2 ;Not done. Loop for more. ; ;Draw 11 green lines from center (X=65,Y=80) to a series ;of targets (X=120,110,...,20, Y=150) near bottom of screen. RCall Green ;Select green ; MOVLW 11 ;11 targets MOVWF StrCntr,A ; MOVLW 120 ;Initial X target = 120 MOVWF XT,A ; MOVLW 150 ;Y target for all 11 lines is 150 MOVWF YT,A ; StrLp3: ; MOVLW 65 ;Set the start point at X=65,Y=80 MOVWF X,A MOVLW 80 MOVWF Y,A ; RCall LCDDrwLn ;Draw the line ; MOVLW -10 ADDWF XT,F,A ;XT=XT-10 to create next target ; DECFSZ StrCntr,F,A;See if we are done. BRA StrLp3 ;Not done. Loop for more. ; ;Draw 14 blue lines from center (X=65,Y=80) to a series of ;targets (X=10, Y=150,140,...,20) along left side of screen. RCall Blue ; MOVLW 14 ;14 targets MOVWF StrCntr,A ; MOVLW 10 ;X target for all 14 lines is 10 MOVWF XT,A ; MOVLW 150 ;Initial Y target = 150 MOVWF YT,A ; StrLp4: ; MOVLW 65 ;Set the start point at X=65,Y=80 MOVWF X,A MOVLW 80 MOVWF Y,A ; RCall LCDDrwLn ;Draw the line ; MOVLW -10 ADDWF YT,F,A ;YT=YT-10 to create next target ; DECFSZ StrCntr,F,A;See if we are done. BRA StrLp4 ;Not done. Loop for more. ; EndLp: BRA EndLp ;Just hang here while human admires result. ;--------------------------------------------------------------------------------- ;------------------------------------; ; DELAY ROUTINE ; ;------------------------------------; ;This project uses a single delay subroutine. We want delays up to 500 ;microseconds and some short delays down around 10 microseconds. This ;routine delays for a period of time approximately 10 microseconds ;times the number in W. It assumes a 48 MHz system clock. ; DlyWx10us:MOVWF DlyCnt,A ;Save number of 10 usec periods to count. DlyLp1: MOVLW 40 ;40 loops of 3 instruction times each is 120 DlyLp2: DECFSZ WREG,F,A ;instruction times or 10 usec BRA DlyLp2 DECFSZ DlyCnt,F,A;Count that 10 usec period. Are we done? BRA DlyLp1 ;No. Keep going. RETURN ;Yes, done. Exit. ;--------------------------------------------------------------------------------- ;------------------------------------; ; INITPORTS ; ;------------------------------------; InitPorts:;Sub to initialize the hardware ports MOVLW 0x0E ;Disable A/D converter except for AN0 MOVWF ADCon1,A ; MOVLW 0x07 ;Disable the analog comparators. (Same as reset condition) MOVWF CmCon,A ; ;Now we mode I/O bits to be inputs or outputs as needed. ;Clearing a Tris bit makes it an output. Setting it makes it be an input. ; ;Port C MOVLW 0x3C ;Make outputs of C0 LCD_RS ANDWF TrisC,F,A ; C1 LCD_RESET ; ; C6 LCD_SCK ; ; C7 LCD_SDO ; MOVLW 0x3E ;Set all LCD outputs low except... ANDWF LatC,F,A BSF LatC,1,A ;... set LCD_RESET to high ; RETURN ;--------------------------------------------------------------------------------- ;------------------------------------; ; INITLCD ; ;------------------------------------; InitLCD: ;Sub to initialize the LCD display. BSF LCD_RESET,A;Create a pulse (high-to-low-to-high) MOVLW 50 ;to reset the LCD controller. RCall DlyWx10us ;500 usec high BCF LCD_RESET,A MOVLW 50 RCall DlyWx10us ;500 usec low BSF LCD_RESET,A MOVLW 50 RCall DlyWx10us ;500 usec high ; MOVLW Low(InitSeqnc) ;Point Rom pointer to the init sequence MOVWF TBLPTRL,A MOVLW High(InitSeqnc) MOVWF TBLPTRH,A CLRF TBLPTRU,A ; ;Read and send to the LCD, commands and associated parameters ;from a list in Flash memory. The ROM Pointer shows where the command ;sequence is stored. The first byte read via the pointer is a command ;byte. ; ;Following each command byte, the next byte in Flash indicates the ;number of bytes to be sent as data bytes (i.e., the parameters for ;the command). When the specified number of data bytes has been read ;and sent, the routine again expects to see another command byte. ; ;A command byte of 0xFF (which is not a command for the LCD controller) ;causes a program delay. The contents of the following byte times 10 ;is the number of microseconds to delay. The next byte following that ;is expected to be another command byte. ; ;A command byte of 0xFE (which is not a command for the LCD controller) ;causes no action and is used as a filler to permit each DB directive ;to start at a whole word boundary. The next byte following a filler ;byte is expected to be another command byte. ; ;A command byte of 0x00 (which would be a NOP for the LCD controller) ;passes control to the LCDCls routine to complete the LCD init action. ; LCDCmdLp: TBLRD*+ ;Fetch a cmd byte into TABLAT and inc TBLPTR INFSNZ TABLAT,F,A;Inc TABLAT & check if it had been FF BRA DoLCDDly ;It was FF so go make delay. INFSNZ TABLAT,W,A;Inc TABLAT again but only into W. (Check for FE.) BRA LCDCmdLp ;Yes. It was just a filler. Loop back for next cmd. DCFSNZ TABLAT,W,A;Dec TABLAT into W to see if it started out as zero BRA LCDCls ;It was zero so we are done. Go clear the screen. RCall LCDWrCmd ;Not delay and not zero so send it to LCD as cmd. TBLRD*+ ;Fetch the number of data bytes to follow cmd. INCF TABLAT,W,A;Inc and move the count to DatCntrL. Since we will ; ;be using a decrement instruction to step this ; ;counter down, incrementing the count up front lets ; ;us do the decrementing before the action being ; ;counted. That way, a count of zero is permitted ; ;when a cmd is encountered that needs no data bytes. MOVWF DatCntrL,A;Set the counter with the pre-incremented count. LCDDatLp: DCFSNZ DatCntrL,F,A;Dec DatCntrL to see if done w/ data bytes. BRA LCDCmdLp ;Done with data bytes. Loop back for next cmd. TBLRD*+ ;Fetch a data byte to TABLAT MOVF TABLAT,W,A;Load data byte into W RCall LCDWrDat ;and go send it as a data byte. BRA LCDDatLp ;Loop back for another data byte. ; DoLCDDly: TBLRD*+ ;Come here to create delay. Fetch delay period. MOVF TABLAT,W,A;Load delay period into W RCall DlyWx10us ;Delay 10 uSec times W BRA LCDCmdLp ;Loop back for the next cmd. LCDCLS: ;Sub to clear screen, i.e., write black to every pixel CLRF X,A ;Initial pixel is at X=0,Y=0. CLRF Y,A RCall LCDSetXY ; ;Set up 16-bit counter for total number of pixels in display MOVLW Low(ScrnWdth * ScrnHght) MOVWF DatCntrL,A MOVLW High(ScrnWdth * ScrnHght) MOVWF DatCntrH,A ; CLRF WREG,A ;0 is used to indicate black. LCDCLS1: RCall WrtSPIByt ;WrtSPIByt preserves W. 2 bytes of zero RCall WrtSPIByt ;means black. ; DECFSZ DatCntrL,F,A;Count that pixel. Are we done? BRA LCDCLS1 ;Not done. Keep going. DECFSZ DatCntrH,F,A;Decrement high byte. Are we done? BRA LCDCLS1 ;Not done. Keep going. RETURN ;Yes. Done. Return from subroutine. #Define Exit 0x00 ;Used to mark the end of the sequence. #Define Dly10usx 0xFF ;Causes a delay of 10 usec x data byte that follows #Define Filler 0xFE ;Does nothing & takes no data byte. InitSeqnc:;Here is the init sequence to be followed: ;Software reset ;Delay 150 uSec DB LCD_SWRESET,0, Dly10usx,15 ; ;Out of Sleep Mode ;Delay 500 uSec DB LCD_SLPOUT,0, Dly10usx,50 ; ;Set color mode + 1 data byte ; 5 3=12 bit/pixel, 5=16 bit/pixel, 6=18 bit/pixel ;Delay 10 uSec DB LCD_COLMOD,1,5, Dly10usx,1, Filler ; ;Frame rate control for Normal mode + 3 data bytes ; 0x01 Frame rate = fosc/(RTNAx2 + 40)*(LINE+0x2C+0x2D) ; 0x2C where RTNA=1, fosc=850kHz ; 0x2D DB LCD_FRMCTR1,3,0x01,0x2C,0x2D, Filler ; ;Frame rate control for Idle mode + 3 data bytes ; 0x01 Frame rate = fosc/(RTNAx2 + 40)*(LINE+0x2C+0x2D) ; 0x2C where RTNA=1, fosc=850kHz ; 0x2D DB LCD_FRMCTR2,3,0x01,0x2C,0x2D, Filler ; ;Frame rate control for Partial mode + 6 data bytes ; 0x01 Dot inversion mode ; 0x2C ; 0x2D ; 0x01 Line inversion mode ; 0x2C ; 0x2D DB LCD_FRMCTR3,6,0x01,0x2C,0x2D,0x01,0x2C,0x2D ; ;Display inversion control + 1 data byte ; 0x07 No inversion DB LCD_INVCTR,1,0x07, Filler ; ;Power control #1 + 3 data bytes ; 0xA2 AVDD=5.0V, GVDD=4.6V ; 0x02 GVCL=-4.6V ; 0x84 AUTO mode DB LCD_PWCTR1,3,0xA2,0x02,0x84, Filler ; ;Power control #2 + 1 data byte ; 0xC5 VGH25=2.4, VGL=-10, VGH=3*AVDD-0.5 DB LCD_PWCTR2,1,0xC5, Filler ; ;Power control #3 (In Norml Mode/full colors) + 2 data bytes ; 0x0A AP: OpAmp current medium low ; SAP: OpAmp current small ; 0x00 Boost frequency DB LCD_PWCTR3,2,0x0A,0x00 ; ;Power control #4 (In Idle Mode/8 colors) + 2 data bytes ; 0x8A BCLK/2, Opamp current small & Medium low ; 0x2A DB LCD_PWCTR4,2,0x8A,0x2A ; ;Power control #5 (In Partial Mode/full colors)+ 2 data bytes ;0x8A ;0xEE DB LCD_PWCTR5,2,0x8A,0xEE ; ;VCOM power control + 1 data byte ; 0x0E VCOM voltage = -0.775V DB LCD_VMCTR1,1,0x0E, Filler ; ;Don't invert display + 0 data bytes DB LCD_INVOFF,0 ; ;Memory access control (directions) + 1 data byte ; 0xC0 If red & blue are swapped, change to 0xC8 ; Set Row addr dir, col addr dir. ; Both 0xC0 and 0xC8 cause top-to-bot & ; left-to-right refresh. DB LCD_MADCTL,1,0xC0, Filler ; ;Set Color mode + 1 data byte ; 5 3=12 bit/pixel, 5=16 bit/pixel, 6=18 bit/pixel DB LCD_COLMOD,1,5, Filler ; ;Column Addr Set + 4 data bytes ; 0 XStart (H) ; 0 XStart (L) = 0 ; 0 XEnd (H) ; ScrnWdth-1 XEnd (L) = 127 DB LCD_CASET,4,0,0,0,ScrnWdth-1 ; ;Row Addr Set + 4 data bytes ; 0 YStart (H) ; 0 YStart (L) = 0 ; 0 YEnd (H) ; ScrnHght-1 YEnd (L) = 159 DB LCD_RASET,4,0,0,0,ScrnHght-1 ; ;Set Gamma control (+ polarity) + 16 data bytes ; 0x0F These are the 16 + polarity ; 0x1A gamma correction settings. ; 0x0F ; 0x18 ; 0x2F ; 0x28 ; 0x20 ; 0x22 ; 0x1F ; 0x1B ; 0x23 ; 0x37 ; 0x00 ; 0x07 ; 0x02 ; 0x10 DB LCD_GMCTRP1,16,0x0F,0x1A,0x0F,0x18,0x2F,0x28,0x20,0x22 DB 0x1F,0x1B,0x23,0x37,0x00,0x07,0x02,0x10 ; ;Set Gamma control (- polarity) + 16 data bytes ; 0x0F These are the 16 - polarity ; 0x1B gamma correction settings. ; 0x0F ; 0x17 ; 0x33 ; 0x2C ; 0x29 ; 0x2E ; 0x30 ; 0x30 ; 0x39 ; 0x3F ; 0x00 ; 0x07 ; 0x03 ; 0x10 DB LCD_GMCTRN1,16,0x0F,0x1B,0x0F,0x17,0x33,0x2C,0x29,0x2E DB 0x30,0x30,0x39,0x3F,0x00,0x07,0x03,0x10 ; ;Display on + 0 data bytes ;Delay 100 uSec ;Normal display mode + 0 data bytes ;Delay 10 uSec DB LCD_DISPON,0, Dly10usx,10, LCD_NORON,0, Dly10usx,1 ; ;Column address set + 4 data bytes ; 0 XStart (H) ; 0 XStart (L) XStart = 0 ; 0 XEnd (H) ; ScrnWdth-1 XEnd (L) XEnd = 127 DB LCD_CASET,4,0,0,0,ScrnWdth-1 ; ;Row address set + 4 data bytes ; 0 YStart (H) ; 0 YStart (L) YStart = 0 ; 0 YEnd (H) ; ScrnHght-1 YEnd (L) YEnd = 159 DB LCD_RASET,4,0,0,0,ScrnHght-1 ; ;Exit DB Exit, Filler ;NOTE: During initialization of the LCD controller chip, we set the boundaries ;of the active window of the LCD to cover the entire LCD area. That means ;the XEnd and YEnd values are set to the far right edge and the very bottom ;edge of the LCD screen. By never updating XEnd and YEnd, we can move only ;the XStart and YStart coordinates around as needed and plot points. LCDSetXY: ;Sub to show the LCD controller the upper left corner of active ;window. The coordinates are provided in X and Y. MOVLW LCD_CASET ;Column addr set RCall LCDWrCmd CLRF WREG,A ;XStart (H) RCall LCDWrDat MOVF X,W,A ;XStart (L) RCall LCDWrDat ; MOVLW LCD_RASET ;Row addr set RCall LCDWrCmd CLRF WREG,A ;YStart (H) RCall LCDWrDat MOVF Y,W,A ;YStart (L) RCall LCDWrDat ; MOVLW LCD_RAMWR ;Write to RAM (enables writing image data to RAM) RCall LCDWrCmd BSF LCD_RS,A ;High indicates to LCD that data is coming RETURN LCDWrCmd: ;Sub to send the byte in W to LCD as a command BCF LCD_RS,A ;Low indicates a command being sent BRA WrtSPIByt ;Send W as SPI byte LCDWrDat: ;Sub to send the byte in W to LCD as data BSF LCD_RS,A ;High indicates data being sent BRA WrtSPIByt ;Send W as SPI byte LCDDrwPxl:;Sub to set current color into the pixel at X,Y RCall LCDSetXY ; LCDWrCol: ;Sub to send the current color to LCD as 2 data bytes MOVF ColorH,W,A RCall WrtSPIByt MOVF ColorL,W,A ; WrtSPIByt:;Sub to transmit the byte in W via bit bang SPI. Preserves W. ;Transmission is serial, 8 bits, starting with the most ;significant bit. BCF LCD_SDO,A ;Clear the data out pin to zero. BCF LCD_SCK,A ;Clear the clock pin to zero. BTFSC WREG,7,A ;If m.s. bit is 0, skip setting data out pin BSF LCD_SDO,A ;m.s. bit was 1 so set data out pin. BSF LCD_SCK,A ;Set clock to 1 to clock data bit into LCD. ; BCF LCD_SDO,A ;Repeat the same set of operations in turn BCF LCD_SCK,A ;for each of the remaining 7 bits. BTFSC WREG,6,A BSF LCD_SDO,A BSF LCD_SCK,A ; BCF LCD_SDO,A BCF LCD_SCK,A BTFSC WREG,5,A BSF LCD_SDO,A BSF LCD_SCK,A ; BCF LCD_SDO,A BCF LCD_SCK,A BTFSC WREG,4,A BSF LCD_SDO,A BSF LCD_SCK,A ; BCF LCD_SDO,A BCF LCD_SCK,A BTFSC WREG,3,A BSF LCD_SDO,A BSF LCD_SCK,A ; BCF LCD_SDO,A BCF LCD_SCK,A BTFSC WREG,2,A BSF LCD_SDO,A BSF LCD_SCK,A ; BCF LCD_SDO,A BCF LCD_SCK,A BTFSC WREG,1,A BSF LCD_SDO,A BSF LCD_SCK,A ; BCF LCD_SDO,A BCF LCD_SCK,A BTFSC WREG,0,A BSF LCD_SDO,A BSF LCD_SCK,A ; RETURN LCDDrwLn: ;Sub to draw a line from X,Y to XT,YT using the current color. ;XT,YT remain unchanged. Upon exit, X,Y equals the XT,YT. MOVFF X,X0 ;Move the end points to some working MOVFF Y,Y0 ;variables that we can mangle up in MOVFF XT,X1 ;the process of drawing the line. MOVFF YT,Y1 ; ;Bresenham's Algorithm - This algorithm draws a straight ;line between X0,Y0 and X1,Y1 using only integer arithmetic. ;However, it does destroy X0,Y0,X1, and Y1 in the process. ; ;The algorithm: ; SteepFlg = ABS(Y1 - Y0) > ABS(X1 - X0) ; IF SteepFlg THEN SWAP X0, Y0: SWAP X1, Y1 ; IF X0 > X1 THEN SWAP X0, X1: SWAP Y0, Y1 ; DX = X1 - X0 ; DY = ABS(Y1 - Y0) ; ER = DX / 2 ; YPt = Y0 ; IF Y0 < Y1 THEN YStep = 1 ELSE YStep = -1 ; FOR XPt = X0 TO X1 ; IF SteepFlg THEN PSET(YPt,XPt) ELSE PSET(XPt,YPt) ; ER = ER - DY ; IF ER < 0 THEN YPt = YPt + YStep: ER = ER + DX ; NEXT ; BCF SteepFlg,A;SteepFlg = ABS(Y1 - Y0) > ABS(X1 - X0) MOVF X0,W,A SUBWF X1,W,A BTFSS Status,C,A NEGF WREG,A MOVWF XDif,A MOVF Y0,W,A SUBWF Y1,W,A BTFSS Status,C,A NEGF WREG,A SUBWF XDif,W,A BTFSS Status,C,A BSF SteepFlg,A ; BTFSS SteepFlg,A;IF SteepFlg THEN SWAP X0, Y0: SWAP X1, Y1 BRA LCDDL1 MOVFF X0,Temp MOVFF Y0,X0 MOVFF Temp,Y0 MOVFF X1,Temp MOVFF Y1,X1 MOVFF Temp,Y1 LCDDL1: ; MOVF X1,W,A ;IF X0 > X1 THEN SWAP X0, X1: SWAP Y0, Y1 CPFSGT X0,A BRA LCDDL2 MOVFF X0,Temp MOVFF X1,X0 MOVFF Temp,X1 MOVFF Y0,Temp MOVFF Y1,Y0 MOVFF Temp,Y1 LCDDL2: ; MOVFF X1,DX ;DX = X1 - X0 MOVF X0,W,A SUBWF DX,F,A ; MOVFF Y1,DY ;DY = ABS(Y1 - Y0) MOVF Y0,W,A SUBWF DY,F,A CPFSGT Y1,A NEGF DY,A ; BCF Status,C,A;ER = DX / 2 (Due to steps above, DX must be positive) RRCF DX,W,A MOVWF ER,A ; MOVFF Y0,YPt ;YPt = Y0 ; SETF YStep,A ;IF Y0 < Y1 THEN YStep = +1 ELSE YStep = -1 MOVF Y1,W,A CPFSGT Y0,A NEGF YStep,A ; MOVFF X0,XPt ;FOR XPt = X0 TO X1 LCDDL3: ; MOVFF YPt,X ;IF SteepFlg THEN PSET(YPt, XPt) ELSE PSET(XPt, YPt) MOVFF XPt,Y BTFSC SteepFlg,A BRA LCDDL4 MOVFF XPt,X MOVFF YPt,Y LCDDL4: RCall LCDDrwPxl ; MOVF DY,W,A ;ER = ER - DY SUBWF ER,F,A ; BTFSS Status,N,A;IF ER < 0 THEN YPt = YPt + YStep: ER = ER + DX BRA LCDDL5 MOVF YStep,W,A ADDWF YPt,F,A MOVF DX,W,A ADDWF ER,F,A LCDDL5: ; INCF XPt,F,A ;NEXT DECF XPt,W,A CPFSEQ X1,A BRA LCDDL3 ; ;Arrive here when the line has been completed. ; ;The target now becomes the current X,Y location. MOVFF XT,X MOVFF YT,Y RETURN ;--------------------------------------------------------------------------------- ;Here are some color selection subroutines. Many more are possible. White: ;Sub to set the current color to white SETF ColorL,A SETF ColorH,A RETURN Blue: ;Sub to set the current color to blue MOVLW 0x1F MOVWF ColorL,A CPFSEQ WREG,A ;i.e., skip always Black: ;Sub to set the current color to black CLRF ColorL,A CLRF ColorH,A RETURN Red: ;Sub to set the current color to red CLRF ColorL,A MOVLW 0xF8 BRA Green1 Green: ;Sub to set the current color to green MOVLW 0xE0 MOVWF ColorL,A MOVLW 0x07 Green1: MOVWF ColorH,A RETURN END