Quantcast
Channel: Forums - Recent Threads
Viewing all articles
Browse latest Browse all 262198

CC1310: Firmware upgrade HOWTO

$
0
0

Part Number:CC1310

Our Goal:
    We have a program running on CC1310.
    This program is able to receive binary file either through some serial interface or through radio or using any other method.
    We want to rewrite the running program with a newer version contained in received binary file.
    
Definitions and constraints:
    Internal flash memory:
        CC1310 contains internal flash memory with limited number of rewrites through its lifetime.
        CPU pipeline fetches instrucitons directly from this flash when it is running - so we can not rewrite those sections of internal flash that are just executing.
        The internal flash is divided into 32 pages, each consisting of 0x1000 bytes.
        When rewriting the internal flash, we have to erase a whole page and then write data to that page.
        End of the last memory page contains special section - ccfg. This section is read by the hardware and it should be always valid and it can not be moved - otherwise the cc1310 would lock itself up.
    
    Reset vectors:
        When the cc1310 starts, it will automaticaly read first 8 bytes of the flash memory and will interpret them as a reset vector.
        We need to have a reset vector on position 0x0.
        If there is not a reset vector on position 0x0, you need the RESET pin of the cc1310 to be connected to the debugger in order to be able to flash something new to the internal flash.
        The internal flash can contain multiple programs, each program is expected to have its own reset vector (but only the vector on 0x0 will be started automaticaly on power up).
        We can use the following code to reset the running program and run program whose reset vector is located on position 0x1000:
          asm(" MOV R0, #0x1000 ");
          asm(" LDR R1, [R0, #0x4] ");
          asm(" LDR SP, [R0, #0x0] ");
          asm(" BX R1 ");
    
    Linker configuration:
        Each project in Code Composer Studio contains a linker configuration file (any file that ends with .cmd).
        This file describes what sections of generated code will be put where in the output binary.
        This is useful when we want to put programs in particular flash memory pages.
        If the project uses XDCtools, second linker configuration file (.cmd) will be generated by the XDCtools script in build directory.
        XDCtools are configured with a .cfg file located in project directory.
        When the linker is run, it will also generate a map file (ends with .map) in build directory.
        The map file contains text log describing, what sections were put where.
        So we can use the map file to verify that we configured the linker correctly (and that all the sections of program are located in correct memory pages).
    
    Generating hex files:
        We need one binary / hex file to be flashed into memory when updating firmware.
        How do we generate these exact binary data that can be directly cloned to the internal flash memory?
        Usualy the linker generates only an .out file - it is an ELF binary.
        I am not sure how different it is from our desired binary executable file, but it is not exactly what we need.
        The Code Composer Studio contains a ARM Hex Utility.
        This utility can be setup in project properties using GUI.
        But I found that it is easier to just go to project properties -> Build -> Steps (tab) -> Post-build steps and put this there:
            ${CG_TOOL_HEX}  -order MS --memwidth=8 --romwidth=8 --intel -o ${ProjName}.hex ${ProjName}
        The hex tool should in both cases generate a .hex file in the build directory.
        The hex file contains the binary encoded in intel hex file format (description of this format can be found on wikipedia).
        This can be easily converted to the final binary.
        You can test the hex tool by generating the hex file and then using Flash Programmer 2 to flash in into your cc1310 and checking if the program works on it (it should).

Basic idea of our solution:
    We will have an external memory connected to our cc1310 via SPI interface.
    The program in cc1310 will consist of two parts - custom bootloader (BIM - boot image manager) and the main program.
    The BIM will be located in the first memory page possibly with some extra data in the last page.
    Memory pages 1 - 30 will contain the main program.
    The last page will contain the CCFG section and may also contain some BIM data.
    The reset vector of the BIM is located on position 0x0 and reset vector of main program is located on position 0x1000.
    When cc1310 starts, it will start executing the BIM code.
    The BIM will communicate with external memory to check if some new firmware is located in it.
    If external memory contains new firmware, BIM will read it block by block and will use it to rewrite pages 1 - 30 that contain the main program.
    Once BIM is finished (either it rewrote the program or it did not find any new firmware), it will reset the board using initialization vector on position 0x1000 (start of first page where the main program starts).
    The main program can do its usual job but it can also issue the firmware update by writing new firmware into the external memory and restarting the board (either by using BIM initialization vector on position 0x0 or by calling software reset: { #include <driverlib/sys_ctrl.h>, SysCtrlSystemReset(); }.
    

Step 1 - BIM project:
    The BIM should be as small as possible, it should not use TI-RTOS or any other big libraries or runtimes.
    So I started with the sample bim_offchip project: "SimpleLink cc13x0 SDK 2.10.00.36/Examples/Development Tools/CC13130 LaunchPad/EasyLink/bim_offchip" (dev.ti.com/.../
    The main() is located in Application/bim_main.c.
    Lets simplify the main function for now - just replace content of the main() function with this:
    
    #include "driverlib/gpio.h"
    #include "driverlib/ioc.h"
    #include "driverlib/prcm.h"
    void main()
    {
         // Power on periperal domain
        PRCMPowerDomainOn( PRCM_DOMAIN_PERIPH );
        while( PRCMPowerDomainStatus( PRCM_DOMAIN_PERIPH ) != PRCM_DOMAIN_POWER_ON );

        // Power on the GPIO peripheral
        PRCMPeripheralRunEnable( PRCM_PERIPH_GPIO );
        PRCMLoadSet();
        while( !PRCMLoadGet() );
        
        // enable output for the LED
        GPIO_setOutputEnableDio( IOID_5, GPIO_OUTPUT_ENABLE );
        GPIO_setDio( IOID_5 );
        
        //
        while( 1 );
    }
        
    Replace the two occurences of IOID_5 there with any pin that will be used as output.
    I am starting this simple because in my case, even this did not work properly.
    
    Build the program and look into the .map file generated by the linker that is in the build directory and check if everything is ok - everything should be in page 0 (0x0 - 0x1000) or in page 31 (0x1f000 - 0x20000), the beginning of page 0 should contain reset vector (section .resetVecs or .intvecs) and end of page 31 (I am not sure about the exact required position) should contain the .ccfg section.
    If something is not right in the .map file, try to fix it in the linker configuration file (.cmd).
    I had problem with the .intvecs section - it was specified in .cmd file but it did not appear in .map file, I am not sure why.
    I solved this issue by copying file "c:\ti\simplelink_cc13x0_sdk_2_10_00_36\source\ti\devices\cc13x0\startup_files\startup_ccs.c" into the project (bim_extflash_cc1310lp/Application/startup_ccs.c).
    
    If the .map file looks ok, flash the program into cc1310 (in CCS: Run->Debug).
    The pin IOID_5 should be outputting logical 1 and that should work even after power-cycling the board (if this functionality does not persist after power-cycling the board, there is a problem with the reset vector).
    
Step 2 - create main program:
    Create some simple program that for example blinks some diodes (it can use TI-RTOS and everything).
    Make sure that the program is working under normal circumstances (without bootloader).
    When it is working, we will move the program to pages 1 - 30 and let the reset vector be in the beginning of flash page 1.
    To do this, we will need to modify the linker .cmd file and also the XDCtools .cfg file.
    Most sections will be moved if we modify the FLASH_BASE and FLASH_SIZE macros in the .cmd file:
        #define FLASH_BASE   0x01000
        #define FLASH_SIZE   0x1F000
        
    The reset vector will be moved as well if it is defined in .cmd file. But if we use XDCtools, the reset vector is probably controlled by it and we need to move it in the .cfg file:
        m3Hwi.resetVectorAddress = 0x1000;
    
    When using XDCtools, we also need to comment out the "ROM configuration" section in the .cfg file.
    The ROM configuration does something like fixing some parts of TI-RTOS to flash page 1, which reduces its size but it can not be used if the program does not start on page 0 (it triggers a linker error).
    I did it like this:
        /* ================ ROM configuration ================ */
        /*
         * To use BIOS in flash, comment out the code block below.
         */
         /* Can not run TIRTOS in ROM with BIM
         /*
        var ROM = xdc.useModule('ti.sysbios.rom.ROM');
        if (Program.cpu.deviceName.match(/CC26/)) {
            ROM.romName = ROM.CC2650;
        }
        else if (Program.cpu.deviceName.match(/CC13/)) {
            ROM.romName = ROM.CC1350;
        }
        */
        
    This can not be realy tested to work (we could move or possibly just manualy copy the reset vector to 0x0, but that seems like an unnecessary test).
    So just make sure that the program builds succesfuly and look in the .map to see if the reset vector (section .resetVecs or .intvecs) is in the correct location (0x1000) and that all other things are on pages 1-30 except for .ccfg that should be at 0x0001ffa8 (around the end of the last page).
    
Step 3 - combine BIM and main program:
    Modify the BIM main function:
        void main()
        {
            asm(" MOV R0, #0x1010 ");
            asm(" LDR R1, [R0, #0x4] ");
            asm(" LDR SP, [R0, #0x0] ");
            asm(" BX R1 ");
        }
        
    Flash main program to cc1310 (Run->Debug in CCS).    
    Flash the BIM to cc1310 (Run->Debug in CCS).
    Because both programs use mostly different flash pages, they should not overwrite each other.
    Only the last flash page with ccfg section is in both programs.
    That is why the BIM should be flashed after the main program - they both use the same .ccfg section in last memory page but BIM might have something more there.
    Now power-cycle the board and the second program should be started - if it is a LED blinking program, the LEDs should be blinking.
    
    If you want to have the whole binary (combined BIM and main program), just generate the .hex files from them and then combine those hex files.
    It is quite easy to do that by hand or a script can be made to do that.
    There is a script to do that packed with SimpleLink sdk (simplelink_cc13x0_sdk_1_40_00_10/tools/easylink/oad/oad_image_tool.py) but I think that this script only works when the reset vector of main program is located on 0x1010 (the first 16 bytes of page 1 are used for metadata).
    Python has a IntelHex library that can be used to combine those hex files.

Conclusion:
    That should cover all the basic building blocks of a program capable of firmware update.
    When this is working, it can be improved in various ways - it might be interesting to have the whole bootloader in the last page, so that we have one more page for our main program and we can enable the ROM configuration section in .cfg file (the bootloader will be either called from the main program on demand or it will have just the reset vector in first page).
    API for rewriting internal flash memory is in "driverlib/flash.h" - FlashSectorErase(), FlashProgram().
    We can use uart to read the binary from external location or we can use half of internal flash pages as executable section and the second half as new firmware storage.


Viewing all articles
Browse latest Browse all 262198

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>