I have a situation where I need to erase and program flash from code
placed into ram.
I can not use the pushed on stack code method shown in various app
notes.
I have writen a routine that works perfectly if placed in flash but
will not run out of ram.
I am testing the busy just like in the app note. I can not even get
the flash to erase reliably (It did erase for me a few times)
Here is the initial code up to the erase:
DINT ;DISABLE INTERUPTS
CLR.B &0 ;CLEAR INTERUPTS
MOV #5A80,&288 ;SHUT DOWN WATCHDOG
MOV #0,R13 ;SETUP LOOP COUNTER TO ERASE 10 SEGMENTS
ERSLP: CMP #10,R13
JGE WRTBYT ;JUMP TO WRITE BYTE ROUTINE WHEN DONE
WAIT1: BIT #1,&12CH ;TEST THE BUSY FLAG IN FCTL3
JNZ WAIT1 ;WAIT TILL NOT BUSY
MOV R13,R12 ;CALCULATE SEGMENT ADDRESS OFFSET
ADD.B R12,R12 ;BY MULTIPLYING 512 TIMES COUNTER
SWPB R12 ;THEN ADDING IT T0 THE BASE ADD LATER
MOV #0A500H,&12CH ;REMOVE THE LOCK
MOV #0A502,&128H ;SET ERASE
CLR.B #0D800H(R12) ;DUMMY WRITE AT BASE + OFFSET
WAIT2: BIT #1,&12CH ;TEST THE BUSY FLAG IN FCTL3
JNZ WAIT2
MOV #0A510H,&12CH ;SET THE LOCK
ADD #1,R13 ;INCREMENT THE LOOP COUNTER
JMP ERSLP ;GO BACK TO DO NEXT SEGMENT
WRTBYT: ; CODE NOW WRITES DATA TO FLASH IF I COULD GET THIS FAR.
Like I said, this code works fine if run out of flash.
Is it a speed problem? I have tried setting up a number of timing
options to no avail.
Does anyone know of a DCO clocked or a 32768 clocked senario that
would work in the msp430f149?
You help in this would be greatly appreciated.
Ted Gregorius
TAG Systems
I haven't looked at your code in detail but the first question to ask
when
running code from RAM is how did the code get there? That might seem a peculiar
question, but generally to do this you would place the code to do the
erase/write in flash along with the rest of your code and copy it to RAM when
it becomes time to do some erasing/writing. Therein lies the (or at least a)
problem. If the code is linked with other code at a flash address it won't
work
when re-located by a simple copy operation, eg if you just copy it from some
flash address to some (other) RAM address unless it only uses relative
addressing. Depending on the processor type you use, an instruction such as JGE
uses relative addressing and therefore may be re-located from flash to RAM or
another flash segment without problems (JGE to an address is ok when that
address moves along with the re-located code). However, an instruction such as
JMP generally uses absolute addressing which will fail, since the absolute
address you're jumping to stays where it was linked, ie back in the flash
area
where you copied the code from and not in the new RAM area. In other words at
the first absolute JMP your RAM program jumps straight back into the flash area
you copied it from and it can't get back.
To avoid this problem only use relative addressing in re-locatable code or
modify your target jumps in absolute addressing (eg JMP ERSLP+OFFSET where
offset is the distance between flash address and RAM address). I'd post
some
code as an example but I haven't done this on the MSP430 yet; however I
seem to
recall some past posts addressed this issue. Relative addressing is easy to do,
however, particularly when you're working in assembler. Replace all
instructions with an absolute target address with instructions using a relative
address. A JMP can be replaced with a JGE if you fiddle with the flags to make
a GE condition prior to the JGE. Look at the assembler description of all the
instructions which modify the program counter to see whether they are relative
(ie ok )or absolute (need fixing).
Otherwise on the MSP430 RAM is just as good as flash for running code, there
are no penalties.
Regards, Hugh
>I have a situation where I need to erase and
program flash from code
placed into ram.
I can not use the pushed on stack code method shown in various app
notes.
I have writen a routine that works perfectly if placed in flash but
will not run out of ram.
I am testing the busy just like in the app note. I can not even get
the flash to erase reliably (It did erase for me a few times)
Here is the initial code up to the erase:
DINT ;DISABLE INTERUPTS
CLR.B &0 ;CLEAR INTERUPTS
MOV #5A80,&288 ;SHUT DOWN WATCHDOG
MOV #0,R13 ;SETUP LOOP COUNTER TO ERASE 10 SEGMENTS
ERSLP: CMP #10,R13
JGE WRTBYT ;JUMP TO WRITE BYTE ROUTINE WHEN DONE
WAIT1: BIT #1,&12CH ;TEST THE BUSY FLAG IN FCTL3
JNZ WAIT1 ;WAIT TILL NOT BUSY
MOV R13,R12 ;CALCULATE SEGMENT ADDRESS OFFSET
ADD.B R12,R12 ;BY MULTIPLYING 512 TIMES COUNTER
SWPB R12 ;THEN ADDING IT T0 THE BASE ADD LATER
MOV #0A500H,&12CH ;REMOVE THE LOCK
MOV #0A502,&128H ;SET ERASE
CLR.B #0D800H(R12) ;DUMMY WRITE AT BASE + OFFSET
WAIT2: BIT #1,&12CH ;TEST THE BUSY FLAG IN FCTL3
JNZ WAIT2
MOV #0A510H,&12CH ;SET THE LOCK
ADD #1,R13 ;INCREMENT THE LOOP COUNTER
JMP ERSLP ;GO BACK TO DO NEXT SEGMENT
WRTBYT: ; CODE NOW WRITES DATA TO FLASH IF I COULD GET THIS FAR.
Like I said, this code works fine if run out of flash.
Is it a speed problem? I have tried setting up a number of timing
options to no avail.
Does anyone know of a DCO clocked or a 32768 clocked senario that
would work in the msp430f149?
You help in this would be greatly appreciated.
Ted Gregorius
TAG Systems
__________________________________
Reply by Kevin Brewster●July 8, 20032003-07-08
I ran into these relocation issues when writing some code to allow for
in-field firmware updates. On the MSP430 all of the "jump" type
instructions
(JMP, JGE etc.) are relative, while BRANCH & CALL are absolute.
Unfortunately the MSP430 doesn't appear to have a relative equivalent to
CALL, so everything has to be put in one function if it's to be copied to
ram :-(
If it's of any help, here's some early code (with bugs included free
of
charge ;-). Be aware that there is no DCO stabilisation, error detection
etc. in this yet. But it did work in early tests.
I'm a relative newbie to C programming, so if anyone notices any glaring
evils please let me know!
Regards,
Kevin Brewster
Australia
void fieldinit(void) // initialise field programming
{
register unsigned int i; // loop counter
register unsigned char *fn_flash, *fn_ram; // function copying pointers
register void (*fieldinit_in_ram)(void); // function pointer
BCSCTL1 = (BCSCTL1&~(RSEL2+RSEL1+RSEL0))+RSEL1; // RSEL = 2
DCOCTL = (DCOCTL&~(DCO2+DCO1+DCO0))+DCO1+DCO0; // DCO =
3
BCSCTL2 &= ~(SELS+DIVS_3); // SCLK = DCO/1 ~280kHz
FCTL2 = FWKEY + FSSEL_2; // FCLK = SCLK/1
UTCTL0 = SSEL0; // UCLK = ACLK
URCTL0 = 0x00 ; // receieve all chars, not just address chars
UCTL0 = CHAR; // enable UART0, 8-bit chars
UBR10 = 0x00;
UBR00 = 0x0D; // 32768/2400 = 13.65
UMCTL0 = 0x6B; // Modulation (compensate for 0.65)
P3OUT &= ~LIN_SEL; // put lin chip to sleep
P3SEL &= ~LIN_TXD; // P3.4 port function
P3DIR |= LIN_TXD; // P3.4 output direction
P3OUT |= LIN_TXD; // P3.4 high (signal normal slope mode)
P3OUT |= LIN_SEL; // select lin chip
ME1 |= UTXE0 + URXE0; // enable USART0 TX/RX modules
IE1 &= ~(UTXIE0+URXIE0); // disable USART0 TX/RX interrupts
P3SEL |= 0x30; // P3.4,5 = module function (USART0 TXD/RXD)
i = (unsigned int) &fieldprog_sizer - (unsigned int) &fieldprog; //
length
of fieldprog() function
fn_flash = (void *) &fieldprog; // address of fieldprog() function in flash
fn_ram = (void *) 0x200; // ram address to copy fieldprog() into
for (;i>0;--i)
*fn_ram++ = *fn_flash++; // copy code from flash to ram
fieldinit_in_ram = (void*) 0x200; // point at new function location
(*fieldinit_in_ram)(); // call the function in ram
}
// fieldprog() must be position independent to allow it to be copied to and
run from RAM
// To this end all function calls have been unrolled to form a single
function, since
// the MSP430 does not support pc-relative subroutine calls (like BSR in the
HC11).
// Also, all variables used must be of type register or auto (allocated on
stack frame).
// INTEL HEX RECORD FORMAT
// :10E000007B78300030380020007D7B78310030385C
// || | | | |
// || | | data checksum
// || | record type (00a 01=eof)
// || start address
// |number of data bytes in this record
// intel hex record identifier
void fieldprog(void)
{
auto char value[24] = {0,1,2,3,4,5,6,7,8,9, 0,0,0,0,0,0,0,
10,11,12,13,14,15,0};
auto char inchar, *rxptr, rxbuf[100]; // maximum supported record length
including end-of-line characters
auto char *address, data[50];
auto char i, numdata, rectype, checksum;
while(1) {
while ((IFG1 & URXIFG0) == 0); // wait for new character
inchar=RXBUF0; // get new char (clears flag)
if (rxptr >= rxbuf + 99) // prevent buffer overrun
rxptr = rxbuf + 98;
if (inchar == ':') { // start of new ihex record
rxptr = rxbuf; // ..reset pointer
continue; // ..and get next character
}
if (inchar>='0' && inchar<='9' ||
inchar>='A' && inchar<='F') { // part of
ihex record
*rxptr++ = inchar; // ..add to buffer
continue; // ..and get next character
}
if (inchar == 0x0d) { // end of ihex record -> program it into
flash
numdata = (value[rxbuf[0]-'0']<<4) +
value[rxbuf[1]-'0']; // number of
data bytes in this record :NN....
address = (char*)((value[rxbuf[2]-'0']<<12) +
(value[rxbuf[3]-'0']<<8) +
(value[rxbuf[4]-'0']<<4) + value[rxbuf[5]-'0']);
rectype = (value[rxbuf[6]-'0']<<4) +
value[rxbuf[7]-'0']; // record type
:nnaaaaRR....
checksum = numdata; // checksum calculation
for (i=0; i<numdata+2+1+1; i++) // (+2+1+1 =
+addr,rectyp,chksum)
numdata += (value[rxbuf[8+2*i]-'0']<<4) +
value[rxbuf[9+2*i]-'0'];
if (!checksum) { // if bad checksum
while ((IFG1 & UTXIFG0) == 0); // wait transmit buffer empty
TXBUF0 = 'X'; // handshake 'X' = checksum error
continue; // get next character (new record)
}
for (i=0; i<numdata; i++) // copy ascii hex values into data[] as
binary
data[i] = (value[rxbuf[8+2*i]-'0']<<4) +
value[rxbuf[9+2*i]-'0'];
if (rectype == 0x00) { // 0x00 = data record
for (i=0; i<numdata; i++) {
if (((unsigned int)address & 0x1ff) == 0) { // if start of new flash
segment -> erase this segment
while (FCTL3 & BUSY); // wait for flash memory not busy (not
needed with this code in same flash module)
FCTL1 = FWKEY + ERASE; // set erase bit
FCTL3 = FWKEY; // clear lock bit
*address = 0; // dummy write to erase flash segment
FCTL1 = FWKEY; // clear erase bit
FCTL3 = FWKEY + LOCK; // lock flash from accidental writes
}
while (FCTL3 & BUSY); // wait for flash memory not busy (not
needed with this code in same flash module)
FCTL1 = FWKEY + WRT; // set WRT bit for write operation
FCTL3 = FWKEY; // clear lock bit
*address++ = data[i]; // write data to address
FCTL1 = FWKEY; // clear WRT bit
FCTL3 = FWKEY + LOCK; // lock flash from accidental writes
}
}
else if (rectype == 0x01) // 0x01 = end of data record
WDTCTL = ~WDTPW; // kick watchdog with bad password -> reset
while ((IFG1 & UTXIFG0) == 0); // wait transmit buffer empty
TXBUF0 = '#'; // handshake '#' = packet programmed
okay
}
}
}
void fieldprog_sizer(void){} // address to obtain size of fieldprog()
function for teleport to ram
Reply by tagrace_99●July 9, 20032003-07-09
Thanks for the replys...
The code put in RAM is written in Assembler and is fully relocatable.
In fact I can load it into any FLASH space without changes and it
will run perfectly. It just won't run out of RAM.
How do I get the code into the RAM was asked.
This project has a USB port. The USB code has a 200 byte buffer which
is used to transfer data back and forth to the outside world (a PC).
The RAM code is around 140 bytes (this includes other functions
besides the erase and program of flash). The RAM code is loaded into
the BUFFER via a USB transfer (I have proven it is there intact and
in it's entirity). A command is then sent to the unit via the USB
which causes a BR to the start address of the BUFFER.
I basically see two different results (debug tools are limited on the
live product).
1. The unit will reboot which I belive is being caused by a PUC. This
is probably being generated by an ACCESS VIOLATION of the flash.
2. The unit is in an endless loop as if it was waiting for the BUSY
to reset.
If I load the code into FLASH space, I can initiate the code using
the USB BRANCH command so I know that is working. (I also use the USB
branch command for other functions in this unit of which thousands
have been shipped)
Here is somthing interesting...
If I don't wait for the BUSY to be clear, I will get at least the
first segment of FLASH erased. The code crashes at some point but it
must be a clue.
Yesterday I added a hook that allowed me to measure the MCLK
frequency on Port5.4. The freq was 714kHz. In the FCTL2 I set the
source as MCLK and divide it by 2 which should be in the correct
ballpark for proper operation or is it? I've seen various freq specs
for flash programming.
Today I plan on adding some hooks to look at the ACCVIFG and KEYV
bits.
I can't sleep over this one. I'm thinking that there must be some
flash activitiy still happening, like an interupt service, that is
causing an access violation even though I have a DINT in the top of
the code and I hold the Watch Dog.
Sure am willing to hear anyones ideas on this.
Thanks
Ted
--- In msp430@msp4..., "tagrace_99" <ted@t...> wrote:
> I have a situation where I need to erase and
program flash from
code
> placed into ram.
>
> I can not use the pushed on stack code method shown in various app
> notes.
>
> I have writen a routine that works perfectly if placed in flash but
> will not run out of ram.
>
> I am testing the busy just like in the app note. I can not even get
> the flash to erase reliably (It did erase for me a few times)
>
> Here is the initial code up to the erase:
>
> DINT ;DISABLE INTERUPTS
> CLR.B &0 ;CLEAR INTERUPTS
> MOV #5A80,&288 ;SHUT DOWN WATCHDOG
> MOV #0,R13 ;SETUP LOOP COUNTER TO ERASE 10
SEGMENTS
> ERSLP: CMP #10,R13
> JGE WRTBYT ;JUMP TO WRITE BYTE ROUTINE WHEN DONE
>
> WAIT1: BIT #1,&12CH ;TEST THE BUSY FLAG IN FCTL3
> JNZ WAIT1 ;WAIT TILL NOT BUSY
>
> MOV R13,R12 ;CALCULATE SEGMENT ADDRESS OFFSET
> ADD.B R12,R12 ;BY MULTIPLYING 512 TIMES COUNTER
> SWPB R12 ;THEN ADDING IT T0 THE BASE ADD LATER
>
> MOV #0A500H,&12CH ;REMOVE THE LOCK
> MOV #0A502,&128H ;SET ERASE
> CLR.B #0D800H(R12) ;DUMMY WRITE AT BASE + OFFSET
>
> WAIT2: BIT #1,&12CH ;TEST THE BUSY FLAG IN FCTL3
> JNZ WAIT2
>
> MOV #0A510H,&12CH ;SET THE LOCK
> ADD #1,R13 ;INCREMENT THE LOOP COUNTER
> JMP ERSLP ;GO BACK TO DO NEXT SEGMENT
>
> WRTBYT: ; CODE NOW WRITES DATA TO FLASH IF I COULD GET THIS FAR.
>
> Like I said, this code works fine if run out of flash.
>
> Is it a speed problem? I have tried setting up a number of timing
> options to no avail.
>
> Does anyone know of a DCO clocked or a 32768 clocked senario that
> would work in the msp430f149?
>
> You help in this would be greatly appreciated.
>
> Ted Gregorius
> TAG Systems
Reply by Martijn Broens●July 10, 20032003-07-10
Hi kevin,
Thanks for the code snippet, this will help me on the way, i already had
written bootloader code for other devices but indead they are able of
handling jumps and calls etc, and this explaines why this code didn't
run on the msp, thanks.
One question though,
I've compiled the code and downloaded it to the F149, I could see that
the code is been fetched and stored at $200, but am I correct if I say
that after download and call upon $200 you're not able to set
breakpoints anymore??
Further:
"If it's of any help, here's some early code (with bugs included
free of
charge ;-). Be aware that there is no DCO stabilisation, error detection
etc. in this yet. But it did work in early tests."
Which bugs?? Do you have a bug report?
thanks,
Martijn
Signal Processing Engineer Seeking a DSP Engineer to tackle complex technical challenges. Requires expertise in DSP algorithms, EW, anti-jam, and datalink vulnerability. Qualifications: Bachelor's degree, Secret Clearance, and proficiency in waveform modulation, LPD waveforms, signal detection, MATLAB, algorithm development, RF, data links, and EW systems. The position is on-site in Huntsville, AL and can support candidates at 3+ or 10+ years of experience.