Mikanum/IRremote/sam.cpp
2023-01-19 08:45:51 +01:00

102 lines
2.8 KiB
C++

// Support routines for SAM processor boards
#include "IRremote.h"
#include "IRremoteInt.h"
#if defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD)
// "Idiot check"
#ifdef USE_DEFAULT_ENABLE_IR_IN
#error Must undef USE_DEFAULT_ENABLE_IR_IN
#endif
//+=============================================================================
// ATSAMD Timer setup & IRQ functions
//
// following based on setup from GitHub jdneo/timerInterrupt.ino
static void setTimerFrequency(int frequencyHz)
{
int compareValue = (SYSCLOCK / (TIMER_PRESCALER_DIV * frequencyHz)) - 1;
//Serial.println(compareValue);
TcCount16* TC = (TcCount16*) TC3;
// Make sure the count is in a proportional position to where it was
// to prevent any jitter or disconnect when changing the compare value.
TC->COUNT.reg = map(TC->COUNT.reg, 0, TC->CC[0].reg, 0, compareValue);
TC->CC[0].reg = compareValue;
//Serial.print("COUNT.reg ");
//Serial.println(TC->COUNT.reg);
//Serial.print("CC[0].reg ");
//Serial.println(TC->CC[0].reg);
while (TC->STATUS.bit.SYNCBUSY == 1);
}
static void startTimer()
{
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
TcCount16* TC = (TcCount16*) TC3;
TC->CTRLA.reg &= ~TC_CTRLA_ENABLE;
while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync
// Use the 16-bit timer
TC->CTRLA.reg |= TC_CTRLA_MODE_COUNT16;
while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync
// Use match mode so that the timer counter resets when the count matches the compare register
TC->CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ;
while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync
// Set prescaler to 1024
//TC->CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1024;
TC->CTRLA.reg |= TC_CTRLA_PRESCALER_DIV64;
while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync
setTimerFrequency(1000000 / USECPERTICK);
// Enable the compare interrupt
TC->INTENSET.reg = 0;
TC->INTENSET.bit.MC0 = 1;
NVIC_EnableIRQ(TC3_IRQn);
TC->CTRLA.reg |= TC_CTRLA_ENABLE;
while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync
}
//+=============================================================================
// initialization
//
void IRrecv::enableIRIn()
{
// Interrupt Service Routine - Fires every 50uS
//Serial.println("Starting timer");
startTimer();
//Serial.println("Started timer");
// Initialize state machine variables
irparams.rcvstate = STATE_IDLE;
irparams.rawlen = 0;
// Set pin modes
pinMode(irparams.recvpin, INPUT);
}
void irs(); // Defined in IRRemote as ISR(TIMER_INTR_NAME)
void TC3_Handler(void)
{
TcCount16* TC = (TcCount16*) TC3;
// If this interrupt is due to the compare register matching the timer count
// we toggle the LED.
if (TC->INTFLAG.bit.MC0 == 1) {
TC->INTFLAG.bit.MC0 = 1;
irs();
}
}
#endif // defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD)