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.

CCS/MSP430F5418A: Vacant Memory Interrupt occurs when executing instruction fetch from last 8 bytes of FLASH

Part Number: MSP430F5418A
Other Parts Discussed in Thread: MSP430F5437A, , MSP430WARE

Tool/software: Code Composer Studio

Hi,

I've recently upgraded CCS from 7.X up to 8.1.0 and enabled the vacant memory access interrupt for the first time. After doing so I came accross very regular and strange SYSNMI_VECTOR interrupts every time a function executed that did an instruction fetch from address 0x25BFF.

On each compilation and attempt to debug the issue it kept moving as the function placed at the end location changed. Many red herring and dead end paths taken to come to this conclusion.

An exert from my .cmd file now reads;

MEMORY
{
    SFR                     : origin = 0x0000, length = 0x0010
    PERIPHERALS_8BIT        : origin = 0x0010, length = 0x00F0
    PERIPHERALS_16BIT       : origin = 0x0100, length = 0x0100

    BSL0                    : origin = 0x1000, length = 0x0200
    BSL1                    : origin = 0x1200, length = 0x0200
    BSL2                    : origin = 0x1400, length = 0x0200
    BSL3                    : origin = 0x1600, length = 0x01F0
    /* This will nuke the BSL entirely and NOT let it startup.
     * Upon next erasure cycle of the BSL3 area this will be set
     * to 0xFFFF which is an acceptable value. it must be 0xFFFF
     * or 0x0000. If this is NOT the case, then the device becomes
     * inoperable. And that would be bad :)
     *
     * Side note; this also ensures that the BSL is never accidentially
     * entered.
     */
    BSLZ                    : origin = 0x17F0, length = 0x0010, fill = 0x0000

    INFOD                   : origin = 0x1800, length = 0x0080
    INFOC                   : origin = 0x1880, length = 0x0080
    INFOB                   : origin = 0x1900, length = 0x0080
    INFOA                   : origin = 0x1980, length = 0x0080
	//RAMZ					: origin = 0x1C00, length = 0x0100, fill=0xA0A0
    RAM                     : origin = 0x1C00, length = 0x4000
    FLASH                   : origin = 0x5C00, length = 0xA380 , fill = 0x3FFF
    FLASH2                  : origin = 0x10000,length = 0x15B80, fill = 0x3FFF
    //Keep these bytes empty. Had VMAI errors raised in last section
    FLASH3                  : origin = 0x25B80,length = 0x80   , fill = 0x3FFF
    ....

SECTIONS
{
    .TI.noinit  : {} > RAM                  /* For #pragma noinit                */
    .bss        : {} > RAM                  /* Global & static vars              */
    .data       : {} > RAM                  /* Global & static vars              */
    .cio        : {} > RAM                  /* C I/O Buffer                      */
    .dbg        : {} > RAM
    .sysmem     : {} > RAM                  /* Dynamic memory allocation area    */
    /******************************** MEMORY HOLE ********************************/
    .stack      : {} > RAM (HIGH)           /* Software system stack             */

#ifndef __LARGE_CODE_MODEL__
    .text       : {} > FLASH                /* Code                              */
#else
    .text       : {} >> FLASH2 | FLASH      /* Code                              */
#endif
    .text:_isr  : {} > FLASH                /* ISR Code space                    */
    .cinit      : {} > FLASH                /* Initialization tables             */
#ifndef __LARGE_DATA_MODEL__
    .const      : {} > FLASH                /* Constant data                     */
#else
    .const      : {} >> FLASH | FLASH2      /* Constant data                     */
#endif

    .pinit      : {} > FLASH                /* C++ Constructor tables            */
    .binit      : {} > FLASH                /* Boot-time Initialization tables   */
    .init_array : {} > FLASH                /* C++ Constructor tables            */
    .mspabi.exidx : {} > FLASH              /* C++ Constructor tables            */
    .mspabi.extab : {} > FLASH              /* C++ Constructor tables            */
#ifdef __TI_COMPILER_VERSION__
  #if __TI_COMPILER_VERSION__ >= 15009000
    #ifndef __LARGE_CODE_MODEL__
    .TI.ramfunc : {} load=FLASH, run=RAM, table(BINIT)
    #else
    .TI.ramfunc : {} load=FLASH | FLASH2, run=RAM, table(BINIT)
    #endif
  #endif
#endif

    .bsl0.noinit      : {} > BSL0, type=NOLOAD
    .bsl1.noinit      : {} > BSL1, type=NOLOAD
    .bsl2.noinit      : {} > BSL2, type=NOLOAD
    .bsl3.noinit      : {} > BSL3, type=NOLOAD

    /* Nerf the BSLZ zone leaving the BSL disabled and JTAG access
     * enabled for development/release 
    */
    .bslz             : {} > BSLZ, fill=0x0000

    .infoA     : {} > INFOA              /* MSP430 INFO FLASH Memory segments */
    .infoB     : {} > INFOB
    .infoC     : {} > INFOC
    .infoD     : {} > INFOD

I'm filling all unused flash with 0x3FFF to ensure a proper code jump in case of onerous execution. The function that was being placed into the very last few bytes were

Proof _outc is at end of address range;

0x025BE2 _outc
0x025BE2 9D9D 0002 0004 2C07 4D2E 0ECF 531F
0x025BF0 4F8D 0000 4CCE 0000
0x025BF8 $C$L6
0x025BF8 539D 0004 4C4C 0110

Use linker directive;

MEMORY
{
...
FLASH3                  : origin = 0x25B80,length = 0x80   , fill = 0x3FFF
...
}
SECTIONS { ... .VMI.endFlash : { --library=rts430x_lc_sd_eabi.lib<snprintf.c.obj>(.text:_outc) } > FLASH3 (HIGH) ... }


Set breakpoint after program address 0x25BEE to be able to step through the code during run-time.

execute this code on startup;

/* Enable the FLASH and Memory access interrupts
 */
SFR_clearInterrupt(SFR_VACANT_MEMORY_ACCESS_INTERRUPT |
		SFR_FLASH_CONTROLLER_ACCESS_VIOLATION_INTERRUPT);
SFR_enableInterrupt(SFR_VACANT_MEMORY_ACCESS_INTERRUPT |
		SFR_FLASH_CONTROLLER_ACCESS_VIOLATION_INTERRUPT);


Pre & Post interrupt core registers


If I run the same hex file on a MSP430F5437A I do not get the same interrupt. I assume this is because the next flash address of 0x25C00 is valid and some kind of pre-fetch operation is occurring without checking for flash boundary limits.

If any instruction fetch operation occurs in the last 0x08 bytes of FLASH then a VMA Interrupt occurs. (I've tested 0x10 to 0x01 buffer zone from end of flash)

This will fail; Less than 8 bytes

//Keep these bytes empty. Had VMAI errors raised in last section
FLASH3 : origin = 0x25B00,length = 0xFA , fill = 0x3FFF
FLASH4 : origin = 0x25BFA,length = 0x06 , fill = 0x3FFF

This is OK; Equal or greater than 8 bytes

//Keep these bytes empty. Had VMAI errors raised in last section
FLASH3 : origin = 0x25B00,length = 0xF8 , fill = 0x3FFF
FLASH4 : origin = 0x25BF8,length = 0x08 , fill = 0x3FFF

https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/166/lnk_5F00_msp430f5418a.7z

My working linker file for the MSP430F5418a project

This is my linker line for all my build options and inclusions.

"C:/ti/ccsv8/tools/compiler/ti-cgt-msp430_18.1.2.LTS/bin/cl430" -vmspx 
--data_model=small -O0 
--opt_for_speed=1 
--align_for_power 
--use_hw_mpy=F5 
--define=__MSP430F5418A__ 
--c99 
--float_operations_allowed=all 
--printf_support=full 
--gen_data_subsections=on 
--silicon_errata=CPU21 
--silicon_errata=CPU22 
--silicon_errata=CPU23 
--silicon_errata=CPU40 -z 
--heap_size=160 
--stack_size=2048 
--cinit_hold_wdt=on -i"C:/ti/ccsv8/ccs_base/msp430/include" 
-i"C:/ti/ccsv8/tools/compiler/ti-cgt-msp430_18.1.2.LTS/lib" 
-i"C:/ti/ccsv8/tools/compiler/ti-cgt-msp430_18.1.2.LTS/include" 
-i"C:/ti/ccsv8/ccs_base/msp430/lib/5xx_6xx_FRxx" 
-i"C:/ti/msp/MSP430Ware_3_80_04_05/iqmathlib/libraries/CCS/MPY32/5xx_6xx" 
--reread_libs 
--warn_sections 
--xml_link_info="MAT3_linkInfo.xml" 
--rom_model -o "MAT3.out" ## <obj list removed> ## "../lnk_msp430f5418a.cmd"  -llibc.a -llibmath.a -lIQmathLib.a -lIQmathLib_CCS_MPY32_5xx_6xx_CPUX_large_code_small_data.lib 




  • Hello Lucas,

    This seems strange here. From the looks of it, you seem to be using a custom linker file. Are you able to reproduce the error on the default linker file?
  • Hi,

    I originally had a custom linker file, then updated to the latest 1.205 from msp430ware while trying to nail down where I was going wrong. So yes I detected the problem with the default linker file before adding all the other guff.

    Attached is a clean project built with the driverlib source and with all interrupts "coded" with both a clean CMD file and a PROOF cmd file. The proof file just locates the _outc function at the end of the flash for the purpose of showing the chip fault.

    Build and run Debug with a 20MHz crystal attached to XT1 (ommit or modify this for your dev board. I dont have a msp430 launchpad board here to work with unfortunately)

    Then

    Build and run "Debug_Proof" and place a breakpoint at line 192 of main.c.. or just pause the debugger once its crashed :)

    https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/166/VMA_5F00_Erattum_5F00_Example.7z

    ti-format txt files are in the build directory too. 

  • Also I've been studying the erattum document again (www.ti.com/.../slaz280z.pdf) and it seem strange that a major fault is identifid and not implemented in the CMD file by default.

    FLASH35 FLASH Module
    Category Functional
    Function Flash read error may cause invalid memory access
    Description
    Flash memory accesses are always 32-bit wide and performed on 32-bit boundaries. A
    read error when accessing flash may corrupt the most significant bit (MSB) in a 32-bit
    access when programmed as a logic 0.
    When affected flash is idle, the read disturb may occur on the first flash access that
    follows any of the listed events:
    - On reset issued at RST input pin
    - On wakeup from low-power modes when accessing interrupt vector addresses
    located at addresses <0x8000
    - When moving program execution from unaffected to affected areas of flash
    - When accessing affected flash after execution from RAM
    Workaround
    See Flash Read Error and Susceptibility for MSP430F54xxA (SLAA470) for detailed
    background information and possible workaround(s).

    There should be a section defined between 0x8000 and 0xFF80 which all ISR functions MUST reside, and then other init blobs can use the remainder of the area. So split the flash section again to ensure all ISR address pointers are 0x8### like the erratum states.

    What are your thoughts on this ?

    I personally have had no end of random problems with this family of chips. very hard to track down, obscure issues which change on every compilation...
  • Hi Lucas,

    I think the FLASH35 has nothing to do with the behavior you seen and also it applies only on RevB to D.

    It also appears only if you have placed following code in the last addresses correct?

    0x025BE2 _outc

    0x025BE2 9D9D 0002 0004 2C07 4D2E 0ECF 531F

    0x025BF0 4F8D 0000 4CCE 0000

    0x025BF8 $C$L6

    0x025BF8 539D 0004 4C4C 0110

    Can you please send me the disassembly window so that I can see what code is executed there.
    Based on pipeline CPU it could be that depending on the code the VMA flag is triggered if you execute on the last address.

    For Example if you plase a jmp & (machine code 0x3FFF) at 0x25BFE it should also trigger the VMA because the CPU will read the next address which does not exist. This is quite normal so the best is you do not place code on the last words as you pointed out.
  • Here is the Disassembly window output

    _outc():
    025be2: 9D9D 0002 0004     CMP.W 0x0002(R13),0x0004(R13)
    025be8: 2C07               JHS (0x5bf8)
    102        *holder->out_end++ = c;
    025bea: 4D2E               MOV.W @R13,R14
    025bec: 0ECF               MOVA R14,R15
    025bee: 531F               INC.W R15
    025bf0: 4F8D 0000          MOV.W R15,0x0000(R13)
    025bf4: 4CCE 0000          MOV.B R12,0x0000(R14)
    104        holder->written++;
            $C$L6:
    025bf8: 539D 0004          INC.W 0x0004(R13)
    106        return c;
    025bfc: 4C4C               MOV.B R12,R12
    025bfe: 0110               RETA 

    I had tried my main code with placing this routine at the top, like above, and padded from the last flash address by up to 8 bytes, in 1 byte increments. The issue stopped once there was 8 bytes of padding to the end of the flash array. I also had fill=0x3FFFF so that the next address locations had that invalid memory jump location as is suggested in some wiki..

    Would you like any other outputs?

    I've made another change to my mainline CMD file to include forcing any ISR routine to be linked into the 0x8000-0xFF80 address range as per FLASH35

    FLASH : origin = 0x5C00, length = 0x2400, fill = 0x3FFF // WARNING: Affected by FLASH35
    FLASH_ISR : origin = 0x8000, length = 0x7F80, fill = 0x3FFF // WARNING: Affected by FLASH35

    This did make my sections quite dirty looking. perhaps I should have used a group?

    #ifndef __LARGE_CODE_MODEL__
        .text       : {} > FLASH | FLASH_ISR    /* Code                              */
    #else
        .text       : {} >> FLASH2 | FLASH | FLASH_ISR   /* Code                     */
    #endif
        /* Keep all ISR code in the lower address range as the interrupt jump table  */
        /* requires interrupt routies to be below 64KB for addressing reasons        */
        .cinit      : {} > FLASH  | FLASH_ISR   /* Initialization tables             */
    #ifndef __LARGE_DATA_MODEL__
        .const      : {} > FLASH | FLASH_ISR    /* Constant data                     */
    #else
        .const      : {} >> FLASH | FLASH_ISR | FLASH2  /* Constant data             */
    #endif
    
        .pinit      : {} > FLASH | FLASH_ISR    /* C++ Constructor tables            */
        .binit      : {} > FLASH | FLASH_ISR    /* Boot-time Initialization tables   */
        .init_array : {} > FLASH | FLASH_ISR    /* C++ Constructor tables            */
        .mspabi.exidx : {} > FLASH | FLASH_ISR  /* C++ Constructor tables            */
        .mspabi.extab : {} > FLASH | FLASH_ISR  /* C++ Constructor tables            */

  • The resolution I've put in place is exactly this

    lnk_msp430f5418a.cmd

     // Reduce the size by 8 bytes to prevent placement at end of flash bank
     FLASH2                  : origin = 0x10000,length = 0x15BF8, fill = 0x3FFF
     //Keep these bytes empty. Had VMAI errors raised in last section
     FLASH3 (R)              : origin = 0x25BF8,length = 0x08   , fill = 0x3FFF // FATAL: Affected by ERRATUM UNKNOWN

  • Lucas,

    regarding FLASH35: You only need to do this if you have affected DIE revisions B to D which I cannot imagine because this is very very old material normally you should only get F to H maybe E.

    Regarding the other phenomena can you please place a "nop instruction" after the RETA to see if this helps. And then place the the RETA at 0x25BFC.Also shifting it by another 32 bit to 0x25BF8 and place 3 nops after it.

    What is a bit stragne that the last 8 bytes are showing this behavior. Normally the FLASH is read in 32 bit double words. Therefore I would understand if the RETA in the last 32 bit affect it but the at 0x25BF8 with a nop at 0x25BFA it should work.
    There aere some ERRATAS with respect to this which are addressed by the Compiler. So you mentioned you saw this after downloading the latest CCS correct. Can you please let me know which Compiler you use now and you used before?
  • Lucas,

    did some additional design checks. The point is that a pipelined CPU is used which will continue increase MAB when the RETA is fechted that's why you need to leave some room to the boundery of the memory ensuring no VMA is triggered. At least for code placement this part of the memory should not be used. For data it's not problem.
  • Lucas,

    I performed a bench test using a very simple Assembler code and I cannot 100% confirm your results. I used the larger memory spin F5438A RevH and placed a "reta" instruction at address 0x45BFC as you can see below. In this case the VMA NMI is triggered because the CPU makes an auto increment due to pipeline architecture.

    However I remove 3 nops and put the "reta" on 0x45BF6 the VMA NMI disappears on the locations 0x45BF8, 0x45BFA, 0x45BFC it still appears

    Also a nop after the reta will not help here. I will furhter check in design and will come back to you how we proceed with this. But as mentioned before this is due to pipelined CPU architecture.

  • Ok good to know that you can replicate it on the larger chip also, and that I'm not going crazy :)

    8 bytes of flash wont be missed for instructions I'm sure. I'll leave it here then as I've adjusted my CMD file already to exclude that block so I'm back running again.

  • Ok I must have mis-read the sheet for FLASH35 (phew).. I was going mad at the time.

    18.1.3 and 18.1.2 I've used.

    I dont "recall" seeing it in previous versions, but that being said, I never enabled the interrupt before now as I was having SVMH/L problems from a fauly power supply circuit and numerous un-explained executions of code into infinitum, which I hadn't seen before version 18.1.2/3

    I have MSP430F5418a Rev E in my devices FWIW. In my later devices I have Rev H. I can dump the TLV table from the running device if you like. It should be the latest revision as it was fabricated this year with new stock.

    Thanks for looking into this :)
  • Hi Lucas,

    got it. The simulation work is still ongoing as soon as I have something new I will let you know but expect results by end of the week.

  • Lucas,

    I simulated this behavior now and have to correct me a little bit based on simulation it is only critical if the "reta" instruction is located at addresses 0x45BFC, 0x45BFE. In the end it means that only the last 2 words should not be filled with instruction code and the last 4 words.

    I also confirmed this on silicon!  The reason why I had seen the point also before at addresses 0x45BF8 and 0x45BFA is that the I had a breakpoint on the reta which will lead to additional flash accesses. But in free run mode or without debugger connected the "reta" should only be not located on 0x45BFC, 0x45BFE. Can you please confirm this.

    The root cause as mentioned before the pipelined CPU architecture and it's prefetching mechanism.

    On the top on this you have to know that the "reta" is an emulated MOVA @SP+,PC which takes 5 clocks.

    Looking at the instruction cycles there can be other instructions which takes a clock more e.g. mova  &EDE,PC. For this the instruction should not be located on address 0x45BFA

    So finally said if you keep the last 8 words free or do not use it for instruction code it should work fine. But it would be enough for the "reta" to keep the last 2 words free. Please let me know if you can confirm this.

    Afterwards we will file this in our internal systems and decide how this is handled e.g. External ERRATA or Linker Command File fixes.....

**Attention** This is a public forum