From 9d87c925a9eaa4fc256be3173c14a20d1469472d Mon Sep 17 00:00:00 2001 From: fishsoupisgood Date: Wed, 9 Sep 2020 11:53:37 +0100 Subject: everything, mostly, working --- boiler-monster/pic/selfprog.asm | 391 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 391 insertions(+) create mode 100644 boiler-monster/pic/selfprog.asm (limited to 'boiler-monster/pic/selfprog.asm') diff --git a/boiler-monster/pic/selfprog.asm b/boiler-monster/pic/selfprog.asm new file mode 100644 index 0000000..9e18769 --- /dev/null +++ b/boiler-monster/pic/selfprog.asm @@ -0,0 +1,391 @@ + title "Self Programming" + list b=8, r=dec + +;######################################################################## +; Self programming, based on Microchip AN851 +;######################################################################## +; This code has been optimized for size so it would fit in 0x100 code words. +; To achieve this, some special tricks had to be used. As a result the code +; may be a little hard to read +; +; The functionality differs from that described in AN851 in the following +; respects: +; 1. No auto baud detection. Communication must take place at 9600 baud. +; 2. Dropped the first that was used for auto baud detection. +; 3. Dropped the third address byte as it would always be 0. +; 4. The code does not check the last byte of EEPROM data memory to enter boot +; mode. Instead it transmits a character and waits up to 1 second for +; a character. +; 5. The code is designed to be placed in the highest part of memory. That way +; it doesn't interfere with the interrupt code address. It does rely on the +; main program to call the self-program code at an appropriate time. +; 6. Due to the location of the boot loader code, it cannot be protected using +; the code protection bits in the configuration word. This means that the +; boot loader code can also be updated, if necessary. +; 7. The Erase Flash command has been implemented for the PIC16F device. +; 8. The device reset command is 0x08, not any command with a 0 length. +; 9. The version command can be called with a data length of 1-3 words. It will +; report the following information: +; 1. Version +; 2. Boot loader start address +; 3. Boot loader end address +; The software used to reflash the device can use the last two pieces of +; information to determine which part of memory should not be touched. + +#include "p16f88.inc" + + errorlevel -302, -306 + +#define MAJOR_VERSION 1 +#define MINOR_VERSION 1 + +#define STX 0x0F +#define ETX 0x04 +#define DLE 0x05 + +CHKSUM equ 0x70 +COUNTER equ 0x71 +RXDATA equ 0x72 +TXDATA equ 0x73 +TEMP equ 0x74 + +DATA_BUFF equ 0x10 ;Start of receive buffer +COMMAND equ 0x10 ;Data mapped in receive buffer +DATA_COUNT equ 0x11 +ADDRESS_L equ 0x12 +ADDRESS_H equ 0x13 +PACKET_DATA equ 0x14 + +#define SELFRESET PORTB,1 +#define RX PORTB,2 +#define TX PORTB,5 + +#ifdef SELFPROGNEW + #define SELFPROG SelfProgNew + #define STARTADDRESS 0x0700 +#else + #define SELFPROG SelfProg + #define STARTADDRESS 0x0f00 +#endif + + global SELFPROG +SELFPROG code STARTADDRESS + ;Do not go into selfprog mode after a watchdog timeout reset +SELFPROG btfss STATUS,NOT_TO + return ;Let the main code handle a timeout + + bcf INTCON,GIE ;Ignore interrupts + + banksel OSCCON + movlw b'01100000' ;Internal oscillator set to 4MHz + movwf OSCCON ;Configure the oscillator + + ;Set the LEDS as outputs +#ifndef LVP + movlw b'00100111' +#else + movlw b'00101111' +#endif + movwf TRISB + + ;Configure the comparators and voltage reference + ;Allow communication between thermostat and boiler to continue + ;while reprogramming the device + movlw b'11100111' ;Pins 3 and 4 are digital ouputs + movwf TRISA + movlw b'00000111' ;A0 through A2 are used for analog I/O + movwf ANSEL + movlw b'11100110' ;Voltage reference at 1.25V + movwf CVRCON + movlw b'00000110' ;Two common reference comps with output + movwf CMCON + + ;Configure Timer 0 & Watchdog Timer + ;Bit 7 RBPU = 1 - Port B pull up disabled + ;Bit 6 INTEDG = 1 - Interrupt on rising edge + ;Bit 5 T0CS = 0 - Internal clock + ;Bit 4 T0SE = 1 - High to low transition + ;Bit 3 PSA = 0 - Prescaler assigned to Timer 0 + ;Bit 2-0 PS = 7 - 1:256 Prescaler + movlw b'11010111' + movwf OPTION_REG + + movlw 25 ;9600 baud + movwf SPBRG + movlw b'00100110' + movwf TXSTA ;High speed, Asynchronous, Enabled + bcf STATUS,RP0 + bsf RCSTA,SPEN ;Enable serial port + bsf RCSTA,CREN ;Enable receive + + ;Clear the LEDS + movlw b'11111111' + movwf PORTB + + clrf TMR0 + movlw 1 + call Pause +;Notify the external programming software (Pause returns ) + call WrRS232 +;Programmer should react within 1 second + movlw 16 + call Pause + btfss PIR1,RCIF +;No data received, resume the normal program + return +;Check that the received character is + call RdRS232 + skpz +;Other serial data received, resume normal program + return + + bsf STATUS,IRP +ReSync movlw DATA_BUFF + movwf FSR + clrf CHKSUM +GetNextDat call RdRS232 ;Get the data + skpnz + goto ReSync ;Found unprotected STX + xorlw STX ^ ETX ;Check for ETX + skpnz + goto CheckSum ;Yes, examine checksum + xorlw ETX ^ DLE ;Check for DLE + skpnz + call RdRS232 ;Yes, get the next byte + movfw RXDATA + movwf INDF ;Store the data + addwf CHKSUM,F ;Get sum + incf FSR,F + goto GetNextDat + +CheckSum tstf CHKSUM + skpz + goto StartOfLine + bsf STATUS,RP1 + movfw ADDRESS_L + movwf EEADR + movfw ADDRESS_H + movwf EEADRH + movlw PACKET_DATA + movwf FSR + movfw DATA_COUNT + movwf COUNTER +CheckCommand +#ifdef SELFPROGNEW + movlw high ($ + 0x800) +#else + movlw high $ +#endif + movwf PCLATH + movfw COMMAND + sublw 8 + sublw 8 + skpc + goto StartOfLine + addwf PCL,F + goto ReadVersion ;0 Read Version Information + goto ReadProgMem ;1 Read Program Memory + goto WriteProgMem ;2 Write Program Memory + goto EraseProgMem ;3 Erase Program Memory + goto ReadEE ;4 Read EEDATA Memory + goto WriteEE ;5 Write EEDATA Memory + goto StartOfLine ;6 Read Config Memory + goto StartOfLine ;7 Write Config Memory + goto VReset ;8 Reset + +VersionData data (MAJOR_VERSION << 8) | MINOR_VERSION +#ifdef SELFPROGNEW + data SELFPROG + 0x800, SelfProgEnd + 0x800 +#else + data SELFPROG, SelfProgEnd +#endif + +ReadVersion movlw low VersionData + movwf EEADR +#ifdef SELFPROGNEW + movlw high (VersionData + 0x800) +#else + movlw high VersionData +#endif + movwf EEADRH + movlw DATA_BUFF + 2 + movwf FSR +ReadProgMem bsf STATUS,RP0 + bsf EECON1,EEPGD + bsf EECON1,RD + nop + nop + bcf STATUS,RP0 + movfw EEDATA + movwf INDF + incf FSR,F + movfw EEDATH + movwf INDF + incf FSR,F + incf EEADR,F + skpnz + incf EEADRH,F + decfsz COUNTER,F + goto ReadProgMem +WritePacket movlw DATA_BUFF + subwf FSR,W +WritePacketJ1 movwf COUNTER + movlw STX + call WrRS232 + clrf CHKSUM + movlw DATA_BUFF + movwf FSR +SendNext movfw INDF + addwf CHKSUM,F + incf FSR,F + call WrData + decfsz COUNTER,F + goto SendNext + comf CHKSUM,W + addlw 1 + call WrData ;WrData returns + call WrRS232 +StartOfLine bcf STATUS,RP1 + call RdRS232 ;Look for a start of line + skpnz + goto ReSync + goto StartOfLine + +WriteProgMem movlw b'10000100' + call LoadEECon1 + movlw b'11111100' + andwf EEADR,F + movlw 4 + movwf TEMP +Lp1 movfw INDF + movwf EEDATA + incf FSR,F + movfw INDF + movwf EEDATH + incf FSR,F + call StartWrite + decfsz TEMP,F + goto Lp1 + decfsz COUNTER,F + goto WriteProgMem + goto WritePacketJ1 + +EraseProgMem movlw b'10010100' + call LoadEECon1 + movlw 0x1F + iorwf EEADR,F + call StartWrite + decfsz COUNTER,F + goto EraseProgMem + goto WritePacketJ1 + +ReadEE bsf STATUS,RP0 + clrf EECON1 + bsf EECON1,RD + bcf STATUS,RP0 + movfw EEDATA + movwf INDF + incf FSR,F + incf EEADR,F + decfsz COUNTER,F + goto ReadEE + goto WritePacket + +WriteEE movlw b'00000100' + call LoadEECon1 + movfw INDF + movwf EEDATA + incf FSR,F + call StartWrite + decfsz COUNTER,F + goto WriteEE + goto WritePacketJ1 + +WrData movwf TXDATA + xorlw STX + skpnz + goto WrDLE + xorlw STX ^ ETX + skpnz + goto WrDLE + xorlw ETX ^ DLE + skpz + goto WrNext +WrDLE movlw DLE + call WrRS232 +WrNext movfw TXDATA +WrRS232 clrwdt + bcf STATUS,RP1 +WaitTxEmpty btfss PIR1,TXIF + goto WaitTxEmpty + movwf TXREG + retlw ETX + +RdRS232 btfsc RCSTA,OERR + goto VReset +RdLp1 clrwdt + btfss PIR1,RCIF + goto RdLp1 + movfw RCREG + movwf RXDATA + xorlw STX + return + +LoadEECon1 bsf STATUS,RP0 + movwf EECON1 + bcf STATUS,RP0 + return + +StartWrite clrwdt + bsf STATUS,RP0 + movlw 0x55 + movwf EECON2 + movlw 0xAA + movwf EECON2 + bsf EECON1,WR +WaitEEWrite btfsc EECON1,WR ;Skipped when writing program memory + goto WaitEEWrite ;Skipped when writing program memory + bcf STATUS,RP0 + incf EEADR,F + skpnz + incf EEADRH,F + retlw 1 ;Return length of acknowledgement + +Pause clrwdt + btfsc PIR1,RCIF + return + btfss INTCON,TMR0IF + goto Pause + bcf INTCON,TMR0IF + addlw -1 + skpz + goto Pause + retlw ETX + +;Reset the device via an external connection from an I/O pin to the reset pin. +VReset bcf STATUS,RP1 + bcf SELFRESET ;Prepare the output latch + bsf STATUS,RP0 + bcf SELFRESET ;Switch the pin to output + +;If resetting via the output pin doesn't work, restore all used registers to +;their power-on defaults and jump to address 0. +;Do not simply return because the code that called this routine may have been +;wiped and reprogrammed to something completely different. + movlw b'11111111' + movwf TRISA + movwf TRISB + movwf OPTION_REG + movwf ANSEL + movlw b'00000111' + movwf CMCON + clrf TXSTA + clrf SPBRG + clrf STATUS + clrf RCSTA + clrf INTCON + clrf PCLATH + clrwdt +SelfProgEnd goto 0 + + end -- cgit v1.2.3