Hello everyone, I'm using ICC430 and trying to compile a small program where I want main() to stay on the first page of my MSP430F149, and all other rotines and constants to start from the second page, so I can erase the entire flash (page 2 to the end) and reprogram it (using a serial link). That would allow in-system reprogramming without using MSP jtag/bootloader and also would never make the system unbootable. How do I tell ICC where to place the code? I tried to use #pragma abs_address:0x____, but the compiler still placing constants on the first page. Gabriel
Setting absolute addresses on flash (ICC)
Started by ●March 9, 2005
Reply by ●March 9, 20052005-03-09
--- In msp430@msp4..., "Gabriel" <gcalin@u...> wrote:
> I'm using ICC430 and trying to compile a
small program where I want
> main() to stay on the first page of my MSP430F149, and all other
> rotines and constants to start from the second page, so I can erase
> the entire flash (page 2 to the end) and reprogram it (using a serial
> link).
> That would allow in-system reprogramming without using MSP
> jtag/bootloader and also would never make the system unbootable.
> How do I tell ICC where to place the code? I tried to use #pragma
> abs_address:0x____, but the compiler still placing constants on the
> first page.
My approach was to build a separate image for the "loader" code. You
can use the project options or the linker command line option -blit to
set the range of addresses each image uses. I put my loader up at
FE00, with the interrupt vectors. (Interrupts present an ineresting
challenge.)
I'd be interested to hear Al's thoughts on field updates of code.
Regards,
William
Reply by ●March 10, 20052005-03-10
Hi William. I've written on this subject a few times. All but one of
my
systems is field upgradable (and that will be after the current
re-write). There was a very long discussion some time ago. On that
occasion I wrote a fairly long response on the methods that I employed.
This included dealing with midstream failures, power downs, vector
interrupt updates etc. The method you suggest, whereby you assume that
vector interrupts are seldom changed, thus you share the update code
with the vector table is one method. however it is very limited. I find
that the thing I might want to change most is ISR's. Of course if you
are really disciplined you can fix the address of each ISR, and leave
gaps between them. But this still falls over when you might realise that
one ISR needs to be larger than the space allowed. Then things get messy
with subroutine calls from ISR's or a branch from the entry point.
As a very brief synopsis of how I handle it. I typically reserve one of
the smaller data flash segments for tracking my progress, and a full
segment for my downloader. more if necessary. In the 128 byte data
segment I allocate 1 bit per segment of memory to be programmed,
including the downloader for completeness. My RESET vector always points
to the start of the downloader code, which, after turning off the WDT
and setting SP, adds a variable called MODE, stored in the dataflash, to
PC. This vectors the program to the relevant program entry point
depending upon the programmed status of the device. 0 takes me to the
normal program entry point, 4 takes me to the start a new upload point
and 2 takes me to the continue update point. The difference between the
latter two is simply that in the case of an update the software finds
the last succesfully updated segemnt from the dataflash tracking table.
Here a 0 bit means succesfully programmed and verified. The bit is
written AFTER all the tests of the most recently programmed segment. The
segments containing the uploader are set to 0 after skipping the program
step.. The very last segment to be written ios the vector tables. This
segment is erased and the RESET vector is immediately reprogrammed
first. Thus the only risk point is the time between segment erasure and
RESET programming completion. The remaining vectors are then programmed
before completing programming of the remainder of that segment.
If I am using a UART or other peripheral to update the system (rather
than bit banging). The ISR's needed are included in the uploader
segment, and programmed immediately after RESET vector.
A slightly riskier version of this moves the uploader into RAM first,
and reprograms the uploader segments first, using the same techniques.
I think that, provided you have enough space to cater for it, a field
upgrade system like this should be included in every design. It can be
made ass ecure as anything micro based can be, with a little care, and
adds convenience for your customers. There is nothing to stop you from
including encryption in your uploader, allowing your clients to download
updates over the internet and upate their own systems.
Al
William J. Watson wrote:
>--- In msp430@msp4..., "Gabriel"
<gcalin@u...> wrote:
>
>
>>I'm using ICC430 and trying to compile a small program where I want
>>main() to stay on the first page of my MSP430F149, and all other
>>rotines and constants to start from the second page, so I can erase
>>the entire flash (page 2 to the end) and reprogram it (using a serial
>>link).
>>That would allow in-system reprogramming without using MSP
>>jtag/bootloader and also would never make the system unbootable.
>>How do I tell ICC where to place the code? I tried to use #pragma
>>abs_address:0x____, but the compiler still placing constants on the
>>first page.
>>
>>
>
>My approach was to build a separate image for the "loader" code.
You
>can use the project options or the linker command line option -blit to
>set the range of addresses each image uses. I put my loader up at
>FE00, with the interrupt vectors. (Interrupts present an ineresting
>challenge.)
>
>I'd be interested to hear Al's thoughts on field updates of code.
>
>Regards,
>
>William
>
>
>
>
>
>
>.
>
>
>Yahoo! Groups Links
>
>
>
>
>
>
>
>
>
>
Reply by ●March 10, 20052005-03-10
Al-
Could you expand on this a bit? Especially the branch part?
It sounds simple and easy, so I must be overlooking something.
Jack
On Mar 9, 2005, at 7:16 PM, Onestone wrote:
> things get messy
> with subroutine calls from ISR's or a branch from the entry point.
Jack
Reply by ●March 10, 20052005-03-10
Jack wrote: >Al- >Could you expand on this a bit? Especially the branch part? >It sounds simple and easy, so I must be overlooking something. > I've explained the issue regarding branching below, hopefully in adequate detail. The rest is fairly simple, this assumes (being lazy) that the uploader is in the first two main flash segments, so I am just linearly updating:- 1. Receive instruction to upgrade. 2. Confirm this is valid. 3. Erase tracking block 4. clear bit 1 of MODE (MODE = NOT.MODE -2) 5. Signal ready to host 6. Receive next block 7. If Block type (first 2 bytes) = void GOTO 5 8. confirm CRC16 of block 9. if correct GOTO 12 10. send repeat block to host 11. GOTO 6 12. Clear bit 2 in MODE to signal updating 13. erase current segment 14. if segment = VECTORS program in vector sequence then GOTO14 15. program segment (I still prefer a word at a time) 16. verify segment 17. if OK CLEAR BIT IN TRACKING SEGMENT 18. GOTO 5 19. if third attempt GOTO 20 20. GOTO 12 21. if NOT complete GOTO 5 22. END 23. ABORT SESION Obviously there needs to be a little more flesh to this, for example I usually move the erased segment to RAM before erasure, then have the option to reprogram it if I get persistent failures. The 'block type' word at the start of a data packet can be used to indicate if this segment is able to stand alone. This outlines the general principals of the update process. the only thing left is the start up:- ORG UPDATESEG0 RESET: MOV #STACKTOP,SP MOV #PUPPYCIDE,&WDT MOV &MODE,R4 INV R4 DECD R4 AND #0x0006,R4 ;RESTRICT RANGE OF VALUES ADD R4,PC JMP RUNMODE JMP UPDATE RECOVER: ;scan dataflash to get address of next block to program ... ... ... UPDATE: ;DO THE FLASH UPDATE PROCESS ... ... ... ORG USERSEG0 RUNMODE: CALL #INIT ETC ETC > >Jack > >On Mar 9, 2005, at 7:16 PM, Onestone wrote: > > > >>things get messy >>with subroutine calls from ISR's or a branch from the entry point. >> The Branch issue goeas like this:- My old isr setup for TimerA looks like this:- ;TA0 PRODUCES A HEART BEAT TA0_ISR: ADD #TICK,&CCRA0 BIC #CCIFG,&CCTLA0 RETI TA_ISR: ADD &TAIV,PC RETI ;CAN'T BE 0 JMP TA1_ISR JMP TA2_ISR RETI ;DUMMY IN CASE OF TIMERA_5 STYLE RETI JMP TA_OVF ;TIMERA OVERFLOW ISR RETI ;JUST IN CASE TA1_ISR: XOR #BUZZER,&P3OUT ;DO ANYTHING BIC #CCIFG,&CCTLA1 RETI TA2_ISR: BIC #CCIE+CCIFG,&CCTLA2 ;UNUSED INT IS HANDLED RETI Now lets assume that instead of a simple pin toggle for a buzzer your TimerA_1 is now to be used to sequence an external positional servo motor controller. Which requires a sequenced pulse train to instruct it to move and how far. Physically the ISR requires more space than the 3 words it currently uses. If you have not allowed for movable ISR vectors you must now somehow handle the ISR. Luckily I have used 3 words for ISR1, so I could use a call and RETI, as follows:- TAISR: ... ... JMP TA_OVF ;TIMERA OVERFLOW ISR RETI ;JUST IN CASE TA1_ISR: ; XOR #BUZZER,&P3OUT ;DO ANYTHING ; BIC #CCIFG,&CCTLA1 CALL #NEWTA1_ISR RETI TA2_ISR: BIC #CCIE+CCIFG,&CCTLA2 ;UNUSED INT IS HANDLED RETI However, if it was TA2 that I wanted to coopt for a new task I would be stuck using the above method. Although I've (correctly) handled the unused ISR, it only uses 2 words of memory, not enough for a call and return, and using a JMP limits the range I can jump. Typically code would have been packed in the original, so that any space is likely to be out of range of a jmp. In this case use the BRanch instruction:- TA1_ISR: ; XOR #BUZZER,&P3OUT ;DO ANYTHING ; BIC #CCIFG,&CCTLA1 CALL #NEWTA1_ISR RETI TA2_ISR: ; BIC #CCIE+CCIFG,&CCTLA2 ;UNUSED INT IS HANDLED ; RETI BR NEWTA1_ISR TA_OVF: INC &OVERFLOW RETI
Reply by ●March 10, 20052005-03-10
Thanks! Very instructive.
For one thing, I hadn't considered "out of range of a jmp"
likelyhood.
--- In msp430@msp4..., Onestone <onestone@b...> wrote:
> However, if it was TA2 that I wanted to coopt for
a new task I would be
> stuck using the above method. Although I've (correctly) handled the
> unused ISR, it only uses 2 words of memory, not enough for a call and
> return, and using a JMP limits the range I can jump. Typically code
> would have been packed in the original, so that any space is likely to
> be out of range of a jmp. In this case use the BRanch instruction:-