SPRADN2 January 2025 MSPM0G1518 , MSPM0G1519 , MSPM0G3518 , MSPM0G3519 , MSPM0L1227 , MSPM0L1228 , MSPM0L2227 , MSPM0L2228
The CSC needs to know the location of application image for some security function. So, the first thing needs to be done is to arrange flash memory for CSC code and application code. Change the linker file accordingly. An example of linker file configuration shows below. Split the FLASH memory into two sections FLASH_CSC and FLASH_APP. Set the SECTIONS.intvecs to the start of FLASH_CSC. And assign related sections to FLASH_CSC as well.
In bank-swappable configuration, the flash memory protections are automatically mirrored to both banks. This requests that CSC code must be identical across both BANK0 and BANK1 and the application code starts at the same offset address.
-uinterruptVectors
--stack_size=256
--define=_CSC_SIZE_=(6*1024)
/* Note: SRAM is partitioned into two separate sections SRAM_BANK0 and SRAM_BANK1
to account for SRAM_BANK1 being wiped out upon the device entering any low-power
mode stronger than SLEEP. Thus, this is up to the end-user to enable SRAM_BANK1 for
applications where the memory is considered lost outside of RUN and SLEEP Modes.
*/
MEMORY
{
FLASH_CSC (RX) : origin = 0x00000000, length = _CSC_SIZE_
FLASH_APP (RX) : origin = _CSC_SIZE_, length = (0x00040000 - _CSC_SIZE_)
SRAM_BANK0 (RWX) : origin = 0x20200000, length = 0x00010000
SRAM_BANK1 (RWX) : origin = 0x20210000, length = 0x00010000
BCR_CONFIG (R) : origin = 0x41C00000, length = 0x000000FF /*Boot configuration routine*/
BSL_CONFIG (R) : origin = 0x41C00100, length = 0x00000080 /*Bootstrap loader*/
DATA (R) : origin = 0x41D00000, length = 0x00004000
}
SECTIONS
{
.intvecs : > 0x00000000
.text : palign(8) {} > FLASH_CSC
.const : palign(8) {} > FLASH_CSC
.cinit : palign(8) {} > FLASH_CSC
.pinit : palign(8) {} > FLASH_CSC
.rodata : palign(8) {} > FLASH_CSC
.ARM.exidx : palign(8) {} > FLASH_CSC
.init_array : palign(8) {} > FLASH_CSC
.binit : palign(8) {} > FLASH_CSC
.TI.ramfunc : load = FLASH_CSC, palign(8), run=SRAM_BANK0, table(BINIT)
.vtable : > SRAM_BANK0
.args : > SRAM_BANK0
.data : > SRAM_BANK0
.bss : > SRAM_BANK0
.sysmem : > SRAM_BANK0
.TrimTable : > SRAM_BANK0
.stack : > SRAM_BANK0 (HIGH)
.BCRConfig : {} > BCR_CONFIG
.BSLConfig : {} > BSL_CONFIG
.DataBank : {} > DATA
}
An example is provided below on how to implement the bank swap function based on CSC start up sequence. The software checks the INITDONE bit first. If INITDONE has not been issued, then set up the security code here. In this case, the bank swap function is configured by calling the DL_SYSCTL_executeFromUpperFlashBank() function first. Then, delay for a proper time and issue INITDONE bit by calling DL_SYSCTL_issueINITDONE() function. Calling the DL_SYSCTL_issueINITDONE() function triggers a SYSRST. After the SYSRST, the MCU starts the run at BANK1. Customers can also add bank swap conditions in the code. If the condition matches, then the software calls the bank swap function and runs the BANK1 application project. Customers can add other CSC functions in the code but do not forget to issue INITDONE after all the CSC functions are executed. After system reset, if the bank swap function is not enabled, then the software can run to the BANK0 application project by calling start_app() function.
int main(void)
{
SYSCFG_DL_init();
if (!(DL_SYSCTL_isINITDONEIssued())) {
if(bankswap == true){ // Add bank swap conditions if needed
DL_SYSCTL_executeFromUpperFlashBank(); // Set swap bank0 to bank1
delay_cycles(160);
DL_SYSCTL_issueINITDONE(); // Issue INITDONE to trigger System Reset -> swap to bank1
}else
{
// Add other CSC function if needed
DL_SYSCTL_issueINITDONE(); // Then issue INITDONE to trigger System Reset
}
}else
{
start_app((uint32_t *) (0x1800)); // Jump to BANK0 app start address
}
}
An example of start_app() function is provided below. The input parameter is the start address of the application. The memory map in the linker file configuration has been changed. In this case, the application code in BANK0 starts at 0x1800. The software resets the SP value and Reset Vector to the vector table of the application code. Then, set the PC to the Reset Handler address of the application code. This procedure lets the MCU start to run the application code in BANK0.
static void start_app(uint32_t *vector_table)
{
/* Reset the SP with the value stored at vector_table[0] */
__asm volatile(
"LDR R3,[%[vectab],#0x0] \n"
"MOV SP, R3 \n" ::[vectab] "r"(vector_table));
/* Set the Reset Vector to the new vector table (Resets to 0x000) */
SCB->VTOR = (uint32_t) vector_table;
/* Jump to the Reset Handler address at vector_table[1] */
((void (*)(void))(*(vector_table + 1)))();
}