PIC16F1455 bootloader using Xmodem - Page 1
Forum section: electronics / general

author: MIS42N
author_rank: Frequent Contributor
timestamp: November 01, 2021, 06:31:00 am
content: ## UPDATED ## - source code documented properly, program modified to do two passes.I am writing an assembler program for the PIC16F1455. I thought of giving programmed chips to other people then wondered how they could be updated. Not everybody has a PICkit or other suitable programmer. The program uses serial input/output to a terminal emulator like PuTTy or Tera Term. Some searching found that several companies updated their devices using the Xmodem protocol to send the update. Tera Term supports Xmodem. Could the 16F1455 update itself from a .hex file using Xmodem? Yes it can.I have written a bootloader specifically for the program I am writing, so it is a part of the program. It sits at program location 0x1E00 to about 0x1F80 and is initiated by a user request. The user then has a minute to set Tera Term to transmit the new .hex file. The bootloader then uploads the new .hex and ignores the bits that would overwrite itself. It terminates by rebooting, which hopefully starts the newly updated program.So now I'm wondering if this is a good idea. If the transfer is interrupted then the system is effectively bricked, has to be reprogrammed with a proper programmer. Maybe the bootloader should change the start vector to point to the bootloader while it is running. At least then a borked load could be restarted. Or maybe not bother to add the facility at all.I am posting this because I might shelve the idea, but maybe someone would like the code. I cut it out of the original program and compiled it as a standalone one shot bootloader. The test was if it could reload the original program and it does. So a lot of the comments are a frankenmash of the original and the standalone. It doesn't change the configuration bits, but maybe it should.

author: Benta
author_rank: Super Contributor
timestamp: November 01, 2021, 07:55:30 pm
content: Look at ZModem instead. This supports interrupted transfers.

author: MIS42N
author_rank: Frequent Contributor
timestamp: November 01, 2021, 09:19:56 pm
content: Quote from: Benta on November 01, 2021, 07:55:30 pmA bootloader has to occupy memory, which is therefore not available to the program being loaded. So the bootloader should use little memory. This one is 340 instructions (could be a little bit smaller). Hard to estimate for Zmodem but it is much more complex and mostly, for this application, unnecessary features. One of those features, sliding windows, would need interrupts enabled, that adds the complication of protecting the interrupt vector from overwriting. This bootloader doesn't use interrupts, runs entirely by polling.I think Xmodem is actually quite good for the purpose. It has a basic error checking mechanism (checksum) with a repeat mechanism. My inclination at this stage is to ask the user to send the file twice. The first time just check all the checksums (the .hex data also has checksums) and only proceed to the second pass (overwriting) if the first is successful.I put this out in case it is useful to others. It works, so I am not looking for another solution.

author: spostma
author_rank: Regular Contributor
timestamp: November 01, 2021, 10:58:13 pm
content: Good idea to do this in assembly!Could you protect your bootloader by filtering out writes to the bootloader addres range?A similar bootloader is Matt Sarnoff's 512 byte ASM DFU Bootloader for PIC16F145x,which now is maintained by Anobium:https://github.com/Anobium/PIC16F1-USB-DFU-Bootloader---By the way, also Anobium's PicKitPlus software is great to give your PicKit2/3a new life supporting the latest PIC and many AVR microconrollers!https://github.com/Anobium/PICKitPlus

author: MIS42N
author_rank: Frequent Contributor
timestamp: November 02, 2021, 04:24:40 am
content: Quote from: spostma on November 01, 2021, 10:58:13 pmIf you read the fine print in my first post "... and ignores the bits that would overwrite itself.". Yup. Thought of that. At the moment it only loads code into addresses less than the bootloader (so less than word 0x1E00). So it won't change the configuration bits. What it does do is force the device to run on the 16MHz internal oscillator regardless of the oscillator settings and runs at 9600 baud.If the bootloader needed replacing, not too hard to write a program that loads into the lower memory then when invoked copied boot loader code into the proper place and jump to it. Then feed the original program to the bootloader to reinstate normality.I was trying to avoid using any extra software to condition the .hex file, just send it as is, as a file, via the Xmodem protocol already built into Tera Term. That puts the task of decoding Xmodem data, then decoding the embedded .hex data in the Xmodem packets, on the bootloader. Which accounts for it being 340 words. This I believe makes it smaller than Matt Sarnoff's. His is described as 512 words (of 14 bits) not 512 bytes. He did well to squeeze the USB protocol into that. Most bootloaders have some smarts built into the sending program, this one all the smarts are in the bootloader. I could shave a bit off 340 words but the program that uses the bootloader also uses some memory above 0x1ff0 to store non volatile variables in the high endurance flash. So even if it were squeezed down, 0x1E00 would still be the 256 word boundary chosen to load it.I did look at other bootloaders. None of them took the .hex file and loaded it. The .hex file had to read by a special program on the sender end and reformatted before being sent. This bootloader is a somewhat special case in that the user is already using a serial terminal program of some sort. So using the terminal program to load new software was (to me) logical. Tera Term seems as good as any other serial terminal programs, so requiring it be used also seemed logical. Horses for courses.

author: 8goran8
author_rank: Contributor
timestamp: November 20, 2021, 09:03:33 pm
content: Great job. I did a very similar thing for the PIC18 series two years ago but my bootloader is written in C.I also used XModem and TeraTerm. The difference is that I send a bin file via XModem.I suggest you to disable interrupts when deleting or writing to memory.

author: MIS42N
author_rank: Frequent Contributor
timestamp: November 21, 2021, 01:46:53 am
content: Quote from: 8goran8 on November 20, 2021, 09:03:33 pmThanks.I should update this, I have documented the source code now, and modified it to be a two pass operation. The first time, the loader checks all the checksums are valid (and if the transfer was not corrupted). It then says 'OK' and waits for a second pass that does the actual programming. That way, if the first pass fails for any reason, nothing is changed.The intent of the code was it is part of a bigger program that has a serial interface. In the particular program this is part of, the user types <TAB>P and the program then doesCode:BCFINTCON,GIE ; Disable interruptsLGOTObootstrapSo interrupts are disabled for the whole time the bootstrap is run. All transfers use polling for input, and it isn't necessary on output because it only sends one or two characters at a time.It can be used as a separate program, to load another program later on. In that case the processor starts with interrupts disabled and they aren't enabled by the loader.The one disadvantage is that to use the bootloader more than once, the user has to have some way of invoking it from any program they load. I haven't looked to see how Arduino code manages to fire the bootstrap every start then decide it doesn't need to run and switches to the program. For my purpose how it works is fine. I only want to send users a program that I have tested already, so each Version will be able to update itself to the next version.

author: MIS42N
author_rank: Frequent Contributor
timestamp: November 21, 2021, 01:54:49 am
content: The source attached to Post #1 has been updated.

author: 8goran8
author_rank: Contributor
timestamp: November 21, 2021, 08:27:33 am
content: QuoteAccording to datasheet, row erase size is 32 words so, if you want to use the space above the bootloader to store variables, you have to reserve that space only for variables. The bootloader must not be in that space. Otherwise, the user program will dill with the part of the bootloader when changing the contents of the variables and I don't think that's a good option.QuoteIn my case, the bootloader is always booted first. If it does not receive the appropriate instruction from the serial port within a certain interval, the bootloader runs the user program.