writing to text segment in flash cause hard fault

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

writing to text segment in flash cause hard fault

Jump to solution
1,730 Views
roymessinger
Contributor V

(I've moved this question from my original thread and decided to open a new one...)

I'm using a K64 on custom board and KBOOT (but it happened also when putting the app on address zero, without Kboot). When writing to a new defined section in the text segment of the flash a hard fault is caused.

My code snippet is as follows:

include...
#ifdef __cplusplus
extern "C" {
#endif
uint16_t __attribute__((section (".MyappFlag"))) appFlag = 0xBEEF;\\after this line is executed all is well and appFlag is changed to BEEF. I see it with breakpoints.


int main(void) {
appFlag = 1; \\after this line is executed the hard fault occurs.
BOARD_BootClockRUN();
Board_Init_UART();
Board_InitLEDs();
Board_Inputs();
Board_Outputs();

the linker file which cause it is as follows:

MEMORY
{
m_interrupts (RX) : ORIGIN = 0x0000A000, LENGTH = 0x00000400
m_text (RX) : ORIGIN = 0x0000A400, LENGTH = 0x000FFBF0 - 0xA400 - 0x100
appFlag (RX) : ORIGIN = 0xFFAF0, LENGTH = 0x100    \* 0xFFAF0 = FFBF0 - 100. But doesn't matter what is the size of the flag, and I tried various addresses. always hard fault*/
m_data (RW) : ORIGIN = 0x1FFF0000, LENGTH = 0x00010000
m_data_2 (RW) : ORIGIN = 0x20000000, LENGTH = 0x00030000
}

/* Define output sections */
SECTIONS
{

.my_section :
{
. = ALIGN(4);
KEEP(*(.MyappFlag)) /* keep my variable even if not referenced */
. = ALIGN(4);
} > appFlag

when writing the linker in that way (accessing the RAM and not the ROM-writing the appFlag to m_data_2) it works fine, but then the bin file size is huge (I guess because 0x20020000 =~512MB):

 

MEMORY
{
m_interrupts (RX) : ORIGIN = 0x0000A000, LENGTH = 0x00000400
m_text (RX) : ORIGIN = 0x0000A400, LENGTH = 0x00075C00
m_data (RW) : ORIGIN = 0x1FFF0000, LENGTH = 0x00010000
m_data_2 (RW) : ORIGIN = 0x20000000, LENGTH = 0x00030000
}

/* placing appFlag section at given address:*/
.my_section 0x20020000 :
{

. = ALIGN(4);

KEEP(*(.MyappFlag)) /* keep my variable even if not referenced */

. = ALIGN(4);

} > m_data_2

Code size:

arm-none-eabi-size --format=berkeley -x --totals "BCA2.elf"
text           data      bss     dec    hex    filename
0x164f0 0x8d0 0x1344 98564 18104 BCA2.elf
0x164f0 0x8d0 0x1344 98564 18104 (TOTALS)

Any ideas?

Tags (2)
0 Kudos
1 Solution
1,315 Views
mjbcswitzerland
Specialist V

Roy

Essentially the method is attempting to do the same thing but I wouldn't involve the linker script since you will be making things non-portable and then involve a rats nest of further tool specific complications such as the one that it then thinks the variable needs to be placed in program code and the huge resulting object files that you have seen - there are certainly workarounds but it is too complicated in my opinion and may break whenever there are tool updates or the same pain if you move to a different environment.

A simple define (i.e. header file) shared by loader and application
eg. #define MAILBOX_MESSAGE *(unsigned char *)TOP_OF_RAM

is adequate (where TOP_OF_RAM is the last byte at the end of however much RAM is present and so automatically adjustable for whatever processor used)

#define EXECUTE_BOOT_LOADER 0x5a

Application does

MAILBOX_MESSAGE = EXECUTE_BOOT_LOADER;
fnSW_reset();

and

Loader does

if (MAILBOX_MESSAGE == EXECUTE_BOOT_LOADER) {
    MAILBOX_MESSAGE = 0;
    if (fnLastReset() == SW_RESET) {

        // stay in loader

    }

}
MAILBOX_MESSAGE = 0;
// jump to application

End of story - no need to complicate things....

Regards

Mark

View solution in original post

8 Replies
1,315 Views
mjbcswitzerland
Specialist V

Roy

If I follow, appFlag is a 'variable' located at 0xffaf0. That is it is initialised directly in the program image.

If you look in the program that you load (eg. binary of srec) you will see its value 0xBEEF there and if you look in Flash after you have loaded it you will see it physically there (also the "variable" will be displayed with the value when doing source level debugging).

Since it is in flash it is not possible to write to it without causing a hard fault.

Since only const data can be store in Flash, correct code would in fact be

const uint16_t __attribute__((section (".MyappFlag"))) appFlag = 0xBEEF;

In this case the compiler would already generate an error message when you do

appFlag = 1;

because the compiler is then aware that writes to the (const) 'variable' are either illegal or not possible.

If you really want to modify the value at this location you need to use a flash driver to erase the sector that it is in and then use a flash driver to write the phrase it is located in with the new value.

Regards

Mark

Kinetis: http://www.utasker.com/kinetis.html
Kinetis K64:
- http://www.utasker.com/kinetis/FRDM-K64F.html
- http://www.utasker.com/kinetis/TWR-K64F120M.html
- http://www.utasker.com/kinetis/TEENSY_3.5.html
- http://www.utasker.com/kinetis/Hexiwear-K64F.html
Flash interface: http://www.utasker.com/docs/uTasker/uTaskerFileSystem_3.PDF


Free Open Source solution: https://github.com/uTasker/uTasker-Kinetis
Working project in 15 minutes video: https://youtu.be/K8ScSgpgQ6M

Professional Kinetis support, one-on-one training and complete fast-track project solutions: http://www.utasker.com/support.html

1,315 Views
roymessinger
Contributor V

Thanks, Mark. 

Fully understood now.

So, this brings me back to starting point.

I want to implement a jump from application to the bootloader and stay there (without time out). The jumping action is working, but obviously, since there's an application at 0xa000 the bootloader jumps back to the app.

I was trying to do that using this idea (https://community.nxp.com/thread/440822 , and there are various different ideas, all based on the same concept of writing a flag to specific location and altering/reading it from both bl and app) , and while it is working if the appFlag is in the m_data section, the flaw is the bin file is huge and flashing it using the bl_host is practically useless.

So, question remains, how do I jump to bl and stay there, with a reasonable size of bin file (with my app it is ~100KB, with adding a section in RAM it getting ~500MB).

Roy

0 Kudos
1,315 Views
mjbcswitzerland
Specialist V

Roy

In the uTasker project, which includes a number of boot loaders, one method used to command the boot loader to remain in its loader mode (and not jump to the application) is to use a RAM mailbox.

Assuming you can modify the boot loader you are using you just need to add something like (pseudo-code):
if (mail box value is equal to boot mode) and (last reset was a SW reset)

    stay in loader

else

    jump to application if available

After this decision the boot loader can clear the RAM mailbox so that it never stays in the loader more than once.

In the uTasker project there is RAM mailbox area reserved by simply setting the stack pointer at the boot loader and application to be a few long words below the top of SRAM. This will then never be used by code and thus is retained across warm resets (and most low leakage modes). One of the entries is reserved for application/loader communication and others for things like random number seeds, time backups for devices that don't hold RTC values across resets etc.

Therefore, the application commands the boot loader mode by writing the boot loader command in the mailbox and commanding a (SW) reset.

Regards

Mark

0 Kudos
1,315 Views
roymessinger
Contributor V

Ok, thanks. I have the source code of KBOOT, so I can alter anything.

Isn't RAM mailbox like what I'm doing when writing to m_data_2 the appFlag?

...

m_data_2 (RW) : ORIGIN = 0x20000000, LENGTH = 0x00030000
}

/* placing appFlag section at given address:*/
.my_section 0x20020000 :
{

. = ALIGN(4);

...

 

As said, this does work (clearing the 'RAM mailbox' works), but the bin file is very large, something I cannot change. The bin file is huge because I'm placing the RAM mailbox at specific RAM location, this is clear to me.

I've found some guidance regarding neglecting the bss section to reduce the bin file size but it didn't work (or I did not manage to do it properly). 

0 Kudos
1,316 Views
mjbcswitzerland
Specialist V

Roy

Essentially the method is attempting to do the same thing but I wouldn't involve the linker script since you will be making things non-portable and then involve a rats nest of further tool specific complications such as the one that it then thinks the variable needs to be placed in program code and the huge resulting object files that you have seen - there are certainly workarounds but it is too complicated in my opinion and may break whenever there are tool updates or the same pain if you move to a different environment.

A simple define (i.e. header file) shared by loader and application
eg. #define MAILBOX_MESSAGE *(unsigned char *)TOP_OF_RAM

is adequate (where TOP_OF_RAM is the last byte at the end of however much RAM is present and so automatically adjustable for whatever processor used)

#define EXECUTE_BOOT_LOADER 0x5a

Application does

MAILBOX_MESSAGE = EXECUTE_BOOT_LOADER;
fnSW_reset();

and

Loader does

if (MAILBOX_MESSAGE == EXECUTE_BOOT_LOADER) {
    MAILBOX_MESSAGE = 0;
    if (fnLastReset() == SW_RESET) {

        // stay in loader

    }

}
MAILBOX_MESSAGE = 0;
// jump to application

End of story - no need to complicate things....

Regards

Mark

1,315 Views
roymessinger
Contributor V

Ok, Mark. Thank you very much for clarifying that issue.

By the way, why do you need this line:

    if (fnLastReset() == SW_RESET) 

Since the MsgBox is already erased after power off?

I tested it without the fnLastReset function and it seems to work flawless.

In the app I set the MsgBox to EXECUTE_BOOT_LOADER

Then i reset and it stays in bootloader.

I do not need to write 0 to Msgbox, since only after poweroff does the MsgBox is erased and it goes back to application.

In that way, reset - stay at bootloader. Power off-power on - jump to application (with the usual conditions...)/

In app:

void JumpToBootloader()
{
MAILBOX_MESSAGE = STAY_IN_BOOTLOADER;

NVIC_SystemReset(); 

}

In bootloader:

if (MAILBOX_MESSAGE == STAY_IN_BOOTLOADER)
{

   // do nothing
{

else // jump to application
{
...

}

I think i'm missing something here?

0 Kudos
1,315 Views
mjbcswitzerland
Specialist V

Roy

The content of RAM is "undefined" after a power on so there is a chance that it powers to the boot loader if the cause of reset is not also checked (if the mailbox happens to randomly have this value set). To check it on the K64 one can do
if ((RCM_SRS1 & RCM_SRS1_SW) != 0) {

}

Since the boot loader code or the application code could be reset unexpectedly (various reset sources including watchdog or EMC disturbances) the mailbox really should be cleared immediately after being read so that there is no chance of it rebooting to the boot-loader (unless that is what you want). Theoretically the check for the software reset cause may make this redundant but it is best to do it cleanly to avoid any unexpected possibilities taking place.

Regards

Mark

P.S. Note also that the uTasker project (it is free and open source) has a complete set of boot loader functions built in which include these configurations, with KBOOT, USB-MSD, Ethernet, UART, SD card, memory stick, Modbus and more methods that can be combined as one wants without the need to invest in redeveloping the basics. It also gives lower footprint loaders to save space in the chips.

0 Kudos
1,315 Views
mjbcswitzerland
Specialist V

Roy

Note that I show the mailbox reset to boot loader in operation in the new uTasker I2C slave loader video in this thread: https://community.nxp.com/thread/468691 

Regards

Mark

0 Kudos