login

Author Topic: WHardwareTimer.h  (Read 1954 times)

0 Members and 1 Guest are viewing this topic.

pabloxid

WHardwareTimer.h
« on: October 08, 2014, 11:19:21 AM »
I've spent years programming in Arduino/Wiring environments, and every time I have to do something that involves the use of timers/counters, I ended up losing hours looking at the Atmega datasheet and implementing the same code over and over again.

Recently I decided to use WHardwareTimer.h which is, in fact, the only library that exists worldwide to handle AVR timers.

The problem is that it lacks documentation, it's not even commented the code itself, which is a real shame.

My question then is: how to use setMode and setOutputMode methods? What is supposed to pass as parameters?

Thank you in advance.

Regards,
P.G.

bhagman

Re: WHardwareTimer.h
« Reply #1 on: October 20, 2014, 03:01:13 PM »
Yes, the reason it seems unfinished is because the way the hardware timers were being built originally were very Atmel AVR-centric, which led to a lot of AVR-isms.  We've been working on developing the Wiring Framework to be target independent, and as such, the settings for the hardware timers in the AVR series differ from other controllers.

As I built out the WHardwareTimer library, I started realizing that it was not going to go away from the the AVR-isms, so I ended up half-finishing the setMode and other register management functions.

But, in a nutshell, setMode writes to the WGM (Waveform Generation Mode) bits of the AVR 8 bit series TCCR (Timer/Counter Control Register).

Have a look at the HardwareTimer::setMode() function to see exact details:

Code: [Select]
void HardwareTimer::setMode(uint8_t mode)
{
  // WGMn3 and WGMn2 are in positions 4 and 3, respectively, in TCCRnB
  // WGMn1 and WGNn0 are in positions 1 and 0, respectively, in TCCRnA

  // For devices with global TIMSK, 8 bit timers have:
  // WGMn0 in position 6 of TCCRn register
  // WGMn1 in position 3 of TCCRn register

#if defined (TIMSK)
  if (_timerNumber == 0 || _timerNumber == 2)
  {
    // only a single control register on these devices (TCCRn)
    *_tccrna = (*_tccrna & 0b10110111)
                 | ((mode & 0b00000001) << 6)
                 | ((mode & 0b00000010) << 2);
  }
  else
  {
    // everything else conforms (the two control registers for the WGM)
#endif
  *_tccrna = (*_tccrna & 0b11111100) | (mode & 0b00000011);
  *_tccrnb = (*_tccrnb & 0b11100111) | ((mode & 0b00001100) << 1);
#if defined (TIMSK)
  }
#endif
}

The same applies to setOutputMode - which sets the COM (Compare Output Mode) bits of the TCCR register:

Code: [Select]
void HardwareTimer::setOutputMode(uint8_t channel, uint8_t outputMode)
{
  uint8_t COMbitMask = 0b11;
  uint8_t shiftCount;

  outputMode &= 0b11;  // only 4 modes

  if (channel < _channelCount)
  {
    if ((_timerNumber == 0 || _timerNumber == 2) && _channelCount == 1)
    {
      // 8 bit timers with only 1 OCR
      shiftCount = COMn0;
    }
    else
    {
      // 16 bit timers
      if (channel == CHANNEL_A)
        shiftCount = COMnA0;
      else if (channel == CHANNEL_B)
        shiftCount = COMnB0;
      else if (channel == CHANNEL_C)
        shiftCount = COMnC0;
    }

    COMbitMask <<= shiftCount;
    outputMode <<= shiftCount;

    *_tccrna = (*_tccrna & ~(COMbitMask)) | outputMode;
  }
}

I'd like to develop the HardwareTimer class into a cross-platform Framework class, such that the functions we use are generic enough to apply to any target controller.  I know that there will still be specific functions that will need to be supported, and may be handled by platform specific functions (i.e. incompatible), but target independent is what I'd personally like to shoot for.

As always, any help in designing and defining the Framework would be greatly appreciated.

pabloxid

Re: WHardwareTimer.h
« Reply #2 on: November 15, 2014, 01:39:07 AM »
Hi Brett, thank you for your response.

I think the only thing missing from this library is a set of #defines for modes and output modes, as there exist for prescalers and interrupts. For example, in my application I used the following:

Timer2.setClockSource (CLOCK_NO_PRESCALE);
Timer1.setClockSource (CLOCK_PRESCALE_8);
Timer1.attachInterrupt (INTERRUPT_COMPARE_MATCH_A, timer1IntHandler);

Timer2.setMode (0b0100);   // CTC mode
Timer1.setMode (0);        // Normal counting mode (0->2^16)
Timer2.setOutputMode (CHANNEL_A, 1);
etc.

These values I obtained by looking into the Wiring code, at sections where WHardwareTimer.h was used. Then I could define:

#define MODE_CTC              0b0100
#define MODE_NORMAL_COUNTING  0
#define OUTPUTMODE_ENABLE     1
etc.

But I really don't feel fully qualified to complete this work and to remain consistent with the style of the rest of the library.

Regards,
P.G.