S32K1xx bootloader: separate projects and RAM content during reset

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

S32K1xx bootloader: separate projects and RAM content during reset

Jump to solution
4,295 Views
Joao_Roscoe
Contributor III

I'm in the early stages of a project that uses S32K144 and will require a custom bootloader. My intention is to go the KISS way, so my basic idea is:

* Create separate projects for the bootloader and for the main application, with proper locator scripts, to ensure they won't mess with each other's memory usage

* Create separate interrupt vector tables for the bootloader and for the main application;

* Create a startup flag in RAM, to be used by bootloader to choose what to do: keep running the bootloader or hand over control to main application;

* Handover control to application really early, before unmasking interrupts, to avoid the need of fancy handover code (except for the inevitable VTOR change, and possibly some stack tweaking);

* Switch from main application to bootloader only via reset (after writing to RAM the proper statup flag);

My questions:

1. Can I rely on the (previously written) content of a RAM location, right after a CPU reset ?

2. What would be the best way to perform a software reset ?

3. Is it possible, with S32DS for ARM / openSDA / S32K144EVB, to flash two separate firmwares to work together? According to the tests I did, so far, just running the two builds in Debug mode, sequentially, won't do, it seems that the second flashing compromises the first one;

4. Is it possible, with S32DS for ARM /openSDA / S32K144EVB, to load the symbols of two different, separate, builds, to debug the handover process?

Thank you in advance for your time,

Joao

1 Solution
3,106 Views
stanish
NXP Employee
NXP Employee

Hi Joao,

You can fing the answers to your questions 3) and 4)  in this document:

https://community.nxp.com/docs/DOC-342385 

hope it helps.

Stan

View solution in original post

13 Replies
3,106 Views
dianabatrlova
NXP TechSupport
NXP TechSupport

Hi Joao, 

1.

The SRAM content is retained during reset. If you follow the procedure mentioned in the "29.3.4 SRAM retention: power modes and resets" in the RM rev. 9. This procedure is used for preventing memory corruption during reset assertion.

If you enable RAM retention you should check the bits in CHIPCTL register and write 1 to them to allow accesses to SRAM immediately after reset. Otherwiseyou will not have access to SRAM.

2. I recommend you to look at the Cortex™ -M4 Devices Generic User Guide - 4.3.5 Application Interrupt and Reset Control Register

http://infocenter.arm.com/help/topic/com.arm.doc.dui0553b/DUI0553.pdf 

The code below will trigger software reset

S32_SCB->AIRCR = S32_SCB_AIRCR_VECTKEY(0x5FA) | S32_SCB_AIRCR_SYSRESETREQ(1);

I hope it helps you.

Best Regards,

Diana

0 Kudos
3,106 Views
Joao_Roscoe
Contributor III

Hi, Diana,

Goot tips.

I wrote the code to crear the SRAM retention bits, and and also included the software reset code. So, now I have:

---

void SYSTEM_STARTUP_bootloader_req(void)
{
    uint32_t SIM_CHIPCTL_aux;

    /* Set boot loader request flag */
    BOOTLOADER_REQUEST_FLAG = BOOTLOADER_REQUEST_PATTERN;
    /* Clear SRAM retention bits */
    SIM_CHIPCTL_aux = SIM->CHIPCTL;
    SIM_CHIPCTL_aux &= ~SIM_CHIPCTL_SRAMU_RETEN(1);
    SIM_CHIPCTL_aux &= ~SIM_CHIPCTL_SRAML_RETEN(1);
    SIM->CHIPCTL = SIM_CHIPCTL_aux;
    /* Set System Reset Request bit - will reset the chip */
    S32_SCB->AIRCR = S32_SCB_AIRCR_VECTKEY(0x5FA) | S32_SCB_AIRCR_SYSRESETREQ(1);
}

---

In the above code, BOOTLOADER_REQUEST_FLAG is located in a RAM section that is shared by application and bootloader projects - I have included some code in the startup routine to look at that RAM position and jump to application or to bootloader depending on that.

My main app flashes a led for 5 secons or so, an than calls SYSTEM_STARTUP_bootloader_req(). Looks like everything is ok, because the led does flash for some seconds, than stops.

However, it seems that the board *really* stops. I cannot launch a debug session with S32DS + OpenSDA, conneting to the EVB. S32DS just stops forever trying to launch GDB.

I also noticed that my led flashing code runs when I unplug the EVB and than plug it back to USB, restoring power supply. It flashes for a while, than stops. That would imply that my bootloader *was* properly flashed (using Stanislav's tip, in this thread), or there would not be code in the lower flash addresses to run after power on (my application and its vector table are located at 0x3000). However, my bootloader should flash another led, and I can't see that. The EVB seems dead, until the next unplug/replug sequence.

I also tried generating an hex file of my bootloader, alone, and to flash it to the board, by copying it to the emulated storage, using windows explorer. After unplugging the EVB and plugging it back, nothing changes, except that the hex file is gone. Looked at LASTSTAT.txt, and it's still reading "Ready.", only. No report on the flash procedure. Just to clarify: I did this last test without resetting the EVB to bootloader mode, as per my understanding, that would be needed to update the OpenSDA bootloader itself. Is that right?

Any tip?

Thanks a lot,

Joao

0 Kudos
3,106 Views
Joao_Roscoe
Contributor III

Hi, Diana,

Thank you for tor time;

I already have included resetting the retention bits in the startup routine.

I added the code below directly to bootloader's Reset Handler:

/* Set SRAM retention bits */
ldr r0, =0x40048004 /* CHIPCTL register address */
ldr r1, =0x00300000 /* Bitmask for bits 20 and 21*/
ldr r2, [r0] /* Load CHIPCTL content */
orr r2, r1 /* Set bits 20 and 21 */
str r2, [r0] /* Store new CHIPCTL content */

...right after interruption masking and registers initialization, at "startup_S32K144.s".

So, this is done prior to ECC RAM initialization.

Anyway, right now, I am not able to download anything to the EVB. The debugger won'to do it,

and I haven't managet to do it by any alternative means.

I suppose that if I copy the hex generated by S32DS into the EVB's emulated removable device, in Windows, the hex should be flashed at EVB's poweron, and I shoud get a report of the flashing process in "LASTSTAT.txt". Am I right?

thanks a lot,

Joao

0 Kudos
3,106 Views
Joao_Roscoe
Contributor III

Hi, Diana,

I got a bit forward debugging my attempt to retain RAM content across a reset.

Using GDB, I noticed that my RAM content gets cleared do zeroes on the very moment that I write 0x0 to CHIPCTL.

To be more precise: I read CHIPCTL, set bits 20 and 21, and than write that back to CHIPCTL.

I'm puzzled...

Joao

0 Kudos
3,106 Views
dianabatrlova
NXP TechSupport
NXP TechSupport

Hi Joao,

I prepared a simple example which shows the use of RAM retention.

Example S32K144 RAM Retention S32DS.R1 

After allowing accesses to SRAM (retention bits are set to 1)  in "startup_S32K144.S" the ECC RAM initialization should be skipped.

There can be a condition which decides that the RAM initialization will be skipped only in the case the RAM retention.  

I hope it helps you.

Best Regards,

Diana

3,106 Views
riccardolalli
Contributor I

Hello,

what are the drawbacks of not protecting RAM using SRAMU_RETEN and SRAML_RETEN registers?

I tried it and it seems to work anyway.

Thanks,

Riccardo

0 Kudos
3,106 Views
dianabatrlova
NXP TechSupport
NXP TechSupport

Hello,

It can works without using the retention bits. However, as we can read in the RM rev. 9. this logic ensures that any attempted access to SRAM is blocked after these bits are written, thereby preventing memory corruption during reset assertion. 

This is the advantage. You can be sure that any access to SRAM did not occur.

Best Regards,

Diana

0 Kudos
3,106 Views
riccardolalli
Contributor I

Ok, thank you very much!

Riccardo

0 Kudos
3,106 Views
Joao_Roscoe
Contributor III

Hi, Diana,

Yes, your exemple was really helpful.

Thank you very much.

Joao

0 Kudos
3,106 Views
dianabatrlova
NXP TechSupport
NXP TechSupport

Hi Joao,

I'm not sure where you call your void SYSTEM_STARTUP_bootloader_req(void) function, but I assume that this issue occurs because of initialization of ECC RAM while the RAM retention bits are written. So, you should disable the ECC RAM initialization which can be found in the startup_S32K144.S

Also, you can look at the document below:

for S32K14x which could be attached while couldn't be re-programmed 

I hope it helps you.

Best Regards,

Diana

0 Kudos
3,107 Views
stanish
NXP Employee
NXP Employee

Hi Joao,

You can fing the answers to your questions 3) and 4)  in this document:

https://community.nxp.com/docs/DOC-342385 

hope it helps.

Stan

3,106 Views
Joao_Roscoe
Contributor III

Yeah, that did the trick. After changing debug configuration to load the second "elf", and after adding the symbols file (the elf itself), it was just a matter of issuing >monitor reset halt to force a target reset.

Going head:

My boot loader tries jumping into applicative as below (__app_interrupt_vector_table__ is a global symbol from locator script, containing the address of applicative's vector table - in this case, 0x3000):

-----------------

/* Set VTOR (VTOR's memory mapped address: 0xE000ED08) pointing to applicative's Vector Table */
ldr r0, =__app_interrupt_vector_table__
ldr r1, =0xE000ED08
str r0, [r1]
/* Branch to application's Reset Handler vector content (applicative's Reset Handler will set the stack pointer properly)*/
ldr r1, =__app_interrupt_vector_table__ + 4
blx r1

-----------------

Everything seems ok until right before the branch (blx r1). At this point, r1 does contain 0x3004, and memory, at 0x3004 does contains applicative's Reset Handler's address:

Memory browser:

0000_3000: 000034A5

And 0x34A5 does point to the beginning of applicative's Reset Handler:

Disassembly:

000034a5: cpsid i
000034a7: mov.w r1, #0
000034ab: mov.w r2, #0
000034af: mov.w r3, #0
000034b3: mov.w r4, #0
000034b7: mov.w r5, #0
000034bb: mov.w r6, #0
...

The assembly file, in applicative's project that generates the disassembly above reads as below:

...

/* Reset Handler */

.thumb_func
.align 2
.globl Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
cpsid i /* Mask interrupts */

/* Init the rest of the registers */
ldr r1,=0
ldr r2,=0
ldr r3,=0
ldr r4,=0
ldr r5,=0
ldr r6,=0

...

 Well, everything seems to be ok.

However, going one single step ahead blows it, and processor gets stuck at application's default ISR loop.

***What I am not grasping here***: shouldn't the ddress of applicative's Reset Handler be a multiple of 4?

To get another look into it, I changed Debug configuration back to loading only the applicative, and voila:

The address of the first Reset Handler's instruction is 0x34A4:

Disassembly:

000034a4: cpsid i
310 ldr r1,=0
000034a6: mov.w r1, #0
311 ldr r2,=0
000034aa: mov.w r2, #0
312 ldr r3,=0
000034ae: mov.w r3, #0
313 ldr r4,=0
000034b2: mov.w r4, #0
314 ldr r5,=0
000034b6: mov.w r5, #0
315 ldr r6,=0

...

Where is my bad step?

Best regards,

João

0 Kudos
3,106 Views
Joao_Roscoe
Contributor III

This was a killer tip, thanks a lot.

Well, it turned out that I *also* had another nasty bug - I was not branching to the Reset Handler, but to the Handler's Vector itself. Below, the working code, so other's to see in the future.

**ATTENTION**: no need to set the LSB here, because the BLX will use the content of the vector as branching destination, and that content is already properly filled with the application's Reset Handler address, *with the LSB already set*, due to the application build.

...

.APPL_BRANCH:
/* Clear *magic* number (a new bootloader request will be needed for bootloader to run again) */
ldr r0, =0x0
ldr r1, =__bootloader_flag__
str r0, [r1]
/* Set VTOR (VTOR's memory mapped address: 0xE000ED08) pointing to application's Vector Table */
ldr r0, =__app_interrupt_vector_table__
ldr r1, =0xE000ED08
str r0, [r1]

/* *** Ready to really branching to application's Reset Handler ***
* The __app_interrupt_vector_table__ global (from locator script)
* has the address of the application's Interrupt Vector Table;
* Position [0] of the table has the address of application's stack's
* top. We ignore that, because application's Reset Handler will
* set the stack pointer properly anyway;
* Position [1] (__app_interrupt_vector_table__ + 4) has the address
* of application's Reset Handler */
ldr r1, =__app_interrupt_vector_table__ + 4
ldr r0, [r1]
blx r0

...

Best regards,

João

0 Kudos