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.

MSP430FR2355: Can't get NMI to trigger using the MSP430FR2355 LaunchPad board

Part Number: MSP430FR2355
Other Parts Discussed in Thread: MSP-FET

I'm trying to invoke the bootloader (BSL) via the falling edge of a 2 millisecond negative pulse applied on the RST~ pin.

The code reconfigures the RST~ pin as NMI. But then when I apply the RST~ pulse, the NMI interrupt handler does not run.

What is missing in the code that would prevent the NMI handler from running?

#include <msp430fr2355.h>

typedef void (*FuncPtr)(void);

void main(void) {
    WDTCTL = WDTPW | WDTHOLD;               // Stop watchdog timer
    PM5CTL0 &= ~LOCKLPM5;                   // Disable the GPIO power-on default high-impedance mode
                                            // to activate previously configured port settings
    P1DIR |= 0x03;                          // Set P1.0, P1.1 to output direction
    P1OUT  = 0x03;                          // Turn on the red LED
    P6DIR |= (1<<6);                        // Set P6.6 to output direction (green LED)
    P6OUT |= (1<<6);                        // Turn on the green LED

    // NMI interrupt triggers on falling edge of RST~/NMI pin
    SFRRPCR |= SYSNMIIES__FALLING;
    // Configure RST~/NMI pin as NMI
    SFRRPCR |= SYSNMI__NMI_L;       // RST~/NMI

    for(;;)
    {
        volatile unsigned int i;            // volatile to prevent optimization

        P1OUT ^= 0x01;                      // Toggle P1.0 using exclusive-OR
        P6OUT ^= (1<<6);                    // Toggle P6.6 using exclusive-OR

        i = 100000;                         // SW Delay

        do
        {
            i--;
        } while(i != 0);
    }
}


/*****************************************************************************
 Function:      NMI interrupt service routine

 Description:

 Dependency:    None

 *****************************************************************************/
#pragma vector=UNMI_VECTOR
__interrupt void UNMI_ISR(void)
{
    volatile unsigned int i;

    // Clear all pending user NMI flags
    SYSUNIV = 0;

    // Enable FRAM program memory writing
    SYSCFG0 &= ~PFWP_0;

    // Disable global interrupts
    __bic_SR_register(GIE);

    // Disable NMI interrupt
    SFRIE1 &= ~NMIIE__ENABLE;

    P1OUT |= 0x01;      // Turn on the red LED
    P6OUT &= !(1<<6);   // Turn off the green LED
    for(i=10000; i!=0; i--);    // Delay

    P1OUT &= !0x01;     // Turn off the red LED
    P6OUT |= (1<<6);    // Turn on the green LED
    for(i=100000; i!=0; i--);   // Delay

    // Invoke the BSL bootloader (never returns)
    // Setting the program counter to the memory location 0x1000 starts the BSL.
    // The stack is always reset, and RAM is cleared.
    // It should be noted that the GIE bit is not disabled, so this should be done by the calling
    // application if interrupts are not desired and appropriately returned from "Return to BSL" if they are used.
    // Because the stack is reset, the BSL warm start entry point is called as a C function.
    FuncPtr fpBsl=(FuncPtr)0x1000;
    fpBsl();
}

 

//***************************************************************************************//  MSP430 Blink the LED Demo - Software Toggle P1.0////  Description; Toggle P1.0 by xor'ing P1.0 inside of a software loop.//  ACLK = n/a, MCLK = SMCLK = default DCO////                MSP430x5xx//             -----------------//         /|\|              XIN|-//          | |                 |//          --|RST          XOUT|-//            |                 |//            |             P1.0|-->LED////  Texas Instruments, Inc//  July 2013//***************************************************************************************
#include <msp430fr2355.h>
typedef void (*FuncPtr)(void);
void main(void) {    WDTCTL = WDTPW | WDTHOLD;               // Stop watchdog timer    PM5CTL0 &= ~LOCKLPM5;                   // Disable the GPIO power-on default high-impedance mode                                            // to activate previously configured port settings    P1DIR |= 0x03;                          // Set P1.0, P1.1 to output direction    P1OUT  = 0x03;                          // Turn on the red LED    P6DIR |= (1<<6);                        // Set P6.6 to output direction (green LED)    P6OUT |= (1<<6);                        // Turn on the green LED
    // NMI interrupt triggers on falling edge of RST~/NMI pin    SFRRPCR |= SYSNMIIES__FALLING;    // Configure RST~/NMI pin as NMI    SFRRPCR |= SYSNMI__NMI_L;       // RST~/NMI
    for(;;)    {        volatile unsigned int i;            // volatile to prevent optimization
        P1OUT ^= 0x01;                      // Toggle P1.0 using exclusive-OR        P6OUT ^= (1<<6);                    // Toggle P6.6 using exclusive-OR
        i = 100000;                         // SW Delay
        do        {            i--;        } while(i != 0);    }}

/***************************************************************************** Function:      NMI interrupt service routine
 Description:
 Dependency:    None
 *****************************************************************************/#pragma vector=UNMI_VECTOR__interrupt void UNMI_ISR(void){    volatile unsigned int i;
    // Clear all pending user NMI flags    SYSUNIV = 0;
    // Enable FRAM program memory writing    SYSCFG0 &= ~PFWP_0;
    // Disable global interrupts    __bic_SR_register(GIE);
    // Disable NMI interrupt    SFRIE1 &= ~NMIIE__ENABLE;
    P1OUT |= 0x01;      // Turn on the red LED    P6OUT &= !(1<<6);   // Turn off the green LED    for(i=10000; i!=0; i--);    // Delay
    P1OUT &= !0x01;     // Turn off the red LED    P6OUT |= (1<<6);    // Turn on the green LED    for(i=100000; i!=0; i--);   // Delay
    // Invoke the BSL bootloader (never returns)    // Setting the program counter to the memory location 0x1000 starts the BSL.    // The stack is always reset, and RAM is cleared.    // It should be noted that the GIE bit is not disabled, so this should be done by the calling    // application if interrupts are not desired and appropriately returned from "Return to BSL" if they are used.    // Because the stack is reset, the BSL warm start entry point is called as a C function.    FuncPtr fpBsl=(FuncPtr)0x1000;    fpBsl();}

  • Hi MWagner,

    I don't see where you enable the NMI interrupt  (SFRIE1.NMIIE) in your code?

  • Enabling the NMI interrupt is the missing piece. I can now successfully enter the BSL via the NMI interrupt handler.

    Thanks for the support!

  • Dennis and TI Friends and Family,

    Indeed proper enabling of the NMI interrupt was one of the missing pieces.  Thank you!

    Now on to the next issue ---

    Section 3.3.3 of slau550v MSP430™ FRAM Devices Bootloader (BSL) states the following about a blank MSP430FR2355:

     

    Blank Device Detection

    The boot code on the FR26xx, FR25xx, FR24xx, and FR23xx MCUs supports blank device detection to

    avoid the BSL entry sequence. This saves time and also eliminates the need for two additional wires

    (TEST, RST) for the BSL invocation sequence. The BSL entry sequence can be bypassed when the blank

    detection is enabled. The device jumps directly to the BSL and bypasses the entry sequence only when

    the reset vector has a value of 0xFFFF.

     

    Customer can successfully program a virgin device using the MSP-FET and Code Composer Studio.

    However, when they attempt to program a virgin device via I2C commands, programming fails.

     

    Their programming firmware pulses the RST~ signal low, which should cause the MSP430 to enter BSL mode.

    Then the firmware waits for 100 milliseconds, and then sends the default password (32 0xFFs) to the device over I2C.

    But the MSP430 does not acknowledge the RX_PASSWORD command sent down to unlock it for programming.

     

    This programming failure only happens when attempting to program a virgin MSP430 device over I2C.

    If they program a virgin part via the MSP-FET, then do a mass erase on the part, they can successfully reprogram the device over I2C using their programming firmware.

     

    What would be the difference between the contents of a virgin device and one that has been programmed, then mass erased?

    What would cause a virgin device to not enter BSL mode?

     

    Here is the user programming firmware for writing the password to the MSP430 (based on the slaa760 programming sample code):

    The failure occurs when sending the RX_PASSWORD command in the m_I2c.DevWriteN() call below. It returns with an I2C_NO_ACK error code.

     

    /**************************************************************************

    Function:          WritePasswordDefault()

     

    Description:       Write The Default Password (all 0xFF)

                        MSP430 FRAM devices bootloader documentation:

                        The BSL core receives the password contained in the packet

                        and unlocks the BSL protected commands if the password

                        matches the top 16 words in the BSL interrupt vector table

                        (located between addresses 0xFFE0 and 0xFFFF).

                        When an incorrect password is given, a mass erase is initiated.

                        This means all code FRAM is erased, but not Information Memory.

                        When a mass erase is performed, two conditions must be checked: the

                        password is always 0xFF for all bytes,

                        this is commonly used to gain access to an empty device or to

                        load a new application to a locked device without password.

     

                        

     Parameters:        none

                       

     Returns:           true - success

                        false - failed to write password

    **************************************************************************/

    bool Msp430Programmer::WritePasswordDefault()

    {

                uint8 password[PASSWORD_LENGTH] = {0};

                uint16 loopIndex = 0;

     

                MSP430_PROGRAMMER_DEBUGLOG_VERBOSE("WritePasswordDefault");

     

                for (loopIndex = 0; loopIndex < PASSWORD_LENGTH; loopIndex++)

                {

                            password[loopIndex] = 0xFF;

                }

     

                return WritePassword(password, PASSWORD_LENGTH);

    }

     

    /**************************************************************************

    Function:          WritePassword()

     

    Description:       Write the BSL password (to gain access to locked BSL registers)

                        

     Parameters:        password : pointer to the password string

                        passwordSize: number of bytes in the password

                       

     Returns:           true - success

                        false - failed to write password

    **************************************************************************/

    bool Msp430Programmer::WritePassword(uint8* password, uint16 passwordSize)

    {

                uint16 checksum = 0;

        bool status = FAIL;

        bool retVal = false;

     

                MSP430_PROGRAMMER_DEBUGLOG_VERBOSE("WritePassword (passwordSize)", passwordSize);

     

                if (passwordSize != PASSWORD_LENGTH)

                {

                MSP430_PROGRAMMER_DEBUGLOG_STD("Password length is incorrect (passwordSize)", passwordSize);

                            return false;

                }

     

        // RX_PASSWORD command header

                sendBuffer[0] = (uint8)(HEADER);

                sendBuffer[1] = RX_PASSWORD_NL;

                sendBuffer[2] = RX_PASSWORD_NH;

                sendBuffer[3] = RX_PASSWORD;

     

                // Copy the password to the command buffer

                memcpy(&sendBuffer[4], password, PASSWORD_LENGTH);

     

                // Add checksum

                checksum = CalculateChecksum(&sendBuffer[3], (uint16)(PASSWORD_LENGTH + 1));

                sendBuffer[PASSWORD_LENGTH + 4] = GetCKL(checksum);

                sendBuffer[PASSWORD_LENGTH + 5] = GetCKH(checksum);

     

        // Send the command to the MSP430

        status = m_I2c.DevWriteN(I2C_TARGETID_ELEVATOR, PASSWORD_LENGTH + 6, sendBuffer);

        if (status == PASS)

        {

            // Add 1-2 millisecond delay between MSP430 I2C read and write

            MsDelay(2);

            // Command successfully sent to MSP430

            // Read the command response from the MSP430

            status = m_I2c.DevReadN(I2C_TARGETID_ELEVATOR, 8, receiveBuffer);

            if (status == PASS)

            {

                // Response successfully read from MSP430

                // Validate the response

                        MsDelay(5);

     

                // Validate the response

                        if ((receiveBuffer[0] == ACK)

                                    &&(receiveBuffer[1] == HEADER)

                                    &&(receiveBuffer[2] == RX_PASSWORD_RESP_NL)

                                    &&(receiveBuffer[3] == RX_PASSWORD_RESP_NH)

                                    &&(receiveBuffer[4] == RX_PASSWORD_RESP_CMD)

                                    &&(receiveBuffer[5] == 0x00))

                        {

                            MSP430_PROGRAMMER_DEBUGLOG_STD("Correct RX_PASSWORD received");

                                    return true;

                        }

                else

                {

                            MSP430_PROGRAMMER_DEBUGLOG_STD("Incorrect RX_PASSWORD: erasing PPC pgm (hdr, CMD/MSG/CKL/CKH)",

                                            ((receiveBuffer[0] << 24) |

                                             (receiveBuffer[1] << 16) |

                                             (receiveBuffer[2] << 8)  |

                                              receiveBuffer[3]

                                            ),

                                            ((receiveBuffer[4] << 24) |

                                             (receiveBuffer[5] << 16) |

                                             (receiveBuffer[6] << 8)  |

                                              receiveBuffer[7]

                                            ));

                    retVal = false;

                }

            }

            else

            {

                // Failure to read response

                MSP430_PROGRAMMER_DEBUGLOG_STD("WritePassword failed reading response");

                retVal = false;

            }

        }

        else

        {

            // Failure to write command

            MSP430_PROGRAMMER_DEBUGLOG_STD("WritePassword failed writing command");

            retVal = false;

        }

     

                return retVal;

    }

     

     Now your input or comments are indeed welcomed!

    TY,
    CY

  • Team,

    They have determined that the root cause of the problem is an unprogrammed CPLD that is holding down the TEST and RST~ pins on the MSP430 SPY-BI-WIRE interface.  If those CPLD connections are removed, they can now successfully erase and program the MSP430 using the I2C interface regardless of whether the part is blank or programmed.

    Regards,

    CY

**Attention** This is a public forum