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.

Problems to set DMTimer1_1MS

Other Parts Discussed in Thread: AM3359, CLOCKTREETOOL, OMAP3530

Hello

I have problem to set up the DMTimer1_1ms on a AM3359.

I would like to have every 1ms an Interrupt.

The Registers a set like:

TISTAT 0x00000001

TIER 0x00000007

TCLR 0x00000003

TLDR 0xFFFFFFE0

TSICR 0x00000004

At the emulator I could see that the Register TCRR change its value.

My code is:

void init_timer1_1ms(void)
{
unsigned int regVal;

    // init clock
    HWREG(SOC_CM_DPLL_REGS + CM_DPLL_CLKSEL_TIMER1MS_CLK) &=
                                         ~(CM_DPLL_CLKSEL_TIMER1MS_CLK_CLKSEL);

    while((HWREG(SOC_CM_DPLL_REGS + CM_DPLL_CLKSEL_TIMER1MS_CLK)
           & CM_DPLL_CLKSEL_TIMER1MS_CLK_CLKSEL) != 0x0);

    HWREG(SOC_CM_DPLL_REGS + CM_DPLL_CLKSEL_TIMER1MS_CLK) = CM_DPLL_CLKSEL_TIMER1MS_CLK_CLKSEL_SEL5; // set to external 32KHz clock

    while((HWREG(SOC_CM_DPLL_REGS + CM_DPLL_CLKSEL_TIMER1MS_CLK)
           & CM_DPLL_CLKSEL_TIMER1MS_CLK_CLKSEL) != CM_DPLL_CLKSEL_TIMER1MS_CLK_CLKSEL_SEL5);

    HWREG(SOC_CM_WKUP_REGS + CM_WKUP_TIMER1_CLKCTRL) |=
                                  CM_WKUP_TIMER1_CLKCTRL_MODULEMODE_ENABLE;

    while((HWREG(SOC_CM_WKUP_REGS + CM_WKUP_TIMER1_CLKCTRL)
            & CM_WKUP_TIMER1_CLKCTRL_MODULEMODE)
                                   != CM_WKUP_TIMER1_CLKCTRL_MODULEMODE_ENABLE);

    while((HWREG(SOC_CM_WKUP_REGS + CM_WKUP_TIMER1_CLKCTRL)
           & CM_WKUP_TIMER1_CLKCTRL_IDLEST)
                                   != CM_WKUP_TIMER1_CLKCTRL_IDLEST_FUNC);
    // init timer mode and registers
//     from spruh73i.pdf Datasheet page 4129
//    For 1 ms tick with a 32768-Hz clock:
//    TPIR = 232000
//    TNIR = -768000
//    TLDR = 0xFFFFFFE0
    HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TPIR) = 232000;
    HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TNIR) = -768000;
    HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TLDR) = 0xFFFFFFE0;

 //  Enable interrupt
    HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TIER) |= (DMTIMER_1MS_TIER_TCAR_IT_ENA
                                                      & (DMTIMER_1MS_TIER_TCAR_IT_ENA_ENB_CAPT <<  DMTIMER_1MS_TIER_TCAR_IT_ENA_SHIFT))
                                                    |(DMTIMER_1MS_TIER_MAT_IT_ENA
                                                      & (DMTIMER_1MS_TIER_MAT_IT_ENA_ENB_MATCH << DMTIMER_1MS_TIER_MAT_IT_ENA_SHIFT))
                                                    |(DMTIMER_1MS_TIER_OVF_IT_ENA
                                                      & (DMTIMER_1MS_TIER_OVF_IT_ENA_ENB_OVF << DMTIMER_1MS_TIER_OVF_IT_ENA_SHIFT));   // Enable interrupt

    // init interrupt
    IntSystemEnable(SYS_INT_TINT1_1MS);
    IntPrioritySet(SYS_INT_TINT1_1MS, 0, AINTC_HOSTINT_ROUTE_IRQ);
    IntRegister(SYS_INT_TINT1_1MS, ISR_timer1_1ms);

    ms_time_tick = 0;

    regVal = HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TCLR);
    regVal |= DMTIMER_1MS_TCLR_AR & (DMTIMER_1MS_TCLR_AR_AUTO_REL << DMTIMER_1MS_TCLR_AR_SHIFT); // Auto Reload
    regVal |= DMTIMER_1MS_TCLR_ST & (DMTIMER_1MS_TCLR_ST_CNT_START << DMTIMER_1MS_TCLR_ST_SHIFT); // Start Timer
    HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TCLR)  = regVal;
}

static void ISR_timer1_1ms(void)
{
    ms_time_tick++;
}

at main init
    IntAINTCInit();
    IntMasterIRQEnable();

Were is my problem?

I would be helpful to have the Register values of an working example off a 1ms timer.

regards Tobias

  • Hi Tobias,

    Support for DMTimer 1ms is not present in StarterWare.

    Since you are able to see the Timer running the Timer is clocked. Hence i guess the interrupts are not getting generated?

    If so can you please check if the necessary Interrupt status is getting set in the TISR register.

    Regards,

    Jeethan

  • Hello

    I now that there is no direct support for DMTimer1, but I have the necessary registers and bit-defines for it in Starterware.

    If I'm in the wrong forum could anyone relocate my post to the right forum.

    I guess that I'm wrong with my register settings. But I don't know what to change.

    I could not see anything at the TISR register.

    I anyone have a working register setup of DMTimer1 for me, that would be very helpful.

    regards Tobias

      

  • Hello

    I have solved my main problem. To start the timer with the right frequency you have to write the startup value direct to TCRR Register.

    And second you have to reset the interrupt flag at TISR after each interrupt

     

    void init_timer1_1ms(void)
    {
    unsigned int regVal;
    
        // init clock
        HWREG(SOC_CM_DPLL_REGS + CM_DPLL_CLKSEL_TIMER1MS_CLK) &=
                                             ~(CM_DPLL_CLKSEL_TIMER1MS_CLK_CLKSEL);
    
        while((HWREG(SOC_CM_DPLL_REGS + CM_DPLL_CLKSEL_TIMER1MS_CLK)
               & CM_DPLL_CLKSEL_TIMER1MS_CLK_CLKSEL) != 0x0);
    
        HWREG(SOC_CM_DPLL_REGS + CM_DPLL_CLKSEL_TIMER1MS_CLK) = CM_DPLL_CLKSEL_TIMER1MS_CLK_CLKSEL_SEL5; // set to external 32KHz clock
    
        while((HWREG(SOC_CM_DPLL_REGS + CM_DPLL_CLKSEL_TIMER1MS_CLK)
               & CM_DPLL_CLKSEL_TIMER1MS_CLK_CLKSEL) != CM_DPLL_CLKSEL_TIMER1MS_CLK_CLKSEL_SEL5);
    
        HWREG(SOC_CM_WKUP_REGS + CM_WKUP_TIMER1_CLKCTRL) |=
                                      CM_WKUP_TIMER1_CLKCTRL_MODULEMODE_ENABLE;
    
        while((HWREG(SOC_CM_WKUP_REGS + CM_WKUP_TIMER1_CLKCTRL)
                & CM_WKUP_TIMER1_CLKCTRL_MODULEMODE)
                                       != CM_WKUP_TIMER1_CLKCTRL_MODULEMODE_ENABLE);
    
        while((HWREG(SOC_CM_WKUP_REGS + CM_WKUP_TIMER1_CLKCTRL)
               & CM_WKUP_TIMER1_CLKCTRL_IDLEST)
                                       != CM_WKUP_TIMER1_CLKCTRL_IDLEST_FUNC);
        // init timer mode and registers
    //     from spruh73i.pdf Datasheet page 4129
    //    For 1 ms tick with a 32768-Hz clock:
    //    TPIR = 232000
    //    TNIR = -768000
    //    TLDR = 0xFFFFFFE0
        HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TPIR) = 0x00038A40; //232000;
        HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TNIR) = 0xFFF44800; //-768000;
        HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TLDR) = 0xFFFFFFE0;
    
        HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TIER) |= (DMTIMER_1MS_TIER_OVF_IT_ENA
                                                          & (DMTIMER_1MS_TIER_OVF_IT_ENA_ENB_OVF << DMTIMER_1MS_TIER_OVF_IT_ENA_SHIFT));   // Enable interrupt
    
        // init interrupt
        IntSystemEnable(SYS_INT_TINT1_1MS);
        IntPrioritySet(SYS_INT_TINT1_1MS, 0, AINTC_HOSTINT_ROUTE_IRQ);
        IntRegister(SYS_INT_TINT1_1MS, ISR_timer1_1ms);
    
        ms_time_tick = 0;
    
        regVal = HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TCLR);
    
        regVal |= DMTIMER_1MS_TCLR_AR & (DMTIMER_1MS_TCLR_AR_AUTO_REL << DMTIMER_1MS_TCLR_AR_SHIFT); // Auto Reload
        regVal |= DMTIMER_1MS_TCLR_ST & (DMTIMER_1MS_TCLR_ST_CNT_START << DMTIMER_1MS_TCLR_ST_SHIFT); // Start Timer
        HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TCLR)  = regVal;
    
        //set start value of timer
        HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TCRR) = 0xFFFFFFE0;
    }
    
    void DMTimer1IntStatusClear(unsigned int intFlags)
    {
        /* Clear the interrupt status from IRQSTATUS register */
        HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TISR) = (intFlags &
                                             (DMTIMER_1MS_TISR_MAT_IT_FLAG |
                                              DMTIMER_1MS_TISR_OVF_IT_FLAG |
                                              DMTIMER_1MS_TISR_TCAR_IT_FLAG));
    }
    
    static void ISR_timer1_1ms(void)
    {
        ms_time_tick++;
        DMTimer1IntStatusClear(DMTIMER_1MS_TISR_OVF_IT_FLAG); // clear interrupt Flag
    }


    Now I have the Problem that the timer is too fast. I'm not sure that all my values are correct.

    Dose anyone have correct Register settings for a 1ms tick for me?

    regards Tobias

     

     

  • Hi Tobias,

    Can you use the DMTIMER_1MS_TOWR Register register to mask say 5000 interrupts and understand how fast the timer is actually running. I suspect the clock configuration to be off the mark.  Also try to configure the timer in auto reload no compare mode. Rest of your init seems to be good.

  • Hello

    I have found that the timer is running with double speed. That means I have a 0,5ms tick.

    If I enable the presacaler with one, I get the 1ms tick.

    But that is not how it is described at the datasheet .

    I use a external clock, and I have checked the clock settings with the ClockTreeTool.

    regards Tobias

  • Hi Tobias,

    Sorry that we are not able to root cause your issue. Could you please give it a check with the other two 32 khz clock sources configured in CLKSEL_TIMER1MS_CLK register.

    Namely:
    • The PER PLL generated 32.768 KHz clock (CLK_32KHZ)
    • The on-chip ~32.768 KHz oscillator (CLK_RC32K)
    In the ISR could you please disable the dmtimer_1ms interrupts -> clear the interrupt status and then -> enable dmtimer_1ms instrrupts again. 

    I

  • Hello

    I have checked the other clock sources, but there are no changes.

    But If I disable the interrupt like:

    static void ISR_timer1_1ms(void)
    {
        HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TIER) |= (DMTIMER_1MS_TIER_OVF_IT_ENA
                                                                & (DMTIMER_1MS_TIER_OVF_IT_ENA_DSB_OVF << DMTIMER_1MS_TIER_OVF_IT_ENA_SHIFT));   // Disable interrupt at timer level
        ms_time_tick++;
        DMTimer1IntStatusClear(DMTIMER_1MS_TISR_OVF_IT_FLAG); // clear timer interrupt flag
        HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TIER) |= (DMTIMER_1MS_TIER_OVF_IT_ENA
                                                            & (DMTIMER_1MS_TIER_OVF_IT_ENA_ENB_OVF << DMTIMER_1MS_TIER_OVF_IT_ENA_SHIFT));   // Enable interrupt at timer level
    }

     

    Now I have the requested 1ms.

    But why? What is too slow or what is too fast?

    An other question:

    Are the settings for TPIR and TNIR are correct.  

        HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TPIR) = 0x00038A40; //232000;
        HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TNIR) = 0xFFF44800; //-768000;
        HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TLDR) = 0xFFFFFFE0;

    regards Tobias

     

  • Tobias, did you ever get this DMTimer1_1ms working?  I am having alot of problems getting it to work.  Firstly, I created a project and had the timer and interrupts working after a fashion using DMTimer2.  I did not use Starterware code, but am not averse to using specific api's out of it, if it makes the project easier.  I need to keep my code absolutely as stripped down as is possible so I don't want to pull in anything that I don't absolutely need. 

    Anyhow, after I had the timer and interrupts working with dmtimer2 I tried to change over to dmtimer1ms and set the proper base and offset register values to get it to initialize. But the problem I am having is that my project hangs whenever I try to read or write an address that is an offset of the dmtimer1ms, such as TCRR, TCLR, etc. I am running in Supervisor mode, which can be seen by reading the CPSR. 

    Why are the registers unable to be read?  I have scoured the documentation on dmtimer1ms and don't see anything that states anything other than being in a privileged mode, but I am obviously missing something.  

    I am loading and starting my program at 0x80000000.  What am I missing?

  • Hello

    my DMTimer1 is running with 1ms second but I need the disable and enable the interrupts to get the 1ms.

    I don't know how your registers are unreadable.

    Please have also a look to

    http://e2e.ti.com/support/embedded/starterware/f/790/p/324735/1145753.aspx#1145753

    There is a pitfall with the external 32KHz clock, by default the inputs of the external oscillator are driven to high impedance from the RTC.

    regards Tobias

     

     

  • Hello

    to sum up the problem

    here my working code

    void init_timer1_1ms()
    {
    unsigned int regVal;
    
        // init External 32k Clock
        RTCWriteProtectDisable(SOC_RTC_0_REGS); // enable access to RTC registers
        RTCOscillatorStateControl(SOC_RTC_0_REGS, RTC_32KOSC_ENABLE); // enable the External Oscillator
        // if this is not done the Oscillator outputs would be driven to High Impedance by Reset
        RTCWriteProtectEnable(SOC_RTC_0_REGS); // disable access to RTC registers
    
        // init clock
        HWREG(SOC_CM_DPLL_REGS + CM_DPLL_CLKSEL_TIMER1MS_CLK) &=
                                             ~(CM_DPLL_CLKSEL_TIMER1MS_CLK_CLKSEL); // reset the clock
    
        while((HWREG(SOC_CM_DPLL_REGS + CM_DPLL_CLKSEL_TIMER1MS_CLK)
               & CM_DPLL_CLKSEL_TIMER1MS_CLK_CLKSEL) != 0x0); // wait for clock reset
    
        HWREG(SOC_CM_DPLL_REGS + CM_DPLL_CLKSEL_TIMER1MS_CLK) = CM_DPLL_CLKSEL_TIMER1MS_CLK_CLKSEL_SEL5; // set to external 32KHz clock
        while((HWREG(SOC_CM_DPLL_REGS + CM_DPLL_CLKSEL_TIMER1MS_CLK)
               & CM_DPLL_CLKSEL_TIMER1MS_CLK_CLKSEL) != CM_DPLL_CLKSEL_TIMER1MS_CLK_CLKSEL_SEL5); // wait for setting
        HWREG(SOC_CM_WKUP_REGS + CM_WKUP_TIMER1_CLKCTRL) |=
                                      CM_WKUP_TIMER1_CLKCTRL_MODULEMODE_ENABLE; // enable Timer1 module
    
        while((HWREG(SOC_CM_WKUP_REGS + CM_WKUP_TIMER1_CLKCTRL)
                & CM_WKUP_TIMER1_CLKCTRL_MODULEMODE)
                                       != CM_WKUP_TIMER1_CLKCTRL_MODULEMODE_ENABLE); // wait for enabling
    
        while((HWREG(SOC_CM_WKUP_REGS + CM_WKUP_TIMER1_CLKCTRL)
               & CM_WKUP_TIMER1_CLKCTRL_IDLEST)
                                       != CM_WKUP_TIMER1_CLKCTRL_IDLEST_FUNC);  // wait for timer coming to its fully functionality
        // init interrupt
        IntSystemEnable(SYS_INT_TINT1_1MS);
        IntPrioritySet(SYS_INT_TINT1_1MS, 0, AINTC_HOSTINT_ROUTE_IRQ);
        IntRegister(SYS_INT_TINT1_1MS, ISR_timer1_1ms);
    
        //int tick variable
        ms_time_tick = 0;
    
        // init timer mode and registers
    //    For 1 ms tick with a 32768-Hz clock:
    //    TPIR = 232000
    //    TNIR = -768000
    //    TLDR = 0xFFFFFFE0
        HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TPIR) = 0x00038A40; //232000;
        HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TNIR) = 0xFFF44800; //-768000;
        HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TLDR) = 0xFFFFFFE0;
    
        HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TIER) |= (DMTIMER_1MS_TIER_OVF_IT_ENA
                                                          & (DMTIMER_1MS_TIER_OVF_IT_ENA_ENB_OVF << DMTIMER_1MS_TIER_OVF_IT_ENA_SHIFT));   // Enable interrupt at timer level
    
        HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TCRR) = 0xFFFFFFE0; //set start value of timer
    
        regVal = HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TCLR);
        regVal |= DMTIMER_1MS_TCLR_AR & (DMTIMER_1MS_TCLR_AR_AUTO_REL << DMTIMER_1MS_TCLR_AR_SHIFT); //set auto reload
        regVal |= DMTIMER_1MS_TCLR_ST & (DMTIMER_1MS_TCLR_ST_CNT_START << DMTIMER_1MS_TCLR_ST_SHIFT); // start timer
        HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TCLR)  = regVal; // start timer
    }
    
    
    static void ISR_timer1_1ms(void)
    {
        HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TIER) |= (DMTIMER_1MS_TIER_OVF_IT_ENA
                                                                & (DMTIMER_1MS_TIER_OVF_IT_ENA_DSB_OVF << DMTIMER_1MS_TIER_OVF_IT_ENA_SHIFT));   // Disable interrupt at timer level
        ms_time_tick++;
        HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TISR) = DMTIMER_1MS_TISR_OVF_IT_FLAG; // clear timer interrupt flag
        HWREG(SOC_DMTIMER_1_REGS + DMTIMER_1MS_TIER) |= (DMTIMER_1MS_TIER_OVF_IT_ENA
                                                            & (DMTIMER_1MS_TIER_OVF_IT_ENA_ENB_OVF << DMTIMER_1MS_TIER_OVF_IT_ENA_SHIFT));   // Enable interrupt at timer level
    }

    Tobias

  • I got that code to run, and the counter value is changing, but the interrupts apparently aren't, because the ISR is never getting called.  Do you have any idea what might be causing that to happen?  Like I am pretty confident that the timer is now set up properly, and I don't have any errors, but the handler is not getting called.  

  • Hello

    have you enabled and configured all system interrupts?

    IntAINTCInit();         // init interrupts
    IntMasterIRQEnable(); // enable interrupts

    regards Tobias

     

  • Thanks, I got it working, although I am using another way to set up the interrupt vector table.  I think that was part of my problem.  I am not using Starterware because of the need for a super slim code base, so if I use any of their api's I have to pull them in piece by piece, which is a process. 

  • Obviously there is something wrong with the 1ms Timer module.

    The reference manual values are correct:

    TPIR = 232000

    TNIR = -768000

    TLDR = 0xFFFFFFE0

    My observations:

    If you clear the overflow flag too early (DMTIMER_1MS_TISR_OVF_IT_FLAG), it looks like the interrupt is fired twice. That's why Tobias is getting the 0.5ms interrupt interval.

    However, if you put some code before you clear the overflow flag (let's say loop 4000 times and do nothing), the interrupt interval is exactly 1ms.

    @TI: What's the problem with the 1ms Timer module?

  • TI, could you please reply regarding my observations with the 1ms Timer module?

  • I'm not TI, but we found two bugs in the DMTimer 1ms module. Here's what we found and did to workaround them.

    1. This hardware bug appears in the 1-ms tick generation section of the GPTIMER blocks on some OMAP3530 chips.  TOCR is sometimes incremented when a timer overflow event occurs and TPIR = TPNR = TOWR = TOCR = 0, in contradiction of AM335x TRM SPRUH73J Section 20.2.3.1.1. (The kernel currently relies on overflow interrupts to generate ticks and drive the scheduler.)  When TOCR is incremented under these conditions, the timer will not generate any further overflow interrupts until the value in TOCR again matches the value in TOWR (0). Since TOCR is a 24 bit register, and its value is incremented at a 1ms rate, (interval of DMTimer 1ms) interrupts are effectively masked for a period of ~4.66 hours. (See http://permalink.gmane.org/gmane.comp.handhelds.openembedded.scm/5245section)

    Workaround:  The TOCR register is explicitly cleared on every DMTimer 1ms interrupt during the Periodic1ms() ISR function.

           2.  If a General Purpose Timer (GPTimer) is in posted mode (TSICR [2].POSTED=1), due to internal resynchronizations, values read in TCRR, TCAR1 and TCAR2 registers right after the timer interface clock (L4) goes from stopped to active may not return the expected values. GPTimer non-posted synchronization mode is not impacted by this limitation (see http://arago-project.org/git/projects/?p=linux-am33x.git;a=commit;h=506c079b8421c901cbf81ebd4c8c27f1315dc769).

    Solution:  This bug was observed when referencing the external 32K oscillator (CLK_32K_RTC), but it does not appear to affect the DMTimer 1ms module when using the PER PLL generated 32.768 KHz (CLK_32KHZ) clock source. For this reason CLK_32KHZ is used. This was deemed a better solution than using non-posted mode, as utilizing non-posted mode has a negative performance impact.