Tone.cpp
1 /* Tone generation for the Teensy and Teensy++ 2 * http://www.pjrc.com/teensy/ 3 * Copyright (c) 2010 PJRC.COM, LLC 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a copy 6 * of this software and associated documentation files (the "Software"), to deal 7 * in the Software without restriction, including without limitation the rights 8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 * copies of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 * THE SOFTWARE. 22 */ 23 24 #include <avr/interrupt.h> 25 #include "wiring.h" 26 #include "core_pins.h" 27 #include "pins_arduino.h" 28 29 static uint8_t timer_acquired = 0; 30 31 static uint8_t *tone1_reg = (uint8_t *)0; 32 static uint8_t tone1_mask = 0; 33 static uint16_t tone1_inc = 0; 34 static uint32_t tone1_count = 0; 35 36 static uint8_t *tone2_reg = (uint8_t *)0; 37 static uint8_t tone2_mask = 0; 38 static uint16_t tone2_inc = 0; 39 static uint32_t tone2_count = 0; 40 41 static uint8_t *tone3_reg = (uint8_t *)0; 42 static uint8_t tone3_mask = 0; 43 static uint16_t tone3_inc = 0; 44 static uint32_t tone3_count = 0; 45 46 #define MAX_FREQ (F_CPU / 16 / 25) 47 #define MIN_FREQ (F_CPU / 16 / 65535 + 1) 48 49 50 51 #define PIN_REG_AND_MASK_LOOKUP(pin, reg, mask) \ 52 asm volatile( \ 53 "lsl %2" "\n\t" \ 54 "add %A3, %2" "\n\t" \ 55 "adc %B3, __zero_reg__" "\n\n" \ 56 "lpm %1, Z+" "\n\t" \ 57 "lpm %A0, Z" "\n\t" \ 58 "ldi %B0, 0" "\n" \ 59 : "=z" (reg), "=r" (mask), "+r" (pin) \ 60 : "z" (digital_pin_table_PGM), "2" (pin)) 61 62 #if defined(__AVR_ATmega32U4__) 63 //#define TONE_USE_TIMER1 64 #define TONE_USE_TIMER3 65 #elif defined(__AVR_AT90USB1286__) 66 //#define TONE_USE_TIMER1 67 #define TONE_USE_TIMER3 68 #elif defined(__AVR_AT90USB162__) 69 #define TONE_USE_TIMER1 70 #elif defined(__AVR_AT90USB646__) 71 //#define TONE_USE_TIMER1 72 #define TONE_USE_TIMER3 73 #endif 74 75 #ifdef TONE_USE_TIMER3 76 #define TIMSKx TIMSK3 77 #define OCIExA OCIE3A 78 #define OCIExB OCIE3B 79 #define OCIExC OCIE3C 80 #define TCCRxA TCCR3A 81 #define WGMx0 WGM30 82 #define TCCRxB TCCR3B 83 #define CSx1 CS31 84 #define TCNTx TCNT3 85 #define OCRxA OCR3A 86 #define OCRxB OCR3B 87 #define OCRxC OCR3C 88 #define TIFRx TIFR3 89 #define OCFxA OCF3A 90 #define OCFxB OCF3B 91 #define OCFxC OCF3C 92 #define VECTxA TIMER3_COMPA_vect 93 #define VECTxB TIMER3_COMPB_vect 94 #define VECTxC TIMER3_COMPC_vect 95 #endif 96 #ifdef TONE_USE_TIMER1 97 #define TIMSKx TIMSK1 98 #define OCIExA OCIE1A 99 #define OCIExB OCIE1B 100 #define OCIExC OCIE1C 101 #define TCCRxA TCCR1A 102 #define WGMx0 WGM10 103 #define TCCRxB TCCR1B 104 #define CSx1 CS11 105 #define TCNTx TCNT1 106 #define OCRxA OCR1A 107 #define OCRxB OCR1B 108 #define OCRxC OCR1C 109 #define TIFRx TIFR1 110 #define OCFxA OCF1A 111 #define OCFxB OCF1B 112 #define OCFxC OCF1C 113 #define VECTxA TIMER1_COMPA_vect 114 #define VECTxB TIMER1_COMPB_vect 115 #define VECTxC TIMER1_COMPC_vect 116 #endif 117 118 119 void tone(uint8_t pin, uint16_t frequency, uint32_t duration) 120 { 121 uint8_t *reg; 122 uint8_t mask; 123 uint16_t inc; 124 uint32_t count; 125 126 if (pin >= CORE_NUM_TOTAL_PINS) return; 127 if (frequency < MIN_FREQ) { 128 frequency = MIN_FREQ; 129 } else if (frequency > MAX_FREQ) { 130 frequency = MAX_FREQ; 131 } 132 inc = (F_CPU / 16 + frequency / 2) / frequency; 133 if (duration) { 134 count = duration * frequency / 500; 135 } else { 136 count = 0; 137 } 138 if (!timer_acquired) { 139 TIMSKx = 0; // disable all interrupts 140 TCCRxA = 0; 141 TCCRxB = (1<<CSx1); // normal mode, div8 prescale 142 timer_acquired = 1; 143 } 144 PIN_REG_AND_MASK_LOOKUP(pin, reg, mask); 145 146 if (!tone1_mask || (tone1_mask == mask && tone1_reg == reg)) { 147 TIMSKx &= ~(1<<OCIExA); // disable compare interrupt 148 tone1_reg = reg; 149 tone1_mask = mask; 150 tone1_count = count; 151 tone1_inc = inc; 152 cli(); 153 *(reg + 2) &= ~mask; // clear pin 154 *(reg + 1) |= mask; // output mode 155 OCRxA = TCNTx + inc; 156 TIFRx |= (1<<OCFxA); // clear any pending compare match 157 sei(); 158 TIMSKx |= (1<<OCIExA); // enable compare interrupt 159 return; 160 } 161 if (!tone2_mask || (tone2_mask == mask && tone2_reg == reg)) { 162 TIMSKx &= ~(1<<OCIExB); // disable compare interrupt 163 tone2_reg = reg; 164 tone2_mask = mask; 165 tone2_count = count; 166 tone2_inc = inc; 167 cli(); 168 *(reg + 2) &= ~mask; // clear pin 169 *(reg + 1) |= mask; // output mode 170 OCRxB = TCNTx + inc; 171 TIFRx |= (1<<OCFxB); // clear any pending compare match 172 sei(); 173 TIMSKx |= (1<<OCIExB); // enable compare interrupt 174 return; 175 } 176 if (!tone3_mask || (tone3_mask == mask && tone3_reg == reg)) { 177 TIMSKx &= ~(1<<OCIExC); // disable compare interrupt 178 tone3_reg = reg; 179 tone3_mask = mask; 180 tone3_count = count; 181 tone3_inc = inc; 182 cli(); 183 *(reg + 2) &= ~mask; // clear pin 184 *(reg + 1) |= mask; // output mode 185 OCRxC = TCNTx + inc; 186 TIFRx |= (1<<OCFxC); // clear any pending compare match 187 sei(); 188 TIMSKx |= (1<<OCIExC); // enable compare interrupt 189 return; 190 } 191 } 192 193 void noTone(uint8_t pin) 194 { 195 uint8_t *reg; 196 uint8_t mask; 197 198 if (pin >= CORE_NUM_TOTAL_PINS) return; 199 PIN_REG_AND_MASK_LOOKUP(pin, reg, mask); 200 201 if (tone1_mask == mask && tone1_reg == reg) { 202 TIMSKx &= ~(1<<OCIExA); 203 tone1_mask = 0; 204 } else if (tone2_mask == mask && tone2_reg == reg) { 205 TIMSKx &= ~(1<<OCIExB); 206 tone2_mask = 0; 207 } else if (tone3_mask == mask && tone3_reg == reg) { 208 TIMSKx &= ~(1<<OCIExC); 209 tone3_mask = 0; 210 } 211 if (!tone1_mask && !tone2_mask && !tone3_mask) { 212 TCCRxA = (1<<WGMx0); // restore timer 213 timer_acquired = 0; 214 } 215 } 216 217 218 ISR(VECTxA) 219 { 220 OCRxA += tone1_inc; 221 *(tone1_reg) = tone1_mask; 222 if (tone1_count > 0) { 223 if ((--tone1_count) == 0) { 224 *(tone1_reg + 2) &= ~tone1_mask; 225 TIMSKx &= ~(1<<OCIExA); 226 tone1_mask = 0; 227 if (!tone2_mask && !tone3_mask) { 228 TCCRxA = (1<<WGMx0); 229 timer_acquired = 0; 230 } 231 } 232 } 233 } 234 235 ISR(VECTxB) 236 { 237 OCRxB += tone2_inc; 238 *(tone2_reg) = tone2_mask; 239 if (tone2_count > 0) { 240 if ((--tone2_count) == 0) { 241 *(tone2_reg + 2) &= ~tone2_mask; 242 TIMSKx &= ~(1<<OCIExB); 243 tone2_mask = 0; 244 if (!tone1_mask && !tone3_mask) { 245 TCCRxA = (1<<WGMx0); 246 timer_acquired = 0; 247 } 248 } 249 } 250 } 251 252 ISR(VECTxC) 253 { 254 OCRxC += tone3_inc; 255 *(tone3_reg) = tone3_mask; 256 if (tone3_count > 0) { 257 if ((--tone3_count) == 0) { 258 *(tone3_reg + 2) &= ~tone3_mask; 259 TIMSKx &= ~(1<<OCIExC); 260 tone3_mask = 0; 261 if (!tone1_mask && !tone2_mask) { 262 TCCRxA = (1<<WGMx0); 263 timer_acquired = 0; 264 } 265 } 266 } 267 } 268 269