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
Programming flash from ram code
Started by ●July 8, 2003
Reply by ●July 8, 20032003-07-08
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 ●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 ●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 ●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