PDA

View Full Version : My first PBP bootloader (almost) working .. help



Marcick
- 6th February 2021, 09:39
Hi all,
here I'm with my first PBP bootloader that unfortunately doesn't work properly....
The main program jumps to bootloader, flash the new code, come back to main, do something expected at beginning
then starts to behave "funny", resets chips, etc.
I describe everything as if it were a tutorial so some expert maybe can see where is the weak area.


The bootloader is intended for a PIC18F67k22 that has a blocksize of 128 bytes and Int_Vector at 08h and 18h.
I leave free the first block 0-127 to remap Reset_Vector and Int_Vectors.
The bootloader code starts at 80h after the first block and has available all memory to 2FFFh, it's about 12k.
The main program starts at 3000h and have avaliable the remaining about 120k.


The bootloader has a complex UART communication with a GSM module and I need interrupt to manage properly
a 1k serial buffer. It works fine in other applications of mine, no problem at all that side.
Please note, I have found in this forum some other interesting solutions, like keeping the bootloader in the
high memory, retrieve code from I2C EEprom etc. But for several reasons they doesn't fit my needings.
I just would like to discover why my code fails and let it works properly, hope to find help :-)


This is the bootloader code:




DEFINE RESET_ORG 80h
BlockSize CON 128
UpperLimit CON $1FFFF-BlockSize
@ nop
STKPTR=0
CLEAR
' initialize your stuff, declare VAR, etc
Goto BootLoaderStart

INCLUDE "DT_INTS-18.bas" ; Base Interrupt System
INCLUDE "ReEnterPBP-18.bas" ; Include if using PBP interrupts
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler RX1_INT, _Rx1INT, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM
INCLUDE "interrupt.inc" ; here I manage the serial buffer, it works perfect


BootLoaderStart:
' remap Reset_Vector and INT_Vectors for bootloader
EraseCode 0 ' erase first block
WriteCode $00,$EF40 ' --> put a GoTo $80 at address $00
WriteCode $02,$F000
WriteCode $08,$EF44 ' --> put a GoTo $88 at address $08
WriteCode $0A,$F000
WriteCode $18,$EF4C ' --> put a GoTo $98 at address $18
WriteCode $1A,$F000
WriteCode $7F,$FF ' write the last byte of the block to allow WriteCode
Pause 500


' erase memory from $3000 to end
FOR Adr=$3000 to UpperLimit STEP BlockSize
ERASECODE Adr
NEXT Adr


' enable UART
RCSTA1.4=0 ' Reset Overrun flag
RCSTA1.4=1
@ INT_ENABLE RX1_INT ; enable RS232 interrupts
INTCON.7=1 ; enable global int
INTCON.6=1


' here i scan the new HEX file that has been already downloaded via FTP and stored in the GSM module memory
ScanLoop:
' read a line, example :1000A0000BE0060604C0E9FF05C0EAFFEE50E9CF09
' decode address, check crc, etc
' be careful to skip addresses from 0 to 2FFFh, not to overwrite the bootloader we are executing
' WRITECODE Adr, FlashByte
' when fnished, exit loop
goto ScanLoop

ExitBootLoader:
' remap Reset_Vector and INT_Vectors before jumping back to main program
@ INT_DISABLE RX1_INT ; disable RS232 interrupts
INTCON=0 ; disable INT
EraseCode 0 ; erase first block 0-127
WriteCode $00,$EF00 ; --> put a GoTo $3000 at address 0h
WriteCode $02,$F018
WriteCode $08,$EF04 ; --> put a GoTo $3008 at address 8h
WriteCode $0A,$F018
WriteCode $18,$EF0C ; --> put a GoTo $3018 aat address 18h
WriteCode $1A,$F018
WriteCode $7F,$FF ; write the last byte of the block to allow WriteCode
Pause 500
@ RESET


@ ORG 0h
@ GOTO 80h ' Reset Vector
@ ORG 8h
@ GOTO 88h ' High priority Int_Vector
@ ORG 18h
@ GOTO 98h ' Low priority Int_Vector PIC18F67K22


@ ORG 3000h
BootLoaderEnd:



Now build the program. I'm using PBP Long option here to be able to WriteCode at address > 64k
I'm in MPLAB IDE 8.92, open "Program memory" view, then in the "Opcode HEX" tab right click "Export Table"
Put 0x80 as start Address and 0x2FFF as End Address, check "Single column output" and save.
Now you need to write a tool (I have used B4J) to read this file and obtain this format




ASM
dw 0x0EFA1, 0x0F002, 0x0FFFF, 0x0FFFF, 0x0EF4D, 0x0F004, 0x0FFFF
dw 0x0E00B, 0x00606, 0x0C004, 0x0FFE9, 0x0C005, 0x0FFEA, 0x050EE
.....
.....
ENDASM



Let's jump now to our main program. This (and all updates) needs to work starting at 3000h so it will have
the structure as below. When you want to trigger an update you can simpy call @ GOTO 80h




DEFINE RESET_ORG 3000h
@ nop
STKPTR=0
CLEAR
' initialize your stuff, declare VAR, etc
goto Start

INCLUDE "DT_INTS-18.bas" ; Base Interrupt System
INCLUDE "ReEnterPBP-18.bas" ; Include if using PBP interrupts
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler TMR1_INT, _Timer1_250mS_INT, PBP, yes
INT_Handler RX1_INT, _Rx1INT, PBP, yes
INT_Handler RX2_INT, _Rx2INT, PBP, yes
INT_Handler TMR0_INT, _Timer0_8000mS_INT, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM
INCLUDE "interrupt.inc" ; here I manage all the interrupt, it works perfect (before an update)




Start:
; do your main program stuff
; When you want to trigger an update you can simpy call @ GOTO 80h


if Update_Needed = true then
; download the new HEX file via FTP and store in the GSM module memory
; so that it will be available for the BootLoader code, then
@ INT_DISABLE TMR1_INT
@ INT_DISABLE TMR0_INT
@ INT_DISABLE RX1_INT
@ INT_DISABLE RX2_INT
INTCON.7=0
@ goto 80h
endif
goto start


@ ORG 0h
@ GOTO 3000h
@ ORG 8h
@ GOTO 3008h
@ ORG 18h
@ GOTO 3018h




' here you have to copy the file generated before
@ ORG 80h
BootLoader:
ASM
dw 0x0EFA1, 0x0F002, 0x0FFFF, 0x0FFFF, 0x0EF4D, 0x0F004, 0x0FFFF
dw 0x0E00B, 0x00606, 0x0C004, 0x0FFE9, 0x0C005, 0x0FFEA, 0x050EE
.....
.....
ENDASM



The main program above works normally as expected. When I want to publish an update, I send the new HEX file
to the FTP server then send a message to the main program to inform that a new update is available.


As I told at beginning, everything works, but when the BootLoader jump back to the new main program, it starts
to do something correctly then behave funny and reset the chip.
Can you see some concept errors ? Besides disabling interrupt before enetering bootloader and remapping the vectors
is there any other register to take care ?
Thanks in advance. Hope that (once fixed) this stuff can be useful to other in the forum.
Cheers

Marcick
- 6th February 2021, 13:48
Found the bug !
There was an error in the flash procedure so that the last block was lost. Remember when using WriteCode:

"Note that block writes are not actually executed until the end location of the block is written to. If you write to random addresses within a block and neglect to write to the end location, the previously buffered data will not be written and will be lost."

So, I cant' modify the title but I say here that now everything works perfect and I'm reaaly happy and satisfied.
I want to tanks Pedja and Richard that helped me during these last days. I wouldn't be able to arrive here if alone.
Cheers.

pedja089
- 6th February 2021, 21:53
Just spent half an hour reading your first post :D

You can get block size from ASM.

BlockSize VAR BYTE BANKA SYSTEM
@ MovLW BLOCK_SIZE
@ MovWF BlockSize

CuriousOne
- 15th February 2021, 20:52
A little off-topic question.

Say I've built something using PIC, and want it's firmware to be user upgradeable without specific hardware, such as pickit or standalone programmer.
As I know, some PICs have native USB interface, and there are some examples about updating the firmware via USB.
Can we do same trick with PBP? I mean, flash some bootloader, and then user, via USB, updates only "main" code area?

Marcick
- 19th February 2021, 15:28
No problem at all. You just have to remap Reset and Int vector and you can jump to another program and back and do what you want of the PIC memory.
I've never played with built-in USB but I see there are specific instructions in PBP so you shouldn't have problems.