chipKIT® Development Platform

Inspired by Arduino™

analog output of sampled pulses or ???

Created Mon, 14 Nov 2011 05:10:25 +0000 by spencoid


spencoid

Mon, 14 Nov 2011 05:10:25 +0000

I need to create sine wave pulses of a specified frequency. I can either calculate or use a wav table. Each time a digital lines goes low, I need to output a single pulse. Any ideas on how to do this easily? I need to make 2000 to 4000 hz pulses with the best sample rate I can get. I am open to any ideas or to hiring someone to write a library if necessary. I looked at the PWM for servo library but it doesn't look like I can get it to work fast enough.


Jacob Christ

Mon, 14 Nov 2011 08:23:55 +0000

Check this out:

http://www.youtube.com/watch?v=8LdxwfSsjZM

http://www.chipkit.org/forum/viewtopic.php?f=15&t=529

Jacob


spencoid

Mon, 14 Nov 2011 09:12:40 +0000

this certainly looks like it has the guts of what i need but a lot more that i don't quite understand. i understand the score concept and the note samples loaded into memory but can not figure out how to strip it down to just what i need. i would like to make a sample of the few tones that i need and then to play these samples when needed. any help in simplifying and or commenting would be greatly appreciated.


serveurperso

Wed, 16 Nov 2011 10:24:17 +0000

this certainly looks like it has the guts of what i need but a lot more that i don't quite understand. i understand the score concept and the note samples loaded into memory but can not figure out how to strip it down to just what i need. i would like to make a sample of the few tones that i need and then to play these samples when needed. any help in simplifying and or commenting would be greatly appreciated.

Here is just my simplified sampler + linear interpolation (directly posted here, not tested)

Currently my new version can play multiple samples on any channels like an Amiga soundtracker MOD Player, if you want even more simple and stripped (without linear interpolation) I can write it.

// Use http://www.wusik.com/arduino/Libraries/WAV2Code and adjust SAMPLESIZE
#define SAMPLESIZE 4189

#define CHANNELS 4

#define PWMPIN 3            // OC1 PWM

#define SAMPLERATE 44100    // Hz
#define DIVIDER 11          // Octave by octave

// Store data in flash (program) memory instead of RAM
const int8_t sample[] = {
0,0,64,208,151,239,85,240,63,80,208,128,191,95,

//... Your UNSIGNED 8 bits sample array
// Use WAV2Code or any similar tool
// it's an easy to write tool in C
// (Binary data to ASCII values, without the WAVfile header)...
// sorry for me english !

128,128,128,128,128,128,128,128,128};

uint32_t samplePos[CHANNELS] = {0};
int16_t sampleSpeed[CHANNELS] = {0};

void setup() {
 pinMode(PWMPIN, OUTPUT);

 // 10 bits PWM
 OpenTimer2(T2_ON | T2_PS_1_1, 1024);
 OpenOC1(OC_ON | OC_TIMER2_SRC | OC_PWM_FAULT_PIN_DISABLE, 0, 0);

 // Sampler
 ConfigIntTimer1(T1_INT_ON | T1_INT_PRIOR_3);
 OpenTimer1(T1_ON | T1_PS_1_1, F_CPU / SAMPLERATE);
}

void loop() {

 samplePos[0] = 0;      // Rewind ch 0 (0 to 3 of CHANNELS = 4)
 sampleSpeed[0] = 1000; // Play the sample on ch 0

 delay(1000);

}

extern "C" {
 void __ISR(_TIMER_1_VECTOR, ipl3) T1InterruptHandler() {
  static uint8_t channel;
  static int16_t sum;
  static uint16_t pos;
  static int32_t linearInterpolation;

  mT1ClearIntFlag();

  sum = 0;
  for(channel = 0; channel < CHANNELS; channel++) {
   pos = (samplePos[channel] >> DIVIDER);
   if(pos >= SAMPLESIZE - 2) {
    pos = 0;
    samplePos[channel] = 0;
    sampleSpeed[channel] = 0;
   }

   // Integer linear interpolation
   linearInterpolation = (sample[pos + 1] - sample[pos]) *
                         (samplePos[channel] & (1 << DIVIDER) - 1) >> DIVIDER;

   sum += sample[pos] + linearInterpolation;

   samplePos[channel] += sampleSpeed[channel];
  }

  sum = (sum << 2) / CHANNELS;     // Scale to 10 bits

  SetDCOC1PWM(sum + 512);          // Signed to unsigned
 }
}

spencoid

Wed, 16 Nov 2011 10:45:44 +0000

Thanks, It is very similar to what I just "wrote". I took your code apart piece by piece to learn how it worked and removed much of it making something similar to what you posted. I then made it even simpler since I just need two frequencies and only a single channel. What I have now reads the sample array and sequentially sets the PWM to these values at the interrupt rate. I can have just one sample and change the interrupt rate but will probably have one sample for each of the two freqs instead. I have a sine wave sample that I got from another sample sketch but will write a program to create my own. I will also need to read an external interrupt to initiate the generation of a single sample cycle. Should not be difficult to figure that out. Will probably use a global boolean that is toggled by the external interrupt and also by the timer interrupt routine when the sample position reaches the end of the sample.