- title "PIC16F870 Unilink Interface by Werner Johansson (c) 2003"\r
+ title "PIC16F870 Unilink(R) Interface by Werner Johansson (c) 2003"\r
subtitl "Definitions"\r
- list c=132,P=16F870,R=DEC,F=inhx8m\r
+ list c=150,P=16F870,R=DEC,F=inhx8m\r
include "p16f870.inc" ; Standard equates & Macros\r
ERRORLEVEL 1,-302 ; Get rid of those annoying 302 msgs!\r
\r
__CONFIG _HS_OSC&_WDT_OFF&_PWRTE_ON&_BODEN_ON&_LVP_OFF&_CPD_OFF&_WRT_ENABLE_ON&_DEBUG_OFF&_CP_OFF\r
\r
;----------------------------------------------------------------\r
-; HISTORY\r
+; TODO\r
+;----------------------------------------------------------------\r
+; BUSON OUT control isn't implemented\r
+; No checksum checking is done on incoming packets\r
+; Investigate whether we actually have to save PCLATH in ISH, maybe save FSR?\r
+; Move RS232 code into ISH\r
+; Check Overrun errors from the UART\r
+; Implement Bus re-initialize command\r
+; Implement lots of other Unilink commands\r
+\r
+;----------------------------------------------------------------\r
+; HISTORY\r
;----------------------------------------------------------------\r
; Version\r
;\r
+; 0.2 First attempt at responding to the Anyone command\r
; 0.1 Receives Unilink data OK, relays it to serial\r
; 0.0 Very first "Fucking No Work!" version\r
-;\r
+\r
+;----------------------------------------------------------------\r
+; I/O LAYOUT\r
;----------------------------------------------------------------\r
+; Unilink BUSON IN (blue) connected to RC2/CCP1\r
+; Unilink DATA (green) connected to RC3\r
+; Unilink BUSON OUT (blue) connected to RC4 (this is for daisy-chaining)\r
+; Unilink CLK (yellow) connected to RB0/INT (Interrupt pin)\r
+; Unilink RST (lilac) connected to RA4\r
+; LCD RS connected to pin RB1\r
+; LCD RW connected to pin RB2\r
+; LCD E connected to pin RB3\r
+; LCD DB4-DB7 connected to RB4-RB7\r
+; RS-232 TX from computer connected to RC7/RX\r
+; RS-232 RX to computer connected to RC6/TX\r
+; RS-232 RI to computer connected to RC5\r
+;\r
+; This leaves RC0, RC1 and the analog inputs (AN0-AN4) free for now...\r
\r
-; Unilink BUSON IN (blue) connected to RC2/CCP1\r
-; Unilink DATA (green) connected to RC3\r
-; Unilink BUSON OUT (blue) connected to RC4 (this is for daisy-chaining)\r
-; Unilink CLK (yellow) connected to RB0/INT (Interrupt pin)\r
-; Unilink RST (lilac) connected to RA4\r
-; LCD RS connected to pin RB1\r
-; LCD RW connected to pin RB2\r
-; LCD E connected to pin RB3\r
-; LCD DB4-DB7 connected to RB4-RB7\r
-; RS-232 TX from computer connected to RC7/RX\r
-; RS-232 RX to computer connected to RC6/TX\r
-; RS-232 RI to computer connected to RC5\r
-\r
-; This leaves RC0, RC1 and the analog inputs (AN0-AN4) free for now...\r
+#define BUSON_IN_BIT PORTC,2\r
+#define DATA_BIT PORTC,3\r
+#define BUSON_OUT_BIT PORTC,4\r
+#define CLK_BIT PORTB,0\r
+#define RST_BIT PORTA,4\r
\r
#define LCD_RS_BIT PORTB,1\r
#define LCD_RW_BIT PORTB,2\r
#define LCD_DB6_BIT PORTB,6\r
#define LCD_DB7_BIT PORTB,7\r
\r
-;----------------------------------------------------------------\r
-; File register usage\r
+#define RS232_RI_BIT PORTC,5\r
\r
-Dcount equ 20h\r
-e_LEN equ 21h\r
-Icount equ 2Dh ; Offset of string to print\r
-TxTemp equ 2Eh ; blahblah\r
-TxTemp2 equ 2Fh ; Blahblah2\r
-\r
-LCDWTmp equ 30h\r
-Dcount2 equ 31h\r
-temp equ 32h\r
-\r
-DataCount equ 33h\r
-DataStore equ 34h\r
-\r
-IRQW equ 7fh\r
-IRQSTATUS equ 7eh\r
-IRQPCLATH equ 7dh\r
+;----------------------------------------------------------------\r
+; FILE REGISTER USAGE\r
+;----------------------------------------------------------------\r
+Dcount equ 20h\r
+e_LEN equ 21h\r
+Icount equ 2Dh ; Offset of string to print\r
+TxTemp equ 2Eh ; blahblah\r
+TxTemp2 equ 2Fh ; Blahblah2\r
+\r
+LCDWTmp equ 30h\r
+Dcount2 equ 31h\r
+temp equ 32h\r
+\r
+DataCount equ 33h ; Temp storage for the bit counter used during bit shifts (Unilink TX/RX)\r
+DataStore equ 34h ; This is a kludge\r
+\r
+UnilinkSelected equ 3bh\r
+UnilinkBit equ 3ch ; This is my "bitmask" to be used for requests\r
+UnilinkID equ 3dh ; This is my Bus ID\r
+UnilinkCmdLen equ 3eh ; This gets updated with the actual packet length after CMD1 has been received\r
+UnilinkTXRX equ 3fh ; This is a pointer to the Unilink packet below, used with indirect addressing\r
+\r
+UnilinkRAD equ 40h ; Beginning of Unilink packet - the Receiving Address\r
+UnilinkTAD equ 41h ; Transmitter address\r
+UnilinkCMD1 equ 42h ; CMD1 byte\r
+UnilinkCMD2 equ 43h ; CMD2 byte\r
+UnilinkParity1 equ 44h ; First or only parity byte for short packets (6 bytes)\r
+UnilinkData1 equ 45h ; Extra data for medium/large packets, or zero for short packets\r
+UnilinkData2 equ 46h ;\r
+UnilinkData3 equ 47h ;\r
+UnilinkData4 equ 48h ;\r
+UnilinkData5 equ 49h ; Data5 if this is a large packet\r
+UnilinkParity2M equ 49h ; Parity2 shares the same byte if it's a medium sized packet\r
+UnilinkData6 equ 4ah ; Extra data for large packets, or zero for medium packets\r
+UnilinkData7 equ 4bh ;\r
+UnilinkData8 equ 4ch ;\r
+UnilinkData9 equ 4dh ;\r
+UnilinkParity2 equ 4eh ; Parity byte for large packets\r
+UnilinkZero equ 4fh ; Should always be zero (possibly used to signal corrupt packets from slave to master?)\r
+\r
+IRQPCLATH equ 7dh ; ISH storage\r
+IRQSTATUS equ 7eh ; Needs to be located in a shared area accessible from all register banks\r
+IRQW equ 7fh ; \r
\r
subtitl "Startup"\r
page\r
;----------------------------------------------------------------\r
; Power up/Reset starting point [den rulerar]\r
\r
- org 0\r
- call Bootstrap ; Call Flash Load routine\r
- call LCDInit ; Initialize LCD I/F\r
- call IRQInit ; Set up and start the IRQ handler\r
- goto Main ; Run the main program loop (skip the IRQ handler)\r
+ org 0 ; Start at the beginning of memory (the reset vector)\r
+ call Bootstrap ; Call Flash Load routine\r
+ call LCDInit ; Initialize LCD I/F\r
+ call IRQInit ; Set up and start the IRQ handler\r
+ goto Main ; Run the main program loop (skip the IRQ handler)\r
\r
subtitl "IRQ Handler"\r
;----------------------------------------------------------------\r
; Interrupt handler always starts at addr 4\r
+; In order to save one instruction cycle we put the actual code here directly instead of a goto instruction\r
\r
- org 4 ; Must be on Address 4!\r
- movwf IRQW ; Save W\r
- swapf STATUS,w ; Get the status register into w\r
- clrf STATUS ; Zero out the status reg, gives us Bank0 all the time\r
- movwf IRQSTATUS\r
- movf PCLATH,w\r
- movwf IRQPCLATH\r
- clrf PCLATH\r
+ org 4 ; ISR vector is at address 4\r
+ movwf IRQW ; Save W\r
+ swapf STATUS,w ; Get the status register into w\r
+ clrf STATUS ; Zero out the status reg, gives us Bank0 all the time\r
+ movwf IRQSTATUS ; Store the STATUS reg\r
+ movf PCLATH,w ; Get the PCLATH reg\r
+ movwf IRQPCLATH ; And store it\r
+ clrf PCLATH ; Go to low memory\r
+; Maybe save FSR here as well (if there's a need for it in the non-ISR code)\r
\r
- btfss INTCON,INTF ; Check if it's INT (CLK)\r
- goto IRQNotINT ; Nope\r
+ btfss INTCON,INTF ; Check if it's the INT edge interrupt (Unilink CLK)\r
+ goto IRQNotINT ; No it's not, check the other sources\r
\r
; If there's activity on the clock line (the clock goes high) we stay in here until we have clocked eight bits\r
; - this saves us a lot of context switching (and it's just a few hundred cpu cycles after all (20us*8 bits=\r
; 6250 bytes per second from the UART, and the 2-byte FIFO somehow fills up (this should be impossible even @ 115200\r
; as we're only calling this blocking INT handler a maximum of 1000 times per second, halting INT's for 1/6250 of a second,\r
; this gives the CPU ample of time to deal with all bytes from the USART. I'm checking the OERR (Serial Overrun) bit\r
-; to catch this though..\r
+; to catch this though.. Note that this piece of code does both TX and RX at the same time (in order to receive packets\r
+; one has to make sure that the packet buffer is zeroed out before entering here, otherwise collisions will occur..\r
+; According to my logic analyzer this implementation is pretty decent when it comes to timing, even though it's a\r
+; interrupt driven software based USART - by trigging the interrupt on the rising edge we buy us some extra time here\r
+; (the clock goes high 10us before the master clocks the bit in (on the falling edge), that should be plenty of time..)\r
\r
- movlw 8 ; Loop this many times\r
+ movlw 8 ; Loop through the 8 bits\r
movwf DataCount\r
-\r
-CLKWaitHigh\r
- btfss PORTC,2 ; Check for BUSON\r
- goto IRQAfterINT\r
- btfss PORTB,0 ; Wait for clock to go high\r
- goto CLKWaitHigh\r
-\r
-CLKWaitLow\r
+ movf UnilinkTXRX,w ; Get the pointer\r
+ movwf FSR ; Store it to make use of indirect addressing\r
+\r
+IRQINTBitSet\r
+ btfss INDF,7 ; Test high bit of data (that's the first bit to be clocked out)\r
+ goto IRQINTTristate ; Bit is low, we should tristate bit\r
+ bcf PORTC,3 ; Otherwise set DATA bit low\r
+ bsf STATUS,RP0 ; Select high regs\r
+ bcf TRISC,3 ; And pull low (now it's an output)\r
+ bcf STATUS,RP0 ; Back to regbank 0\r
+ goto IRQINTCLKWaitLow ; Wait for master to actually clock this bit in\r
+\r
+IRQINTTristate\r
+ bsf STATUS,RP0 ; Select high regs\r
+ bsf TRISC,3 ; Force the bit to be tristated\r
+ bcf STATUS,RP0 ; Back to regbank 0\r
+\r
+IRQINTCLKWaitLow\r
btfss PORTC,2 ; Check for BUSON\r
goto IRQAfterINT\r
btfsc PORTB,0 ; Wait for clock to go low\r
- goto CLKWaitLow\r
+ goto IRQINTCLKWaitLow\r
\r
clrc ; Clear carry (this way the DataStore byte doesn't have to be cleared before)\r
btfss PORTC,3 ; Test DATA\r
setc ; Set carry if data is LOW (data is inverted!)\r
- rlf DataStore,f ; Shift it into our accumulator\r
+ rlf INDF,f ; Shift it into our accumulator\r
\r
decfsz DataCount,f ; Loop once more perhaps?\r
- goto CLKWaitHigh\r
+ goto IRQINTCLKWaitHigh ; Yes, again!\r
+ goto IRQINTRecvDone ; No we're done, don't check for clock to go high again\r
+\r
+IRQINTCLKWaitHigh\r
+ btfss PORTC,2 ; Check for BUSON\r
+ goto IRQAfterINT\r
+ btfss PORTB,0 ; Wait for clock to go high\r
+ goto IRQINTCLKWaitHigh\r
+ goto IRQINTBitSet ; Loop again\r
\r
; Successfully received a byte here, run it through a state machine to figure out what to do\r
; (several possibilites exists here:\r
-; If more than 1.1ms has passed since last receive, reset receive counter to zero\r
+;;;;;; If more than 1.1ms has passed since last receive, reset receive counter to zero\r
; If receive counter is zero and the received byte is a zero byte, discard it\r
; Otherwise store the byte in our receive buffer and increment receive counter\r
; If the receive counter is 3 check the two upper bits of recv'd byte (CMD1) - this tells us the length of the packet\r
; 10 = medium 11 byte packet\r
; 11 = long 16 byte packet\r
; Update the receive length byte accordingly\r
-; Check whether receive length and receive count are equal, that means that we're finished, flag this by setting \r
-; the high bit of receive length\r
+; Check whether receive length and receive count are equal, that means that we're finished and we can carry on parsing\r
+; the packet and take appropriate action.\r
+\r
+IRQINTRecvDone\r
+ movf UnilinkTXRX,w ; Find out which byte we got\r
+ andlw 0fh ; Mask\r
+ bnz IRQINTRecvNotFirst ; Not the first byte\r
+ movf UnilinkRAD,w ; Get the first byte received\r
+ bz IRQINTRecvNullByte ; Null byte received, ignore this, don't increment counter\r
+IRQINTRecvNotFirst\r
+ incf UnilinkTXRX,f ; Increment address\r
+\r
+ movf UnilinkTXRX,w ; Get the byte position again\r
+ andlw 0fh ; Only lower 4 bits of interest\r
+ xorlw 03h ; Well, is it the third byte? (CMD1, telling us the length of the packet)\r
+ bnz IRQINTRecvNotCMD1 ; No, skip the length code for now\r
+ movlw 6 ; Assume it's a short packet\r
+ btfss INDF,7 ; INDF still points to received byte, test high bit for medium/long\r
+ goto IRQINTRecvShort ; Nope, it's a short packet\r
+ addlw 5 ; OK, it's long or medium at least\r
+ btfsc INDF,6 ; Test for long\r
+ addlw 5 ; Yep, it's a long packet\r
+IRQINTRecvShort\r
+ movwf UnilinkCmdLen ; Store the length\r
+\r
+IRQINTRecvNotCMD1\r
+ movf UnilinkTXRX,w ; Get the byte position\r
+ xorwf UnilinkCmdLen,w ; XOR with the calculated command length\r
+ andlw 0fh ; and mask - this results in a zero result when finished receiving\r
+ bnz IRQINTRecvIncomplete ; Packet not ready yet\r
+\r
+; Here we actually have received a packet, should check the checksum(s) as well, but I don't care right now\r
+; (I need music in my car! :))\r
+; This is inefficient, I know, I'll improve it later... (Not that it matters, we have plenty of time here\r
+; (there can't be any more communication for another 4.8ms))\r
+\r
+; Unilink command parser:\r
+\r
+; Check for CMD1 = 01h (System bus commands)\r
+ movf UnilinkCMD1,w\r
+ xorlw 01h\r
+ bnz IRQINTParseNot01\r
+\r
+; Check for 01 02 (Anyone)\r
+ movf UnilinkCMD2,w\r
+ xorlw 02h\r
+ bnz IRQINTParseNot0102\r
+\r
+ movf UnilinkID,w ; Do I have an ID already?\r
+ bnz IRQINTParseNot0102 ; Yep, I don't want another one!\r
+\r
+ movlw 10h ; Sending to Master\r
+ movwf UnilinkRAD\r
+ movlw 0d0h ; I'm in the MD changer group\r
+ movwf UnilinkTAD\r
+ movlw 8ch ; Device discovery command reply\r
+ movwf UnilinkCMD1\r
+ movlw 00h ; 00??\r
+ movwf UnilinkCMD2\r
+ movlw 6ch ; Hard coded parity (!)\r
+ movwf UnilinkParity1\r
+ movlw 24h ; My internal MD sends 25 here first time, and then 24 when appointed!??\r
+ movwf UnilinkData1\r
+ movlw 2ch ; 2c??\r
+ movwf UnilinkData2\r
+ movlw 22h ; 22??\r
+ movwf UnilinkData3\r
+ movlw 00h ; 00??\r
+ movwf UnilinkData4\r
+ movlw 0deh ; Hard coded parity 2 (!)\r
+ movwf UnilinkData5\r
+ clrf UnilinkData6\r
+ goto IRQINTParseBypassClear ; We don't want to clear the data, we want to send what's in the buffer next time\r
+\r
+IRQINTParseNot0102\r
+\r
+; Check for 01 12 (Time poll)\r
+ movf UnilinkCMD2,w\r
+ xorlw 12h\r
+ bnz IRQINTParseNot0112\r
+\r
+ movf UnilinkRAD,w\r
+ xorwf UnilinkID,w ; Is it for us?\r
+ bnz IRQINTParseNot0112 ; nope\r
+\r
+ clrf UnilinkParity1\r
+ movlw 10h ; Sending to Master\r
+ addwf UnilinkParity1,f\r
+ movwf UnilinkRAD\r
+ movf UnilinkID,w ; This is my ID\r
+ addwf UnilinkParity1,f\r
+ movwf UnilinkTAD\r
+ movlw 00h\r
+ addwf UnilinkParity1,f\r
+ movwf UnilinkCMD1\r
+\r
+ movlw 80h ; We're idle unless selected\r
+ btfsc UnilinkSelected,7 \r
+ clrw\r
+ \r
+ addwf UnilinkParity1,f\r
+ movwf UnilinkCMD2\r
+ clrf UnilinkData6\r
+ goto IRQINTParseBypassClear ; We don't want to clear the data, we want to send!\r
+\r
+IRQINTParseNot0112\r
+\r
+IRQINTParseNot01\r
+\r
+; Check for CMD1 = 02h (Appoint)\r
+ movf UnilinkCMD1,w\r
+ xorlw 02h\r
+ bnz IRQINTParseNot02\r
+\r
+ movf UnilinkRAD,w ; Get the ID the master has given us\r
+ movwf UnilinkID ; Store my id\r
+ movf UnilinkCMD2,w ; Get the bitmask\r
+ movwf UnilinkBit ; And store it (this is needed when doing slave breaks and actually responding)\r
+\r
+ clrf UnilinkParity1\r
+ movlw 10h ; Sending to Master\r
+ addwf UnilinkParity1,f\r
+ movwf UnilinkRAD\r
+ movf UnilinkID,w ; This is my ID\r
+ addwf UnilinkParity1,f\r
+ movwf UnilinkTAD\r
+ movlw 8ch ; Device discovery command again\r
+ addwf UnilinkParity1,f\r
+ movwf UnilinkCMD1\r
+ movlw 00h\r
+ addwf UnilinkParity1,f\r
+ movwf UnilinkCMD2\r
+\r
+ movf UnilinkParity1,w\r
+ movwf UnilinkParity2M ; That's the parity when sending medium messages\r
+\r
+ movlw 24h\r
+ addwf UnilinkParity2M,f\r
+ movwf UnilinkData1\r
+ movlw 2ch ; My internal MD sends 1c here... (external/internal or 1/10 disc difference?)\r
+ addwf UnilinkParity2M,f\r
+ movwf UnilinkData2\r
+ movlw 22h\r
+ addwf UnilinkParity2M,f\r
+ movwf UnilinkData3\r
+ movlw 00h\r
+ addwf UnilinkParity2M,f\r
+ movwf UnilinkData4\r
+\r
+ clrf UnilinkData6\r
+ goto IRQINTParseBypassClear ; We don't want to clear the data, we want to send!\r
+\r
+IRQINTParseNot02\r
+\r
+; Check for CMD1 = f0h (Source Select)\r
+ movf UnilinkCMD1,w\r
+ xorlw 0f0h\r
+ bnz IRQINTParseNotF0\r
+\r
+ movf UnilinkCMD2,w\r
+ xorwf UnilinkID,w ; Check if it's selecting us\r
+ bnz IRQINTParseF0Deselect\r
+\r
+ bsf UnilinkSelected,7 ; Now we're selected\r
+ goto IRQINTParseNotF0\r
+\r
+IRQINTParseF0Deselect\r
+\r
+ bcf UnilinkSelected,7 ; Now we're de-selected\r
+ goto IRQINTParseNotF0\r
+\r
+IRQINTParseNotF0\r
+\r
+; We end up here when parsing is complete and we're not interested in sending any reply back to the master\r
+; (that's why we clear out all the packet buffer bytes)\r
+; TODO: Replace this with an FSR access to save space and make the code neater\r
+\r
+ clrf UnilinkRAD\r
+ clrf UnilinkTAD\r
+ clrf UnilinkCMD1\r
+ clrf UnilinkCMD2\r
+ clrf UnilinkParity1\r
+ clrf UnilinkData1\r
+ clrf UnilinkData2\r
+ clrf UnilinkData3\r
+ clrf UnilinkData4\r
+ clrf UnilinkData5\r
+ clrf UnilinkData6\r
+ clrf UnilinkData7\r
+ clrf UnilinkData8\r
+ clrf UnilinkData9\r
+ clrf UnilinkParity2\r
+ clrf UnilinkZero\r
+\r
+IRQINTParseBypassClear\r
+\r
+ movlw UnilinkRAD ; Get the pointer to the first byte in the receive buffer\r
+ movwf UnilinkTXRX ; Store it - this way the next byte that gets received goes into RAD\r
+\r
+ clrf UnilinkCmdLen ; No command length as we're waiting for a new packet\r
\r
-IRQAfterINT\r
+ \r
+IRQINTRecvIncomplete\r
\r
- bcf INTCON,INTF ; Clear our IRQ\r
+IRQINTRecvNullByte\r
+ movf INDF,w\r
+ movwf DataStore ; Store it so our non-irq code can snoop\r
+\r
+IRQAfterINT\r
+ bcf INTCON,INTF ; Clear our IRQ source bit so we can receive new bits again\r
\r
IRQNotINT\r
\r
+; Finally restore CPU state and return from the ISR\r
movf IRQPCLATH,w\r
movwf PCLATH ; Restore PCLATH\r
swapf IRQSTATUS,w\r
retfie ; Interrupt return\r
\r
\r
-\r
subtitl "Main loop"\r
page\r
\r
; Data can be stored between here and 100h...\r
\r
StartUpText1\r
- DT "-WJ UniLink I/F-"\r
-StartUpText2\r
- DT "Code and design:"\r
-StartUpText3\r
- DT "**TCC of Yodel**"\r
-\r
+ DT "----- WJ UniLink"\r
\r
LookUp movwf PCL ; Go to it\r
\r
org 100h\r
Main\r
\r
- bsf STATUS,RP0\r
+ bsf RS232_RI_BIT ; We want RI to be high (inverted logic, not set)\r
+ bcf BUSON_OUT_BIT ; But we don't want BUSON_OUT on just yet, we need to be appointed first\r
+\r
+ bsf STATUS,RP0 ; Select bank 1\r
+\r
+ bcf RS232_RI_BIT ; Both bits should be outputs at least\r
+ bcf BUSON_OUT_BIT ;\r
+\r
+; bcf STATUS,RP0\r
+; bsf STATUS,RP0\r
+\r
bsf TXSTA,TXEN ; Enable UART TX\r
bcf STATUS,RP0 ; Back to bank 0\r
\r
bsf RCSTA,SPEN ; Enable serial port\r
bsf RCSTA,CREN ; Enable UART RX\r
\r
+; Replace this with an FSR access\r
+ clrf UnilinkSelected\r
+ clrf UnilinkID\r
+ clrf UnilinkBit\r
+ clrf UnilinkCmdLen\r
+ clrf UnilinkRAD\r
+ clrf UnilinkTAD\r
+ clrf UnilinkCMD1\r
+ clrf UnilinkCMD2\r
+ clrf UnilinkParity1\r
+ clrf UnilinkData1\r
+ clrf UnilinkData2\r
+ clrf UnilinkData3\r
+ clrf UnilinkData4\r
+ clrf UnilinkData5\r
+ clrf UnilinkData6\r
+ clrf UnilinkData7\r
+ clrf UnilinkData8\r
+ clrf UnilinkData9\r
+ clrf UnilinkParity2\r
+ clrf UnilinkZero\r
+\r
+ clrf DataStore\r
+ movlw UnilinkRAD ; Get the pointer to the first byte in the receive buffer\r
+ movwf UnilinkTXRX ; Store it\r
+\r
+ movlw StartUpText1\r
+ call TxLCD16B\r
retry\r
\r
-; movlw 8 ; Loop this many times\r
-; movwf DataCount\r
-\r
-;CLKWaitHigh\r
-; btfsc PORTA,4 ; Check for RST\r
-; goto retry\r
-; btfss PORTC,2 ; Check for BUSON\r
-; goto retry\r
-; btfss PORTB,0 ; Wait for clock to go high\r
-; goto CLKWaitHigh\r
-;CLKWaitLow\r
-; btfsc PORTA,4 ; Check for RST\r
-; goto retry\r
-; btfss PORTC,2 ; Check for BUSON\r
-; goto retry\r
-; btfsc PORTB,0 ; Wait for clock to go low\r
-; goto CLKWaitLow\r
-\r
-; clrc ; Clear carry\r
-; btfss PORTC,3 ; Test DATA\r
-; setc ; Set carry if data is LOW (data is inverted!)\r
-; rlf DataStore,f ; Shift it into our accumulator\r
-\r
-; decfsz DataCount,f ; Loop once more perhaps?\r
-; goto CLKWaitHigh\r
-\r
bcf LCD_RS_BIT ;Command mode\r
movlw 80h ;DisplayRam 0\r
call TxLCDB\r
movlw 'D'\r
call TxLCDB\r
\r
+ movf UnilinkCmdLen,w\r
+ bz DontPrintCmd\r
+ addlw '0'\r
+ call TxLCDB\r
+DontPrintCmd\r
+\r
movf DataCount,w ; Load bit counter (if 0 then byte is available)\r
skpz\r
goto retry\r
\r
- movf DataStore,w ; Get the result\r
decf DataCount,f ; Set it non-zero\r
\r
+ movf DataStore,w\r
call BootTXB ; Send to terminal\r
-\r
goto retry\r
\r
\r
\r
- movlw StartUpText1\r
- call TxLCD16B\r
- call LongDelay\r
+; movlw StartUpText1\r
+; call TxLCD16B\r
+; call LongDelay\r
\r
- bsf PORTA,4 ; turn off LED\r
+; bsf PORTA,4 ; turn off LED\r
\r
- movlw StartUpText2\r
- call TxLCD16B\r
- call LongDelay\r
+; movlw StartUpText2\r
+; call TxLCD16B\r
+; call LongDelay\r
\r
- bcf PORTA,4 ; turn on LED\r
+; bcf PORTA,4 ; turn on LED\r
\r
- movlw StartUpText3\r
- call TxLCD16B\r
- call LongDelay\r
+; movlw StartUpText3\r
+; call TxLCD16B\r
+; call LongDelay\r
\r
- goto retry\r
+; goto retry\r
\r
\r
;----------------------------------------------------------------\r
LCDInit\r
clrf PORTB\r
bsf STATUS,RP0 ; Hi Bank\r
- movlw 0cfh ; RC4 & RC5 should be outputs...\r
- movwf TRISC ; Yep.\r
movlw 001h ; All but RB0 are outputs.\r
movwf TRISB ; Yep\r
bcf OPTION_REG,NOT_RBPU ; Turn on port B pull-up\r