relocate Interrupt vector start address

Go To Last Post
16 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

I am trying to write a bootloader for the mega128. I want to equally separate the application section of the flash into two parts. I have programmed the necessary fuses to produce a bootloader section of 2048 bytes. The idea is to let the bootloader decide based on version number stored in eeprom which section has the latest code, and run it when the part comes out of reset. This way, i'll always have a backup in flash.

I have sucessfully written some test code which starts executing at 0x7c00. The IVSEL is clear so that the interrupt vector table starts at address 0x0002. The problem is, my interrupts don't work after the code jumps into the application section from boot section.

Is there a way to rewire the interrupt vector start address so that it starts at an address other than 0x0002 or, in my case, 0xF802? If someone could point me in the right direction, i'd greatly appreciate it.

hodgeep

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can, respectively you have to map your ISR-Vectors either to the bootloader section or to the application section.

//---------------------------------------
// Map ISR vectors to bootloader section
//---------------------------------------
cli();               // disable interupts
MCUCR = (1<<IVCE);   // enable interruptvectors change
MCUCR = (1<<IVSEL);  // move interruptvectors to bootloader
sei();               // reenable interrupts
//---------------------------------------
//---------------------------------------
// Map ISR vectors to application section
//---------------------------------------
cli();               // disable interupts
MCUCR = (1<<IVCE);   // enable interruptvectors change
MCUCR = (0<<IVSEL);  // move interruptvectors to application
sei();               // reenable interrupts
//---------------------------------------

Regrds Peter

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank Peter.

You are absolutely right, and I had already implemented your suggestion. But I was looking for information on relocating the ISR-Vector to a specific address in the application section. I believe those instructions put the vector table at either of two addresses (0x0002, or in my case, 0xF802).

Remember that the application section will be divided in two. The version that starts at address 0x0000 works fine. The version that starts at 0x7C00 doesn't. I believe the ISR-vector start address is responsible. Therefore I think I need to relocate it to interrupt vector start address 0x7C02 if I want the interrupts to work . The reset vector is 0x7C00 in the second version of the code.

hodgeep

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You cannot re-map the locations beyond the app/boot section switch available via the IVSEL bit.

Does your boot section use interrupts? If not use the boot table for the first version, the the application section table for the second.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Dean.

The bootloader does not need to use interrupts. It does so now only for test, but I can switch to polling very easily.

Any tips on how I can accomplish your suggested task? How do I tell the code loaded in my reserve application section to use the interrupt vector table from the bootloader section?

hodgeep

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

By messing with IVSEL as peter.sager says. You'll have to do a song and dance to get the darn thing to all link correctly. I've personally never tried it, but it's possible.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Apologies for bringing this thread back from the mists of time, but I'm trying to do almost exactly what the original was trying, and have yet to find a solution better than those above, which will work, but don't seem optimal.

 

Fiddling with MCUCR and IVSEL will work, but only allows two interrupt tables, and as Deans said, will likely need a song and dance with the linker.

 

I'm trying to do this almost with an ATmega128, specifically an ATmegaS128, so my purpose is plausibly guessed as involving a higher level radiation environment than normal. smiley

 

I'd like to have several copies of my program available, and will generally patch an unused copy, before changing the reboot location (probably stored in EEPROM) and then initiating a reboot using the Watchdog.  There may also be a CRC or Checksum done on the code, before allowing switching into that program space.  Being able to have more than a bare minimum two copies, would be preferable, so I'm considering just sending all of the interrupts to a part of the "bootloader" (which won't really do any loading), where it looks up the interrupt from a RAM based table, and jumps to that location.

 

There will be a slight cost in speed and RAM use, but I guess that will probably be tolerable.  I'm still going to have to fiddle with the linker, and write a few small functions to handle interrupt setup, but probably nothing particularly onerous.  There's also an increased risk of failure, since corruption/failure of either the relevant part of the Flash or the secondary interrupt lookup table in RAM would cause an interrupt to fail.

 

Has anyone thought of a tidier or better way of doing this, in the intervening decade ?

Actually, I am a rocket scientist.

Last Edited: Mon. May 14, 2018 - 07:29 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Flexagain wrote:
where it looks up the interrupt from a RAM based table, and jumps to that location.
Sorry but you are working in a rad-hard environment and you actually want to have the vectors go via RAM which is even more hazardous than the flash?!?

 

AVRs only allow for two copies of the vector table - the one at 0 and the one at the BOOTSZ location (and enabled by IVSEL) and that is it. So you are going to have to "trust" one or other of those as that's the only place the AVR will (initially) be headed on the occasion of an interrupt event. Sure, one or other of those could then have some fancy function pointer based redefinable destination but the stuff at the initial vector location has to be trusted. Also, like I say, taking execution out through RAM (which might be blown away in a cosmic nanosecond) is "dangerous" at best.

 

I would advise you write any code for a "hostile" environment with a minimum of MISRA as your guiding standard and one of the first things you are going to find there is that RAM based vectoring is a no-no.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Flexagain wrote:
where it looks up the interrupt from a RAM based table, and jumps to that location.

Sorry but you are working in a rad-hard environment and you actually want to have the vectors go via RAM which is even more hazardous than the flash?!?

 

Well, without a detailed radiation report, whether Flash or RAM is the most radiation tolerant is an arguable point, neither is generally very rad hard.  If we were really worried about radiation effects, we wouldn't be using an AVR, which only has a TID of 30 kRad anyway.

 

clawson wrote:
... Also, like I say, taking execution out through RAM (which might be blown away in a cosmic nanosecond) is "dangerous" at best.

 

In an ideal world, I'd find other ways to do it.  I could put the patch table into Flash or EEPROM too, but that would substantially complicate the code, which itself is generally undesirable, and may be just as bad from an SEU point-of-view.  Having to patch a single copy of the code, whilst it's executing would also be undesirable.

 

clawson wrote:
I would advise you write any code for a "hostile" environment with a minimum of MISRA as your guiding standard and one of the first things you are going to find there is that RAM based vectoring is a no-no.

 

If I had the time to deal with proper software management standards, I'd being using far more stringent than MISRA, but unfortunately this is a small mission, where available manpower and costs are minimal, so we have to get by with what's available.  I'd love to be able to write stringent code, and undertake a lot of testing, but practically I've barely got the time to write the code and get it working !

 

The best we can do to make things more tolerant, is follow Atmel's guidance (ie Application Note 41086A), use the Watchdog and throw CRC/checksums at things, when I can.  A temporary flip in RAM is just likely to crash the CPU, and hopefully that's recoverable with a Watchdog reboot.  A flip in the Flash could be more permanent, and a minimal bootloader, doing some sort of consistency checking on the Flash, before it switches to the most reliable codeset has some advantages.  The bootloader itself is always going to be a single point of failure, but there's nothing that can be done about that, with a single chip solution, like an AVR.

Actually, I am a rocket scientist.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Well like I say, the AVR does not give you much choice. There are only two possible locations for the IVT (and only one can be active) so you have to trust the active one.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can use a common interrupt jump table to another set of addresses, that will execute a jump to an address recorded in a table at the eeprom.  So, whenever your application starts, address zero or bootload address, it will transfer its own jump address table to this common address at eeprom, if the eeprom doesn't contain the exact copy of it (saving erase/write life count of eeprom).  So, no matter which application is running, the eeprom will contain the jump addresses for that application, and interrupts will jump to the right addresses.

 

I used a similar technique with 8051 microcontroller accessing more than 64k of program code, when the code by itself switch eproms (or banks in the same 512kBytes eprom), he had the same jump table at the interrupt address on both eproms, and both eproms had the exactly the same interrupt routines, so it never get lost.  I even wrote this on my very old (many years ago) website http://www.ustr.net/electronics/512k.shtml

Wagner Lipnharski
Orlando Florida USA

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My approach to this sort of problem was to partition the Flash into N+1 sections. (Where N is the number of possible applications which you want to be able to fall back on at any point in time.)

 

The running application always resides in the zeroth Flash partition, and the higher partitions are only used to hold the archived alternate applications.

 

The bootloader determines which application needs to run in any given circumstance, and copies it into the zeroth partition, where it is always mapped directly into the AVR's native interrupt vector table, no extra indirect jumps need to be computed or evaluated, and the linker doesn't need any trickery to know how to call functions, compute interrupt addresses, etc.

 

For good measure, of course, all Flash partitions are signed with a CRC so that the bootloader can be certain, in advance, that the application it's about to run hasn't experienced any accidental corruption.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would advise you write any code for a "hostile" environment with a minimum of MISRA as your guiding standard

If you don't, you will likely be rather "misrable".  crying 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

place an universal interrupt-vector-table at $0000 and all of your applications (with their own interrupt-vector-tables in the beginning) on page boundaries from $0100 on

 

an interrupt-vector on page $00 has room for two 1-word-assembler instructions: the first will fetch his own vector-address low-byte and 'rjmp' to the universal interrupt-handler. the handler will fetch the high-byte of the active application from EEPROM (or SRAM or an unused IO-register [GPIO would be fine but there isn't one on mega128, is it?]), push the two bytes in the right order onto stack and perform an 'ret' 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My question is related to ATMega 640/1280/2560. Let us suppose that the Reset Vector is moved to BLS and the IVT resides in the app section. Under the stated condition, I assume that the app section address 0x0000 is like any other normal flash location, but can not be used for useful purpose. Is it correct?

Vinu Raja Kumar C

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you do use interrupts in a bootloader usually youd have TWO interrupt vector tables in the AVR. One is built at the BLS address and is used by the bootloader. When it first starts it sets IVSEL so that one is active. Once it has done its thing and is about to start the app it resets IVSEL then jumps to the app that can then use it's own set of interrupts. Obviously if either program will not use interrupts you can build it with -nostartfiles and reclaim the flash space the IVT from the CRT would have occupied.