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.

Fast periodic timer interrupt from dmtimer-Example not working

Genius 5820 points

Since my old thread regarding this problem was filled with some off-topic-trash and never was answered, I'll try it again here:

I'm using the dmtimer-Example to toggle an output and to toggle a LED (this LED is of course switched only every 10000th..100000th call of ISR execution to see it blinking).

I'm using exactly the code from the BeagleBone example of Starterware except the serial interface output and timer start and reload count value. When I use values of 0xFFFFFE00 (equal to 21 usec) here, the ISR is called periodically as expected.

When I change the timer count/reload to 0xFFFFFF00 (equal to 10.6 usec) or higher values, the ISR is no longer called in expected way:

- ISR is called once more or less immediately (possibly after these 10.6 usec)
- then it is not called for several minutes
- then it is called periodically but according to frequency it seems the 32kHz clock is used instead of 24MHz CLK_M_OSC

My calculation is as follows: in 10.6 usec a CPU @1GHz can execute about 10000 clock cycles in ISR which should be more than enough for my little code, so this should not be a reason for stumbling about timing.

Is this calculation correct?

If not: there is an internal RAM/cache available that should be much faster - is it possible to move the ISR and all used variables into that RAM to execute the whole thing faster and to avoid timing problems?

All I want to do is to call a ISR with a frequency of 100 kHz (equal 10usec, equal timer value of 0xFFFFFF0F) which really should not be too fast for such a CPU?

Thanks!

  • Hi Hans,

    We shall look into this and get back to you shortly.

    Regards,

    Jeethan

  • Hi Jeethan,

    great, so I'm waiting for your response!?

    Cheers

    Hans

  • Hi Hans,

    Thanks for your time and patience.

    1) Your calculation is correct i.e. for overflow value of 10.6 usecs and for a CPU @1GHz the ISR execution time should not cause any discrepancy.

    2) Following is our observation while debugging the code for a overflow value of 10.6usec with CCS IDE

    • Code was tested on AM335x GPEVM
    • In the code first interrupts are enabled and then timer is enabled.
    • On enabling the interrupt the ISR would hit before enabling the timer. On checking further we found out that the timer would be already running. Probably the Gel file is causing this. We will look into this.
    • Due to this the programmed overflow values would not be reflected initially and the timer would start from 0. Hence it would take a long time to interrupt after the first ISR is hit.
    • To overcome this we added "void DMTimerReset(unsigned int baseAdd)" as the first call inside "DMTimerSetUp"
    • On doing this the overflow values would be configured properly and the ISR is working as expected.

    Please add the Reset API in your code and let us know if it works for your use case.

    I shall raise an IR to track the addition of Reset API in the DMTimer example and share that with you in 2 days.

    Regards,

    Jeethan

  • Hi Jeethan,

    with this modification the IRQ is running and the ISR is called without that very long delay after first execution.

    BUT: the frequency still seems to be way to slow. There is no difference in frequency between timer values 0xFFFFFE00, 0xFFFFFF00 and even 0xFFFFFFF0.

    I'm currently not sure what frequency it is, I'll check it with an oscilloscope later but it is not the expected one.

    Kind regards

    Hans

     

     

     

     

  • OK, I did some more tests. My ISR now looks as follows:

    static void DMTimerIsr(void)
    {
        HWREG(SOC_DMTIMER_2_REGS + DMTIMER_IRQENABLE_CLR) = (DMTIMER_INT_OVF_EN_FLAG &
                                               (DMTIMER_IRQENABLE_CLR_TCAR_EN_FLAG |
                                                DMTIMER_IRQENABLE_CLR_OVF_EN_FLAG |
                                                DMTIMER_IRQENABLE_CLR_MAT_EN_FLAG));
        HWREG(SOC_DMTIMER_2_REGS + DMTIMER_IRQSTATUS) = (DMTIMER_INT_OVF_IT_FLAG &
                                             (DMTIMER_IRQSTATUS_TCAR_IT_FLAG |
                                              DMTIMER_IRQSTATUS_OVF_IT_FLAG |
                                              DMTIMER_IRQSTATUS_MAT_IT_FLAG));
    
        // turn LED on and off slowly 
    ledCtr++; if (ledCtr==1) { fast_GPIOPinSet(SOC_GPIO_1_REGS, (1<<23)); } else if (ledCtr==8000) { fast_GPIOPinClear(SOC_GPIO_1_REGS, (1<<23)); } else if (ledCtr==16000) ledCtr=0; // toggle GPIO1[15] on every call of ISR clockCtr++; if ((clockCtr & 0x00000001)==0x00000001) { fast_GPIOPinSet(SOC_GPIO_1_REGS,_CLK_BIT); } else { fast_GPIOPinClear(SOC_GPIO_1_REGS,_CLK_BIT); } HWREG(SOC_DMTIMER_2_REGS + DMTIMER_IRQENABLE_SET) = (DMTIMER_INT_OVF_EN_FLAG & (DMTIMER_IRQENABLE_SET_TCAR_EN_FLAG | DMTIMER_IRQENABLE_SET_OVF_EN_FLAG | DMTIMER_IRQENABLE_SET_MAT_EN_FLAG)); }

     

    I'm using a timer/reload value of 0xFFFFFF0F which is a frequency of 100kHz on CLK_M_OSC of 24 MHz which means the ISR should be called every 10 usec. But when I run the application the output pin is toggled every 20 usec only!

    More than this, when I change timer/reload value to 0xFFFFFF70 (which should be about double frequency/halve time) the ISR is called with same frequency, still every 20 usec.

    (Note: I tested it with an analogue oscilloscope so the value of 20 usec might not be very accurate).

    So...is there still a problem with the timer/IRQ or is something different limiting the speed?

     Thanks

     Hans

     

  • Hi Hans,

    Could you please try this out .

    • Take out the GPIO code from the ISR .
    • Set the timer count and reload value for 10us period.   
    • Run the code for 10 seconds - use a stop watch to count 10 seconds
    • Stop the code and check the value of g_isr_count - it should be 1000 000 ( 10usx 100 x 1000 x 10)

    static void DMTimerIsr(void)

    {
        HWREG(SOC_DMTIMER_2_REGS + DMTIMER_IRQENABLE_CLR) = (DMTIMER_INT_OVF_EN_FLAG &
                                               (DMTIMER_IRQENABLE_CLR_TCAR_EN_FLAG |
                                                DMTIMER_IRQENABLE_CLR_OVF_EN_FLAG |
                                                DMTIMER_IRQENABLE_CLR_MAT_EN_FLAG));
        HWREG(SOC_DMTIMER_2_REGS + DMTIMER_IRQSTATUS) = (DMTIMER_INT_OVF_IT_FLAG &
                                             (DMTIMER_IRQSTATUS_TCAR_IT_FLAG |
                                              DMTIMER_IRQSTATUS_OVF_IT_FLAG |
                                              DMTIMER_IRQSTATUS_MAT_IT_FLAG));
    
    g_isr_count++;
        HWREG(SOC_DMTIMER_2_REGS + DMTIMER_IRQENABLE_SET) = (DMTIMER_INT_OVF_EN_FLAG &
                                               (DMTIMER_IRQENABLE_SET_TCAR_EN_FLAG |
                                                DMTIMER_IRQENABLE_SET_OVF_EN_FLAG |
                                                DMTIMER_IRQENABLE_SET_MAT_EN_FLAG));
    }
    

     

  • Hi Hans,

    An IR has been raised to track the change required to be maded to DMTimer applications regarding soft reset.

    The IR can be tracked here https://cqweb.ext.ti.com/cqweb/#/SDO-Web/SDOWP/RECORD/SDOCM00105165&recordType=IncidentReport&format=HTML&noframes=false&format=HTML&version=cqwj

    Regards,

    Jeethan

  • @Vineeth: OK, I placed nothing more than "clockCtr++" into my ISR, and stopped the time until it reached a value of 1000000 (I did it this may since my debugger is still locked by the customs).

    With a timer value of 0xFFFFFF0Fu (equal to 100 kHz) I got about 11 seconds which would be OK.

    With a timer value of 0xFFFFFF70u (equal of about 200 kHz) I got 11 seconds too - which should be about 5 seconds.

     

  • Hello Hans,

    5us periodicity should still be OK.  Are other latencies coming into play?

    Could you do a quick check by turning the MMU and cache on. This code would be there in evmsk (evmsk is another another board like beagle bone) example for dmtimer. Change the ISR to do clockCtr++ and build the application .

    Executable can be found in evmskAM335x folder.

    Another issue could be with the dmtimer input clock skew . At frequencies like this even a small variation could cause large output variation. Let me look around and try to find some answers for you. 

  •   Vineeth,

     enabling the MMU (by using MMUConfigAndEnable() from the code you mentioned) lets the application die during initialisation, only CacheEnable() works.

    Unfortunately it does not change something regarding the speed problem.

    Cheers

     Hans

     

  • Hi Hans,

    I had tried enabling the cache and trying the same out . Your observation is correct that the ISR is not visited enough number of times. Let me look  into this and I will get back to you in a few days. 

  • Any news regarding this issue?

  • I did some more - or better to say other - experiments and found out that enetLwip example performs some initialisation that lets the dmtimer run with a frequency of up to 1 usec.

    So I did nothing more than integrating my dmtimer-example into enetLwip to have a http-server (beside my bit-toggling function). and amazingly I could use exactly the same code to call the ISR every 1 usec.

    But a similar behaviour here: when I try to go below this limit all timer values/reload counts are ignored, is is impossible to run faster than this 1 usec.

    Does this make any sense? Perhaps there is some additional initialisation in enetLwip that influences the timer interrupt speed?

     

     

     

  • And just an other experiment: Since DMTimer2 integrated into enetLwip-example caused an interrupt every 1 usec I tried to use interleaving interrupts. Thus I set up DMTimer3 with the same parameters but with a slightly different initial timer value and an own ISR. Both should be called interleaved and one of them every 0.5 usec. The code within the ISRs is quite simple and fast: one turns a GPIO on, the other ISR turns it off. That should result in a rectangular output signal with about 1 MHz frequency.

    The amazing result: now interrupt frequency again goes down dramatically and the ISRs are called every 10 usec. The system itself is completeley stalled, some code in main-loop is no longer executed.

    So: any ideas what makes the interrupts that unreliable?

    Thanks!

  • So...any news regarding this issue?

  • Hi Hans,

    Sorry for the delay - was struck up in another work. I did look around and found an issue with our timer configuration.

    One of the things that I found was that we are not configuring the timer in posted mode as recommended by the TRM. Using the timer in non posted mode could cause transaction latency. Linux or similar OSes do not use such high resolution timers and hence their config would not be of much help.

    I need to try this once but in the mean time could you give this a shot? You could use the DMTimerPostedModeConfig ()

    to configure the same.

     

  • Seems like this does not help...I tried different locations in my initialisation code but I'm still a bit unsure. So where should I place this call?

    Thanks!

  • Hans,

    regarding your fast periodic timer problem I have two questions:

    • why do you call DMTIMER_IRQENABLE_CLR and DMTIMER_IRQENABLE_SET in every cycle inside your ISR?
      You could try just clearing the status flag register.
    • Have you tried to read back the status flag register before returning from interrupt?
      May be it needs some time before the flag register is written out.

    regards

    Ralf

  • > why do you call DMTIMER_IRQENABLE_CLR and DMTIMER_IRQENABLE_SET in every cycle inside your ISR? You could try just clearing the status flag register.

    That's taken out of the dmtimer-example that comes with Starterware. I have no idea what it is good for and already tried without it - seems to work but does not solve the speed issue.

    > Have you tried to read back the status flag register before returning from interrupt? May be it needs some time before the flag register is written out.

    No, but when I wait for this code in ISR it should not change anything than expanding the execution time of ISR? In my opinion it should not matter if the status flag is set some time after the ISR is left or within the scope of ISR...

  • Hans, I meant just read back the status register not wait for any change. This should ensure that the register is updated in place and not some (unexpected) time later on in your main thread.

  • I think we're talking about the same:

    1. Write data to the register (what is currently done)

    2. Read the register until the previously written value can be found there -> has to be done in a loop until the written value can be read -> means wait until it can be read.

  • No, I assume we are not talking about the same. I mean:

    • your ISR code 
    • clear status register:
      HWREG(SOC_DMTIMER_2_REGS + DMTIMER_IRQSTATUS) = (DMTIMER_INT_OVF_IT_FLAG &
                                               (DMTIMER_IRQSTATUS_TCAR_IT_FLAG |
                                                DMTIMER_IRQSTATUS_OVF_IT_FLAG |
                                                DMTIMER_IRQSTATUS_MAT_IT_FLAG));
    • read back status register:
      volatile_irqstatst = HWREG(SOC_DMTIMER_2_REGS + DMTIMER_IRQSTATUS);
    • return from ISR

    thats all. BTW this is an often used "Flush posted write" method found in device drivers (i.e. Linux)

  • OK, that's indeed something different. Starterware performs readback by using a while-loop that is active until the expected value can be read, that's why I assumed a delay here.

    I'll try your suggestion and see if it helps :-)

  • Since this ist still an issue I'll sum up the current state again to get an overview about the whole story:

    - when using dmtimer-Example it is not possible to have fast interrupts, it is not even possible to call a ISR every 10 usec (ISR of course is MUCH shorter than 10 usec)

    - after integration of ethernet functionality out of enetLwip-demo into the dmtimer-based application it was possible to have an interrupt every 10 usec - but that's the limit, it was not possible to have faster interrupts; it is still unclear which part of the enetLwip-code caused this speed-up

    - setting up two different DMTimer-interrupts that have to be called interleaved did not work in above scenario, this stalled the whole system while the both ISRs became very slow again - independent from used timer count/reload value it was no longer possible to call them every 10 usec

    Any ideas?

  • Vineeth Balan said:
    Let me look around and try to find some answers for you

    Since this seems to be a bigger problem: is it possible for me to file a bugreport for the faulty dmtimer-Example?

  • Meanwhile I found an answer there: http://stackoverflow.com/questions/20314955/set-up-fast-dmtimer-interrupt-on-beaglebone-black/21609090?noredirect=1#21609090

    The prescaler has to be disabled using DMTimerPreScalerClkDisable(). 

    In my opinion it is a bit embarrasing the guys at TI did not find this simple solution...

  • Hello Hans,

    We are extremely sorry that we could not find the issue that you have reported and thankful that you have posted the solution to the problem.

    When you had reported this issue sometime in November, I had run the 02.00.01.01 version of the code on our EVM and found that ISR was not being visited at the required rate. From the code base released by us , we do not enable the prescaler input clock and hence it was not deemed necessary to disable the  presclaer . If you verify the value of

    Timer Control Register (TCLR) it would be 0x03 implying that the timer mode is AR and the timer is running. Prescler clock is disabled by default. Clock input to the dmtimer module can be varied by either using the prescaler or by using the PRCM clock selection mux. I had check with max values for the mux and prescler disabled. 

    I checked out the timer input clock selection MUX value in the PRCM module . After setting it to CLK_M_OSC  I had tried to run our example and failed to get the desired output. With reference to TRM 

    CLKSEL_TIMER2_CLK register , CLKSEL field defaults to 1 on reset.

    I still do not have any explanation as to why disabling the prescaler would get the timer working. 

     

     

        

  • Hello,

    I'm facing the same problem at the moment, my timer also don't work with the 10us interrupt

    Hans could you add your working code for me, thanks.

    If I add DMTimerPreScalerClkDisable(...) the timer don't work correct

    Tobias 

  • Tobias Haerter said:
    If I add DMTimerPreScalerClkDisable(...) the timer don't work correct

    When you use this call the timer reload counter values have to be changed too since the whole divider changes.

    I can't share the full code here, it is way too complex meanwhile. One thing that brought me a huge step forward was integration of lwip_enet example. I know, it does not have to do anything with the timer but it seems there is an important initialisation part of this example which is neccessary for dmtimer too. Until now I could not find out which initialisation of lwip-example did the trick, the experts from TI here in webboard also don't have an answer to this question :-/

  • Hello,

    that means the problem is not solved comprehensible?

    Very bad!

    So you assume that the clock of the timer is initialized in a  differently way at the Iwip example?

    regards Tobias

  • @Tobias: please refer to http://e2e.ti.com/support/embedded/starterware/f/790/t/324059.aspx , there a small DMTimer application is posted that can go down to 0,5 usec.