Using internal eeprom for bootloader selection(fixed!) Now I need help with interrupt vectors!

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

Using internal eeprom for bootloader selection(fixed!) Now I need help with interrupt vectors!

2,203 Views
fredrikb
Contributor I

Hello!

 

I'm trying to make a bootloader for a MC9S08PT60 using the processor expert (CW 10.6), but I'm having some problems.

I've looked at this project for inspiration:

http://mcuoneclipse.com/2013/04/28/serial-bootloader-for-the-freedom-board-with-processor-expert/

But I'm trying to adopt it to my cpu, and I need to do some other changes, so I'm basically trying to do it from scratch.

 

First off, I want to use the internal eeprom as a bootloader/main-app selector.

I've made a selector-function, and added it to "User code before PE initialization" under "build options" of the cpu.

And I've added the header-file where the selector-function is declared under "user data declaration".

And to read from the eeprom-area I'm using the PE-generated "IEE1_GetByte"-function.

 

But I get 0xFF in return, regardless of the content of the cell (and I get err=OK)...

The eeprom functions works well in the main-function after "PE_low_level_init()"

So I'm guessing that I need to initialize the eeprom in some way, in my selector-function?

 

And secondly, I dont understand how the jump to the main-app is done in that example:

What exactly does this row do?

((void(*)(void))startup)(); /* Jump to application startup code */

 

Here's the declaration and assignment of "startup" from the same example:

  uint32_t startup; /* assuming 32bit function pointers */

startup = ((uint32_t*)APP_FLASH_VECTOR_START)[1]; /* this is the reset vector (__startup function) */

 

 

Can anyone please help me with this?

Thanks in advance!

 

Ps. one more thing: The eeprom area always erases itself every time I re-program the cpu with CW and the BDM-connector.

How can I prevent that from happening?

Labels (1)
0 Kudos
9 Replies

1,662 Views
fredrikb
Contributor I

I've found out to avoid erasing the eeprom when programming, by checking that memory area under "advanced programming options".

But I would really appreciate some help with the eeprom initialization?

0 Kudos

1,662 Views
Carlos_Mendoza
NXP Employee
NXP Employee

Hi Fredrikb,

Attached is a code example of the UART (SCI) bootloader for the S08P device, it was developed with CW 10.2 for MCU and based on AN2295 (see link below). The bootloader can download the application code to flash via SCI without any other tools. This version of the bootloader can not be used to download code to EEPROM due to limitations of the AN2295 protocol but you can use it as a reference.

http://cache.freescale.com/files/microcontrollers/doc/app_note/AN2295.pdf

About the initialization of the EEPROM, you could call the EEPROM initialization routine the same way you call the selector-function.

Regarding your question about what the line ((void(*)(void))startup)(); does, it cast startup as a function pointer that has void parameters and returns void, and calls it.

Hope it helps!

Best Regards,

Carlos Mendoza

Technical Support Engineer

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

Note: If this post answers your question, please click the Correct Answer button. Thank you!

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

1,662 Views
fredrikb
Contributor I

Thank you for your reply Carlos!

I think I've got the rest of the bootloader functionality pretty much sorted out.

I'm using a WLAN-module to download a s19-file, chunk by chunk from a cloud server.

And I'm trying to use two diffent memory areas for the main app, so it can revert to the old one if anything goes wrong.

That's one of the reasons for wanting to use the eeprom, so I can see what area is currently in use...

I think I have found out how to use the eeprom now.

I tried initializing the FCLKDIV-register (as in "IEE1_Init()"), but then for some strange reason it only worked half of the time I resetted it...

But after copying most parts of the PE-generated "PE_low_level_init"-function and "_EntryPoint"-function, to my boot selector-function, and comment away line for line,

I finally found that the watchdog neds to be initialized before I can use the eeprom.

So now I've just copied the first five rows from the " _EntryPoint"-function, and added them to the beginning of my function.a small delay

I also had to add a small delay before I could read from the eeprom...

0 Kudos

1,662 Views
Carlos_Mendoza
NXP Employee
NXP Employee

Hi Fredrikb,

It is good to hear that the eeprom is now working on your project, please don't hesitate to post a question if you encounter any other problem.

Best Regards,

Carlos Mendoza

Technical Support Engineer

0 Kudos

1,662 Views
fredrikb
Contributor I

Thanks Carlos, I think I'll take you up on that offer right away, since I'm a little uncertain about what to do with interrupt and reset vektors...

I have however managed to make a working bootloader now (without interrups).

Downloading, parsing, verifying, writing flash, resetting and jumping to new app all works :smileyhappy:

And I place them at two different areas in memory, so I can revert back to the previous one, if the download or flash write fails.

But this vector-thing has got me thinking....

As it is now, my BL is located from 0xE000 to 0xFF6F

with it's interrupt vectors at 0xFFB0 - 0xFFFD    

and it's reset vector at 0xFFFE - 0xFFFF

(Which is the MC9S08PT60's default location for both interrupt and reset vectors)

When I make the main apps I give them different adresses in PE (under build options and properties of the cpu)

And I place every even numbered update high in memory, and every odd numbered update low in memory,


So v0.1 would be at 0x3200 - 0x88AF

with it's interrups vectors at 88B0 - 88FD

and it's reset vector at 0x88FE - 0x88FF

And v0.2 would be at 0x8900 - 0xDFAF

with it's interrups vectors at DFB0 - DFFD

and it's reset vector at 0xDFFE - 0xDFFF

This way the BL doesn't have to relocate anything, it just writes to the address specified in the s19-file.

But I don't use interrupts in the test-program, so I haven't been able to determine if the interrupts work if I do it this way.

Would it work, or is this a bad way of doing it?

Best regards

Fredrik

0 Kudos

1,662 Views
fredrikb
Contributor I

Hello again,

I have now tried making it work with my real application, which uses interrupts...

First thing I noticed was that the interrupts doesn't work.

Just because I tell PE to place the interrupts at another address, it still seems to jump to the default location at interrupt.

I have also realized that it is a bad idea to use different addresses for different versions.

Some users might skip over one update, and then it would delete the current version when updating

Instead I will use the same address as for a stand-alone application without the bootloader, and relocate both program and vectors with the bootloader before I write it to flash.

That way I don't have to keep track of changing the settings every time I complile a new version either.

I still have problems with relocating the intrerrupt vectors though :smileysad:

I've tried just writing over the default vectors for the bootloader with the content of the application vectors (after making a backup of the bootloader vectors, so I can change it back later).

And I keep track of which vectors are currently in use, with a byte in the eeprom.

But this doesn't seem to work.

Is there some security function that doesn't allow me to write to the default vector locations while the program is running.

I have not initialized any functions that uses interrupts before i try this.

And I don't get any error message when writing, it just doesn't write the correct data...

If it tries to write 0xE000 it ends up writing 0x2000 instead.

I tried looking at the project you posted Carlos, but I really suck at assembler, and there are some low level aspects of C I'm not so familiar with either, so I don't understand all of it :smileyblush:

I think I have found where you are doing this, but could you please explain what these line does:


uint8_t jmp_code @0x103D = 0xcc;

uint8_t jmp_addr[2] @0x103E = {0,0};


#define INSTALL_VECTOR(n)interrupt n void vector_##n##_ISR(void) {__asm LDHX (RELOCATION_VERTOR_ADDR+(39-n)*2);  __asm STHX  jmp_addr;  __asm PULH; __asm JMP jmp_code;}

This part I understand about the new address for every single interrupt, but thats about it :smileyconfused:

(RELOCATION_VERTOR_ADDR+(39-n)*2)

0 Kudos

1,662 Views
Carlos_Mendoza
NXP Employee
NXP Employee

Hi Fredrikb,

The code you mention will take the INSTALL_VECTOR number and replace it on the declaration interrupt n void vector_##n##_ISR(void), for example:

for INSTALL_VECTOR(5) you will get __interrupt 5 void vector_5_ISR ( void )

then the assembly functions will be executed:

__asm LDHX (RELOCATION_VERTOR_ADDR+(39-5)*2);  (the instruction LDHX will load the index register from memory)

__asm STHX  jmp_addr; (the instruction STHX will store the index register on the global variable jmp_addr located on the address 0x103E)

__asm PULH; (the instruction PULH will pull H (Index Register High) from the stack)

__asm JMP jmp_code; (with the instruction JMP the program will jump to the address where the global variable jmp_code is located, in this case is 0x103D, then it will read the value on this address which is 0xcc, CC is the object code for an extended addressing mode for the JMP function so the effective address will be 0x103E)

Regarding your question about a security function, , please take a look to the Flash protection section 4.5.2.6 of the reference manual:

http://cache.freescale.com/files/microcontrollers/doc/ref_manual/MC9S08PT60RM.pdf

Hope it helps!

Best Regards,

Carlos Mendoza

Technical Support Engineer

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

Note: If this post answers your question, please click the Correct Answer button. Thank you!

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

1,662 Views
fredrikb
Contributor I

I'm having a hard time wrapping my head around how the interrupts are handled, and how I can redirect them...

So I would really appreciate some help.

I have adopted that part of your code, and got it to compile, but when it starts downloading I get this error message:

"Failed to resume target process.

Downloading binary to target..."

I'm also wondering how its supposed to work if I get it to work.

When does the redirection gets invoked?

If it's at start-up of the bootloader, what about the bootloaders own interrupts?

And do I need to change anything in the application program, for it to be able to use the vector redirection?

I have used CW 10.6 in the processor expert mode when I programmed both bootloader and application, if that matters.

0 Kudos

1,662 Views
fredrikb
Contributor I

Thanks a lot for the explaination, that was very helpful!

I guess I have to make sure never to use the entire RAM in the application, so 0x103D-0x103F never gets overwritten.


So can I call that function for every interrupt just before I jump to the application?

like this:

for(i=1;i<40;i++)

     INSTALL_VECTOR(i);

((void(*)(void))startup)(); /* Jump to application startup code *

In you program that code is at the end of main.c:

#if defined(USE_C_VECTOR)

// Interrupt ISRs to jump to user vectors


INSTALL_VECTOR(1)

INSTALL_VECTOR(2)

INSTALL_VECTOR(3)

...

...


When does that code get executed?

Is it at start-up, or only at an actual interrupt?

If so, what if the bootloader uses interrupts as well?

Best regards

Fredrik

0 Kudos