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.

MSP-EXP430FR5994: Uart receive overrun error flag

Part Number: MSP-EXP430FR5994
Other Parts Discussed in Thread: BQ79616, BQ79600EVM,

I have the UART loopback example working at 1Mbps baud rate with no problems. I used a 4MHz SMCLK for the UART clock. These results are using an eternal clock on the MSP430 EVM.

When interfaced with the BQ79600EVM and the a custom BQ79616, the uart receive interrupt is firing soon after I try a single device read command. I can see the UCOE flag is set. Is there anything wrong in the setup/use of the UART driver?

I have setup a 100 bit delay for the BQ79600 chip to respond so the MSP430 has time to switch from uart transmit to uart receive. Is there an ideal number for the MSP430 for this to happen?

I am using the external clock in this setup. 

#define BQUART                        EUSCI_A1_BASE
#define BQUART_DISABLE                EUSCI_A_UART_disable
#define BQUART_CLOCKSOURCE            EUSCI_A_UART_CLOCKSOURCE_SMCLK
#define BQUART_PARITY                 EUSCI_A_UART_NO_PARITY
#define BQUART_BITORDER               EUSCI_A_UART_LSB_FIRST
#define BQUART_STOPBIT                EUSCI_A_UART_ONE_STOP_BIT
#define BQUART_MODE                   EUSCI_A_UART_MODE
#define BQUART_OVERSAMPLING           EUSCI_A_UART_LOW_FREQUENCY_BAUDRATE_GENERATION
#define BQUART_INIT                   EUSCI_A_UART_init
#define BQUART_initParam              EUSCI_A_UART_initParam
#define BQUART_enable                 EUSCI_A_UART_enable
#define BQUART_disable                EUSCI_A_UART_disable

#define BQUART_REG                    P2OUT
#define BQUART_TX_PORT                GPIO_PORT_P2
#define BQUART_RX_PORT                GPIO_PORT_P2
#define BQUART_RX_PIN                 GPIO_PIN6
#define BQUART_TX_PIN                 GPIO_PIN5
#define BQUART_SELECT_FUNCTION        GPIO_SECONDARY_MODULE_FUNCTION


#define BQUART_enableInterrupt        EUSCI_A_UART_enableInterrupt
#define BQUART_RX_INT                 EUSCI_A_UART_RECEIVE_INTERRUPT
#define BQUART_clearInterrupt         EUSCI_A_UART_clearInterrupt
#define BQUART_TXBUF                  UCA1TXBUF
#define BQUART_RXBUF                  UCA1RXBUF


#define BQUART_ISR                    USCI_A1_ISR
#define BQUART_VECTOR                 USCI_A1_VECTOR
#define BQUART_IFG                    UCA1IFG
#define BQUART_IV                     UCA1IV

#define BQUART_BUSY                   (UCA1STATW&UCBUSY)
void Clock_Init()
{
#ifdef EXT_CLK
    GPIO_setAsPeripheralModuleFunctionInputPin(
         GPIO_PORT_PJ,
         GPIO_PIN4 + GPIO_PIN5,
         GPIO_PRIMARY_MODULE_FUNCTION
     );


     // Set PJ.6 and PJ.7 as Primary Module Function Input, HFXT.
     GPIO_setAsPeripheralModuleFunctionInputPin(
            GPIO_PORT_PJ,
            GPIO_PIN6 + GPIO_PIN7,
            GPIO_PRIMARY_MODULE_FUNCTION
            );

     // Check if one FRAM waitstate is needed for 5962, 5994 device as well!
     FRAMCtl_A_configureWaitStateControl(FRAMCTL_A_ACCESS_TIME_CYCLES_1);

     uint32_t u32ClockFrequencyCheck = 0u;

     // JA - Enable lxft & HXFT
     CS_setExternalClockSource(32768, 16000000);


     CS_initClockSignal(CS_SMCLK, CS_HFXTCLK_SELECT, CS_CLOCK_DIVIDER_4);

     CS_initClockSignal(CS_MCLK, CS_HFXTCLK_SELECT, CS_CLOCK_DIVIDER_1);

     //Set ACLK=LFXT
     CS_initClockSignal(CS_ACLK, CS_LFXTCLK_SELECT, CS_CLOCK_DIVIDER_1);


     //Set the appropriate drive values for each oscillator for the launchpad vs. actual schematic.
     CS_turnOnLFXT(CS_LFXT_DRIVE_3);
//       CS_turnOnLFXT(CS_LFXT_DRIVE_0);

     CS_turnOnHFXT(CS_HFXT_DRIVE_16MHZ_24MHZ);
 // JA - SMCLK appears to be running extremely slowly when sourced from HFXT


      // JA - Check SMCLK, MCLK clock frequencies
      u32ClockFrequencyCheck = CS_getMCLK();
      u32ClockFrequencyCheck = CS_getSMCLK();
#endif

#ifdef DCO_CLK
      // Configure one FRAM waitstate as required by the device datasheet for MCLK
      // operation beyond 8MHz _before_ configuring the clock system.
      FRCTL0 = FRCTLPW | NWAITS_1;

      // Clock System Setup
      CSCTL0_H = CSKEY_H;                                     // Unlock CS registers
      CSCTL1 = DCOFSEL_0;                                     // Set DCO to 1MHz

      // Set SMCLK = MCLK = DCO, ACLK = VLOCLK
      CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;

      // Per Device Errata set divider to 4 before changing frequency to
      // prevent out of spec operation from overshoot transient
      CSCTL3 = DIVA__4 | DIVS__4 | DIVM__4;                   // Set all corresponding clk sources to divide by 4 for errata
      CSCTL1 = DCOFSEL_4 | DCORSEL;                           // Set DCO to 16MHz

      // Delay by ~10us to let DCO settle. 60 cycles = 20 cycles buffer + (10us / (1/4MHz))
      __delay_cycles(60);
      CSCTL3 = DIVA__1 | DIVS__4 | DIVM__1;                   // SMCLK=2Mhz MCLK=16MHz
      CSCTL0_H = 0;                                           // Lock CS registers
#endif
}



void UART_Init(void){

    GPIO_setAsPeripheralModuleFunctionInputPin(
          BQUART_TX_PORT,
          BQUART_TX_PIN + BQUART_RX_PIN,
          BQUART_SELECT_FUNCTION
    );

    BQUART_initParam param = {0};

    param.clockPrescalar = 4,
    param.firstModReg = 0,
    param.secondModReg = 0,
    param.selectClockSource = BQUART_CLOCKSOURCE;
    param.parity =            BQUART_PARITY;
    param.msborLsbFirst =     BQUART_BITORDER;
    param.numberofStopBits =  BQUART_STOPBIT;
    param.uartMode =          BQUART_MODE;
    param.overSampling =      BQUART_OVERSAMPLING;

    if(STATUS_FAIL == BQUART_INIT(BQUART, &param))
    {
       return;
    }

    BQUART_enable(BQUART);
    BQUART_clearInterrupt(BQUART, BQUART_RX_INT);
    BQUART_enableInterrupt(BQUART, BQUART_RX_INT);

}

void uartSend(int length, uint8_t * data){
    uint8_t i;

    for (i = 0; i < length; i++){
        while (!(UCA1IFG & UCTXIFG));
        BQUART_TXBUF = data[i];
    }

}

void uartReceive(BYTE * data, BYTE length){
    while (length > 0){
        while (BQUART_BUSY);
        *data = BQUART_RXBUF;
        data++;
        length--;
    }
}

//******************************************************************************
// SPI_B1 Interrupt ************************************************************
//******************************************************************************
#pragma vector=BQUART_VECTOR
/*******************************************************************************
  USCI_B1_ISR ******************************************************************
 *******************************************************************************
* Function: B1 Interrupt Routine
********************************************************************************/
__interrupt void BQUART_ISR(void)
{
    switch(__even_in_range(BQUART_IV, USCI_UART_UCTXCPTIFG))
    {
        case USCI_NONE: break;
        case USCI_UART_UCRXIFG:
            BQUART_IFG &= ~UCRXIFG;
            __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 on reti
        break;
        case USCI_UART_UCTXIFG:  break;
        case USCI_UART_UCSTTIFG: break;
        case USCI_UART_UCTXCPTIFG: break;
        default: break;
    }
}
#endif

  • 1) Using UCBUSY for receive is just flat out wrong. If a steady stream of data is being received then the time between when the receiver state machine finishes up (somewhere in the final stop bit) and the next start bit is short. Really short at  1Mbps.

    2) Reading the IV register will have reset RXIFG so no need to do that again in the ISR.

    3) Waking up the main task to handle the data is not going to work. The usual method is to put the data into a queue. The main task can then check to see if there is data in the queue.

    4) Even with a 16Mhz clock you don't have a lot of time to deal with each byte of data.

    5) It takes no time at all for the MSP430 to switch the UART from transmit to receive. In fact they work simultaneously. Which means you could get a receive interrupt before the transmit code is finished.

  • I looked at the loopback example and I see the only processing done in the receive ISR is assigning 

    EUSCI_A_UART_receiveData(EUSCI_A0_BASE).

    I eliminated other things I had in the ISR. 

    My setup is MSP-EXP430FR5994 -> BQ79600EVM -> custom BQ79616

    When reading from the BQ79600EVM, a read command is issued for the specific register.

    Then a ReadFrameReq is sent out. This involves a write message through the UART.

    Here is where you say that the receive can happen even before the transmit ends. Can you explain more about the transmit and receive working simultaneously? I see Figure 30-1 in SLAU367P on page 769.

    I don’t have RTOS in the firmware, there is a main loop. Here is what I tried to restructure the uart receive, I don’t have uartReceive anymore. This still does not work. I can use some more pointers.

    1. ReadReg
    2. ReadFrameReq
      1. Set idx, rxComplete = 0; assign uartRxLen
      2. Compile and transmit the write frame through UART.

    #pragma vector=BQUART_VECTOR
    /*******************************************************************************
      USCI_B1_ISR ******************************************************************
     *******************************************************************************
    * Function: B1 Interrupt Routine
    ********************************************************************************/
    __interrupt void BQUART_ISR(void)
    {
        switch(__even_in_range(BQUART_IV, USCI_UART_UCTXCPTIFG))
        {
            case USCI_NONE: break;
            case USCI_UART_UCRXIFG:
                RXData[idx] = EUSCI_A_UART_receiveData(BQUART);
                idx++;
                if (idx == uartRxLen)
                   rxComplete = 1;
    
            break;
            case USCI_UART_UCTXIFG:  break;
            case USCI_UART_UCSTTIFG: break;
            case USCI_UART_UCTXCPTIFG: break;
            default: break;
        }
    }
    #endif
    

  • The receiver and transmitter are independent. Sharing a bit rate generator and not much else. So if data arrives while the transmitter is sending something, the receiver is going to handle it.

    You say it doesn't work. How doesn't it work? Is there no data at all in the receive buffer? Data that looks wrong? Not enough data? All of these are clues to the problem. (Too much data would cause trouble and a likely buffer overrun.)

  • I have a breakpoint at the first step ReadReg. If I step into this, it goes straight into the UART ISR, overrun flag is set. Instead of stepping in, I put a breakpoint at WriteFrame and run the program until here. Then I put a breakpoint in the ISR and run the program until here. I find one byte is received (not the one expected), the idx increments and then the ISR does not continue triggering until the uartRxLen.

    Even if I wait to enable the receive interrupt until uartSend, somehow the UART ISR is firing. How can this be? If all of uartRxLen is received, I disable the receive interrupt.

  • Did you try using DMA to your UART receive and Transmit operation? 

    As David suggested, use queue to push data using DMA and check the queue once the DMA transfer is complete

**Attention** This is a public forum