diff --git a/DueTimer.cpp b/DueTimer.cpp index 5349a8d..bbf3ec5 100644 --- a/DueTimer.cpp +++ b/DueTimer.cpp @@ -13,15 +13,17 @@ #include "DueTimer.h" const DueTimer::Timer DueTimer::Timers[NUM_TIMERS] = { - {TC0,0,TC0_IRQn}, - {TC0,1,TC1_IRQn}, - {TC0,2,TC2_IRQn}, - {TC1,0,TC3_IRQn}, - {TC1,1,TC4_IRQn}, - {TC1,2,TC5_IRQn}, - {TC2,0,TC6_IRQn}, - {TC2,1,TC7_IRQn}, - {TC2,2,TC8_IRQn}, + {TC0,0,TC0_IRQn, PIOB, PIO_PER_P25, PIO_PERIPH_B, PIOB, PIO_PER_P27, PIO_PERIPH_B, PIOB, PIO_PER_P26, PIO_PERIPH_B}, + {TC0,1,TC1_IRQn, PIOA, PIO_PER_P2 , PIO_PERIPH_A, PIOA, PIO_PER_P3 , PIO_PERIPH_A, PIOA, PIO_PER_P4, PIO_PERIPH_A}, + {TC0,2,TC2_IRQn, PIOA, PIO_PER_P5 , PIO_PERIPH_A, PIOA, PIO_PER_P6 , PIO_PERIPH_A, PIOA, PIO_PER_P7, PIO_PERIPH_A}, + + {TC1,0,TC3_IRQn, PIOB, PIO_PER_P0 , PIO_PERIPH_B, PIOB, PIO_PER_P1 , PIO_PERIPH_B, PIOA, PIO_PER_P22, PIO_PERIPH_B}, + {TC1,1,TC4_IRQn, PIOB, PIO_PER_P2 , PIO_PERIPH_B, PIOB, PIO_PER_P3 , PIO_PERIPH_B, PIOA, PIO_PER_P23, PIO_PERIPH_B}, + {TC1,2,TC5_IRQn, PIOB, PIO_PER_P4 , PIO_PERIPH_B, PIOB, PIO_PER_P5 , PIO_PERIPH_B, PIOB, PIO_PER_P16, PIO_PERIPH_A}, + + {TC2,0,TC6_IRQn, PIOC, PIO_PER_P25, PIO_PERIPH_B, PIOC, PIO_PER_P26 , PIO_PERIPH_B, PIOC, PIO_PER_P27, PIO_PERIPH_B}, + {TC2,1,TC7_IRQn, PIOC, PIO_PER_P28, PIO_PERIPH_B, PIOC, PIO_PER_P29 , PIO_PERIPH_B, PIOC, PIO_PER_P30, PIO_PERIPH_B}, + {TC2,2,TC8_IRQn, PIOD, PIO_PER_P7 , PIO_PERIPH_B, PIOD, PIO_PER_P8 , PIO_PERIPH_B, PIOD, PIO_PER_P9, PIO_PERIPH_B}, }; // Fix for compatibility with Servo library @@ -42,6 +44,7 @@ const DueTimer::Timer DueTimer::Timers[NUM_TIMERS] = { void (*DueTimer::callbacks[NUM_TIMERS])() = {}; #endif double DueTimer::_frequency[NUM_TIMERS] = {-1,-1,-1,-1,-1,-1,-1,-1,-1}; +uint32_t DueTimer::_statusRegister[NUM_TIMERS] = {0,0,0,0,0,0,0,0}; /* Initializing all timers, so you can use them like this: Timer0.start(); @@ -102,23 +105,29 @@ DueTimer& DueTimer::detachInterrupt(void){ return *this; } +DueTimer& DueTimer::start(void){ + /* + Start the timer + */ + if (callbacks[timer]) { + NVIC_ClearPendingIRQ(Timers[timer].irq); + NVIC_EnableIRQ(Timers[timer].irq); + } + TC_Start(Timers[timer].tc, Timers[timer].channel); + + return *this; +} + DueTimer& DueTimer::start(double microseconds){ /* Start the timer If a period is set, then sets the period and start the timer */ - if(microseconds > 0) setPeriod(microseconds); - if(_frequency[timer] <= 0) setFrequency(1); - - NVIC_ClearPendingIRQ(Timers[timer].irq); - NVIC_EnableIRQ(Timers[timer].irq); - - TC_Start(Timers[timer].tc, Timers[timer].channel); - + start(); return *this; } @@ -127,8 +136,9 @@ DueTimer& DueTimer::stop(void){ Stop the timer */ - NVIC_DisableIRQ(Timers[timer].irq); - + if (callbacks[timer]) { + NVIC_DisableIRQ(Timers[timer].irq); + } TC_Stop(Timers[timer].tc, Timers[timer].channel); return *this; @@ -220,9 +230,12 @@ DueTimer& DueTimer::setFrequency(double frequency){ // Set up the Timer in waveform mode which creates a PWM // in UP mode with automatic trigger on RC Compare // and sets it up with the determined internal clock as clock input. - TC_Configure(t.tc, t.channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | clock); + TC_Configure(t.tc, t.channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_ACPA_SET | TC_CMR_ACPC_CLEAR | TC_CMR_BCPB_SET | TC_CMR_BCPC_CLEAR | TC_CMR_EEVT_XC0| clock); // Reset counter and fire interrupt when RC value is matched: TC_SetRC(t.tc, t.channel, rc); + // Configure RA and RB for a 50% duty cycle + TC_SetRA(t.tc, t.channel, rc >> 1); + TC_SetRB(t.tc, t.channel, rc >> 1); // Enable the RC Compare Interrupt... t.tc->TC_CHANNEL[t.channel].TC_IER=TC_IER_CPCS; // ... and disable all others. @@ -231,33 +244,265 @@ DueTimer& DueTimer::setFrequency(double frequency){ return *this; } +DueTimer& DueTimer::enablePinA() { + // Configure TIOA + + // disable pioa protection (useless but...) + Timers[timer].pioa->PIO_WPMR = 0x50494F00; + + PIO_Configure( + Timers[timer].pioa, + Timers[timer].tioaPeriph, + Timers[timer].tioaBits, + PIO_DEFAULT + ); + return *this; +} +DueTimer& DueTimer::enablePinB() { + // Configure TIOB + + // disable piob protection + Timers[timer].piob->PIO_WPMR = 0x50494F00; + + PIO_Configure( + Timers[timer].piob, + Timers[timer].tiobPeriph, + Timers[timer].tiobBits, + PIO_DEFAULT + ); + return *this; +} +DueTimer& DueTimer::enablePinClock() { + // Configure CLK pin + + // disable pio protection + Timers[timer].piob->PIO_WPMR = 0x50494F00; + + PIO_Configure( + Timers[timer].pioclk, + Timers[timer].tioClkPeriph, + Timers[timer].tioClkBits, + PIO_DEFAULT + ); + return *this; +} + DueTimer& DueTimer::setPeriod(double microseconds){ /* Set the period of the timer (in microseconds) */ - // Convert period in microseconds to frequency in Hz double frequency = 1000000.0 / microseconds; setFrequency(frequency); return *this; } +uint32_t DueTimer::getDutyCycleRX(double percent){ + /* + get the corresponding R of a given duty cycle. + */ + Timer t = Timers[timer]; + uint32_t rc; + // Actual RC + rc = t.tc->TC_CHANNEL[t.channel].TC_RC; + + if (percent>=100.0) rc = 0; else rc = (uint32_t) ((1-percent) * rc); + return rc; +} + +DueTimer& DueTimer::setDutyCycleA(double percent){ + /* + Set the duty cycle of the TIOA + */ + Timer t = Timers[timer]; + TC_SetRA(t.tc, t.channel, getDutyCycleRX(percent)); + return *this; +} + +DueTimer& DueTimer::setDutyCycleB(double percent){ + /* + Set the duty cycle of the TIOB + */ + Timer t = Timers[timer]; + TC_SetRB(t.tc, t.channel, getDutyCycleRX(percent)); + return *this; +} + double DueTimer::getFrequency(void) const { /* Get current time frequency */ - return _frequency[timer]; } double DueTimer::getPeriod(void) const { /* - Get current time period + Get current time period (microsecond) */ + return 1.0e6 / getFrequency(); +} - return 1.0/getFrequency()*1000000; +uint8_t DueTimer::bestCaptureClock(double maxPeriodMicroSeconds, double& resolution, uint32_t& maxPeriodRC){ + /* + Pick the best capture Clock + Timer Definition + TIMER_CLOCK1 MCK / 2 + TIMER_CLOCK2 MCK / 8 + TIMER_CLOCK3 MCK / 32 + TIMER_CLOCK4 MCK /128 + TIMER_CLOCK5 SCLK 32.768Khz + */ + const struct { + uint8_t flag; + uint8_t divisor; + } clockConfig[] = { + { TC_CMR_TCCLKS_TIMER_CLOCK1, 2 }, + { TC_CMR_TCCLKS_TIMER_CLOCK2, 8 }, + { TC_CMR_TCCLKS_TIMER_CLOCK3, 32 }, + { TC_CMR_TCCLKS_TIMER_CLOCK4, 128 } + }; + double tick; // µsecond + double range = 4294967295; // 32 bits + + for (int idx=0; idx<4; idx++) { + tick = 1e6 * (float) clockConfig[idx].divisor / (float) VARIANT_MCK; + if (range * tick > maxPeriodMicroSeconds ) { + resolution = tick; + maxPeriodRC = 1 + (uint32_t) (maxPeriodMicroSeconds / tick); + return clockConfig[idx].flag; + } + } + resolution = tick; + maxPeriodRC = 1 + (uint32_t) (maxPeriodMicroSeconds / tick); + return TC_CMR_TCCLKS_TIMER_CLOCK4; +} + +DueTimer& DueTimer::setCapture(double maxPeriodMicroSeconds){ + + Timer t = Timers[timer]; + double resolution = 0; + uint32_t periodRC = 0xFFFFFFFF; + uint8_t clock; + + // Tell the Power Management Controller to disable + // the write protection of the (Timer/Counter) registers: + pmc_set_writeprotect(false); + // Enable clock for the timer + pmc_enable_periph_clk((uint32_t)t.irq); + + // Find the best clock for the wanted frequency + clock = bestCaptureClock(maxPeriodMicroSeconds, resolution, periodRC); + // store the counter resolution + _frequency[timer] = resolution; + + // Set up the Timer in capture mode + // TIOA : falling edge TC_CMR_LDRA_FALLING + // TIOB : rising edge TC_CMR_LDRB_RISING + // No trigger condition (free run) + + // RA on falling, RB on rising (RB must be loaded after RA) + TC_Configure(t.tc, t.channel, TC_CMR_LDRA_FALLING | TC_CMR_LDRB_RISING | TC_CMR_CPCTRG |clock); + // Enable the LOAD RA,RB,RC and OverFlow Interrupt... + t.tc->TC_CHANNEL[t.channel].TC_IER = (TC_IER_LDRAS | TC_IER_LDRBS | TC_IER_COVFS | TC_IER_CPCS); + // ... and disable all others. + t.tc->TC_CHANNEL[t.channel].TC_IDR = ~(TC_IER_LDRAS | TC_IER_LDRBS | TC_IER_COVFS | TC_IER_CPCS); + + // Max period reset trigger + TC_SetRC(t.tc, t.channel, periodRC); + + // Configure TIOA as input + enablePinA(); + + return *this; +} + +DueTimer& DueTimer::setCounter(void){ + + Timer t = Timers[timer]; + uint32_t mask,reg,clock; + + // Tell the Power Management Controller to disable + // the write protection of the (Timer/Counter) registers: + pmc_set_writeprotect(false); + // Enable clock for the timer + pmc_enable_periph_clk((uint32_t)t.irq); + + // store the counter resolution + _frequency[timer] = 0; + + // configure the block clock selction + switch (t.channel) { + case 0 : mask = TC_BMR_TC0XC0S_Msk; reg = TC_BMR_TC0XC0S_TCLK0; clock = TC_CMR_TCCLKS_XC0; break; // XC0:TCLK0 + case 1 : mask = TC_BMR_TC1XC1S_Msk; reg = TC_BMR_TC1XC1S_TCLK1; clock = TC_CMR_TCCLKS_XC1; break; // XC1:TCLK1 + case 2 : mask = TC_BMR_TC2XC2S_Msk; reg = TC_BMR_TC2XC2S_TCLK2; clock = TC_CMR_TCCLKS_XC2; break; // XC2:TCLK2 + } + t.tc->TC_BMR &= ~mask; + t.tc->TC_BMR |= reg; + + // Set up the Timer in WAVE mode, external clock + TC_Configure(t.tc, t.channel, TC_CMR_WAVE | clock); + // Enable the LOAD RA,RB,RC and OverFlow Interrupt... + t.tc->TC_CHANNEL[t.channel].TC_IER = (TC_IER_COVFS); + // ... and disable all others. + t.tc->TC_CHANNEL[t.channel].TC_IDR = ~(TC_IER_COVFS); + + // Configure Clk Input + enablePinClock(); + + return *this; +} + +double DueTimer::getResolutionMicroSeconds(void) const { + /* + Get current capture resolution + */ + return _frequency[timer]; } +uint32_t DueTimer::statusRegister(void) { + // Get the status register of the timer + //Timer t = Timers[timer]; + //return t.tc->TC_CHANNEL[t.channel].TC_SR; + return _statusRegister[timer]; +} +uint32_t DueTimer::counterValue(void) { + // Get the value of the counter + Timer t = Timers[timer]; + return t.tc->TC_CHANNEL[t.channel].TC_CV; +} +uint32_t DueTimer::captureValueA(void) { + // Get the value of the RegA register of the timer + Timer t = Timers[timer]; + return t.tc->TC_CHANNEL[t.channel].TC_RA; +} +uint32_t DueTimer::captureValueB(void) { + // Get the value of the RegB register of the timer + Timer t = Timers[timer]; + return t.tc->TC_CHANNEL[t.channel].TC_RB; +} +uint32_t DueTimer::counterValueAndReset(void) { + // Get the value of the counter and reset + uint32_t val; + Timer t = Timers[timer]; + val = t.tc->TC_CHANNEL[t.channel].TC_CV; + t.tc->TC_CHANNEL[t.channel].TC_CCR = TC_CCR_SWTRG; + return val; +} +DueTimer& DueTimer::resetCounterValue(void) { + // Reset the counter (software trigger) + Timer t = Timers[timer]; + t.tc->TC_CHANNEL[t.channel].TC_CCR = TC_CCR_SWTRG; + return *this; +} +double DueTimer::valueToMicroSeconds(uint32_t value) { + return value * getResolutionMicroSeconds(); +} +double DueTimer::valueToMilliSeconds(uint32_t value) { + return valueToMicroSeconds(value) / 1000.0; +} +double DueTimer::valueToSeconds(uint32_t value) { + return valueToMicroSeconds(value) / 1000000.0; +} /* Implementation of the timer callbacks defined in @@ -266,43 +511,43 @@ double DueTimer::getPeriod(void) const { // Fix for compatibility with Servo library #ifndef USING_SERVO_LIB void TC0_Handler(void){ - TC_GetStatus(TC0, 0); - DueTimer::callbacks[0](); + DueTimer::_statusRegister[0] = TC_GetStatus(TC0, 0); + if (DueTimer::callbacks[0]) DueTimer::callbacks[0](); } #endif void TC1_Handler(void){ - TC_GetStatus(TC0, 1); - DueTimer::callbacks[1](); + DueTimer::_statusRegister[1] = TC_GetStatus(TC0, 1); + if (DueTimer::callbacks[1]) DueTimer::callbacks[1](); } // Fix for compatibility with Servo library #ifndef USING_SERVO_LIB void TC2_Handler(void){ - TC_GetStatus(TC0, 2); - DueTimer::callbacks[2](); + DueTimer::_statusRegister[2] = TC_GetStatus(TC0, 2); + if (DueTimer::callbacks[2]) DueTimer::callbacks[2](); } void TC3_Handler(void){ - TC_GetStatus(TC1, 0); - DueTimer::callbacks[3](); + DueTimer::_statusRegister[3] = TC_GetStatus(TC1, 0); + if (DueTimer::callbacks[3]) DueTimer::callbacks[3](); } void TC4_Handler(void){ - TC_GetStatus(TC1, 1); - DueTimer::callbacks[4](); + DueTimer::_statusRegister[4] = TC_GetStatus(TC1, 1); + if (DueTimer::callbacks[4]) DueTimer::callbacks[4](); } void TC5_Handler(void){ - TC_GetStatus(TC1, 2); - DueTimer::callbacks[5](); + DueTimer::_statusRegister[5] = TC_GetStatus(TC1, 2); + if (DueTimer::callbacks[5]) DueTimer::callbacks[5](); } #endif void TC6_Handler(void){ - TC_GetStatus(TC2, 0); - DueTimer::callbacks[6](); + DueTimer::_statusRegister[6] = TC_GetStatus(TC2, 0); + if (DueTimer::callbacks[6]) DueTimer::callbacks[6](); } void TC7_Handler(void){ - TC_GetStatus(TC2, 1); - DueTimer::callbacks[7](); + DueTimer::_statusRegister[7] = TC_GetStatus(TC2, 1); + if (DueTimer::callbacks[7]) DueTimer::callbacks[7](); } void TC8_Handler(void){ - TC_GetStatus(TC2, 2); - DueTimer::callbacks[8](); + DueTimer::_statusRegister[8] = TC_GetStatus(TC2, 2); + if (DueTimer::callbacks[8]) DueTimer::callbacks[8](); } #endif diff --git a/DueTimer.h b/DueTimer.h index 52fb1b4..bb014b4 100644 --- a/DueTimer.h +++ b/DueTimer.h @@ -43,9 +43,13 @@ class DueTimer // Stores the object timer frequency // (allows to access current timer period and frequency): static double _frequency[NUM_TIMERS]; + static uint32_t _statusRegister[NUM_TIMERS]; // Picks the best clock to lower the error static uint8_t bestClock(double frequency, uint32_t& retRC); + static uint8_t bestCaptureClock(double maxPeriodMicroSeconds, double& resolution, uint32_t& maxPeriodRC); + + uint32_t getDutyCycleRX(double percent); // Make Interrupt handlers friends, so they can use callbacks friend void TC0_Handler(void); @@ -65,25 +69,83 @@ class DueTimer Tc *tc; uint32_t channel; IRQn_Type irq; + // TIOA + Pio *pioa; + uint32_t tioaBits; + EPioType tioaPeriph; + // TIOB + Pio *piob; + uint32_t tiobBits; + EPioType tiobPeriph; + // TCLK + Pio *pioclk; + uint32_t tioClkBits; + EPioType tioClkPeriph; }; // Store timer configuration (static, as it's fixed for every object) static const Timer Timers[NUM_TIMERS]; public: - static DueTimer getAvailable(void); DueTimer(unsigned short _timer); DueTimer& attachInterrupt(void (*isr)()); DueTimer& detachInterrupt(void); - DueTimer& start(double microseconds = -1); + DueTimer& start(void); + DueTimer& start(double microseconds); DueTimer& stop(void); DueTimer& setFrequency(double frequency); - DueTimer& setPeriod(double microseconds); - double getFrequency(void) const; double getPeriod(void) const; + + DueTimer& setPeriod(double microseconds); + DueTimer& setPeriodMilliSeconds(double milliseconds) { + return setPeriod(milliseconds * 1.0e3); + }; + + DueTimer& setDutyCycleA(double percent); + DueTimer& setTimeOnA(double microseconds) { + return setDutyCycleA( microseconds / getPeriod()); + } + DueTimer& setTimeOnAMilliSeconds(double milliseconds) { + return setTimeOnA(milliseconds * 1.0e3); + }; + + DueTimer& setDutyCycleB(double percent); + DueTimer& setTimeOnB(double microseconds) { + return setDutyCycleB( microseconds / getPeriod()); + }; + DueTimer& setTimeOnBMilliSeconds(double milliseconds) { + return setTimeOnB(milliseconds * 1.0e3); + }; + + uint32_t statusRegister(void); + DueTimer& enablePinB(); + DueTimer& enablePinA(); + DueTimer& enablePinClock(); + + // Capture mode, triggered by TIOA pin + DueTimer& setCapture(double maxPeriodMicroSeconds); + uint32_t captureValueA(void); + uint32_t captureValueB(void); + DueTimer& resetCounterValue(void); + double valueToMicroSeconds(uint32_t value); + double valueToMilliSeconds(uint32_t value); + double valueToSeconds(uint32_t value); + inline double getResolutionMicroSeconds(void) const; + + DueTimer& setCaptureMilliSeconds(double maxPeriodMilliSeconds) { + return setCapture(maxPeriodMilliSeconds * 1.0e3); + }; + DueTimer& setCaptureSeconds(double maxPeriodSeconds) { + return setCapture(maxPeriodSeconds * 1.0e6); + }; + + // Counter mode, external clock + DueTimer& setCounter(void); + uint32_t counterValue(void); + uint32_t counterValueAndReset(void); }; // Just to call Timer.getAvailable instead of Timer::getAvailable() : diff --git a/README.md b/README.md index 89ad2df..cfecc58 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,49 @@ DueTimer::getAvailable().attachInterrupt(callback2).start(10); // And so on... ``` +### Activate the output pins (TIOA,TIOB) +Timer1.attachInterrupt(timerISR).setFrequency(1000).enablePinB().start(); +Timer1.attachInterrupt(timerISR).setFrequency(1000).enablePinA().start(); + +### Set the duty cycle +Timer1.attachInterrupt(timerISR).setPeriodMilliSeconds(10).setTimeOnBMilliSeconds(1).enablePinB().start(); +Timer1.attachInterrupt(timerISR).setFrequency(1000).setDutyCycleA(25).enablePinA().start(); + +### Capture mode : +### Capture the period and duty cycle (time on) of the TIO input signal +### Note : capture mode automatically enable the TIOA pin which is the capture pin + +void timerCapture() { + + capture++; + + uint32_t status = Timer8.statusRegister(); + + if (status & TC_SR_LDRAS) { + captureTimeOn = Timer8.captureValueA(); + captureChange++; + } else + if (status & TC_SR_LDRBS) { + capturePeriod = Timer8.captureValueB(); + captureChange++; + Timer8.resetCounterValue(); + } else + if ((status & TC_SR_CPCS)||(status & TC_SR_COVFS)) { + // Overflow trigger + capturePeriod = 0; + captureTimeOn = 0; + captureOverRun++; + }; +} +Timer8.attachInterrupt(timerCapture).setCaptureMilliSeconds(100).start(); + +### Counter mode +### Count rising edge of selected timer input clock +### Note : Counter mode enable the TCLK pin + +Timer3.setCounter().start(); + + ### Compatibility with Servo.h Because Servo Library uses the same callbacks of DueTimer, we provides a custom solution for working with both of them. However, Timers 0,2,3,4 and 5 will not Work anymore. diff --git a/examples/CaptureMode/CaptureMode.pde b/examples/CaptureMode/CaptureMode.pde new file mode 100644 index 0000000..1e98ff0 --- /dev/null +++ b/examples/CaptureMode/CaptureMode.pde @@ -0,0 +1,136 @@ +/* + Arduino Due Timer capture example + This example code is in the public domain + */ + +#include // Arduino LCD library +#include +#include + +// pin definition for the TFT +#define cs 7 +#define dc 3 +#define rst 6 + +// create an instance of the library +TFT TFTscreen = TFT(cs, dc, rst); + +long tickms = 0; +long capture = 0; + +char charBuffer[20]; + +long capturePeriod = 0; +long captureTimeOn = 0; +int captureOverRun = 0; +byte captureChange = 0; + +void timerISR() { + // 1ms tick + tickms++; + } + +void timerCapture() { + + capture++; + + uint32_t status = Timer8.statusRegister(); + + if (status & TC_SR_LDRAS) { + captureTimeOn = Timer8.captureValueA(); + captureChange++; + } else + if (status & TC_SR_LDRBS) { + capturePeriod = Timer8.captureValueB(); + captureChange++; + Timer8.resetCounterValue(); + } else + if ((status & TC_SR_CPCS)||(status & TC_SR_COVFS)) { + // Overflow trigger + capturePeriod = 0; + captureTimeOn = 0; + captureOverRun++; + }; + +} + +void setup() { + // buil in led + pinMode(LED_BUILTIN, OUTPUT); + + // Put this line at the beginning of every sketch that uses the GLCD: + TFTscreen.begin(); + + // clear the screen with a black background + TFTscreen.background(0, 0, 0); + + // write the static text to the screen + // set the font color to white + TFTscreen.stroke(255, 255, 255); + // set the font size + TFTscreen.setTextSize(2); + // write the text to the top left corner of the screen + TFTscreen.text("Period Value :\n ", 0, 0); + // ste the font size very large for the loop + TFTscreen.setTextSize(3); + + TFTscreen.fill(0, 0, 0); + TFTscreen.noStroke(); + + // for debugging monitor + //Serial.begin(9600); //This pipes to the serial monitor + //Serial1.begin(9600); //This is the UART, pipes to sensors attached to board + + // Note : TIOA input of Timer8 (Digital7) is wired on TIOB output of Timer1 (Analog6) + + // Start timer 1 100Hz (10ms period) with 1 ms on and enable output B + Timer1.attachInterrupt(timerISR).setPeriodMilliSeconds(10).setTimeOnBMilliSeconds(1).enablePinB().start(); + + // Start timer 8 in capture mode with a max capture window of 100 ms + Timer8.attachInterrupt(timerCapture).setCaptureMilliSeconds(100).start(); +} + +void loop() { + + /* + if (tickms==50) { + digitalWrite(LED_BUILTIN, ! digitalRead(LED_BUILTIN)); + tickms = 0; + */ + + if (capture==50) { + digitalWrite(LED_BUILTIN, ! digitalRead(LED_BUILTIN)); + capture = 0; + } + + if (captureOverRun==10) { + TFTscreen.rect(0,20,TFTscreen.width(),80); + TFTscreen.stroke(255, 255, 255); + + sprintf(charBuffer,"No signal"); + TFTscreen.text(charBuffer, 0, 20); + + TFTscreen.noStroke(); + captureOverRun = 0; + } + + + if (captureChange==10) { + TFTscreen.rect(0,20,TFTscreen.width(),80); + TFTscreen.stroke(255, 255, 255); + + double valMS = Timer8.valueToMilliSeconds(capturePeriod); + sprintf(charBuffer,"%.2f",valMS); + TFTscreen.text(charBuffer, 0, 20); + + valMS = Timer8.valueToMilliSeconds(captureTimeOn); + sprintf(charBuffer,"%.2f",valMS); + TFTscreen.text(charBuffer, 0, 60); + + TFTscreen.noStroke(); + captureChange = 0; + } + +} + + diff --git a/examples/CounterMode/CounterMode.pde b/examples/CounterMode/CounterMode.pde new file mode 100644 index 0000000..fcf3793 --- /dev/null +++ b/examples/CounterMode/CounterMode.pde @@ -0,0 +1,88 @@ +/* + Arduino Due Timer in Counter mode example + This example code is in the public domain + */ + +#include // Arduino LCD library +#include +#include + +// pin definition for the Due +#define cs 7 +#define dc 3 +#define rst 6 + +// create an instance of the library +TFT TFTscreen = TFT(cs, dc, rst); + +long tickms = 0; +long counterValue = 0; +byte counterChange = 0; + +char charBuffer[20]; + +void timerISR() { + // 1ms tick + tickms++; +} + +void timerGate() { + // 1 second gate signal + // Get counter value and reset + counterValue = Timer3.counterValueAndReset(); + counterChange++; +} + +void setup() { + // buil in led + pinMode(LED_BUILTIN, OUTPUT); + + // Put this line at the beginning of every sketch that uses the GLCD: + TFTscreen.begin(); + + // clear the screen with a black background + TFTscreen.background(0, 0, 0); + + // write the static text to the screen + // set the font color to white + TFTscreen.stroke(255, 255, 255); + // set the font size + TFTscreen.setTextSize(2); + // write the text to the top left corner of the screen + TFTscreen.text("Count Value :\n ", 0, 0); + // ste the font size very large for the loop + TFTscreen.setTextSize(3); + + TFTscreen.fill(0, 0, 0); + TFTscreen.noStroke(); + + // for debugging monitor + //Serial.begin(9600); //This pipes to the serial monitor + //Serial1.begin(9600); //This is the UART, pipes to sensors attached to board + + // Timer 1 TIOB output (analog6) is wired on timer 3 input clock TCLK3 (Analog3) + + // Start timer 1, 100 Hz generator (Analog6) + Timer1.attachInterrupt(timerISR).setPeriodMilliSeconds(10).setTimeOnBMilliSeconds(1).enablePinB().start(); + // Start timer 2, 1s gate signal + Timer2.attachInterrupt(timerGate).setPeriodMilliSeconds(1000).start(); + // Start timer 3, counter mode on TCLK3 (Analog3) + Timer3.setCounter().start(); +} + +void loop() { + + if (counterChange) { + TFTscreen.rect(0,20,TFTscreen.width(),40); + TFTscreen.stroke(255, 255, 255); + + sprintf(charBuffer,"%u",counterValue); + TFTscreen.text(charBuffer, 0, 20); + + TFTscreen.noStroke(); + counterChange--; + } + +} + + diff --git a/keywords.txt b/keywords.txt index 28a7c2f..2c54ba5 100644 --- a/keywords.txt +++ b/keywords.txt @@ -8,6 +8,9 @@ setFrequency KEYWORD2 getFrequency KEYWORD2 getPeriod KEYWORD2 +setCapture KEYWORD2 + + Timer KEYWORD1 Timer0 KEYWORD1 Timer1 KEYWORD1 @@ -17,4 +20,5 @@ Timer4 KEYWORD1 Timer5 KEYWORD1 Timer6 KEYWORD1 Timer7 KEYWORD1 +Timer8 KEYWORD1