I am working with a customer that is trying to use App Note SLAA116 - "Using PWM Timer_B as a DAC" to create a sine wave output implemented in an MSP430 timer. He is targeting an MSP430F2xxx family device.
Here is the customers code for a function he is calling to attempt to generate a sine wave:
void generate_sine (uint16_t periods)
{
uint16_t p_table_ptr;
// Clear TimerA
TACTL |= TACLR;
// TimerA Setup:
// SMCLK Source | Divided by 0 | Count Up Mode
TACTL = TASSEL_2 | MC_1;
// Load timer to set period of PWM to 256 counts (8-bits)
TACCR0 = 0xff;
// Load first table value
TACCR1 = sine_table[0];
// Set CCR0 in compare mode and enable interrupt
TACCTL0 = CCIE;
// Set CCR1 in compare mode, output mode 7 (reset/set)
TACCTL1 = OUTMOD_7;
while (periods)
{
for (p_table_ptr = 1; p_table_ptr < SINE_TABLE_SIZE; ++p_table_ptr)
{
// Turn off CPU until timer interrupt
LPM0;
// Load next table value
//TACCR1 = sine_table[p_table_ptr];
TACCR1 = 31 - p_table_ptr;
}
--periods;
}
// TimerA OFF
TACCTL1 = 0;
TACCTL0 = 0;
TACTL = 0;
}
Here is the customer's comments on the problem he is seeing with the above code:
"I’m just decreasing the pulse widths as I go through the for loop. What I found is that any time I decrease the pulse widths and get to around a value of 20-25 (to load into TACCR1) I get a full-period pulse. So, if you can see the output on the pin you would see decreasing pulse widths until pulse number 7, which would be a max-width pulse. Then the pulse widths continue decreasing as they should. This does not occur if I increase pulse-widths through the same range of values.
For added reference, here is the main program where he is calling the above function:
void main (void)
{
// Stop WDT
WDTCTL = WDTPW + WDTHOLD;
// External LF crystal with 10pF loading
BCSCTL3 = XCAP_2;
BCSCTL1 = XT2OFF;
// Set FLASH-writes timing generator ->must be in range ~257kHz - ~476kHz
// Source = MCLK / 3 = 333kHz
FCTL2 = FWKEY | FSSEL_1 | FN1;
for (volatile int cnt=0; cnt<0xfff; cnt++)
{
// Delay for XTAL stabilization
}
// Clear oscillator fault flag
IFG1 = 0;
// Perform initial calibration of DCO
set_dco();
// Setup WDT as interval timer
// sourced from ACLK (32kHz)
WDTCTL = WDT_ADLY_250;
// IO config
P1OUT = 0; // All outs are zero
P2OUT = 0; // All outs are zero
P1DIR = 0xFF; // p1.x Direction - output
P2DIR = 0xFF; // p2.x Direction - output
//Set P1.2 as TA1 output
P1SEL |= BIT2;
// Enable interrupts
_BIS_SR(GIE);
// Enable WDT interrupt
IE1 |= WDTIE;
for(;;)
{
// Sleep until WDT expires
LPM3;
//if (hap_timer == 0)
//{
generate_sine(1);
//hap_timer = rand() % 40;
//}
//else
//{
//--hap_timer;
//}
} // end for(;;)
}