View previous topic :: View next topic |
Author |
Message |
richi-d
Joined: 28 Aug 2007 Posts: 106
|
How to change start address in program memory |
Posted: Fri Jan 27, 2012 8:45 am |
|
|
Hi,
I need to change the start address of the program memory from a PIC24FJ128GA Pic. The bootloader is not allowed to programm adress below 0x400 when CodeProtect is active. But the compiler generates code from adress 0x200.
How can this be shifted? Normally this is done in the Linker, but how to make this with CCS C?
![Twisted Evil](images/smiles/icon_twisted.gif) |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19364
|
|
Posted: Fri Jan 27, 2012 9:11 am |
|
|
#build
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
richi-d
Joined: 28 Aug 2007 Posts: 106
|
|
Posted: Fri Mar 09, 2012 6:15 am |
|
|
Hello Ttelmah,
Can you describe more exactly? The Help file give no answer to my question as it define the memory from start to and end address. But I only want to define the start address. End address may change with program changes.
At what place of the program must I write the #build ?
thanks |
|
![](templates/subSilver/images/spacer.gif) |
richi-d
Joined: 28 Aug 2007 Posts: 106
|
|
Posted: Fri Mar 09, 2012 6:23 am |
|
|
I tried this, but it doesn´t work:
Code: |
#include <24FJ128GA108.h>
#device adc=10
#build(memory=0x06CD4:0x157F6) |
|
|
![](templates/subSilver/images/spacer.gif) |
dyeatman
Joined: 06 Sep 2003 Posts: 1924 Location: Norman, OK
|
|
Posted: Fri Mar 09, 2012 9:29 am |
|
|
Try looking on page 97 of the CCS C manual _________________ Google and Forum Search are some of your best tools!!!! |
|
![](templates/subSilver/images/spacer.gif) |
richi-d
Joined: 28 Aug 2007 Posts: 106
|
|
Posted: Fri Mar 09, 2012 9:41 am |
|
|
Hello,
so it´s not possible to say CCS: here is the start address? This is Page 98:
Syntax: #build(segment = address)
#build(segment = address, segment = address)
#build(segment = start:end)
#build(segment = start: end, segment = start: end)
#build(nosleep)
#build(segment = size) : For STACK use only
#build(ALT_INTERRUPT)
Elements: segment is one of the following memory segments which may be assigned a
location: RESET, INTERRUPT, or STACK
For PIC24 it seems it´s not possible... I need that because after every compiling of the main program, the CCS makes another startadress. I have always to change the start adress in my combined HEXFILE (MAIN+BOOT) |
|
![](templates/subSilver/images/spacer.gif) |
jeremiah
Joined: 20 Jul 2010 Posts: 1328
|
|
Posted: Sat Mar 10, 2012 3:59 pm |
|
|
Did you try the #BUILD statement to see what it does?
I inserted this into a random program of my code:
Code: |
#DEFINE LOADER_END (getenv("FLASH_ERASE_SIZE")-1)
#BUILD (reset=LOADER_END+1,interrupt=LOADER_END+5)
#ORG 0x000,LOADER_END {}
|
Inserting that into your application code with a header file would probably get what you are wanting, unless I am misunderstanding you.
Mind you, you have to handle the ISR mapping in your bootloader program. When using the #build to remap the interrupt vector table, it appears to place interrupt vector addresses every +4 addresses instead of the normal +2, at least in compiler revision 4.130 |
|
![](templates/subSilver/images/spacer.gif) |
richi-d
Joined: 28 Aug 2007 Posts: 106
|
|
Posted: Mon Mar 12, 2012 10:30 am |
|
|
Hello,
I don´t overwrite the page with the interoupt vektors with the bootloader, as this causes problem with older PIC24 with REV.01
The Interrupt vektors are defined by the main program. How can I ensure that they are always at the same adresses?
The thing with the start adress is now secondary... but if later changes to the program change the interrupt vectors, this would be critical...
The problem is the misssing linker in the CCS compiler. |
|
![](templates/subSilver/images/spacer.gif) |
jeremiah
Joined: 20 Jul 2010 Posts: 1328
|
|
Posted: Mon Mar 12, 2012 10:59 am |
|
|
richi-d wrote: | Hello,
I don´t overwrite the page with the interoupt vektors with the bootloader, as this causes problem with older PIC24 with REV.01
The Interrupt vektors are defined by the main program. How can I ensure that they are always at the same adresses?
The thing with the start adress is now secondary... but if later changes to the program change the interrupt vectors, this would be critical...
The problem is the misssing linker in the CCS compiler. |
With PIC24, the only thing I could figure out to do which seems to work is in your bootloader, have the IVT point to specific addresses that would appear in your application program. Then you just have to make sure the application programs all put their interrupt GOTO.
So for example, lets take the timer1 interrupt. NORMALLY, the IVT entry for this is 0x001A, which holds the jump address. What I would do is in your "application" include those 3 lines I mentioned in my last post. What this will do is is put a line at 0x830 that says GOTO XXXX, where XXXX is the interrupt isr location. If your bootloader calls:
#ROM 0x001A = {0x0830}
Then when a timer 1 interrupt happens, it will go to the IVT at location 0x001A, which tells it the ISR is at 0x0830. It will then go to 0x0830 and see the GOTO XXXX instruction, which it will follow to the ISR
The nice thing about this method is that your compiler will use the correct location every time as long as you include those 3 lines in the top of your application |
|
![](templates/subSilver/images/spacer.gif) |
jeremiah
Joined: 20 Jul 2010 Posts: 1328
|
|
Posted: Mon Mar 12, 2012 11:32 am |
|
|
Here is an example of what I mean. It's a mix of the bootloader + application together, so I had to use some #ORG statements to make it all line up:
Code: |
#case
#include <24FJ256GA106.h>
//16 bit pointers
#device *=16
//Fuses for this project
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOJTAG //JTAG disabled
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOWRT //Program memory not write protected
#FUSES NODEBUG //No Debug mode for ICD
#FUSES ICSP1 //ICD uses PGC1/PGD1 pins
#FUSES NOIOL1WAY //Allows multiple reconfigurations of peripheral pins
#FUSES WINDIS //Watch Dog Timer in non-Window mode
#FUSES WDT128 //Watch Dog Timer PreScalar 1:128
#FUSES WPOSTS16 //Watch Dog Timer PostScalar 1:32768
#FUSES NOIESO //Internal External Switch Over mode enabled
#FUSES PR //Pimary oscillaotr enabled
#FUSES NOCKSFSM //Clock Switching is disabled, fail Safe clock monitor is disabled
#FUSES NOOSCIO //OSC2 is clock output
#FUSES HS
//Only adding this to align application code settings
#DEFINE LOADER_END (getenv("FLASH_ERASE_SIZE")-1)
#BUILD (interrupt=LOADER_END+5)
//Remap IVT table, #ORG empty spaces
#ORG 0x0004,0x0019 {}
#ROM 0x001A = {0x0830} //Timer1 Interrupt will always be at 0x0830
#ORG 0x001C,0x01FF {}
void app_main(); //just for forward declaration purposes
#ORG 0x0200,LOADER_END
void main()
{
app_main(); //normally a GOTO LOADER_END+1 here in the bootloader
}
//Application code. Normally, you would do a
// #include "bootloader.h" here which contains:
//
// #DEFINE LOADER_END (getenv("FLASH_ERASE_SIZE")-1)
// #BUILD (reset=LOADER_END+1,interrupt=LOADER_END+5)
// #ORG 0x0000,LOADER_END
#pin_select U1TX = PIN_B6
#pin_Select U1RX = PIN_B7
#use delay(clock=22118400)
#use rs232(UART1,baud=9600,ERRORS,bits=8,parity=N,stop=1)
unsigned int8 count = 0;
#INT_TIMER1
void timer1_isr(){
if(count){count--;}
}
#define COUNTER_VAL 500;
void app_main(){
setup_timer1(TMR_INTERNAL | TMR_DIV_BY_1,11060);
set_timer1(0);
enable_interrupts(INT_TIMER1);
enable_interrupts(INTR_GLOBAL);
printf("STARTING:\r\n\r\n");
count = COUNTER_VAL;
while(TRUE){
if(!count){
printf("Timer Finished...Restarting\r\n");
count = COUNTER_VAL;
}
}
}
|
The #build(interrupts=LOADER_END+5) guarantees the ISR's will be at the same location every time as long as your application code includes the bootloader.h I recommend. No linker would be needed, because as long as the #build statements are there, all the ISRs will be put into the right place no matter how your code changes. |
|
![](templates/subSilver/images/spacer.gif) |
richi-d
Joined: 28 Aug 2007 Posts: 106
|
|
Posted: Tue Mar 13, 2012 2:28 am |
|
|
Hello,
thank you for the detailed answer. The Bootloader is not writen with CCS Compiler (Microchip compiler). We are merging the *.hex Files together.
But if I have the IVT always identical in my CCS Main File, it works. |
|
![](templates/subSilver/images/spacer.gif) |
jeremiah
Joined: 20 Jul 2010 Posts: 1328
|
|
Posted: Tue Mar 13, 2012 2:26 pm |
|
|
Yeah, that can be sucky if the bootloader is not CCS, but it can still work.
Are you able to recompile the "application" code (not the bootloader code)?
Where does the bootloader expect the application reset vector to be?
Where does the bootloader expect the application IVT to be and how is it aligned? |
|
![](templates/subSilver/images/spacer.gif) |
richi-d
Joined: 28 Aug 2007 Posts: 106
|
|
Posted: Wed Mar 14, 2012 2:37 am |
|
|
Hello,
Yes it works perfect, but after every change in the application I have to look where the code start address is, and have to write this start address in the Hex File of the combined App+Boot. This is why I asked how I can make the start address of the application fix. So I don´t have to change always this address in the combined .hex.
The Bootloader doesn't need interrupts. It's polling the Uart and this works perfect. |
|
![](templates/subSilver/images/spacer.gif) |
jeremiah
Joined: 20 Jul 2010 Posts: 1328
|
|
Posted: Wed Mar 14, 2012 9:00 am |
|
|
Well, just the bootloader by itself should expect the code start address to be a particular value. It has to for a bootloader to even work. If you can find out that value from the maker of the bootloader, then all you have to do is:
#build (reset=address)
Where address is that address the bootloader itself expects the code to start.
Once that is done, then the compiler will make changes to the start address for you and always put it where the bootloader expects. The compiler will put a GOTO statement at that address and it will automatically update it with the location of your main when you compile your code. No need to maintain it.
The only reason I mentioned the interrupts is if your application wanted to use them. You said you couldn't write to less than 0x400, so you wouldn't be able to do interrupts unless you went through the steps I mentioned. If you don't need them in the application, then forget about that part. |
|
![](templates/subSilver/images/spacer.gif) |
richi-d
Joined: 28 Aug 2007 Posts: 106
|
|
Posted: Wed Mar 14, 2012 2:16 pm |
|
|
Thank you!
Thats what I was looking for: #build (reset=address)
Now I can say adress is always at 0x10000 and I don´t have to change the adress in the Main+Boot.hex.
But now I really have problems with the Interrupts of my main application. You are right- the compiller doesn´t make the IVT´s at the same adresses when something changes in the aplication. Because of the Bug in the REV01 Pic24FJ the bootloader is not allowed to write the IVT new. Else different IVT would be a problem. But now I must ensure that the IVTs are always on the same adress. For example I have found this two different pointers, because I changes only some little in the code:
This is from the Program memory of the Version 1 of my app:
18 00022 00791E TIMER2_isr
This is from the Program memory of the Version 2 of my app:
18 00022 00790E TIMER2_isr
I tried your code, but get a lot of error messages:
//Remap IVT table, #ORG empty spaces
#ORG 0x0004,0x0019 {}
#ROM 0x001A = {0x0830} //Timer1 Interrupt will always be at 0x0830
#ORG 0x001C,0x01FE {}
How can I easilymake it that this example above is always on 00791 |
|
![](templates/subSilver/images/spacer.gif) |
|