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.

TMS320F28379D: Timer 2 Interrupt Enable Causes Unexpected Execution

Part Number: TMS320F28379D
Other Parts Discussed in Thread: C2000WARE,

Greetings,

    I am setting up a project to use Timer 2 to generate a periodic interrupt.  The interrupt is disabled at the timer (TIE), and in the core registers IER, and INTM.  I can run the code and watch the timer run.  When it decrements to 0, TIF is set, PRD is loaded into TIM, and the count down begins again – all as expected.

    But when the interrupt from the timer (TIE) is enabled (IER and INTM are still disabled), once TIM has been decremented to 0, the code stops at an ESTOP0 instruction in the TI bootloader at address 0x3fe493.  No interrupt should have occurred, but the code was ready if it did.  But the interrupt routine never executed. The setup is as follows:

  1. The interrupt routine is a C routine prefaced by the “__interrupt” keyword.
  2. The interrupt routine increments a counter and exits.
  3. All locations in the interrupt vector table (0xD00 – 0xEFF) are pointing to the interrupt routine.
  4. Core Registers.ST1.INTM is 1
  5. Core Registers.IER.INT14 is 0
  6. CpuTimer2Regs.TCR.TIE is 1

What could I have done to cause the code to wind up in the TI bootloader?

Thank you,

Ed

 

  • Correction.  I captured the information too soon in the process.  When this occurs, INTM is 0, and INT14 is 1.

    Sorry for any confusion.

    Ed

  • Hi Ed,

    I tried to duplicate what you did based on the information provided, but couldn't get the program to stop at the ESTOP instruction you mentioned.

    Below is a modified version of the timed_led_blink example from C2000WARE that should have what you are looking for: Configures a timer with an interrupt that increments a count each time the ISR is entered.

    C:\ti\c2000\C2000Ware_Version\device_support\f2837xd\examples\cpu1\timed_led_blink

    Could you please let me know if you still see the issue with the sample code below, and if so, how to replicate the issue?

    If you watch ' CpuTimer2.InterruptCount' in the expressions window you should see the count increment every time the ISR is entered.

    //
    // Included Files
    //
    #include "F28x_Project.h"
    
    //
    // Function Prototypes
    //
    __interrupt void cpu_timer2_isr(void);
    
    void main(void)
    {
    //
    // Step 1. Initialize System Control:
    // PLL, WatchDog, enable Peripheral Clocks
    // This example function is found in the F2837xD_SysCtrl.c file.
    //
       InitSysCtrl();
    
    //
    // Step 2. Initialize GPIO:
    // This example function is found in the F2837xD_Gpio.c file and
    // illustrates how to set the GPIO to it's default state.
    //
    // InitGpio();  // Skipped for this example
    
    //
    // Step 3. Clear all __interrupts and initialize PIE vector table:
    //
       DINT;
    
    //
    // Initialize the PIE control registers to their default state.
    // The default state is all PIE __interrupts disabled and flags
    // are cleared.
    // This function is found in the F2837xD_PieCtrl.c file.
    //
       InitPieCtrl();
    
    //
    // Disable CPU __interrupts and clear all CPU __interrupt flags:
    //
       IER = 0x0000;
       IFR = 0x0000;
    
    //
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    // This will populate the entire table, even if the __interrupt
    // is not used in this example.  This is useful for debug purposes.
    // The shell ISR routines are found in F2837xD_DefaultIsr.c.
    // This function is found in F2837xD_PieVect.c.
    //
       InitPieVectTable();
    
    //
    // Interrupts that are used in this example are re-mapped to
    // ISR functions found within this file.
    //
       EALLOW;  // This is needed to write to EALLOW protected registers
       PieVectTable.TIMER2_INT = &cpu_timer2_isr;
       EDIS;    // This is needed to disable write to EALLOW protected registers
    
    //
    // Step 4. Initialize the Device Peripheral. This function can be
    //         found in F2837xD_CpuTimers.c
    //
       InitCpuTimers();   // For this example, only initialize the Cpu Timers
    
    //
    // Configure CPU-Timer 2 to __interrupt every 500 milliseconds:
    // 60MHz CPU Freq, 50 millisecond Period (in uSeconds)
    //
       ConfigCpuTimer(&CpuTimer2, 60, 500000);
    
    //
    // To ensure precise timing, use write-only instructions to write to the entire
    // register. Therefore, if any of the configuration bits are changed in
    // ConfigCpuTimer and InitCpuTimers (in F2837xD_cputimervars.h), the below
    // settings must also be updated.
    //
       CpuTimer2Regs.TCR.all = 0x4001;
    
    //
    // Step 5. User specific code, enable __interrupts:
    
    //
    // Enable CPU INT14 which is connected to CPU-Timer 2:
    //
       IER |= M_INT14;
    
    //
    // Enable global Interrupts and higher priority real-time debug events:
    //
       EINT;   // Enable Global __interrupt INTM
       ERTM;   // Enable Global realtime __interrupt DBGM
    
    //
    // Step 6. IDLE loop. Just sit and loop forever (optional):
    //
       for(;;);
    }
    
    //
    // cpu_timer2_isr - CPU Timer2 ISR 
    // __interrupt void cpu_timer2_isr(void){ CpuTimer2.InterruptCount++; //For Timers 1 and 2 the CPU acknowledges the interrupt } // // End of file //

    Best Regards,

    Marlyn

  • Hi Marlyn,

                     Please forgive my ignorance here.  This is my first attempt at building a project using only the resources under the C:\ti folder.  I created a new project and copied the code from your response into main.c. I have then been adding Include Options to bring in the various things which are required.  But this has resulted in it bringing in a file which wants to include adc.h which does not exist. I am using C2000Ware_3_01_00_00. Should I be using the new version?  Or maybe an older version?

                    But taking a code inspection approach, other than the rate at which the timer is running, I’m not seeing a difference in how the timer is setup.  And the only difference in the setup of the interrupt vector table, is that I am filling the entire table with the interrupt vector, as partially shown below.  The assembly code at the vector address looks like valid interrupt code.  So I believe an interrupt is being generated, but the CPU gives the appearance of having used a different interrupt vector table.  What could cause that?

     

    I’ve included some before and after captures of the CPU and Timer2 registers as well as the PieVectTable.

     

     Timer 2 setup just prior to starting the timer.

    Core registers just prior to starting the timer.

    ===============================================================================================

    Timer 2 registers at the failure point.

    Core registers at the failure point.

    Thanks,

    Ed

  • Hi Marlyn,

    I spent the day working on getting your main code to build using only the latest C2000Ware (3.02.00.00), and I ran it with the same results as my own code. It still ends up in the Boot ROM. I have tried power cycling it, and also a different copy of the HW. So I’m certain that it is not something left over from another run, nor is it a HW issue.

    It would help if we understood which routine in the Boot ROM it was winding up in, and from that what needs to happen to get it there.

    Thanks,

    Ed

     

  • Ed Sanders said:
    It would help if we understood which routine in the Boot ROM it was winding up in, and from that what needs to happen to get it there.

    The TMS320F2837xD Dual-Core Microcontrollers Technical Reference Manual has:

    Where the reported address of 0x3fe493 is within the ITRAP ISR for CPU1, which means the CPU has attempted to to execute an illegal instruction.

  • Hi Ed,

    Chester is correct, your code is stopping at an ITRAR ISR. You can find more information about what that entails here: TMS320C28x CPU and Instruction Set

    Can we try the below and see if anything changes?

    1) Try importing the project I described above. This can be done through CCS by going to Project -> Import CCS Projects.. -> Navigating to the directory below and then choosing the project. Once loaded you can replace the code in the main file with the one I provided. You should not have to include and source files. I know you said that you already tried to incorporate it into your project, but it may help if this is isolated from other code you may have written. 

    C:\ti\c2000\C2000Ware_Version\device_support\f2837xd\examples\cpu1\timed_led_blink

    2) How are you running your project? Sometimes having breakpoints in designated areas may affect the behavior of your code. I would suggest running your code by just pressing the 'Run' button if you aren't already. This is different from single stepping through each line of the code. 

    3) What is the clock source of your Timer 2? By default it is SYSCLK, but I am wondering if you configured something else.

    4) By any chance, are you utilizing TI-RTOS in your application? I ask this because CPU-Timer2 is reserved for real-time operating system uses (for example, TI-RTOS). However, if your application is not using an operating system that utilizes this timer, then CPU-Timer2 can be used.

    Best Regards,

    Marlyn

  • Thank you both,

    Based on Chester’s comment, I have taken a more critical look at the interrupt routine, and specifically the location of the ISR. Looking at the vector addresses in the PieVectTable, the timer 2 ISR is the only odd address. It doesn’t seem like this should be an issue because the first instruction in the ISR is an ASP instruction which is a single word instruction. But if the processor ignores the LSb, it would definitely matter.  Is this an issue?

    Marlyn o your questons...

    1) a. I created the project from a blank project, used your code as the main() code, and pulled in code from C:\ti\c2000\C2000Ware_3_02_00_00\device_support\f2837xd as needed. None of our code is in that project. Is there a way for me to send it to you so you can have a look?

    1) b. I imported the timed_led_blink project and built it. That was successful. However, when I changed the Properties->General->Project->Variant to specify the TMS320F28379D, selected our Connection (Texas Instruments XDS2xx USB Debug Probe), and did a Clean Build, the linker gave me a lot of errors consisting of various memory ranges having already been specified. For example, the first of the errors says:

    "C:/ti/c2000/C2000Ware_3_02_00_00/device_support/f2837xd/common/cmd/2837xD_RAM_lnk_cpu1.cmd", line 7: error #10263:

       BEGIN memory range has already been specified

    The linker moves through the list of declarations in the cmd file, rejecting each in turn.

     

    2) Both my project and yours were run without any breakpoints. The only thing I did was to click the Run button.

     

    3) Rather not put this on a public forum. Can I get this information to you privately?

    4) Rather not put this on a public forum. Can I get this information to you privately?

     

    Thanks,

    Ed

     

  • Hi Chester,

    This helps.  Thank you.  Please see my comment below to Marlyn.  I just looked at the Core Registers, and noted that the RPC is 0.  Is there any way to determine which address contained the illegal instruction?

    Thank you,

    Ed

  • Ed Sanders said:
    Is there any way to determine which address contained the illegal instruction?

    The address which contains the illegal instruction gets pushed on the stack.

    I performed a test where I deliberately inserted an invalid instruction in the code using asm (" .word 0xffff") which is ITRAP1. Upon entry to the start of the ITRAP ISR in the boot rom at address 0x3FE468 then the offending instruction is on the stack at word SP - 3.

    Once the ESTOP0 at the end of ITRAP ISR in the boot rom at address 0x3FE493 is hit then the offending instruction is on the stack at word SP - 0x1C.

    E.g. when the process was halted at ESTOP in the boot rom at address 0x3FE493 then:

    a. SP = 0x0432.

    b. SP - 0x1C = 0x416

    c. In the Memory Browser word 0x416 = 20F0 (lsw) and word 0x0417 = 0x0008 (msw). Which points at address 0x0820F0 as containing the offending instruction. In this test actual ITRAP1 instruction was in the preceding word at address 0x0820EF. I.e. in this test it appears the illegal instruction address which gets pushed on the stack is the one after the problematic instruction.

  • Ed Sanders said:
    That was successful. However, when I changed the Properties->General->Project->Variant to specify the TMS320F28379D, selected our Connection (Texas Instruments XDS2xx USB Debug Probe), and did a Clean Build, the linker gave me a lot of errors consisting of various memory ranges having already been specified.

    When the device variant is changed on an existing project, CCS can add a linker command file to the project for the newly selected variant which can then lead to errors from the linker due to overlapping definitions for memory ranges.

    You need to resolve the conflict by either removing one of the linker command files from the project, or right-clicking one in the Project Explorer and selecting "Exclude from Build"

  • Hi Chester,

    That seems to be what is happening.  I have browsed through each of the folders in the project, but the only cmd file I can find is in the root of the project.  It doesn’t include anything, and doesn’t repeat any of the ranges.  Is there a default cmd file which it might be using?

    Thanks,

    Ed

     

  • Ed Sanders said:
    Is there a default cmd file which it might be using?

    It looks like some C2000ware examples don't add a copy of a linker command file to the Project Explorer, but instead reference the linker command file by name in the project properties. E.g.:

    In which case the the linker command file could be removed form the list under "Include library file or command file as input".

  • Now I see it.  There are two from which to choose.  Which do you suggest I remove?

  • Clicked Reply too soon.  There is also the cmd file in the root, 2837x_FLASH_lnk_cpu1.cmd.

  • Of the .cmd files I think:

    a. F2837xD_Headers_nonBIOS_cpu1.cmd in the File Search Path was from the original example C2000ware imported example. This sets addresses for peripherals, rather than FLASH or RAM memory regions.

    b. 2837xD_RAM_lnk_cpu1.cmd was in the File Search Path from the original example C2000ware imported example. This allocates sections to place the program in RAM.

    c. 2838x_FLASH_lnk_cpu1.cmd was added to the root when the device variant was selected in the CCS project properties. This allocates sections to place the program in FLASH.

    The 2837xD_RAM_lnk_cpu1.cmd and 2838x_FLASH_lnk_cpu1.cmd will have conflicting memory regions, and you need to select one depending upon if want the example code to run from RAM or FLASH.

  • OK.  I excluded the file in the root, and it built and is running.  I can see the timer incrementing!  I'm going to start comparing the two projects.

  • I switched the cmd files to use the Flash version, and that also works. So I’ve compared the following, and noted the registers which differ.

    1. STI1.INTM – No difference
    2. IER.INT14 – No difference
    3. CpuTimer2Regs
      1. PRD
    4. ClkCfgRegs
      1. IMULT
      2. PLLSYSCLKDIV
      3. LSPCLKDIV
    5. PieVectTable
      1. Both have the correct address to their respective interrupt routine at 0c0D1C in the table.

    The differences would cause the timers to run at different rates, which is what I observe.  But I don't see how any of these differences could be causing the issue.  So I believe that there is another piece to this puzzle that I need to learn about.  What else should I be looking at?

    Also, to your previous comment, SP – 0x1C shows an address of 0x1F0000 which contains an ITRAP0 instruction.  Since there is nothing in the PieVectTable with this address, I’m at a loss to explain how the processor got there.

    Thanks,

    Ed

     

  • Hi Ed,

    I believe there might be something in the timer configuration that may be causing this issue. I've sent you a friend request so you can share with me the information to questions 3/4 I asked previously.

    What happens to the example project if you configure the same clk/timer settings? Does it still run properly?

    Best Regards,

    Marlyn

  • Ed Sanders said:
    Also, to your previous comment, SP – 0x1C shows an address of 0x1F0000 which contains an ITRAP0 instruction.

    The address 0x1F0000 appears to be vacant, i.e. not decoded, and read as all zeros which is an ITRAP0 instruction.

    While my initial suggestion was to inspect the contents of SP – 0x1C to find the address of the instruction which caused the ITRAP, I have realised that C2000ware comes with the symbols and source code for the boot rom. Once has stopped at address 0x3FE493 in the CPU1 boot rom, in the CCS debugger you can use Run -> Load -> Add Symbols and point at the .out file containing the symbols for boot rom. In my case was in ~/ti/C2000Ware_3_02_00_00_Software/libraries/boot_rom/f2837xd/revB/rom_sources/ccs_files/cpu01/Release/F2837x_cpu01_bootROM_REVB_Golden_020314.out. There are boot rom revisions for REV0 and REVB and since was using TMS320F28379D with rev C silicon used the REVB boot rom.

    Once the symbols for the boot rom have been added then the global variable iTrap_addr contains the address of the instruction which caused the ITRAP. For my test program which deliberately inserted an ITRAP1 into the code the correct address was reported:

  • I've accepted the friend  request.  How do I get the information to you?

  • Ed,

    I sent you a private message, you can reply to it with the information. Let me know if you don't see it.

    Best Regards,

    Marlyn

  • I saw it, and just sent the info.  You should be able to see it.

    Thanks,

    Ed

  • Hi Chester,

    iTrap_addr has an address of 0x1EFFFF which has a value of 0x0000.

  • Ed Sanders said:
    iTrap_addr has an address of 0x1EFFFF which has a value of 0x0000.

    OK, that is consistent with when you previously manually inspected SP – 0x1C; allowing for the following in the boot rom c1brom_itrap_isr function:

    	/*return address from interrupt will be PC location where illegal instruction is executed + 1*/
    	iTrap_addr -= 1;

    I still don't know how the PC got set to that address. Hopefully the info you sent to Marlyn will allow the cause to be found.

  • I keep coming back to the interrupt vector because everything is fine until the interrupt occurs.  After the CPU stops in the bootloader, the vector is correct in the PieVectTable.  Does the processor ever get an interrupt vector from anywhere else?

    Thanks,

    Ed

  • This post was resolved offline. The solution to the issue was to enable the Pie Vector Table (bit ENPIE in the PIECTRL register).

    Best Regards,

    Marlyn

  • Marlyn Rosales Castaneda20 said:
    The solution to the issue was to enable the Pie Vector Table (bit ENPIE in the PIECTRL register).

    Thanks for the update.

    By taking a program which uses a timer 2 interrupt, and then disabling the ENPIE bit can repeat the same problem as Ed in that get an ITRAP for address 0x001EFFFF. Presumably, with the ENPIE bit clear the CPU ends up branching to an undefined interrupt vector.

  • Everything makes sense now.  Thanks for your help Chester.

    Ed