[S32K144] Copy DFlash to PFlash issue (In-Application Programming)

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

[S32K144] Copy DFlash to PFlash issue (In-Application Programming)

Jump to solution
1,463 Views
ArneB
Contributor II

Hi,

I'm currently implementing an In-Application Programming (IAP) procedure for firmware updates in my project, but have some issues in the final step.

Note: I'm using S32 Design Studio for S32 platform,  Build 201217 (Update 3) and SDK for S32K144, version S32SDK_S32K1XX_RTM_4.0.2

What am I doing ?

1) Receive a new firmware via CAN and store it in the DFlash block (The FW size is ~25k, so this fits well into the 64k block of the DFlash). I've verified the content of the DFlash after receiving it and it's identical to the generated and uploaded .bin file, so I assume this step is working

2) Disable all interrupts and call a function located in RAM, which erases the PFlash block and copy the Dflash content to PFlash (starting at address 0).

3) Issue a SW reset request

The MCU stalls somewhere at step 2. The PFlash memory is corrupted, the MCU won't start. Unfortunately it's hard to debug, so I'm asking for any helpful hints

Here are the important snippets of my code:

#define  CODE_RAM  __attribute__ ((section(".code_ram")))
void CODE_RAM copy_firmware(void);

I've checked the .map file and the copy_firmware() function is indeed placed into the .code_ram section.

 *(.code_ram)
 .code_ram      0x1fff8ab8       0x38 ./SDK/platform/drivers/src/flash/flash_driver.o
 .code_ram      0x1fff8af0       0xcc ./src/can_operator.o
                0x1fff8af0                copy_firmware
                0x1fff8bbc                . = ALIGN (0x4)
                0x1fff8bbc                __code_end__ = .
                0x1fff8bbc                __code_ram_end__ = .
                0x0000644c                __CODE_END = (__CODE_ROM + (__code_end__ - __code_start__))
                0x0000644c                __CUSTOM_ROM = __CODE_END

I'm calling the copy_firmware() function with these commands:

FLASH_DRV_SetPFlashProtection(0xFFFFFFFF);
DISABLE_INTERRUPTS()
copy_firmware();

...and here is the copy_firmware function. The length of the new firmware is stored in the FirmwareBlockBuffer.Current_Address variable (I've already verified that this value is correct)

void CODE_RAM copy_firmware() {
uint8_t *ptr8;
uint32_t regValue;
uint32_t i;

	// Erase PFlash
	while ((FTFC->FSTAT & FTFC_FSTAT_CCIF_MASK) == 0);
	FTFC->FSTAT = FTFC_FSTAT_ACCERR_MASK | FTFC_FSTAT_FPVIOL_MASK;
	FTFC->FCCOB[3] = 0x08; // Erase block cmd
	FTFC->FCCOB[2] = 0;    // Addr = 0 (= PFlash block)
	FTFC->FCCOB[1] = 0;
	FTFC->FCCOB[0] = 0;
	FTFC->FSTAT = FTFC_FSTAT_CCIF_MASK; //execute command
	while ((FTFC->FSTAT & FTFC_FSTAT_CCIF_MASK) == 0); //wait for done

// Program PFlash
	ptr8 = (uint8_t *)Flash_InitConfig0.DFlashBase;
	for(i=0;i<FirmwareBlockBuffer.Current_Address;i+=8) {
		FTFC->FSTAT = FTFC_FSTAT_ACCERR_MASK | FTFC_FSTAT_FPVIOL_MASK;
		FTFC->FCCOB[3]  = 0x07; // Program 8 bytes
		FTFC->FCCOB[2]  = (uint8_t)((i & 0x00FF0000)>>16);
		FTFC->FCCOB[1]  = (uint8_t)((i & 0x0000FF00)>>8);
		FTFC->FCCOB[0]  = (uint8_t)( i & 0x000000FF);
		FTFC->FCCOB[7]  = *ptr8;
		FTFC->FCCOB[6]  = *(ptr8+1);
		FTFC->FCCOB[5]  = *(ptr8+2);
		FTFC->FCCOB[4]  = *(ptr8+3);
		FTFC->FCCOB[11] = *(ptr8+4);
		FTFC->FCCOB[10] = *(ptr8+5);
		FTFC->FCCOB[9]  = *(ptr8+6);
		FTFC->FCCOB[8]  = *(ptr8+7);
		FTFC->FSTAT = FTFC_FSTAT_CCIF_MASK; //execute command
		while ((FTFC->FSTAT & FTFC_FSTAT_CCIF_MASK) == 0);
        ptr8 += 8;
	}

// Reset microcontroller to activate new firmware
    /* Read Application Interrupt and Reset Control Register */
    regValue = S32_SCB->AIRCR;

    /* Clear register key */
    regValue &= ~( S32_SCB_AIRCR_VECTKEY_MASK);

    /* Configure System reset request bit and Register Key */
    regValue |= S32_SCB_AIRCR_VECTKEY(FEATURE_SCB_VECTKEY);
    regValue |= S32_SCB_AIRCR_SYSRESETREQ(0x1u);

    /* Write computed register value */
    S32_SCB->AIRCR = regValue;
	while(1); // Wait for reset
}

Any support/answer/explanation, why this code isn't working is highly appreciated, as I'm currently stuck...

Thank you very much

 

0 Kudos
1 Solution
1,417 Views
ArneB
Contributor II

Another quick update: I've found the last root cause for my issues and now everything is working as expected

The firmware was stored in the DFlash area in the correct endian order, but the flash process reversed it...

For the archive and future users with similar issues I will post my working solution below.

 

Necessary definitions:

#define  CODE_RAM  __attribute__ ((section(".code_ram")))
void CODE_RAM copy_firmware(void);

 

Calling the copy function:

DISABLE_INTERRUPTS()
copy_firmware();

 

The copy function (located in RAM):

void CODE_RAM copy_firmware() {
uint32_t regValue;
uint8_t  *ptr8;
uint32_t i;

    ptr8 = (uint8_t *)Flash_InitConfig0.DFlashBase;

// Erase PFlash
	while ((FTFC->FSTAT & FTFC_FSTAT_CCIF_MASK) == 0);
	FTFC->FSTAT = FTFC_FSTAT_ACCERR_MASK | FTFC_FSTAT_FPVIOL_MASK;
	FTFC->FCCOB[3] = 0x08; // Erase block cmd
	FTFC->FCCOB[2] = 0;    // Addr = 0 (= PFlash block)
	FTFC->FCCOB[1] = 0;
	FTFC->FCCOB[0] = 0;
	FTFC->FSTAT = FTFC_FSTAT_CCIF_MASK; //execute command
	while ((FTFC->FSTAT & FTFC_FSTAT_CCIF_MASK) == 0); //wait for done

// Program PFlash
	for(i=0;i<(FirmwareBlockBuffer.Current_Address+FIRMWARE_BLOCK_BUFFER_LENGTH);i+=8) {
		FTFC->FSTAT = FTFC_FSTAT_ACCERR_MASK | FTFC_FSTAT_FPVIOL_MASK;
		FTFC->FCCOB[3]  = 0x07; // Program 8 bytes
		FTFC->FCCOB[2]  = (uint8_t)((i & 0x00FF0000)>>16);
		FTFC->FCCOB[1]  = (uint8_t)((i & 0x0000FF00)>>8);
		FTFC->FCCOB[0]  = (uint8_t)( i & 0x000000FF);
		FTFC->FCCOB[4]  = *ptr8;
		FTFC->FCCOB[5]  = *(ptr8+1);
		FTFC->FCCOB[6]  = *(ptr8+2);
		FTFC->FCCOB[7]  = *(ptr8+3);
		FTFC->FCCOB[8]  = *(ptr8+4);
		FTFC->FCCOB[9]  = *(ptr8+5);
		FTFC->FCCOB[10] = *(ptr8+6);
		FTFC->FCCOB[11] = *(ptr8+7);
		FTFC->FSTAT = FTFC_FSTAT_CCIF_MASK; //execute command
		while ((FTFC->FSTAT & FTFC_FSTAT_CCIF_MASK) == 0);
        ptr8 += 8;
	}

// Reset microcontroller to activate new firmware
    /* Read Application Interrupt and Reset Control Register */
    regValue = S32_SCB->AIRCR;

    /* Clear register key */
    regValue &= ~( S32_SCB_AIRCR_VECTKEY_MASK);

    /* Configure System reset request bit and Register Key */
    regValue |= S32_SCB_AIRCR_VECTKEY(FEATURE_SCB_VECTKEY);
    regValue |= S32_SCB_AIRCR_SYSRESETREQ(0x1u);

    /* Write computed register value */
    S32_SCB->AIRCR = regValue;
	while(1); // Wait for reset
}

 

Thank you Daniel for your support !

View solution in original post

6 Replies
1,431 Views
ArneB
Contributor II

Just a quick update: I've found at least one root cause of this issue

It's this line in the copy function:

ptr8 = (uint8_t *)Flash_InitConfig0.DFlashBase;

The struct "Flash_InitConfig0" was declared as:

const flash_user_config_t Flash_InitConfig0 =
{
    .PFlashBase = 0x0U,
    .PFlashSize = 0x80000U,
    .DFlashBase = 0x10000000U,
    .EERAMBase = 0x14000000U,
    .CallBack = NULL_CALLBACK
};

Therefore it's located in PFlash. But as I just erased the whole PFlash, the members are all set to "0xFFFFFFFF" and are invalid.

Easy solution: Set the ptr8 variable to the DFlash memory address before the flash area is erased.

Now the copy proceeds as expected (I verified it with the memory debugger), but the new firmware won't run, even after an external reset. What am I missing ? Any checksum ?

0 Kudos
1,418 Views
ArneB
Contributor II

Another quick update: I've found the last root cause for my issues and now everything is working as expected

The firmware was stored in the DFlash area in the correct endian order, but the flash process reversed it...

For the archive and future users with similar issues I will post my working solution below.

 

Necessary definitions:

#define  CODE_RAM  __attribute__ ((section(".code_ram")))
void CODE_RAM copy_firmware(void);

 

Calling the copy function:

DISABLE_INTERRUPTS()
copy_firmware();

 

The copy function (located in RAM):

void CODE_RAM copy_firmware() {
uint32_t regValue;
uint8_t  *ptr8;
uint32_t i;

    ptr8 = (uint8_t *)Flash_InitConfig0.DFlashBase;

// Erase PFlash
	while ((FTFC->FSTAT & FTFC_FSTAT_CCIF_MASK) == 0);
	FTFC->FSTAT = FTFC_FSTAT_ACCERR_MASK | FTFC_FSTAT_FPVIOL_MASK;
	FTFC->FCCOB[3] = 0x08; // Erase block cmd
	FTFC->FCCOB[2] = 0;    // Addr = 0 (= PFlash block)
	FTFC->FCCOB[1] = 0;
	FTFC->FCCOB[0] = 0;
	FTFC->FSTAT = FTFC_FSTAT_CCIF_MASK; //execute command
	while ((FTFC->FSTAT & FTFC_FSTAT_CCIF_MASK) == 0); //wait for done

// Program PFlash
	for(i=0;i<(FirmwareBlockBuffer.Current_Address+FIRMWARE_BLOCK_BUFFER_LENGTH);i+=8) {
		FTFC->FSTAT = FTFC_FSTAT_ACCERR_MASK | FTFC_FSTAT_FPVIOL_MASK;
		FTFC->FCCOB[3]  = 0x07; // Program 8 bytes
		FTFC->FCCOB[2]  = (uint8_t)((i & 0x00FF0000)>>16);
		FTFC->FCCOB[1]  = (uint8_t)((i & 0x0000FF00)>>8);
		FTFC->FCCOB[0]  = (uint8_t)( i & 0x000000FF);
		FTFC->FCCOB[4]  = *ptr8;
		FTFC->FCCOB[5]  = *(ptr8+1);
		FTFC->FCCOB[6]  = *(ptr8+2);
		FTFC->FCCOB[7]  = *(ptr8+3);
		FTFC->FCCOB[8]  = *(ptr8+4);
		FTFC->FCCOB[9]  = *(ptr8+5);
		FTFC->FCCOB[10] = *(ptr8+6);
		FTFC->FCCOB[11] = *(ptr8+7);
		FTFC->FSTAT = FTFC_FSTAT_CCIF_MASK; //execute command
		while ((FTFC->FSTAT & FTFC_FSTAT_CCIF_MASK) == 0);
        ptr8 += 8;
	}

// Reset microcontroller to activate new firmware
    /* Read Application Interrupt and Reset Control Register */
    regValue = S32_SCB->AIRCR;

    /* Clear register key */
    regValue &= ~( S32_SCB_AIRCR_VECTKEY_MASK);

    /* Configure System reset request bit and Register Key */
    regValue |= S32_SCB_AIRCR_VECTKEY(FEATURE_SCB_VECTKEY);
    regValue |= S32_SCB_AIRCR_SYSRESETREQ(0x1u);

    /* Write computed register value */
    S32_SCB->AIRCR = regValue;
	while(1); // Wait for reset
}

 

Thank you Daniel for your support !

1,450 Views
ArneB
Contributor II

Hi Daniel,

no, the flash should not be write protected (I never set any flash region write protected in my program). The line is just a left over from my tests and I've already deleted it (but have still the same copy issues...).

Best regards

  Arne

0 Kudos
1,443 Views
danielmartynek
NXP TechSupport
NXP TechSupport

Hi Arne,

Thank you, I see.

What about the FTFC error flags?

Can you read it after CCIF= 1 for each operation?

danielmartynek_0-1643033423668.png

 

Regards,
Daniel

 

0 Kudos
1,434 Views
ArneB
Contributor II

Hi Daniel,

I've set a breakpoint to to the erase PFlash command execution (first line below):

FTFC->FSTAT = FTFC_FSTAT_CCIF_MASK; //execute command
while ((FTFC->FSTAT & FTFC_FSTAT_CCIF_MASK) == 0); //wait for done

After executing the first line in the debugger (GDB & PE Multilink Universal) the FSTAT register shows a RDCOLERR (bit 6 is set). I'm unsure, if this is caused by the debugging process or if this is a real error...

The program flash is at least completely erased.

The first copy loop in the following paragraph results in a hard fault with the following console message in the IDE:

BusFault: A precise (synchronous) data access error has occurred.
Possible BusFault location: 0xFFFFFFFF.
HardFault: A fault has been escalated to a hard fault.

The program counter is stuck at the DefaultISR function:

DefaultISR:
  b DefaultISR
.size DefaultISR, . - DefaultISR

 

0 Kudos
1,455 Views
danielmartynek
NXP TechSupport
NXP TechSupport

Hello @ArneB,

You call this function:

FLASH_DRV_SetPFlashProtection(0xFFFFFFFF);

Does it mean the flash is protected out-of-reset?

If so, this could be the root cause here.

Becasue the protection can only be increased not descreased.

danielmartynek_0-1643031778002.png

Please read the returned status value of the funtion and check for any FTFC errors in your custom functions.

 

Thank you,

BR, Daniel

 

0 Kudos