Search code examples
craspberry-piembeddedraspberry-pi4raspberry-pi-pico

Trouble using the UART with RPi Pico C sdk


I'm making a remote controlled machine using a pi pico to drive the motors and read some sensors, and a raspberry pi 4 to send commands to the pi pico via serial and host the web interface.

I'm working on sending and receiving commands from the raspberry and for now I'm stuck with this code:

#include <string.h>

#include "pico/stdlib.h"
#include "hardware/uart.h"
#include "hardware/irq.h"

#define UART_ID uart0
#define BAUD_RATE 19200
#define DATA_BITS 8
#define STOP_BITS 1
#define PARITY    UART_PARITY_NONE
#define UART_TX_PIN 0
#define UART_RX_PIN 1

static int chars_rxed = 0;

char uCommand[32] = {0, 0};

void on_uart_rx() {
    char tmp_string[] = {0, 0};
    while (uart_is_readable(UART_ID)) {
        uint8_t ch = uart_getc(UART_ID);
        tmp_string[0] = ch;
        strcat(uCommand, tmp_string);
        if(uart_is_writable(UART_ID)){
          uart_putc(UART_ID, '-');
          uart_puts(UART_ID, uCommand);
          uart_putc(UART_ID, '-');
        }
        chars_rxed++;
    }
}

int main(){

  uart_init(UART_ID, BAUD_RATE);

  gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
  gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);
  uart_set_hw_flow(UART_ID, false, false);
  uart_set_format(UART_ID, DATA_BITS, STOP_BITS, PARITY);
  uart_set_fifo_enabled(UART_ID, false);

  int UART_IRQ = UART_ID == uart0 ? UART0_IRQ : UART1_IRQ;

  irq_set_exclusive_handler(UART_IRQ, on_uart_rx);
  irq_set_enabled(UART_IRQ, true);
  uart_set_irq_enables(UART_ID, true, false);

  uart_puts(UART_ID, "\nOK\n");
    while (1){
        tight_loop_contents();
        if(uCommand[0] != 0){
          uart_putc(UART_ID, '/');
          uart_puts(UART_ID, uCommand);
          uart_putc(UART_ID, '/');
        }
      }
}

my idea was to take the command sent via serial during the interrupt and place it in a charset, then parse it and execute it externally.

Trying it, I notice that it never enters the if inside the while and it doesn't 'fill' the 'uCommand' charset completely but only a few characters compared to the ones sent.

I hope my question is not off topic.


Solution

  • You should declare uCommand (and any other shared objects) volatile.

    The while-loop is waiting for uCommand[0] != 0 to become true, but the main thread does not modify uCommand[0] so the compiler is free to "optimise" away the entire block of code if it "knows" it can never be true.

    Similarly chars_rxed may get optimised away because you write but never read it. Declaring it volatile will also prevent that.

    The optimisaton of apparently redundant accesses usually only occurs when -O1 or higher optimisation level is set. Though you should in any event use volatile in such circumstances regardless.