here’s a treat for anyone that’s into the audio side of arduino. it’s an 8-bit two-timer based LFO Generator using timer 0/2 on an ATMega328p. i’m only using timer0 for output in this code. i’ve started implementing the LFO code into my 8-bit melotronium where timer2 is dedicated for the audio output. in the larger code base, timer0 just stores values in an unsigned integer that the other timer grabs and modulates the output mathematically. for now, this should be a good reference to anyone looking for the outline of an LFO with seven different wave forms.
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) uint8_t sineTable[] = { 127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190, 192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238, 239,240,242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254, 254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234, 233,231,229,227,225,223,221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184, 181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118, 115,111,108,105,102,99,96,93,90,87,84,81,78,76,73,70,67,64,62,59,56,54,51,49,46,44, 42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0, 0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31, 33,35,37,39,42, 44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124 }; uint8_t tWave = 128; uint8_t sWave = 255; uint8_t ruWave = 128; uint8_t rdWave = 128; uint8_t rWave = 128; int i = 0; int rate; int waveform; byte d = HIGH; void setup() { pinMode(3, OUTPUT); setupTimer(); OCR0A = 128; } void loop() { waveform = map(analogRead(0),0,1023,1,7); rate = map(analogRead(1),0,1023,255,0); OCR0A = rate; } ISR(TIMER0_COMPA_vect) { if(i == 255) i = 0; switch(waveform) { case 1: analogWrite(3,sine(i)); break; case 2: analogWrite(3,triangle(i)); break; case 3: analogWrite(3, square(i)); break; case 4: analogWrite(3, rampUp(i)); break; case 5: analogWrite(3, rampDown(i)); break; case 6: analogWrite(3, rand(i)); break; case 7: analogWrite(3, white(i)); break; } i++; } void setupTimer() { cli(); /*--- TIMER2 CONFIG ---*/ sbi(TCCR2A,WGM20); sbi(TCCR2A,WGM21); cbi(TCCR2A,WGM22); sbi(TCCR2B, CS20); cbi(TCCR2B, CS21); cbi(TCCR2B, CS22); sbi(TCCR2A,COM2B1); cbi(TCCR2A,COM2B0); /*--- TIMER0 CONFIG ---*/ cbi(TCCR0B,CS00); cbi(TCCR0B,CS01); sbi(TCCR0B,CS02); sbi(TCCR0A, COM0A1); cbi(TCCR0A, COM0A0); cbi(TCCR0A, WGM00); sbi(TCCR0A, WGM01); cbi(TCCR0A, WGM02); cbi(TIFR0,OCF0A); sbi(TIMSK0,OCIE0A); sei(); } int sine(int i) { return sineTable[i]; } int triangle(int i) { if(tWave >= 255) d = LOW; if(tWave <= 0) d = HIGH; if(d == HIGH) tWave++; if(d == LOW) tWave--; return tWave; } int rampUp(int i) { ruWave++; if(ruWave > 255) ruWave = 0; return ruWave; } int rampDown(int i) { rdWave--; if(rdWave < 0) rdWave = 255; return rdWave; } int square(int i) { if(i >= 128) sWave = 255; if(i <= 127) sWave = 0; return sWave; } int rand(int i) { if(i == rWave) rWave = random(255); return rWave; } int white(int i) { return random(255); }
Update: Here's my current code for the ATTiny85. It's not exactly bug-free as there seems to be some issue with latch-up when the speed of the LFO is high. This of course could be remedied by limiting the map() function's minimum value. I can't remember off hand if there are any other issues. Good power supply and output filtering is definitely needed to reduce noise in any additional stages of the circuit. At some point, I'll just make a separate post detailing my tremolo effect circuit in detail (so many projects and so little time!). Until then:
/* * Title: LFO Generator for ATTiny85 v0.12 * Author: Abram Morphew * Date: 09.19.2016 * Purpose: Low frequency oscillator with wave output controls */ #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) uint8_t sineTable[] = { 127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190, 192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238, 239,240,242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254, 254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234, 233,231,229,227,225,223,221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184, 181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118, 115,111,108,105,102,99,96,93,90,87,84,81,78,76,73,70,67,64,62,59,56,54,51,49,46,44, 42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0, 0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31, 33,35,37,39,42, 44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124 }; uint8_t tWave = 128; uint8_t sWave = 255; uint8_t ruWave = 128; uint8_t rdWave = 128; uint8_t rWave = 128; int i = 0; int rate; int waveform; byte d = HIGH; const uint8_t output = 1; // output pin #6 on ATTiny85 void setup() { setupTimer(); pinMode(3, INPUT); pinMode(2, INPUT); pinMode(output, OUTPUT); OCR0A = 128; } void loop() { waveform = map(analogRead(2),0,1023,1,6); rate = map(analogRead(3),0,1023,255,0); OCR0A = rate; } ISR(TIMER0_COMPA_vect) { if(i == 255) i = 0; switch(waveform) { case 1: analogWrite(output,sine(i)); break; case 2: analogWrite(output,triangle(i)); break; case 3: analogWrite(output, square(i)); break; case 4: analogWrite(output, rampUp(i)); break; case 5: analogWrite(output, rampDown(i)); break; case 6: analogWrite(output, rand(i)); break; case 7: analogWrite(output, white(i)); break; } i++; } void setupTimer() { cli(); /*--- TIMER0 CONFIG ---*/ TCCR0A = 0b10000011; TCCR0B = 0b00001010; // last 3 bits set prescalar for Timer0 cbi(TIFR,OCF0A); sbi(TIMSK,OCIE0A); sei(); } int sine(int i) { return sineTable[i]; } int triangle(int i) { if(tWave >= 255) d = LOW; if(tWave <= 0) d = HIGH; if(d == HIGH) tWave++; if(d == LOW) tWave--; return tWave; } int rampUp(int i) { ruWave++; if(ruWave > 255) ruWave = 0; return ruWave; } int rampDown(int i) { rdWave--; if(rdWave < 0) rdWave = 255; return rdWave; } int square(int i) { if(i >= 128) sWave = 255; if(i <= 127) sWave = 0; return sWave; } int rand(int i) { if(i == rWave) rWave = random(255); return rWave; } int white(int i) { return random(255); }
Leave a Reply
You must be logged in to post a comment.