Any way to write flash from the flash application sector?

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

I have an xmega256a3u that I am connecting to the outside world via a bluetooth low energy chip (BLUENRG-MS).  I would like to use the bluetooth interface to update my firmware.

 

As stated in AVR1316: SPM-based commands can only run from Boot Section.  So you can only change flash from the boot section.

 

My code never exceeds 128k, so I was hoping to save the new firmware from the bluetooth interface to the bottom 128k of the flash application section.

 

Is there any trick (such as access the boot from application) so I can change the second 128k of flash?

 

 

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

You need to put the code that writes the application section in the bootloader section, as you have identified. The easiest way to do it is to put a jump table in the bootloader section at a known location, e.g. right after the interrupt vectors, and call functions from the application. Something like this:

 

const BOOTLOADER_JUMP_TABLE_t BL_jump_table __attribute((section(".vectors"))) = {
	{ 'B', 'J', 'T' },
	2,	// version
	(uint16_t)(SP_WriteUserSignatureRow),
	(uint16_t)(SP_EraseUserSignatureRow),
	(uint16_t)(SP_LoadFlashPage),
	(uint16_t)(SP_EraseWriteBootPage),
	
	(uint16_t)(BL_test_jump_table),
	(uint16_t)(BL_check_image),
	
	(uint16_t)(WBL_LoadFlashPage),
	(uint16_t)(WBL_EraseWriteBootPage)
};

 

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

That seems overly complex. Why not just apply BOOTLOADER_SECTION to the routines to be in high flash - the SPM ones and any others need to access data while the application section is "invisible". Then use -Wl,-section-start=.bootloader=0x12345 where 12345 is replaced with the BLS address.

 

But I'm not clear if what's being asked here is simply to add some flash writing to the app or to implement a full bootloader? If the latter just write it as a completely separate program with -Wl,-Ttext=0x12345 to reposition the whole thing to the BLS.

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

The main issue with your method, clawson, is that it is difficult to have both a bootloader and the necessary shared NVM code in the same build using just sections. It's easier to build the bootloader as a separate project.

 

There is then no danger of making changes to the main application that alter the location of the functions in the bootloader, or having to update both the bootloader and application together.

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

Thanks for a responses, all I am hoping to do is use the "extra" flash to store the firmware - just want to be able to write flash within the application section.  I am fine rebooting after the firmware is downloaded and allowing the boot sector to do the actual update.  

 

Also, apologizing for my ignorance, if I put the jump table in my bootloader section, how do I call jump table/SP_LoadFlashPage from the application section?

Last Edited: Wed. Sep 16, 2015 - 04:24 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Try something like:

 

		EIND = 0x01;
		( (void(*)(const uint8_t*)) jump_table.WBL_LoadFlashPage_ptr )( buffer );
		EIND = 0x00;

 

You will need to change the EIND number depending on the size of your flash memory... For 256k it needs to be 0x02 I think (it extends a 16 bit, 64k word address space, so 2 = 256k bytes).

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

Once again you are assuming the app code wants to make calls to functions in the bootloader? Why? The vast majority of bootloaders exist completely standalone and do just one job and I don't really see where OP has asked for anything more than this? The only reason to "access the boot from the app" is to force it into bootloading surely? And to achieve that you don't need fancy jump table schemes that over-complicate. You either just force a WDt reset or even just JUMP to the bootloader entry point (perhaps having set some flag to say "stay in the bootloader and do the update" first).

 

As far as I can see the OP only needs to make a completely separate bootloader that just interacts with the comms, downloads the data and programs it when triggered then jumps into the app code (or just does that anyway when not triggered). As I say the only "trick" here is a -Wl,-Ttext=0x12345 to position the program of the bootloader to the right place.

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

AIUI the op wants the application to load the new firmware image into the upper 128k of application flash memory, and then have the bootloader copy it into the lower half once. In order to write it into the upper 128k, the code that does the writing has to be in the bootloader. Then other code in the bootloader has to do the copying. It could all be part of one large project using sections, but the danger is that the compiler will decide to move something in the bootloader section which can't be updated, and then the new firmware will jump to the wrong address once loaded.

 

I did something similar, but kept the firmware image in an external flash memory, because the comms were too complex to fit into the bootloader section. I agree that it would be best to have all the BTLE code in the bootloader if possible.

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

Oh if THAT is what is really required then I have done that myself (I stored the new code image in a connected AT45 in fact) and the way I did it was simply with BOOTLOADER_SECTION on the routines that either did the SPM or accessed the AT45 (so they would all remain accessible even when the NRWW section goes invisible).

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

We have experimented with an external flash in the past and that works great.  Was just hoping to use the excess flash for this purpose and save 60 cents per module.

 

I have not tried but I was assuming that the BLE code would not all fit in the BOOTLOADER_SECTION, I will try to implement it.

 

If I can't get it all to fit, from your comments I am hearing that I could write the BLE data to the extra flash by jumping to the boot section for flash write but neither of you would recommend that approach?

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

The best option, IMHO, is what I have used previously.

 

 

1. Create a completely separate bootloader. It is made of two parts:

 

    A) Code that runs at reset, checks for the presence of a firmware image in the upper 128k of the application section, and if found copies it the lower 128k.

 

    B) Code that allows writing pages in the upper 128k of the application section, and is callable from a jump table as described above.

 

 

2. Create your application which can call the page write function via the jump table set up in 1B.

 

 

The two are completely separate projects. Changes to one don't affect the other. Don't try to combine them, it gets messy, especially if you use Atmel Studio to manage your projects. It also means you can easily re-use the bootloader in other projects.

 

If I can find some time I might add a jump table to my open source USB HID bootloader (https://github.com/mojo-chan/hid...) but I can't make any promises. It's really not hard to do. Just remember that you need to set up Atmel Studio to erase only the application section and not the bootloader if you are using it to write your application code to the XMEGA.

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

I will start playing, thanks for the insight.