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.

Weird issue debugging FRAM part (Trouble Halting Target CPU: Internal error)

Other Parts Discussed in Thread: MSP-TS430RGZ48C, MSP430FR5969, MSP430FR5735

Hi,

I am trying to run a simple demo app writing to the FRAM on a MSP430FR5969. I'm using Code Composer Studio 5.5.0.00077 (freshly downloaded this morning) and an MSP-FET430UIF (received from Digikey last Friday). The target board is a MSP-TS430RGZ48C "rev 1.2", with date code "39/2012" marked on the packaging it came in. I am debugging using Spy-Bi-Wire mode and power is supplied by the FET. The power rails are clean and show no obvious problems on a scope.

The first thing I did was run the msp430fr59xx_1 ("Blink LED") example. The very first debug session, CCS uploaded a new firmware to the FET, and after a subsequent plugcycling, reliably connects to the debugger, uploads the binary and suspends at main(). When run, the LED on the target board blinks as expected. So far so good.

However, when I run the msp430fr59xx_framwrite ("Long word writes to FRAM") example, the code gets uploaded, but the debugger does not halt at main(), at least according to the text on the screen (which reports "Running"). However, nothing appears to happen at the target board (it should blink the same LED while writing dummy data to FRAM). Attempting to pause or stop the "running" program results in the following error message:

MSP430: Trouble Halting Target CPU: Internal error

This behavior is repeatable. The blink example runs, halts and does everything it should; the FRAM demo doesn't seem to do anything at all (but the GUI reports "running").

Now, here's where it gets weird. If I copy-paste the FRAM-specific code from the FRAM demo into the blink demo, it starts to exhibit the same failure. So far, I've narrowed the behavior to the 2 lines commented out below. If I uncomment either of these lines, debugging fails (compilation proceeds OK and generates no errors/warnings in both cases).

The code size reported by CCS is as follows, respectively:

MSP430: Loading complete. Code Size - Text: 190 bytes Data: 52 bytes.
MSP430: Loading complete. Code Size - Text: 258 bytes Data: 70 bytes.

So I don't believe it is getting anywhere near the (16K?) code size restriction of the free CCS license.

Any ideas what is going on?

#include <msp430.h>

unsigned long *FRAM_write_ptr;
unsigned long data = 0;

#define FRAM_TEST_START 0xD000

void FRAMWrite(unsigned long data)
{

    *FRAM_write_ptr = data;
}

unsigned long FRAMRead(void)
{

    data = *FRAM_write_ptr;
    return data;
}

int main(void)
{
  WDTCTL = WDTPW | WDTHOLD;       // Stop WDT

  // Configure GPIO
  P1OUT &= ~0x01;                 // Clear P1.0 output latch for a defined power-on state
  P1DIR |= 0x01;                  // Set P1.0 to output direction

  PM5CTL0 &= ~LOCKLPM5;           // Disable the GPIO power-on default high-impedance mode
                                  // to activate previously configured port settings

  //FRAM_write_ptr = (unsigned long *)FRAM_TEST_START;
  //FRAMWrite(data);                    // write 1 long

  while(1)
  {
    P1OUT ^= BIT0;                // Toggle LED
    __delay_cycles(100000);
  }
}

  • What are the settings of MPU? Are you allowed to write to 0xD000-0xD003?

  • I don't think it is a permissions (MPU?) issue - the problem occurs whether the code actually writes to 0xD000 or not. In the test case above, merely having code that will (in the future) assign a value to the variable FRAM_write_ptr seems to trigger the problem. The value assigned there doesn't seem to matter, either.

    It also seems like that would be a run-time error, whereas the problem I am having occurs sooner. For example, if I add a loop before that assignment to blink the LED 200 times, that doesn't run either. But if I change that loop to an infinite loop, it works again.

    Needless to say, this exceeds my ability to continue hunting for the source of the problem myself. Either I am missing something very fundamental here, or something very weird is going on.

    Any suggestions?

  • Tim Gipson said:
    ... merely having code that will (in the future) assign a value to the variable FRAM_write_ptr seems to trigger the problem. ...

    That sounds like someone or something has a crystal ball to see into the future. It is very difficult for me to imaging that the hardware is doing that. CCS on the other hand, can do that with ease and I will not be surprised at all if the TI tool makers did so  (I do not have or use CCS.)

    If you can share the object code in either TI.TXT or Intel.hex format generated by CCS with such problem, I may be able to decipher what it is.

  • Same problem by my side, the firmware didn't halt on main when trying to debug can't manually halt the device or do single stepping.

    I've added the "int _system_pre_init(void)" function, this one is reached but goes in the wild on exit.

    Today it is;

    000000: D032 00F0 BIS.W #0x00f0,SR
    000004: 3FFF JMP (0x0004)

    CCS/FRAM drives me crazy.... 

  • Argail said:
    000000: D032 00F0 BIS.W #0x00f0,SR
    000004: 3FFF JMP (0x0004)

    The first instruction enters LPM4, and 0x3fff is a 'jump on place'
    This is the emergency fallback sequence in case someone returns from main.

    However, from the error descriptions above, I can imagine that there is  aproblem with the memory proteciton unit (or how it is programmed).

    The suspected crystal ball could be the fact that with a variable placed in FRAM, the memory protection unit needs to be programmed to allow R/W access to the area where the variable is placed (whether it is actually written to or not). With no variables in FRAM area, the memory proteciton unit is programmed differently.

  • The link files is modified to set all the FRAM as read/write, but there is no initialization of the FRAM register during the init.

  • @old_cow_yellow,

    Thanks for the offer to help! I've reduced the testcase to a minimum and attached the resulting .hex file along with the source and other potentially relevant files (.map, linker file).

    In retrospect, your idea of something funny going on with memory writeability (or the lack of it) is sounding more and more likely - if the default startup routine (initializing .idata, etc.) is tripping over a memory protection issue, that would send the CPU into lala land before main()... unfortunately, I'm new to the MSPs in general and especially the FR parts, and their linker files are likewise voodoo to me. So I can't say if there is an issue hiding in the example's link script.

    In the code attached, I tried fishing out the starting address of the 'fram_rw_start' section (hmm, same address as the 'fram_ro_start' section...) from the .map file and used that as the FRAM address to write. No change though. Although, since the mere act of assigning to the global variable FRAM_write_ptr (at runtime, in the future!) seems to trigger the issue, maybe that variable itself is being placed somewhere it shouldn't, and being optimized away (hiding the issue) if it is never assigned to?

    0434.msp430fr_test_case.zip

  • Thanks for the link, but I'm not sure what I'm supposed to be looking at there. It's an unanswered thread by someone else having a different (if not necessarily unrelated) problem with the same chip. They can read and write values (apparently), but the read results are incorrect. In my case, execution doesn't even get as far as main() if a certain global variable will (in the future) have a value assigned to it. Dr. Schrodinger would love this bug!

  • Tim Gipson said:
    In my case, execution doesn't even get as far as main() if a certain global variable will (in the future) have a value assigned to it.

    I haven't got a MSP430FR5969 to investigate, but it possible to single step through the start-code code (in assembler) to try and locate at what point the failure occurs.

    To get CCS to stop at the processor reset vector, rather than trying to run to main, under CCS Project Properties -> Debug -> Auto Run and Launch Options -> Auto Run Options ensure "On a program load or restart" and "On a reset" are not ticked. When downloading the program can you then single step through the start up code?

  • Tim,

    The object code you sent me contains a lot of things your source code did not intend to do. Were you using Grace? I am puzzled. I do not use CCS nor Grace. I cannot figure out why the object code doing those extra things.

    --OCY

  • @old_cow_yellow:

    Not using GRACE, at least that I know of. All I did was click on the FRAM example in the "TI Resource Explorer" tab that appears in CCS, which did a bit of hocus-pocus and created the example project in my workspace. It could be part of some CCS' background voodoo I'm not aware of, though.

    @Chester Gillion: Now we are getting somewhere!

    Single-stepping through the TI startup code, I can find the exact point the chip goes into lalaland. It's in a function apparently named TI_zero_init (possibly preceded by one or more underscores) in "copy_zero_init.c". Note, on my system this file appears to not actually exist, neither in the temporary dir CCS builds to, nor in the entirety of the 'ti' installation folder (including CCS, "grace", "xcdtools"), but there is disassembly for it (wtf?)

    In the dump below, the crash occurs at 00489c (CLR.B 0x0000(R13)).Upon hitting this opcode, the debugger stops responding and CCS generates the error message:

    MSP430: Can't Single Step Target Program: Could not single step device

    Does this make sense to anyone?

            __TI_zero_init:
    004870:   140A                PUSHM.A #1,R10
    004872:   531C                INC.W   R12
    004874:   630D                ADC.W   R13
    004876:   180F 5D4D           RPT #16   RLAX.A  R13
    00487a:   1800 DC4D           BISX.A  R12,R13
    00487e:   4D2C                MOV.W   @R13,R12
    004880:   4D1B 0002           MOV.W   0x0002(R13),R11
    004884:   930B                TST.W   R11
    004886:   2002                JNE     ($C$L1)
    004888:   930C                TST.W   R12
    00488a:   240F                JEQ     ($C$L2)
            $C$L1:
    00488c:   0ECA                MOVA    R14,R10
    00488e:   0FCD                MOVA    R15,R13
    004890:   531E                INC.W   R14
    004892:   630F                ADC.W   R15
    004894:   180F 5D4D           RPT #16   RLAX.A  R13
    004898:   1800 DA4D           BISX.A  R10,R13
    00489c:   43CD 0000           CLR.B   0x0000(R13)   <--- CRASH!
    0048a0:   831C                DEC.W   R12
    0048a2:   730B                SBC.W   R11
    0048a4:   23F3                JNE     ($C$L1)
    0048a6:   930C                TST.W   R12
    0048a8:   23F1                JNE     ($C$L1)
            $C$L2:
    0048aa:   160A                POPM.A  #1,R10
    0048ac:   0110                RETA    
     88       WDTCTL = WDTPW | WDTHOLD;       // Stop WDT
  • Tim, Two suggestions.

    (1) Before you start to single step the start-up code,  stop the WDT from counting down.

    (2) Before you step into 0x489C (where it crashes), take a note of the content of R13. I think it should have been 0x1C00 (points to RAM). If not, how did it get that value?

    --OCY

  • @old_yellow_cow,

    >> Before you start to single step the start-up code,  stop the WDT from counting down.

    How would I go about doing this? (Presuming I probably can't easily inject user code before the TI startup routine - is there a menu option / debugger argument available through CCS?)

    >> Before you step into 0x489C (where it crashes), take a note of the content of R13. I think it should have been 0x1C00 (points to RAM). If not, how did it get that value?


    R13 is indeed 0x1c00 just before the crash.

    In case it's helpful, here is the state of all the core registers just before crash:


    R PC 0x00000011 0x00489C
    R SP 0x00000011 0x0023E8
    R SR 0x0000000B 0x0002
    R R3 0x00000011 0x000000
    R R4 0x00000011 0x00FFFF
    R R5 0x00000011 0x00FFFF
    R R6 0x00000011 0x00FFFF
    R R7 0x00000011 0x00A55A
    R R8 0x00000011 0x004400
    R R9 0x00000011 0x004412
    R R10 0x00000011 0x001C00
    R R11 0x00000011 0x000000
    R R12 0x00000011 0x000002
    R R13 0x00000011 0x001C00
    R R14 0x00000011 0x001C01
    R R15 0x00000011 0x000000

  • Tim Gipson said:
    in "copy_zero_init.c". Note, on my system this file appears to not actually exist

    THis is normal. The linker fetches this code from a precompiled library in which the debug information about its source is still present, but whose sourcecode is not provided. This function is meant to clear (set to 0) all uninitialized (or initialized to 0) global variables.

    However, this code looks weird.
    It is inefficient and slow.

    If you put $c$L1 on 0x4886, you can replace the three instructions before $C$L2 with JMP $C$L1, saving 6 bytes.
    If you move the lines on 94894/94898 before 0488c, you can use R14 directly instead of R1, you don't need R10 at all and don't need to save and restore it.
    But the whole construct can be rewritten by joining R14+R15 into a 20 bit value R13 once, and increment R13 instead of R14/R15 (and rebuilding R13) in each (!) iteration.

    From what I can tell, the function is called with a long address pointer in R14/R15 and a pointer to a size value in R12/R13. R12/R13 are combined into a 20 bit value and the size of the area to clear is loaded from there into R11/R12. Then the area from R14/R15 to (R14/R15+R11/R12)  is (slowly) cleared.
    I have no idea why the size of the area is passed by reference and not by value. Maybe that's the problem?

    I'd have done the address joining by pushing the two words to stack (pushm #2, R13) and pop them as address word (popm #1, R13). Results in 4 bytes, 8 cycles (since the funciton is called and returns, the stack is already initialized). The posted code, however, requires 12 bytes and 21 cycles and clobbers a register. And worst of all, it calculates the address over and over again instead of just calculating it once and then incrementing it. Same for the count, it can't be >20bit anyway, so why not using DECX.A on a 20 bit value? Slighly faster (3 cycles/256 bytes) and smaller (6 instead of 10 bytes) - since the count is already loaded from memory, the converison is free (if it were passed by value, it wouldn't make a difference in code size)

    No wonder the watchdog barks even on a few bytes.

    Bah!

  • Tim Gipson said:

    @old_yellow_cow,

    >> Before you start to single step the start-up code,  stop the WDT from counting down.

    How would I go about doing this?

    ...

    The Debugger probably has a "Register Window" where you can see the the WDTCTL register. And it probably let you change the contents by clicking at the current contents and enter a new hex value. Just enter the hex number that represent the WDT password bit-wise OR with the WDT Hold-bit.

    =========

    If R13=0x01C00, the instructions:

    00489c:   43CD 0000           CLR.B   0x0000(R13)
    0048a0:   831C                DEC.W   R12
    0048a2:   730B                SBC.W   R11
    should not cause a crash. The GIE bit in SR is not set, thus unexpected maskable interrupt cannot cause that either. The prime suspect is the WDT did it. Else CCS must have some other "features" that I do not know.
  • @Jens-Michael Gross - Good insights in the TI startup routine. This would be an interesting philosophical discussion for the TI employee responsible for maintaining the init functions, but I can't say it gets me any closer to getting my off-the-shelf JTAG box programming an off-the-shelf eval board with off-the-shelf example code working.

    This was actually supposed to be part of a quick-n-dirty demo for a large-ish customer tomorrow morning, but it's clear that isn't going to happen. (The demo is to update a persistent power-on counter from an intermittent, but very low-energy power source. Should have been doable in an entire week, no?) Guess I spend the rest of this afternoon bashing it together in PIC assembler with the onboard EEPROM... gah.

    @everyone else:

    As a final hurrah, I googled in some more circles and found I CAN inject user code pre-startup, via some further CCS voodoo, so as to rule out the WDT. I've now added the following to the project, and confirmed that it appears in the disassembly dump and gets executed. Absolutely no change to the crashing behavior though.

    int _system_pre_init(void)
    {
      // stop WDT
      WDTCTL = WDTPW + WDTHOLD;

      // Perform C/C++ global data initialization
      return 1;
    }

    If I get the PIC version done quick enough, I might try seeing if this return-value-to-bypass-the-TI-init actually works, and what problems that generates for me in place of the orignal one...

  • OK, curiosity (or rather, the thought of scrounging various parts bins for a spare PIC XLP) got the better of me and I tried fiddling with the _system_pre_init return value. Returning 0 does indeed entirely bypass the TI startup routine and thus the original crash. It now instead crashes when assigning the value to FRAM_write_ptr (0x0048c0 below). As before, using the example's hardcoded FRAM address of 0xD000 or a should-be-writeable address fished from the .map file makes no difference...

            main:
    0048ae:   40B2 5A80 015C      MOV.W   #0x5a80,&Watchdog_Timer_WDTCTL
    101       P1OUT &= ~0x01;                 // Clear P1.0 output latch for a defined power-on state
    0048b4:   C3D2 0202           BIC.B   #1,&Port_A_PAOUT
    102       P1DIR |= 0x01;                  // Set P1.0 to output direction
    0048b8:   D3D2 0204           BIS.B   #1,&Port_A_PADIR
    104       PM5CTL0 &= ~LOCKLPM5;           // Disable the GPIO power-on default high-impedance mode
    0048bc:   C392 0130           BIC.W   #1,&PMM__Power_Management_System_PM5CTL0
    121       FRAM_write_ptr = (unsigned long *)FRAM_TEST_START;
    0048c0:   40B2 D000 1C00      MOV.W   #0xd000,&FRAM_write_ptr  // <--- CRASH HERE INSTEAD!
    129         P1OUT ^= BIT0;                // Toggle LED
            $C$L1:
    0048c6:   E3D2 0202           XOR.B   #1,&Port_A_PAOUT
    130         __delay_cycles(100000);
    0048ca:   140D                PUSHM.A #1,R13
    0048cc:   403D 8232           MOV.W   #0x8232,R13
            $1_$5:
    0048d0:   831D                DEC.W   R13
    0048d2:   23FE                JNE     ($1_$5)
    0048d4:   160D                POPM.A  #1,R13
    127       while(1)
    0048d6:   3FF7                JMP     ($C$L1)
    0048d8:   4303                NOP 
  • 0048c0: 40B2 D000 1C00 MOV.W #0xd000,&FRAM_write_ptr

    Can can cause a crash if the MPU was set up to forbid writing to 0xD000. You can inspect the MPU settings in the register window.

  • The FRAM and MPU bits look OK to me. In particular, the FRAM power is enabled (although a datasheet note says accessing the FRAM will set that flag automatically), all the controllable MPU protections appear to be disabled, and all the segments are set R/W/X (the startup default).

    R FRAM_FRCTL0 0x0000000B 0x9608
    R FRAM_GCCTL0 0x0000000B 0x0006
    R FRAM_GCCTL1 0x0000000B 0x0000
    R MPU_MPUCTL0 0x0000000B 0x9600
    R MPU_MPUCTL1 0x0000000B 0x0000
    R MPU_MPUSEGB2 0x0000000B 0x0000
    R MPU_MPUSEGB1 0x0000000B 0x0000
    R MPU_MPUSAM 0x0000000B 0x7777
    R MPU_MPUIPC0 0x0000000B 0x0000
    R MPU_MPUIPSEGB2 0x0000000B 0x0000
    R MPU_MPUIPSEGB1 0x0000000B 0x0000
    
  • Hi Tim,

    This is rather interesting.  First, the code that you've pasted into your OP; Is this the code that you're using?  This looks fairly modified when compared to the original demo.  Something else that I noticed is that the code sizes you quoted are significantly smaller than what my system produces (Text: 684 Data:94).  I brought in the project, built,  and ran to main without issue.  I disabled "run to main" and went back and checked for the line that was causing you to crash.  That disassembly line corresponds to halfway through the a section generated by a while statement from the copy_zero_init.c runtime source.

    while(count--) WRITE8_ADV(outbuf, 0);

    and about 5 lines above this is a define for WRITE8_ADV

    #define WRITE8_ADV(x, c) (*x++ = (c))

    and all that specific line did was clear R13.  I can't quite explain why that would crash you.

    Onto why I posted; the source code that I'm looking at is a bit different than what you pasted and also, I don't see this issue.  I'm using the same target board (rev 1.2), CCS v5.5, MSP430 CGT 4.2.1, and the below source:

    //******************************************************************************
    //   MSP430FR59xx Demo - Long word writes to FRAM
    //
    //   Description: Use long word write to write to 512 byte blocks of FRAM.
    //   Toggle LED after every 100 writes.
    //   NOTE: Running this example for extended periods will impact the FRAM
    //   endurance.
    //   MCLK = SMCLK = default DCO
    //
    //           MSP430FR5969
    //         ---------------
    //     /|\|               |
    //      | |               |
    //      --|RST            |
    //        |               |
    //        |               |
    //        |          P1.0 |---> LED
    //
    //   Priya Thanigai
    //   Texas Instruments Inc.
    //   August 2012
    //   Built with IAR Embedded Workbench V5.40 & Code Composer Studio V5.2
    //******************************************************************************
    #include "msp430.h"
    
    void FRAMWrite(void);
    
    unsigned char count = 0;
    unsigned long *FRAM_write_ptr;
    unsigned long data;
    
    #define FRAM_TEST_START 0xD000
    
    int main(void)
    {
      WDTCTL = WDTPW | WDTHOLD;                 // Stop WDT
    
      // Configure GPIO
      P1OUT &= ~BIT0;                           // Clear P1.0 output latch for a defined power-on state
      P1DIR |= BIT0;                            // Set P1.0 to output direction
    
      // Disable the GPIO power-on default high-impedance mode to activate
      // previously configured port settings
      PM5CTL0 &= ~LOCKLPM5;
    
      // Initialize dummy data
      data = 0x00010001;
    
      while(1)
      {
        data++;
        FRAM_write_ptr = (unsigned long *)FRAM_TEST_START;
        FRAMWrite();                            // Endless loop
        count++;
        if (count > 100)
        {
          P1OUT ^= 0x01;                        // Toggle LED to show 512K bytes
          count = 0;                            // ..have been written
          data = 0x00010001;
        }
      }
    }
    
    void FRAMWrite(void)
    {
      unsigned int i=0;
    
      for ( i= 0; i<128; i++)
      {
        *FRAM_write_ptr++ = data;
      }
    }
    

    Just out of curiosity, what are the topside markings of your device inside the socket?  Were these the parts that came with the board or were they separately ordered samples?

  • @Michael - The issue occurs for me with the unmodified FRAM example, but I've tried to reduce it to a minimal testcase that repeatably triggers the bug. I'll attach both the unmodified example (should match your code) and the current testcase code. These are in the zipfile as msp430fr59xx_framwrite and msp430fr59xx_1, respectively.

    When I compile the unmodified example I get [Code Size - Text: 686 bytes Data: 94 bytes.] Close to what you get, but not identical.

    The socketed chip is marked:

    X430

    FR5969CS

    TI 281 D

    AJRK G4

    (the text "G4" is underscored)

    I'm using the 2 samples that came with the kit (both have identical markings). The issue manifests on both samples. In previous Googling I saw a note that certain versions of this kit shipped with dud chips, but the datecode on the kit (39/2012) doesn't match the ones reported to be affected.

    8546.code_workspace.zip

  • Tim Gipson said:
    This was actually supposed to be part of a quick-n-dirty demo [...] int _system_pre_init(void)

    If you return 0 in _system_pre_init, the startup code should skip the variable initialization.

    As long as your demo initializes all global variables manually (not assuming them zero or whatever you assigned in the variable definition) this shoul bring you past the crash point.

    Of course, this is a quick and dirty hack for a quick and dirty demo.

    Note that all global constants will still be initialized (or rather, they are stored in flash and are not copied/zeroed).

    Edit: I just noticed you did try this already. I didn't notice that the thread has already grown into a second page before answering.

    Tim Gipson said:
    Good insights in the TI startup routine. [...]  but I can't say it gets me any closer to getting my off-the-shelf JTAG box programming an off-the-shelf eval board with off-the-shelf example code working.

    Well knowing what the function does could have helped to interpret the debugger output of the register contents in this function.
    But it rather looks like the memory protection unit is somehow misprogrammed. So analysis of more of the startup code (not just the crashing function) is required.

    However, if R13 is indeed containing 0x1c00 (and not 0x11c00), then it points to ram and I don't see how a write accerss to ram could possibly cause a crash. Especially since the ram was already accessed previously (by the function call and push oeperations)

    However, if this is really an off-the-shelf untouched example code in a default project, then it of course should work off-the-shelf too.

  • Hi Tim,

    I've attached a modified source file.  Build and load with this.  If this changes nothing, the next step would be to order some samples and try newer silicon because this is an off-the-shelf demo, it should work.

    0068.modified_msp430fr59xx_framwrite.c
    /* --COPYRIGHT--,BSD_EX
     * Copyright (c) 2012, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     *******************************************************************************
     * 
     *                       MSP430 CODE EXAMPLE DISCLAIMER
     *
     * MSP430 code examples are self-contained low-level programs that typically
     * demonstrate a single peripheral function or device feature in a highly
     * concise manner. For this the code may rely on the device's power-on default
     * register values and settings such as the clock configuration and care must
     * be taken when combining code from several examples to avoid potential side
     * effects. Also see www.ti.com/grace for a GUI- and www.ti.com/msp430ware
     * for an API functional library-approach to peripheral configuration.
     *
     * --/COPYRIGHT--*/
    //******************************************************************************
    //   MSP430FR59xx Demo - Long word writes to FRAM
    //
    //   Description: Use long word write to write to 512 byte blocks of FRAM.
    //   Toggle LED after every 100 writes.
    //   NOTE: Running this example for extended periods will impact the FRAM
    //   endurance.
    //   MCLK = SMCLK = default DCO
    //
    //           MSP430FR5969
    //         ---------------
    //     /|\|               |
    //      | |               |
    //      --|RST            |
    //        |               |
    //        |               |
    //        |          P1.0 |---> LED
    //
    //   Priya Thanigai
    //   Texas Instruments Inc.
    //   August 2012
    //   Built with IAR Embedded Workbench V5.40 & Code Composer Studio V5.2
    //******************************************************************************
    #include "msp430.h"
    
    /*void FRAMWrite(void);
    
    unsigned char count = 0;
    unsigned long *FRAM_write_ptr;
    unsigned long data;*/
    
    #define FRAM_TEST_START 0xD000
    
    int main(void)
    {
      WDTCTL = WDTPW | WDTHOLD;                 // Stop WDT
    
      unsigned char count = 0;
      unsigned long *FRAM_write_ptr;
      unsigned long data;
    
      unsigned int i=0;
    
      // Configure GPIO
      P1OUT &= ~BIT0;                           // Clear P1.0 output latch for a defined power-on state
      P1DIR |= BIT0;                            // Set P1.0 to output direction
    
      // Disable the GPIO power-on default high-impedance mode to activate
      // previously configured port settings
      PM5CTL0 &= ~LOCKLPM5;
    
      // Initialize dummy data
      data = 0x00010001;
    
      while(1)
      {
        data++;
        FRAM_write_ptr = (unsigned long *)FRAM_TEST_START;
    //    FRAMWrite();                            // Endless loop
    
        for ( i= 0; i<128; i++)
        {
          *FRAM_write_ptr++ = data;
        }
    
        count++;
        if (count > 100)
        {
          P1OUT ^= 0x01;                        // Toggle LED to show 512K bytes
          count = 0;                            // ..have been written
          data = 0x00010001;
        }
      }
    }
    
    /*void FRAMWrite(void)
    {
      unsigned int i=0;
    
      for ( i= 0; i<128; i++)
      {
        *FRAM_write_ptr++ = data;
      }
    }*/
    

  • The story so far...

    1) Built the demo successfully with another chip. Crisis averted. Pretty ugly, but hopefully they will take our word that it will look far less fragile with more than a couple hours to bash it together and operate on even punier power sources with a new, FRAM-bearing chip.

    2) Deadbugged a MSP430FR5735 to the back of the eval board and ran its FRAM demo... it works! (After changing the write address specified in the demo code.) No crashes.

    3) Can probably rule out "write to unwriteable memory" as the cause of crashes. The '5735 FRAM demo specifies an address in non-existing memory (0xCA00); the '5735's FRAM starts at 0xE000. With the invalid address, write proceeds as normal, and reading back simply returns zeros - no crash.

    4) My employer is probably going to want to know why I burned so many hours on such a trivial demo. Any chance TI will reimburse them for their time I spent as an unofficial TI QA engineer?

    @Michael - I'm pretty swamped in other work, but maybe I can try this out in the next couple days. As I said, the customer demo is now working with another solution (bullet dodged), so any further chasing I do on this is on imaginary time.

**Attention** This is a public forum