|
- /*
- FrequencyTimer2.h - A frequency generator and interrupt generator library
- Author: Jim Studt, jim@federated.com
- Copyright (c) 2007 David A. Mellis. All right reserved.
-
- http://www.arduino.cc/playground/Code/FrequencyTimer2
-
- Version 2.1 - updated by Paul Stoffregen, paul@pjrc.com
- for compatibility with Teensy 3.1
-
- Version 2 - updated by Paul Stoffregen, paul@pjrc.com
- for compatibility with newer hardware and Arduino 1.0
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-
- #include <FrequencyTimer2.h>
-
- #include <avr/interrupt.h>
-
-
- void (*FrequencyTimer2::onOverflow)() = 0;
- uint8_t FrequencyTimer2::enabled = 0;
-
- #if defined(__AVR__)
-
- #if defined(TIMER2_COMPA_vect)
- ISR(TIMER2_COMPA_vect)
- #elif defined(TIMER2_COMP_vect)
- ISR(TIMER2_COMP_vect)
- #else
- #error "This board does not have a hardware timer which is compatible with FrequencyTimer2"
- void dummy_function(void)
- #endif
- {
- static uint8_t inHandler = 0; // protect us from recursion if our handler enables interrupts
-
- if ( !inHandler && FrequencyTimer2::onOverflow) {
- inHandler = 1;
- (*FrequencyTimer2::onOverflow)();
- inHandler = 0;
- }
- }
-
- void FrequencyTimer2::setOnOverflow( void (*func)() )
- {
- FrequencyTimer2::onOverflow = func;
- #if defined(TIMSK2)
- if ( func) TIMSK2 |= _BV(OCIE2A);
- else TIMSK2 &= ~_BV(OCIE2A);
- #elif defined(TIMSK)
- if ( func) TIMSK |= _BV(OCIE2);
- else TIMSK &= ~_BV(OCIE2);
- #endif
- }
-
- void FrequencyTimer2::setPeriod(unsigned long period)
- {
- uint8_t pre, top;
-
- if ( period == 0) period = 1;
- period *= clockCyclesPerMicrosecond();
-
- period /= 2; // we work with half-cycles before the toggle
- if ( period <= 256) {
- pre = 1;
- top = period-1;
- } else if ( period <= 256L*8) {
- pre = 2;
- top = period/8-1;
- } else if ( period <= 256L*32) {
- pre = 3;
- top = period/32-1;
- } else if ( period <= 256L*64) {
- pre = 4;
- top = period/64-1;
- } else if ( period <= 256L*128) {
- pre = 5;
- top = period/128-1;
- } else if ( period <= 256L*256) {
- pre = 6;
- top = period/256-1;
- } else if ( period <= 256L*1024) {
- pre = 7;
- top = period/1024-1;
- } else {
- pre = 7;
- top = 255;
- }
-
- #if defined(TCCR2A)
- TCCR2B = 0;
- TCCR2A = 0;
- TCNT2 = 0;
- #if defined(ASSR) && defined(AS2)
- ASSR &= ~_BV(AS2); // use clock, not T2 pin
- #endif
- OCR2A = top;
- TCCR2A = (_BV(WGM21) | ( FrequencyTimer2::enabled ? _BV(COM2A0) : 0));
- TCCR2B = pre;
- #elif defined(TCCR2)
- TCCR2 = 0;
- TCNT2 = 0;
- ASSR &= ~_BV(AS2); // use clock, not T2 pin
- OCR2 = top;
- TCCR2 = (_BV(WGM21) | ( FrequencyTimer2::enabled ? _BV(COM20) : 0) | pre);
- #endif
-
- }
-
- unsigned long FrequencyTimer2::getPeriod()
- {
- #if defined(TCCR2B)
- uint8_t p = (TCCR2B & 7);
- unsigned long v = OCR2A;
- #elif defined(TCCR2)
- uint8_t p = (TCCR2 & 7);
- unsigned long v = OCR2;
- #endif
- uint8_t shift=0;
-
- switch(p) {
- case 0 ... 1:
- shift = 0;
- break;
- case 2:
- shift = 3;
- break;
- case 3:
- shift = 5;
- break;
- case 4:
- shift = 6;
- break;
- case 5:
- shift = 7;
- break;
- case 6:
- shift = 8;
- break;
- case 7:
- shift = 10;
- break;
- }
- return (((v+1) << (shift+1)) + 1) / clockCyclesPerMicrosecond(); // shift+1 converts from half-period to period
- }
-
- void FrequencyTimer2::enable()
- {
- FrequencyTimer2::enabled = 1;
- #if defined(TCCR2A)
- TCCR2A |= _BV(COM2A0);
- #elif defined(TCCR2)
- TCCR2 |= _BV(COM20);
- #endif
- }
-
- void FrequencyTimer2::disable()
- {
- FrequencyTimer2::enabled = 0;
- #if defined(TCCR2A)
- TCCR2A &= ~_BV(COM2A0);
- #elif defined(TCCR2)
- TCCR2 &= ~_BV(COM20);
- #endif
- }
-
-
-
- #elif defined(__arm__) && defined(TEENSYDUINO)
-
- void FrequencyTimer2::setPeriod(unsigned long period)
- {
- uint8_t bdiv, cdiv=0;
-
- if (period == 0) period = 1;
- period *= (F_BUS / 1000000);
- if (period < 65535*16) {
- bdiv = 0;
- } else if (period < 65535*2*16) {
- bdiv = 1;
- } else if (period < 65535*3*16) {
- bdiv = 2;
- } else if (period < 65535*4*16) {
- bdiv = 3;
- } else if (period < 65535*5*16) {
- bdiv = 4;
- } else if (period < 65535*6*16) {
- bdiv = 5;
- } else if (period < 65535*7*16) {
- bdiv = 6;
- } else if (period < 65535*8*16) {
- bdiv = 7;
- } else if (period < 65535*9*16) {
- bdiv = 8;
- } else if (period < 65535*10*16) {
- bdiv = 9;
- } else if (period < 65535*11*16) {
- bdiv = 10;
- } else if (period < 65535*12*16) {
- bdiv = 11;
- } else if (period < 65535*13*16) {
- bdiv = 12;
- } else if (period < 65535*14*16) {
- bdiv = 13;
- } else if (period < 65535*15*16) {
- bdiv = 14;
- } else if (period < 65535*16*16) {
- bdiv = 15;
- } else if (period < 65535*18*16) {
- bdiv = 8;
- cdiv = 1;
- } else if (period < 65535*20*16) {
- bdiv = 9;
- cdiv = 1;
- } else if (period < 65535*22*16) {
- bdiv = 10;
- cdiv = 1;
- } else if (period < 65535*24*16) {
- bdiv = 11;
- cdiv = 1;
- } else if (period < 65535*26*16) {
- bdiv = 12;
- cdiv = 1;
- } else if (period < 65535*28*16) {
- bdiv = 13;
- cdiv = 1;
- } else if (period < 65535*30*16) {
- bdiv = 14;
- cdiv = 1;
- } else if (period < 65535*32*16) {
- bdiv = 15;
- cdiv = 1;
- } else if (period < 65535*36*16) {
- bdiv = 8;
- cdiv = 2;
- } else if (period < 65535*40*16) {
- bdiv = 9;
- cdiv = 2;
- } else if (period < 65535*44*16) {
- bdiv = 10;
- cdiv = 2;
- } else if (period < 65535*48*16) {
- bdiv = 11;
- cdiv = 2;
- } else if (period < 65535*52*16) {
- bdiv = 12;
- cdiv = 2;
- } else if (period < 65535*56*16) {
- bdiv = 13;
- cdiv = 2;
- } else if (period < 65535*60*16) {
- bdiv = 14;
- cdiv = 2;
- } else if (period < 65535*64*16) {
- bdiv = 15;
- cdiv = 2;
- } else if (period < 65535*72*16) {
- bdiv = 8;
- cdiv = 3;
- } else if (period < 65535*80*16) {
- bdiv = 9;
- cdiv = 3;
- } else if (period < 65535*88*16) {
- bdiv = 10;
- cdiv = 3;
- } else if (period < 65535*96*16) {
- bdiv = 11;
- cdiv = 3;
- } else if (period < 65535*104*16) {
- bdiv = 12;
- cdiv = 3;
- } else if (period < 65535*112*16) {
- bdiv = 13;
- cdiv = 3;
- } else if (period < 65535*120*16) {
- bdiv = 14;
- cdiv = 3;
- } else {
- bdiv = 15;
- cdiv = 3;
- }
- period /= (bdiv + 1);
- period >>= (cdiv + 4);
- if (period > 65535) period = 65535;
- // high time = (CMD1:CMD2 + 1) ÷ (fCMTCLK ÷ 8)
- // low time = CMD3:CMD4 ÷ (fCMTCLK ÷ 8)
- SIM_SCGC4 |= SIM_SCGC4_CMT;
- CMT_MSC = 0;
- CMT_PPS = bdiv;
- CMT_CMD1 = ((period - 1) >> 8) & 255;
- CMT_CMD2 = (period - 1) & 255;
- CMT_CMD3 = (period >> 8) & 255;
- CMT_CMD4 = period & 255;
- CMT_OC = 0x60;
- CMT_MSC = (cdiv << 5) | 0x0B; // baseband mode
- }
-
- unsigned long FrequencyTimer2::getPeriod()
- {
- uint32_t period;
-
- period = (CMT_CMD3 << 8) | CMT_CMD4;
- period *= (CMT_PPS + 1);
- period <<= ((CMT_MSC >> 5) & 3) + 4;
- period /= (F_BUS / 1000000);
- return period;
- }
-
- void FrequencyTimer2::enable()
- {
- FrequencyTimer2::enabled = 1;
- CORE_PIN5_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_DSE|PORT_PCR_SRE;
- }
-
- void FrequencyTimer2::disable()
- {
- FrequencyTimer2::enabled = 0;
- CORE_PIN5_CONFIG = PORT_PCR_MUX(1)|PORT_PCR_DSE|PORT_PCR_SRE;
- digitalWriteFast(5, LOW);
- }
-
- void FrequencyTimer2::setOnOverflow( void (*func)() )
- {
- if (func) {
- FrequencyTimer2::onOverflow = func;
- NVIC_ENABLE_IRQ(IRQ_CMT);
- } else {
- NVIC_DISABLE_IRQ(IRQ_CMT);
- FrequencyTimer2::onOverflow = func;
- }
- }
-
- void cmt_isr(void)
- {
- static uint8_t inHandler = 0;
-
- uint8_t __attribute__((unused)) tmp = CMT_MSC;
- tmp = CMT_CMD2;
- if ( !inHandler && FrequencyTimer2::onOverflow) {
- inHandler = 1;
- (*FrequencyTimer2::onOverflow)();
- inHandler = 0;
- }
- }
-
- #endif
|