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.

MSP430FR5969: UART communication with USCIA1 not working

Part Number: MSP430FR5969

Hi everyone,

I'm using CCS composer and I want to communicate from the msp430FR5969 with the ESP8266 module through UART communication. Basically I want to send an AT command to the ESP8266 through the USCI_A1 interrupt in order to obtain an answer (OK) and send it to the serial monitor on my PC using the USCI_A0 module.

The problem is that the code never enters the interrupt of USCI_A1, but only the one of USCI_A0.

//***************************************************************************************
//  Sending data via UART: try to catch response to AT
//***************************************************************************************
//

#include <msp430.h>
#include "driverlib.h"
#include "stdint.h"
#include <stddef.h>
#include <string.h>


#define RX_BUFFER_LENGTH 100

static volatile uint8_t RXbuffer[RX_BUFFER_LENGTH];
static volatile uint8_t RXbufferIDX;

#define RX_BUFFER_LENGTH1 100

static volatile uint8_t RXbuffer1[RX_BUFFER_LENGTH1];
static volatile uint8_t RXbufferIDX1;


// -------------------------------------------------------------------------
// UART SEND/PARSE STRING FUNCTIONS
// -------------------------------------------------------------------------

// ------------------------------------------------------------------------------
// UART interface
// -------------------------------------------------------------------------------

//USCI_A0
#define UART_TX_READY       (UCA0IFG & UCTXIFG)
#define UART_RX_READY       (UCA0IFG & UCRXIFG)
#define UART_TX_DONE        (UCA0IFG & UCTXCPTIFG)
#define UART_RESET_TX_DONE  (UCA0IFG &= ~UCTXCPTIFG)

//USCI_A1
#define UART_TX_READY_1       (UCA1IFG & UCTXIFG)
#define UART_RX_READY_1       (UCA1IFG & UCRXIFG)
#define UART_TX_DONE_1        (UCA1IFG & UCTXCPTIFG)
#define UART_RESET_TX_DONE_1  (UCA1IFG &= ~UCTXCPTIFG)


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// ---------------------------------------------------------------
// FUNCTIONS for USCI_A0
// ---------------------------------------------------------------

// Send a single character using UART
static void send_char(char c)
{
    // Sending data through UART test
    while (!UART_TX_READY)
        ;
    UCA0TXBUF = c;
    while (!UART_TX_DONE)
        ;
    UART_RESET_TX_DONE;
}

// Send a string using UART
static void send_str(char str[])
{
    while (*str != '\0')
    {
        send_char(*str);
        str++;
    }
}

static void send_int(int n, int b)
{
    static char digits[] = "0123456789ABCDEF";
    char buffer[5];
    int i = 0, sign;

    if ((sign = n) < 0)
    {
        n = -n;
    }

    do
    {
        buffer[i++] = digits[n % b];
    }
    while ((n /= b) > 0);

    if (sign < 0)
    {
        buffer[i++] = '-';
    }

    while (--i >= 0)
    {
        send_char(buffer[i]);
    }
}

static void new_line()
{
    send_char(0xD);
    send_char(0xA);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// ---------------------------------------------------------------
// FUNCTIONS for USCI_A1
// ---------------------------------------------------------------


static void send_char1(char c)
{
    // Sending data through UART test


    while (!UART_TX_READY_1)
        ;
    UCA1TXBUF = c;
    while (!UART_TX_DONE_1)
        ;
    UART_RESET_TX_DONE_1;
}

static void send_str1(char str[])
{
    while (*str != '\0')
    {
        send_char1(*str);
        str++;
    }
}

static void send_int1(int n, int b)
{
    static char digits[] = "0123456789ABCDEF";
    char buffer[5];
    int i = 0, sign;

    if ((sign = n) < 0)
    {
        n = -n;
    }

    do
    {
        buffer[i++] = digits[n % b];
    }
    while ((n /= b) > 0);

    if (sign < 0)
    {
        buffer[i++] = '-';
    }

    while (--i >= 0)
    {
        send_char1(buffer[i]);
    }
}

static void new_line1()
{
    send_char1(0xD);
    send_char1(0xA);
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// ---------------------------------------------------------------
// UART INITIALIZATIONS
// ---------------------------------------------------------------

void init_UART_A0(void)
{
    // UART1 port
    // 2.0 : TX
    // 2.1 : RX
    P2SEL1 |= (BIT0 | BIT1);
    P2SEL0 &= ~(BIT0 | BIT1);

    // ---------------------------------------------------------------------
    // Initialization of the UART
    // - No parity
    // - LSB first
    // - One stop bit
    // - 8-bit data
    // - UART mode (asynchronous)
    // - SMCLK clock is used (rate = 1MHz)
    // - Erroneous characters rejected
    // - No break characters interrupts
    // - Not dormant
    // - Software reset disabled
    // - Baudrate: 9600 baud
    // ---------------------------------------------------------------------
    UCA0CTLW0 = UCSWRST;    // Reset
    UCA0CTLW0 = UCSSEL__SMCLK;
    // Setting the baudrate
    UCA0BR0 = 6;
    UCA0BR1 = 0x00;
    UCA0MCTLW |= UCOS16 | UCBRF_8;
    UCA0IE |= UCRXIE;                         // Enable USCI_A0 RX interrupt
    UCA0CTLW0 &= ~UCSWRST;  // Unreset
}


void init_UART_A1(void)
{
    // UART1 port
    // 2.5 : TX
    // 2.6 : RX
    P2SEL1 |= (BIT5 | BIT6);
    P2SEL0 &= ~(BIT5 | BIT6);

    UCA1CTLW0 = UCSWRST;    // Reset
    UCA1CTLW0 |= UCSSEL__SMCLK;
    // Setting the baudrate
    UCA1BR0 = 6;
    UCA1BR1 = 0x00;
    UCA1MCTLW |= UCOS16 | UCBRF_8;
    UCA1IE |= UCRXIE;                        // Enable USCI_A1 RX interrupt
    UCA1IE |= UCTXIE;                        // Enable USCI_A1 TX interrupt
    UCA1CTLW0 &= ~UCSWRST;  // Unreset
}


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// ---------------------------------------------------------------
// Init the clock
// ---------------------------------------------------------------
static void init_clock(void)
{
    // -------------------------------------------------------------------
    // Setting the clock
    // MCLK at 1MHz sourced by DCO
    // SMCLK at 1MHz sourced by DCO for UART com
    // ACLK at 32Khz sourced by LFXT for I2C com with the sensor bord
    // -------------------------------------------------------------------
    CSCTL0_H = CSKEY >> 8;  // Unlock CS registers
    CSCTL1 = DCOFSEL_0;     // Set DCO to 8 MHz
    CSCTL2 = SELA__LFXTCLK | SELS__DCOCLK | SELM__DCOCLK; // Set ACLK = LFXT (32kHz) and MCLK = SMCLK = DCO.
    CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1;   // All dividers set to 1
    CSCTL0_H = 0x01; // Lock Register
}


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//------------------------------------------------------------------------------
// USCI_A0 interrupt vector service routine.
//------------------------------------------------------------------------------

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A0_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(USCI_A0_VECTOR)))
#endif
void USCI_A0_ISR(void)
{
    switch (__even_in_range(UCA0IV, USCI_UART_UCTXCPTIFG))
    {
    case USCI_NONE:
        break;
    case USCI_UART_UCRXIFG:

        RXbuffer[RXbufferIDX] = UCA0RXBUF;
        RXbufferIDX = (RXbufferIDX + 1) % RX_BUFFER_LENGTH;
        LPM3_EXIT;
        break;
    case USCI_UART_UCTXIFG:
        break;
    case USCI_UART_UCSTTIFG:
        break;
    case USCI_UART_UCTXCPTIFG:
        break;
    }
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//------------------------------------------------------------------------------
// USCI_A1 interrupt vector service routine.
//------------------------------------------------------------------------------

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A1_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(USCI_A1_VECTOR)))
#endif
void USCI_A1_ISR(void)
{
    //debug string just to know if the interrupt works
    send_str("Success USCI_A1_ISR");
    new_line();

    switch (__even_in_range(UCA1IV, USCI_UART_UCTXCPTIFG))
    {
    case USCI_NONE:
        break;
    case USCI_UART_UCRXIFG:

        RXbuffer1[RXbufferIDX1] = UCA1RXBUF;
        RXbufferIDX1 = (RXbufferIDX1 + 1) % RX_BUFFER_LENGTH1;
        send_str("Data recieved!");
        send_int(RXbufferIDX, 10);
        new_line();
        LPM3_EXIT;
        break;
    case USCI_UART_UCTXIFG:
        break;
    case USCI_UART_UCSTTIFG:
        break;
    case USCI_UART_UCTXCPTIFG:
        break;
    }
}

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//MAIN

void main(void)
{
    volatile unsigned j;
    WDTCTL = WDTPW | WDTHOLD;   // Stop Watchdog Timer
    PM5CTL0 &= ~LOCKLPM5;       // This is Needed for MSP430FR5969!

    
    init_clock();
    init_UART_A0();
    init_UART_A1();

    _EINT();			// Enable interrupts globally.

    while (1)
    {
        send_str("begin");
        new_line();

        send_char1('A');
        send_char1('T');
        new_line1();

        send_str("AT sent");
        new_line();

        LPM3;

    }
}

 

Here we can see that the code never enters in USCI_A1 interrupt.

begin
AT sent
begin
AT sent
begin
AT sent
begin
I apologize if the question looks bad, it is the first time I ask something on a forum, so I'm not very practical.
Thanks in advance for the replies!
  • Hi Samuele,

    At first glance, I don't see anything apparently wrong with your code. The first thing I would do is get my hands on a logic analyzer or oscilloscope and probe the RX and TX lines. This way you can see if any data is actually being transmitted between the two devices. Once you've done this, can you upload an image of the transmission?

    I also recommend reading through the Section 2 and 3 of Solutions to Common eUSCI and USCI Serial Communication Issues on MSP430 MCUs. Keep me updated!

    Best regards, 
    Caleb Overbay

  • Hi Caleb,

    Right now I don't have an oscilloscope, so I have to wait til Saturday to make the probe.

    Anyway I forgot to mention that I also tried to do it polling, without entering the Low Power Mode (and so without the interrupt routine) and it went good: RX and TX worked well.
    And also: I first tried it out just communicating with the msp430 through USCI_A0 and it worked well, then I added the USCI_A1 part of code and tried to communicate with the ESP8266, but it didn't work and neither did the USCI_A0 part that worked fine.

    The code blocked in function send_char at line 54 { while (!UART_TX_READY) }.

    Hope this will help.

    Best,
    Samuele
  • Hi Samuele,

    I overlooked that you were going into LPM3. This is probably the issue. Please read through Section 3.2 "Approaches to using UART with Low-Power Modes" of  Solutions to Common eUSCI and USCI Serial Communication Issues on MSP430 MCUs

    It looks like you're sourcing UART with SMCLK and this source is off in LPM3. You can see which clocks are active in what LPM in section 6.3 of MSP430FR59xx Mixed-Signal Microcontrollers. I see you're have setup a 32-kHz LFXT sourcing ACLK and this source is still active in LPM3. You could setup your UART communication at 9600 baud sourced from ACLK and I would expect the issue to go away. 

    Best regards, 

    Caleb Overbay

  • Hi Caleb,

    I tried changing the LPM mode to LPM1 and then also to LMP0 (of course checking that the smclk was enabled), but it didn't work.

    So I tried setting the ACLK and I'm not sure it's the right way to do it, because it gives me some problems either in UART0 (that worked well before).

    Can you please tell me if this is wrong?

    void init_UART_A0(void)
    {
        // UART1 port
        // 2.0 : TX
        // 2.1 : RX
        P2SEL1 |= (BIT0 | BIT1);
        P2SEL0 &= ~(BIT0 | BIT1);
    
        // ---------------------------------------------------------------------
        // Initialization of the UART
        // - No parity
        // - LSB first
        // - One stop bit
        // - 8-bit data
        // - UART mode (asynchronous)
        // - ACLK clock is used (rate = 32kHz)
        // - Erroneous characters rejected
        // - No break characters interrupts
        // - Not dormant
        // - Software reset disabled
        // - Baudrate: 9600 baud
        // ---------------------------------------------------------------------
        UCA0CTLW0 = UCSWRST;    // Reset
        UCA0CTLW0 = UCSSEL__ACLK;
        // Setting the baudrate
        UCA0BR0 = 3;
        UCA0BR1 = 0x00;
        UCA0MCTLW &= UCOS16;                    // Required for low frequency baud rate generation
        UCA0IE |= UCRXIE;                       // Enable USCI_A0 RX interrupt
        UCA0CTLW0 &= ~UCSWRST;                  // Unreset
    }
    
    
    void init_UART_A1(void)
    {
        // UART1 port
        // 2.5 : TX
        // 2.6 : RX
        P2SEL1 |= (BIT5 | BIT6);
        P2SEL0 &= ~(BIT5 | BIT6);
    
        UCA1CTLW0 = UCSWRST;    // Reset
        UCA1CTLW0 |= UCSSEL__ACLK;
        // Setting the baudrate
        UCA1BR0 = 3;
        UCA1BR1 = 0x00;
        //UCA1MCTLW |= UCBRF_8;
        UCA1MCTLW &= UCOS16;
        UCA1IE |= UCRXIE;                        // Enable USCI_A1 RX interrupt
        UCA1IE |= UCTXIE;                        // Enable USCI_A1 TX interrupt
        UCA1CTLW0 &= ~UCSWRST;  // Unreset
    }

    Kind regards,

    Samuele

  • > UCA1IE |= UCRXIE; // Enable USCI_A1 RX interrupt
    > UCA1IE |= UCTXIE; // Enable USCI_A1 TX interrupt
    > UCA1CTLW0 &= ~UCSWRST; // Unreset

    1) Set the IE bits After taking the UART out of reset. (See also SLAU367E sec 21.3.1).
    2) Don't set TXIE at all. Your ISR doesn't deal with it, so it will interfere with your polled-mode code.
    3) Sending a string during a (single-byte) Rx interrupt will (high probability) result in dropped Rx data. This isn't affecting you now, since you're only looking for yes/no, but it will eventually.
  • Hi Bruce,

    I've done what you recommended me and it doesn't work.

    Bruce McKenney47378 said:


    1) Set the IE bits After taking the UART out of reset. (See also SLAU367E sec 21.3.1).

    I think that it doesn't change it, because I'm setting it with a mask and I also exit the reset mode masking a 0 in the right spot.

    Anyway I decided to use only UART USCI_A0 wiring esp tx to  msp debug receive , removing the jumper, and esp rx to msp transmitter so that I cannot communicate with msp via serial monitor, but I can receive esp responses. Now it works fine.

    Thank you all for your answers!


    Samuele

  • Hi Samuele,

    It's good to hear you were able to get things working. I agree with all the points Bruce made and recommend you take them into account when developing your application.

    When you tried running UART from the LFXT, you said you were experiencing some issues. This may be due to the crystal not oscillating properly. In init_clock() you setup ACLK to be sourced from LFXT1 but never check for any fault flags to ensure LFXT1 is oscillating correctly. An example of properly setting up an external crystal can be seen below. There are also examples in MSP430Ware which can be accessed in CCS via the TI Resource Explorer.

    // XT1 Setup
      CSCTL0_H = CSKEY >> 8;                    // Unlock CS registers
      CSCTL2 = SELA__LFXTCLK | SELS__DCOCLK | SELM__DCOCLK;
      CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1;     // Set all dividers
      CSCTL4 &= ~LFXTOFF;
      do
      {
        CSCTL5 &= ~LFXTOFFG;                    // Clear XT1 fault flag
        SFRIFG1 &= ~OFIFG;
      }while (SFRIFG1&OFIFG);                   // Test oscillator fault flag
      CSCTL0_H = 0;                             // Lock CS registers

    Best regards, 
    Caleb Overbay

**Attention** This is a public forum