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.

NVIC_VTABLE Offset Not Loaded at Startup with xM4x Device

Other Parts Discussed in Thread: TM4C123GH6PGE

My project started on the LM3S series micro and I moved to the LM4F (XM4F232H part label).  Months ago I moved the library from Stellarisware to Tivaware and except for a few minor issues/bugs with the library, have been operational for a while.  Recently, I noticed my CCS project is still set up for the LM3S5R31 micro and proceeded to change it to the LM4F232H5QDF (TM4C123GH6PGE) part.  This change broke the code to run.  It appears that the startup code no longer sets the NVIC-VTABLE register to point to the code start offset of 0x4000.  It begins at 0 and the first interrupt I register (SysTick) ends up copying the bootloader interrupt vector instead of the application vector.  

I have been through many different tests to locate the issue without success.  I have verified the .cmd files are still correctly set up.  I have even reverted the project file to the original before the change and it too doesn't undo this problem.  I have copied the startup_ccs.c file from the example projects to replace the startup.c I had previously and that too doesn't work.  I looked through the _c_int00 function in the boot.asm file for where this register gets loaded and couldn't find anything there either.  I tried pointing the project setting to use the specific command file below located within my project.  

UPDATE: I tried version 5.3. and version 5.4.0 of CCS and have tried this on two different computers.

--retain=g_pfnVectors
MEMORY
{
    FLASH (RX) : origin = 0x00004000, length = 0x0003c000
    SRAM (RWX) : origin = 0x20000000, length = 0x00008000
}
/* The following command line options are set as part of the CCS project.    */
/* If you are building using the command line, or for some reason want to    */
/* define them here, you can uncomment and modify these lines as needed.     */
/* If you are using CCS for building, it is probably better to make any such */
/* modifications in your CCS project and leave this file alone.              */
/*                                                                           */
/* --heap_size=0                                                             */
/* --stack_size=256                                                          */
/* --library=rtsv7M4_T_le_eabi.lib                                           */
/* Section allocation in memory */
SECTIONS
{
    .intvecs:   > 0x00004000
    .text   :   > FLASH palign(4)
    .const  :   > FLASH palign(4)
    .cinit  :   > FLASH
    .pinit  :   > FLASH
    .vtable :   > 0x20000000
    .data   :   > SRAM
    .bss    :   > SRAM
    .sysmem :   > SRAM
    .stack  :   > SRAM
}
__STACK_TOP = __stack + 256;

The final problem I have now is selecting the old LM3S device does not undo the issue and so I seem stuck in this mode.  What happened in the start-up or initialization code when the Device was changed that broke this and how do I undo it?  Also, why doesn't the LM4 or TM4 devices load this register value correctly and the LM3 device did?  Is there a workspace value that is holding this bug as I have reverted everything in the project except my source files and it still doesn't work?  Is there a bug in the XM4 hardware that the LM4F and TM4C devices are not compatible?  How is the LM3S device setting able to make this work?

Thanks, -Tim

  • Hi,

    I think you need to add this line: ccs=ccs to the predefined compiler options (same place as you define DEBUG and PART_IS_.... The reason are these lines in driver lib/interrupt.c file: (you can verify map file if the section vtable is generated).

    #elif defined(ccs) || defined(DOXYGEN)
    #pragma DATA_ALIGN(g_pfnRAMVectors, 1024)
    #pragma DATA_SECTION(g_pfnRAMVectors, ".vtable")
    void (*g_pfnRAMVectors[NUM_INTERRUPTS])(void);

    No ccs - no vtable section in RAM...

    Petrei

  • Thanks Petrei for your help but that is not quite the issue I have.  All the flash code is correct and the table transfer from flash to RAM is correct.  It is the register that is wrong now.

    I already have that define in the compiler options.  The issue is that by the time the program counter reaches the start of main(), it has no longer loaded the NVIC_VTABLE register with the correct location of the interrupt vector table.  The vector table should reside at 0x4000.  It always did by main before I changed the device type. The interrupts are located in flash at 0x4000 but the register isn't telling the micro to look there but at 0x0000.  Since I do have the ccs defined in the compiler options, the first time I register an interrupt (the SysTick), the Tivaware function IntRegister(...) has the following code that copies the Flash table into the RAM table:

        if(HWREG(NVIC_VTABLE) != (uint32_t)g_pfnRAMVectors)
        {
            //
            // Copy the vector table from the beginning of FLASH to the RAM vector
            // table.
            //
            ui32Value = HWREG(NVIC_VTABLE);
            for(ui32Idx = 0; ui32Idx < NUM_INTERRUPTS; ui32Idx++)
            {
                g_pfnRAMVectors[ui32Idx] = (void (*)(void))HWREG((ui32Idx * 4) +
                                           ui32Value);
            }
            //
            // Point the NVIC at the RAM vector table.
            //
            HWREG(NVIC_VTABLE) = (uint32_t)g_pfnRAMVectors;
        }
    The first if statement checks if the vector table (NVIC_VTABLE register) value is located in RAM already.  It is not and therefore copies the table from Flash to RAM.  The issue is that the NVIC_VTABLE register is wrong as it points to 0x0000 location.  My vectors are in 0x4000 so it copies the Bootloader interrupt table at 0x0000 into RAM.  Regardless of the RAM copy or static interrupts, it is clear the program will not work as the Application interrupt vectors are located at 0x4000 not 0x0000.
    Yes, I did try setting TM4C device as well and the behavior is the same.
    I believe there is something that got messed up in the startup code that the NVIC_VTABLE register is not loading with the value of .intvecs from the command file any longer.  I just can't find any code that sets this register.  Unfortunately, when I change back to the old LM3S device type in the project, it doesn't seem to fix this problem.  Replacing the .cproject file with the original no longer works either.  So, I figure either a workspace value has changed or a CCS program setting changed.  But if it was the latter, then other projects on the old LM3S would no longer work either.  TI, what is going on here?  I can't load my code anymore.
  • Hi,

    I think in this case the NVIC_VTABLE should be initialized with the right value and then the function called. But this has already done - as example - look out in the file bootloader/startup_ccs.c - lines 305..338 initialize NVIC_VTABLE to 0x20000000 and then copy the vector interrupt table (without any other function call).

    Petrei

  • Hi Tim,

    Tim49805 said:
    I believe there is something that got messed up in the startup code that the NVIC_VTABLE register is not loading with the value of .intvecs from the command file any longer.  I just can't find any code that sets this register.  Unfortunately, when I change back to the old LM3S device type in the project, it doesn't seem to fix this problem.  Replacing the .cproject file with the original no longer works either.  So, I figure either a workspace value has changed or a CCS program setting changed.  But if it was the latter, then other projects on the old LM3S would no longer work either.  TI, what is going on here?  I can't load my code anymore.

    When a device variant is selected, the CCS project manager will load default options for that variant. This can include:

    -compiler/linker options

    -linker command file

    -run time library

    -default source files in a new project

    -target configuration file

    -etc

    If you already have a variant selected and then you change it to a different one, it will wipe away your current settings and set it to the default of the new variant. Changing it back will only set it back to the default options of that original variant. Any customizations you made to that original variant options would not be restored.

    If you want to get the options back before you made the switch, you need to also restore the .project and .ccsproject file in addition to the .cproject.

    Hope this helps.

    ki