6 years, 2 months ago.

UART locks up after transmission (STM32L152)

Hello,

I am running in a very weird issue with the USART on my Nucleo STM32L1 board (STM32L152RE).

My code is supposed to do the following things:

  • Register a callback function for the USART RX interrupt. In there, read all the received bytes and save it in a buffer
  • in the main thread, periodically print the contents of the RX buffer every second
  • in the main thread, transmit some dummy data every 5 seconds

My code displays the receive buffer every second without a problem and also transmits something every 5 seconds. The problem is that as soon as I have transmitted something, and then send the MCU some data over the USART, it locks up completely. The main thread just seems to not ever continue printing the RX buffer.

If I transmit something to the board before it transmits something first, then I can see the data I sent in the MCU's receive buffer, which is printed in the main thread.

It seems that after I execute my asynchronous write call, it screws up something so bad, that it never continues to do anything useful the moment it gets sent something. I have no idea why.

The following is a minimal example in which the problem occurs:

#include "rtos.h"

/* Declare the builtin USB UART for debugging purposes
 * and the UART over which data will be sent */

Serial pc(USBTX, USBRX, "debug", 115200);
Serial DataSerial(PA_9, PB_7, "dataserial", 115200); //TX, RX

/* main UART buffer */
#define UART_BUF_LEN 100
uint8_t UART_Buf[UART_BUF_LEN];
int UART_Buf_Position = 0;

/* EventFlags object for signaling that TX is done */
EventFlags txEvent;

/* function prototypes */
void RX_Complete_Callback();
void Print_RX_Buf();
void DataSerial_SendMessage(const uint8_t* data, size_t len);

int main() {
    //Register our RX interrupt callback
    DataSerial.attach(callback(&RX_Complete_Callback), Serial::RxIrq);

    int i=0;
    while(1) {
        i++;
        pc.printf("Loop iteration %d\n", i);
        //Wait a second
        wait(1.0f);
        //Print RX buffer
        Print_RX_Buf();

        //Every 5th second, send something
        if(i % 5 == 0) {
            const uint8_t testMessage[] = { 0xff, 0x00, 0x01, 0x02, 0x03};
            DataSerial_SendMessage(testMessage, sizeof(testMessage));
        }
    }
    return 0;
}

void RX_Complete_Callback() {
    while(DataSerial.readable()) {
        uint8_t readByte = (uint8_t) DataSerial.getc();
        //Write into UART buf, increment position
        UART_Buf[UART_Buf_Position++] = readByte;

        //check overflow
        if(UART_Buf_Position == UART_BUF_LEN) {
            pc.printf("UART RX BUF OVERFLOW!\n");
            UART_Buf_Position = 0;
        }
    }
}

void Print_RX_Buf() {
    pc.printf("RX Buf (%d bytes):\n", UART_Buf_Position);
    for(int i=0; i < UART_Buf_Position; i++) {
        printf("%02x ", UART_Buf[i]);
    }
    printf("\n");
}

void TX_Complete_Callback(int events) {
    pc.printf("TX_Complete_event %d\n", events);
    if(events & SERIAL_EVENT_TX_COMPLETE) {
        txEvent.set(0x1);
    } else {
        pc.printf("Unknown TX event %d\n", events);
    }
}

void DataSerial_SendMessage(const uint8_t* data, size_t len) {
    pc.printf("=== TRANSMITTING MESSAGE ====\n");
    //Start an asynchronous write operation
    DataSerial.write(data, len, callback(&TX_Complete_Callback));
    //Wait for completion
    txEvent.wait_all(0x1);
}

Output when I send it something before 5 seconds uptime and after it has sent something:

Loop iteration 1
RX Buf (0 bytes):

Loop iteration 2
RX Buf (6 bytes):
20 03 00 01 02 03 
Loop iteration 3
RX Buf (6 bytes):
20 03 00 01 02 03 
Loop iteration 4
RX Buf (6 bytes):
20 03 00 01 02 03 
Loop iteration 5
RX Buf (6 bytes):
20 03 00 01 02 03 
=== TRANSMITTING MESSAGE ====
TX_Complete_event 4
Loop iteration 6
RX Buf (6 bytes):
20 03 00 01 02 03 
Loop iteration 7
RX Buf (6 bytes):
20 03 00 01 02 03 
Loop iteration 8
[IT HANGS HERE FOREVER AFTER I SENT IT SOMETHING]

I'd be thankful for any pointers on what I'm doing wrong (or even if this is reproducable on any other STM32L1 board or similar).

1 Answer

6 years, 2 months ago.

Same problem here...