ARDUINO: Setting up a Gentoo development environment…

if you’re reading this post, most likely you’re having issues with setting up Crossdev as mentioned on the arduino.cc site. i tried countless times to configure my system for AVR compiling that way, but it always failed compiling avr-libc and would never compile avr-g++ no matter how i applied the USE flags. in short, i had to manually compile the necessary environment and this article is so i don’t forget how that’s done. it seems there are only a smattering ink blot’s worth of people developing Arduino sketches under the Gentoo distribution, but this should work (in theory) for most any Linux distro out there since it’s all manual installation. if anyone happens to hit a snag during their installation, feel free to let me know.

Download the tool chain…

getting the right version is the key. some newer versions don’t play nice with ATMEL’s chips for whatever reason.

1) BinUtils 2.20.1a: http://ftp.gnu.org/gnu/binutils/binutils-2.20.1a.tar.bz2
2) GCC 4.3.6: http://gcc.petsads.us/releases/gcc-4.3.6/gcc-g++-4.3.6.tar.bz2
3) AVR LibC 1.7.1: http://download.savannah.gnu.org/releases/avr-libc/avr-libc-1.7.1.tar.bz2

these are the versions that both myself and Jose Moldonado in Spain have been able to run without problems.

Additional downloads…

you’ll need AVRDuDe. i installed it from source just to be safe, though i think the portage install is just as good.

http://download.savannah.gnu.org/releases/avrdude/avrdude-5.11.tar.gz

PREFIX and PATH

this is how my system is setup.

#PREFIX=/usr/i686-pc-linux-gnu/avr
#export PREFIX
#PATH=$PATH:$PREFIX/bin
#export PATH

make sure to do this FIRST. not modifying the PREFIX variable could potentially hose the whole system.

Compiling…

then you can start compiling binutils:

# cd binutils-2.20.1a
# mkdir obj-avr
# cd obj-avr
# ../configure --prefix=/usr/x86_64-pc-linux-gnu/avr --target=avr --disable-nls
# make
# make install

then onto gcc…

# cd gcc-4.3.6
# mkdir obj-avr
# cd obj-avr
# ../configure --prefix=/usr/x86_64-pc-linux-gnu/avr --target=avr --enable-languages=c,c++ --disable-nls --disable-libssp --with-dwarf2
# make
# make install

then avr-libc…

# cd avr-libc-1.7.1
# ./configure --prefix=/usr/x86_64-pc-linux-gnu/avr --build=x86_64-pc-linux-gnu --host=avr
# make
# make install

Symlinking your libs and includes…

now on my system, there was a /usr/avr folder that the Arduino IDE definitely looks in for the includes and additional libraries. i had to symlink two folders in order for the IDE to work.

# ln -s /usr/i686-pc-linux-gnu/avr/avr/include /usr/avr/include
# ln -s /usr/i686-pc-linux-gnu/avr/avr/lib /usr/avr/lib

…and that was that. the latest Arduino IDE ran without a hitch.

for more detailed information, go here: http://www.nongnu.org/avr-libc/user-manual/install_tools.html

Arduino: LFO Generator

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);
}