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.

MSP430FR2422: VerifyMem_430Xv2() fails. PSA value read out over SBW interface is wrong.

Part Number: MSP430FR2422

Hi!

Using VerifyMem_430Xv2() fails. I did some digging with only one word in memory (FRAM or RAM addresses) to check.
It seems that the PSA value being read out is the same as if there is 0x3FFF in the memory.
This cannot be a coincidence because 0x3FFF is the same for vacant memory.

Does this mean the PSA engine is not able to internally access FRAM or RAM addresses?

Why is this?

The strange thing is that reads from and writes to RAM or FRAM is working.
Also I noticed that reading out the DeviceID gives 0x3FFF.

  • I think you post twice for the same issue. 

    Hi, 

    Could you share where to find VerifyMem_430Xv2() and PSA? I cannot find them in MSP430 Drivelib. 

    Thanks, 

    Lixin

  • I tested the code provided with slau320ai and also with slaa754.

    For slau320ai it's the Replicator430FR folder and it can be found in JTAGfunc430FR.c

    For slaa754 it's the SimpleLink Host for MSP430 subfolder SBW and it can be found in SBW430FR.c

    Both show the said behaviour.

    Interestingly the JTAG mailbox functions seem to work.
    Also reading from the memory directly via ReadMem_430xv2 gives the correct data.
    However, the PSA value returned is the same as if the data in memory were all 0x3FFF.
    I tested with user data FRAM @ 0x01800, with user prog FRAM @ 0x0E300 and with RAM @ 0x02000.

    It does not make much sense why some functions work and some do not.

  • What is the host MCU do you use for the application? 

  • Does the example application in slau320ai use this PSA feature?

    Nima

  • The host MCU I'm using is LPC 4330 from NXP.

  • Yes, it does. That's the whole point of my question.
    It's in the file JTAGFunc430FR.c at line 461:

    //----------------------------------------------------------------------------
    //! \brief This function compares the computed PSA (Pseudo Signature Analysis)
    //! value to the PSA value shifted out from the target device.
    //! It is used for very fast data block write or erasure verification.
    //! \param[in] unsigned long StartAddr (Start address of data block to be checked)
    //! \param[in] unsigned long Length (Number of words within data block)
    //! \param[in] word *DataArray (Pointer to array with the data, 0 for Erase Check)
    //! \return word (STATUS_OK if comparison was successful, STATUS_ERROR otherwise)
    word VerifyPSA_430Xv2(unsigned long StartAddr, unsigned long Length, unsigned short const *DataArray)
    {
        word TDOword;
        unsigned long i;
        const word POLY = 0x0805;             // Polynom value for PSA calculation
        word PSA_CRC = (word)(StartAddr-2);   // Start value for PSA calculation
    
        ExecutePOR_430Xv2();
        
        SetPC_430Xv2(StartAddr);
        
        SetTCLK();
        
        IR_Shift(IR_CNTRL_SIG_16BIT);
        DR_Shift16(0x0501);
    
        IR_Shift(IR_DATA_16BIT);
        DR_Shift16(PSA_CRC);
    
        IR_Shift(IR_DATA_PSA);   
        
        for (i = 0; i < Length; i++)
        {      
            // Calculate the PSA (Pseudo Signature Analysis) value
            if ((PSA_CRC & 0x8000) == 0x8000)
            {
                PSA_CRC ^= POLY;
                PSA_CRC <<= 1;
                PSA_CRC |= 0x0001;
            }
            else
            {
                PSA_CRC <<= 1;
            }
            // if pointer is 0 then use erase check mask, otherwise data
            &DataArray[0] == 0 ? (PSA_CRC ^= 0xFFFF) : (PSA_CRC ^= DataArray[i]);      
            
            ClrTCLK();
            
    #ifdef SPYBIWIRE_MODE
    
            TMSH_TDIH();
            TMSL_TDIH();
            TMSL_TDIH();
            TMSH_TDIH();
            TMSH_TDIH();
            TMSL_TDIH();
            
    #else
            // Clock through the PSA     
          
            ClrTCK();
         
            SetTMS();
            SetTCK();            // Select DR scan
            ClrTCK();
            ClrTMS();
            
            SetTCK();            // Capture DR
            ClrTCK();
           
            SetTCK();            // Shift DR
            ClrTCK();
             
            SetTMS();        
            SetTCK();          // Exit DR  
            ClrTCK();
            
             // Set JTAG FSM back into Run-Test/Idle
            SetTCK();
            ClrTMS();
            ClrTCK();
            SetTCK();          
            
    #endif        
            SetTCLK();    
        }
        
        IR_Shift(IR_SHIFT_OUT_PSA);
        TDOword = DR_Shift16(0x0000);     // Read out the PSA value
         
        ExecutePOR_430Xv2();
    
        return((TDOword == PSA_CRC) ? STATUS_OK : STATUS_ERROR);
    }
    

    And since the DUT is MSP430FR2422 the Spy-Bi-Wire interface is relevant. See the #ifdef for SBW and ignore the #else for the JTAG-part.

    It is used in those two functions:

    //----------------------------------------------------------------------------
    //! \brief This function performs an Erase Check over the given memory range
    //! \param[in] word StartAddr (Start address of memory to be checked)
    //! \param[in] word Length (Number of words to be checked)
    //! \return word (STATUS_OK if erase check was successful, STATUS_ERROR 
    //! otherwise)
    word EraseCheck_430Xv2(unsigned long StartAddr, unsigned long Length)
    {
        return (VerifyPSA_430Xv2(StartAddr, Length, 0));
    }
    
    //----------------------------------------------------------------------------
    //! \brief This function performs a Verification over the given memory range
    //! \param[in] word StartAddr (Start address of memory to be verified)
    //! \param[in] word Length (Number of words to be verified)
    //! \param[in] word *DataArray (Pointer to array with the data)
    //! \return word (STATUS_OK if verification was successful, STATUS_ERROR
    //! otherwise)
    word VerifyMem_430Xv2(unsigned long StartAddr, unsigned long Length, unsigned short const *DataArray)
    {
        return (VerifyPSA_430Xv2(StartAddr, Length, DataArray));
    }
    

    As you can see it is really used in the code. It's used for blank checking and for comparing data.

    And the blank checking is called in the main function of Replicator430FR.c at line 229:

        // Check if main memory is completely erased.
        if (!EraseCheck_430Xv2(mainStartAdress, mainLength/2))   
        { 
            ShowStatus(STATUS_ERROR, 2);
        }
     

  • How are you using this code on "LPC 4330 from NXP"? did you port it?

  • Yes, I ported the code into C++ to have better type control as the original code in C with all those #defines.

    Meanwhile I got my code working with the bare minimal. So I have EraseViaBootCode, that's good because it unlocks the device when the SBW interface is locked. Also reading and writing to user and programm FRAM is working. But I could not use ReadMemQuick, it gives false values. So I used the slower access via ReadMem.

    But the problems remain:
    - still no correct deviceID in GetDevice at the start.
    - ReadMemQuick does not work as advertised, has wrong data in the return.
    - EraseFRAM via the JTAG mailbox functions does not work, it seems the CPU does not run at all, so the code presented is irrelevant.

    The datasheets and the documentation of the examples codes does not help in this case. Nowhere is there any mention of these problems.

    I would have been happy with a hint that not all functions are allowed for the MSP430FR2422, but in the example code it does not look like it is deactivated for this DUT.

    Doesn't anyone have any idea what else I could test?

  • For MSP430FR2422, the 0x1800 is Information memory address. When writing this area, you need to enable the write by clear the SYSCFG0.DFWP bit. Please refer to the section 1.9.3 FRAM Write Protection in MSP430FR4xx and MSP430FR2xx Family User's Guide (Rev. I) and MSP430FR2522 Code Examples (Rev. C) for details. 

    For prog FRAM @ 0x0E300 writing, it also requests to enable the write by clear the SYSCFG0.PFWP bit. 

  • Sorry, your answer does not address my question in any way. It's not about writing to FRAM. As I wrote before: "reads from and writes to RAM or FRAM is working"

    The problem is with the provided example code from TI. In it there is this function VerifyMem_430Xv2() which uses the PSA engine of the chip to calculate a CRC value. This would be a very nice and fast way to check if all FRAM is programmed.

    But it does not work. FRAM VerifyMem_430Xv2() always returns the same value. I can read out the memory word by word and I can verify everything has been programmed correcly. But word by word accesses are slow.

    I found out that I can calculate the value returned by VerifyMem_430Xv2(). The value is the same as if all locations contained 0x3FFF. But according to the users guide 0x3FFF is an error value.

  • I am also not familiar with the library. Could you trace into the function and find the root cause?

  • The function VerifyPSA_430Xv2 seems okay to me. Only the returned value is wrong.
    But I did not dig any further. Maybe it has also something to do with the timing of the signals. See below.

    Meanwhile ReadMemQuick is working and reading back FRAM and calculating CRC takes 0.6 s which is fast enough for me now (compared to 5.7 s before using the slow ReadMem function.)

    Some notes on the example code from TI:

    It looks like it was pieced together by at least three different sources / programmers. There are three different definitions for the signals (clock and data) and three different usages for changing the levels of those signals. The difference is timing: One definition uses delays to ensure the time between pulses. The second uses NOPs which is dependend on the CPU on which it is running. And the third did not use any NOPs or delays at all. This mix of code is responsible for all of the mess I found while porting the code.

    My solution: Refactoring by removing unnecessary definitions. Now every change in the signal level takes place via one and the same definition with a subsequent delay of 300 ns (which for an MSP430 then corresponds to 5 NOPS at 18 MHz.)

    I ask myself, of course, why this could not have been properly coded at TI beforehand?

  • Thanks to make great progress on the code in your side. It seems only the return value is not correct. I will check expert if he can provide some suggestions.

  • Since you are porting code to another host MCU, we can do nothing about it. You can refer to our code and debug by yourself.

    Thanks,

    Lixin

**Attention** This is a public forum