bootloader - problem while erasing and writing flash sector

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

bootloader - problem while erasing and writing flash sector

2,002 Views
Seppel
Contributor I

Hi @all,

i have one project with CAN-bootloader code and app code in it. I have read a lot about the risks by don't seperating bootloader and app in different projects and i have changed every failure source in my C code project... i thought so.

 

Afters reset bootloader starts and when receiving special CAN-FLASH-messages, it starts flashing sector by sector. That works fine for the first 15 sectors! But then it stops and break up. When i debug step by step, i see that the bootloader assembler code which is generated by the compiler (my project is written in C), jumps to an address in application segment that i have erased before!

What the hell is this?!? Why did he do that? All my bootloader C-functions are placed in seperate segment by #pragma CODE_SEG assignment.

Anyway the bootloader code jumps out of its segment in the app segment. Here is the code where it crashes:

//in my Boot.c#pragma CODE_SEG BOOT_CODE#pragma DATA_SEG BOOT_DATA#pragma CONST_SEG BOOT_CONST#pragma STRING_SEG BOOT_STRING //therefor everything that follows belongs to bootloader segment: BOOTLOADER = READ_ONLY 0xD600 TO 0xF9FF;...void FirmwareCanRx(...)  {  unsigned long id_var = 0; //Hilfsvariable zur ID Umrechnung  id_var = CANRIDR0;  id_var <<= 8;       //here assembler code jumps to CODE_SEG application  id_var |= CANRIDR1;  ...  }//////////////////////////////////////////////////////////Debug Code and have a look at generated assembler code//////////////////////////////////////////////////////////C code:id_var = 0CANRIDR0; //to assembler code:LDA _CANRIDR.Dword //PC=DCAF -> BOOTLOADER (everything above 0xD600)TAX                //PC=DCB2STHX  3,SP         //PC=DCB3CLRX               //PC=DCB6STHX  1,SP         //PC=DCB7//C code://id_var <<= 8;//to assembler code:TSX                //PC=DCBAAIX #0             //PC=DCBBLDA #0x08          //PC=DCBDJSR _LLSL          //PC=DCBFJSR _ENTER_UNARY_L //PC=C589 -> error, jump to position below BOOTLOADERSTX ,X             //PC=C1D3STX ,X             //PC=C1D4STX ,X             //PC=C1D5STX ,X             //PC=C1D6...

 I don't know, why the compiler generates such an assembler code. It looks like a code optimization problem for me. Therefor i go to the projects options (Edit->Standard settings->Compiler for HC08) and "disable optimizations" by "-O0" Command line argument. But my code still crashes at this point.

 

Can anyone help me? I am pretty shure that this is a compiler or preprozessor problem... by optimization or linking or whatever... but i don't know what to do next.

Labels (1)
0 Kudos
Reply
7 Replies

1,656 Views
CompilerGuru
NXP Employee
NXP Employee

Well, the "right" solution is to separate the bootloader into its own project....

 

Anyhow. Short of that, the compiler will be using runtime routines for patterns which he thinks that inlining the code is not optimal. Just think of floating point operations or long divisions, there will always be cases where a 8 bit microcontrol has to use runtime routines to translate "simple" C code. Also disabling the optimizations actually makes the resulting code more likely to need runtime routines as it is not optimized. I would try optimizing for time instead, might be the compiler does not use a runtime routine for long shifts then. To avoid using runtime routines, use smaller types. 

 

If you want to make sure some code does not use runtime routines, you can let the compiler issue a warning (or even an error) for that:

 

#pragma MESSAGE WARNING C3605 // Enable warning about using of runtime routines.<boot loader code here>#pragma MESSAGE DISABLE C3605

 

For your case, you can try to recode the long shift operation somehow that the compiler is not using the long runtime routine. 

 

BTW: When using separate apps, the bootloader has its own copy of the runtime routines and this issue does not come up.

 

Daniel

0 Kudos
Reply

1,656 Views
TurboBob
Contributor IV

I agree that the compiler is jumping to a library function.

 

The problem with fiddling with the link order is that then the application will be jumping to the boot segment to use the library.  If a future build puts that library function in a different place then things are broken again.

 

The only way to make this work is to either write the bootloader so it does not use any library functions,  or write it in assembler.

(or write it in C,  and use the compiler output to make an assembler version of the bootloader).

 

There may be some tricks you could play with locating the libraries,  but I suspect you will be building in more future problems than you solve.

 

 

Bob

0 Kudos
Reply

1,656 Views
Seppel
Contributor I

Hi and thanks for your replies.

 

Changing the build order sounds as a really good hint, but didn't change anything :smileysad: Its almost the same error, although the Bootloader.h/.c is linked first now, the assembler code jumps to application segment using _LLSL and _ENTER_UNARY_L. That behavior doesn't make sense for me... perhaps the compiler do so, because the app is located on lower address?!

 

The only way to make this work is to either write the bootloader so it does not use any library functions

mhn.. but the error causing code is just a shifting operation. Its not really a libary function, isn't it? The linker/compiler just recognizes that the code line "id_var <<= 8;" is present in Bootloader.c and App.c and so he decide to bring this function in only once and jumps back by second call of the same code. The only linked library function in bootloader.c is the standard function for the register defines  #include <MC9S08DV32.h> and that one i will never change... could this cause such a problem?

 

or write it in assembler. (or write it in C,  and use the compiler output to make an assembler version of the bootloader).

puh.. that would be time expensive and error prone. I think i am now on that point, where i really have to devide bootloader and app project because of unpredictable behavior :smileysad:

I mean i only recognize this error because a small part of the bootloader wants to jump in a app-sector that i incidentally delete before. I am quite certain that there are more jumps to app which i don't recognize till now... and which i will recognize perhaps in 2 years by changing a liitle thing in the code.

 

So i see there is no way to 100% devide bootloader code from app code in one project, although by using seperated segments and the #pragma CODE_SEG instructions! Linker and/or compiler can generate code, that jumps to unpredictable code segments... which bypasses the #pragma instructions.

0 Kudos
Reply

1,656 Views
CompilerGuru
NXP Employee
NXP Employee

>but the error causing code is just a shifting operation. Its not really a libary function, isn't it? The linker/compiler just

> recognizes that the code line "id_var <<= 8;" is present in Bootloader.c and App.c and so he decide to bring this function

> in only once and jumps back by second call of the same code.

 

No, even if this pattern only exists in the bootloader, the code will look identical and use the runtime routine.

It's not an optimization causing this, its the basic (and unoptimized way) how to perform **bleep**fs on longs.

 

The compiler can warn when using runtime routines, see the other post. But in the end, the proper solution is to use separate applications.



0 Kudos
Reply

1,656 Views
TurboBob
Contributor IV
I think that having a built-in bootloader has advantages in some circumstances. So the "proper" way is to follow the "rules" which means no code execution outside of your bootloader segment. There is no unpredictability in assembler, because there is no optimization of assembler. The cpu does what you tell it to. Its the C compiler that is causing your grief. However, having the bootloader be a separate project does 'fix' all the issues. Bob
0 Kudos
Reply

1,656 Views
bigmac
Specialist III

Hello,

 

Assuming the variable id_var is a 16-bit type, you are attempting to shift the low byte value to the high byte position, with the low byte then zeroed.

 

Inline assembly code to achieve this might be substituted -

 

  __asm {

    ldhx  id_var

    pshx

    pulh

    clrx

    sthx  id_var

  }

.

Regards,

Mac

 

0 Kudos
Reply

1,656 Views
bigmac
Specialist III

Hello,

 

This would seem to be a side effect of compiling the application and bootloader together.  The functions _LLSL and _ENTER_UNARY_L are probably library functions.  It is most likely that the _ENTER_UNARY_L function is used by both the application and the bootloader, resulting in the linker placing the code within the application area, and reusing the code for the bootloader.

 

Maybe changing the link order, so that the bootloader is linked first, could be a possibility.

 

Regards,

Mac

 

0 Kudos
Reply