• AVR Freaks

Hot!XC8 and AN851 bootloader for PIC16F876A

Author
TechDpt
Starting Member
  • Total Posts : 45
  • Reward points : 0
  • Joined: 2011/06/13 09:29:39
  • Location: 0
  • Status: offline
2019/08/16 16:00:21 (permalink)
0

XC8 and AN851 bootloader for PIC16F876A

Dear all,
from the mad-c answer on this thread (link) I've reported below this interesting information:

"If you have read about the--CODEOFFSET option in the User's Guide, noted that it shifts the reset vector as well as the interrupts, tried experimenting with this option, ...
 If you use the CODEOFFSET option, it will simply offset all the vectors (reset and any applicable interrupts) by the amount you specify. It is up to you, the programmer, to work out how you get from the actual device vector to where the remapped software entry points will be located. That is usually done by a boot loader that performs a jump to  these locations."
 
Now from the XC8 v1.45 manual, paragraph 3.5.3 ("How Do I Link Bootloaders and Downloadable Applications"):
 
"On PIC18 devices, typically the application code is offset, and the bootloader is linked
with no offset so that it populates the Reset and interrupt code locations. The bootloader
Reset and interrupt code merely contains code which redirects control to the real
Reset and interrupt code defined by the application and which is offset.

On mid-range devices, this is not normally possible to perform when interrupts are
being used. Consider offsetting all of the bootloader with the exception of the code
associated with Reset, which must always be defined by the bootloader. The application
code can define the code linked at the interrupt location. The bootloader will need
to remap any application code that attempts to overwrite the Reset code defined by the
bootloader."

In my application I've interrupt code to manage the USART port and many timers so I'm confused if the AN851 bootloader for my PIC16F876A can be used or not; my idea is to use the #pragma directive to set the code start for the interrupt service routine and with another #pragma directive the startin address for the application code.

From this last point of view this seems possible to me but I kindly ask if someone can give me some explanation about this XC8 sentence.

Thank and best regards!
#1

11 Replies Related Threads

    ric
    Super Member
    • Total Posts : 23526
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: online
    Re: XC8 and AN851 bootloader for PIC16F876A 2019/08/16 16:18:29 (permalink)
    +1 (1)
    TechDpt
    ...
    my idea is to use the #pragma directive to set the code start for the interrupt service routine



    That just puts the code at the specified address, it does NOT cause the hardware to jump to that address.
    That is the whole problem, you can't just put a GOTO at the interrupt location in a standard midrange device.
     
    The only time it will work is if all of your bootloader AND your application fit within a single code page (0x800 words).
    If you ever change the value of the PCLATH register, then it simply won't work right.
    The only solution is to dedicate a number of global registers to the bootloader (remember you only have 16, and that will take them away from your application), and have interrupt service code in the bootloader which does a full context save and restore before and after calling your application's ISR. That will consume another stack position (you only have 8).
     
    This is yet another reason why enhanced devices (PIC16F1xxx and PIC16F1xxxx) are so much better to work with.
    They are cheaper, faster, and much more powerful than the old devices, and have easier workarounds for this sort of problem.
     

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #2
    TechDpt
    Starting Member
    • Total Posts : 45
    • Reward points : 0
    • Joined: 2011/06/13 09:29:39
    • Location: 0
    • Status: offline
    Re: XC8 and AN851 bootloader for PIC16F876A 2019/08/16 16:37:06 (permalink)
    0
    Hi @ric thank for your answer.
    I kindly ask you some other explanation about the AN851 PIC16F code.
    At the end of the bootloader code I can see:
     
     ORG 0x100
    RVReset

     ORG 0x104
    RVInt

     
    then from the bootloader perspective and from I can read inside the AN851 at 0x100 seems to me that I've simply to put a jmp to my application entry point and also put the related application ISR code at 0x104 so I think is a matter to reserve enough space to whole ISR code, then the jmp at the 0x100 will be to an address just after the end of the ISR code.
    Inside the AN851 I'm unable to find any advice concerning the single page for the bootloader and the code application.
    Could you please let me know if this is possible or not?
    Thank!
    post edited by TechDpt - 2019/08/16 16:50:32
    #3
    ric
    Super Member
    • Total Posts : 23526
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: online
    Re: XC8 and AN851 bootloader for PIC16F876A 2019/08/16 16:50:34 (permalink)
    +1 (1)
    I guess you did not understand my explanation.
    If any part of your application extends out of the first page of code memory, then when an interrupt occurs, you might be executing code in that other page.
    If you put a GOTO 0x0104 instruction at address 0x0004, then when the interrupt occurs, it will try to jump to offset 0x0104 within whichever code page is currently selected. i.e. instant crash.
    So, you would have to save the current value of PCLATH somewhere, and zero it before doing the GOTO.
    But, that involves corrupting the W register and the STATUS register, so first you have to preserve those two registers somewhere before you can preserve PCLATH. Then after the application's ISR has run, you have to run more code to put all those registers back how they were. That is what I was referring to above about "preserving and restoring context.
     
    Do you REALLY have to use a PIC16F876? All this is so much easier in a newer chip.
     

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #4
    TechDpt
    Starting Member
    • Total Posts : 45
    • Reward points : 0
    • Joined: 2011/06/13 09:29:39
    • Location: 0
    • Status: offline
    Re: XC8 and AN851 bootloader for PIC16F876A 2019/08/16 17:00:03 (permalink)
    0
    Hi @ric, thank for your time,
    concerning the bootloader code I've reported for completeness all the code below:
     
     
     ; *****************************************************************************
    ;        Software License Agreement                    
    ;                                     
    ; The software supplied herewith by Microchip Technology         
    ; Incorporated (the “Company”) for its PICmicro® Microcontroller is
    ; intended and supplied to you, the Company’s customer, for use     
    ; solely and exclusively on Microchip PICmicro Microcontroller        
    ; products. The software is owned by the Company and/or its         
    ; supplier, and is protected under applicable copyright laws. All   
    ; rights are reserved. Any use in violation of the foregoing          
    ; restrictions may subject the user to criminal sanctions under        
    ; applicable laws, as well as to civil liability for the breach of  
    ; the terms and conditions of this license.                
    ;                                    
    ; THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
    ; WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
    ; TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A         
    ; PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
    ; IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR         
    ; CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.            
    ;                                    
    ;                                     
    ; Bootloader for PIC16F by Rodger Richey
    ; Adapted from PIC18F bootloader developed by Ross Fosler
    ; 03/18/2002    ... First full implementation
    ; 03/25/2002    Modified receive & parse engine to vector to autobaud on a checksum
    ;        error since a checksum error could likely be a communications problem.
    ;         Modified the protocol to incorporate the autobaud as part of the
    ;        first received <STX>. Doing this improves robustness by allowing
    ;        re-sync under any condition. Previously it was possible to enter a
    ;        state where only a hard reset would allow re-syncing.
    ; 04/09/2002    Fixed bugs: 1) clear carry before shifting ABTIME in Autobaud
    ;                    2) Increment address in program memory write
    ;                    3) Increment address in program memory read
    ; 06/07/2002    Fixed bug in read, byte counter in code is word counter.  Needed
    ;               to multiply by 2 to get bytes.
    ;
    ; Memory Map
    ;    -----------------
    ;    |    0x0000    |    Reset vector
    ;    |            |
    ;       |    0x0004    |    Interrupt vector
    ;    |            |    
    ;    |        |
    ;    |  Boot Block     |    (this program)
    ;     |        |
    ;    |    0x0200    |    Re-mapped Reset Vector
    ;    |    0x0204    |    Re-mapped High Priority Interrupt Vector
    ;    |        |
    ;    |    |    |
    ;    |        |
    ;        |  Code Space     |    User program space
    ;    |        |
    ;    |    |    |
    ;    |        |
    ;    |    0x3FFF     |
    ;    -----------------
    ;
    ;
    ; Incomming data format:
    ;
    ;    <STX><STX><DATA><CHKSUM><ETX>
    ;          /    \
    ;     ________/      \____________________________
    ;    /                                         \
    ;    <COMMAND><DLEN><ADDRL><ADDRH><ADDRU><DATA>...
    ;
    ; Definitions:
    ;
    ;     STX    -    Start of packet indicator
    ;    ETX    -    End of packet indicator
    ;     LEN     -    Length of incomming packet
    ;     DATA    -    General data up to 255 bytes
    ;     CHKSUM     -     The 8-bit two's compliment sum of LEN & DATA
    ;     COMMAND -     Base command
    ;     DLEN    -    Length of data associated to the command
    ;     ADDR    -    Address up to 24 bits
    ;     DATA     -    Data (if any)
    ;
    ;
    ; Commands:
    ;
    ;     RD_VER        0x00    Read Version Information
    ;     RD_MEM        0x01    Read Program Memory
    ;     WR_MEM        0x02    Write Program Memory
    ;     ER_MEM        0x03    Erase Program Memory (NOT supported by PIC16)
    ;     RD_EE        0x04    Read EEDATA Memory
    ;     WR_EE        0x05    Write EEDATA Memory
    ;     RD_CONFIG    0x06    Read Config Memory (NOT supported by PIC16)
    ;     WT_CONFIG    0x07    Write Config Memory (NOT supported by PIC16)
    ;
    ; *****************************************************************************

     

    ; *****************************************************************************
        #include P16F876A.INC        ; Standard include
    ; *****************************************************************************

        errorlevel -302            ; Do not show any banking warnings

    ; *****************************************************************************
    #define    MINOR_VERSION    0x03        ; Version
    #define    MAJOR_VERSION    0x00

    #define    RC_DLE        0x01
    #define    RC_STX        0x02

    #define    STX        0x0F
    #define    ETX        0x04
    #define    DLE        0x05

    ;#define DEBUGGING            ; Debugging enabled with ICD
    ; *****************************************************************************



    ; *****************************************************************************
    CHKSUM        equ    0x71        ; Checksum accumulator
    COUNTER        equ    0x72        ; General counter
    ABTIME        equ    0x73
    RXDATA        equ    0x74
    TXDATA        equ    0x75
    TEMP        equ    0x76

    PCLATH_TEMP    equ    0x7D        ; Interrupt context
    STATUS_TEMP    equ    0x7E        ; save/restore registers
    W_TEMP        equ    0x7F

    ; Frame Format
    ;
    ;  <STX><STX>[<COMMAND><DATALEN><ADDRL><ADDRH><ADDRU><...DATA...>]<CHKSUM><ETX>

    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
    ADDRESS_U    equ    0x14
    PACKET_DATA    equ    0x15    
    ; *****************************************************************************


     
    ; *****************************************************************************
        ORG    0x0000            ; Re-map Reset vector
    VReset
        bcf    STATUS,RP0                            ; B0/B2
        bsf    STATUS,RP1                            ; B2
        clrf    PCLATH                                ; B2
        goto    Setup                                ; B2

        ORG    0x0004
    VInt
        movwf    W_TEMP                                ; ?
        swapf    STATUS,W                            ; ?
        movwf    STATUS_TEMP                            ; ?
        clrf    STATUS                                ; B0
        movf    PCLATH,W                            ; B0
        movwf    PCLATH_TEMP                            ; B0
        clrf    PCLATH                                ; B0
        goto    RVInt            ; Re-map Interrupt vector        ; B0

    ; *****************************************************************************



    ; *****************************************************************************
    ; Setup the appropriate registers.
    Setup    clrwdt
        movlw    0xFF                                ; B2
        movwf    EEADR            ; Point to last location        ; B2
        bsf    STATUS,RP0                            ; B3
        clrf    EECON1                                ; B3
        bsf    EECON1,RD        ; Read the control code            ; B3
        bcf    STATUS,RP0                            ; B2
        incf    EEDATA,W                            ; B2
        btfsc    STATUS,Z                            ; B2
        goto    SRX                                ; B2

        bcf    STATUS,RP1                            ; B0
        goto    RVReset            ; If not 0xFF then normal reset        ; B0

    SRX    bcf    STATUS,RP1                            ; B0
        movlw    b'10000000'        ; Setup rx and tx, CREN disabled    ; B0
        movwf    RCSTA                                ; B0
        bsf    STATUS,RP0                            ; B1
        bcf    TRISC,6            ; Setup tx pin                ; B1
        movlw    b'00100110'                            ; B1
        movwf    TXSTA                                ; B1
        bsf    STATUS,IRP                            ; B1
    ; *****************************************************************************




    ; *****************************************************************************
    Autobaud
    ;
    ; ___     __________            ________
    ;    \__/       \__________/
    ;       |                     |
    ;       |-------- p ----------|
    ;
    ;    p = The number of instructions between the first and last
    ;           rising edge of the RS232 control sequence 0x0F. Other
    ;        possible control sequences are 0x01, 0x03, 0x07, 0x1F,
    ;         0x3F, 0x7F.
    ;
    ;    SPBRG = (p / 32) - 1      BRGH = 1
                                            ; B0/B1/B2
        bcf    STATUS,RP1                            ; B0/B1
        bsf    STATUS,RP0                            ; B1
        movlw    b'00000011'                            ; B1
        movwf    OPTION_REG                            ; B1
        bcf    STATUS,RP0                            ; B0
        bcf    RCSTA,CREN                            ; B0

        call    WaitForRise                            ; B0
     
        clrf    TMR0            ; Start counting            ; B0

        call    WaitForRise                            ; B0

        movf    TMR0,W            ; Read the timer            ; B0
        movwf    ABTIME                                ; B0

        bcf    STATUS,C
        rrf    ABTIME,W                            ; B0
        btfss    STATUS,C        ; Rounding                ; B0
        addlw    0xFF                                ; B0

        bsf    STATUS,RP0                            ; B1
        movwf    SPBRG                                ; B1
        bcf    STATUS,RP0                            ; B0
        bsf    RCSTA,CREN        ; Enable receive            ; B0

        movf    RCREG,W                                ; B0
        movf    RCREG,W                                ; B0

        bsf    STATUS,RP0                            ; B1
        movlw    b'11111111'                            ; B1
        movwf    OPTION_REG                            ; B1
    ; *****************************************************************************



    ; *****************************************************************************
    ; Read and parse the data.
    StartOfLine                                    ; B1/B2/B0
        bcf    STATUS,RP0                            ; B0/B2
        bcf    STATUS,RP1                            ; B0
        call    RdRS232            ; Look for a start of line        ; B0
        xorlw    STX            ; <STX><STX>                ; B0
        btfss    STATUS,Z                            ; B0
        goto    Autobaud        ;was StartOfline            ; B0

        movlw    DATA_BUFF        ; Point to the buffer            ; B0
        movwf    FSR                                ; B0

        clrf    CHKSUM            ; Reset checksum            ; B0
            
    GetNextDat                
        call    RdRS232            ; Get the data                ; B0
        xorlw    STX            ; Check for a STX            ; B0
        btfsc    STATUS,Z                            ; B0
        goto    StartOfLine        ; Yes, start over            ; B0

    NoSTX    movf    RXDATA,W                            ; B0
        xorlw    ETX            ; Check for a ETX            ; B0
        btfsc    STATUS,Z                            ; B0
        goto    CheckSum        ; Yes, examine checksum            ; B0

    NoETX    movf    RXDATA,W                            ; B0
        xorlw    DLE            ; Check for a DLE            ; B0
        btfss    STATUS,Z                            ; B0
        goto    NoDLE            ; Check for a DLE            ; B0

        call    RdRS232            ; Yes, Get the next byte        ; B0
        
    NoDLE    movf    RXDATA,W                            ; B0
        movwf    INDF            ; Store the data            ; B0
        addwf    CHKSUM,F        ; Get sum                ; B0
        incf    FSR,F                                ; B0

        goto    GetNextDat                            ; B0

    CheckSum    
        movf    CHKSUM,F        ; Checksum test                ; B0
        btfss    STATUS,Z                            ; B0
        goto    Autobaud                            ; B0
    ; ***********************************************



    ; ***********************************************
    ; Pre-setup, common to all commands.                        ; B0
        bsf    STATUS,RP1                            ; B2
        movf    ADDRESS_L,W        ; Set all possible pointers        ; B2
        movwf    EEADR                                ; B2
        movf    ADDRESS_H,W                            ; B2
        movwf    EEADRH                                ; B2

        movlw    PACKET_DATA                            ; B2
        movwf    FSR                                ; B2

        movf    DATA_COUNT,W         ; Setup counter                ; B2
        movwf    COUNTER                                ; B2
        btfsc    STATUS,Z                            ; B2
        goto    VReset            ; Non valid count (Special Command)    ; B2
    ; ***********************************************

     

    ; ***********************************************
    ; Test the command field and sub-command.                    ; B2
    CheckCommand
        movf    COMMAND,W        ; Test for a valid command        ; B2
        sublw    d'7'            ; 7-COMMAND -> W            ; B2
        btfss    STATUS,C                            ; B2
        goto    Autobaud                            ; B2

        movf    COMMAND,W        ; Perform calculated jump        ; B2
        addwf    PCL,F                                ; B2
        
        goto    ReadVersion        ; 0                    ; B2
        goto    ReadProgMem        ; 1                    ; B2
        goto    WriteProgMem        ; 2                    ; B2
        goto    StartOfLine        ; 3                    ; B2
        goto    ReadEE            ; 4                    ; B2
        goto    WriteEE            ; 5                    ; B2
        goto    StartOfLine        ; 6                    ; B2
        goto    StartOfLine        ; 7                    ; B2
    ;maybe add jump to reset vector in this table
    ; ***********************************************



    ; ***********************************************
    ; Commands
    ;
    ; In:    <STX><STX>[<0x00><0x02>]<0xFF><ETX>
    ; OUT:    <STX><STX>[<0x00><VERL><VERH>]<CHKSUM><ETX>
    ReadVersion                                    ; B2
        movlw    MINOR_VERSION                            ; B2
        movwf    DATA_BUFF + 2                            ; B2
        movlw    MAJOR_VERSION                            ; B2
        movwf    DATA_BUFF + 3                            ; B2

        movlw    0x04                                ; B2
        goto    WritePacket                            ; B2


    ; In:    <STX><STX>[<0x01><DLEN><ADDRL><ADDRH><ADDRU>]<CHKSUM><ETX>
    ; OUT:    <STX><STX>[<0x01><DLEN><ADDRL><ADDRH><ADDRU><DATA>...]<CHKSUM><ETX>
    ReadProgMem                                    ; B2
    RPM1    bsf    STATUS,RP0                            ; B3
        bsf    EECON1,EEPGD                            ; B3
        bsf    EECON1,RD                            ; B3
        nop                                    ; B3
        nop                                    ; B3
        bcf    STATUS,RP0                            ; B2
        movf    EEDATA,W                            ; B2
        movwf    INDF                                ; B2
        incf    FSR,F                                ; B2
        movf    EEDATH,W                            ; B2
        movwf    INDF                                ; B2
        incf    FSR,F                                ; B2

        incf    EEADR,F                                ; B2
        btfsc    STATUS,Z                            ; B2
        incf    EEADRH,F                            ; B2

        decfsz    COUNTER,F                            ; B2
        goto    RPM1            ; Not finished then repeat        ; B2

        rlf    DATA_COUNT,W        ; Setup packet length            ; B2
        addlw    0x05                                ; B2
                    
        goto    WritePacket                            ; B2


    ; In:    <STX><STX>[<0x02><DLENBLOCK><ADDRL><ADDRH><ADDRU><DATA>...]<CHKSUM><ETX>
    ; OUT:    <STX><STX>[<0x02>]<CHKSUM><ETX>
    WriteProgMem                                    ; B2
        bsf    STATUS,RP0                            ; B3
        movlw    b'10000100'        ; Setup writes                ; B3
        movwf    EECON1                                ; B3
        bcf    STATUS,RP0                            ; B2
        movlw    b'11111100'        ; Force a boundry            ; B2
        andwf    EEADR,F                                ; B2
     
        movlw    0x04                                ; B2
        movwf    TEMP                                ; B2

    Lp1    
        movf    INDF,W                                ; B2
        movwf    EEDATA                                ; B2
        incf    FSR,F                                ; B2
        movf    INDF,W                                ; B2
        movwf    EEDATH                                ; B2
        incf    FSR,F                                ; B2
        call    StartWrite                            ; B2

        incf    EEADR,F                                ; B2
        btfsc    STATUS,Z                            ; B2
        incf    EEADRH,F                            ; B2

        decfsz    TEMP,F                                ; B2
        goto    Lp1                                ; B2

        decfsz    COUNTER,F                            ; B2
        goto    WriteProgMem        ; Not finished then repeat        ; B2

        goto    SendAcknowledge        ; Send acknowledge            ; B2


    ; In:    <STX><STX>[<0x04><DLEN><ADDRL><ADDRH><0x00>]<CHKSUM><ETX>
    ; OUT:    <STX><STX>[<0x04><DLEN><ADDRL><ADDRH><0x00><DATA>...]<CHKSUM><ETX>
    ReadEE                                        ; B2
        bsf    STATUS,RP0                            ; B3
        clrf    EECON1                                 ; B3

        bsf    EECON1,RD        ; Read the data                ; B3
        bcf    STATUS,RP0                            ; B2
        movf    EEDATA,W                            ; B2
        movwf    INDF                                ; B2
        incf    FSR,F                                ; B2
        
        incf    EEADR,F            ; Adjust EEDATA pointer            ; B2

        decfsz    COUNTER,F                            ; B2
        goto    ReadEE            ; Not finished then repeat        ; B2

        movf    DATA_COUNT,W        ; Setup packet length            ; B2
        addlw    0x05                                ; B2
                    
        goto    WritePacket                            ; B2


    ; In:    <STX><STX>[<0x05><DLEN><ADDRL><ADDRH><0x00><DATA>...]<CHKSUM><ETX>
    ; OUT:    <STX><STX>[<0x05>]<CHKSUM><ETX>
    WriteEE                                        ; B2
        movf    INDF,W                                ; B2
        movwf    EEDATA                                ; B2
        incf    FSR,F                                ; B2
        call    WriteWaitEEData        ; Write data                ; B2

        incf    EEADR,F            ; Adjust EEDATA pointer            ; B2

        decfsz    COUNTER,F                            ; B2
        goto    WriteEE            ; Not finished then repeat        ; B2

        goto    SendAcknowledge        ; Send acknowledge            ; B2
    ; ***********************************************



    ; ***********************************************
    ; Send the data buffer back.
    ;
    ; <STX><STX>[<DATA>...]<CHKSUM><ETX>

    SendAcknowledge                                    ; B2
        movlw    0x01            ; Send acknowledge            ; B2
                                            ; B2
    WritePacket
        movwf    COUNTER                                ; B2

        movlw    STX            ; Send start condition            ; B2
        call    WrRS232                                ; B2
        call    WrRS232                                ; B0

        clrf    CHKSUM            ; Reset checksum            ; B0

        movlw    DATA_BUFF        ; Setup pointer to buffer area        ; B0
        movwf    FSR                                ; B0
        
    SendNext                ; Send DATA
        movf    INDF,W                                ; B0
        addwf    CHKSUM,F                            ; B0
        incf    FSR,F                                ; B0
        call    WrData                                ; B0
        decfsz    COUNTER,F                            ; B0
        goto    SendNext                            ; B0

        comf    CHKSUM,W        ; Send checksum                ; B0
        addlw    0x01                                ; B0
        call    WrData                                ; B0

        movlw    ETX            ; Send stop condition            ; B0
        call    WrRS232                                ; B0

        goto    Autobaud                            ; B0
    ; *****************************************************************************




    ; *****************************************************************************
    ; Write a byte to the serial port.

    WrData                                        ; B0
        movwf    TXDATA            ; Save the data                ; B0

        xorlw    STX            ; Check for a STX            ; B0
        btfsc    STATUS,Z                            ; B0
        goto    WrDLE            ; No, continue WrNext            ; B0

        movf    TXDATA,W                            ; B0
        xorlw    ETX            ; Check for a ETX            ; B0
        btfsc    STATUS,Z                            ; B0
        goto    WrDLE            ; No, continue WrNext            ; B0

        movf    TXDATA,W                            ; B0
        xorlw    DLE            ; Check for a DLE            ; B0
        btfss    STATUS,Z                            ; B0
        goto    WrNext            ; No, continue WrNext            ; B0

    WrDLE
        movlw    DLE            ; Yes, send DLE first            ; B0
        call    WrRS232                                ; B0

    WrNext
        movf    TXDATA,W        ; Then send STX                ; DC

    WrRS232                                        ; B2/B0
        clrwdt                                    ; B2
        bcf    STATUS,RP1                            ; B0
        btfss    PIR1,TXIF        ; Write only if TXREG is ready        ; B0
        goto    $ - 1                                ; B0
        
        movwf    TXREG            ; Start sending                ; B0

        return                                    ; B0
    ; *****************************************************************************




    ; *****************************************************************************
    RdRS232                                        ; B0
        clrwdt                                    ; B0

        btfsc    RCSTA,OERR        ; Reset on overun            ; B0
        goto    VReset                                ; B0

        btfss    PIR1,RCIF        ; Wait for data from RS232        ; B0
        goto    $ - 1                                ; B0

        movf    RCREG,W            ; Save the data                ; B0
        movwf    RXDATA                                ; B0
     
        return                                    ; B0
    ; *****************************************************************************




    ; *****************************************************************************
    WaitForRise                                    ; B0
        btfsc    PORTC,7            ; Wait for a falling edge        ; B0
        goto    WaitForRise                            ; B0
        clrwdt                ;;; Do we need this?            ; B0
    WtSR    btfss    PORTC,7            ; Wait for starting edge        ; B0
        goto    WtSR                                ; B0
        return                                    ; B0
    ; *****************************************************************************




    ; *****************************************************************************
    ; Unlock and start the write or erase sequence.

    StartWrite                                    ; B3
        clrwdt                                    ; B2
        bsf    STATUS,RP0                            ; B3
        movlw    0x55            ; Unlock                ; B3
        movwf    EECON2                                ; B3
        movlw    0xAA                                ; B3
        movwf    EECON2                                ; B3
        bsf    EECON1,WR        ; Start the write            ; B3
        nop                                    ; B3
        nop                                    ; B3
        bcf    STATUS,RP0                            ; B2
        return                                    ; B2
    ; *****************************************************************************




    ; *****************************************************************************
    WriteWaitEEData                                    ; B2
        bsf    STATUS,RP0                            ; B3
        movlw    b'00000100'        ; Setup for EEData            ; B3
        movwf    EECON1                                ; B3
        call    StartWrite                            ; B3
        btfsc    EECON1,WR        ; Write and wait            ; B3
        goto    $ - 1                                ; B3
        bcf    STATUS,RP0                            ; B2
        return                                    ; B2
    ; *****************************************************************************


    ; *****************************************************************************
        ORG    0x100
    RVReset                    

        ORG    0x104
    RVInt

    ; *****************************************************************************


        END


     
    so the final application code ISR is effectively remapped and also it seems to me that this implement the register copy in order to prevent any wrong jump...
     
    Isn't it?
     
    Thank!
     
    #5
    ric
    Super Member
    • Total Posts : 23526
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: online
    Re: XC8 and AN851 bootloader for PIC16F876A 2019/08/16 17:11:06 (permalink)
    +1 (1)
    That code has the "context save" code in the bootloader.
    That means you MUST code your application to
    [1] NOT do the context save again at it's own ISR location
    [2] Implement the matching "context restore" code at the end of its ISR. It MUST use the same addresses for W_TEMP, STATUS_TEMP, and PCLATH_TEMP as the bootloader does.
     
    Yes, this scheme could work. It does mean that your app is now tied to the bootloader. It wouldn't run standalone just by changing the CODEOFFSET back to 0.
     
     
     

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #6
    1and0
    Access is Denied
    • Total Posts : 9607
    • Reward points : 0
    • Joined: 2007/05/06 12:03:20
    • Location: Harry's Gray Matter
    • Status: offline
    Re: XC8 and AN851 bootloader for PIC16F876A 2019/08/16 18:42:30 (permalink)
    +1 (1)
    The shared memory area 0x70-0x7F is precious, so don't waste it. Only W_TEMP of the context needs has to be in there, like this:
            org     0x0004
            movwf   W_TEMP
            swapf   STATUS,w
            clrf    STATUS
            movwf   STATUS_TEMP
            swapf   PCLATH,w
            movwf   PCLATH_TEMP
            clrf    PCLATH
            goto    RVInt

    I'd suggest putting the context restore in the bootloader too if there is space available, and your app just branches to it after servicing the ISR.
    post edited by 1and0 - 2019/08/16 18:43:42
    #7
    TechDpt
    Starting Member
    • Total Posts : 45
    • Reward points : 0
    • Joined: 2011/06/13 09:29:39
    • Location: 0
    • Status: offline
    Re: XC8 and AN851 bootloader for PIC16F876A 2019/08/17 06:44:38 (permalink)
    0
    Thank you all for the suggestions, after reading your answers, the main application have to deal about the bootloader so is tied with it, may be a better approach would found a way to detach this two object so make the bootloader and the application independent.
    I'm thinking and asking if a possible solution may be to move the bootloader code to the end of the program memory and then save the main application code starting from 0x0000. At the reset vector I've to put a jmp branch to the entry point bootloader code and then when all the work is finished (or simply I don't have to perform any bootloader operation) get back to the original application entry point.
    In this way I think that the ISR coded inside the main application should not require any special processing and the application code have only a small code change regarding the non bootloader version concerning the starting jmp to the bootloader entry point.
    Is a possible way?
    Thank!
    #8
    ric
    Super Member
    • Total Posts : 23526
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: online
    Re: XC8 and AN851 bootloader for PIC16F876A 2019/08/17 06:48:35 (permalink)
    +1 (1)
    That is almost precisely what the text you quoted on post#1 said to do.

    On mid-range devices, this is not normally possible to perform when interrupts are
    being used. Consider offsetting all of the bootloader with the exception of the code
    associated with Reset, which must always be defined by the bootloader. The application
    code can define the code linked at the interrupt location. The bootloader will need
    to remap any application code that attempts to overwrite the Reset code defined by the
    bootloader."

     

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #9
    TechDpt
    Starting Member
    • Total Posts : 45
    • Reward points : 0
    • Joined: 2011/06/13 09:29:39
    • Location: 0
    • Status: offline
    Re: XC8 and AN851 bootloader for PIC16F876A 2019/08/17 07:11:20 (permalink)
    0
    Yep, after various reasoning now is more clear what I've to do, then the first step will be change the original AN851 bootloader in order to move it to end of the program memory space of the PIC16F876A and perform the necessary remapping to go back to the main application...
    Strange that the AN851 was not modified to better adapt the bootloader code and make it more independent from the the main application code.
     
    Thank and best regards.
    #10
    TechDpt
    Starting Member
    • Total Posts : 45
    • Reward points : 0
    • Joined: 2011/06/13 09:29:39
    • Location: 0
    • Status: offline
    Re: XC8 and AN851 bootloader for PIC16F876A 2019/08/17 14:40:46 (permalink)
    0
    Hi,
    I've also read the AN1310 application notes, this one is about another bootloader claim to be high speed but the good news is that this one is located at the end of the program memory space, this follow the idea delineated in the previous post, into the AN1310 is reported:
     
    "Placing the bootloader firmware towards the end of Flash memory space should require little or no changes to application firmware, due to the automatic Reset vector remapping done by the host PC bootloader software. Interrupt vectors are handled by application firmware at the normal hardware interrupt vector addresses, so no application firmware changes are required in this design."
     
    the host application responsible to send data to the bootloader also change the first reset vector to point at the bootloader entry point.
     
    Best regards.
    #11
    TechDpt
    Starting Member
    • Total Posts : 45
    • Reward points : 0
    • Joined: 2011/06/13 09:29:39
    • Location: 0
    • Status: offline
    Re: XC8 and AN851 bootloader for PIC16F876A 2019/08/30 05:41:06 (permalink)
    0
    As update for this thread, at the end, I've chosen to use the Tiny Bootloader (link) due to his very small footprint.
     
    This bootloader code reside at the end of the program space, so I've no issue with the interrupt vector of the main application.
     
    Because I can not perform a hardware reset of my microcontroller, in order to start the bootloader I've chosen to use the watchdog feature, in this way, when I need to program a new firmware, firstly I put the microcontroller in a simple infinite loop and then simply wait for the watchdog to expire, this will bring the execution to the reset vector and then from this point to the bootloader entry point (of course the reset vector is filled with the necessary instructions to jump at the bootloader entry point).
     
    By configuring the Tiny Bootloader to wait for a time of 10" every byte received on the RX port, I'm able to run the updater script written in Python and perform the upload process. Fot those that was
     
    For those interested in the Python script, I used the code release 0.6.6 at this link (tinybldlin) and modified to adapt it to the PIC16F876A by correcting a bug related the entry point instructions of the bootloader.
    More in detail, inside the file "transferhex.py", function "transfer_hex", you have to change these original instructions:
     

            #ading movlw 0x1f
            pic_mem[0]=0x1f
            pic_mem[1]=0x30
            #ading movwf PCLATH
            pic_mem[2]=0x8a
            pic_mem[3]=0x00
            #ading goto 0x7a0
            pic_mem[4]=0xa0
            pic_mem[5]=0x2F

     
    with these ones:
     

            #ading movlw 0x1f
            #pic_mem[0]=0x1f
            #pic_mem[1]=0x30
            pic_mem[0]=0x8a
            pic_mem[1]=0x15
            #ading movwf PCLATH
            #pic_mem[2]=0x8a
            #pic_mem[3]=0x00
            pic_mem[2]=0x0a
            pic_mem[3]=0x16
            #ading goto 0x7a0
            pic_mem[4]=0xa0
            pic_mem[5]=0x2F
     

    Basically the python script read the firmware hex file and translate it in a sequence of byte stored inside the pic_mem vector and strip out the reset vector of the main application in order to put it at the init of the bootloader space, at this address the bootloader will jump after it have finished the upgrading work. Concerning the reset vector this one is filled with the instruction that perform the GOTO to the bootloader code entry point.
     
    Of course we need also to instruct the compiler do not use the last locations of the flash program memory in order to prevent the bootloader overwriting.
     
    When the writing process finish and no more bytes are sent to the bootloader, after 10", the bootloader jump to the GOTO instruction that point to the main application entry point (as written above the python script scan the hex firmware file to look for the original reset vector then it writes these instructions at the init of the bootloader reserved space so after the bootloader has completed its work it can jump to the right application entry point).
     
    This is just for reference.
     
    Best regards.
     
    #12
    Jump to:
    © 2019 APG vNext Commercial Version 4.5