• AVR Freaks

EZBL & OTA with PIC24FJ1024GB610

Author
mgleria
New Member
  • Total Posts : 16
  • Reward points : 0
  • Joined: 2017/06/22 12:18:48
  • Location: 0
  • Status: offline
2018/08/22 11:17:28 (permalink)
0

EZBL & OTA with PIC24FJ1024GB610

Hi everyone,
I'm working on my thesis project. For short explanation, it consists of a telemetry unit which senses some variables and sends reports to a remote server through a 3G Modem (TELIT UL865-NAD). All this running above FreeRTOS V9.0.0.
I need to be able to update the FW of my running app receiving the new firmware from the remote server using the same UART that I'm using to send and receives messages with it. That put me in a difficulty, I need to have two different sets of ISR for that UART. 
I was looking how could I achieve that, and I found 2 different approaches:
  1. Write a big ISR function which includes the logic for my app and the logic for EZBL library, and at runtime, choose one of them using a flag.   
  2. Write two separate ISR functions, define a function pointer which has to be initialized to one of the two ISR functions and save this function pointer to the designated register that holds the ISR pointer. Then, at runtime, I will be able to change this function pointer so I could change the ISR. (I'm not sure if this has been done yet) 
Recently I found on release notes of the new EZBL Library that there is a new API that allows modifying differents registers related to Interrupt handling. I quote the point of interest (#2 of New ezbl_lib APIs section):
EZBL_RdIntFlag(), EZBL_WrIntFlag(), EZBL_ClrIntFlag(), EZBL_SetIntFlag(), EZBL_InvIntFlag(), EZBL_RdIntEn(), EZBL_WrIntEn(), EZBL_ClrIntEn(), EZBL_SetIntEn(), EZBL_InvIntEn(), EZBL_RdIntPri() and EZBL_WrIntPri() added. These provide a means to run-time manipulate IECx, IFSx and IPCy bitfields by IRQ number without needing to statically specify which registers and bit positions are applicable during build time.
Another related question is which partition mode should I choose? I think I should take advantage of Dual-Partition Mode that my PIC24F supports, but I'm not sure if that is my best choice. It is not a critical application, it could deal with downtimes. 
 
I have no experience with OTA updates of firmware, neither with EZBL library, this will be my first time. I will appreciate any clue that anyone could give me. 
 
Thanks all!
 
#1

7 Replies Related Threads

    HowardSchlunder
    MCU16 Applications
    • Total Posts : 746
    • Reward points : 0
    • Joined: 2007/06/14 16:26:19
    • Location: Chandler, AZ
    • Status: offline
    Re: EZBL & OTA with PIC24FJ1024GB610 2018/08/22 13:28:32 (permalink)
    5 (1)
    I suggest using the ex_boot_app_blink_dual_partition project in EZBL v2.10.
     
    For OTA bootloading, it generally is quite advantageous or necessary to implement a "memory" type Bootloader where the existing Application doesn't get erased until after the new firmware image is saved locally in its entirety and verified with a checksum or hash. This ensures a transient OTA communications failure does not disrupt the reprogramming process and orphan the device without a way to retry OTA communications or have a valid Application to execute in the interim while waiting for the OTA medium to come back online.
     
    The PIC24FJ1024GB610 in Dual Partition mode is indeed a convenient and appropriate route to achieving OTA reprogramming. The ex_boot_app_blink_dual_partition project in EZBL implements Dual Partition mode and ping-pongs between the two partitions, allowing complete OTA programming, read-back verification and execution testing of the new firmware without erasing the previous Application image.
     
    As far as sharing the communications medium for firmware updates and application messages, I suggest using the existing EZBL_FIFOWrite()/EZBL_FIFORead()/EZBL_FIFOPeek()/etc. APIs in EZBL for doing your application-level messaging. The protocol EZBL implements is file oriented and entirely passive until the remote node starts sending the new firmware image to the bootloader, so it is inherently trivial to share the medium. The only real restriction you will have in your Application code is that you can't pop/delete data from the RX FIFO and shouldn't generate TX data while bootloading is actively underway. This is done by simply qualifying read/write operations with if(EZBL_COM_RX == 0). EZBL_COM_RX is a global pointer that is set to null when the bootloader is idle/inactive and set to a communications FIFO address when a firmware update image is being received/programmed.
    #2
    mgleria
    New Member
    • Total Posts : 16
    • Reward points : 0
    • Joined: 2017/06/22 12:18:48
    • Location: 0
    • Status: offline
    Re: EZBL & OTA with PIC24FJ1024GB610 2018/08/23 05:18:05 (permalink)
    0
    Thanks a lot, @HowardSchlunder. I really appreciate your guidance. 
     
    I will follow your advice, starting by analyzing how EZBL_FIFOWrite()/et. works, in order to be able to adapt my app-level messaging. 
     
    Your last advice regarding EZBL_COM_RX lets me a doubt, Who is responsible for changing this pointer?
     
    Thanks again!
    #3
    HowardSchlunder
    MCU16 Applications
    • Total Posts : 746
    • Reward points : 0
    • Joined: 2007/06/14 16:26:19
    • Location: Chandler, AZ
    • Status: offline
    Re: EZBL & OTA with PIC24FJ1024GB610 2018/08/27 20:55:25 (permalink)
    5 (1)
    EZBL_COM_RX is a global pointer defined in ezbl_lib.a:weak_defaults/EZBL_COM_RX.c, set to a null value by the compiler provided reset/start up data initialization routines (and/or main.c initialization), set to a non-null value in an asynchronously executed communications peripheral ISR (ex: _U1RXInterrupt(), _U2RXInterrupt(), _SI2C1Interrupt(), etc.), read/used by the main bootloading functions (EZBL_Install2Flash() or EZBL_Install2IP()) and written back to null at bootload termination within the same EZBL_Install2Flash()/EZBL_Install2IP() function.
     
    EZBL_COM_RX, along with the paired EZBL_COM_TX global pointer, serve the purpose of dynamically defining at run-time which communications peripheral and peripheral instance number has begun receiving a firmware update offer/request. The Application's .bl2 flash image is read verbatim from *EZBL_COM_RX while the EZBL_COM_TX pointer gets used for flow control and status transmissions back to the PC or other entity that has initiated the firmware update/is providing the .bl2 file contents.
     
    To minimize processing overhead within ISRs, each communications ISR peeks for a fixed, 8-byte bootloader wake-up string, but otherwise does no bootloader state handling or erase/programming and instead just copies all RX/TX bytes from/to hardware SFRs and larger RAM FIFOs for low priority decoding/use/status generation. Upon exact-match detection of the 8 byte wake-up string, the EZBL_Install2Flash()/EZBL_Install2IP() function wakes up and begins looking for a much longer 48-byte, globally unique Bootloader ID + App image version ID + fixed header fields to determine if the wake-up was a false collision with arbitrary application-level data on the same medium, or if not, if the .bl2 file is appropriate for the hardware and suitable for programming. If a false collision or non-Applicable Bootloader ID is detected, EZBL_Install2Flash()/EZBL_Install2IP() write EZBL_COM_RX back to null and go back to sleep. If the firmware is ultimately accepted for programming, interrupts are typically disabled (to prevent other communications ISRs changing EZBL_COM_RX if they happened to also find a bootloader wake-up match), the specific TX/RX/Timing ISRs needed for bootloading are turned back on, flash is erased, and bootloading proceeds over the currently assigned EZBL_COM_RX/EZBL_COM_TX file/status streams.
     
    Because EZBL_COM_RX is written to within communications ISRs and nullified when no longer needed, each check for null represents an instantaneous boolean check to see if the Bootloader owns the communications peripheral at the moment or if the communications peripheral can be used for arbitrary other application communications purposes. The 8-byte wake-up test is a sufficiently long bit-string such that it is extremely unlikely the wake-up string will accidentally collide with application-level data and cause the Bootloader to steal RX bytes from the FIFO. The converse of having the Application steal Bootloader data is, however, quite likely if the Application code is not designed to suppress FIFO reads when the EZBL_COM_RX == 0 test fails.
    #4
    mgleria
    New Member
    • Total Posts : 16
    • Reward points : 0
    • Joined: 2017/06/22 12:18:48
    • Location: 0
    • Status: offline
    Re: EZBL & OTA with PIC24FJ1024GB610 2018/09/02 15:32:02 (permalink)
    0
    I was surprised by how much do you know about EZBL until I see your name on author comments on the library code and I suddenly understood everything. 
    Thanks again for taking the time of explaining the great job that it is EZBL Library. 
    I followed your pieces of advice, and after to try individually differents API functions to write and read to/from a UART FIFO, I started to regenerate the ex_boot_app_blink_dual_partition MPLAB project mixed with my application, according to the documentation notes. I paid special attention to hardware configurations, and I finally was able to do sort of "merge" between my configurations, made mostly with MCC plugin, and the configurations present on pic24fj1024gb610_explorer_16.c file, from ex_boot_app_blink_dual_partition project.
     
     
    I'm having problems with NOW_Reset(TMRx, FCY) API call. It is generating an error at runtime, that is trapped on TRAPS_halt_on_error(uint16_t code) [code=0] function when I'm trying to start debugging the application. That function is created by MCC plugin. I'm currently using TMR1, TMR2 & TMR3 for other purposes, so I tried with TMR4 & TMR5 with the same negative result. 
     
    I know that this will be a really broad question, but, any idea of what would be my most probable mistake here?
     
    When I find the cause of this, I will do a small PoC to try communication between my PIC24F and a modem Telit through UART2. When that is ready, my application should work just like now, but now using EZBL APIs instead of an MCC UART2 driver. 
     
    And right after that is achieved, I have to start thinking about how to solve the server side of this solution. I'm talking about how to get an FW update remotely from the server. I imagine that the server has to do the job that is doing ezbl_tools.jar on my laptop? Am I right? 
     
    Thank you again!
    #5
    HowardSchlunder
    MCU16 Applications
    • Total Posts : 746
    • Reward points : 0
    • Joined: 2007/06/14 16:26:19
    • Location: Chandler, AZ
    • Status: offline
    Re: EZBL & OTA with PIC24FJ1024GB610 2018/09/06 17:46:49 (permalink)
    5 (1)
    I can't think of a particular reason why/how NOW_Reset() would cause a trap. TMR4 and TMR5 should work fine, as well as CCP1, CCP2, CCP3, CCP4, CCP5, CCP6 or CCP7 on your PIC24FJ1024GB610 device. You aren't calling NOW_Reset() in two or more places with a different TMR/CCP specified, are you? Also, you haven't tried to configure the selected timer using MCC, have you?
     
    Multiple NOW_Reset() calls to change the frequency should be fine, but the timer needs to be the same between calls. NOW_Reset() initializes/enables the timer peripheral SFRs, configures the interrupt priority and enable bit, and generates a linker reference to include the correct interrupt function, so you shouldn't configure or try to use the same timer peripheral instance in MCC.
     
    To figure out what is happening, you likely need to change the trap code so you can return from it and see where the PC was. To return from a trap, execute INTCON1 &= 0x8700; and let the handler exit rather than enter an infinite loop.
     
    It may be possible to assign PPS pins, call UART_Reset() prior to the NOW_Reset() call, remove the MCC trap handlers, and add EZBL_KeepSYM(EZBL_TrapHandler); to any .c source file to get relatively detailed text debugging information printed to the UART. This will include the trap return address, which can be looked up in the .map file, the IDE's Program Memory view, or best, by disassembling the .elf file from a command line using xc16-objdump.exe:
    cd \ezbl-v2.11\ex_boot_app_blink_dual_partition
    "C:\Program Files (x86)\Microchip\xc16\v1.35\bin\xc16-objdump.exe" --full-contents --disassemble --source --disassembler-options=symbolic dist\uart\production\ex_boot_app_blink_dual_partition.production.elf > dump.s
    start dump.s
     
    What type of hardware/OS makes up your server? Starting in EZBL v2.10, ezbl_tools.jar is actually just a pass through process that launches ezbl_comm.exe to do the actual communications with the bootloader. The idea is that ezbl_tools.jar can be launched from Windows/Mac/Linux alike, whereas each OS needs a separately compiled ezbl_comm.exe file, so ezbl_tools.jar can auto-select the correct file to launch. Since ezbl_comm.exe has currently only been compiled for Windows, your server really just needs to do the job of ezbl_comm.exe, not ezbl_tools.jar.
     
    The ezbl_comm project is fairly simple and tries to be as portable as possible, so you may be able to recompile it on your server, even if it isn't using Windows or is an SoC of some kind. However, the EZBL communications protocol is quite simple, so you may alternatively want to just reimplement the essential functionality in a language and environment of your choice. The documentation for this protocol is in help\EZBL Communications Protocol.pdf.
     
    Lastly, in Dual Partition mode, there is a rather short spool up delay as the Bootloader can erase the Inactive Partition in only ~20ms rather than sequentially blank-check and erase flash pages at ~20ms each. This also doesn't block the CPU and UART RX interrupt. Therefore you can perhaps implement nothing and just copy the new firmware.bl2 file to the modem in binary form. With a sufficiently slow baud rate and/or large UART2_RxFifoBuffer declaration, a binary file copy won't overflow the RX FIFO during the erase delay and then programming will complete faster than you can feed it new data. This makes it possible to perform an open-loop firmware update using only the server TX data and no RX channel (or lack of decoding and consumption of the RX data in software on your server). Obviously, you'll lose all status information doing this, but sometimes simple is nice. I observe success executing this in a Windows console:
    cd \ezbl-v2.11\ex_boot_app_blink_dual_partition\dist\uart\production
    mode COM21 BAUD=38400 DATA=8 STOP=1 octs=off to=off
    copy /b ex_boot_app_blink_dual_partition.production.bl2 \\.\COM21
    #6
    mgleria
    New Member
    • Total Posts : 16
    • Reward points : 0
    • Joined: 2017/06/22 12:18:48
    • Location: 0
    • Status: offline
    Re: EZBL & OTA with PIC24FJ1024GB610 2018/09/30 18:49:24 (permalink)
    0
    Thank you so much, Howard. Your comments really help me to move forward. Is far from finished yet, but I could do another step.
    I tried your first advice for debugging but I must have done something wrong, I did not succeed in that test. But I got an ICD3 debugger and when I tried it, I figured out that the problem wasn't where I said (NOW_Reset() API call), It was instead on a call to printf() function on my app, after comment that lines the program didn't crash anymore. I was previously using embedded Pickit in the Explorer16/32 board.
    I imagine that there is a conflict when EZBL library associates STDOUT with its functions and I try to use printf() function instead.
    I was currently using in my project 2 UART, one for modem communications and now for FW updating, and the other to interact with a PC using a minimalist shell that I coded and also for debugging and control messages.
    Since I can not use printf() function, I thought that I could manage my two UARTs with EZBL library and use EZBL_print* functions, but when I tried to do that I realized that there is no apparent way of binding an EZBL FIFO* data structures to one general purpose UART, and that makes sense since EZBL is a library to deal with bootloaders, not with general purposes peripherals.
    So I have two possible scenarios to manage this:
    1. Use UART1 like general purpose UART with MCC driver (without use printf()) and leave UART2 for communicating with the modem through EZBL API calls.
    2. Use only one UART2 for both purposes, but I have to take care of guaranteeing mutual exclusion through a mutex.
    What do you recommend me at this point?

    On the other hand, you were very clear on the server side application related question. We have Debian based servers, so I will have to re-compile for it. But, since the server won't be using a local HW port to communicate with the remote PIC, I imagine that I will have to reimplement the essential functionality like you said, to adapt it to my needs. 
     
    Once again, thanks for your time and for sharing your knowledge.
     
    Have a great week! 
    #7
    mgleria
    New Member
    • Total Posts : 16
    • Reward points : 0
    • Joined: 2017/06/22 12:18:48
    • Location: 0
    • Status: offline
    Re: EZBL & OTA with PIC24FJ1024GB610 2018/10/07 18:39:12 (permalink)
    0
    Hello again Howard and community!
     
    Regarding my last question, I took the approach 1.
     
    I have one more question about it. I understand that there should be associated 2 EZBL_FIFO* with the peripheral which is configured through UART_Reset() function.  
    According to the comments on ezbl.h, and I quote, UART_Reset() function return:
     
    * @return (EZBL_FIFO*) pointer to the UARTx_RxFifo implemented by the given
    * UART FIFO library. This is equivalent to &UART1_RxFifo,
    * &UART2_RxFifo, &UART3_RxFifo, etc., depending on the peripheralNum
    * input parameter.
    So, my question is: How can I associate a UART2_TxFifo (EZBL_FIFO*) with the peripheral in order to avoid the use of EZBL_printf() and use instead EZBL_FIFOWrite()? In fact, the only way I could send a message through UART2 was using EZBL_printf (). 
     
    I want to unlink STDIN and STDOUT from UART2 (useForStdio=0) and link it with UART1 which I'm handling with the MCC driver, This way I could use the function printf() with UART1 as I was doing previously in my app. 
     
    Thanks again for your time and help. 
    #8
    Jump to:
    © 2020 APG vNext Commercial Version 4.5