This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430FR2433: Clock is off

Part Number: MSP430FR2433
Other Parts Discussed in Thread: MSP-EXP430FR2433

Hi Team,

Posting on behalf of our customer.

I have this MSP-EXP430FR2433 and CCS installed. I have some code here, which Google Gemini helped me with. My goal is to run the code on the LaunchPad and then change it to run on my target which has a MSP4302422 on it. It is very simple, a pair of ports - one of which will be pulled low and then a three byte serial message is sent out.

I have my project running, but there is a problem.

Perhaps the clock within the MSP430 is not accurate enough?
I believe there is some factory calibration on the REFO to make
it more accurate? I am using the defaults, which gives a DIVCLK
of 1 MHz for SMCLK and divide by 32 to get the MIDI rate 31,250 Hz.
The 3 byte message should be 960 microseconds long however on
the scope it appears to be a tiny bit less than 920 microseconds.

 

IN any event, the MIDI keyboard reports "MIDI error".

Perhaps I need to use more provided hardware in the MSP430 to get
the baud rate about 6% slower than what I am getting. I actually did
suspect this might happen, but I didn't think the clock would be off
as much as it appears to be.

What do you think?

Regards,

Danilo

  • I am using the defaults,

    The default is the DCO. Without even the benefit of the calibration data in the TLV. But even with that, the DCO has a significant variation with temperature.

    If you need an accurate clock, nothing beats a crystal. 

  • Hi Danilo,
    I also recommend looking over the following document to improve the accuracy of the internal oscillator.

    Best Regards,

    Diego Abad

  • Hi David and Diego,

    Thank you for your response. Please see our customer's feedback below.

    Thanks for getting this information to me. It is interesting that there is some internal calibration but it is not in use with the defaults, I believe that is what you have said in your message? I am back in Italy now but I will be delighted to return to working on my project in a few weeks time. I have already finished the circuit board and had them fabricated so adding a crystal is not possible, although I could modify the code and use the crystal on my LaunchPad, but I was expecting that I might need to take some steps to improve the accuracy of the clock for some individual ICs thinking that some individual ICs might work right out of the box, but at least for the one IC installed on my LaunchPad the accuracy is out of specification. When I look at the information you just sent I hope my expectations are confirmed - that once I measure any inaccuracy on an individual IC, there would be some way to calculate a register value to fix it for that one individual IC. Each IC may require a different value I expect.
    I was using Google Gemini to help me write the code. Gemini suggested that I could change the baud rate divisor from 32 to 33, I don't know if that is really a
    possible value? Gemini is kind of a silly helper sometimes...
    I don't expect there would be much temperature variation in my application, the target will be in use in a very controlled temperature environment.

    Regards,

    Danilo

  • When I crunch the numbers on the reported message time (920us) I get an error greater than the maximum specified for REF0. Which suggests that there might be an additional problem. Some code demonstrating the problem would be nice.

  • Hi David,

    Please see our customer's response below.

    Yes, I was thinking the same thing. But I did some more research and
    here is what I think about the clock functions of MSP430: 

    If  DCOFTRIMEN is clear, then  DCOFTRIM register is not used but another register
    holding the factory cal is used. It would not really help in my application to use  DCOFTRIM.

    there are a few experiments I can try when I get back to my workbench in Euless TX:

    1) I could spray the 2433 IC on my LaunchPad with coolant and see if DCO slows down
    2) I could change the baud rate divisor from 32 to 33 and see if that makes it work
    3) I could enable the crystal on my LaunchPad by moving jumpers and enable the pins

    Basically the clock on my particular LaunchPad is too fast, and also a little out of spec.

    The goal is to run the target, which can not use a crystal, but uses a 2422 instead of 2433.

    I will attach the code. It does work, but the clock is 4-5% too fast for some reason.

    There are copious notes in the file, but the code is at the end I think.

    clock stuff: section 8.12.3 page 21-22
    Clock System (CS) and Clock Distribution: section 9.10.2 page 44
    
    for LaunchPad, Goal: To slightly slow down the DCO frequency by 4.348%
    ********************************************************************
    MSP430FR2xx User Guide Clock Notes
    page 102 showing
    After PUC, DCO locked by FLL operation with XT1CLK is selected by default. The FLL stabilizes MCLK and SMCLK to 1 MHz and fDCOCLKDIV = 1 MHz.
    	{note: page 116 SELREF default 0h which is XT1CLK}
    [if XT1CLK selected by default, then external pins would be XT1 but also on
    this page showing "At power up, the default operation is I/O"]
    	{note: page 120 Table 3-10 XT1BYPASS default internal (not pins)}
    [further down the page 102 showing]
    A default monitor is engaged with XT1 oscillation. If XT1 is used but does not work properly, fault protection logic forces REFO as the FLL reference clock.
    
    page 114 Table 3-5 CSCTL1 register (default)
    showing DCO range select 2 MHz but FLLD (divider) is 2
    
    page 117 Table 3-8 MCLK & SMCLK source default is DCOCLKDIV
     {so according to diagram page 100, result is default both 1MHz}
    ****************************************************************
    With SMCLK = 1MHz, divide by 32 to get 31,250 Hz
    
    MSP430FR2xx User Guide UART Notes
    After a PUC, the UCSWRST bit is automatically set, keeping the eUSCI_A in a reset condition. When set, the UCSWRST bit sets the UCTXIFG bit and resets the UCRXIE, UCTXIE, UCRXIFG, UCRXERR, UCBRK, UCPE, UCOE, UCFE,
    UCSTOE, and UCBTOE bits. Clearing UCSWRST releases the eUSCI_A for operation. A transmission is initiated by writing data to UCAxTXBUF.
    When this occurs, the baud-rate generator is enabled, and the data in UCAxTXBUF is moved to the transmit shift register on the next BITCLK after the transmit shift register is empty. UCTXIFG is set when new data can be written into UCAxTXBUF.
    
    defaults starting page 593 Table 22-8
    no parity, LSB first, 8-bit, 1 stop bit, UART mode, Async
    BRCLK source = UCLK(?) change to SMCLK perhaps
    
    
    *************************************************************************
    when DCO is 16 MHz and MCLK (/64) is 250 KHz and SMCLK (/8) is 31,250 Hz
    then a midi bit is 32 microsec, sending 85d or 55h message 256 usec long
    appears as |_|~|_|~|_|~|_|~|_| = 64 + 16 + 4 + 1
                        180                    85                   
    stop shows: l l l h l h h l h h - l h l h l h l h l h - l l l l l l l h l h = 64
    S2 shows  : l l l h l h h l h h - l h l h l h l h l h - l h h h h h h l l h = 63
    S1 shows  : l l l h l h h l h h - l h l h l h l h l h - l h l l l l l h l h = 65
    
    So I can program the device to send a string of messages (85d or 55h) and
    measure the signal to figure out how to adjust the register values.
    *****************************************************************
    
    UART alt
    pin 12 - P1.5/UCA0RXD(uart)/UCA0SOMI(spi)/TA0.2(timer)/TMS(jtag)
    pin 13 - P1.4/UCA0TXD(uart)/UCA0SIMO(spi)/TA0.1(timer)/TCK(jtag)
    The eUSCI_A and eUSCI_B are connected either from P1 port
    or P2 port, it can be selected from the USCIARMP of SYSCFG3
    or USCIBRMP bit of SYSCFG2
    PIN (USCIARMP = 0) UART
    P1.4 TXD (pin 13 on target) not used (used on LaunchPad)
    P1.5 RXD (pin 12 on target) not used (used on LaunchPad)
    
    half moon switch
    J1 tip to pin 1 (P1.1) low input = slow
    J1 ring to pin 2 (P1.0) low input = fast
    J1 when both are hi then = stop
    for midi channel 5
    For Slow we need CC#85 value 0 (to 63)    = 180 85 63
    for Stop we need CC#85 value 64		  = 180 85 64
    for Fast we need CC#85 value (65 to) 127  = 180 85 65
    
    midi jacks - output can be type A (3.5mm) or type B (2.5mm)
    UCATxD P2.0 pin 8 -> buf OE pin 13 (pin 11->R4->J2 tip (A) altJ2 ring (B))
    UCARxD P2.1 pin 7 <- buf out pin 8 (pin 10 -> gnd) pin 9 midi in 47K -> 5v
    
    SpyByWire
    pin 3 SBWtck
    pin 4 SBWtdio
    
    *******************************************************************
    
    for 2422 (target):
    pin 14 is DO NOT CONNECT
    pin 3 = SBWTCK
    pin 4 = SPWTDIO
    pin 5 = Vcc
    pin 6 = Vss
    
    pin 7,8 P2.0 & P2.1 P2SELx = 01 is UCA0Tx - UART function
    	(P2.0 & P2.1 P2DIR.x - n/a)
    pin 9 P2.2 P2SELx = 00 is I/O
    	P2.2 P2DIR.x = 0 is input
    
    P1.0 & P1.1 (pin 1,2) P1DIR.x = 0 is input
    P1.0 & P1.1 P1SELx = 00 I/O
    P1.2,P1.3,P1.4,P1.5,P1.6,P1.7 (pin 16,15,13,12,11,10) P1DIR.x = 0 is input
    P1.2 & P1.3 & P1.4 P1SELx = 00 is I/O
    
    setup:
    clocks, UART, ports, active mode, timer, activate UART
    read ports 1.0 & 1.1 and store in RAM (00, 01, or 10)
    
    code loop:
    start snooze timer (20 ms?)
    check ports against stored value: if different, store and send MIDI
    snooze again -> back to read ports
    
    ********************************************************************
    
    to transmit the MIDI code after UART is setup:
    write status byte to UCAxTXBUF and wait for UCTXIFG to be set
    then write first data byte, wait for UCTXIFG, write second data byte
    
    ********************************************************************
    
    Here's the code:
    
    /*
     * MSP-EXP430FR2433 UART Transmitter Program (Polling Version)
     *
     * This version uses a polling loop for button state checking and implements
     * software debouncing using Timer A0. Interrupts are disabled.
     *
     * 1. Clock: DCO=2MHz, MCLK=1MHz, SMCLK=1MHz (Default).
     * 2. UART Baud Rate: 31,250 bps (using 1 MHz SMCLK, UCBRW=32).
     * 3. Timer A0: Implements a single 5-second wait and a 20ms debouncing wait.
     * 4. Button Logic (Active Low, Pull-ups):
     * - STOP (P2.3=Hi, P2.7=Hi): Sends [180, 85, 64]
     * - SLOW (P2.3=Hi, P2.7=Low): Sends [180, 85, 63]
     * - FAST (P2.3=Low, P2.7=Hi): Sends [180, 85, 65]
     *
     * NOTE: Timer peripherals are correctly set to Timer A0 (TA0).
     */
    
    #include <msp430.h>
    
    // Enumeration for button states
    typedef enum {
        MODE_STOP = 64,
        MODE_SLOW = 63,
        MODE_FAST = 65
    } Mode;
    
    // Function prototypes
    void UART_send_packet(unsigned char byte3);
    void timer_wait_5s(void);
    void timer_wait_20ms(void);
    Mode get_current_mode(void);
    
    
    void main(void)
    {
        Mode previous_mode = MODE_STOP;
        Mode new_mode;
    
        // Stop watchdog timer
        WDTCTL = WDTPW | WDTHOLD;
    
        // =========================================================================
        // 1. Clock System Configuration (Using System Defaults - SMCLK = 1 MHz)
        // =========================================================================
        __bis_SR_register(SCG0); // Disable global interrupts during clock config
        __bic_SR_register(SCG0); // Re-enable interrupts
    
        // =========================================================================
        // 2. GPIO Configuration (Buttons S1/S2 and UART)
        // =========================================================================
    
        // 2a. Configure Buttons S1 (P2.3) and S2 (P2.7)
        P2DIR &= ~(BIT3 | BIT7); // Set P2.3 and P2.7 as inputs
        P2REN |= (BIT3 | BIT7);  // Enable pull-up/pull-down resistors
        P2OUT |= (BIT3 | BIT7);  // Configure as pull-up resistors (P2OUT set = pull-up)
        // P2IE is not set - Interrupts are disabled for polling mode
        P2IFG = 0;               // Clear all P2 interrupt flags
    
        // 2b. Configure UART Pins (P1.4 Tx, P1.5 Rx) for eUSCI_A0
        P1SEL0 |= (BIT4 | BIT5);
        P1SEL1 &= ~(BIT4 | BIT5);
    
        // Disable the unused pins to save power
        PM5CTL0 &= ~LOCKLPM5;
    
        // =========================================================================
        // 3. eUSCI_A0 (UART) Configuration (Using 1 MHz SMCLK)
        // =========================================================================
        UCA0CTLW0 |= UCSWRST;         // Put eUSCI in reset for configuration
        UCA0CTLW0 |= UCSSEL__SMCLK;   // Select SMCLK as source (1 MHz default)
        UCA0BRW = 32;                 // Integer division factor for 31,250 bps
        UCA0MCTLW = 0x0000;           // No modulation
        UCA0CTLW0 &= ~UCSWRST;        // Initialize eUSCI (release from reset)
    
        // =========================================================================
        // 4. Initial 5-Second Wait & Main Loop
        // =========================================================================
        timer_wait_5s();
    
        // Start polling loop (no low power mode is used since we are actively polling)
        while(1)
        {
            // 1. Read the current unsettled mode (State A)
            new_mode = get_current_mode();
    
            // 2. Check for a potential state change
            if (new_mode != previous_mode)
            {
                // 3. Wait 20ms to debounce
                timer_wait_20ms();
    
                // 4. Read the state again (State B)
                Mode settled_mode = get_current_mode();
    
                // 5. If the state is still different (change settled)
                if (settled_mode != previous_mode)
                {
                    // Send the UART message corresponding to the new mode
                    UART_send_packet((unsigned char)settled_mode);
    
                    // Update the stored mode
                    previous_mode = settled_mode;
                }
            }
            // Small delay to prevent constantly hammering the CPU/Timer
            timer_wait_20ms();
        }
    }
    
    /**
     * @brief Reads the state of P2.3 (S1) and P2.7 (S2) and returns the defined Mode.
     */
    Mode get_current_mode(void)
    {
        unsigned int p2_state = P2IN;
        unsigned int s1_state = p2_state & BIT3; // 0 if pressed, BIT3 if released
        unsigned int s2_state = p2_state & BIT7; // 0 if pressed, BIT7 if released
    
        // STOP: P2.3 High (Released) AND P2.7 High (Released)
        if (s1_state && s2_state) {
            return MODE_STOP; // 64
        }
        // SLOW: P2.3 High (Released) AND P2.7 Low (Pressed)
        else if (s1_state && !s2_state) {
            return MODE_SLOW; // 63
        }
        // FAST: P2.3 Low (Pressed) AND P2.7 High (Released)
        else if (!s1_state && s2_state) {
            return MODE_FAST; // 65
        }
    
        // Default to STOP if an ambiguous state (both pressed) occurs, though
        // this shouldn't happen with the current logic.
        return MODE_STOP;
    }
    
    /**
     * @brief Sends a 3-byte packet over the UART (eUSCI_A0).
     */
    void UART_send_packet(unsigned char byte3)
    {
        unsigned char packet[] = {180, 85, byte3};
    
        while (!(UCA0IFG & UCTXIFG));
        UCA0TXBUF = packet[0];
        while (!(UCA0IFG & UCTXIFG));
        UCA0TXBUF = packet[1];
        while (!(UCA0IFG & UCTXIFG));
        UCA0TXBUF = packet[2];
    }
    
    /**
     * @brief Blocks execution for exactly 5.0 seconds using Timer A0.
     *
     * Uses SMCLK (1 MHz) divided by 64 (15,625 Hz). Ticks needed: 78,125.
     */
    void timer_wait_5s(void)
    {
        // Configure TA0: SMCLK / 64 (ID=3, IDEX=7) -> 15625 Hz
        TA0CTL = TASSEL_2 | MC__STOP | TACLR | ID_3;
        TA0EX0 = TAIDEX_7;
    
        // First count: 65536 ticks
        TA0CCR0 = 65536 - 1;
        TA0CTL |= MC__UP;
        while (!(TA0CCTL0 & CCIFG)); // Check CCIFG in TA0CCTL0
        TA0CCTL0 &= ~CCIFG;            // Clear CCIFG
    
        // Second count: remaining 12589 ticks
        TA0CCR0 = 12589 - 1;
        TA0CTL |= MC__UP;
        while (!(TA0CCTL0 & CCIFG)); // Check CCIFG in TA0CCTL0
    
        // Ensure timer is completely stopped and reset
        TA0CTL = MC__STOP | TACLR;
    }
    
    /**
     * @brief Blocks execution for exactly 20 milliseconds using Timer A0.
     *
     * Uses SMCLK (1 MHz) divided by 1 (1,000,000 Hz). Ticks needed: 20,000.
     */
    void timer_wait_20ms(void)
    {
        // Configure TA0 to use SMCLK / 1 -> 1 MHz
        TA0CTL = TASSEL_2 | MC__STOP | TACLR;
    
        TA0CCR0 = 20000 - 1;
        TA0CTL |= MC__UP;
        while (!(TA0CCTL0 & CCIFG)); // Check CCIFG in TA0CCTL0
    
        // Ensure timer is completely stopped and reset
        TA0CTL = MC__STOP | TACLR;
    }
    
    *******************************************************************
    
    2. Load Program Only
    
    If you only want to flash the code without starting the interactive debugger (e.g., for a final release version), you can use the Load option.
    
        Connect the Hardware: Plug in your LaunchPad.
    
        Load Program: Go to Run -> Load -> Load Program...
    
        Browse: A dialog will open, and you'll typically select the .out file located in your project's Debug folder (e.g., LaunchPad midiator 1.out).
    
        Load: Click OK.

    Regards,

    Danilo

  • After a brief scan of the posted text, I ignored it. It is saying silly things like MCLK=250KHz.

    Code is more reliable, usually. For example:

        __bis_SR_register(SCG0); // Disable global interrupts during clock config
        __bic_SR_register(SCG0); // Re-enable interrupts
    

    In spite of the comments, this does nothing to interrupts. Setting SCG0 will disable the FLL. Will turning the FLL off and then on like this annoy it? Maybe not. I don't have one handy to test with. Also, the guide is a little vague on the factory trim. Implying that it is available only for the maximum setting. Use of software trim being required for other values.

    The UART divisor should use UCOS16 (oversampling mode) and UCA0BRW=2. Maybe not a big deal if you only transmit.

  • Hi David,

    Here is our customer's feedback.

    Right you are, the notes should be ignored as it went through many changes.

    The code does work (except the MCLK or perhaps REFO running fast) so I
    left a bunch of stuff in there as it didn't make any trouble. The code was
    actually written entirely by Google Gemini, and at first there was interrupt in
    use instead of polling for the buttons but I requested that Gemini change it -
    at one point I wasn't getting the environment in Code Composer Studio happy.
    So the nonsense with turning the interrupts on and off was a leftover from that.

    I took C and C++ at Purdue 30 years ago, so using Gemini helped what I don't
    remember and avoids me having to lookup all the mnemonic abbreviations. My
    background was entirely assembly and I would just use the memory addresses
    instead of using the alphabetic codes. Thanks for the tip on the UART - I don't
    use the Rx input but would like to have it available since the pins are connected
    through a buffer and it could be used if I needed to.

    I will be back to Euless next week and try those experiments: freeze the IC, run
    the baud rate divisor at 33 instead of 32, and connect the crystal if those don't help.
    If it turns out my LaunchPad is out of spec, you could swap me if you are near Euless.

    Regards,

    Danilo

**Attention** This is a public forum