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.

Issues to General Purpose 64 bit Timer

Hello,

I've used the GP 64 Bit Timer for timing measurements and run into several problems. Having found these two threads (which are unfortunately not answered yet; http://e2e.ti.com/support/dsp/c6000_multi-core_dsps/f/639/t/177732.aspx & http://e2e.ti.com/support/dsp/c6000_multi-core_dsps/f/639/t/180641.aspx), I got the same problems.

Device is a C6678, code example can be seen below (simple set up a timer, trigger an interrupt on Core 0 and measure time until IRQ is entered on Core 1). Testing this I run into following problems:

1) starting the timer just after the reset, I only get a time stamp on the first read; I suppose (low value is very high) on the second read the timer has timed out allthough the period is set to maximum and the timer is set to continous.

2) Starting the timer after open and called "Reset" before triggering the Interrupt just stops the timer and don't reset the counter. Moreover I always got a value in the Low-Register, the High is always 0. Why?

3) To avoid the two problems above, I just start the timer before triggering the Interrupt. The I got the following values: Timer start at 88462901 (Core 0), Timer stop at 88462593 (Core 1). I thought this is timer with the same time stamp on each core. How can the stamp reaching the IRQ be less than the stamp before triggering the interrupt???

4) Calculating the time: timer is running with 1/6 core frequency, which is 166.67 in my example (core runs with 1000 MHz). Cycle difference is 308 -> Time is Cycles / Clock => 308 / (166,67 x 10^6) = 1,85 / 10^6 = 1,85 micro seconds??? Such a long time for triggering a interrupt? Maybe there's something wrong in my calculation or the time stamps are wrong.

Hope somebody can help me on this issues.
Best Regards,
Bernd

--- Core 0 & 1---

    memset(&TmrObject, 0, sizeof(TmrObject));
    TmrHandle = CSL_tmrOpen(&TmrObject, 7, NULL, &CSLStatus);
    if(TmrHandle == NULL)
    {
        Log_print0(Diags_USER1, "Timer_setup failed");
        exitFailure(0);
    }

    TmrHwSetup.tmrTimerMode = CSL_TMR_TIMMODE_GPT;
    TmrHwSetup.tmrTimerPeriodLo = 0xffffffff;
    TmrHwSetup.tmrTimerPeriodHi = 0xffffffff;
    CSL_tmrHwSetup(TmrHandle, &TmrHwSetup);
    CSL_TmrReset64(TmrHandle);

--- Core 0 ---

    CSL_tmrGetTimLoCount(TmrHandle, &uiCountLowStart);
    Log_print1(Diags_USER1, "Timer Low Start:  %d\n", uiCountLowStart);

    volatile uint32_t *uiptr_register = (uint32_t *) 0x02620240;
    uiptr_register += 1;
    *uiptr_register |= (1 << 4);     // set source
    *uiptr_register |= 1;            // interrupt

--- Core 1 ---
void IRQ_test(UArg arg)
{
    if(DNUM == 1)
    {
        CSL_tmrGetTimLoCount(TmrHandle, &uiCountLowStop);
        Log_print1(Diags_USER1, "Timer Low Stop: %d\n", uiCountLowStop);
    }

}

  • Hi Bernd,

    lot's of questions in one go. I attached a project measuring the cycles for an IPC interrupt. My counter reaches approx. 100. In cycle count that's 600 since the general purpose counters run at CPU/6.

    The time measured includes the time to get from the interrupt vector to the actual ISR. So it's not only the time it takes to trigger the interrupt but also run through the ISR dispatching.

    A couple of potential issues in your code. Only one core should configure the GP Timer. You need to synchronize the cores to make sure everything is initialized properly before you start to trigger the interrupt ...

    Kind regards,

    one and zero

    Timed_interrupt.zip
  • Hello one and zero,

    Sorry for misunderstanding due to the measured time; I meant the time which it lasts until the ISR is entered.

    Thanks for your example. I've tested it (I also got 100 cycles). Configure the timer only by one core changed the behaviour of my program so that I measure nearly 160 cycles (I think the other 60 cycles are due to some overhead for SYS/BIOS, SystemAnalyzer, ... I'm using at the moment). So point 1) to 3) are okay. But I'm not clear with point 4:

    Measuring 100 cycles are equivalent with 0,6 microseconds until the ISR entered (with 1000 MHz Core Clock Frequency)? This is a very long time isn't it? Are there any possibilities to speed up this time? I thought I've read about 200 ns instead of 600 ns...

    Best Regards,
    Bernd

  • Hi Bernd,

    yes you can be a bit faster. If you directly jump into your ISR from the Interrupt vector. That way you save the cycles going through the interrupt dispatching done in the CSL.

    I attached this version as Timed_interrupt2(2).zip (Includes 2 zip file with the 2 versions Timed_interrupt using CSL for interrupt handling and Timed_interrupt2 managing interrupts "manually").

    In addition also the CSL interrupt actually consumes less. I did a mistake in my first attempt. I corrected the storage of the time stamps. TI put them in Shared L2 so I can easily read and write from both cores. In my first version I read from local L2 so the start value printed out was always 0. The second change I did was adding a delay for core 0 to make sure core 1 is sitting in the while loop when core 0 triggers the interrupt.

    Now the timer deltas are:

    For CSL: about 80 -> 480 cycles

    No CSL: With optimizer turned on (release) I get 54 -> 324 cycles

    if I move the read of the timer right after the the line that triggers the interrupt the delta goes down to 16 - > 96 cycles. This seems OK looking at the assembly code generated.

    So it also depends a lot on the compiler what you actually see as latency ...

    If you write you ISR in assembly you can  save additional cycles. Because you are responsible to save the C context and can optimize depending on the register usage in your assembly routine ...

    Kind regards,

    one and zero

    Timed_interrupt2 (2).zip
  • Hi...

    I tried the timed_interrupt example of one and zero and got it to work! But when I combined the example with my project, my HWIs don't work anymore.... is there any possibility, to get both (HWI and Inter processor interrupts) running in the same project? what have I to do?

    Thx for your help...

  • Hello Philipp,

    it depends what (if) your using a framework; e.g. if you're using Sys/Bios, it's no problem to use HWI's and IPC (is also only a HWI with an appropriate configuration). For an example see below. If this doesn't work, please provide a code example how you configure your IRQ's. With the example below, you can also configure another HWI beside the IPC one and use it.

    Regards,
    Bernd

    bool configureIPCInterrupt(void)
    {
        Hwi_Params         sHwiParams;
        Hwi_Handle         HwiHandle;
        Error_Block     ErrorBlock;

        Error_init(&ErrorBlock);
        Hwi_Params_init(&sHwiParams);
        sHwiParams.arg = 9;
        sHwiParams.eventId = CSL_GEM_IPC_LOCAL;
        sHwiParams.enableInt = true;
        HwiHandle = Hwi_create(4, IPCHandler, &sHwiParams, &ErrorBlock);
        if(HwiHandle == NULL)
        {
            return false;
        }
        Hwi_enable();

        return true;
    }

    void IPCHandler(UArg uarg)
    {
        DEVICE_REG32_W(IPCAR(DNUM), IPCSOURCE);
        DEVICE_REG32_W(0x80000200 + 4*DNUM, 0xBABEFACE);
        while(1) ;
    }

    Trigger IPC for core 1:

    #define IPCGR(x)                (0x02620240 + x * 4)
    #define IPCAR(x)                (0x02620280 + x * 4)
    #define IPCSOURCE         (0x10)
    DEVICE_REG32_W(IPCGR(1), IPCSOURCE | 0x1);