Skip to content

Instantly share code, notes, and snippets.

@cactrot
Last active May 27, 2018 10:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cactrot/451621c3b25c52284ab95e4c813f25a8 to your computer and use it in GitHub Desktop.
Save cactrot/451621c3b25c52284ab95e4c813f25a8 to your computer and use it in GitHub Desktop.
Attempt at an octave generator for AVR
//https://hackaday.com/2018/05/24/ask-hackaday-diy-top-octave-generator/
// I thought it would be interesting to see if some kind of time/space trade off could be done with this problem.
// It compiles but you probably need an ATMEGA1284 or better to run since it needs a little over 8k ram
// It should run in constant time.
// Don't have anything to test this on.
void setup() {
// put your setup code here, to run once:
}
// repl.it testing
/*
#include <stdio.h>
*/
// bit mask for each note
const uint16_t note1 = 1<<0;
const uint16_t note2 = 1<<1;
const uint16_t note3 = 1<<2;
const uint16_t note4 = 1<<3;
const uint16_t note5 = 1<<4;
const uint16_t note6 = 1<<5;
const uint16_t note7 = 1<<6;
const uint16_t note8 = 1<<7;
const uint16_t note9 = 1<<8;
const uint16_t note10 = 1<<9;
const uint16_t note11 = 1<<10;
const uint16_t note12 = 1<<11;
// calculate the number of counts between pin toggles
const uint32_t clk = 2000000;
const uint16_t note1_period = clk/478;
const uint16_t note2_period = clk/451;
const uint16_t note3_period = clk/426;
const uint16_t note4_period = clk/402;
const uint16_t note5_period = clk/379;
const uint16_t note6_period = clk/358;
const uint16_t note7_period = clk/338;
const uint16_t note8_period = clk/319;
const uint16_t note9_period = clk/301;
const uint16_t note10_period = clk/284;
const uint16_t note11_period = clk/268;
const uint16_t note12_period = clk/253;
//const uint16_t note13_period = clk/239;
//Round up to the next highest power of 2
uint16_t next_pow2( unsigned int v) { // compute the next highest power of 2 of 32-bit v
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
//v |= v >> 16;
v++;
return v;
}
// repl.it testing
/*
uint8_t PORTD = 0xFF;
uint8_t PORTB = 0xFF;
*/
void loop() {
// lowest note sets the max period
const uint16_t scroll_length = next_pow2(note12_period)-1;
// circular buffer to store the toggle markers
//uint16_t scroll[scroll_length] = {0};
uint16_t scroll[scroll_length];
for( uint16_t i = 0 ; i < scroll_length ; i++ )
{
scroll[i] = 0;
}
// set starting index
uint16_t index = 0;
// set starting toggle markers
scroll[index] = 0xFFFF;
while(1) {
// fetch state
uint16_t state = scroll[index];
// update port pins
PORTD ^= (state>>0)&0xFF;
PORTB ^= (state>>8)&0xFF;
// repl.it testing
/*
printf( "INDEX %d ", index );
printf( "PORTD %X ", PORTD );
printf( "PORTB %X\n", PORTB );
printf( "BUFFER LENGTH %d ", scroll_length );
printf( "STATE %X ", state );
printf( "NEXT1 %d ", (index+note1_period)&scroll_length );
printf( "NEXT2 %d\n", (index+note2_period)&scroll_length );
*/
// isolate each notes current toggle marker and
// insert it into the position in the future it next occurs
scroll[(index+note1_period)&scroll_length] |= state & note1;
scroll[(index+note2_period)&scroll_length] |= state & note2;
scroll[(index+note3_period)&scroll_length] |= state & note3;
scroll[(index+note4_period)&scroll_length] |= state & note4;
scroll[(index+note5_period)&scroll_length] |= state & note5;
scroll[(index+note6_period)&scroll_length] |= state & note6;
scroll[(index+note7_period)&scroll_length] |= state & note7;
scroll[(index+note8_period)&scroll_length] |= state & note8;
scroll[(index+note9_period)&scroll_length] |= state & note9;
scroll[(index+note10_period)&scroll_length] |= state & note10;
scroll[(index+note11_period)&scroll_length] |= state & note11;
scroll[(index+note12_period)&scroll_length] |= state & note12;
// clear handled bits and move to the next index
scroll[index++] = 0;
// wrap around at end of buffer
index &= scroll_length;
}
//return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment