Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Not applicable
Hello,

can anybody tell me how to enable fallback Alternate Boot Mode (ABM) for the XMC4500?

Regards
0 Likes
22 Replies
User6793
Level 4
Level 4
It is not trivial, but we have done it and in the end it was worth the effort because of the robustness we achieved in our SW upgrade process on the thousands of XMC4500 CAN nodes we have out there.
We run a Booter/Application scheme because the load-module size of the ABM images can be max 64K.
I would strongly suggest reading up on ABM in the XMC4500 Reference Manual. All the clues are in there.
You will also need to decide on how to generate the fall-back image, as this will reside in another memory address range than the primary one.
You might find generating these load images off-line difficult. We gave up on it because we where not able to find a SW solution for the CRC32 that matched the on chip CRC32 generator.
We ended up just copying the primary image and manipulating all the vectors found on 32bit boundaries to match the new base address and then generate the CRC32 needed in the ABM header.
In your HW, you need to select the BMI boot mode, and after generating the ABM headers, you need to select Fallback ABM mode in the OTP register.
If your code does not boot, activating the JTAG debugger puts the HW back in normal boot mode so that you can regain contact.

Well, not a turnkey answer maybe, but a start on the way.

You might even find some pointers in this thread: http://www.infineonforums.com/threads/1854-Bootloader-running-from-Flash/

Cheers.
0 Likes
Not applicable
Hi,

Please refer to the XMC4500 RM, Chapter 26.2.8 for Fallback ABM.

Also, the user actions that is required for ABM:
- Program flash with application and ABM header
- Drive TCK and TMS to launch Normal boot mode
- Configure STCON.SWCON per Table 26-2
- Issue a system reset (Example: Watchdog reset, Software reset)

Alternatively,
- Program the flash with application and ABM header
- Encode the SWCON field in the BMI word with ABM boot code
- Drive TCK and TMS for BMI and issue PORST

Regards,
Daryl
0 Likes
Not applicable
Hi OMR and Daryl,

thank you for the responses!

@Daryl: I read this Information also in the RM. I haven't tested it so far. But as fas as I understood the Controller will start in Normal mode after PORST (Power on reset) than you can do this. My goal is to have the "Fallback ABM" already activated by the BMI after a PORST. Therefore the BMI string has to be modified and I don't know how to do this.

@OMR: How have you realized to modify the BMI string to activate the BMI mode after PORST?

Regards
0 Likes
Not applicable
Hi OMR and Daryl,

thank you for the responses!

@Daryl: I read this Information also in the RM. I haven't tested it so far. But as fas as I understood the Controller will start in Normal mode after PORST (Power on reset) than you can do this. My goal is to have the "Fallback ABM" already activated by the BMI after a PORST. Therefore the BMI string has to be modified and I don't know how to do this.

@OMR: How have you realized to modify the BMI string to activate the BMI mode after PORST?

Regards
0 Likes
Not applicable
Hello OMR and Daryl,

thank you for your Responses.

@Daryl: I have read this part in the RM as well. I want to use the alternative where the BMI word has to be encoded so that in case of an PORST already the controler executes ABM. My challange is: How to encode the BMI string?

@OMR: How have you encoded the BMI string? Do you have a code example?

Best regards
0 Likes
Not applicable
Hello OMR and Daryl,

thank you for your Responses.

@Daryl: I have read this part in the RM as well. I want to use the alternative where the BMI word has to be encoded so that in case of an PORST already the controler executes ABM. My challange is: How to encode the BMI string?

@OMR: How have you encoded the BMI string? Do you have a code example?

Best regards
0 Likes
Not applicable
Hi Daryl
thank you for your Responses.

I have read this part in the RM as well. I want to use the alternative where the BMI word has to be encoded so that in case of an PORST already the controler executes ABM. My challange is: How to encode the BMI string?
Do you have some code examples?

Regards
0 Likes
Not applicable
Hi OMR,

thank you for your Response.

How have you encoded the BMI string? Do you have a code example?

Regards
0 Likes
User6793
Level 4
Level 4
This is the code we use.
Keep in mind that it is our APP that generates the fallback image and programs the BMI word. (hence, from our make system, IS_BOOTER is false)


const uint32_t BMI_CUSTOM_MODE = 0x02;
const uint32_t BMIWORD_DSRAM1 = 0x20000090; // very bottom of stack
const uint32_t BMIWORD_SET = 0x0000000e; // ABM FALLBACK BMI word, updated on every reset, (but valid bit not set just after BMI word program before PORST)

void Booter::setBMIWord(void)
{
#if (!IS_BOOTER)
uint32_t hwcon = (SCU_GENERAL->STCON & SCU_GENERAL_STCON_HWCON_Msk) >> SCU_GENERAL_STCON_HWCON_Pos;

// if HWCON = BMI and SWCON != FABM, we need to program the BMI word!
if (BMI_CUSTOM_MODE == hwcon) {
if ((*(unsigned int *)BMIWORD_DSRAM1 & 0x0fffffff) != BMIWORD_SET) { // program BMI word ONCE ONLY! (OTP)
if (Flash::getInstance()->configureBmi() != (uint32_t)DAVEApp_SUCCESS) {
printf("configureBmi() failed!\n");
return;
}

printf("BMI word programmed OK for FABM!\n");
}
else
printf("BMI word valid for FABM\n");
}
else
printf("Boot mode is not BMI (0x%02x)\n", hwcon);
#endif
}


int Flash::configureBmi(void)
{
#if (!IS_BOOTER)
const FLASH002BMIString_Type BmiString = { FLASH002_BMI_BOOT_FABM, (FLASH002_BMI_FLAGS_Type)0, {0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0} };

return(Flash002_ConfigureBMI(&BmiString));
#else
return -1;
#endif
}
0 Likes
Not applicable
Ok! That code helps partly.
We don't use the DAVE apps. Do you have access to the code of method "Flash002_ConfigureBMI"?

That's what I need to know.
0 Likes
User6793
Level 4
Level 4
You said it yourself. It's in DAVE: 🙂

/**
* This function can be used to configure the BMI (Boot Mode Index)
* in page1 of UCB2
*/
__attribute__ ((section (".text.fastcode")))
status_t Flash002_ConfigureBMI (const FLASH002BMIString_Type *BMIString)
{
status_t status = (uint32_t) FLASH002_ERROR;
/* NOTE: the array is not initialized here to avoid calling memcpy
* since we may want to dynamically load this function to RAM, we shall
* avoid linking to other functions
*/
uint8_t UCBPageBytes[FLASH002_PAGE_SIZE];
uint32_t i; /*for simple loop counters*/
uint8_t xor_csum = 0U;
uint32_t BMIWord;

/* <<>> */
/*clear the array before filling in*/
for (i = 0U; i < (FLASH002_PAGE_SIZE); i++)
{
UCBPageBytes = 0U;
}


/* BMI word - the boot options and BMI flags
*/
BMIWord = ((uint32_t)(BMIString->BMIFlags)) | \
((uint32_t)(BMIString->BootMode));

UCBPageBytes[0] = (uint8_t)(BMIWord & 0xFFUL);
UCBPageBytes[1] = (uint8_t)((BMIWord & 0xFF00UL) >> 8U);
UCBPageBytes[2] = (uint8_t)((BMIWord & 0xFF0000UL) >> 16U);
UCBPageBytes[3] = (uint8_t)((BMIWord & 0xFF000000UL) >> 24U);

/* copy the MAC addr extension*/
for (i = 0U; i < FLASH002_BMI_MAC_ADDR_SIZE; i++)
{
UCBPageBytes [FLASH002_BMI_MAC_ADDR_LOC + i] = \
BMIString->MACAddrExtn;
}

/*copy the Ethernet IP extension*/
for (i = 0U; i < FLASH002_BMI_IP_EXTN_SIZE; i++)
{
UCBPageBytes [FLASH002_BMI_IP_EXTN_LOC + i] = \
BMIString->EthernetIPExtn;
}

/*copy the USB serial number*/
for (i = 0U; i < FLASH002_BMI_USB_SN_SIZE; i++)
{
UCBPageBytes [FLASH002_BMI_USB_SN_LOC + i] = \
BMIString->USBSerialNumber;
}

/*calculate the XOR checksum and copy to the string*/
xor_csum = 0U;
for (i = 0U; i < (FLASH002_BMI_STR_SIZE - 1U); i++)
{
xor_csum ^= UCBPageBytes;
}

UCBPageBytes [FLASH002_BMI_CSUM_LOC] = \
xor_csum;


/* Enter page mode command */
M32(FLASH002_UNCACHED_BASE + 0x5554U) = 0x50U;

/* Load Assembly Buffer with BMI info*/
for (i = 0U; i < (FLASH002_PAGE_SIZE/8U); i++)
{
M32(FLASH002_UNCACHED_BASE + 0x55F0U) = (uint32_t) \
(((uint32_t) UCBPageBytes[8U*i]) | \
(((uint32_t) UCBPageBytes[(8U*i) + 1U]) << 8U) | \
(((uint32_t) UCBPageBytes[(8U*i) + 2U]) << 16U) | \
(((uint32_t) UCBPageBytes[(8U*i) + 3U]) << 24U));

M32(FLASH002_UNCACHED_BASE + 0x55F4U) = (uint32_t) \
(((uint32_t) UCBPageBytes[(8U*i) + 4U]) | \
(((uint32_t) UCBPageBytes[(8U*i) + 5U]) << 8U) | \
(((uint32_t) UCBPageBytes[(8U*i) + 6U]) << 16U) | \
(((uint32_t) UCBPageBytes[(8U*i) + 7U]) << 24U));
}
/* Write Page command - for programming the UCB page*/
M32(FLASH002_UNCACHED_BASE + 0x5554U) = 0xAAU;
M32(FLASH002_UNCACHED_BASE + 0xAAA8U) = 0x55U;
M32(FLASH002_UNCACHED_BASE + 0x5554U) = 0xC0U;
M32(FLASH002_UNCACHED_BASE + FLASH002_BMI_OFFSET) = 0xAAU;

/*wait until the operation is complete*/
while ((FLASH0->FSR & FLASH_FSR_PBUSY_Msk) != 0U)
{
/*do nothing*/
}
/* Check if any error occurred during the operation*/
if((FLASH0->FSR & FLASH002_FLASH_ERROR_MSK) == 0U)
{
status = (uint32_t)DAVEApp_SUCCESS;
}
return status;
}
0 Likes
Not applicable
Hi OMR,

thanks! This infomation helps me a lot.

You once mentioned it is hard to calculate the ABM CRCs.
Fallback ABM is activated but it doesn't work as expected. So maybe the CRCs aren't correct. In the RM chapter 26.3.2 (Diagnostics Monitor Mode (DMM)) register SCU_TSW0 is mentioned whcih holds the Information why it doesn't work.
Does anybody know the address of this register? Any other way for diagnostics?

Regards
0 Likes
User6793
Level 4
Level 4
Here are our CRC32 code that runs on the XMC4500. We were never able to reproduce result off-chip.
Also note possible HW error in crc32res() method.

Your fallback code, are you sure it has been linked to the correct address in the FLASH?


unsigned int Booter::crc32Gen(unsigned int *memPtr, unsigned int size)
{
unsigned int result = 0;
#if (!IS_BOOTER)
crc32Init();
crc32Chunk(memPtr, size);
result = crc32Res();
#endif
return result;
}

void Booter::crc32Init(void) // HW CRC generator, init for chunk
{
#if (!IS_BOOTER)
SCU_RESET->PRCLR2 = SCU_RESET_PRCLR2_FCERS_Msk;
while((SCU_RESET->PRSTAT2 & SCU_RESET_PRSTAT2_FCERS_Msk))
;

FCE->CLC = 0;
while((FCE->CLC & FCE_CLC_DISS_Msk))
;

FCE_KE0->CFG = 0;
FCE_KE0->CRC = 0;
#endif
}

void Booter::crc32Chunk(unsigned int *memPtr, unsigned int size) // HW CRC generator, chunk data
{
#if (!IS_BOOTER)
size >>=2; // /4 since memPtr is a word pointer

for (uint32_t i=0; i FCE_KE0->IR = *memPtr++;
}
#endif
}

unsigned int Booter::crc32Res(void) // HW CRC generator, final chunk result
{
unsigned int result = 0;
#if (!IS_BOOTER)
result = FCE_KE0->RES;
result = FCE_KE0->RES; // must be read twice, or else the result is wrong!
#endif
return result;
}
0 Likes
Not applicable
The fall back code is linked to address range 0x0C008000 .. 0x0C00FFFF
The ABM Header is placed at 0x0C00FFE0

ABM Header:

static __root const abm_header_t abmHeader @ ".abmHeader" = {
.magicKey = 0xA5C3E10Fu,
.applicationStartAddress = 0x0C008000
.applicationLength = 0xFFFFFFFFu, // diable CRC check to make it easier
.crc32Application = 0xFFFFFFFFu,
.crc32Header = 0x7bd7ece7u
};


We are using IAR Compiler.
Here an extract of the map file.

"ROM Region":
place in [from 0x0c008000 to 0x0c00ffff] { ro };
"A1": place at 0x0c008000 { ro section .intvec };
"A2": place at 0x0c008200 { ro section .partitionHeader };
"A3": place at 0x0c00ffe0 { ro section .abmHeader };
"DRAM1 Region":
place in [from 0x20000100 to 0x2000ffff] { rw, block CSTACK, block HEAP };
"A4": place at 0x20000100 { rw section .sharedMemory };

Section Kind Address Size Object
------- ---- ------- ---- ------
"A1": 0x200
.intvec ro code 0x0c008000 0x200 startup_XMC4500.o [9]
- 0x0c008200 0x200
0 Likes
User6793
Level 4
Level 4
Are you sure it is possible to disable the CRC check?

We have a RS232 serial port providing debug info when our booter starts and our headers looks like this:

VTOR=0x08000000
STCON=0x00000202 HWCON=0x02 SWCON=0x02 BMIWORD=0x8000000E
ABM[0]@0x0C00FFE0: 0xA5C3E10F
ABM[1]@0x0C00FFE4: 0x08000000
ABM[2]@0x0C00FFE8: 0x0000FFE0
ABM[3]@0x0C00FFEC: 0x49D74060
ABM[4]@0x0C00FFF0: 0x16BFB7D6
ABM[0]@0x0C01FFE0: 0xA5C3E10F
ABM[1]@0x0C01FFE4: 0x08010000
ABM[2]@0x0C01FFE8: 0x0000FFE0
ABM[3]@0x0C01FFEC: 0xBC0ED2FB
ABM[4]@0x0C01FFF0: 0x91106F64


The value of VTOR tells us if we have booted the primary (VTOR=0x08000000) or fallback (VTOR=0x08010000) image.
I was under the impression that each image could be max 64K, but I might be wrong.

Chime in if you need anything more.

Cheers.
0 Likes
Not applicable
OMR wrote:
I was under the impression that each image could be max 64K, but I might be wrong.


According to the RM it is possible to deactivate the CRC check for the application.
0 Likes
Not applicable
I do have a small success:
Fallback Boot Mode is working by the activation via the SWCON Register. It is important to clear the Reset Status Register otherwise the SSW will always detect that the reason for the reset was PORST instead of a System reset.
From my Point of view it isn't properly documented!


// Clear the reset cause field for proper reset detection of the Start-up Software
SCU_RESET->RSTCLR = (uint32_t) (1U<// Start Alternate Boot Mode (0x08 - ABM0 / 0x0C - ABM1 / 0x0E - Fallback ABM)
SCU_GENERAL->STCON |= (uint32_t) (0x0E << SCU_GENERAL_STCON_SWCON_Pos);
system_reset();


@Infineon: Please update the documentation. It cost me one week of work!!!
0 Likes
Not applicable
Now I need to write the BMI String to UCB2. So far it didn't work.
Is it needed to erase the UCB before it is written?
In the code example I cannot detect an erase.

Regards
0 Likes
User6793
Level 4
Level 4
I thought the BMI String was OTP (OneTimeProgrammable)?
As such it is not possible to erase.

Anyway, you can read the current value after a PowerOnReset from:


const uint32_t BMIWORD_DSRAM1 = 0x20000090; // very bottom of stack

uint32_t hwcon = (SCU_GENERAL->STCON & SCU_GENERAL_STCON_HWCON_Msk) >> SCU_GENERAL_STCON_HWCON_Pos;
uint32_t swcon = (SCU_GENERAL->STCON & SCU_GENERAL_STCON_SWCON_Msk) >> SCU_GENERAL_STCON_SWCON_Pos;
uint32_t bmiword = *(unsigned int *)BMIWORD_DSRAM1;

printf("VTOR=0x%08x\n", PPB->VTOR);
printf("STCON=0x%08x HWCON=0x%02x SWCON=0x%02x BMIWORD=0x%08x\n", SCU_GENERAL->STCON, hwcon, swcon, bmiword);



Yes, another thing you might check. The DAVE code snippet I provided earlier must execute in RAM. Hence the fastcode attribute. We added that. Our startup code copies the code from FLASH to RAM.
0 Likes
Not applicable
You are right it is OTP. Also I am executing the code from the PSRAM.

I am using one by one the code snipped of the DAVE tool you provided. After flashing there is no error in the Flash Status register.
After reset RAM address always provides value 0x00000000.
The linker script is also modified that the application starts using the DSRAM beginning from address 0x20000100.

Topic is addressed to our FAE.
0 Likes
User6793
Level 4
Level 4
OK, the only other method we call from our flash class is the DAVE FLASH002_Init(), but it doesn't seem to do much:

void FLASH002_Init()
{
/* <<>> */
/*clear error status*/
M32(FLASH002_UNCACHED_BASE + 0x5554U) = 0x000000F5U;

}


Good luck hunting it down.
0 Likes
Not applicable
I found the Problem! It was my mistake!
Used Offset address 0x800 instead of 0x900 to write the BMI string.

Shit happens 🙂

@OMR: Thank you for the great Support! You helped me a lot!

Best regards
BeGu
0 Likes