Hi,
Can anyone share a basic example of a SAMD21 TC count function which has a BPM of 120 (4/4) and a duty cycle of 50%. With both the BPM and duty cycle values updatable.
- Beats-per-minute: 120 BPM
- Beats-per-second: 2 Hz
- Length of 1 beat: 0.5 second
- Length of 1 bar: 2 second
Reference link: BPM calculator
The BPM and Duty Cycle would be updated using two rotary encoders. The output would be 0-3.3v via a jack socket to control a Eurorack Modular synth.
Background:
I've been working with a NANO 33 IoT and have had multiple issues with timers when transferring code from a UNO/MEGA. Because of this I think it’s time to learn and how to use the internal timers (TC) on the SAM D21 platform. The code Markus Bader supplied in post #8 of this thread helped a lot (link below):
/*
Testing with Arduino NANO 33 IoT
@author Markus Bader
@brief this program shows how to use the TC timer with interrupts on an Arduino Zero board
@email markus.bader@tuwien.ac.at
https://forum.arduino.cc/index.php?topic=332275.0
Post: #8
*/
int pin_ovf_led = 2; // debug pin for overflow led
int pin_mc0_led = 5; // debug pin for compare led
unsigned int loop_count = 0;
unsigned int irq_ovf_count = 0;
void setup() {
pinMode(pin_ovf_led, OUTPUT); // for debug leds
digitalWrite(pin_ovf_led, LOW); // for debug leds
pinMode(pin_mc0_led, OUTPUT); // for debug leds
digitalWrite(pin_mc0_led, LOW); // for debug leds
// Enable clock for TC
REG_GCLK_CLKCTRL = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID_TCC2_TC3) ;
while ( GCLK->STATUS.bit.SYNCBUSY == 1 ); // wait for sync
// The type cast must fit with the selected timer mode
TcCount16* TC = (TcCount16*) TC3; // get timer struct
TC->CTRLA.reg &= ~TC_CTRLA_ENABLE; // Disable TC
while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync
TC->CTRLA.reg |= TC_CTRLA_MODE_COUNT16; // Set Timer counter Mode to 16 bits
while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync
TC->CTRLA.reg |= TC_CTRLA_WAVEGEN_NFRQ; // Set TC as normal Normal Frq
while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync
TC->CTRLA.reg |= TC_CTRLA_PRESCALER_DIV256; // Set perscaler (1,2,4,8,64,256,1024)
//TC->CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1024; // Set perscaler
while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync
// TC->PER.reg = 0xFF; // Set counter Top using the PER register but the 16/32 bit timer counts allway to max
// while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync
TC->CC[0].reg = 0xFFF;
while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync
// Interrupts
TC->INTENSET.reg = 0; // disable all interrupts
TC->INTENSET.bit.OVF = 1; // enable overfollow
TC->INTENSET.bit.MC0 = 1; // enable compare match to CC0
// Enable InterruptVector
NVIC_EnableIRQ(TC3_IRQn);
// Enable TC
TC->CTRLA.reg |= TC_CTRLA_ENABLE;
while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync
}
void loop() {
// dummy
delay(500);
}
void TC3_Handler()
{
TcCount16* TC = (TcCount16*) TC3; // get timer struct
if (TC->INTFLAG.bit.OVF == 1) { // A overflow caused the interrupt
digitalWrite(pin_ovf_led, irq_ovf_count % 2); // for debug leds
digitalWrite(pin_mc0_led, HIGH); // for debug leds
TC->INTFLAG.bit.OVF = 1; // writing a one clears the flag ovf flag
irq_ovf_count++; // for debug leds
}
if (TC->INTFLAG.bit.MC0 == 1) { // A compare to cc0 caused the interrupt
digitalWrite(pin_mc0_led, LOW); // for debug leds
TC->INTFLAG.bit.MC0 = 1; // writing a one clears the flag ovf flag
}
}
https://forum.arduino.cc/index.php?topic=332275.0
Also the official documentation (Atmel-42123-SAM-Timer-Counter-(TC)-Driver_ApplicationNote_AT03263) is worth reading and having to hand. So now I understand some of the terminology and methods but its still confusing.
To my project is based on the SM Tik Tak BPM Clock with CV (control voltage) outputs. With the addition of rotary encoders and OLED display. For this to work effectively the timer count needs to be the primary function and cannot be blocked by any other activity (encoders, display updates, etc). The original project used a timer library but this is not compatible with the SAM D21 platform.
This is a simple project which could be used as a basis for multiple Eurorack modules.
Circuit components:
- NANO 33 IoT
- BPM rotary encoder
- Duty Cycle rotary encoder
- BPM out, 3.5mm jack socket
- Half division out, jack socket
- Quarter division out, jack socket
- Eighth division out, jack socket
- OLED display (BPM, Duty Cycle, Divisions)
The circuit is built and tested.