|
|
View previous topic :: View next topic |
Author |
Message |
Eoin87
Joined: 20 Oct 2009 Posts: 18
|
Bootloader questions |
Posted: Thu Oct 18, 2012 10:38 am |
|
|
Hi all,
I'm currently building a wireless boot-loader for PIC24F. I have some questions about how I could generate an object file from my project code.
The problem is the following, the Hex File and the addresses in each line are not sequential, this makes the standard bootloader quite complicated because Flash Memory is only programmable in sectors of 64 instructions. Therefore when I am reading through the hex file, there will be breaks between sectors in program memory which are programmable. This will lead to very slow programming.
Is it possible for the compiler to generate a file which simply give a list of the instruction at each memory location. This would allow for much faster programming of the device.
Any ideas thoughts?
Eoin |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Thu Oct 18, 2012 1:44 pm |
|
|
Well the nice thing is you can write 0xFFFF in words that are not currently being written to until those data values are read from the file, so while, yes slower, you don't have to re-erase the block which is nice.
In general I have found most files to be in order, but you are right, I have seen some that are not in order.
The tricky thing with CCS and non sequential hex files is that the write_program_memory() function will erase the block automatically if the address supplied is on a page boundary. This can get you if you have already erased a block but written to other parts of it prior to calling it for a page boundary address. I ended up having to write my own copy of write_program_memory() that didn't call the erase and managed the erases manually.
In terms of if you can generate a file with specific order of instructions...I don't think it is possible, but maybe a more experienced person here can comment. I've tried using #ROM statements to force stuff, but in the end, the hex file was still out of order, so not sure on that. |
|
|
Eoin87
Joined: 20 Oct 2009 Posts: 18
|
|
Posted: Fri Oct 19, 2012 4:41 am |
|
|
Exactly my thoughts
Thanks for clarifying that, I managed to read the program memory and save to a file on my PC.This way I should be able to write sequentially in full blocks and save time.
Thanks! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Fri Oct 19, 2012 4:43 am |
|
|
Yes, I'd say to a question like this, read it into MPLAB, and write it out from this. It'll then be sequential.
Best Wishes |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Fri Oct 19, 2012 5:12 am |
|
|
Ttelmah wrote: | Yes, I'd say to a question like this, read it into MPLAB, and write it out from this. It'll then be sequential.
|
Until Microchip updates MPLAB in some way that just happens to make it non-sequential. There is no *guarantee* that any file will be sequential: that is built in to the specification. Best therefore to allow for it... somehow.
Another way therefore would be to write a PC app loader that reads the hex into a shadow, and then downloads it sequentially.
RF Developer |
|
|
asmallri
Joined: 12 Aug 2004 Posts: 1634 Location: Perth, Australia
|
|
Posted: Fri Oct 19, 2012 6:20 am |
|
|
I just want to make sure I understand the comments in this thread correctly. I interpreted Eoin's original post to mean the hex file was disjointed but contiguous (i.e. each record is located in memory above the previous record).
However Jeremiah is saying he has seen examples where the records are not contiguous (i.e. a record may be destined for a memory location lower in program memory than the current record). Personally I have not seen this from CCS hex file or Microchip hex files. Also, knowing how some commercial programmers work, they would fail as a result.
Question for Eoin - is the problem you are experiencing because the record is disjointed but contiguous? _________________ Regards, Andrew
http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Fri Oct 19, 2012 6:31 am |
|
|
RF_Developer wrote: | Ttelmah wrote: | Yes, I'd say to a question like this, read it into MPLAB, and write it out from this. It'll then be sequential.
|
Until Microchip updates MPLAB in some way that just happens to make it non-sequential. There is no *guarantee* that any file will be sequential: that is built in to the specification. Best therefore to allow for it... somehow.
Another way therefore would be to write a PC app loader that reads the hex into a shadow, and then downloads it sequentially.
RF Developer |
Yes, however it is very unlikely that a program simply outputting hex from a memory block, would do it in a non sequential way, since this would require extra code, and gain nothing. Just like reading a page, if you have to read the whole thing, the simplest way is to go through it from top to bottom...
It is very different from how the compiler will generate code, since here it is working on logical 'sections' (functions), and having to fit them into available gaps.
Better by far to make the target code support this, but I think the odds are that load and output will give sequential output for any conceivable time.
Best Wishes |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Fri Oct 19, 2012 3:01 pm |
|
|
Yeah, when he said not sequential, I was thinking "out of sequence" rather than "missing chunk". I think I misunderstood what he meant. My apologies.
asmallri wrote: |
However Jeremiah is saying he has seen examples where the records are not contiguous (i.e. a record may be destined for a memory location lower in program memory than the current record). Personally I have not seen this from CCS hex file or Microchip hex files. Also, knowing how some commercial programmers work, they would fail as a result.
|
If you want, I can pm you one of the hex files (assuming it fits in the PM limit). What did it was my IVT remap. Even though the #ROM calls were at the beginning of the code, they placed the actual hex file data at the end. I found it quite weird.
If I get time, I'll try to generate a small example, if you don't think it will derail this thread too much.
EDIT: Did this for PCWHD 4.135:
Code: |
#case
#include <24FJ256GA106.h>
#DEVICE *=16
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOWINDIS //Watch Dog Timer in Window mode
#FUSES NOJTAG //JTAG disabled
#FUSES HS //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOIOL1WAY //Allows multiple reconfigurations of peripheral pins
#FUSES NOCKSFSM //Clock Switching is disabled, fail Safe clock monitor is disabled
#FUSES PR //Primary Oscillator
//Set application space at two pages away
#define PM_END (getenv("PROGRAM_MEMORY")-1) //in words
#define PM_PAGE_SIZE (getenv("FLASH_ERASE_SIZE")/2) //in words
#define PM_ROW_SIZE (getenv("FLASH_WRITE_SIZE")/2) //in words
#define PM_NUM_PAGES (PM_END/PM_PAGE_SIZE)
#define PM_FUSE_PAGE (PM_NUM_PAGES*PM_PAGE_SIZE)
//Just for convenience
#DEFINE BL_IVT_START 0x0004
#DEFINE APP_RESET_LOC (PM_PAGE_SIZE*1)
#DEFINE APP_IVT_START (APP_RESET_LOC+4)
//App IVT entries are spaced twice as far apart as Bootloader IVT entries
//due to using GOTO commands (4 WORDs) instead of just addresses (2 WORDs)
#define REMAP_IVT_ENTRY(entry) \
#ROM entry = {0x00FFFFFF & ((entry-BL_IVT_START)*2+APP_IVT_START)}
//Remap the IVT using the APP IVT location to keep the compiler from
//not wanting to let you remap the IVT here. This doesn't generate any code,
//but lets the #ROM and #ORG statements work
#BUILD (interrupt=APP_IVT_START) //must do this to remap IVT table
//IVT Mapping to application code space
//To mass generate these, use a compiler with output with the following
//code:
//for(int i = 0x0004; i < 0x0100; i+=2){
// printf("REMAP_IVT_ENTRY(0x%04x)\r\n",i);
//}
REMAP_IVT_ENTRY(0x0004)
REMAP_IVT_ENTRY(0x0006)
REMAP_IVT_ENTRY(0x0008)
REMAP_IVT_ENTRY(0x000a)
REMAP_IVT_ENTRY(0x000c)
REMAP_IVT_ENTRY(0x000e)
REMAP_IVT_ENTRY(0x0010)
REMAP_IVT_ENTRY(0x0012)
REMAP_IVT_ENTRY(0x0014)
REMAP_IVT_ENTRY(0x0016)
REMAP_IVT_ENTRY(0x0018)
REMAP_IVT_ENTRY(0x001a)
REMAP_IVT_ENTRY(0x001c)
REMAP_IVT_ENTRY(0x001e)
#ORG 0x0020,0x01FF{}
////////////////////////////////////////////////////////////////////////////////
//BOOTLOADER Utility Code
////////////////////////////////////////////////////////////////////////////////
#ORG (PM_FUSE_PAGE-PM_PAGE_SIZE),(PM_FUSE_PAGE-1) default
#use delay(clock=22118400)
void main()
{
unsigned int8 read_data[32];
//read_program_memory(APP_RESET_LOC,read_data,4);
read_program_memory(APP_RESET_LOC,read_data,4);
delay_ms(3000);
#asm
GOTO APP_RESET_LOC;
#endasm
}
#ORG default
|
This was the resultant hex:
Code: |
:080000003EA404000200000010
:020000040005F5
:10480000910188000300E000130032000000AF00B7
:10481000060037003059BA008301E9000E0032006B
:104820001059BA008301E9000B0032000000E900D2
:1048300030D9BA008301E900070032000059EB00CB
:104840008301E9000000E8000000E0004220AF0022
:104850003220EC00EBFF3700000006000000E00013
:104860004220AF00040037002E2B0900000000009A
:104870000000E900FCFF3A000000060081E0A8000B
:104880002CA3EF000F782400F07F240020A0B700B5
:10489000000000000F782400F07F240020A0B70063
:1048A00000000000004020000100200022802000C5
:1048B0004300200000A402000200000080BB200092
:1048C0002EA402000200000000040400000000000A
:0448D0000040FE00A6
:020000040000FA
:1000080004040000080400000C04000010040000B0
:1000180014040000180400001C0400002004000060
:1000280024040000280400002C0400003004000010
:0800380034040000380400004C
:020000040005F5
:1057F000000000FFFFFF00FFAA8200FF1F3F00FF25
:00000001FF
;PIC24FJ256GA106
;CRC=E217 CREATED="19-Oct-12 17:44"
|
Notice how it toggles the upper address word throughout the hex |
|
|
Eoin87
Joined: 20 Oct 2009 Posts: 18
|
|
Posted: Fri Oct 19, 2012 5:45 pm |
|
|
Often when I looked at my hex files I saw sudden jumps in the addresses.
From the above posted example, one can even see the initial goto being written to location 0x0000 and the main body of the code being written to 0X4800.
heres another example from one of my .hex files
Code: |
:104FF00056250200000000007053880081E0A900DF
:10500000040820001402880081E0A8006E2AEF0046
:1050100000002500A820B7009560A800FFFF37001A
:04502000FFFF370057
:10A00000362BEF00CCA2A90041E2A900F4132000F6
:10A010001412880041E2A800481280003400200099
|
Here there is a jump from 0x5020(phy addr /2) to 0XA000.
I want to write full blocks everytime to the flash memory and not have to run back and forward. This involves also reading before writing and modifying the positions which should be modified.
My aim is to have a file which looks like the following:
Code: |
Address Opcode
0000 04275C
0002 000000
0004 FFFFFF
0006 FFFFFF
0008 0004C0
000A FFFFFF
000C FFFFFF
000E FFFFFF
0010 FFFFFF
0012 FFFFFF
0014 00237E
|
I achieved this file by viewing program memory and exporting the resultant table. This should allow for very fast programming because I can program the flash memory rows, in full 64 instruction blocks, of course after first erasing the correct number of blocks for the new program |
|
|
asmallri
Joined: 12 Aug 2004 Posts: 1634 Location: Perth, Australia
|
|
Posted: Fri Oct 19, 2012 6:56 pm |
|
|
Eoin87 wrote: | Often when I looked at my hex files I saw sudden jumps in the addresses.
From the above posted example, one can even see the initial goto being written to location 0x0000 and the main body of the code being written to 0X4800.
heres another example from one of my .hex files
Code: |
:104FF00056250200000000007053880081E0A900DF
:10500000040820001402880081E0A8006E2AEF0046
:1050100000002500A820B7009560A800FFFF37001A
:04502000FFFF370057
:10A00000362BEF00CCA2A90041E2A900F4132000F6
:10A010001412880041E2A800481280003400200099
|
Here there is a jump from 0x5020(phy addr /2) to 0XA000.
I want to write full blocks everytime to the flash memory and not have to run back and forward. This involves also reading before writing and modifying the positions which should be modified.
My aim is to have a file which looks like the following:
Code: |
Address Opcode
0000 04275C
0002 000000
0004 FFFFFF
0006 FFFFFF
0008 0004C0
000A FFFFFF
000C FFFFFF
000E FFFFFF
0010 FFFFFF
0012 FFFFFF
0014 00237E
|
I achieved this file by viewing program memory and exporting the resultant table. This should allow for very fast programming because I can program the flash memory rows, in full 64 instruction blocks, of course after first erasing the correct number of blocks for the new program |
In your example the blocks are disjointed but contiguous. This is not as efficient for a bootloader as non contiguous code but it is not really going to impact the bootload time significantly.
Jeremiah's example listing has more significance because it will result in writing multiple times to the same page in program memory. Some basic bootloaders (low program memory footprint) will have a problem with this as they will perform a page erase whenever a type 4 record crosses a page boundary. The result is that records from an earlier section of the hex file that has already been programmed earlier in the sequence will be lost during the page erase. It is also BAD for PICs with low program memory flash endurance, significantly shortening the programming life of these PICs. _________________ Regards, Andrew
http://www.brushelectronics.com/software
Home of Ethernet, SD card and Encrypted Serial Bootloaders for PICs!! |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Fri Oct 19, 2012 10:26 pm |
|
|
Eoin87,
One thing you can do to combat the "missing chunks" issue is to have a page sized buffer in your bootloader, initialized to 0xFF in all bytes. Then just fill in data as you get it from the downloader and do a single write.
The gotcha for this method is the issue I was highlighting (and mistakenly thought you meant) where memory jumps around, preventing you from saving data to a page sized buffer completely before data from the next page is introduced. In that scenario, you would just have to write what you have, and eat the "extra" time spent on any later chunks for that page. Remember, you can write 0xFF to any program memory spot as many times as you want as it doesn't change the current value of the spot, so overlap from 0xFF won't hurt you.
Asmallri,
One thing I have been experimenting with to combat this is to rewrite the write_program_memory() method to not erase if the address is a multiple of the page size. Then what I do is when the bootloader starts, it just bulk erases all pages in the user application space before it even determines which pages will be written to.
Now this method means I will be erasing pages that I may not be using, but all pages will have roughly the same lifetime at least. I still may have to deal with not having all of a page's data at once, but I won't have to erase the pages over and over due to data being out of order. |
|
|
Eoin87
Joined: 20 Oct 2009 Posts: 18
|
|
Posted: Wed Oct 31, 2012 9:43 am |
|
|
Getting back to this, reading the program memory and saving to a file works like a charm Very efficient programming. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|