EmbDev.net

Forum: ARM programming with GCC/GNU tools jump to address within flash space


von Roman M. (romez777)


Attached files:

Rate this post
useful
not useful
MCU: at91sam7s256
toolchain: Yagarto (gcc-4.2.1)

I'm developing a simple application:

First image XXX bytes length is burnt on the flash at the very
beginning, by address 0x100000; second image resides on the flash at the
(0x100000 + XXX). First image prints a short debug message on DBGU port
and then should jump to (0x100000 + XXX) and run the second one - but it
never happens!

Enclosed are the main source file and linker scripts. What did I miss,
seems like some trouble with addresses, at which applications run.

Thanks in advance for any hints!

von Roman M. (romez777)


Rate this post
useful
not useful
As far as I guess, the first image should disable interrupts before
transferring control to the 2nd image. Am I right?

And perhaps similar actions should be done with peripherial used by the
first image, may be reset is important.

Any comments are welcome! Thanks.

von Kees S. (kees)


Rate this post
useful
not useful
Roman Mashak wrote:
> As far as I guess, the first image should disable interrupts before
> transferring control to the 2nd image. Am I right?
>
> And perhaps similar actions should be done with peripherial used by the
> first image, may be reset is important.
>
> Any comments are welcome! Thanks.

Hi Roman,

There should not be a need to disable interrupts. You only do a jump to
some other location, so an interrupt should not cause problems.

What I would like to know is, does the first program work as expected ?
How do you load the two parts into the flash ?
How is the first part executed ?
Why do you include the startup code in the second part.

Let me explain why I would like the answer to especially the last two
questions. As you probably know, any ARM7 processor starts executing
code from address 0x0. Most ARM processors have an option to temporary
map the flash into this area. (I don't know how the AT91 does this
though, so I hope the part below also applies to you) Your startup code
should take care of mapping the flash back to 0x100000 when done and map
RAM memory in the 0x00 area. The boot code of course should resides in
the flash. Mmmm, is difficult to explain. But in your case, the startup
code runs from address 0x00, but is stored at 0x100000.

So I would expect a line in your linker file where you specify that the
bootloader code is running in address 0x00 but stored in the flash.
Normally you make a special section for that like:

SECTIONS
{
  BOOT 0x00000000 : AT (0x100000)
  {
    *Cstartup.o (.text)
  }
  _boot_size = (. + 3) & ~ 3;

  .text (0x100000 + _boot_size) :
   {
    *(.text .text.*)

....

Of course the startup code only runs after a reset and should call the
main function of your first program part. The 2nd part does not need
startup code, as it is simply called from the first part.

Hope this helps,
Cheers,
Kees.

von Roman M. (romez777)


Rate this post
useful
not useful
Hi,

Kees Stoop wrote:
> There should not be a need to disable interrupts. You only do a jump to
> some other location, so an interrupt should not cause problems.

On the another forum I read, that enabled interrupts may cause the
application, one transfers control to, to get into unpredictable state.
I'm actually trying to implement a simple bootloader, which can load new
firmware via USB and burn into flash.

> What I would like to know is, does the first program work as expected ?
Yes, it works as it should.

> How do you load the two parts into the flash ?
I use SAM-BA, which allows to specify the load address.

> How is the first part executed ?
The first part prints a string in DBGU, and attempts to jump over the
address the second image resides on:

[snippet]
typedef void (*funct)(void);

//* external functions
extern unsigned disableIRQ();

...

int main(void)
{
    AT91F_DBGU_Init();
    AT91F_DBGU_Printk("before jump\n\r");

    disableIRQ();
    *AT91C_RSTC_RCR = 0xa5000004;    //Reset only peripherals

    //Run the application
    ((funct)0x10058c)();  // address of 2nd part

}

This is what 2nd part is supposed to do:

//* external functions
extern unsigned enableIRQ();
...

int main(void)
{
   enableIRQ();

   AT91F_DBGU_Init();
   AT91F_DBGU_Printk("after jump\n\r");

   while (1)
   {
   }
}

> Why do you include the startup code in the second part.
Earlier http://en.mikrocontroller.net/topic/144666#new I've been
explained that startup is needed.

...

von Kees S. (kees)


Rate this post
useful
not useful
Roman Mashak wrote:
> Hi,
>
> Kees Stoop wrote:
>> There should not be a need to disable interrupts. You only do a jump to
>> some other location, so an interrupt should not cause problems.
>
> On the another forum I read, that enabled interrupts may cause the
> application, one transfers control to, to get into unpredictable state.
> I'm actually trying to implement a simple bootloader, which can load new
> firmware via USB and burn into flash.
>
>> What I would like to know is, does the first program work as expected ?
> Yes, it works as it should.
>
>> How do you load the two parts into the flash ?
> I use SAM-BA, which allows to specify the load address.
>
>> How is the first part executed ?
> The first part prints a string in DBGU, and attempts to jump over the
> address the second image resides on:
>
> [snippet]
> typedef void (*funct)(void);
>
> //* external functions
> extern unsigned disableIRQ();
>
> ...
>
> int main(void)
> {
>     AT91F_DBGU_Init();
>     AT91F_DBGU_Printk("before jump\n\r");
>
>     disableIRQ();
>     *AT91C_RSTC_RCR = 0xa5000004;    //Reset only peripherals
>
>     //Run the application
>     ((funct)0x10058c)();  // address of 2nd part
>
> }
>
> This is what 2nd part is supposed to do:
>
> //* external functions
> extern unsigned enableIRQ();
> ...
>
> int main(void)
> {
>    enableIRQ();
>
>    AT91F_DBGU_Init();
>    AT91F_DBGU_Printk("after jump\n\r");
>
>    while (1)
>    {
>    }
> }
>
>> Why do you include the startup code in the second part.
> Earlier http://en.mikrocontroller.net/topic/144666#new I've been
> explained that startup is needed.
>
> ...

Hi Roman,

Ok, well, after a second look, I guess that the link files are correct
after all.

You do need your startup code when you want to intialize the bss and
data sections, so to init. global variables. However, normally the
startup code does a lot more then just clearing bss and init the data
section. I guess that the AT91, like all ARM7's start at address 0x00
after a reset, so the startup code should remap the flash. It also
should provide the interrupt vector table and provide dummy handlers for
unused exceptions. I don't think that the 2nd startup code should re-do
those parts. So I guess it is best to write some simple startup code for
the second part, that only clears bss and copies etext to data, before
calling main. The first program should then jump to the start of the
second startup code.

But still, I don't get it. You do a jump to address 0x10058c, but you
load the second program at 0x001004f8 so maybe I am just missing
something.

Kees.

von Roman M. (romez777)


Rate this post
useful
not useful
Hi Kees and thank you for your response.

Hm.. I'm completely confused with what should I do.
And I don't quite understand the concept of remapping, though I've read
in Atmel's appnote and in your message - but it's still unclear :(

Do you think, if I make two identical C-startups, it will somehow spoil
the behavior of the processor after jump?

Kees Stoop wrote:
> You do need your startup code when you want to intialize the bss and
> data sections, so to init. global variables. However, normally the
> startup code does a lot more then just clearing bss and init the data
> section. I guess that the AT91, like all ARM7's start at address 0x00
> after a reset, so the startup code should remap the flash. It also
> should provide the interrupt vector table and provide dummy handlers for
> unused exceptions. I don't think that the 2nd startup code should re-do
> those parts. So I guess it is best to write some simple startup code for
> the second part, that only clears bss and copies etext to data, before
> calling main. The first program should then jump to the start of the
> second startup code.
>

von Martin T. (mthomas) (Moderator)


Rate this post
useful
not useful
The code attached to the first e-mail is not complete. Just some
thoughts:
- Read the map-file and maybe the disassembly to see where your code and
data gets located by the linker
- Even if not done for AT91 the code in this project might help to
understand some the needed settings in makefile, linkerscript and
startup:
http://www.siwawi.arubi.uni-kl.de/avr_projects/arm_projects/index_str.html#str7_uart_boot
Of cause the hardware-init and remapping of exception-vectors has to be
handled differently for AT91 but the concept is the same.

von Roman M. (romez777)


Attached files:

Rate this post
useful
not useful
Martin Thomas wrote:
> The code attached to the first e-mail is not complete. Just some
> thoughts:
> - Read the map-file and maybe the disassembly to see where your code and
> data gets located by the linker

Herllo, Martin.

I've made 'objdump' of both images and explored it. So far I didn't find
anything suspicious, except there's a bunch of instructions past the
main() function, I don't know for sure it's normal or not.

Just in case I'm attaching the archive with dumps, they're quite small,
perhaps someone may clarify the issue :)

von Kees S. (kees)


Rate this post
useful
not useful
Roman Mashak wrote:
> Hi Kees and thank you for your response.
>
> Hm.. I'm completely confused with what should I do.
> And I don't quite understand the concept of remapping, though I've read
> in Atmel's appnote and in your message - but it's still unclear :(
>
> Do you think, if I make two identical C-startups, it will somehow spoil
> the behavior of the processor after jump?
>
> Kees Stoop wrote:
>> You do need your startup code when you want to intialize the bss and
>> data sections, so to init. global variables. However, normally the
>> startup code does a lot more then just clearing bss and init the data
>> section. I guess that the AT91, like all ARM7's start at address 0x00
>> after a reset, so the startup code should remap the flash. It also
>> should provide the interrupt vector table and provide dummy handlers for
>> unused exceptions. I don't think that the 2nd startup code should re-do
>> those parts. So I guess it is best to write some simple startup code for
>> the second part, that only clears bss and copies etext to data, before
>> calling main. The first program should then jump to the start of the
>> second startup code.
>>

Hi Martin,

Yes, I think that with two identical startups you will have a problem.
The 2nd startup is not required, unless you need to have your global
variables initialized. To explain the mapping concept is a little
difficult and I guess that the people from Atmel are much better in this
then I am, so I suggest to read the datasheet about this.

For the 2nd startup file, I would simply make a 2nd c-file and make sure
this is loaded first. Your first program should jump to the StartSecond
function, so make sure that this is the first function in the file. This
should init the bss and data sections and then jump to main. So
something like this:

void StartSecond(void)
{
        InitBss();
        InitData();
        main();
}

To init bss, you can use the linker variables that you specified in the
.ld file. You can use something like this:
  extern unsigned long __bss_start__[];
  extern unsigned long __bss_end__[];

  unsigned long *ptr;

  ptr = _bss_start_;
  while(ptr < _bss_end_)
    *ptr++ = 0;


to init data, you can use something like this:
  extern unsigned long _data[];
  extern unsigned long _edata[];
  extern unsigned long _etext[];

  unsigned long *src, *dest;

  src = _etext;
  dest = _data;

  while(dest < _edata)
  {
    *dest = *src;
    dest++;
    src++;
  }

This should work (I know this from experience)
Have fun!

Kees.

von Jonathan D. (dumarjo)


Rate this post
useful
not useful
Roman Mashak wrote:
> Martin Thomas wrote:
>> The code attached to the first e-mail is not complete. Just some
>> thoughts:
>> - Read the map-file and maybe the disassembly to see where your code and
>> data gets located by the linker
>
> Herllo, Martin.
>
> I've made 'objdump' of both images and explored it. So far I didn't find
> anything suspicious, except there's a bunch of instructions past the
> main() function, I don't know for sure it's normal or not.
>
> Just in case I'm attaching the archive with dumps, they're quite small,
> perhaps someone may clarify the issue :)

I have done this for a boot loader,

You need to set of linker script.

1- your first program should have a starting based address of you flash
at 0x100000.

The second one you will have to modify you new address to

0x100000 + size of your choice.

After that when you download you bin files, don't forget to remove the
flash erease command.

Change your download script to reflect the address of your both bin
files.

After that everything should work.

Jonathan

von Roman M. (romez777)


Rate this post
useful
not useful
Jonathan Dumaresq wrote:
> You need to set of linker script.
>
> 1- your first program should have a starting based address of you flash
> at 0x100000.
>
> The second one you will have to modify you new address to
>
> 0x100000 + size of your choice.
>
> After that when you download you bin files, don't forget to remove the
> flash erease command.
>
> Change your download script to reflect the address of your both bin
> files.
>
> After that everything should work.

Hello Jonathan.

I've already done all this, and it didn't work for me. I'm pretty sure
linker scipt is correct, because I explored the MAP file, generated
after build, and 'objdump -SD ..'. Addresses seem to be correct.

I suspect problem is with C-startup somewhere. If you don't mind, can I
mail you my linker script and startup files? Perhaps you could catch the
error.

Thanks.

von Jonathan D. (dumarjo)


Rate this post
useful
not useful
Roman Mashak wrote:
> Jonathan Dumaresq wrote:
>> You need to set of linker script.
>>
>> 1- your first program should have a starting based address of you flash
>> at 0x100000.
>>
>> The second one you will have to modify you new address to
>>
>> 0x100000 + size of your choice.
>>
>> After that when you download you bin files, don't forget to remove the
>> flash erease command.
>>
>> Change your download script to reflect the address of your both bin
>> files.
>>
>> After that everything should work.
>
> Hello Jonathan.
>
> I've already done all this, and it didn't work for me. I'm pretty sure
> linker scipt is correct, because I explored the MAP file, generated
> after build, and 'objdump -SD ..'. Addresses seem to be correct.
>
> I suspect problem is with C-startup somewhere. If you don't mind, can I
> mail you my linker script and startup files? Perhaps you could catch the
> error.
>
> Thanks.

look here

www.cimeq.qc.ca/AT91SAM7SERIALBOOT_s256.zip

you should find what your are looking for

Jonathan

Please log in before posting. Registration is free and takes only a minute.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
No account? Register here.