News:

Let's find out together what makes a PIC Tick!

Main Menu

MQTT With a Bootloader

Started by Craig, Jan 27, 2023, 01:15 PM

Previous topic - Next topic

Craig

Hi I am Busy with a Project where a Gateway is installed in a Remote location and will use MQTT to do it's communication via the GSM Network. I need to  install a Bootloader on the Pic 18F47K40 (or Similar) through which I can do Remote Firmware upgrades over the Air Via the MQTT Mosquito Network. I was looking at the DS30 Secure Bootloader  https://www.ds30loader.com/index.php/products/ds30-loader
Has anyone used the secure bootloader from DS and is this the best option to look at, My concern is with overall Hacking and security which is on the increase globally?

All help is very much appreciated!
Regards
Craig
 

trastikata

#1
To have more control I'd write own bootloader and put it in the boot or lower sectors which I can lock from being overwritten, make sure the fuse configuration is also locked and can't be modified by the chip itself.

Use a watchdog, and put a successful firmware update "marker", store the original firmware in a EEPROM/FLASH chip which can be recovered if firmware update fails. This way you can have a program "self" recovery future in case of failure.

As for encryption over the air - no need - you can put all kinds of simple security measures, like sequence of commands or codes, only after which the firmware can be updated.   

P.s. Writing a bootloader is very simple and straightforward.

Gamboa

Craig,

I have used the secure bootloader of DS30 loader for a development that I did with PIC18F25K22.
The advantage of this system is that you can send the .hex file to the client to put it. In your case, as it is via radio, it is not necessary to send the client the .hex file, but I think it is convenient to always encrypt in commercial applications.

Regards,
Gamboa
Long live for you

John Lawton

I've used bootloaders from DS30. Mikael is very helpful.

Craig

Thanks very much for the feedback Trastikata, Gamboa and John very much appreciated. I will have to definitely control the flashing process as if it fails I will have to have a mechanism for rebooting the firmware.
Kind regards
Craig 

Frizie

Trastikata, you wrote "Writing a bootloader is very simple and straightforward".

What was your first step (where did you start?)
I need a bootloader for the 18F45K22 and would possibly write it myself, but where and how to start?
And in what language do you write a bootloader for a PIC18F45K22?
Ohm sweet Ohm | www.picbasic.nl

trastikata

#6
Quote from: Frizie on Jan 28, 2023, 07:49 PMWhat was your first step (where did you start?)
I need a bootloader for the 18F45K22 and would possibly write it myself, but where and how to start?
And in what language do you write a bootloader for a PIC18F45K22?

I used TimB's (apologies if I am mistaken about the author) article on the old Proton page, which is no longer existent.

Bootloader is just a program as any other a I wrote it in Positron, if you talking about the PC host program, I used MS VisualStudio to write it because I wrote USB bootloaders using USB HID interface for 18F4550(3), 18F26(5)J50, 18F26(5)J50, 18F14(3)K50 ....

- See if you can fit the bootloader in a (how many) Program Flash Page (blocks) that you can protect.
-- I see 18F45K22 has Boot Block (000h-7FFh) and Block 0 (800h-1FFFh) - probably the boot block will be enough, depending what you need as code

- Set the fuses in your bootloader to protect those Blocks
- Set the fuses in your bootloader to protect the Configuration Words page

- Determine:
-- The address where your main code starts (say only Boot Block is Protected) - 0800h - based on protected blocks
-- End of the code space - 3FFFh - based on memory size
-- Flash erase block size - 64 bytes - see datasheet, might be different from write size i.e. 1024 bytes
-- Flash write block size - 64 bytes - see datasheet
-- Where to put a marker indicating the program flash status (EEPROM or FLASH)

- Think of some commands to accept for erase, write and finish flashing depending on if it is an external (USB. Serial) or internal (EEPROM/FLASH chip) to the device 

- Remap interrupt vectors

- Start program
-- Use some way to verify if firmware update is required
--- If previous flashing was unsuccessful (successful flash marker not set)
--- Forced - by button, PC host command etc
-- If not, Call (Go to) the main code start address (0800h for example)

- Flashing
-- Set "successful flash marker" to Not
-- Request and Receive flash address and data
-- erase block based on the write address - CErase Address - respect boundary sizes of 64 bytes in your case
-- write block based on the write address - CWrite Address, [Data] - writes are executed in blocks of 64 bytes in your case
-- Set "successful flash marker" to Yes
-- Call (Go to) the MainCodeStart (0800h for example)

I am attaching just a snippet of my bootloader where I have cut out most of the communication protocol between the PC host and the Bootloader, but I've left the important part that demonstrates the principle, described earlier, so this is not a code that you can compile right away.

As for the communication protocol and different check-ups - it is something you need to decide upon depending on the the individual application requirements - for example where and how the data is presented to the bootloader, who is the Master and Slave in this process, commands etc,



Device = 18F25J50
Declare Xtal = 48

Include "USB_Bootloader.inc"
'VID = 6017
'PID = 2031 (arbitrary PID for Bootloader request)

On_Interrupt     GoTo USER_HIGH_INTERRUPT_VECTOR   ; RE-MAP INT VECTORS
On_Low_Interrupt GoTo USER_LOW_INTERRUPT_VECTOR    ; RE-MAP INT VECTORS

Config_Start
  WPFP = PAGE_3    ;Write Protect Program Flash Page 63
  WPEND = PAGE_0    ;Page 0 to WPFP<5:0> erase/write protected
  WPCFG = On    ;Configuration Words page is erase/write-protected
  WPDIS = On    ;WPFP<5:0>/WPEND protected
Config_End

Symbol MainCodeStart            = 5120                          ; Main code start address / Keep on boundry
Symbol EndOfCodeSpace           = 32767                         ; End of code space
Symbol FlashEraseSeg            = 1024                          ; The size of memory bank erased in one go
Symbol FlashWriteBlock          = 64                            ; The memory size Flash write needs to do in one block
Symbol FlashClearedStatus       = 4992                          ; Address in Flash of the current status of the eeprom if cleared etc
Symbol EraseProgram             = $01                           ; Erase memory ;
Symbol WriteFlash               = $02                       
Symbol FinishWrite              = $03                           ; Finish the write ;
Symbol RunMainCode              = $04                           ; Run the main code above the bootloader

Main:
    BootOk = CRead FlashClearedStatus       'Read Flash update marker       
   
    If BootOk = "O" Then                                           
        GoTo CheckUSBRequest                'It was OK
    Else
        GoTo ForceBootMode                  'It wasn't OK                     
    EndIf 

CheckUSBRequest:
    'USB connected?
    '- Yes - go to ForceBootMode
    @ Call MainCodeStart    '- No - call main program 

ForceBootMode:
    '- Wait for Flash command
    ' Flash command received
    ' Set Flash Marker to Not OK (because the device has no EEPROM I use Flash memory and write the entire 64 byte block)
    For i = FlashClearedStatus To FlashClearedStatus + 63
        CWrite i, ["N"]
    Next
   
EraseProgramData:   
    'Received a command to Erase the Program memory
    'Erase it in segments 
    For PromAddress = MainCodeStart To (EndOfCodeSpace - FlashEraseSeg) Step FlashEraseSeg
        CErase PromAddress
        DelayMS 8
    Next       
   
WriteFlashData:
    'Received data for flashing at address PromAddress and put the data in a buffer of corresponding size
    For i = 0 To 63
        bTemp = FlashBuffer[i]
        CWrite PromAddress,[bTemp]
        Inc PromAddress
    Next     
    DelayMS 8
   
WriteFlashDataEnd:     
    'Received command for end of flash program
    'Update Flash Marker to  OK (because the device has no EEPROM I use Flash memory and write the entire 64 byte block)
    For i = FlashClearedStatus To FlashClearedStatus + 63
        CWrite i, ["O"]
    Next
   
    'Call main program
    @ Call MainCodeStart 
   
Org  MainCodeStart + $8
USER_HIGH_INTERRUPT_VECTOR:
Org MainCodeStart + $18
USER_LOW_INTERRUPT_VECTOR:

P.s. I forgot to mention that you need to offset your main code to start at the corresponding address in the Bootloader, this is done by using the Positron command:

Declare Compiler_Start_Address = xxxx 

(xxxx = main code start address = 0800h = 2048 in your example)

P.p.s. To parse and send the flash data to the bootloader, you will need an understanding of the *.hex file, which is being generated by Positron. There are different sites but I find it excellent the file format description in the following link:

https://www.kanda.com/blog/microcontrollers/pic-microcontrollers/pic-hex-file-format/

Frizie

Thank you very much for your very comprehensive answer Trastikata!  :D
I'll be on vacation soon so I'll get to it.
This is a first start :)
Ohm sweet Ohm | www.picbasic.nl

Craig

Thanks very much Trastikata for the very informative explanation much appreciated!
regards
Craig