This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320F28388D: How does one go about writing a bootloader for the CM processor?

Part Number: TMS320F28388D
Other Parts Discussed in Thread: C2000WARE

Hi,

I know it is possible to store a bootloader in alternate Flash sector and have CPU1 instruct the CM to boot from this sector during a firmware update. However, the ideal scenario would have the bootloader only existing in RAM as part of the firmware update process. The issue with getting a bootloader into RAM is that the CM boot mode that loads external data, IPC Message RAM boot, has a limit of 2000 bytes.

As a result of this limit, it is not possible to directly load a bootloader that contains the Flash API. One possible way around this is to load a smaller bootloader that then proceeds to load the proper Flash reprogramming bootloader. A solution to a size-constrained boot mode has been documented for C6000 MCUs. Can this solution be adapted for C2000 MCUs?

If it can be adapted, then the issue then becomes more personal. I have no experience writing applications in Assembly. Experimenting with CCS projects suggest that it is possible to write this smaller intermediate bootloader in C. If it possible to write such an application in C, please confirm so; otherwise confirm that Assembly must be used.

Sincerely,

Howard Li

  • Howard

    I don't think writing assembly will be necessary. C code will be easier and faster to write while with the optimizer enabled be fairly close to assembly. 

    Suggestion: You could load a small starter program via the IPC message RAM boot and then once that is running have CPU1 send additional data (such as the flash library). Since to use IPC message RAM boot you already need CPU1 interfacing with CM via the user application. 

    From a high level overview, a similar to the C6000 solution won't be possible if you want the CM using an EMIF. CPU1 does have EMIF, but I still feel my suggestion above would be easier.

    Best regards

    Chris 

  • Hi Chris,

    Thanks for confirming that it is possible to write the small starter program in C. Also, yes the CM will not be using any sort of EMIF.

    Now my next questions concern how the small starter program should be hexed using the armhex tool.

    • Should I enable the --boot option to generate the byte information in the boot table format?
    • What output format should I choose? The default according to the documentation is Extended Tektronix Object Format. I know that if I choose to use the --boot option, then I should probably use the --ascii output format for readability.
    • Comparing the hex utility output to the map file, I noticed that there is no occurrence of the function stack start address. Is that normal?
    • Should I translate the hexadecimal representation of the bytes to binary on the host side or the device side?

    Sincerely,

    Howard Li

  • Hi Chris,

    I have encountered an obstacle in transferring data from Message RAM to CM S0RAM

    I have specified the boot mode to be IPC Message RAM Copy and a sufficient copy length in CPU1TOCPU2IPCBOOTMODE yet nothing being transferred to the S0RAM.

    Sincerely,

    Howard Li

  • Howard

    Are you storing the CM app as part of the CPU1 flash? If so, you could use the "--array" option which puts the HEX image in an array that can be easily included in your CPU1 application. I believe you should see the stack address in there with this option.

    I assume you mean CPU1TOCMIPCBOOTMODE not CPU1TOCPU2IPCBOOTMODE. Make sure you're putting the data to be copied into message RAM 1 (starting address 0x0003 9400) and are looking at S0RAM start address + 0x800 (which is 0x20000800)

    Best regards

    Chris

  • Is it safe to omit the vector table on the CM application? I do not plan on using any interrupts.

  • Howard

    Yes that should be alright as it will use the boot vector table for any NMIs which does the following action for any NMIs: sends CPU1 an IPC indication of the NMI occurrence and then enters infinite loop. If that behavior is fine, then you don't need your own table.

    Best regards

    Chris

  • Also for future readers, one must make sure to "pack" the bytes. C28x processors don't have an 8 bit type, so uint8_t and char are actually 16-bits in length. Every two "bytes" must be packed into a single uint16_t using the following algorithm:

    for(int i = 0; i < raw_bytes_len; i+=2) {
        packed_bytes[i/2] = raw_byte[i]+(256*raw_byte[i+1]);
    }

    Failure to do so will result in bad bytes being written to the Message RAM and will result in the CM processor hard faulting.

  • Howard

    Valid point, thank you for sharing! I will make sure to mention this in the future as well.

    Best regards

    Chris 

  • Hi Chris,

    I have successfully used the small starter program to load a different program into CM S1RAM.

    How do I branch to the start of S1RAM (address 0x20004000) to start executing the newly loaded program?

    Sincerely,

    Howard Li

    EDIT: I tried out the ((void (*)(void))bootEntryAddress)() technique and it works as expected. Execution jumped to the newly loaded program (which, for testing purposes, was the blinking LED project)  and I was able observe the effects.

  • Howard

    Excellent! Yes, your use of ((void (*)(void))bootEntryAddress)() is the recommended technique.

    Best regards

    Chris 

  • The USB Flash kernel example for F2837xD had the following codestartbranch.asm

    ***********************************************************************
    
    WD_DISABLE	.set	1		;set to 1 to disable WD, else set to 0
    
        .global code_start
        .global _ExitBoot
    	.ref _main
    
    ***********************************************************************
    * Function: codestart section
    *
    * Description: Branch to code starting point
    ***********************************************************************
    
        .sect "codestart"
    
    code_start:
            LB wd_disable       ;Branch to watchdog disable code
    
    ;end codestart section
    
    ***********************************************************************
    * Function: wd_disable
    *
    * Description: Disables the watchdog timer
    ***********************************************************************
        .if WD_DISABLE == 1
    
        .text
    __stack:    .usect ".stack",0
    
    wd_disable:
        SETC OBJMODE        ;Set OBJMODE for 28x object code
        EALLOW              ;Enable EALLOW protected register access
        MOVZ DP, #7029h>>6  ;Set data page for WDCR register
        MOV @7029h, #0068h  ;Set WDDIS bit in WDCR to disable WD
        EDIS                ;Disable EALLOW protected register access
    ;    LB _c_int00         ;Branch to start of boot._asm in RTS library
    	LCR _main
    ; Cleanup and exit.  At this point the EntryAddr
    ; is located in the ACC register
        BF  _ExitBoot,UNC
        .endif
    
    ;end wd_disable
    
    
    ;-----------------------------------------------
    ; _ExitBoot
    ;-----------------------------------------------
    ;-----------------------------------------------
    ;This module cleans up after the boot loader
    ;
    ; 1) Make sure the stack is deallocated.
    ;    SP = 0x400 after exiting the boot
    ;    loader
    ; 2) Push 0 onto the stack so RPC will be
    ;    0 after using LRETR to jump to the
    ;    entry point
    ; 2) Load RPC with the entry point
    ; 3) Clear all XARn registers
    ; 4) Clear ACC, P and XT registers
    ; 5) LRETR - this will also clear the RPC
    ;    register since 0 was on the stack
    ;-----------------------------------------------
    
    _ExitBoot:
    
    ;-----------------------------------------------
    ;   Insure that the stack is deallocated
    ;-----------------------------------------------
    
        MOV SP,#__stack
    
    ;-----------------------------------------------
    ; Clear the bottom of the stack.  This will endup
    ; in RPC when we are finished
    ;-----------------------------------------------
    
        MOV  *SP++,#0
        MOV  *SP++,#0
    
    ;-----------------------------------------------
    ; Load RPC with the entry point as determined
    ; by the boot mode.  This address will be returned
    ; in the ACC register.
    ;-----------------------------------------------
    
        PUSH ACC
        POP  RPC
    
    ;-----------------------------------------------
    ; Put registers back in their reset state.
    ;
    ; Clear all the XARn, ACC, XT, and P and DP
    ; registers
    ;
    ; NOTE: Leave the device in C28x operating mode
    ;       (OBJMODE = 1, AMODE = 0)
    ;-----------------------------------------------
        ZAPA
        MOVL  XT,ACC
        MOVZ  AR0,AL
        MOVZ  AR1,AL
        MOVZ  AR2,AL
        MOVZ  AR3,AL
        MOVZ  AR4,AL
        MOVZ  AR5,AL
        MOVZ  AR6,AL
        MOVZ  AR7,AL
        MOVW  DP, #0
    
    ;------------------------------------------------
    ;   Restore ST0 and ST1.  Note OBJMODE is
    ;   the only bit not restored to its reset state.
    ;   OBJMODE is left set for C28x object operating
    ;   mode.
    ;
    ;  ST0 = 0x0000     ST1 = 0x0A0B
    ;  15:10 OVC = 0    15:13      ARP = 0
    ;   9: 7  PM = 0       12       XF = 0
    ;      6   V = 0       11  M0M1MAP = 1
    ;      5   N = 0       10  reserved
    ;      4   Z = 0        9  OBJMODE = 1
    ;      3   C = 0        8    AMODE = 0
    ;      2  TC = 0        7 IDLESTAT = 0
    ;      1 OVM = 0        6   EALLOW = 0
    ;      0 SXM = 0        5     LOOP = 0
    ;                       4      SPA = 0
    ;                       3     VMAP = 1
    ;                       2    PAGE0 = 0
    ;                       1     DBGM = 1
    ;                       0     INTM = 1
    ;-----------------------------------------------
    
        MOV  *SP++,#0
        MOV  *SP++,#0x0A0B
        POP  ST1
        POP  ST0
    
    ;------------------------------------------------
    ;   Jump to the EntryAddr as defined by the
    ;   boot mode selected and continue execution
    ;-----------------------------------------------
    
        LRETR
    
    ;eof ----------
    
    	.end
    	
    ;//===========================================================================
    ;// End of file.
    ;//===========================================================================

    I adapted that codebranch.asm for a very simple CPU1 project. Apparently, if the project is a Driverlib project there is a high chance of encountering an error when initializing the SysPLL (the specific error appears to be the result of "frequency out of range"), however there is no such issue with a bitfield project.

    Is there any way to adjust a pure driverlib project so that the codebranch.asm can function without issue?

  • Howard

    The issue you describe doesn't seem to be related to codestartbranch.asm.

    Are you using the latest C2000Ware version of 3.02.00.00? Are you using a controlCARD, if so which rev? Or custom board?

    In v3.02.00.00, examples are designed for an external clock of 25MHz, this is changed from previous 20MHz. The newest controlcard has this change.

    Do think you're seeing issues related to this? Are you hitting ESTOP when debugging? 

    Best regards

    Chris

  • I am using the controlCARD, my C2000Ware version is 3.02.00.00, and I defined the USE_20MHZ_XTAL macro.

    I only attempted to change the codestartbranch.asm because I was concerned about the need to perform some sort of clean up procedure after the CPU1 Flash kernel has finished reprogramming the flash.

    Is it okay for the CPU1 Flash kernel to branch directly to the Flash entry point instead performing some sort of _ExitBoot (after reprogramming the Flash and resetting the PLLs and peripherals)?

  • Howard

    Alright, that's good.

    Yes, that should be ok as long as you're branching to the codestart of the new app which will go through the c_init RTS routine.

    Best regards

    Chris

  • Christopher Chiarella said:
    Yes, that should be ok as long as you're branching to the codestart of the new app which will go through the c_init RTS routine.

    If I do not need to use _ExitBoot, that means I do not need to explicitly:

    • De-allocate the stack
    • Set the RPC to the application entry point address
    • Clear the XARn, ACC, XT, P and DP registers
    • Reset the status registers ST0 and ST1

    Is that correct?

  • Howard

    Yes, that's correct. I don't expect skipping those actions to be an issue.

    Best regards

    Chris

  • Okay I've gotten a working implementation of the CM Flash kernel to work.

    Thanks for the assistance.

    Sincerely,

    Howard Li