D21G timer library

How to use the Industruino D21G hardware timers

Tom

The Industruino's D21G MCU belongs to the SAMD21G family of 32 bit ARM Cortex M0 microcontrollers. The Arduino Zero board has the same ATSAMD21G18 chip, but the pin mapping is slightly different. For most applications and libraries this is not relevant, but for some features, such as timers, there are minor differences that should be taken into account. This blog post explains how to use timers on the Industruino D21G, based on an earlier version (1.0.0) of the Adafruit_ZeroTimer library (written for Arduino Zero) available here, and the extra layer of the avdweb_SAMDtimer library that makes it very easy to use these timer functions:

  • attach an ISR (interrupt service routine) to a timer
  • generate PWM on specific timer output pins (PROTO only)

First install the above libraries. (If you'd rather use the latest version of the Adafruit_ZeroTimer library, you will have to find out what needs to be changed based on the below info).

As mentioned, the pin mapping is slightly different for the Industruino D21G, so we have to edit the Adafruit_ZeroTimer.cpp library file (in sketchbook/libraries).

  1. in line 31, change pin 12 to pin 0 (the Industruino D21G has timer 3 on D0 instead of D12)
  2. comment out 4 lines 45-49 (the Industruino D21G does not use pin A1) - you can add // in front of the line to achieve this
  3. in line 56, change pin A2 to pin 6 (the Industruino D21G does not use A2 and has timer 4 on D6)

Now you can use 3 16-bit timers with the avdweb_SAMDtimer library, for this functionality:

  • timer3 with interrupt (ISR) and with PWM output on D0 (if you do not use it for Serial)
  • timer4 with interrupt (ISR) and with PWM output on D6
  • timer5 with interrupt (ISR)

Example of constructors for that avdweb_SAMDtimer library:

  • SAMDtimer timer3_10Hz = SAMDtimer(3, ISR_timer3_LED1 , 1e5); // timer 3 with 10Hz interrupt routine
  • SAMDtimer timer3_1Hz = SAMDtimer(3, TC_COUNTER_SIZE_16BIT, 0, 1e6, 9e5); // timer 3 on D0 with 1Hz, pulse width 0.9s
  • SAMDtimer timer4_2Hz = SAMDtimer(4, TC_COUNTER_SIZE_16BIT, 6, 5e5, 1e5); // timer 4 on D6 with 2Hz, pulse width 20% 
  • SAMDtimer timer5_1Hz = SAMDtimer(5, ISR_timer5_LED2 , 1e6); // timer 5 with 1Hz interrupt routine
The PWM output on D0 and D6 is available on the PROTO's terminals (and to be complete, also on the 14-pin PROTO and INDIO IDC connector).
On the INDIO, the output channels can be manipulated with ISR (see code below).
Please note that we did not test the Adafruit_ZeroTimer functionality beyond what is used in below examples based on the avdweb_SAMDtimer library.

Code example (tested on PROTO, generating signals on D4, D0, D6, and the LCD backlight)

/*
   TIMER library example for Industruino D21G

   Arduino Zero timer library https://github.com/adafruit/Adafruit_ZeroTimer/
   simplified library http://www.avdweb.nl/arduino/libraries/samd21-timer.html
   simple example below

   Necessary modifications to Adafruit_ZeroTimer.cpp:
   >> in line 31, change pin 12 to pin 0 (the Industruino D21G has timer 3 on D0 instead of D12)
   >> comment out 4 lines 45-49 (the Industruino D21G does not use pin A1)
   >> in line 56, change pin A2 to pin 6 (the Industruino D21G does not use A2 and has timer 4 on D6)

   Industruino D21G timer functionality:
   >> timer3 with interrupt and with output on D0 (if you do not use it for Serial)
   >> timer4 with interrupt and with output on D6
   >> timer5 with interrupt
   Note: D0 and D6 are available on the terminals of the PROTO platform (and on the IDC connector of both PROTO and INDIO)
   
   Tom Tobback Oct 2017
*/

#include <Arduino.h>
#include "avdweb_SAMDtimer.h"

const byte LED1   = 26;  // D21G LCD backlight or any other pin
const byte LED2   = 4;   // D21G D4 or any other pin

void ISR_timer3_LED1(struct tc_module *const module_inst)
{ static bool b;
  pinMode(LED1, OUTPUT);
  digitalWrite(LED1, b = !b);
}

void ISR_timer5_LED2(struct tc_module *const module_inst)
{ static bool b;
  pinMode(LED2, OUTPUT);
  digitalWrite(LED2, b = !b);
}

// ------------- Timer3 with output on D0 and/or interrupt -------------
SAMDtimer timer3_1Hz = SAMDtimer(3, ISR_timer3_LED1 , 1e6); // timer 3 with 1Hz interrupt (PWM 50% default)
//   SAMDtimer timer3_1Hz = SAMDtimer(3, TC_COUNTER_SIZE_16BIT, 0, 1e6, 9e5); // timer 3 on D0 with 1Hz pulse -- also attach 1Hz interrupt, see below

// ------------- Timer4 with output on D6 and/or interrupt -------------
// SAMDtimer timer4_2Hz = SAMDtimer(4, ISR_timer4_LED2, 5e5, 0); // timer 4 with 2Hz interrupt, disabled
SAMDtimer timer4_2Hz = SAMDtimer(4, TC_COUNTER_SIZE_16BIT, 6, 5e5, 1e5); // timer 4 on D6 with 1Hz, pulse width 0.9s

// ------------- Timer5 with interrupt -------------
SAMDtimer timer5_10Hz = SAMDtimer(5, ISR_timer5_LED2 , 1e5); // timer 5 with 10Hz interrupt

void setup() // test out the several functions:
{ // ------------- timer3 -------------
  // timer3_1Hz.enableTimer(1); // enable timer *1), LED4 blinks again
  // timer3_1Hz.setPulseWidth(1e5); // change pulse width to 0.1s

  // attach a new ISR to a timer with output, this can't be done in the constructor
  timer3_1Hz.attachInterrupt(ISR_timer3_LED1); // LCD backlight blinks
  // timer3_1Hz.attachInterrupt(ISR_timer3_LED1, 0); // the same but ISR is disabled, the timer-output is not disabled

  // ------------- timer4 -------------
  // timer4_2Hz.enableInterrupt(0); // disable ISR_timer4_LED2, LED2 stops blinking
  // timer4_2Hz.enableInterrupt(1); // enable ISR_timer4_LED2, LED2 blinks again *2)

}

void loop()
{
  timer3_1Hz.enableTimer(0);            // all timers off
  timer4_2Hz.enableTimer(0);
  timer5_10Hz.enableTimer(0);
  delay(5000);

  timer3_1Hz.enableTimer(1);            // start timer3 1Hz -- PWM on D0 (default 50%)
  timer3_1Hz.enableInterrupt(0);        // ISR off
  delay(5000);
  timer3_1Hz.enableInterrupt(1);        // ISR on
  delay(5000);

  timer4_2Hz.enableTimer(1);            // start timer4 2Hz -- PWM on D6
  timer4_2Hz.setPulseWidth(1e5);        // 20%
  delay(5000);
  timer4_2Hz.setPulseWidth(4e5);        // 80%
  delay(5000);

  timer5_10Hz.enableTimer(1);           // start timer5 10Hz -- ISR on
  delay(5000);
}

Code for Indio (Digital Output channel 1 and 2)

/*
   TIMER library example for Industruino D21G

   Arduino Zero timer library https://github.com/adafruit/Adafruit_ZeroTimer/
   simplified library http://www.avdweb.nl/arduino/libraries/samd21-timer.html
   simple example below

   Necessary modifications to Adafruit_ZeroTimer.cpp:
   >> in line 31, change pin 12 to pin 0 (the Industruino D21G has timer 3 on D0 instead of D12)
   >> comment out 4 lines 45-49 (the Industruino D21G does not use pin A1)
   >> in line 56, change pin A2 to pin 6 (the Industruino D21G does not use A2 and has timer 4 on D6)

   Industruino D21G timer functionality:
   >> timer3 with interrupt and with output on D0 (if you do not use it for Serial)
   >> timer4 with interrupt and with output on D6
   >> timer5 with interrupt
   Note: D0 and D6 are available on the terminals of the PROTO platform (and on the IDC connector of both PROTO and INDIO)
   
   Tom Tobback Oct 2017
*/

#include <Indio.h>
#include <Wire.h>

#include <Arduino.h>
#include "avdweb_SAMDtimer.h"

void ISR_timer3_CH1(struct tc_module *const module_inst)
{ static bool b;
  Indio.digitalWrite(1, b = !b);
}

void ISR_timer5_CH2(struct tc_module *const module_inst)
{ static bool b;
  Indio.digitalWrite(2, b = !b);
}

// ------------- Timer3 with output on D0 and/or interrupt -------------
SAMDtimer timer3_1Hz = SAMDtimer(3, ISR_timer3_CH1 , 1e6); // timer 3 with 1Hz interrupt 

// ------------- Timer5 with interrupt -------------
SAMDtimer timer5_10Hz = SAMDtimer(5, ISR_timer5_CH2 , 1e5); // timer 5 with 10Hz interrupt

void setup() // test out the several functions:
{ 
  Indio.digitalMode(1, OUTPUT);
  Indio.digitalMode(2, OUTPUT);
  Indio.digitalWrite(1, LOW);
  Indio.digitalWrite(2, LOW);
}

void loop()
{
  timer3_1Hz.enableTimer(0);            // all timers off
  timer5_10Hz.enableTimer(0);
  delay(5000);

  timer3_1Hz.enableTimer(1);            // start timer3 1Hz -- ISR CH1
  delay(5000);

  timer5_10Hz.enableTimer(1);           // start timer5 10Hz -- ISR CH2
  delay(5000);
}