int __digitalRead(uint8_t pin) { uint8_t timer = digitalPinToTimer(pin); uint8_t bit = digitalPinToBitMask(pin); uint8_t port = digitalPinToPort(pin); if (port == NOT_A_PIN) return LOW; // If the pin that support PWM output, we need to turn it off // before getting a digital reading. //if (timer != NOT_ON_TIMER) turnOffPWM(timer); if (*portInputRegister(port) & bit) return HIGH; return LOW; }
// Right now, PWM output only works on the pins with // hardware support. These are defined in the appropriate // pins_*.c file. For the rest of the pins, we default // to digital output. void analogWrite(uint8_t pin, int val) { // We need to make sure the PWM output is enabled for those pins // that support it, as we turn it off when digitally reading or // writing with them. Also, make sure the pin is in output mode // for consistenty with Wiring, which doesn't require a pinMode // call for the analog output pins. pinMode(pin, OUTPUT); if (digitalPinToTimer(pin) == TIMER1A) { // connect pwm to pin on timer 1, channel A sbi(TCCR1A, COM1A1); // set pwm duty OCR1A = val; } else if (digitalPinToTimer(pin) == TIMER1B) { // connect pwm to pin on timer 1, channel B sbi(TCCR1A, COM1B1); // set pwm duty OCR1B = val; } else if (digitalPinToTimer(pin) == TIMER1C) { // connect pwm to pin on timer 1, channel B sbi(TCCR1A, COM1C1); // set pwm duty OCR1C = val; } else if (digitalPinToTimer(pin) == TIMER2A) { // connect pwm to pin on timer 2, channel A sbi(TCCR2A, COM2A1); // set pwm duty OCR2A = val; } else if (digitalPinToTimer(pin) == TIMER3A) { // connect pwm to pin on timer 3, channel A sbi(TCCR3A, COM3A1); // set pwm duty OCR3A = val; } else if (digitalPinToTimer(pin) == TIMER3B) { // connect pwm to pin on timer 3, channel B sbi(TCCR3A, COM3B1); // set pwm duty OCR3B = val; } else if (digitalPinToTimer(pin) == TIMER3C) { // connect pwm to pin on timer 3, channel C sbi(TCCR3A, COM3C1); // set pwm duty OCR3C = val; } else if (val < 128) digitalWrite(pin, LOW); else digitalWrite(pin, HIGH); }
bool SetPinFrequencySafe(int8_t pin, uint32_t frequency) { uint8_t timer = digitalPinToTimer(pin); if(timer == TIMER1A || timer == TIMER1B) return Timer1_SetFrequency(frequency); else if(timer == TIMER2B) return Timer2_SetFrequency(frequency); else if(timer == TIMER3A || timer == TIMER3B || timer == TIMER3C) return Timer3_SetFrequency(frequency); else if(timer == TIMER4A || timer == TIMER4B || timer == TIMER4C) return Timer4_SetFrequency(frequency); else if(timer == TIMER5A || timer == TIMER5B || timer == TIMER5C) return Timer5_SetFrequency(frequency); else return false; }
void digitalWrite(uint8_t pin, uint8_t val) { uint8_t timer = digitalPinToTimer(pin); uint8_t bit = digitalPinToBitMask(pin); uint8_t port = digitalPinToPort(pin); volatile uint8_t *out; if (port == NOT_A_PIN) return; // If the pin that support PWM output, we need to turn it off // before doing a digital write. if (timer != NOT_ON_TIMER) turnOffPWM(timer); out = portOutputRegister(port); if (val == LOW) *out &= ~bit; else *out |= bit; }
void DirectAnalogOutput::setPin(uint8_t pin) { uint8_t port = digitalPinToPort(pin); if (port == NOT_A_PIN) return; volatile uint8_t *modeRegister = portModeRegister(port); _outputRegister = portOutputRegister(port); _bitMask = digitalPinToBitMask(pin); uint8_t oldSREG = SREG; cli(); *modeRegister |= _bitMask; SREG = oldSREG; _timer = digitalPinToTimer(pin); }
float GetPinResolution(uint8_t pin) { TimerData td = timer_to_pwm_data[digitalPinToTimer(pin)]; double baseTenRes = 0; if(td.ChannelRegLoc) { //getting a base 10 resolution td.Is16Bit? (baseTenRes = _SFR_MEM16(td.TimerTopRegLoc)) : (baseTenRes = _SFR_MEM8(td.TimerTopRegLoc)); //change the base and return return toBaseTwo(baseTenRes); } else { return 0; } }
void digitalWrite(uint8_t pin, uint8_t value) { uint8_t timer = digitalPinToTimer(pin); uint8_t bit = digitalPinToBitMask(pin); uint8_t port = digitalPinToPort(pin); t_SetPortCfg cfg; if (timer != NOT_ON_TIMER) turnOffPWM(timer); if(port == NOT_A_PORT) { return; } cfg.pID = (uint16_t)portModeRegister(port); setPinValue(value,cfg.pID,bit); }
int digitalRead(uint8_t pin) { if( (pin >= 0) && (pin <= 7) ) //port A outputs! return -1; //do nothing! uint8_t timer = digitalPinToTimer(pin); uint8_t bit = digitalPinToBitMask(pin); uint8_t port = digitalPinToPort(pin); if (port == NOT_A_PIN) return LOW; // If the pin that support PWM output, we need to turn it off // before getting a digital reading. if (timer != NOT_ON_TIMER) turnOffPWM(timer); if (*portInputRegister(port) & bit) return HIGH; return LOW; }
/* * noTone() - Stop outputting the tone on a pin */ void noTone(uint8_t _pin) { uint8_t timer = digitalPinToTimer(_pin); if(timer == tone_timer) { uint32_t timerBase = getTimerBase(timerToOffset(timer)); uint32_t timerAB = TIMER_A << timerToAB(timer); ROM_TimerIntDisable(timerBase, TIMER_TIMA_TIMEOUT << timerToAB(tone_timer)); ROM_TimerIntClear(timerBase, TIMER_TIMA_TIMEOUT << timerToAB(tone_timer)); ROM_TimerDisable(timerBase, timerAB); tone_state = 0; g_duration = 0; pinMode(_pin, OUTPUT); digitalWrite(_pin, LOW); } }
void DirectOutputPin::setPin(uint8_t pin) { uint8_t port = digitalPinToPort(pin); if (port == NOT_A_PIN) return; volatile uint8_t *modeRegister = portModeRegister(port); _outputRegister = portOutputRegister(port); _bitMask = digitalPinToBitMask(pin); uint8_t oldSREG = SREG; cli(); *modeRegister |= _bitMask; SREG = oldSREG; uint8_t timer = digitalPinToTimer(pin); if (timer != NOT_ON_TIMER) turnOffPWM(timer); }
uint8_t digitalRead(uint8_t pin) { uint8_t timer = digitalPinToTimer(pin); uint8_t bit = digitalPinToBitMask(pin); uint8_t port = digitalPinToPort(pin); t_SetPortCfg cfg; if (timer != NOT_ON_TIMER) turnOffPWM(timer); if(port == NOT_A_PIN) { return 0; } cfg.pID = (uint16_t)portModeRegister(port); return getPinValue(cfg.pID,bit); }
void analogWrite(uint8_t pin, int val) { /* duty cycle(%) = val / 255; * Frequency of 490Hz specified by Arduino API */ uint8_t timer = digitalPinToTimer(pin); if(timer == NOT_ON_TIMER) return; if (val == 0) { pinMode(pin, OUTPUT); digitalWrite(pin, LOW); return; } if (val >= 255) { pinMode(pin, OUTPUT); digitalWrite(pin, HIGH); return; } PWMWrite(pin, 255, val, 490); }
float GetPinResolution(uint8_t pin) { uint8_t timer = digitalPinToTimer(pin); uint16_t top; switch(timer) { case TIMER0B: top = Timer0_GetTop(); break; case TIMER1A: top = Timer1_GetTop(); break; case TIMER1B: top = Timer1_GetTop(); break; case TIMER2B: top = Timer2_GetTop(); default: return 0; } return toBaseTwo(top); }
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) { uint8_t port = digitalPinToPort(_pin); if (port == NOT_A_PORT) return; if (tone_state == 0 || _pin == current_pin) { //Setup PWM current_pin = _pin; tone_timer = digitalPinToTimer(_pin); uint32_t timerBase = getTimerBase(timerToOffset(tone_timer)); tone_state = 1; g_duration = duration; PWMWrite(_pin, 256, 128, frequency); //Setup interrupts for duration, interrupting at 1kHz ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER4); ROM_IntMasterEnable(); ROM_TimerConfigure(TIMER4_BASE, TIMER_CFG_PERIODIC); ROM_TimerLoadSet(TIMER4_BASE, TIMER_A, ROM_SysCtlClockGet()/1000); ROM_IntEnable(INT_TIMER4A); ROM_TimerIntEnable(TIMER4_BASE, TIMER_TIMA_TIMEOUT); ROM_TimerEnable(TIMER4_BASE, TIMER_A); } }
void analogWrite(uint8_t pin, int16_t val) { uint8_t timer = 0xff; setPinMode(pin, OUTPUT); if ((val == 0) || (val <0)) { digitalWrite(pin, LOW); } else if ((val > 255) || (val == 255)) { digitalWrite(pin, HIGH); } else { timer = digitalPinToTimer(pin); initPwm(timer); setPwmDutyCycle((uint8_t)val, timer); } }
// Right now, PWM output only works on the pins with // hardware support. These are defined in the appropriate // pins_*.c file. For the rest of the pins, we default // to digital output. void analogWrite(uint8_t pin, int val) { // We need to make sure the PWM output is enabled for those pins // that support it, as we turn it off when digitally reading or // writing with them. Also, make sure the pin is in output mode // for consistenty with Wiring, which doesn't require a pinMode // call for the analog output pins. pinMode(pin, OUTPUT); if (val <= 0) { digitalWrite(pin, LOW); } else if (val >= 255) { digitalWrite(pin, HIGH); } else { uint8_t timer = digitalPinToTimer(pin); #if defined(TCCR0A) && defined(COM0A1) if( timer == TIMER0A){ // connect pwm to pin on timer 0, channel A sbi(TCCR0A, COM0A1); cbi(TCCR0A, COM0A0); OCR0A = val; // set pwm duty } else #endif #if defined(TCCR0A) && defined(COM0B1) if( timer == TIMER0B){ // connect pwm to pin on timer 0, channel B sbi(TCCR0A, COM0B1); cbi(TCCR0A, COM0B0); OCR0B = val; // set pwm duty } else #endif #if defined(TCCR1A) && defined(COM1A1) && !defined(TCCR1E) if( timer == TIMER1A){ // connect pwm to pin on timer 1, channel A sbi(TCCR1A, COM1A1); cbi(TCCR1A, COM1A0); #ifdef OC1AX cbi(TCCR1D, OC1AV); cbi(TCCR1D, OC1AU); cbi(TCCR1D, OC1AW); sbi(TCCR1D, OC1AX); #endif OCR1A = val; // set pwm duty } else #endif #if defined(TCCR1E) if( timer == TIMER1A){ // connect pwm to pin on timer 1, channel A cbi(TCCR1C,COM1A1S); sbi(TCCR1C,COM1A0S); OCR1A = val; // set pwm duty } else if (timer == TIMER1B){ // connect pwm to pin on timer 1, channel A cbi(TCCR1C,COM1B1S); sbi(TCCR1C,COM1B0S); OCR1B = val; // set pwm duty } else if (timer == TIMER1D){ // connect pwm to pin on timer 1, channel A cbi(TCCR1C,COM1D1); sbi(TCCR1C,COM1D0); OCR1D = val; // set pwm duty } else #endif #if defined(TCCR1) && defined(COM1A1) if(timer == TIMER1A){ // connect pwm to pin on timer 1, channel A sbi(TCCR1, COM1A1); cbi(TCCR1, COM1A0); OCR1A = val; // set pwm duty } else #endif #if defined(TCCR1A) && defined(COM1B1) && !defined(TCCR1E) if( timer == TIMER1B){ // connect pwm to pin on timer 1, channel B sbi(TCCR1A, COM1B1); cbi(TCCR1A, COM1B0); #ifdef OC1BV sbi(TCCR1D, OC1BV); cbi(TCCR1D, OC1BU); cbi(TCCR1D, OC1BW); cbi(TCCR1D, OC1BX); #endif OCR1B = val; // set pwm duty } else #endif #if defined(TCCR1) && defined(COM1B1) if( timer == TIMER1B){ // connect pwm to pin on timer 1, channel B sbi(GTCCR, COM1B1); cbi(GTCCR, COM1B0); OCR1B = val; // set pwm duty } else #endif { if (val < 128) { digitalWrite(pin, LOW); } else { digitalWrite(pin, HIGH); } } } }
void PWMWrite(uint8_t pin, uint32_t analog_res, uint32_t duty, unsigned int freq) { if (duty == 0) { pinMode(pin, OUTPUT); digitalWrite(pin, LOW); } else if (duty >= analog_res) { pinMode(pin, OUTPUT); digitalWrite(pin, HIGH); } else { uint8_t bit = digitalPinToBitMask(pin); // get pin bit uint8_t port = digitalPinToPort(pin); // get pin port uint8_t timer = digitalPinToTimer(pin); uint32_t portBase = (uint32_t) portBASERegister(port); uint32_t offset = timerToOffset(timer); uint32_t timerBase = getTimerBase(offset); uint32_t timerAB = TIMER_A << timerToAB(timer); uint32_t periodPWM; if (port == NOT_A_PORT) return; // pin on timer? periodPWM = ROM_SysCtlClockGet() / freq; enableTimerPeriph(offset); ROM_GPIOPinConfigure(timerToPinConfig(timer)); ROM_GPIOPinTypeTimer((long unsigned int) portBase, bit); // // Configure for half-width mode, allowing timers A and B to // operate independently // HWREG(timerBase + TIMER_O_CFG) = 0x04; if (timerAB == TIMER_A) { HWREG(timerBase + TIMER_O_CTL) &= ~TIMER_CTL_TAEN; HWREG(timerBase + TIMER_O_TAMR) = PWM_MODE; } else { HWREG(timerBase + TIMER_O_CTL) &= ~TIMER_CTL_TBEN; HWREG(timerBase + TIMER_O_TBMR) = PWM_MODE; } ROM_TimerLoadSet(timerBase, timerAB, periodPWM); ROM_TimerMatchSet(timerBase, timerAB, (analog_res - duty)*periodPWM / analog_res); // // If using a 16-bit timer, with a periodPWM > 0xFFFF, // need to use a prescaler // if ((offset < WTIMER0) && (periodPWM > 0xFFFF)) { ROM_TimerPrescaleSet(timerBase, timerAB, (periodPWM & 0xFFFF0000) >> 16); ROM_TimerPrescaleMatchSet(timerBase, timerAB, (((analog_res - duty)*periodPWM / analog_res) & 0xFFFF0000) >> 16); } ROM_TimerEnable(timerBase, timerAB); }
void analogWrite(uint8_t pin, int val) { pinMode(pin, OUTPUT); // pin as output if (val == 0) { digitalWrite(pin, LOW); // set pin to LOW when duty cycle is 0 // digitalWrite will take care of invalid pins } else if (val == 255) { digitalWrite(pin, HIGH); // set pin HIGH when duty cycle is 255 // digitalWrite will take care of invalid pins } else { uint8_t bit = digitalPinToBitMask(pin); // get pin bit uint8_t port = digitalPinToPort(pin); // get pin port volatile uint16_t *sel; volatile uint16_t *sel2; if (port == NOT_A_PORT) return; // pin on timer? sel = portSelRegister(port); // get the port function select register address *sel |= bit; // set bit in pin function select register //TODO: Firgure out a better way to determine if SEL2 needs to be set if(bit == BV(4) && port == P1) { sel2 = portSel2Register(port); // get the port function select register address *sel2 |= bit; } switch(digitalPinToTimer(pin)) { // which timer and CCR? //case: T0A0 // CCR0 used as period register case T0A1: // Timer0 / CCR1 TA0CCR0 = PWM_PERIOD; // PWM Period TA0CCTL1 = OUTMOD_7; // reset/set TA0CCR1 = PWM_DUTY(val); // PWM duty cycle TA0CTL = TASSEL_2 + MC_1 + analog_div; // SMCLK, up mode break; #if defined(__MSP430_HAS_TA3__) case T0A2: // Timer0 / CCR1 TA0CCR0 = PWM_PERIOD; // PWM Period TA0CCTL2 = OUTMOD_7; // reset/set TA0CCR2 = PWM_DUTY(val); // PWM duty cycle TA0CTL = TASSEL_2 + MC_1+ analog_div; // SMCLK, up mode break; #endif #if defined(__MSP430_HAS_T1A3__) //case: T1A0 // CCR0 used as period register case T1A1: // Timer0 / CCR1 TA1CCR0 = PWM_PERIOD; // PWM Period TA1CCTL1 = OUTMOD_7; // reset/set TA1CCR1 = PWM_DUTY(val); // PWM duty cycle TA1CTL = TASSEL_2 + MC_1+ analog_div; // SMCLK, up mode break; case T1A2: // Timer0 / CCR1 TA1CCR0 = PWM_PERIOD; // PWM Period TA1CCTL2 = OUTMOD_7; // reset/set TA1CCR2 = PWM_DUTY(val); // PWM duty cycle TA1CTL = TASSEL_2 + MC_1+ analog_div; // SMCLK, up mode break; #endif #if defined(__MSP430_HAS_T2A3__) //case: T2A0 // CCR0 used as period register case T2A1: // Timer0 / CCR1 TA2CCR0 = PWM_PERIOD; // PWM Period TA2CCTL1 = OUTMOD_7; // reset/set TA2CCR1 = PWM_DUTY(val); // PWM duty cycle TA2CTL = TASSEL_2 + MC_1+ analog_div; // SMCLK, up mode break; case T2A2: // Timer0 / CCR1 TA2CCR0 = PWM_PERIOD; // PWM Period TA2CCTL2 = OUTMOD_7; // reset/set TA2CCR2 = PWM_DUTY(val); // PWM duty cycle TA2CTL = TASSEL_2 + MC_1+ analog_div; // SMCLK, up mode break; #endif case NOT_ON_TIMER: // not on a timer output pin default: // or TxA0 pin if (val < 128) { digitalWrite(pin, LOW); // } else { digitalWrite(pin, HIGH); } } } }
uint8_t WatchPin::pinPWM(uint8_t _pin){ //if pin is pwm return its value, if not return 0 switch(digitalPinToTimer(_pin)) { #if defined(TCCR0) && defined(COM00) && !defined(__AVR_ATmega8__) case TIMER0A: return OCR0; break; #endif #if defined(TCCR0A) && defined(COM0A1) case TIMER0A: return OCR0A; break; #endif #if defined(TCCR0A) && defined(COM0B1) case TIMER0B: return OCR0B; break; #endif #if defined(TCCR1A) && defined(COM1A1) case TIMER1A: return OCR1A; break; #endif #if defined(TCCR1A) && defined(COM1B1) case TIMER1B: return OCR1B; break; #endif #if defined(TCCR2) && defined(COM21) case TIMER2: return OCR2; break; #endif #if defined(TCCR2A) && defined(COM2A1) case TIMER2A: return OCR2A; break; #endif #if defined(TCCR2A) && defined(COM2B1) case TIMER2B: return OCR2B; break; #endif #if defined(TCCR3A) && defined(COM3A1) case TIMER3A: return OCR3A; break; #endif #if defined(TCCR3A) && defined(COM3B1) case TIMER3B: return OCR3B; break; #endif #if defined(TCCR3A) && defined(COM3C1) case TIMER3C: return OCR3C; break; #endif #if defined(TCCR4A) case TIMER4A: return OCR4A; break; #endif #if defined(TCCR4A) && defined(COM4B1) case TIMER4B: return OCR4B; break; #endif #if defined(TCCR4A) && defined(COM4C1) case TIMER4C: return OCR4C; break; #endif #if defined(TCCR4C) && defined(COM4D1) case TIMER4D: return OCR4D; break; #endif #if defined(TCCR5A) && defined(COM5A1) case TIMER5A: return OCR5A; break; #endif #if defined(TCCR5A) && defined(COM5B1) case TIMER5B: return OCR5B; break; #endif #if defined(TCCR5A) && defined(COM5C1) case TIMER5C: return OCR5C; break; #endif case NOT_ON_TIMER: default: return NOT_ON_TIMER; break; } }
boolean WatchPin::pinIsPWM(uint8_t _pin){ return (digitalPinToTimer(_pin)==0) ? false:true; //return TRUE if pin requested is PWM, FALSE if not }
// Right now, PWM output only works on the pins with // hardware support. These are defined in the appropriate // pins_*.c file. For the rest of the pins, we default // to digital output. void analogWrite(uint8_t pin, int val) { // We need to make sure the PWM output is enabled for those pins // that support it, as we turn it off when digitally reading or // writing with them. Also, make sure the pin is in output mode // for consistenty with Wiring, which doesn't require a pinMode // call for the analog output pins. pinMode(pin, OUTPUT); if (digitalPinToTimer(pin) == TIMER1A) { // connect pwm to pin on timer 1, channel A sbi(TCCR1A, COM1A1); // set pwm duty OCR1A = val; } else if (digitalPinToTimer(pin) == TIMER1B) { // connect pwm to pin on timer 1, channel B sbi(TCCR1A, COM1B1); // set pwm duty OCR1B = val; /* ATMega48/32/324P/644 mod provided by AndreS at robotcraft.ca - START */ #if defined(__AVR_ATmega48__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega644__) } else if (digitalPinToTimer(pin) == TIMER0A) { // connect pwm to pin on timer 0, channel A sbi(TCCR0A, COM0A1); // set pwm duty OCR0A = val; } else if (digitalPinToTimer(pin) == TIMER0B) { // connect pwm to pin on timer 0, channel B sbi(TCCR0A, COM0B1); // set pwm duty OCR0B = val; } else if (digitalPinToTimer(pin) == TIMER2A) { // connect pwm to pin on timer 2, channel A sbi(TCCR2A, COM2A1); // set pwm duty OCR2A = val; } else if (digitalPinToTimer(pin) == TIMER2B) { // connect pwm to pin on timer 2, channel B sbi(TCCR2A, COM2B1); // set pwm duty OCR2B = val; #elif defined(__AVR_ATmega32__) } else if (digitalPinToTimer(pin) == TIMER0) { // connect pwm to pin on timer 0 sbi(TCCR0, COM01); // set pwm duty OCR0 = val; } else if (digitalPinToTimer(pin) == TIMER2) { // connect pwm to pin on timer 2 sbi(TCCR2, COM21); // set pwm duty OCR2 = val; /* ATMega48/32/324P/644 mod provided by AndreS at robotcraft.ca - END */ #else } else if (digitalPinToTimer(pin) == TIMER2) { // connect pwm to pin on timer 2, channel B sbi(TCCR2, COM21); // set pwm duty OCR2 = val; #endif } else if (val < 128) digitalWrite(pin, LOW); else digitalWrite(pin, HIGH); }
void AdaEncoder::addEncoder(char _id, uint8_t _pinA, uint8_t _pinB) { AdaEncoder *tmpencoder; id=_id; pinA=_pinA; pinB=_pinB; #ifdef DEBUG printBuffer.putString(getPSTR("addEncoder: ")); printBuffer.put(id); printBuffer.put('\n'); printBuffer.putHex(pinA); printBuffer.put(' '); printBuffer.putHex(pinB); printBuffer.put(' '); printBuffer.putString(getPSTR(" *\n")); #endif // error checking if (pinA == pinB) return; // No! silly if (pinA < 8 && pinB > 7) return; // No! different ports if ((pinA > 7 && pinA < 14) && (pinB < 8 || pinB > 13)) return; // No! different ports if (pinA > 13 && pinB < 14) return; // No! different ports if (pinA > 19 || pinB > 19) return; // No! out of band turning=0; clicks=0; /* ADD TO THE LIST HERE */ if (firstEncoder==NULL) { firstEncoder=this; } else { tmpencoder=firstEncoder; while (tmpencoder->next != NULL) tmpencoder=tmpencoder->next; tmpencoder->next=this; } this->next=NULL; port=portInputRegister(digitalPinToPort(pinA)); if (port == NOT_A_PIN) { return; } // ** A ** bitA=digitalPinToBitMask(pinA); uint8_t timerA=digitalPinToTimer(pinA); if (timerA != NOT_ON_TIMER) turnOffPWM(timerA); #ifdef DEBUG //char buffer[16]; //Serial.print("encoder addr: "); //sprintf(buffer, "%p", this); //Serial.println(buffer); printBuffer.putString("bitA: "); printBuffer.putHex(bitA); #endif // ** B ** bitB=digitalPinToBitMask(pinB); uint8_t timerB=digitalPinToTimer(pinB); if (timerB != NOT_ON_TIMER) turnOffPWM(timerB); #ifdef DEBUG printBuffer.putString("bitB: "); printBuffer.putHex(bitB); #endif // ** INTERRUPT ** #ifndef SWINTR_DEBUG // This section should be on normally. OFF if performing software interrupts! // GreyGnome DEBUG: Turn these two lines off by defining // SWINTR_DEBUG. In the sketch, turn the pins into Outputs and set them high. // Then set them as you wish, to create software interrupts. pinMode(pinA, INPUT); pinMode(pinB, INPUT); digitalWrite(pinA, HIGH); digitalWrite(pinB, HIGH); #endif attachInterrupt(pinA, pinB); #ifdef DEBUGTIME ada_output_port=portOutputRegister(digitalPinToPort(13)); // GreyGnome DEBUG. ada_output_mask=digitalPinToBitMask(13); // defines the actual pin on that port ada_not_output_mask=ada_output_mask^0xFF; #endif }
void _analogWrite(uint8_t pin, uint8_t val) { // We need to make sure the PWM output is enabled for those pins // that support it, as we turn it off when digitally reading or // writing with them. Also, make sure the pin is in output mode // for consistenty with Wiring, which doesn't require a pinMode // call for the analog output pins. // This is now done from static inline void analogWrite() // which is defined in Arduino.h, this allows us to use the // optimized pinMode() for constant pins. // pinMode(pin, OUTPUT); #if ! (defined(ANALOG_WRITE_FLIPPED) && ANALOG_WRITE_FLIPPED) if (val <= 0) { digitalWrite(pin, LOW); } else if (val >= 255) { digitalWrite(pin, HIGH); } else #else // If we flip (invert) the PWM, so that 255 is Off and 0 is On, // then we can do away with the special cases of val == 0 // and val == 255 which in the normal directionality have to // turn off the PWM and use digitalWrite. // // We don't get fully "on" (max is about 99.5%), but that's less // of a problem than not getting fully "off" especially when using // an LED which is probably the most common use case here. // // This saves us a bunch of space for something like the usual // led fader since digitalWrite() can be totally optimized out. // // Of course, we don't want the user to know to do this, so // we take 0 = Off and 255 = On and flip that before passing // it to the AVR which is expecting the flipped value. val = 255-val; #endif { #ifdef turnOnPWM // Some variants (see tiny13) define a turnOnPWM macro which reduces code size turnOnPWM( digitalPinToTimer(pin), val ); #else // All this defined() logic is silly trying to overly generalise wiring_analog.h // to cater for different variants; instead see variants/tiny13/pins_arduino.c for a // better way of doing this for variants in future - in other words, you should ask // the variant to turn on pwm for itself, not try and figure out how to turn on pwm // for any given variant by looking at what is and isn't defined. Crazyness. // // In short, you should #define turnOnPWM(t, v) ( _turnOnPWM(t,v) ) // in pins_arduino.h, and create pins_arduino.c to define the _turnOnPWM() function // (where t is the timer (eg TIMER0A) and v is the value 0-255) // // Do similar for turnOffPWM(t) by the way! uint8_t timer = digitalPinToTimer(pin); #if defined(TCCR0A) && defined(COM0A1) if( timer == TIMER0A){ // connect pwm to pin on timer 0, channel A sbi(TCCR0A, COM0A1); cbi(TCCR0A, COM0A0); OCR0A = val; // set pwm duty } else #endif #if defined(TCCR0A) && defined(COM0B1) if( timer == TIMER0B){ // connect pwm to pin on timer 0, channel B sbi(TCCR0A, COM0B1); cbi(TCCR0A, COM0B0); OCR0B = val; // set pwm duty } else #endif #if defined(TCCR1A) && defined(COM1A1) && !defined(TCCR1E) if( timer == TIMER1A){ // connect pwm to pin on timer 1, channel A sbi(TCCR1A, COM1A1); cbi(TCCR1A, COM1A0); #ifdef OC1AX cbi(TCCR1D, OC1AV); cbi(TCCR1D, OC1AU); cbi(TCCR1D, OC1AW); sbi(TCCR1D, OC1AX); #endif OCR1A = val; // set pwm duty } else #endif #if defined(TCCR1E) if( timer == TIMER1A){ // connect pwm to pin on timer 1, channel A cbi(TCCR1C,COM1A1S); sbi(TCCR1C,COM1A0S); OCR1A = val; // set pwm duty } else if (timer == TIMER1B){ // connect pwm to pin on timer 1, channel A cbi(TCCR1C,COM1B1S); sbi(TCCR1C,COM1B0S); OCR1B = val; // set pwm duty } else if (timer == TIMER1D){ // connect pwm to pin on timer 1, channel A cbi(TCCR1C,COM1D1); sbi(TCCR1C,COM1D0); OCR1D = val; // set pwm duty } else #endif #if defined(TCCR1) && defined(COM1A1) if(timer == TIMER1A){ // connect pwm to pin on timer 1, channel A sbi(TCCR1, COM1A1); cbi(TCCR1, COM1A0); OCR1A = val; // set pwm duty } else #endif #if defined(TCCR1A) && defined(COM1B1) && !defined(TCCR1E) if( timer == TIMER1B){ // connect pwm to pin on timer 1, channel B sbi(TCCR1A, COM1B1); cbi(TCCR1A, COM1B0); #ifdef OC1BV sbi(TCCR1D, OC1BV); cbi(TCCR1D, OC1BU); cbi(TCCR1D, OC1BW); cbi(TCCR1D, OC1BX); #endif OCR1B = val; // set pwm duty } else #endif #if defined(TCCR1) && defined(COM1B1) if( timer == TIMER1B){ // connect pwm to pin on timer 1, channel B sbi(GTCCR, COM1B1); cbi(GTCCR, COM1B0); OCR1B = val; // set pwm duty } else #endif { if (val < 128) { digitalWrite(pin, LOW); } else { digitalWrite(pin, HIGH); } } #endif } }
void AdaEncoder::addEncoder(char id, uint8_t pinA, uint8_t pinB) { #ifdef DEBUG Serial.print("DEBUG addEncoder: "); Serial.print(pinA, HEX); Serial.print(' '); Serial.print(pinB, HEX); Serial.print(' '); Serial.println(" *"); #endif // error checking if (pinA == pinB) return; // No! silly if (pinA < 8 && pinB > 7) return; // No! different ports if ((pinA > 7 && pinA < 14) && (pinB < 8 || pinB > 13)) return; // No! different ports if (pinA > 13 && pinB < 14) return; // No! different ports if (pinA > 19 || pinB > 19) return; // No! out of band encoder *newencoder=(encoder*) malloc(sizeof(struct encoder)); newencoder->turning=0; newencoder->clicks=0; newencoder->id=id; newencoder->next=NULL; newencoder->port=portInputRegister(digitalPinToPort(pinA)); if (newencoder->port == NOT_A_PIN) { free(newencoder); return; } // ** A ** newencoder->bitA=digitalPinToBitMask(pinA); uint8_t timerA=digitalPinToTimer(pinA); if (timerA != NOT_ON_TIMER) turnOffPWM(timerA); #ifdef DEBUG char buffer[16]; Serial.print("encoder addr: "); sprintf(buffer, "%p", newencoder); Serial.println(buffer); Serial.print("bitA: "); Serial.print(newencoder->bitA, BIN); #endif // ** B ** newencoder->bitB=digitalPinToBitMask(pinB); uint8_t timerB=digitalPinToTimer(pinB); if (timerB != NOT_ON_TIMER) turnOffPWM(timerB); #ifdef DEBUG Serial.print("bitB: "); Serial.println(newencoder->bitB, BIN); #endif // ** INTERRUPT ** #ifndef SWINTR_DEBUG // This section should be on normally. OFF if performing software interrupts! // GreyGnome DEBUG: Turn these two lines off by defining // SWINTR_DEBUG. In the sketch, turn the pins into Outputs and set them high. // Then set them as you wish, to create software interrupts. pinMode(pinA, INPUT); pinMode(pinB, INPUT); digitalWrite(pinA, HIGH); digitalWrite(pinB, HIGH); #endif AdaEncoders[pinA]=newencoder; AdaEncoders[pinB]=newencoder; AdaEncoder::attachInterrupt(pinA, pinB); // encoder linked list: add to it. Use this in loop() to search for the encoder that triggered the interrupt. if (firstEncoder==NULL) { firstEncoder=newencoder; } else { tmpencoder=firstEncoder; while (tmpencoder->next != NULL) { tmpencoder=tmpencoder->next; } tmpencoder->next=newencoder; } #ifdef DEBUGTIME ada_output_port=portOutputRegister(digitalPinToPort(13)); // GreyGnome DEBUG. ada_output_mask=digitalPinToBitMask(13); // defines the actual pin on that port ada_not_output_mask=ada_output_mask^0xFF; #endif }
//http://www.arduino.cc/en/Reference/AnalogWrite int isValidPWM(int pin){ //return true if is on a timer return (digitalPinToTimer(pin) != NOT_ON_TIMER); }
// Right now, PWM output only works on the pins with // hardware support. These are defined in the appropriate // pins_*.c file. For the rest of the pins, we default // to digital output. void analogWrite(uint8_t pin, int val) { // We need to make sure the PWM output is enabled for those pins // that support it, as we turn it off when digitally reading or // writing with them. Also, make sure the pin is in output mode // for consistenty with Wiring, which doesn't require a pinMode // call for the analog output pins. pinMode(pin, OUTPUT); if (val == 0) { digitalWrite(pin, LOW); } else if (val == 255) { digitalWrite(pin, HIGH); } else { switch(digitalPinToTimer(pin)) { // XXX fix needed for atmega8 #if defined(TCCR0) && defined(COM00) && !defined(__AVR_ATmega8__) case TIMER0A: // connect pwm to pin on timer 0 sbi(TCCR0, COM00); OCR0 = val; // set pwm duty break; #endif #if defined(TCCR0A) && defined(COM0A1) case TIMER0A: // connect pwm to pin on timer 0, channel A sbi(TCCR0A, COM0A1); OCR0A = val; // set pwm duty break; #endif #if defined(TCCR0A) && defined(COM0B1) case TIMER0B: // connect pwm to pin on timer 0, channel B sbi(TCCR0A, COM0B1); OCR0B = val; // set pwm duty break; #endif /* case TIMER1B: // connect pwm to pin on timer 1, channel B sbi(GTCCR, COM1B1); sbi(GTCCR, PWM1B); OCR1B = val; // set pwm duty break; */ #if defined(TCCR1A) && defined(COM1A1) case TIMER1A: // connect pwm to pin on timer 1, channel A sbi(TCCR1A, COM1A1); OCR1A = val; // set pwm duty break; #endif #if defined(TCCR1A) && defined(COM1B1) case TIMER1B: // connect pwm to pin on timer 1, channel B sbi(TCCR1A, COM1B1); OCR1B = val; // set pwm duty break; #endif case NOT_ON_TIMER: default: if (val < 128) { digitalWrite(pin, LOW); } else { digitalWrite(pin, HIGH); } } } }
/** * analogWrite * * set PWM output level * * @param pin pin number * @param val duty cycle */ void analogWrite(uint8_t pin, uint16_t val) { if (val == 0) { pinMode(pin, OUTPUT); digitalWrite(pin, LOW); } else { uint8_t bit = digitalPinToBitMask(pin); uint8_t port = digitalPinToPort(pin); volatile uint8_t *dir = portDirRegister(port); volatile uint8_t *sel = portSelRegister(port); volatile uint8_t *map = digitalPinToPortMap(pin); *dir |= bit; // Config pin as an output *sel |= bit; // Select alternate function // Set PWM period TA0CCR0 = analogPeriod; TA1CCR0 = analogPeriod; uint8_t timer = digitalPinToTimer(pin); PMAPPWD = 0x02D52; // Get write-access to port mapping regs PMAPCTL |= PMAPRECFG; // Leave Pin mapping open switch(timer) { case T0A1: *map = PM_TA0CCR1A; TA0CCTL1 = OUTMOD_7; // CCR1 reset/set TA0CCR1 = PWM_DUTY(val); // CCR1 PWM duty cycle break; case T0A2: *map = PM_TA0CCR2A; TA0CCTL2 = OUTMOD_7; // CCR1 reset/set TA0CCR2 = PWM_DUTY(val); // CCR1 PWM duty cycle break; case T0A3: *map = PM_TA0CCR3A; TA0CCTL3 = OUTMOD_7; // CCR1 reset/set TA0CCR3 = PWM_DUTY(val); // CCR1 PWM duty cycle break; case T0A4: *map = PM_TA0CCR4A; TA0CCTL4 = OUTMOD_7; // CCR1 reset/set TA0CCR4 = PWM_DUTY(val); // CCR1 PWM duty cycle break; case T1A1: *map = PM_TA1CCR1A; TA1CCTL1 = OUTMOD_7; // CCR1 reset/set TA1CCR1 = PWM_DUTY(val); // CCR1 PWM duty cycle break; case T1A2: *map = PM_TA1CCR2A; TA1CCTL2 = OUTMOD_7; // CCR1 reset/set TA1CCR2 = PWM_DUTY(val); // CCR1 PWM duty cycle break; default: break; } PMAPPWD = 0; // Lock port mapping registers if (timer < T1A1) { if (val == TA0CCR0) // duty cycle = period? { pinMode(pin, OUTPUT); digitalWrite(pin, HIGH); } else TA0CTL = TASSEL_2 + MC_1 + TACLR; // SMCLK, up mode, clear TAR } else { if (val == TA1CCR0) // duty cycle = period? { pinMode(pin, OUTPUT); digitalWrite(pin, HIGH); } else TA1CTL = TASSEL_2 + MC_1 + TACLR; // SMCLK, up mode, clear TAR } } }
//********************************************************************* //* PWM output only works on the pins with hardware support. //* These are defined in the appropriate pins_*.c file. //* For the rest of the pins, we default to digital output. //********************************************************************* void analogWrite(uint8_t pin, int val) { // We need to make sure the PWM output is enabled for those pins // that support it, as we turn it off when digitally reading or // writing with them. Also, make sure the pin is in output mode // for consistenty with Wiring, which doesn't require a pinMode // call for the analog output pins. pinMode(pin, OUTPUT); if (val == 0) { digitalWrite(pin, LOW); } else if (val == 255) { digitalWrite(pin, HIGH); } else { switch(digitalPinToTimer(pin)) { #ifdef _OCMP1 case TIMER_OC1: //* Open Timer2 with Period register value OpenTimer2(T2_ON | T2_PS_1_256, PWM_TIMER_PERIOD); OpenOC1( OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE, (PWM_TIMER_PERIOD*val)/256, (PWM_TIMER_PERIOD*val)/256 ); //Set duty cycle on fly SetDCOC1PWM((PWM_TIMER_PERIOD*val)/256); break; #endif #ifdef _OCMP2 case TIMER_OC2: //* Open Timer2 with Period register value OpenTimer2(T2_ON | T2_PS_1_256, PWM_TIMER_PERIOD); OpenOC2( OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE, (PWM_TIMER_PERIOD*val)/256, (PWM_TIMER_PERIOD*val)/256 ); //Set duty cycle on fly SetDCOC2PWM((PWM_TIMER_PERIOD*val)/256); break; #endif #ifdef _OCMP3 case TIMER_OC3: //* Open Timer2 with Period register value OpenTimer2(T2_ON | T2_PS_1_256, PWM_TIMER_PERIOD); OpenOC3( OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE, (PWM_TIMER_PERIOD*val)/256, (PWM_TIMER_PERIOD*val)/256 ); //Set duty cycle on fly SetDCOC3PWM((PWM_TIMER_PERIOD*val)/256); break; #endif #ifdef _OCMP4 case TIMER_OC4: //* Open Timer2 with Period register value OpenTimer2(T2_ON | T2_PS_1_256, PWM_TIMER_PERIOD); OpenOC4( OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE, (PWM_TIMER_PERIOD*val)/256, (PWM_TIMER_PERIOD*val)/256 ); //Set duty cycle on fly SetDCOC4PWM((PWM_TIMER_PERIOD*val)/256); break; #endif #ifdef _OCMP5 case TIMER_OC5: //* Open Timer2 with Period register value OpenTimer2(T2_ON | T2_PS_1_256, PWM_TIMER_PERIOD); OpenOC5( OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE, (PWM_TIMER_PERIOD*val)/256, (PWM_TIMER_PERIOD*val)/256 ); //Set duty cycle on fly SetDCOC5PWM((PWM_TIMER_PERIOD*val)/256); break; #endif #if 0 //* this is the original code, I want to keep it around for refernce for a bit longer #ifdef _OCMP1 case TIMER_OC1: //* Open Timer2 with Period register value OpenTimer2(T2_ON | T2_PS_1_256, PWM_TIMER_PERIOD); OpenOC1( OC_ON | OC_TIMER_MODE32 | OC_TIMER2_SRC | OC_CONTINUE_PULSE | OC_LOW_HIGH, 256, (256 - val) ); // SetDCOC1PWM((PWM_TIMER_PERIOD * val) / 256); break; #endif #ifdef _OCMP2 case TIMER_OC2: //* Open Timer2 with Period register value OpenTimer2(T2_ON | T2_PS_1_256, PWM_TIMER_PERIOD); OpenOC2( OC_ON | OC_TIMER_MODE32 | OC_TIMER2_SRC | OC_CONTINUE_PULSE | OC_LOW_HIGH, 256, (256 - val) ); // SetDCOC2PWM((PWM_TIMER_PERIOD * val) / 256); break; #endif #ifdef _OCMP3 case TIMER_OC3: //* Open Timer2 with Period register value OpenTimer2(T2_ON | T2_PS_1_256, PWM_TIMER_PERIOD); OpenOC3( OC_ON | OC_TIMER_MODE32 | OC_TIMER2_SRC | OC_CONTINUE_PULSE | OC_LOW_HIGH, 256, (256 - val) ); // SetDCOC3PWM((PWM_TIMER_PERIOD * val) / 256); break; #endif #ifdef _OCMP4 case TIMER_OC4: //* Open Timer2 with Period register value OpenTimer2(T2_ON | T2_PS_1_256, PWM_TIMER_PERIOD); OpenOC4( OC_ON | OC_TIMER_MODE32 | OC_TIMER2_SRC | OC_CONTINUE_PULSE | OC_LOW_HIGH, 256, (256 - val) ); // SetDCOC4PWM((PWM_TIMER_PERIOD * val) / 256); break; #endif #ifdef _OCMP5 case TIMER_OC5: //* Open Timer2 with Period register value OpenTimer2(T2_ON | T2_PS_1_256, PWM_TIMER_PERIOD); OpenOC5( OC_ON | OC_TIMER_MODE32 | OC_TIMER2_SRC | OC_CONTINUE_PULSE | OC_LOW_HIGH, 256, (256 - val) ); // SetDCOC5PWM((PWM_TIMER_PERIOD * val) / 256); break; #endif #endif case NOT_ON_TIMER: default: if (val < 128) { digitalWrite(pin, LOW); } else { digitalWrite(pin, HIGH); } } } }
void PWMWrite(uint8_t pin, uint32_t analog_res, uint32_t duty, uint32_t freq) { analog_res = analog_res * 1000; freq; uint32_t load = (F_CPU / freq) * 1000; uint32_t match = load / (analog_res / duty); match = match; load = load / 1000; uint16_t prescaler = load >> 16; uint16_t prescaler_match = match >> 16; uint8_t timer = digitalPinToTimer(pin); if(timer == NOT_ON_TIMER) return; MAP_PRCMPeripheralClkEnable(PRCM_TIMERA0 + (timer/2), PRCM_RUN_MODE_CLK); uint16_t pnum = digitalPinToPinNum(pin); switch(timer) { /* PWM0/1 */ case TIMERA0A: case TIMERA0B: MAP_PinTypeTimer(pnum, PIN_MODE_5); break; /* PWM2/3 */ case TIMERA1A: case TIMERA1B: MAP_PinTypeTimer(pnum, PIN_MODE_9); break; /* PWM4/5 */ case TIMERA2A: case TIMERA2B: MAP_PinTypeTimer(pnum, PIN_MODE_3); break; /* PWM6/7 */ case TIMERA3A: case TIMERA3B: MAP_PinTypeTimer(pnum, PIN_MODE_3); break; } uint32_t base = TIMERA0_BASE + ((timer/2) << 12); /* FIXME: If B is already opperational and configure A, B get's messed up. */ MAP_TimerConfigure(base, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM | TIMER_CFG_B_PWM); uint16_t timerab = timer % 2 ? TIMER_B : TIMER_A; MAP_TimerPrescaleSet(base, timerab, prescaler); MAP_TimerPrescaleMatchSet(base, timerab, prescaler_match); MAP_TimerControlLevel(base, timerab, 1); MAP_TimerLoadSet(base, timerab, load); MAP_TimerMatchSet(base, timerab, match); MAP_TimerEnable(base, timerab); }
void tone( uint8_t _pin, unsigned int frequency, unsigned long duration ) { if ( tone_pin == 255 ) { /* Set the timer to power-up conditions so we start from a known state */ // Ensure the timer is in the same state as power-up #if (TIMER_TO_USE_FOR_TONE == 0) TCCR0B = (0<<FOC0A) | (0<<FOC0B) | (0<<WGM02) | (0<<CS02) | (0<<CS01) | (0<<CS00); TCCR0A = (0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (0<<WGM01) | (0<<WGM00); // Reset the count to zero TCNT0 = 0; // Set the output compare registers to zero OCR0A = 0; OCR0B = 0; #if defined(TIMSK) // Disable all Timer0 interrupts TIMSK &= ~((1<<OCIE0B) | (1<<OCIE0A) | (1<<TOIE0)); // Clear the Timer0 interrupt flags TIFR |= ((1<<OCF0B) | (1<<OCF0A) | (1<<TOV0)); #elif defined(TIMSK1) // Disable all Timer0 interrupts TIMSK0 &= ~((1<<OCIE0B) | (1<<OCIE0A) | (1<<TOIE0)); // Clear the Timer0 interrupt flags TIFR0 |= ((1<<OCF0B) | (1<<OCF0A) | (1<<TOV0)); #endif #elif (TIMER_TO_USE_FOR_TONE == 1) && defined(TCCR1) // Turn off Clear on Compare Match, turn off PWM A, disconnect the timer from the output pin, stop the clock TCCR1 = (0<<CTC1) | (0<<PWM1A) | (0<<COM1A1) | (0<<COM1A0) | (0<<CS13) | (0<<CS12) | (0<<CS11) | (0<<CS10); // Turn off PWM A, disconnect the timer from the output pin, no Force Output Compare Match, no Prescaler Reset GTCCR &= ~((1<<PWM1B) | (1<<COM1B1) | (1<<COM1B0) | (1<<FOC1B) | (1<<FOC1A) | (1<<PSR1)); // Reset the count to zero TCNT1 = 0; // Set the output compare registers to zero OCR1A = 0; OCR1B = 0; OCR1C = 0; // Disable all Timer1 interrupts TIMSK &= ~((1<<OCIE1A) | (1<<OCIE1B) | (1<<TOIE1)); // Clear the Timer1 interrupt flags TIFR |= ((1<<OCF1A) | (1<<OCF1B) | (1<<TOV1)); #elif (TIMER_TO_USE_FOR_TONE == 1) && defined(TCCR1E) TCCR1A = 0; TCCR1B = 0; TCCR1C = 0; TCCR1D = 0; TCCR1E = 0; // Reset the count to zero TCNT1 = 0; // Set the output compare registers to zero OCR1A = 0; OCR1B = 0; // Disable all Timer1 interrupts TIMSK &= ~((1<<TOIE1) | (1<<OCIE1A) | (1<<OCIE1B) | (1<<OCIE1D)); // Clear the Timer1 interrupt flags TIFR |= ((1<<TOV1) | (1<<OCF1A) | (1<<OCF1B) | (1<<OCF1D)); #elif (TIMER_TO_USE_FOR_TONE == 1) // Turn off Input Capture Noise Canceler, Input Capture Edge Select on Falling, stop the clock TCCR1B = (0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (0<<CS10); // Disconnect the timer from the output pins, Set Waveform Generation Mode to Normal TCCR1A = (0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10); // Reset the count to zero TCNT1 = 0; // Set the output compare registers to zero OCR1A = 0; OCR1B = 0; // Disable all Timer1 interrupts #if defined(TIMSK) TIMSK &= ~((1<<TOIE1) | (1<<OCIE1A) | (1<<OCIE1B) | (1<<ICIE1)); // Clear the Timer1 interrupt flags TIFR |= ((1<<TOV1) | (1<<OCF1A) | (1<<OCF1B) | (1<<ICF1)); #elif defined(TIMSK1) // Disable all Timer1 interrupts TIMSK1 &= ~((1<<TOIE1) | (1<<OCIE1A) | (1<<OCIE1B) | (1<<ICIE1)); // Clear the Timer1 interrupt flags TIFR1 |= ((1<<TOV1) | (1<<OCF1A) | (1<<OCF1B) | (1<<ICF1)); #endif #endif /* Compare Output Mode = Normal port operation, OCxA/OCxB disconnected. Waveform Generation Mode = 4; 0100; CTC; (Clear Timer on Compare); OCR1A; Immediate; MAX Clock Select = No clock source (Timer/Counter stopped). Note: Turn off the clock first to avoid ticks and scratches. */ #if TIMER_TO_USE_FOR_TONE == 1 #if defined(TCCR1) sbi(TCCR1,CTC1); cbi(TCCR1,PWM1A); cbi(GTCCR,PWM1B); #elif !defined(TCCR1E) cbi(TCCR1A,WGM10); cbi(TCCR1A,WGM11); sbi(TCCR1B,WGM12); cbi(TCCR1B,WGM13); #endif #elif TIMER_TO_USE_FOR_TONE == 0 cbi(TCCR0A,WGM00); sbi(TCCR0A,WGM01); cbi(TCCR0B,WGM02); #endif /* If the tone pin can be driven directly from the timer */ #if (TIMER_TO_USE_FOR_TONE == 1) && defined(TCCR1E) if ( (digitalPinToTimer(_pin) == TIMER1A) || (digitalPinToTimer(_pin) == TIMER1B) || (digitalPinToTimer(_pin) == TIMER1D) ) { #elif (TIMER_TO_USE_FOR_TONE == 1) if ( (digitalPinToTimer(_pin) == TIMER1A) || (digitalPinToTimer(_pin) == TIMER1B) ) { #elif (TIMER_TO_USE_FOR_TONE == 0) if ( (digitalPinToTimer(_pin) == TIMER0A) || (digitalPinToTimer(_pin) == TIMER0B) ) { #else if (0) { //unsupported, so only use software. #endif /* Pin toggling is handled by the hardware */ tone_timer_pin_register = NULL; tone_timer_pin_mask = 0; uint8_t timer = digitalPinToTimer(_pin); #if defined(COM0A1) //Just in case there are now pwm pins on timer0 (ATTiny861) if (timer == TIMER0A) { /* Compare Output Mode = Toggle OC0A on Compare Match. */ cbi(TCCR0A,COM0A1); sbi(TCCR0A,COM0A0); } else #endif if (timer == TIMER1A) { /* Compare Output Mode = Toggle OC1A on Compare Match. */ #if defined(TCCR1) cbi(TCCR1,COM1A1); sbi(TCCR1,COM1A0); #elif defined(TCCR1E) cbi(TCCR1C,COM1A1S); sbi(TCCR1C,COM1A0S); #else cbi(TCCR1A,COM1A1); sbi(TCCR1A,COM1A0); #endif } #if defined(COM0B1) //Just in case there are <2 pwm pins on timer0 (ATTiny861) else if (timer == TIMER0B) { /* Compare Output Mode = Toggle OC0B on Compare Match. */ cbi(TCCR0A,COM0B1); sbi(TCCR0A,COM0B0); } #endif #if defined(COM1D1) //in case there is a OCRD. (ATtiny861) else if (timer == TIMER1D){ /* Compare Output Mode = Toggle OC1D on Compare Match. */ #if defined(TCCR1) cbi(TCCR1,COM1D1); sbi(TCCR1,COM1D0); #elif defined(TCCR1E) cbi(TCCR1C,COM1D1); sbi(TCCR1C,COM1D0); #else cbi(TCCR1A,COM1D1); sbi(TCCR1A,COM1D0); #endif } #endif else { /* Compare Output Mode = Toggle OC1B on Compare Match. */ #if defined(TCCR1) cbi(GTCCR,COM1B1); sbi(GTCCR,COM1B0); #elif defined(TCCR1E) cbi(TCCR1C,COM1B1S); sbi(TCCR1C,COM1B0S); #else cbi(TCCR1A,COM1B1); sbi(TCCR1A,COM1B0); #endif } } else { /* Save information needed by the interrupt service routine */ tone_timer_pin_register = portOutputRegister( digitalPinToPort( _pin ) ); tone_timer_pin_mask = digitalPinToBitMask( _pin ); /* Compare Output Mode = Normal port operation, OCxA disconnected. */ #if (TIMER_TO_USE_FOR_TONE == 0) TCCR0A &= ~((1<<COM0A1)|(1<<COM0A0)|(1<<COM0B1)|(1<<COM0B0)); #elif (TIMER_TO_USE_FOR_TONE == 1) & defined(TCCR1) TCCR1 &= ~((1<<COM1A1)|(1<<COM1A0)); GTCCR &= ~((1<<COM1B1)|(1<<COM1B0)); #elif (TIMER_TO_USE_FOR_TONE == 1) && defined(TCCR1E) TCCR1C &= ~((1<<COM1A1S)|(1<<COM1A0S)|(1<<COM1B1S)|(1<<COM1B0S)|(1<<COM1D1)|(1<<COM1D0)); #elif (TIMER_TO_USE_FOR_TONE == 1) TCCR1A &= ~((1<<COM1A1)|(1<<COM1A0)|(1<<COM1B1)|(1<<COM1B0)); #endif } /* Ensure the pin is configured for output */ pinMode( _pin, OUTPUT ); tone_pin = _pin; } if ( tone_pin == _pin ) { /* Stop the clock while we make changes, then set the counter to zero to reduce ticks and scratches. */ // Millis timer is always processor clock divided by MillisTimer_Prescale_Value (64) #if (TIMER_TO_USE_FOR_TONE == 0) TCCR0B &= ~((1<<CS02)|(1<<CS01)|(1<<CS00)); TCNT0 = 0; #elif (TIMER_TO_USE_FOR_TONE == 1) && defined(TCCR1) TCCR1 &= ~((1<<CS13)|(1<<CS12)|(1<<CS11)|(1<<CS10)); TCNT1 = 0; #elif (TIMER_TO_USE_FOR_TONE == 1) && defined(TCCR1E) TCCR1B &= ~((1<<CS13)|(1<<CS12)|(1<<CS11)|(1<<CS10)); TCNT1 = 0; #elif (TIMER_TO_USE_FOR_TONE == 1) TCCR1B &= ~((1<<CS12)|(1<<CS11)|(1<<CS10)); TCNT1 = 0; #endif if ( frequency > 0 ) { /* Determine which prescaler to use */ /* Set the Output Compare Register (rounding up) */ #if TIMER_TO_USE_FOR_TONE == 1 uint16_t ocr = F_CPU / frequency / 2; #if defined(TCCR1E) uint8_t prescalarbits = 0b0001; if (ocr > 256) { ocr >>= 3; //divide by 8 prescalarbits = 0b0100; // ck/8 if (ocr > 256) { ocr >>= 3; //divide by a further 8 prescalarbits = 0b0111; //ck/64 if (ocr > 256) { ocr >>= 2; //divide by a further 4 prescalarbits = 0b1001; //ck/256 if (ocr > 256) { // can't do any better than /1024 ocr >>= 2; //divide by a further 4 prescalarbits = 0b1011; //ck/1024 } } }