// Ask Hackaday: How do you DIY a Top-Octave Generator? | |
// https://hackaday.com/2018/05/24/ask-hackaday-diy-top-octave-generator/?utm_source=feedburner | |
// Target Arduino Mega. | |
// N.B., Timer 1 has highest interrupt priority, so | |
// use it for the highest frequency oscillators. | |
// Note Comp Port/Pin Arduino Pin | |
// C OC1A PB5 pin 11 | |
// B OC1B PB6 pin 12 | |
// A# OC1C PB7 pin 13 | |
// A OC3A PE3 pin 5 | |
// G# OC3B PE4 pin 2 | |
// G OC3C PE5 pin 3 | |
// F# OC4A PH3 pin 6 | |
// F OC4B PH4 pin 7 | |
// E OC4C PH5 pin 8 | |
// D# OC5A PL3 pin 46 | |
// D OC5B PL4 pin 45 | |
// C# OC5C PL5 pin 44 | |
#define RND(a, b) (((a) + (b) / 2) / (b)) | |
#define OCR1A_COUNT (RND(F_CPU, 8372)) | |
#define OCR1B_COUNT (RND(F_CPU, 7902)) | |
#define OCR1C_COUNT (RND(F_CPU, 7459)) | |
#define OCR3A_COUNT (RND(F_CPU, 7040)) | |
#define OCR3B_COUNT (RND(F_CPU, 6645)) | |
#define OCR3C_COUNT (RND(F_CPU, 6272)) | |
#define OCR4A_COUNT (RND(F_CPU, 5920)) | |
#define OCR4B_COUNT (RND(F_CPU, 5588)) | |
#define OCR4C_COUNT (RND(F_CPU, 5274)) | |
#define OCR5A_COUNT (RND(F_CPU, 4978)) | |
#define OCR5B_COUNT (RND(F_CPU, 4699)) | |
#define OCR5C_COUNT (RND(F_CPU, 4435)) | |
void setup() | |
{ | |
// Start Timer/Counter 1. | |
TCCR1A = _BV(COM1A0) | _BV(COM1B0) | _BV(COM1C0); | |
TCCR1B = _BV(CS10); | |
TCCR1C = 0; | |
OCR1A = OCR1A_COUNT; | |
OCR1B = OCR1B_COUNT; | |
OCR1C = OCR1C_COUNT; | |
TIMSK1 = _BV(OCIE1C) | _BV(OCIE1B) | _BV(OCIE1A); | |
// Start Timer/Counter 3. | |
TCCR3A = _BV(COM3A0) | _BV(COM3B0) | _BV(COM3C0); | |
TCCR3B = _BV(CS30); | |
TCCR3C = 0; | |
OCR3A = OCR3A_COUNT; | |
OCR3B = OCR3B_COUNT; | |
OCR3C = OCR3C_COUNT; | |
TIMSK3 = _BV(OCIE3C) | _BV(OCIE3B) | _BV(OCIE3A); | |
// Start Timer/Counter 4. | |
TCCR4A = _BV(COM4A0) | _BV(COM4B0) | _BV(COM4C0); | |
TCCR4B = _BV(CS40); | |
TCCR4C = 0; | |
OCR4A = OCR4A_COUNT; | |
OCR4B = OCR4B_COUNT; | |
OCR4C = OCR4C_COUNT; | |
TIMSK4 = _BV(OCIE4C) | _BV(OCIE4B) | _BV(OCIE4A); | |
// Start Timer/Counter 5. | |
TCCR5A = _BV(COM5A0) | _BV(COM5B0) | _BV(COM5C0); | |
TCCR5B = _BV(CS50); | |
TCCR5C = 0; | |
OCR5A = OCR5A_COUNT; | |
OCR5B = OCR5B_COUNT; | |
OCR5C = OCR5C_COUNT; | |
TIMSK5 = _BV(OCIE5C) | _BV(OCIE5B) | _BV(OCIE5A); | |
// Enable output on pins. | |
DDRB |= _BV(DDB5); | |
DDRB |= _BV(DDB6); | |
DDRB |= _BV(DDB7); | |
DDRE |= _BV(DDE3); | |
DDRE |= _BV(DDE4); | |
DDRE |= _BV(DDE5); | |
DDRH |= _BV(DDH3); | |
DDRH |= _BV(DDH4); | |
DDRH |= _BV(DDH5); | |
DDRL |= _BV(DDL3); | |
DDRL |= _BV(DDL4); | |
DDRL |= _BV(DDL5); | |
// Disable millisecond timer. | |
TIMSK0 = 0; | |
} | |
void loop() | |
{ | |
__asm__ ( "sleep" ); | |
} | |
ISR(TIMER1_COMPA_vect) | |
{ | |
OCR1A += OCR1A_COUNT; | |
} | |
ISR(TIMER1_COMPB_vect) | |
{ | |
OCR1B += OCR1B_COUNT; | |
} | |
ISR(TIMER1_COMPC_vect) | |
{ | |
OCR1C += OCR1C_COUNT; | |
} | |
ISR(TIMER3_COMPA_vect) | |
{ | |
OCR3A += OCR3A_COUNT; | |
} | |
ISR(TIMER3_COMPB_vect) | |
{ | |
OCR3B += OCR3B_COUNT; | |
} | |
ISR(TIMER3_COMPC_vect) | |
{ | |
OCR3C += OCR3C_COUNT; | |
} | |
ISR(TIMER4_COMPA_vect) | |
{ | |
OCR4A += OCR4A_COUNT; | |
} | |
ISR(TIMER4_COMPB_vect) | |
{ | |
OCR4B += OCR4B_COUNT; | |
} | |
ISR(TIMER4_COMPC_vect) | |
{ | |
OCR4C += OCR4C_COUNT; | |
} | |
ISR(TIMER5_COMPA_vect) | |
{ | |
OCR5A += OCR5A_COUNT; | |
} | |
ISR(TIMER5_COMPB_vect) | |
{ | |
OCR5B += OCR5B_COUNT; | |
} | |
ISR(TIMER5_COMPC_vect) | |
{ | |
OCR5C += OCR5C_COUNT; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment