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:-
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 Jack●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 Onestone●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 William J. Watson●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 Gabriel●March 9, 20052005-03-09
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