Audio out of OCR1A/OCR1B

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi guys. Now my SD is working again (pull up on MISO was the key to success) I am listening to an 8 bit version of The Who's My Generation and its awesome.
However....
I am using Timer1 as my headphone jack is attached to OCR1A and OCR1B. I am using a 1824p at 16Mhz.
It "sounds" like it might be playing slowly. I have made the main adjustments I can think of, so I was wondering whether it could be because Timer 1 is a 16 bit timer, and therefore I am only filling to bottom 8 bits or something like that?

These are my methods to initialize the timer:


void start_playback(void) { 

	//audio on OCR1A and OCR1B
	TCCR1A |= (1 << COM1A1) | (1 << COM1B1)| (1 << WGM12) | (1 << WGM10);
   //Clear OC0A on Compare Match, set OC0A at BOTTOM, fast PWM
//   TCCR0A |= (1 << COM0A1) | (1 << COM0B1)| (1 << WGM01) | (1 << WGM00);
    TCCR1B |= (1 << CS10); // no prescale
   OCR1A = 0;
   OCR1B = 0;
   play_index = 0; 
   active = 1; 
   TIMSK1 |= (1 << TOIE1);
   DDRD  |= 0b00110000;
} 

and to stop the timer:

void stop_playback(void) { 
	PORTD  &= ~0b00110000;
    TCCR1B &= ~(1 << CS10); // no prescale
 } 

And my interrupt:

ISR(TIMER1_OVF_vect) {
   divider++; 
   if (divider == 1) { //'4' for 8 bit raw
	
      if (active == 1) { 
         OCR1A = buff1[play_index++];
         OCR1B = buff1[play_index++];

      } // if active == 1
      else { 
         OCR1A = buff2[play_index++];
         OCR1B = buff1[play_index++];

      } //else
      if (play_index >= 512) { 
         if (active == 1) { 
            active = 2; 
         } // if active == 1
         else { 
            active = 1; 
         } //else
         play_index = 0; 
      } //play_index >= 512
	  divider = 0; 
   } // div_er == 2
      if (play_index == 100) { 
         // trigger read of the other buffer when one part used 
         read_next = 1; 

      }// if play_index == 100
	  
} //function

Changing what divider has to be changes the "speed" that the OCR's are updated at. When it is 1 its like daffy duck (fast) but 2 sounds like the devil just walked in...
Any ideas as to what I havent done to make it play at the correct speed, and...

secondly, as I have the option of stereo sound, and I am using a 16 bit Timer, is all I have to do to get better quality audio, record for 16Khz stereo, and then do I set OCR1B as one byte ahead of OCR1A or something (i.e they get every other byte each?)

Oh No! Just remembered, the ADC is only 8 bit anyway so having 16 bit timer is useless isnt it? Can still do stereo though right?

Last Edited: Sat. Feb 9, 2013 - 05:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That looks like you are using Mode 5 (WG12+WG10) which is Fast PWM 8bit with TOP therefore at 0xFF. So your PWM frequency (with CS00) is going to be 16MHz/256 = 62.5kHz. AFAICS you "divider" in the ISR() means that you load the OCR registers on every second interrupt so that would seem to suggest you are playing 16kHz samples at 31.25kHz. I would have thought this would sound like Pinky & Perky, not "slow"?

Are you sure the chip is running at 16MHz? Maybe CKDIV8?

BTW I don't understand your last comment. If you use an 8bit mode for the timer isn't it just the same as an 8 bit timer - both count to TOP at 0xFF.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,
Firstly

ISR(TIMER1_OVF_vect) { 
   divider++; 
   if (divider == 1) {

Did the comments confuse you, or am I confused? I changed it down to 1 to try and double the speed it was playing at, why do you say I load the registers on every second interrupt? surely that is every interrupt?
[quoteI would have thought this would sound like Pinky & Perky, not "slow"?


Interesting you say that, because the way I have it written each other byte goes to OCR1B so it does sound fast, however if I dont use OCR1B it sounds slow. I can understand why playing it in stereo sounds fast - Im using up the data twice as quickly, but not sure whether just getting a track recorded in stereo would solve the problem...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

surely that is every interrupt?

Oh you are right (in which case what's the point of"divider" at all?). In that case you should be playing at 62.5kHz which is almost 4 times too fast.

Think about how an 8bit stereo WAV is encoded:

Lsample, Rsample, Lsample, Rsample....

On the whole, unless it's a very "wide" stereo field, the majority of Lsample's are going to be very similar to the Rsamples's so if you played the entire thing to one channel it would effectively just play at "half speed". Say you have A=R and B=L then either take Lsample and play it to B and Rsample and play it to A or, if you only want to drive one output skip every second sample so you only get all the R's or all the L's. Nothing else makes much sense.

As with so many of your prior threads I sense "run before walk" syndrome. Don't try to do everything on day one. Just get some 8bit mono and play it out to OC1A or something. Only when that works and you are happy consider trading up to stereo. Walk before you can run. Build systems in small, well tested steps from the ground up, basing the next step on firm foundations.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yeah, the divider is only there as long as I am debugging, and it turns out the value should be 1...

I am only using a mono file not stereo - although both OCR1A and OCR1B are connected. So on that basis - and the way I am loading the OCR1x's i would therefore be playing twice as fast. right?
But when I stop using OCR1B and only use OCR1A then I get twice as slow...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But if you are playing mono file, you should load one mono sample to both left and right channels so it sounds OK. This way both channels play all mono samples.

Definitely not loading one mono sample to left and the next mono sample to right channel, as that will play twice as fast, as one channel skips every second sample.

What is the sampling rate of your file?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If it's mono why waste CPU time loading OCR1A and OCR1B? Why not use just OCR1A->OC1A and connect that pin to both L and R in the headphones?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ultimately I want to go stereo, although may prove unnecessary...