Tool/software:
Hi TI experts
I am working on MSP430 FR5739, I am trying to record a modulated sine wave audio at 2500 hz using port 1.1. But we are getting close to 2475 not constant instead of 2500 hz with jitter. Here is the code;
#include <msp430.h>
#include <stdint.h> // For uint16_t, uint8_t
//-----------------------------------------------------------------------------
// Function Prototypes
//-----------------------------------------------------------------------------
void initClock(void);
void initGPIO(void);
void initADC(void);
void initUART(void);
void initTimerA(void);
//-----------------------------------------------------------------------------
// Global variable to store the ADC result
//-----------------------------------------------------------------------------
volatile uint16_t ADC_Result;
//-----------------------------------------------------------------------------
// Main Program
//-----------------------------------------------------------------------------
void main(void)
{
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
initClock(); // Configure DCO=8 MHz, SMCLK=8 MHz, ACLK=4 MHz
initGPIO(); // P1.1=ADC input, P2.0/P2.1=UART
initADC(); // Configure ADC10 (software‐trigger inside Timer ISR)
initUART(); // Configure eUSCI_A0 UART @230400 baud (ACLK=4 MHz)
initTimerA(); // Configure Timer_A to fire at 2500 Hz (SMCLK)
__enable_interrupt(); // Enable global interrupts
while (1)
{
__bis_SR_register(LPM0_bits | GIE); // Enter LPM0; will wake on ADC or UART ISR
__no_operation(); // For debugger
}
}
//-----------------------------------------------------------------------------
// initClock()
// – Direct‐register code (no DriverLib).
// – DCOFSEL_3 sets DCO = 8 MHz exactly (DCORSEL=0 implicitly).
// – Route DCOCLK → MCLK/SMCLK/ACLK.
// – Set ACLK = DCO/2 = 4 MHz, SMCLK = DCO/1 = 8 MHz, MCLK = DCO/1 = 8 MHz.
//-----------------------------------------------------------------------------
void initClock(void)
{
CSCTL0_H = CSKEY_H; // Unlock CS registers (key = 0xA5 << 8)
// Select DCOFSEL_3 with DCORSEL=0 (default) → DCO = 8 MHz exactly
CSCTL1 = DCOFSEL_3; // DCOFSEL_3 = 0b011 → step for 8 MHz
// Route DCOCLK to ACLK, SMCLK, and MCLK
CSCTL2 = SELA__DCOCLK // ACLK = DCOCLK
| SELS__DCOCLK // SMCLK = DCOCLK
| SELM__DCOCLK; // MCLK = DCOCLK
// Divide ACLK by 2 → 4 MHz; leave SMCLK=8 MHz, MCLK=8 MHz
CSCTL3 = DIVA__2 // ACLK divider /2
| DIVS__1 // SMCLK divider /1
| DIVM__1; // MCLK divider /1
CSCTL0_H = 0; // Lock CS registers again
}
//-----------------------------------------------------------------------------
// initGPIO()
// – P1.1 as ADC10 A1 (analog input).
// – P2.0 = UCA0TXD, P2.1 = UCA0RXD for UART.
//-----------------------------------------------------------------------------
void initGPIO(void)
{
// P1.1 → ADC input (A1)
P1SEL0 |= BIT1;
P1SEL1 |= BIT1;
// P2.0/P2.1 → UCA0TXD/UCA0RXD
P2SEL0 &= ~(BIT0 | BIT1);
P2SEL1 |= BIT0 | BIT1;
// Exit GPIO power-on default high-impedance mode
PM5CTL0 &= ~LOCKLPM5;
}
//-----------------------------------------------------------------------------
// initADC()
// – Software‐triggered ADC10.
// – ADC10CLK = SMCLK = 8 MHz → conversion time = 32 cycles/8 MHz = 4 µs.
// – Sample & Hold time = 32 ADC10CLK cycles (ADC10SHT_3).
// – Input channel = A1 (P1.1).
// – Interrupt on conversion complete.
//-----------------------------------------------------------------------------
void initADC(void)
{
// 1) Turn on ADC10, set S/H time = 32 ADC10CLK cycles
ADC10CTL0 = ADC10SHT_3 // S/H time = 32 cycles (ADC10CLK)
| ADC10ON; // ADC10 ON
// 2) Use sampling timer, ADC10CLK = SMCLK (ADC10SSEL_2)
// (no hardware trigger)
ADC10CTL1 = ADC10SHP // Sample/Hold using sampling timer
| ADC10SSEL_2; // ADC10CLK source = SMCLK (8 MHz)
// 3) 10-bit resolution
ADC10CTL2 = ADC10RES; // ADC10RES = 10-bit
// 4) Select channel A1 (P1.1)
ADC10MCTL0 = ADC10INCH_1; // ADC10INCH_1 = channel A1
// 5) Enable interrupt when conversion completes
ADC10IE |= ADC10IE0; // Enable ADC10IFG interrupt
// Note: We do NOT set ADC10ENC here; we will set/clear ENC inside the Timer ISR.
}
//-----------------------------------------------------------------------------
// initUART()
// – eUSCI_A0 in UART mode, 8-N-1.
// – Clock = ACLK = 4 MHz.
// – Baud = 230400 → 4 MHz/230400 ≈ 17.36 → UCA0BR0 = 17, UCA0BR1 = 0, UCA0MCTLW = 0x04A0.
//-----------------------------------------------------------------------------
void initUART(void)
{
UCA0CTL1 |= UCSWRST; // Put eUSCI in reset
UCA0CTL1 |= UCSSEL__ACLK; // CLK = ACLK = 4 MHz
UCA0BR0 = 17; // 4 MHz/230400 ≈ 17.36 → INT = 17
UCA0BR1 = 0; // High byte = 0
UCA0MCTLW = 0x04A0; // Modulation settings (as before)
UCA0CTL1 &= ~UCSWRST; // Release eUSCI_A0 for operation
// Note: We will enable UCTXIE later inside the ADC ISR to send the high byte.
}
//-----------------------------------------------------------------------------
// initTimerA()
// – SMCLK = 8 MHz → CCR0 = 3199 → 8 MHz/(3199+1) = 2500 Hz exactly.
// – Enable CCR0 interrupt; in that ISR we will start the ADC10 conversion.
//-----------------------------------------------------------------------------
void initTimerA(void)
{
TA0CCR0 = 3199; // 8 MHz/(3199+1) = 2500 Hz
TA0CCTL0 = CCIE; // Enable CCR0 interrupt
TA0CTL = TASSEL__SMCLK // Use SMCLK = 8 MHz
| MC__UP // Up mode (counts 0 → CCR0)
| TACLR; // Clear TAR to start fresh
}
//-----------------------------------------------------------------------------
// Timer_A0 CCR0 Interrupt Service Routine
// – Fires at exactly 2500 Hz.
// – Clears ADC10ENC if set, then sets ADC10ENC+ADC10SC to start a fresh conversion.
//-----------------------------------------------------------------------------
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A_CCR0_ISR(void)
{
// Clear ENC so that ADC10SC will actually start a new conversion
ADC10CTL0 &= ~ADC10ENC;
// Arm and start ADC10 conversion now
ADC10CTL0 |= ADC10ENC | ADC10SC;
// ADC will take 4 µs (32 cycles @ 8 MHz) and then fire ADC10_VECTOR.
// We return immediately; LPM0 stays set until ADC ISR wakes the CPU.
}
//-----------------------------------------------------------------------------
// ADC10 Interrupt Service Routine
// – Called when each 10-bit conversion completes (~4 µs after SC).
// – Read ADC10MEM0, send the low byte by UART, then enable UCTXIE for the high byte.
//-----------------------------------------------------------------------------
#pragma vector = ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{
switch (__even_in_range(ADC10IV, ADC10IV_ADC10IFG))
{
case ADC10IV_NONE: break; // No interrupt
case ADC10IV_ADC10OVIFG: break; // Overflow (ignore)
case ADC10IV_ADC10TOVIFG: break; // Time-over (ignore)
case ADC10IV_ADC10HIIFG: break; // Window high (unused)
case ADC10IV_ADC10LOIFG: break; // Window low (unused)
case ADC10IV_ADC10INIFG: break; // Window inside (unused)
case ADC10IV_ADC10IFG: // Conversion complete
ADC_Result = ADC10MEM0; // Read the 10-bit result
UCA0TXBUF = (uint8_t)(ADC_Result & 0xFF); // Send low byte first
UCA0IE |= UCTXIE; // Enable TX interrupt for high byte
break;
default: break;
}
}
//-----------------------------------------------------------------------------
// USCI_A0 (UART) Interrupt Service Routine
// – Fires when UCA0TXBUF is empty (after sending low byte).
// – Send the high byte of ADC_Result, then disable UCTXIE until next conversion.
//-----------------------------------------------------------------------------
#pragma vector = USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
{
switch (__even_in_range(UCA0IV, USCI_UART_UCTXCPTIFG))
{
case USCI_NONE: break;
case USCI_UART_UCRXIFG: break; // RX interrupt (unused)
case USCI_UART_UCTXIFG: // TXBUF is ready for next byte
UCA0TXBUF = (uint8_t)((ADC_Result >> 8) & 0xFF); // Send high byte
UCA0IE &= ~UCTXIE; // Disable UCTXIE until next ADC conversion
break;
case USCI_UART_UCSTTIFG: break;
case USCI_UART_UCTXCPTIFG: break;
default: break;
}
}
Even I have tried alternative clocks ; ACLK still the error of sampling frequency and jitters are same. I am stuck at this stage from 2 months. I tried various approach but the result seems same regarding recorded signal frequency and jitter. I have following questions?
- How stable is DCO clock (SMCLK or ACLK)?
- What is the reason of jitter?
- Do we need Clock calibration? if yes, How to calibrate clock for stable frequency?
- Do we need external clock or crystal ?
Please give me pragmatic response We are closed to deadline?