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.

Marginal Reads - Anybody?

Hi,


anybody ever used the marginal read feature of the MSP430s?

I'm struggling a little bit with definition of relocatable code (generated by the C compiler of course).

Idea is to do marginal reads in the "bootloader" and also during operation of our device (controlled by an MSP430).

Thanks for any starter!

Hardy

  • What does this have to do with relocatable code?
  • Marginal reads might be executed only from RAM. Which means code generation (or linking) has to take care, that the location where the code resides in flash is not necessarily the place where it will be executed.

    My current solution:

    Linker file:

    .text_copytoram : {} > FLASH_BOOT, run > RAM_LOW, align=2,
    LOAD_START(text_copytoram_ld_start),
    RUN_START(text_copytoram_rn_start),
    SIZE(text_copytoram_size)

    Code:

    #pragma CODE_SECTION( FlashMarginalCheck, ".text_copytoram" )
    void FlashMarginalCheck( void )
    {
    for (int i = 0; i < 5; ++i) {
    // some TestCode here
    }
    } // FlashMarginalCheck

    ...
    {
    extern const uint8_t text_copytoram_ld_start[];
    extern uint8_t text_copytoram_rn_start[];
    extern uint16_t text_copytoram_size;

    memcpy( text_copytoram_rn_start, text_copytoram_ld_start, _symval(&text_copytoram_size) );
    FlashMarginalCheck();
    }


    I think not really obvious. At least to me... other ideas or corrections are welcome!

    Hardy
  • Found this thread with an old example that seems to include an example project with detailed comments on getting code to run from RAM in CCS or IAR. It's pretty old (for older version of CCS/IAR) but I think the same method should basically still apply: e2e.ti.com/.../72156 The TI MSP compiler guide www.ti.com/.../slau132 and MSP assembly tools guide www.ti.com/.../slau131 especially section 3.1.1 Load and Run addresses, section 8.8 linker generated copy tables, section 3.5 Run-time relocation and section 8.5.5 Placing a section at different load and run addresses might help explain some of it. But I think the example would be a good starting point.

    Regards,
    Katie

  • Thanks Katie,

    I've found that thread too (BTW anybody else "disgusted" by the new (?) search function? I have really problems limiting the search to the MSP forum and also I'm a fan of opening browser tabs for interesting results. This "dynamic" solution prevents this... :-()

    It has been really a good starting point. Nevertheless I like my solution more, because it uses linker generated symbols for address/size.

    Hardy
  • With gcc, it is possible to do the copying fully automatically, by putting the function into the same section as initialized variables in SRAM. Isn't the same possible with CCS or IAR?

  • Yes, that is possible with CCS too. Nevertheless I prefer doing it "manually"!

    Another point which is neither tested nor I'm sure about it, but I guess with the UNION feature of the linker it should be possible to have one common RAM area for functions to be executed from RAM. Which makes memcpy() necessary.
  • It looks like IAR supports the __ramfunc keyword when declaring the function for this to be done automatically. (see IAR compiler guide under Help > C/C++ Compiler Guide)
    In CCS it does look like there is a GCC attribute you could use for it __attribute__(ramfunc), but I think you would need to use the GCC compiler in CCS for that. I'm not sure if there's an automated way for the TI C compiler or not - you may want to try searching/posting in the (DO NOT USE) TI C/C++ Compiler - Forum and ask there (make sure to mention you are using MSP430)- they may know if something like that exists that I have missed.

    Regards,
    Katie

  • Ah yes, any way to produce for testing purposes a marginally written flash cell?

    H.
  • Hi Hardy,

    Unfortunately I don't know any good way to reliably produce a marginally written cell. Basically any sort of spec violation while doing your flash writing/erasing (like dip of Vcc, too short of timing for the write/erase, etc) I think *could* theoretically cause something like that, but I think it's not a very easy thing to intentionally make happen in any reliable fashion. Which is good because you don't want it to be common to get marginal bits on your part of course ;-) But that might give you some ideas of things to try.
     
    -Katie

  • HardyGriech said:
     anybody ever used the marginal read feature of the MSP430s? ...

    Yes, I have done that many times many years ago. I wrote a short program that uses one marginal read mode to read the entire Flash and calculate a 32-bit CRC and then use the other marginal read mode to read the entire Flash and calculate a second 32-bit CRC the same way. I assumed that the Flash is healthy when those two CRC's match each other. Of course, I used the bootstrap loader to load that test code into RAM and ran that code in place.

    HardyGriech said:
    ... relocatable code (generated by the C compiler of course). ...

    Why do you want relocatable code? What do you mean by the C compiler? And why of course?

    I admit that you need to run some test code at some fixed location in RAM, but you do not need to relocatable code at all.

    I am aware of several different cross compilers, but none of them can be called the C compiler. Further more all of them are originally designed to generate code to be loaded in Flash and also run in place. This created a problem that you are facing. You need to copy the code in one place (in Flash) only to be copied again to another place (in RAM) to run. This do not need relocatable code. So, of course, this is a problem created by the earlier versions of these cross C compilers. And of course there are ways to work around it.

  • Katie Pier said:
    I don't know any good way to reliably produce a marginally written cell.

    Very true. When I did those tests years ago, I was using 2xx devices where the FCLK frequency is programmable. When I speed up the FCLK a lot for erase/write, I managed to generate marginal bits. This is no longer possible to do with 5xx/6xx devices.  

  • Ok OCY, I understand that my requirement "relocatable code" is a little bit over-the-top... what I actually wanted was, that the compiler/linker combo generates code for me which is running at a different place (RAM) than located in flash.

    The other point "marginal reads": interesting approach with this CRC32 (to be honest I like your approaches for many years). But: why don't you make something like:

    mrg0 = 0; mrg1 = 0;
    u_s = *p;
    mrg0 = 1; mrg1 = 0;
    u_0 = *p;
    mrg0 = 0; mrg1 = 1;
    u_1 = *p;
    if (u_s != u_0 || u_s != u_1) {
    // reprogram
    }

    Any performance penalty?

    Hardy
  • Perhaps one could erase/write flash from RAM. This could allow abortion thru EMEX of the flash programming cycle and thus lead to marginal cells!?

    H.

  • HardyGriech said:
    But: why don't you make something like:

    mrg0 = 0; mrg1 = 0;
    u_s = *p;
    mrg0 = 1; mrg1 = 0;
    u_0 = *p;
    mrg0 = 0; mrg1 = 1;
    u_1 = *p;
    if (u_s != u_0 || u_s != u_1) {
    // reprogram
    }

    Any performance penalty?

    The chip I used did not have hardware CRC. I calculated CRC just for fun. Your code is probably faster. 

  • my concern was a little bit more in the direction, that switching the MRG levels require some delay to settle...
  • After some testing (performance too), my final version looks like this:

    #pragma CODE_SECTION( FlashMarginalCheck, ".text_copytoram" )
    _Bool FlashMarginalCheck( uint8_t *addr, uint16_t size )
    /**
     * Do marginal reads on flash memory to detect marginally programmed cells (or cells losing charge).
     *
     * \param addr   address of the block. This must be the start address of a flash segment
     * \param size   size of the block.  This must be the full length of a single flash segment
     *
     * \note
     *    - code must be executed with MCLK <= 1MHZ
     *    - marginal reads only work from RAM
     *    - code checked even with optimization turned on
     */
    {
       volatile uint32_t *a = (uint32_t *)addr;
    
       SETUP_CLOCK_1MHZ();
       for (uint16_t n = 0;  n < size;  n += sizeof(*a), ++a) {
          uint32_t v0, v1, vs;
    
          FCTL4 = FWPW | LOCKINFO | MGR1;
          v1 = *a;
          FCTL4 = FWPW | LOCKINFO | MGR0;
          v0 = *a;
          FCTL4 = FWPW | LOCKINFO;
          vs = *a;
          if (v1 != vs  ||  v0 != vs) {
             SETUP_CLOCK_FAST();
             return 0;
          }
       }
       SETUP_CLOCK_FAST();
       return 1;
    }   // FlashMarginalCheck
    

    This is even faster than using 512bytes blocks and memcpy()/memcmp(). Hopefully this MGR feature works correctly...

    Hardy

  • HardyGriech said:
    Ah yes, any way to produce for testing purposes a marginally written flash cell?

    old_cow_yellow said:
    Katie Pier
    I don't know any good way to reliably produce a marginally written cell.

    Very true. When I did those tests years ago, I was using 2xx devices where the FCLK frequency is programmable. When I speed up the FCLK a lot for erase/write, I managed to generate marginal bits. This is no longer possible to do with 5xx/6xx devices.  

    There is smart (block) write mode for 5xx/6xx devices with writing speed more than doubled (block write, non smart mode). Some 5xx/6xx devices flashed by smart mode will not have verify error, but will have marginal read error. I have 2 of them.

**Attention** This is a public forum