From 1da1eb0ce7960799c3907f13e56b26f6426a9fcc Mon Sep 17 00:00:00 2001 From: Werner Johansson Date: Sat, 16 Oct 2010 00:00:00 -0700 Subject: [PATCH] v0.2 - Boot Agent for UART flash is back? Signed-off-by: Werner Johansson --- wjuni2.asm | 359 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 352 insertions(+), 7 deletions(-) diff --git a/wjuni2.asm b/wjuni2.asm index 39e85d6..16f4b38 100644 --- a/wjuni2.asm +++ b/wjuni2.asm @@ -15,6 +15,7 @@ ; ; 0.0 Very first "Fucking No Work!" version ; 0.1 Some receiving works with the new MCU using HW SPI, yay! +; 0.2 Boot Agent for UART flash is back? ; ;---------------------------------------------------------------- @@ -71,11 +72,11 @@ Icount equ 2Dh ; Offset of string to print TxTemp equ 2Eh ; blahblah TxTemp2 equ 2Fh ; Blahblah2 +; Start of code - four instructions fit before the IRQ handler org 0 - nop ; Leave the first location, just in case -; call Bootstrap ; Call Flash Load routine -; call LCDInit ; Initialize LCD I/F -; call IRQInit ; Set up and start the IRQ handler + nop ; Leave the first location as NOP, just in case (required for ICD use) + call Bootstrap ; Call Flash Load routine at top of flash + call IRQInit ; Set up and start the IRQ handler goto Main ; Run the main program loop (skip the IRQ handler) subtitl "IRQ Handler" @@ -86,7 +87,12 @@ TxTemp2 equ 2Fh ; Blahblah2 org 4 ; Must be on Address 4! retfie ; Interrupt return + subtitl "IRQ Initialization code" +;---------------------------------------------------------------- +; Initializes the interrupt handler and registers. +IRQInit + return subtitl "Main loop" page @@ -212,10 +218,349 @@ UpdateLEDS return + subtitl "Bootstrap/Bootloader code" + page + ;---------------------------------------------------------------------- -; EE Data (64 bytes), located at 2100h +; Bootstrap code - Allows PIC to flash itself with data from the async port. +; Accepts a standard INHX8 encoded file as input, the only caveat is that the code is slow when writing to memory +; (we have to wait for the flash to complete), and therefore care has to be taken not to overflow the RS232 receiver +; (one good way of solving that is to wait for the echo from the PIC before sending anything else) +; Both program memory and Data EEPROM memory can be programmed, but due to hardware contraints the configuration +; register can't be programmed. That means that any references to the config register in the hex file will be ignored. +; +; Startup @9600bps + +; RAM usage for the bootstrap code + +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 +BootDataL equ 7bh +BootDataH equ 7ah +BootTimerL equ 79h +BootTimerM equ 78h +BootTimerH equ 77h +BootNumBytes equ 76h +BootDataVL equ 75h +BootDataVH equ 74h +BootHEXTemp equ 73h + + org 72eh ; Place the boot code at the top of memory page 0 + +Bootstrap + bsf STATUS,RP0 ; Access bank 1 + bsf TXSTA,TXEN ; Enable UART TX + movlw 31 ; Divisor for 9k6 @ 20MHz Fosc + movwf SPBRG ; Store + bcf STATUS,RP0 ; Back to bank 0 + + bsf RCSTA,SPEN ; Enable serial port + bsf RCSTA,CREN ; Enable UART RX + + movlw low BootStartText ; Send boot banner to the serial port + call BootTXStr + + movlw 0e8h ; Initialize timeout timer (e8 is about 3 secs) +; movlw 0fdh ; Initialize timeout timer (fd is short enough to get the headunit to recognize us) + movwf BootTimerL + movwf BootTimerM + movwf BootTimerH + +BootTimeout + incf BootTimerL,f ; A 24-bit counter + skpnz + incf BootTimerM,f + skpnz + incf BootTimerH,f + skpnz ; When overflowing here.. + goto BootReturn ; ..Exit boot loader, no keypress within timeout period, resume program + btfss PIR1,RCIF ; Wait for RX to complete + goto BootTimeout + call BootRXB + xorlw 27 ; ESC + skpz + goto BootTimeout ; If it wasn't ESC, wait for another key + +BootFlash + movlw low BootFlashText ; OK, flashing it is, send "start" text to serial port + call BootTXStr + + bsf BootBits,1 + clrf BootAddrL + clrf BootAddrH + +BootLoop + call BootRXB ; First find the ':' + xorlw ':' + skpz + goto BootLoop ; Loop until we find it! + + 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 + +; Note carry should be clear here as there cannot be odd number of bytes in this format + + call BootRXHEX ; Receive AddrH + movwf BootAddrH + call BootRXHEX ; Receive AddrL + movwf BootAddrL + rrf BootAddrH,f ; Fix the addressing again + rrf BootAddrL,f + + bcf BootBits,2 ; Assume we should program + bsf BootBits,1 ; And assume we should program flash not ee + + movf BootAddrH,w + xorlw 020h ; Check if it's configuration, which we can't program + skpnz ; Skip the bit set if it was false alarm + bsf BootBits,2 ; No programming for this line + + xorlw 001h ; Also check if it's EEPROM memory (first xor 20h then 1 =21h) + skpnz ; Skip the bit set instr if not EE data address + bcf BootBits,1 ; We should program EE, will ignore the AddrH + + call BootRXHEX ; Receive Record Type (must be 0 for real records) + skpz ; Check if zero + goto BootFlashComplete + +BootLineLoop + call BootRXHEX ; Receive low-byte of data word + movwf BootDataVL + call BootRXHEX ; Receive high-byte of data word + movwf BootDataVH + + btfsc BootBits,2 ; Check whether this line should be programmed at all + goto BootWriteSkip + + bcf BootBits,0 ; Read mode first, verify if we actually have to write + call BootEE + movf BootDataVL,w + xorwf BootDataL,f ; Compare and destroy DataL + movwf BootDataL ; Write new data to DataL + skpz ; Skip if no difference, have to check high byte as well + goto BootWrite ; Jump directly to write + + movf BootDataVH,w + xorwf BootDataH,f ; Compare + skpnz ; Skip if no difference, no programming necessary + goto BootWriteSkip + +BootWrite + movf BootDataVH,w + movwf BootDataH ; Have to put the new H byte data in as well + + 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 + +BootWriteSkip + + incf BootAddrL,f ; Advance counter to next addr + skpnz + incf BootAddrH,f ; And add to high byte if needed + + decfsz BootNumBytes,f + goto BootLineLoop + + goto BootLoop + +BootFlashComplete + +BootReturn + movlw low BootRunText + call BootTXStr + + bsf STATUS,RP0 ; Reg bank 1 +BootReturnWait + btfss TXSTA,TRMT ; Wait for last things to flush + goto BootReturnWait + bcf TXSTA,TXEN ; Disable UART TX + bcf STATUS,RP0 ; Back to bank 0 + + bcf RCSTA,SPEN ; Disable serial port + bcf RCSTA,CREN ; Disable UART RX + + return ; Return to code + +;---------------------------------------------------------------------- +; BootTXB - Sends one byte to the UART, waits for transmitter to become +; free before sending + +BootTXB +BootTXW1 + btfss PIR1,TXIF ; Wait for TX to empty + goto BootTXW1 + movwf TXREG ; Send the byte + return - org 2100h -; data 0ffh, 0ffh, 0ffh, 0ffh, 001h, 023h, 045h, 067h +;---------------------------------------------------------------------- +; BootTXStr - Sends ASCII string pointed to by W, zero terminated + +BootTXStr + 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 BootAddrL,f ; Increment pointer + goto BootTXStrLoop + +;---------------------------------------------------------------------- +; BootRXB - Receives one byte from the UART, waits if nothing available + +BootRXB +BootRXW1 + btfss PIR1,RCIF ; Wait for RX to complete + goto BootRXW1 + movf RCREG,w ; Get the recvd byte + call BootTXB ; Echo to terminal + return + +;---------------------------------------------------------------------- +; BootRXHEXNibble - Receives one byte and converts it from ASCII HEX to binary + +BootRXHEXNibble + call BootRXB ; Receive nibble + +; This code is from piclist.com, really neat! + + 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' + addlw 10 ; Add 10 (A get to be 0ah etc.) + + return + +;---------------------------------------------------------------------- +; BootRXHEX - Receives two bytes from the UART, waits if nothing available +; Decodes the bytes as ASCII hex and returns a single byte in W + +BootRXHEX + call BootRXHEXNibble + movwf BootHEXTemp + swapf BootHEXTemp,f ; Swap it up to the high nibble + + call BootRXHEXNibble + addwf BootHEXTemp,w ; And add the two nibbles together + return + +;---------------------------------------------------------------------- +; BootEE - Reads or writes EE or Flash memory, BootBits specify the +; exact action to take. BootAddrL and BootAddrH has to be initialized +; to the address of choice (0000-00ffh for EE and 0000h-1fffh for flash. +; The data to be written has to be put in BootDataL and BootDataH, and +; data will be written to the same place when read back + +BootEE + bsf STATUS,RP1 ; Select bank 2 (RP0 must be 0) + + movf BootAddrH,w ; Load desired address + movwf EEADRH + movf BootAddrL,w + movwf EEADR + movf BootDataH,w ; And load the data (only used when writing) + movwf EEDATH + movf BootDataL,w + movwf EEDATA + + bsf STATUS,RP0 ; Go to bank 3 + + bsf EECON1,EEPGD ; Point to Program Flash mem + btfss BootBits,1 ; Test if that was correct or if we have to clear again + bcf EECON1,EEPGD ; Point to EE DATA mem + + btfss BootBits,0 ; Check from read or write + goto BootEERD ; Skip the WR if we were going for a read + + bsf EECON1,WREN ; Enable writes + movlw 55h + movwf EECON2 + movlw 0AAh + movwf EECON2 ; Unlock write operation + bsf EECON1,WR ; And start a write cycle +BootWRLoop + btfsc EECON1,WR ; This executes for EE only not flash, waits for WR to finish + goto BootWRLoop ; These two instructions gets NOPed when flashing program memory + + bcf EECON1,WREN ; Finally disable writes again + ; Here we read the data back again, can be used as verify +BootEERD + bsf EECON1,RD ; Start a read cycle + nop ; Only necessary for flash read, same thing as when writing above + nop ; Except I could use the two words for something useful there.. :) + +BootEEX + bcf STATUS,RP0 ; Back to bank 2 + movf EEDATA,w ; Store our EE-data + movwf BootDataL + movf EEDATH,w + movwf BootDataH + bcf STATUS,RP1 ; And finally back to bank 0 + + 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 + DA "WJ PIC16F876A Boot Loader - press ESC to flash...\x00" + +BootFlashText + DA "\r\nSend INHX8 file now...\r\x00" + +BootRunText + DA "\r\nExiting loader\r\x00" + +;---------------------------------------------------------------------- +; EE Data (256 bytes), located at 2100h + + org 2100h +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh + +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh + +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh + +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh +; de 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh END -- 1.7.3