From: Werner Johansson Date: Wed, 5 Mar 2003 06:16:57 +0000 (-0800) Subject: v0.4 - Some fixups in the bootstrap code (I actually had to put the PIC in my PICSTAR... X-Git-Url: http://git.xnk.nu/?p=wj-unilink.git;a=commitdiff_plain;h=d43d03082defa70600c47d8158452886d1245361 v0.4 - Some fixups in the bootstrap code (I actually had to put the PIC in my PICSTART Plus programmer again :)) Signed-off-by: Werner Johansson --- diff --git a/wj-uni.asm b/wj-uni.asm index f2a186d..31f5bc1 100644 --- a/wj-uni.asm +++ b/wj-uni.asm @@ -25,6 +25,7 @@ ;---------------------------------------------------------------- ; Version ; +; 0.4 Some fixups in the bootstrap code (I actually had to put the PIC in my PICSTART Plus programmer again :)) ; 0.3 Implementing more Unilink commands and RingIndicator control (to wake the computer from sleep) ; 0.2 First attempt at responding to the Anyone command ; 0.1 Receives Unilink data OK, relays it to serial @@ -69,6 +70,9 @@ ;---------------------------------------------------------------- Dcount equ 20h e_LEN equ 21h + +Counter equ 22h +SlaveBreakState equ 23h ; Hold state and time-out information about slave break, indicates when it can happen Icount equ 2Dh ; Offset of string to print TxTemp equ 2Eh ; blahblah TxTemp2 equ 2Fh ; Blahblah2 @@ -126,7 +130,7 @@ IRQW equ 7fh ; ; Also because of the real-time requirements for clocking data onto the Unilink bus the first check in the ISR ; is to see whether the Unilink clock rise was the reason for the interrupt. This results in a "clock rise to ; bit ready" time of less than 30 instruction cycles, should be plenty of spare time waiting for clock to go low -; again after that. +; again after that. Other interrupts might introduce latencies, but let's see how this works.. org 4 ; ISR vector is at address 4 movwf IRQW ; Save W @@ -134,8 +138,8 @@ IRQW equ 7fh ; clrf STATUS ; Zero out the status reg, gives Reg Bank0 movwf IRQSTATUS ; Store the STATUS reg movf PCLATH,w ; Get the PCLATH reg - movwf IRQPCLATH ; And store it - clrf PCLATH ; Go to low memory +; movwf IRQPCLATH ; And store it +; clrf PCLATH ; Go to low memory ; Maybe save FSR here as well (if there's a need for it in the non-ISR code) btfss INTCON,INTF ; Check if it's the INT edge interrupt (Unilink CLK) @@ -208,6 +212,7 @@ IRQINTCLKWaitHigh ; the packet and take appropriate action. IRQINTRecvDone + clrf SlaveBreakState ; First of all, clear the break state - this got in the way, restart detection.. movf UnilinkTXRX,w ; Find out which byte # that was received andlw 0fh ; Mask bnz IRQINTRecvNotFirst ; Not the first byte @@ -451,12 +456,93 @@ IRQAfterINT IRQNotINT + btfss PIR1,TMR2IF ; Check if it's the TMR2 interrupt (0.5ms timing) + goto IRQNotTMR2 ; No it's not, check the other sources + +; Slave break opportunity detection here - the logic works as follows: +; Look for a data low period of at least 5 ms (10 loops) +; Look for a data high period of at least 2 ms (4 loops) +; If the Slave Break request bit has been set, issue a slave break by holding the data line low for 5ms (10 loops) +; If a packet would be received the packet handler automatically clears out the SlaveBreakState, which means start all over + +; incf Counter,f ; Increment the general purpose counter + + btfsc SlaveBreakState,5 ; Check if already pulling the data line low + goto IRQTMR2SlaveBreak + + btfsc SlaveBreakState,7 ; Looking for low or high data + goto IRQTMR2HighData + btfss DATA_BIT ; Looking for a low data line, if it's low, increment state, if it's high, reset state + goto IRQTMR2LowDataOK + clrf SlaveBreakState ; Got a high data line while waiting for a low one, reset state + goto IRQAfterTMR2 ; Leave ISR + +IRQTMR2HighData + btfsc DATA_BIT ; Looking for a high data line, if it's high - increment state, otherwise wait + goto IRQTMR2HighDataOK + movlw 080h + btfss SlaveBreakState,6 ; Test the "first time around" bit + clrw ; Not the beginning of the state, have to restart the entire thing now, not just this state + andwf SlaveBreakState,f ; Mask out the 1 upper control bits and restart this state + goto IRQAfterTMR2 + +IRQTMR2HighDataOK +IRQTMR2LowDataOK + bsf SlaveBreakState,6 ; Set the "first time around" bit + btfss SlaveBreakState,4 ; Only increment to 0x10 + incf SlaveBreakState,f + + movf SlaveBreakState,w + andlw 1fh + + btfss SlaveBreakState,7 ; Checking whether it's low or high + goto IRQTMR2FoundLow + + xorlw 4 ; It's high now, and if 4 periods have passed we can activate slave break + skpz + goto IRQAfterTMR2 + +; Issue slave break here + incf Counter,f +; clrf SlaveBreakState + movlw 20h + movwf SlaveBreakState + bcf DATA_BIT + bsf STATUS,RP0 + bcf DATA_BIT + bcf STATUS,RP0 + goto IRQAfterTMR2 + +IRQTMR2FoundLow + xorlw 7 + skpz + goto IRQAfterTMR2 + movlw 80h ; Prepare for state 2, looking for data line high + movwf SlaveBreakState + goto IRQAfterTMR2 + +IRQTMR2SlaveBreak + movf SlaveBreakState,w + andlw 01fh + xorlw 4 + skpz + goto IRQAfterTMR2 + bsf STATUS,RP0 + bsf DATA_BIT + bcf STATUS,RP0 + clrf SlaveBreakState + +IRQAfterTMR2 + bcf PIR1,TMR2IF ; Clear the IRQ source bit to re-enable TMR2 interrupts again + +IRQNotTMR2 + ; Finally restore CPU state and return from the ISR ; If I have to save the FSR in the beginning I also need to restore it here... - movf IRQPCLATH,w - movwf PCLATH ; Restore PCLATH +; movf IRQPCLATH,w +; movwf PCLATH ; Restore PCLATH swapf IRQSTATUS,w movwf STATUS ; Restore STATUS swapf IRQW,f @@ -468,20 +554,14 @@ IRQNotINT page ;---------------------------------------------------------------- -; Data can be stored between here and 100h... - -StartUpText1 - DT "----- WJ UniLink" - -LookUp movwf PCL ; Go to it (this assumes PCLATH == 00h) - -;---------------------------------------------------------------- ; Main program begins here. [Called after bootloader, lcdinit and irqinit...] - org 100h ; Maybe not force this to a specific address later +; org 100h ; Maybe not force this to a specific address later Main + movlw high LookUp + movwf PCLATH - movlw StartUpText1 ; Show something on the LCD + movlw low StartUpText1 ; Show something on the LCD call TxLCD16B MainLoop @@ -491,12 +571,14 @@ MainLoop call TxLCDB bsf LCD_RS_BIT - movlw '0' +; movlw '0' + movf Counter,w ; Debug timer btfsc PORTA,4 ; Test RST movlw 'R' call TxLCDB - movlw '0' +; movlw '0' + movf SlaveBreakState,w btfsc PORTB,0 ; Test CLK movlw 'C' call TxLCDB @@ -531,6 +613,7 @@ MainDontPrintCmd ;---------------------------------------------------------------- ; IRQInit - Sets up the IRQ Handler +; Set up Timer2 to generate 2000 interrupts per second, used for timing - 1/16 prescaler and a PR2 reg of 156 (0x9c) is set IRQInit @@ -561,13 +644,21 @@ IRQInit movlw UnilinkRAD ; Get the pointer to the first byte in the receive buffer movwf UnilinkTXRX ; Store it + clrf SlaveBreakState ; Zero out the status, we're starting from the beginning + ; Fix the output state of RI and BUSON_OUT to a safe default bsf RS232_RI_BIT ; RS232 RI should be inactive (inverted logic, a set bit here gives a negative output) bcf BUSON_OUT_BIT ; BUSON_OUT should be disabled for now, must be appointed first + movlw 06h ; Timer2 enabled + 1/16 prescaler + movwf T2CON + bsf STATUS,RP0 ; Reg bank 1 + movlw 09ch ; Timer PR2 reg giving 2000 interrupts per second + movwf PR2 + bcf RS232_RI_BIT ; Both bits should be outputs bcf BUSON_OUT_BIT ; @@ -575,6 +666,8 @@ IRQInit ; bcf OPTION_REG,INTEDG ; We want RB0 to give us an IRQ on the falling edge bsf INTCON,INTE ; Enable the RB0/INT + bsf INTCON,PEIE ; Enable the peripheral interrupts + bsf PIE1,TMR2IE ; Enable the Timer2 peripheral interrupt bsf INTCON,GIE ; Enable global interrupts bsf TXSTA,TXEN ; Enable UART TX @@ -799,6 +892,16 @@ DelayInner return +;---------------------------------------------------------------- +; Data can be stored between 600 and 6ffh... + + org 600h +StartUpText1 + DT "----- WJ UniLink" + +LookUp movwf PCL ; Go to it (this assumes PCLATH == 06h) + + subtitl "Bootstrap/Bootloader code" page @@ -814,7 +917,6 @@ DelayInner ; RAM usage for the bootstrap code -BootRXState equ 7fh ; What are we waiting for @RX BootBits equ 7eh ; bit0 1=write 0=read, bit1 1=PGM 0=EE, bit2 0=normal 1=no-op when prog BootAddrL equ 7dh BootAddrH equ 7ch @@ -827,14 +929,10 @@ BootNumBytes equ 76h BootDataVL equ 75h BootDataVH equ 74h BootHEXTemp equ 73h -BootStrTemp equ 72h - org 700h ; Place the boot code at the top of memory + org 738h ; Place the boot code at the top of memory (currently the loader is exactly 200 bytes) Bootstrap - movlw 7 - movwf PCLATH ; Make sure the lookup code runs with the high PC bits set! - bsf STATUS,RP0 ; Access bank 1 bsf TXSTA,TXEN ; Enable UART TX movlw 31 ; Divisor for 9k6 @ 20MHz Fosc @@ -844,8 +942,6 @@ Bootstrap bsf RCSTA,SPEN ; Enable serial port bsf RCSTA,CREN ; Enable UART RX -; clrf BootRXState ; Waiting for command - movlw low BootStartText ; Send boot banner to the serial port call BootTXStr @@ -879,12 +975,11 @@ BootFlash BootLoop call BootRXB ; First find the ':' - call BootTXB ; Echo to terminal xorlw ':' skpz goto BootLoop ; Loop until we find it! - call BootRXHEX ; Get one ASCII encoded byte (two chars) (this echoes automatically) + call BootRXHEX ; Get one ASCII encoded byte (two chars) movwf BootNumBytes ; This is the number of bytes to be programmed on the line ; Maybe clear cary here? rrf BootNumBytes,f ; Right shift because we're double addressing this 8-bit format @@ -940,21 +1035,12 @@ BootWrite movf BootDataVH,w movwf BootDataH ; Have to put the new H byte data in as well -; movlw '+' -; call BootTXB ; Send progword indicator - bsf BootBits,0 call BootEE ; Write directly into program mem ; Here a verify can take place, the read-back results are now in DataL/H -; movlw '+' -; goto BootWriteDone - BootWriteSkip -; movlw '-' -BootWriteDone -; call BootTXB incf BootAddrL,f ; Advance counter to next addr skpnz @@ -963,11 +1049,6 @@ BootWriteDone decfsz BootNumBytes,f goto BootLineLoop -; movlw 13 ; Progress -; call BootTXB -; movlw 10 ; Progress -; call BootTXB - goto BootLoop BootFlashComplete @@ -986,7 +1067,6 @@ BootReturnWait bcf RCSTA,SPEN ; Disable serial port bcf RCSTA,CREN ; Disable UART RX - clrf PCLATH ; Go back to memory bank 0 return ; Return to code ;---------------------------------------------------------------------- @@ -1004,14 +1084,23 @@ BootTXW1 ; BootTXStr - Sends ASCII string pointed to by W, zero terminated BootTXStr - movwf BootStrTemp ; Store offset - call BootLookup ; Lookup char - addlw 0 - skpnz + movwf BootAddrL ; Store LSB of text pointer + movlw 07h ; MSB of pointer to the text (0700h in this boot loader) + movwf BootAddrH + movlw 02h ; Select "Read Program Memory" operation + movwf BootBits +BootTXStrLoop + call BootEE ; Lookup char (actually two packed into one word) + rlf BootDataL,w ; Shift the MSB out into carry (that's the 2nd char LSB) + rlf BootDataH,w ; Shift it into 2nd char + call BootTXB ; Send the high byte first + movf BootDataL,w ; Get the low byte + andlw 07fh ; Mask of the highest bit + skpnz ; Stop if zero return call BootTXB ; Send char - incf BootStrTemp,w ; Retrieve - goto BootTXStr + incf BootAddrL,f ; Increment pointer + goto BootTXStrLoop ;---------------------------------------------------------------------- ; BootRXB - Receives one byte from the UART, waits if nothing available @@ -1021,6 +1110,7 @@ BootRXW1 btfss PIR1,RCIF ; Wait for RX to complete goto BootRXW1 movf RCREG,w ; Get the recvd byte + call BootTXB ; Echo to terminal return ;---------------------------------------------------------------------- @@ -1028,7 +1118,6 @@ BootRXW1 BootRXHEXNibble call BootRXB ; Receive nibble - call BootTXB ; Echo to terminal addlw -'A' ; Convert from BCD to binary nibble skpc ; Test if if was 0-9 or A-F, skip if A-F addlw 'A' - 10 - '0' ; It was numeric '0' @@ -1103,20 +1192,22 @@ BootEEX return +; To produce compact code the end zero byte has to be in the LSB (that means an even number of chars in every string) BootStartText - DT "WJBoot - press ESC to flash",0 + DW 0x2bca,0x216f,0x37f4,0x102d,0x1070,0x3965,0x39f3,0x1045,0x29c3,0x1074,0x37a0,0x336c,0x30f3,0x3400 +; DE "WJBoot - press ESC to flash\x00" BootFlashText - DT 13,10,"Send INHX8 file now...",13,10,0 + DW 0x068a,0x29e5,0x3764,0x1049,0x2748,0x2c38,0x1066,0x34ec,0x32a0,0x376f,0x3bae,0x172e,0x0680 +; DE "\r\nSend INHX8 file now...\r\x00" BootRunText - DT 13,10,"Exiting loader",13,10,0 + DW 0x068a,0x22f8,0x34f4,0x34ee,0x33a0,0x366f,0x30e4,0x32f2,0x0680 +; DE "\r\nExiting loader\r\x00" -BootLookup - movwf PCL ; Go fetch the char data ;---------------------------------------------------------------------- ; EE Data (64 bytes), located at 2100h org 2100h -; data 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh END