This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Block Write from RAM, data from flash msp430f5419a

I am developing a program backup feature (in mspgcc) and I often need to transfer from backup to Program areas, etc.

I've been following the user guide's figure 7-12 flow diagram for block writing  to flash. However, the first long word copy reads 0x3fff3fff from data_addr (which is wrong), writes it to flash_addr but the  ACCVIFG get's triggered,disabling all the later memory writes.

I am running this from RAM as it is recommended in the manual.

Both interrupts and Watchdog are disabled.

Here are the data types used:

typedef uint8_t byte;
typedef uint16_t word;
typedef uint32_t long_word;

#if __MSP430X__
typedef uint20_t address;
#else
typedef uint16_t address;
#endif /*__MSP430X__*/

Here is my code for the operation (with the steps according to the mentioned flow):

i = IMAGE_APP_SIZE;

// 1. Test busy
while(FCTL3 & BUSY);

// 2. Clear Lock bit
FCTL3 = FWKEY;	    

while (i > 0){
    j = WRITE_BLOCK_SIZE; //128-bytes row (block)

// 3. Enable block write mode
    FCTL1 = FWKEY + BLKWRT + WRT;

    while (j > 0){ //go through a block

// 4. write 4 bytes from data_addr (in flash)
        flashWriteLongWord(flash_addr,
                           flashReadLongWord(data_addr));

// 5. Loop until WAIT is 1;
        while(!(FCTL3 & WAIT));

        flash_addr += long_word_size;
        data_addr += long_word_size;
        i -= long_word_size;
        j -= long_word_size;
// 6. Block Border check.
    }

// 7. Disable BLKWRT bit  (BLKWRT = 0);
    FCTL1 = FWKEY + WRT;

// 8. Loop until BUSY is 0;		
    while(FCTL3 & BUSY);

// 9. Another Block check.
}

//10. set WRT = 0, LOCK = 1 
FCTL1 = FWKEY;
FCTL3 = FWKEY + LOCK;

Here are the definitions of flashWriteLongWord and flashReadLongWord :

inline long_word flashReadLongWord(address flashAddr){
    union {
            long_word lw;
            word w[2];
    }result;

    uint16_t register sr;
    address register flash;

// save SR before disabling IRQ
    __asm__ __volatile__ ( "mov r2,%0":"=r"(sr):);				

    __asm__ __volatile__ ( "movx.a %1, %0":"=r"(flash):"m"(flashAddr) );
    __asm__ __volatile__ ( "movx.w 0(%1), %0":"=m"(result.w[0]):"r"(flash) );
    __asm__ __volatile__ ( "movx.w 2(%1), %0":"=m"(result.w[1]):"r"(flash) );

// restore previous SR and IRQ state
    __asm__ __volatile__ ( "mov %0,r2"::"r"(sr) );				

    return result.lw;
}

inline void flashWriteLongWord(address flashAddr, long_word l){

    union{
            word w[2];
            long_word lw;
    }lw;

    uint16_t register sr;
    address register flash; //address may be 16-32 bit depending the memory mode (small or large)

    lw.lw = l;

// save SR before disabling IRQ
    __asm__ __volatile__ ( "mov r2,%0":"=r"(sr):);				

    __asm__ __volatile__ ( "movx.a %1,%0":"=r"(flash):"m"(flashAddr) );
    __asm__ __volatile__ ( "movx.w %1, 0(%0)":"=r"(flash):"m"(lw.w[0]) );
    __asm__ __volatile__ ( "movx.w %1, 2(%0)":"=r"(flash):"m"(lw.w[1]) );

// restore previous SR and IRQ state
    __asm__ __volatile__ ( "mov %0,r2"::"r"(sr) );				
}

Is it because I am reading from flash while copying?

If so, where should I load to memory the 128-byte chunks? Between step 9 and 10?

Notice that the data_addr and flash_addr are from different banks.

  • Carlos Filipe Costa said:

    Is it because I am reading from flash while copying?

    Yes. I am using it (block write), with all data in RAM / registers, nothing from flash.

    http://forum.43oh.com/topic/2972-sbw-msp430f550x-based-programmer

    Carlos Filipe Costa said:

    If so, where should I load to memory the 128-byte chunks? Between step 9 and 10?

    Notice that the data_addr and flash_addr are from different banks.

    Well, in TI open source examples, there is only simple write or in 5xx family datasheet simple block write, so don't know if there is some bank isolation mechanism (during block write), or you must copy all data to RAM. Maybe block write is not right / best choice for your application. Of course, it is fastest for sure, and even more with smart mode enabled.

  • zrno soli said:
    don't know if there is some bank isolation mechanism (during block write),

    Bank isolation is only available for a bank erase.

  • That kinda sucks. The purpose of burst writing to me would be to speed up the writing of big chunks of data, that is, bigger data sizes than the ones that fit RAM (the performance difference usually is much more noticeable and useful in cases with many sequential writes). I do understand that these things are restricted by the hardware, but still, a fast block write targeted to small write sizes doesn't seem to be that useful, except perhaps, in optimization of critical parts of the code.

    Would the option of refilling a buffer between two block writes bring any sizable performance benefit?

  • You can calculate by yourself, but I guess that fast data copy from flash to RAM buffer between 2 blocks write can be fast (faster than non-block write).

    Well, block write working perfectly with my flasher where data are coming on-the-fly from SBW master device in parallel with flashing (no latency of any kind). Here you can see max practical block writing speed for 5xx devices that I have, reported by my flasher...

    D:\msp430>flash -p com21 -wt
    
    Get Device
    # JTID Fuse Device Core Hard Soft LotWafer DieX DieY
    0  91   OK   3881  1106  10   10  219CA446 1800 0F00
    1  91   OK   5435  0100  10   10  ADE98146 0A00 2100
    2  91   OK   3180  1104  12   12  013BB046 1200 1E00
    3  91   OK   3180  1104  12   12  013BB046 0D00 1E00
    4  91   OK   5435  0100  10   10  ADE98146 0400 2000
    5  91   OK   3180  1104  12   12  013BB046 2A00 2100
    6  91   OK   3080  1104  30   10  B15B9446 2000 1700
    7  91   OK   3081  2106  10   10  B7A50951 0A00 1100
    
    Write Test
    Smart  #0    #1    #2    #3    #4    #5    #6    #7
      0    93,8 100,6 102,0 102,2 102,5 103,3 105,4 106,4
      1   216,8 232,5 235,7 236,1 236,9 238,6 243,6 245,9
    
  • Carlos Filipe Costa said:
    The purpose of burst writing to me would be to speed up the writing of big chunks of data, that is, bigger data sizes than the ones that fit RAM

    You can’t eat the cake and keep it. It’s not that the normal write mode is just slowing things down for some reason, or to save power. No, it is slow because it has to stop the flash write process after each byte to allow you flash access between writes. The only thing that makes block write fast is that it does not constantly exit and enter the write process to allow you flash access in the meantime.

    However, you can combine both. There is no need to write a whole flash segment at once. Else it would be impossible to upload firmware in a reasonable time on devices with less than 1k ram.
    You can load the first 128 bytes into ram, enter block write mode (from ram code), write them, end block write mode, load the next 128 bytes in ram and so on. This is still significantly faster than normal write mode. Especially if you use the DMA controller for the copy process :)
    The only thing you can’t do is reading the data to write form a different flash location during block write.

  • well, I've set up a filling-the-buffer phase between each block, and proceeded to copy a long at each iteration, but to my dismay, after the first write, the ACCVIFG bit still get's triggered... I end up with only the first long written...

    my buffer is defined as:

    union{
        byte bIndex[WRITE_BLOCK_SIZE];
        word wIndex[WRITE_BLOCK_WORD_COUNT];
        long_word lwIndex[WRITE_BLOCK_LONG_COUNT];
    }flashBuffer;

    at the begining of the function run from RAM.

    this Is the code bit of the function (which was copied and runs in ram) :

    // Clear Lock bit
    FCTL3 = FWKEY;													
    
    
    while (i > 0){
    
        for(j = 0, k = 0; j < WRITE_BLOCK_SIZE; j+= long_word_size, k++ ){
            flashBuffer.lwIndex[k] = flashReadLongWord(data_addr + j );
        }
    
        k = 0;
    
    // Enable 128-byte block write mode
        FCTL1 = FWKEY + BLKWRT + WRT;								
    
        while (j > 0){
            *(long_word *)flash_addr = flashBuffer.lwIndex[k];
            while(!(FCTL3 & WAIT));
            flash_addr += long_word_size;
            data_addr += long_word_size;
            i -= long_word_size;
            j -= long_word_size;
            k++;
        }
    
    // Clear BLKWRT bit
        FCTL1 = FWKEY + WRT;
    
    // test busy									
        while(FCTL3 & BUSY);									
    }
    
    FCTL1 = FWKEY;
    FCTL3 = FWKEY + LOCK;

    According to the user guide, this would either be due to a flash read or a flash instruction fetch before the BUSY flag was released, but I see no part of that code that remotely does that. I've even checked the assembly...

    Any idea of what might be causing this?

     

    ,

  • Try to put FCTL3=FWKEY after k=0 inside while, and FCTL3=FWKEY+LOCK after BUSY test inside while. Just follow block write example from MSP430F5xx family datasheet (slau208).

  • Nope, it didn't work. I actually thought it wouldn't but decided to try either way. Since the error occurs inside the inner loop (only the first word is copied) I think the lock instruction has no influence in the error. _Besides, I am following the diagram for the block write in sla08n.

    this is very frustrating...

    Any more ideas?

  • With block write destination address must be aligned and it is not possible to write 128 bytes at once, if there are placed in 2 separate blocks. Also you can make simple testing without coping data to RAM (remove this part from program), use dummy data that are already there (in RAM).

  • well. I actually chose specific memory locations that were aligned to the 512-byte segments... I suppose the 128-byte rows are aligned to the segments. For the 5419a, the program memory starts at 0x5C00. my copy zone starts at 0x6C00 which is 0x1000 away, i.e. 8 segments away. I suppose it is aligned no? I'm also running the msp430 at a speed of 8MHZ... should I lower the clock for flash write operation?

  • No, problem is not in 8 MHz. My advice is to start with clean block write example from MSP430F5xx family datasheet, using dummy data from RAM, that are not changing after reset. Or instead dummy data, using block write function stored in RAM. When everything is working OK, made your modification, step by step.

  • I've figured it out. It seems that before each long word being written, the busy bit must be checked... I figured this from the first paragraph of 7.3.3 of slau208n. 

    "When a write or an erase operation is initiated from RAM while BUSY=1, theCPU may not write to any flash location. Otherwise, an access violation occurs, ACCVIFG is set, and the result is unpredictable. ACCVIFG is also set if a Flashwrite or erase access is attempted without any Flashwrite or erase mode selected first."

    Big bummer that the code example hadn't this. 

  • No, don't think that you need to test both BUSY/WAIT for each write. My block write from RAM is working OK with testing WAIT, not BUSY. Of course, if erase is done first, you must wait for BUSY before first write.

  • Well, in byte/word/dword write mode, BUSY needs to be checked, because each write is a complete flash cycle. So before starting the next, BUSY has to be checked when using byte/word/dword writ emode from RAM (from Flash, the CPU would be stopped anyway)
    In block write mode, wait is the only thing to wait for, and BUSY needs to be checked after ending block write.

    However, when crossing a block border (which is 128 bytes, or 64 bytes on older families, not 512!), BLKWRT needs to be cleared and BUSY checked, then BLKWRT set again before proceeding.

    So the maximum writes that can be done during one block write is 128 bytes or 32 dwords, as the sample code in the users guide shows too (and as usual, it is a bit ambiguous, as it does not show writing of more than 32 dwords)

**Attention** This is a public forum