Showing posts with label MSP430F169. Show all posts
Showing posts with label MSP430F169. Show all posts

Wednesday, June 3, 2009

White Noise on a Microcontroller

I recently finished a project where I had to make a white noise generator using a microcontroller. It was a lot harder than I thought it would be. What didn't work: wavetable with 100-1000 random numbers. The human ear can detect aural patterns, and at an 8kHz sample rate, the 1000 number pattern repeats itself about 8 times per second which is noticeable. What does work: a Linear Feedback Shift Register. (Wikipedia) Using a 16 bit LFSR you can get a 16*16 = 65535 pseudorandom number sequence. In my tests the pattern could not be detected, which is perfect.

I implemented this on an MSP430F2618 using its internal DAC and the internal timer; though an MSP430F169 could work too. It uses TimerA0 to generate a constant period. When the timer interrupt occurs, the LFSR generates a new value and sends it out via the DAC.

Setting up the DAC:
void setupDac()
{
ADC12CTL0 = REF2_5V + REFON; // Internal 2.5V ref on
// Delay is 17mSec for caps to charge, [from code] 13600 at 1MHz, or 0x1A900 at 8MHz
// At 8000 cycles/Msec, need 0x21340 clock cycles to get 17mSec
// for safety, we'll delay a little longer, or 0x22000 clock cycles
#define SEVENTEEN_MS_AT_8MHZ 0x22000
for (long j = SEVENTEEN_MS_AT_8MHZ; j; j--); // Delay for needed ref start-up.
DAC12_1CTL = DAC12IR + DAC12AMP_5 + DAC12ENC + DAC12OPS; // Int ref gain 1, DAC12OPS = output select for DAC12_1 on P6.5
}
Setting up TimerA0
void setupTimerA()
{
TACCTL0 = CCIE; // TACCR0 interrupt enabled
TACCR0 = 200; //starting interval, gets changed at first interrupt
TACTL = TASSEL_2 + MC_2; // SMCLK, up mode
}
And finally, the TimerA0 interrupt service routine (ISR):
/*
* White Noise Generator
* Galois Linear Feedback Shift Register implementation
*/
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
{
TACCR0 += 0x3FF; // Timer interval, Add Offset to TACCR0
lsb = lfsr & 1; //Get lsb (i.e., the output bit).
lfsr >>= 1; //Shift register
if(lsb == 1) //Only apply toggle mask if output bit is 1.
lfsr ^= 0xB400u; //apply toggle mask, value has 1 at bits corresponding to taps, 0 else where.
DAC12_1DAT = lfsr;
}
That's it. In your main code, be sure that you enable interrupts, or else it won't work.

Saturday, May 30, 2009

Sound on the MSP430

Started playing with sound on the MSP430. I'm using an MSP430F2618 because it has an internal DAC, although a '169 or using an external DAC would work too. A couple of notes:
  • Output of DAC feeds a Sallen-Key filter which then drives a TI TPA721 300mW amplifier which drives a little toy speaker
  • White noise is harder than it sounds. After several tries, I ended up using a Linear Feedback Shift Register, specifically a Galois LFSR. See WikiPedia.
  • For sine waves, I made a wave table with 72 points (every 5 degrees from 0 to 355 degrees)
  • To get volume levels I ended up making ten wave tables, one for each 10% volume level. You could of course compute this on the fly but it took too many clock cycles for my implementation.
  • To prevent "zippering" at the start of the code I compute intermediate wave tables (5%, 15%, etc)
  • Learned the hard way that the "rail to rail" op amp ain't. Needed to recompute the wave tables with an offset to keep the bottom of the DAC output above the ~100mV floor of the op-amp.