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.

CCS/MSP430F5529: MSP430F5529

Part Number: MSP430F5529

Tool/software: Code Composer Studio

RX interrupt is only triggered for the last byte. I'm using 115200 baud with 8-N-1. I'm able to transmit with no issues. And I see the received data on my analyzer - not sure why the interrupts are not triggered 

Code snippet below: 

extern void uart_init(void)
{
gpio_set_peripheral_module_output(UART_TX);
gpio_set_peripheral_module_output(UART_RX);

USCI_A_UART_initParam param = { 0 };
param.selectClockSource = USCI_A_UART_CLOCKSOURCE_SMCLK; //1.04MHz 
param.clockPrescalar = 9;
param.firstModReg = 0;
param.secondModReg = 1;
param.parity = USCI_A_UART_NO_PARITY;
param.msborLsbFirst = USCI_A_UART_LSB_FIRST;
param.numberofStopBits = USCI_A_UART_ONE_STOP_BIT;
param.uartMode = USCI_A_UART_MODE;
param.overSampling = 0;

USCI_A_UART_init(USCI_A0_BASE, &param);
USCI_A_UART_enable(USCI_A0_BASE);

USCI_A_UART_clearInterrupt(USCI_A0_BASE, USCI_A_UART_TRANSMIT_INTERRUPT_FLAG);
USCI_A_UART_clearInterrupt(USCI_A0_BASE, USCI_A_UART_RECEIVE_INTERRUPT_FLAG);

USCI_A_UART_enableInterrupt(USCI_A0_BASE, USCI_A_UART_RECEIVE_INTERRUPT);
USCI_A_UART_enableInterrupt(USCI_A0_BASE, USCI_A_UART_TRANSMIT_INTERRUPT);
}

#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
{

switch(__even_in_range(UCA0IV,4))

{

//If RX BUF pending
case 2:
UartRcvBuf[UartRcvBufIndex++] = UCA0RXBUF;

}

  • Hello,

    Did you enable global interrupt?

  • Yes, I enabled it in my main function. What's weird is that the transmit works perfectly fine, but I'm having issues with the receiving multiple bytes. 

    WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer

    _disable_interrupts();
    _enable_interrupts();

  • > USCI_A_UART_enableInterrupt(USCI_A0_BASE, USCI_A_UART_TRANSMIT_INTERRUPT);

    You shouldn't do this, since your ISR doesn't deal with the TXIFG, so between Tx bytes, your program is continuously cycling through the ISR.. (It sounds(?) as though you're using polling for Tx.) 

  • This is my entire interrupt function. I do have a routine to service my TX interrupts. I'm assuming that those are dealt with based on the priority and I saw that the Rx interrupts are higher priority. Not sure why the RX interrupts are not triggered for the first byte of my received data packet.

    #pragma vector=USCI_A0_VECTOR
    __interrupt void USCI_A0_ISR(void)
    {
    switch(__even_in_range(UCA0IV,4))
    {
    //If RX BUF pending
    case 2:
    _nop();

    //If TX BUF pending
    case 4:
    if (uart_tx_counter < uart_tx_length)
    {
    //Transmit next data
    USCI_A_UART_transmitData(USCI_A0_BASE, *(uart_tx_buffer + uart_tx_counter));
    uart_tx_counter++;
    }
    else
    {
    //Last byte
    USCI_A_UART_transmitData(USCI_A0_BASE, *(uart_tx_buffer + uart_tx_counter));
    USCI_A_UART_disableInterrupt(USCI_A0_BASE, USCI_A_UART_TRANSMIT_INTERRUPT);
    }
    break;

    default: break;
    }
    }

  • [Your "case 2:" seems to have disappeared. I'll assume it was a copy/paste error.]

    I don't see anything obviously wrong here, so I imagine there's something going on elsewhere in the program. I'd be looking for a long running interrupts-disabled code sequence (e.g. delay loop in an ISR) which can lock out the UCA0 ISR for a full byte time (~85usec).

    How are you testing this? Breakpoints? Or waiting for it to reach a done(-ish) state and pausing the debugger?

  • Oh right, yeah I removed the code there to just test if it entered the interrupt. Just a copy paste error. 

    I don't really have any thing else running. I basiclaly start up, send 7 bytes and need to read 14 bytes from another device. The way I have it working is, I initiate a send - transmit byte by byte and then it should pretty much just go to the rx interrupt to read the first byte. 

    I just have the breakpoint on the _nop() to check what data I get back. I also set the breakpoint at the _nop() inside the rx int but it only went there once. It's also weird because I see the full frame on my analyzer. 

    I should also mention that I'm using a launchpad and I've connected to pins 3.4 and 3.3 to use A0UART. 

    main()

    {

    _disable_interrupts();
    _enable_interrupts();
    uart_init();

    uart_send();

    _nop();

    }

    void uart_send(uint8_t * data, uint8_t length, uint8_t * rxdata, uint8_t rxlength)
    {
    uart_tx_counter = 0;
    uart_tx_length = length - 1;
    uart_tx_buffer = data;

    uart_rx_counter = 0;
    uart_rx_length = rxlength - 1;
    uart_rx_buffer = rxdata;

    //Transmit first byte - since Tx is ready already
    USCI_A_UART_transmitData(USCI_A0_BASE, *(uart_tx_buffer + uart_tx_counter));
    uart_tx_counter++;
    }

    #pragma vector=USCI_A0_VECTOR
    __interrupt void USCI_A0_ISR(void)
    {
    switch(__even_in_range(UCA0IV,4))
    {
    //If RX BUF pending
    case 2:
    _nop();

    //If TX BUF pending
    case 4:
    if (uart_tx_counter < uart_tx_length)
    {
    //Transmit next data
    USCI_A_UART_transmitData(USCI_A0_BASE, *(uart_tx_buffer + uart_tx_counter));
    uart_tx_counter++;
    }
    else
    {
    //Last byte
    USCI_A_UART_transmitData(USCI_A0_BASE, *(uart_tx_buffer + uart_tx_counter));
    USCI_A_UART_disableInterrupt(USCI_A0_BASE, USCI_A_UART_TRANSMIT_INTERRUPT);
    }
    break;

    default: break;
    }
    }

  • Rather than breakpointing at "case 2" try letting it free-run and then look at UartRcvBuf afterward. Some of the MCU clocks keep running while you're at a breakpoint.

  • The buffer just exits with the last byte. 

  • If I let the program run without any breakpoints (none in main too), I can't see what the buffer has - it returns with identifier not found. What's the best way to debug this? 

  • Here is my code for writing and reading to the device: 

    My uart functions are in a different file from the main file. 

    main{

    WDTCTL = WDTPW | WDTHOLD; // stop watchdog timer

    _disable_interrupts();
    _enable_interrupts();

    uint8_t sendata[8] = {0xAA, 0xBB, 0x03, 0x03, 0x01, 0x2A, 0x00, 0x3A};

    uint8_t recv[14];
    uint8_t *p = recv;

    uart_init();

    uart_send(sendata, 8, p, 14);

    }

    static volatile uint8_t uart_tx_counter;
    static volatile uint8_t uart_tx_length;
    static volatile uint8_t * uart_tx_buffer;

    static volatile uint8_t uart_rx_counter;
    static volatile uint8_t uart_rx_length;
    static volatile uint8_t * uart_rx_buffer;

    extern void uart_init(void)
    {
    gpio_set_peripheral_module_output(UART_TX);
    gpio_set_peripheral_module_output(UART_RX);

    USCI_A_UART_initParam param = { 0 };
    param.selectClockSource = USCI_A_UART_CLOCKSOURCE_SMCLK;
    param.clockPrescalar = 9;
    param.firstModReg = 0;
    param.secondModReg = 1;
    param.parity = USCI_A_UART_NO_PARITY;
    param.msborLsbFirst = USCI_A_UART_LSB_FIRST;
    param.numberofStopBits = USCI_A_UART_ONE_STOP_BIT;
    param.uartMode = USCI_A_UART_MODE;
    param.overSampling = 0;

    USCI_A_UART_init(USCI_A0_BASE, &param);
    USCI_A_UART_enable(USCI_A0_BASE);

    USCI_A_UART_clearInterrupt(USCI_A0_BASE, USCI_A_UART_TRANSMIT_INTERRUPT_FLAG);
    USCI_A_UART_clearInterrupt(USCI_A0_BASE, USCI_A_UART_RECEIVE_INTERRUPT_FLAG);

    USCI_A_UART_enableInterrupt(USCI_A0_BASE, USCI_A_UART_RECEIVE_INTERRUPT);
    USCI_A_UART_enableInterrupt(USCI_A0_BASE, USCI_A_UART_TRANSMIT_INTERRUPT);
    }

    void uart_send(uint8_t * data, uint8_t length, uint8_t * rxdata, uint8_t rxlength)
    {
    uart_tx_counter = 0;
    uart_tx_length = length - 1;
    uart_tx_buffer = data;

    uart_rx_counter = 0;
    uart_rx_length = rxlength - 1;
    uart_rx_buffer = rxdata;

    //Transmit first byte - since Tx is ready already
    USCI_A_UART_transmitData(USCI_A0_BASE, *(uart_tx_buffer + uart_tx_counter));
    uart_tx_counter++;
    }

    #pragma vector=USCI_A0_VECTOR
    __interrupt void USCI_A0_ISR(void)
    {
    switch(__even_in_range(UCA0IV,4))
    {
    //If RX BUF pending
    case 2:
    *(uart_rx_buffer + uart_rx_counter) = UCA0RXBUF;
    uart_rx_counter++;
    break;

    //If TX BUF pending
    case 4:
    if (uart_tx_counter < uart_tx_length)
    {
    //Transmit next data
    USCI_A_UART_transmitData(USCI_A0_BASE, *(uart_tx_buffer + uart_tx_counter));
    uart_tx_counter++;
    }
    else
    {
    //Last byte
    USCI_A_UART_transmitData(USCI_A0_BASE, *(uart_tx_buffer + uart_tx_counter));
    USCI_A_UART_disableInterrupt(USCI_A0_BASE, USCI_A_UART_TRANSMIT_INTERRUPT);
    }
    break;

    default: break;
    }
    }

  • So, I finally see what I see in the buffer. Using the free-run and then breakpointing later. How do I implement this wait for read to finish? 

  • One simple method is to have main wait ("LPM0;"), then have the ISR wake up main ("LPM0_EXIT;") based on some criterion, e.g. buffer-full, buffer-not-empty. The criterion choice might depend on how fast you expect the bytes to arrive.

    You should also be thinking about what should happen if the bytes don't arrive (wait-forever vs timeout).

  • Thank you, I'll try that out. Does this allow enable interrupts to trigger? 

  • The LPM0 macro doesn't (itself) enable interrupts, so you should __enable_interrupt() ahead of time. 

  • If I add another line to check for last byte here:

    case 2:

    *(uart_rx_buffer + uart_rx_counter) = USCI_A_UART_receiveData(USCI_A0_BASE);
    uart_rx_counter++;

    if( last byte)

    { exit lpm0}

    break;

    I found that I'm losing a byte of data if I add the if statement. Is there a way to subscribe to a timer without affecting the UART read operation? 

  • > if( last byte)

    Since this isn't an actual C code line, my first guess is that your actual code doesn't check what you think it does.

    -------------------------

    That said: A simple way to do a timeout is:

    1) Pick a timer, say A0,, set TA0CCR0=your timeout, and set TA0CCTL0:CCIE (MC=1 for Up mode)

    2) Each time you receive a byte, clear the timer (TA0CTL |= TACLR)

    3) If you ever reach vector=TIMER0_A0_VECTOR, set an error flag and do an LPM0_EXIT to wake main.

    4) Once your buffer is full, stop the timer with TA0CTL=0.

    This won't interfere with the UART Rx.

**Attention** This is a public forum