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.

TMDSCNCD28379D: Timing issue using CPU Timer1 as time base

Part Number: TMDSCNCD28379D


Hello,

The controller should check a digital signal input (GPIO40) at least 40 microseconds after a digital signal output (GPIO44) is set.
During run time most of the time it works fine, that is, GPIO40 is tested 40 microseconds after GPIO44 was set. However, there was one time where GPIO40 was tested only about 8 microseconds after GPIO44 was set. I'm trying to understand why did it happen and fix that problem.

Code structure:
The code is loaded to flash and run from RAM.
CPU timer1 is used as time base of 20 microseconds and its overflow flag is polled to advance relevant counters.


One question that may be related:
There is one occurrence where Timer1 is reloaded (same period of 20 microseconds) but it is not stopped prior to reloading command. Could that be related to the problem? If timer overflow flag was going to be set (Timer reach zero) exactly at the time (clock) of instructing the timer to reload (CpuTimer1Regs.TCR.all = 0x8C20;), could the overflow flag remain set?

A very simplified and reduced code to demonstrate the location where the problem occurs is attached.


Your assistance would be very appreciated.

Dvir.

#include "F28x_Project.h"						
//====================================================================
// Functions prototypes
//====================================================================
void ConfigGpio(void);
void Timer1_counters_increment(void);
void function1(void);
//====================================================================
// Variables 
//====================================================================
Uint32 Counter;
Uint32 Flag;
//====================================================================
// main()
//====================================================================
void main(void)
{
    InitSysCtrl();
    DINT;
    InitPieCtrl();
    InitGpio();
    ConfigGpio();
    IER = 0x0000;
    IFR = 0x0000;
    InitPieVectTable();
    InitCpuTimers();  
    EINT;
    ERTM;  
    ConfigCpuTimer(&CpuTimer1, 150, 20u);	// Timer1 serves as 20 microseconds time base
    CpuTimer1Regs.TCR.all = 0x8C00;
    GpioDataRegs.GPACLEAR.bit.GPIO0 = 1;
    GpioDataRegs.GPBCLEAR.bit.GPIO44 = 1;
    
    while(1)
    {
        function1();
    }
	
}	// END of main()

//====================================================================
// Functions definitions
//====================================================================

void ConfigGpio(void)
{
    EALLOW;
    GpioCtrlRegs.GPAGMUX1.all	&= ~0xf0f3cfff;
    GpioCtrlRegs.GPAMUX1.all	&= ~0xf0f3cfff;
    GpioCtrlRegs.GPBGMUX1.all	&= ~0x0f0fffff;
    GpioCtrlRegs.GPBMUX1.all	&= ~0x0f0fffff;
    GpioCtrlRegs.GPAGMUX1.all	|=  0x00000000;
    GpioCtrlRegs.GPAMUX1.all	|=  0x00000500;
    GpioCtrlRegs.GPBGMUX1.all	|=  0x00000000;
    GpioCtrlRegs.GPBMUX1.all	|=  0x00000005;
    GpioCtrlRegs.GPAPUD.all	= 0xC4FF0D3F;
    GpioCtrlRegs.GPBPUD.all	= 0x00003C84;
    GpioCtrlRegs.GPACTRL.all = 0x1E004B4B;
    GpioCtrlRegs.GPBCTRL.all = 0x1E1E1E1E;
    GpioCtrlRegs.GPAQSEL1.all = 0xA0008000;
    GpioCtrlRegs.GPBQSEL1.all = 0x000A2A8F;
    GpioDataRegs.GPADAT.all = 0x00000000;
    GpioDataRegs.GPBDAT.all = 0x00000000;
    GpioCtrlRegs.GPAODR.all = 0x00000000;
    GpioCtrlRegs.GPBODR.all = 0x00000003;
    GpioCtrlRegs.GPADIR.all = 0xC4FF0D0F;
    GpioCtrlRegs.GPBDIR.all = 0x00003084;
    EDIS;
}

void Timer1_counters_increment(void)
{
	CpuTimer1Regs.TCR.all = 0x8C00;	// Resets CPU-Timer 1 overflow flag. Timer runs free
	Counter++;
}

void function1(void)
{
    if(Flag == 0)
    {
        GpioDataRegs.GPBSET.bit.GPIO44 = 1;
        CpuTimer1Regs.TCR.all = 0x8C20;	//Clear timer interrupt flag and reload timer
        Counter = 0;	//Reset counter
        while (Counter < 2)	// count 40 microseconds after GPIO44 is set
        {
        		if (CpuTimer1Regs.TCR.bit.TIF)
        		{
        			Timer1_counters_increment();
        		}	
        }
        Flag = 1;	// Flag that 40 microseconds were counted
        if (GpioDataRegs.GPBDAT.bit.GPIO40)	// After 40 microseconds GPIO40 is tested
        {
        		GpioDataRegs.GPASET.bit.GPIO0 = 1;	// Set GPIO0 to indicate that GPIO44 is high
        }
    }
}


  • Hi Dvir,

    Can you help me understand how to reproduce the issue? I tried running this code and see the delay is consistent. 

    Do you have any ISRs in the actual application?

    Regards,

    Veena

  • Hi Veena,

    Thank you for the prompt response.

    Actually, I don't know how to reproduce the issue as it happened only once (after many instances where everything went fine with 40 microsecond delay as required) and caused a trip in a prototype system using the card.

    The attached code is a very reduced and simplified subset of the real code used in the prototype application. It is a simplified subset showing where the issue occurred in the code. The real code is quite complex and implements a type of state machine with almost all GPIOs of the card utilized with many inputs and outputs including 12 ADC channels. Running the real code without the real system will be impossible as the code will immediately go to "Trip Mode" where the subset of the code in which the issue occurred will not be utilized.

    Only polling is used in the code, no ISRs are utilized or allowed.

    I wanted to check if you can see a problem in the way that the timer is used and instructed.

    Maybe we can start by checking if the operation of the timer is done correctly. I couldn't find in the documentation if the timer needs to be stopped before reloading. Note that the timer is not stopped (with the instruction "CpuTimer1Regs.TCR.bit.TSS = 1;") before clearing timer overflow flag and reloading the timer in the attached code in line 82 with the write-only instruction " CpuTimer1Regs.TCR.all = 0x8C20;". Is that procedure fine and fail safe or should the timer be stopped prior to overflow flag clearing and reloading instruction? Could there be a conflict if the timer is not stopped prior to the instruction " CpuTimer1Regs.TCR.all = 0x8C20;"  and at the exact CPU clock cycle the timer reached zero (completed counting 20 microseconds) and trying to set the overflow flag (that is, the instruction tries to clear the flag and the timer tries to set the flag at the same time)?

    Regards,

    Dvir

     

  • Hi Dvir,

    I will review the code once again and get back to you by tomorrow.

    Regards,

    Veena

  • Hi Veena,

    Thank you. That would be most appreciated.

    Regards,

    Dvir

  • Hi Dvir,

    Couple of questions:

    1. Why are you not reloading the counter inside Timer1_counters_increment() by setting TCR value to 0x8C20, for remaining 20us, it shows 0x8C00?

    2. Once 40us has elapsed and you have set flag=1, can you stop the CPUTIMER by writing TSS=1?

    I think your assessment may be correct. Since the counters are still running when you reload the counters in the beginning of the function.

    Best Regards,

    Nirav

  • Hi Nirav

    Thank you for the response. See reply to your questions below.

    1. Why are you not reloading the counter inside Timer1_counters_increment() by setting TCR value to 0x8C20, for remaining 20us, it shows 0x8C00?

    [Dvir] Reloading is done before "Timer1_counters_increment()" so that exactly 40 microseconds will be counted. If reloading will be done in "Timer1_counters_increment()" the time will be longer than 40 microseconds because the flag is polled and interrupts are not used. Most likely the polling will be done some time after timer reached zero and set the overflow flag.

    2. Once 40us has elapsed and you have set flag=1, can you stop the CPUTIMER by writing TSS=1?

    [Dvir] In the actual code I'm using this timer for other operations which are not shown in the reduced and simplified attached code. So the timer is required to keep running. 

    Will it be possible for you to find in documentation or ask development about the overflow flag question? The question was: if at the same CPU clock cycle the timer (hardware) tries to set the overflow flag but the software tries to clear it and also reload the timer (instruction "CpuTimer1Regs.TCR.all = 0x8C20;"), who has priority, hardware or software? Will the overflow flag be cleared or remain set?

    Best regards,

    Dvir

  • Hi Dvir,

    SW write to Overflow flag and the Overflow flag being generated due to counter getting expired are both asynchronous events. Also when the CPU Timer expires, overflow signal goes through clock synchronizer logic before it gets latched into the TCR register, hence there will be few cycles delay.

    Since both are asynchronous events, if the overflow flag comes after the SW write to the register, then TIF flag will be set right after SW write (i.e. 0x8C20).

    If you are reloading the counters, why would CPU timer running matter? Because you are not waiting on CPU timer to expire, meaning in your function1 you do not check for overflow flag before your reload. So even though CPU timer is running, when you enter this function, you want the timer to be reloaded, which is essentially start and stop operation, correct? Maybe I am missing the full picture.

    Best Regards,

    Nirav

  • Hi Nirav,

    The trigger to this query is an unexpected event we had with a prototype system using the control card.

    The code that was attached is a very reduced and simplified section of the actual code the application uses. This attached code demonstrates where the issue occurred in the actual code.

    What happened was that after many instances where everything went fine there was a single event where the equivalent section to "function1()" in the actual code took 8 microseconds instead of 40 microseconds. I'm looking for bugs or glitches that could cause such behavior.

    If timer expires but due to the delay the timer overflow flag would set after the SW write (0x8C20) then it can explain "function1()" duration reduction from 40 microseconds to 20 microseconds ("Counter" variable would immediately be incremented from 0 to 1 and then will take another timer period of 20 microseconds to reach 2 and terminate the while loop) but not to 8 microseconds. In addition, I tried to deliberately create such event today by adding a new line before the SW instruction 0x8C20. The new line writes directly to the timer counter register TIM. I've tried setting it to the range of values 0-10 but non of them caused TIF to set after the SW instruction 0x8C20. So this issue probably didn't cause the event.

    I may have a lead from today investigations:

    The equivalent while loop from "function1()" in the actual code used in the application includes more routines compared to the sample code attached. The cycle of this while loop is about 4 microseconds. It could be reasonable to assume that the while loop in the event cycled exactly twice and then terminated. This can explain the 8 microseconds duration in the event. Now, if this assumption is correct, the question is what caused it to cycle only twice (rather than about 10 times). If "Counter" variable was incremented every while loop cycle rather than every 20 microseconds timer expiration that could explain this behavior. But what could cause the "Counter" to increment every while loop cycle? Are you familiar with any events in the past where TIF was "stuck" in set position and could not be cleared (if possible, this could explain such behavior)?

    Another thing to consider is some kind of overflow during code execution. Maybe some overflow into "Counter" memory location, stack overflow or similar. However, I couldn't find evidence at the moment that such thing could happen.

    As you mentioned, the fact that the timer was running and not stopped during SW instruction 0x8C20 doesn't seem to be related to the event.

     

    Best regards,

    Dvir

  • Hi Dvir,

    No, TIF should not be "stuck" in set position after you clear it, not aware of any such issue. Maybe you can check for TIF flag to be cleared after you write 0x8C20.

    Best Regards,

    Nirav

  • Hi Nirav,

    Yes, I have checked the TIF flag and it is clear.

    There is one finding from today though:

    I've checked today the generated assembly code, the linker cmd file and the output memory map file of the actual code. 

    The piece of code where the issue occurred is split across two subsequent memory blocks: RAMLS3 and RAMLS4. The boundary is exactly between two assembly opcode dealing with actual code equivalent to the simplified code while loop "while (Counter < 2) // count 40 microseconds after GPIO44 is set". Could that be related to the issue?

    It is an entire function that is spread across subsequent sections of the memory blocks. The function is located on memory addresses 0x00009e77 to 0x0000a4c6 and as mentioned above the boundary is exactly in the section of code where the issue occurred. It is worth mention again that it only occurred once so far after some cases that it worked fine.

    Actual code:

    Assembly code relevant section (memory location in the assembly is offset from address 0x00009989) - boundary is between lines 3259 and 3260. The branch in line 3260 is to the code of line outside the while loop (terminates the while loop --> this exactly seemed to be the problem, the while loop terminated earlier than expected in a single occurrence):

    Linker file relevant memory blocks (united blocks):

    Linker file relevant section is .text:

    Relevant memory map file section - the relevant "father" function where the problematic code section is nested is "_bit":

    Can you see a problem here that could cause the issue? Or is it just a coincidence that the code section where the issue occurred is located on a boundary of memory blocks? As far as I remember functions should not be split across non contiguous blocks but what about contiguous ones?

    Best regards,

    Dvir

  • Hi Dvir,

    This is interesting finding. It feels coincidental and not related, only way it can break the while loop is if TIF flag is set, so memory boundary should not affect reading incorrect TIF flag. But I guess you are suggesting that code never jumped back into the while loop and it terminated, that does not seem possible, unless the stack got corrupted.

    But that seems odd, since it worked for most of the time. Honestly we need to duplicate the issue to root cause.

    Best Regards,

    Nirav

  • Hi Nirav,

    We are still trying to reproduce this issue. We are building a setup that will allow us to run that exact code where the issue occurred.

    In the meantime, we have reviewed again the silicon errata to see if we can find relevant issues.

    In page 32 of the Silicon Errata SPRZ412L there is the issue "Memory: Prefetching Beyond Valid Memory". We have checked allocation to memory blocks M1, GS1, GS15 and all seems to be  fine and within the recommendations. We just want to verify that only these 3 memory blocks are affected by this issue and all other memory blocks are not affected, is that right?

    And one more question, the code where the issued occurred is standalone application, that code is loaded (boot) to FLASH and run from RAM (at initialization all sections of code are copied from Flash to RAM). When the above mentioned testing setup will be completed and the code is run standalone, is there a way to connect to the controlCARD with a debugger through CCS?

    Best regards,

    Dvir

  • Correction - GS11 rather than GS1

  • Hi Dvir,

    Yes those are the only 3 RAM memory blocks that are affected.

    Yes you can connect to debugger, you will probably have to wait boot, and then configure boot to flash. After that you should be able to step through the code.

    Best Regards,

    Nirav