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.

Timer match interrupt in periodic mode

Hello. I use LM3S9b90 microcontroller. I want to generate interrupt in periodic timer mode each time when the timer value equals the timer match register. Corresponding the datasheet this should work:

11.3.2.1 One-Shot/Periodic Timer Mode

In addition to reloading the count value, the GPTM generates interrupts and triggers when it reaches the time-out event... By setting the TnMIE bit in the GPTMTnMR register, an interrupt condition can also be generated when the Timer value equals the value loaded into the GPTM Timer n Match (GPTMTnMATCHR) and GPTM Timer n Prescale Match (GPTMTnPMR) registers.

But my code doesn't work well. It looks as follows:

void Timer0AIntHandler()
{
  TimerIntClear(TIMER0_BASE, TIMER_CAPA_MATCH);

  uint32_t val = GPIOPinRead(GPIO_PORTD_BASE, GPIO_PIN_4);
  val = ~val;
  val = val & GPIO_PIN_4;
  GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_4, val);
}

int main()
{
  SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
  GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_4);
  SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
  TimerConfigure(TIMER0_BASE, TIMER_CFG_32_BIT_PER);

  uint32_t const freq = SysCtlClockGet(); // freq = 80 000 000 = 80MHz
  uint32_t const period = freq; // Overflow period = 1 sec
  TimerLoadSet(TIMER0_BASE, TIMER_A, period);
  uint32_t const pulse_width = period / 2; // Match value = 0.5 sec
  TimerMatchSet(TIMER0_BASE, TIMER_A, pulse_width);

  IntMasterEnable();
  TimerIntRegister(TIMER0_BASE, TIMER_A, Timer0AIntHandler);
  TimerIntEnable(TIMER0_BASE, TIMER_CAPA_MATCH);
  IntEnable(INT_TIMER0A);
  TimerEnable(TIMER0_BASE, TIMER_A);

  while (true)
  {
  }
}

I expect the handler will be called each second, but it happens much more often. It looks like I forgot to clear interrupt bit, but I did.

  • Hi,

    How "much more often"? if it is 0.5 sec, then quoting you:

    an interrupt condition can also be generated when the Timer value equals the value loaded into the GPTM Timer n Match

    so what was your setting?

    Petrei

  • I didn't measure the period, but it is not 0.5 sec. I connected a LED to the pin, so I can not recognise the blinking of the LED. Hence, it is not more than 1/30 sec.

    Furthermore, I allowed the only match case interruption

    TimerIntEnable(TIMER0_BASE, TIMER_CAPA_MATCH);

    So, the period (half period) should be 1 sec.

    P.S. If I use the overflow interruption handler instead of match interruption, this code works well.

  • Hi,

    Please specify your driverlib version - there are some modifications/improvement in the lasts (checked starting with 9453) - if counting up you must specify configuration as TIMER_CFG_PERIODIC_UP.

    And please replace the eye with a real measuring instrument (oscilloscope) - depends on person (my colleague could not discern a short LED blink followed by a "normal" one - was generated by a buggy restart…)

    Petrei

  • Petrei, thank you for your help. It looks like I found a workaround. This doesn't work with 32 bit timer (don't know why), but it works with 16 bit timer.

    So, the following code works correct

    void Timer0AIntHandler()
    {
      // TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
      TimerIntClear(TIMER0_BASE, TIMER_CAPA_MATCH);
    
      uint32_t val = GPIOPinRead(GPIO_PORTD_BASE, GPIO_PIN_4);
      val = ~val;
      val = val & GPIO_PIN_4;
      GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_4, val);
    }
    
    int main()
    {
      SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
      SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
      GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_4);
      SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
      TimerConfigure(TIMER0_BASE, TIMER_CFG_16_BIT_PAIR | TIMER_CFG_A_PERIODIC);
    
      uint32_t const freq = SysCtlClockGet(); // freq = 80 000 000 = 80MHz
    
      TimerPrescaleSet(TIMER0_BASE, TIMER_A, 0xFF);
      TimerPrescaleMatchSet(TIMER0_BASE, TIMER_A, 0xFF);
      TimerLoadSet(TIMER0_BASE, TIMER_A, 0xFFFF); // Period = 255 * 65535 / freq = 0.25 sec
      TimerMatchSet(TIMER0_BASE, TIMER_A, 0xFFFF / 2); // PulseWidth = Period / 2 = 0.125 sec
    
      IntMasterEnable();
      TimerIntRegister(TIMER0_BASE, TIMER_A, Timer0AIntHandler);
      // TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
      TimerIntEnable(TIMER0_BASE, TIMER_CAPA_MATCH);
      IntEnable(INT_TIMER0A);
      TimerEnable(TIMER0_BASE, TIMER_A);
    
      while (true)
      {
        SysCtlDelay(freq);
      }
    }
    

    Furthermore, both the timeout and match interrupts work correct (if I uncomment the lines).

    How to determine in Timer0AIntHandler handler which of 2 actions happened? Can I check an interrupt flag?

    P.S. driverlib revision is 10636.

  • Hi,

    Use this function inside interrupt to read the status into a variable:

    uint32_t TimerIntStatus(uint32_t ui32Base, bool bMasked);

    then check that variable: if (var&TIMER_TIMA_MATCH == TIMER_TIMA_MATCH) do xx;

    Read also the driverlib code...

    If you like to toggle a pin into interrupt, simpler way is this, if you make val static (one line only):

    GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_4, val^=GPIO_PIN_4);

    Petrei

  • Petrei said:
    And please replace the eye with a real measuring instrument (oscilloscope)

    Classic - and "so" needed to be said.  (although technically - you're "augmenting" the eye...)

    And - you added: "If you like to toggle a pin into interrupt, simpler way is this, if you make val static (one line only):"

    GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_4, val^=GPIO_PIN_4);

    That's good stuff Petrei...  (once again)