3

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 am currently testing the operation of the serial from the pi pico. To do this I have connected the pi pico with the raspberry in the following way:

connection diagram

Currently, I am using the following files:

1. main.c to receive and send
2. ring_queue.h where the code for the ring queue is located

main.c

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/uart.h"
#include "hardware/irq.h"
#include "ring_queue.h"

#define UART_ID uart0
#define BAUD_RATE 115200
#define DATA_BITS 8
#define STOP_BITS 1
#define PARITY    UART_PARITY_NONE
#define UART_TX_PIN 0
#define UART_RX_PIN 1
#define LED_PIN PICO_DEFAULT_LED_PIN


volatile int chars_rxed = 0;
volatile char uCommand[32];
volatile queue *rx_queue;
volatile queue *tx_queue;


void receive_rx(){
    while(uart_is_readable(UART_ID)){
      char ch = uart_getc(UART_ID);
      printf("Got a ch! %c\n", ch);
      if(ch != 10){
        uCommand[chars_rxed] = ch;
      }
      printf("Should have added it to uCommand: %s\n", uCommand);
      if(uCommand[chars_rxed] == '/'){
        printf("End of the command\n");
        queue_enqueue((queue*)rx_queue, (char*)uCommand);
        memset((char*)uCommand, 0, sizeof(uCommand));
        chars_rxed = 0;
        break;
      }
      if(ch != 10) chars_rxed++;
    }
}

void send_tx(){
  if(queue_empty((queue*)tx_queue) == 1){
   return;
 }
 else{
   printf("Trying to send something\n");
   char *foo = queue_dequeue((queue*)tx_queue);
   uart_write_blocking(UART_ID, (char*)foo, 32);
   //printf("%s\n", queue_dequeue((queue*)tx_queue));
 }
}

int main(){

  stdio_init_all();

  memset((char*)uCommand, 0, sizeof(uCommand));
  rx_queue = create_queue(32);
  tx_queue = create_queue(32);

  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, true);

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

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

    while (1){
        tight_loop_contents();
        if(queue_size((queue*)rx_queue) != 0){
          printf("Moving from rx to tx to print the received command\n");
          queue_enqueue((queue*)tx_queue, queue_dequeue((queue*)rx_queue));
        }
        send_tx();
      }
}

ring_queue.h

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


typedef struct {
    unsigned int tail;      // current tail
    unsigned int head;      // current head
    unsigned int size;      // current number of items
    unsigned int capacity;  // Capacity of queue
    char** data;                // Pointer to array of data
} queue;


queue *create_queue(unsigned int _capacity){
    printf("Malloc!\n");
    queue *myQueue = malloc(sizeof(queue));
    printf("Malloc done!\n");
    if (myQueue == NULL ){
        printf("Malloc failed!\n");
        return NULL;
    }
    else {
        printf("Malloc succeed!\n");
        myQueue->tail = -1;
        myQueue->head = 0;
        myQueue->size = 0;
        myQueue->capacity = _capacity;
        myQueue->data = malloc(_capacity * sizeof(char*));

        return myQueue;
    }
}


int queue_empty(queue *q) {
    if(q == NULL) return -1;
    else if(q->size == 0) return 1;
    else return 0;
}


int queue_full(queue *q) {
    if(q == NULL) return -1;
    else if(q->size == q->capacity) return 1;
    else return 0;
}


int queue_enqueue(queue *q, const char *item) {
    if (q == NULL) return -1;
    else if (queue_full(q) == 1) return 0;
    else {
      q->tail = (q->tail + 1) % q->capacity;
    q->data[q->tail] = strdup(item);
      q->size++;

      return 1;
    }
}

char *queue_dequeue(queue *q) {
    if(q == NULL) return NULL;
    else if(queue_empty(q) == 1) return '\0';
    else {
        char *item = q->data[q->head];
        q->head = (q->head + 1) % q->capacity;
        q->size--;

        return item;
    }
}


unsigned int queue_size(queue *q) {
    if (q == NULL) return - 1;
    else return q->size;
}


void free_queue(queue *q) {
  for(int i = 0; i < q->capacity; i++) free(q->data[i]);
  free(q->data);
    free(q);
}

I'm using the usb for debbugging and when I send a simple command (via the arduino IDE) like $MOVE / I can receive it correctly but not send it back as serial, instead with the usb I can ( the printf under the uart_write_blocking). When I try to send via uart I get random characters on the arduino serial prompt and the pico also seems to receive some of the ones it sent.

Jonas
  • 121,568
  • 97
  • 310
  • 388
lasb3tas
  • 75
  • 1
  • 9
  • Besides that we usually not use dynamic memory management on embedded systems, but this is the reason of several memory leaks and errors here. `strdup()` --> you never free after `dequeue()` here, besides freeing the whole queue implementation. dequeue returning '`\0'` instead of a `char*`. Sending 32 bytes instead of the length of the string taken from the queue, or is `uart_write_blocking()` checking for `'\0'`? – kesselhaus Aug 16 '21 at 21:26

1 Answers1

1

What are the random characters on the serial prompt? and what characters do you expect?

The third argument (length) of uart_write_blocking is hardcoded to 32, so this function will always try to send 32 bytes back to the raspberry pi -- that could cause some random characters to show up if the string the pico is trying to send is actually less than that. I'd try changing this code snippet to this and see if that stops the random characters.

printf("Trying to send something\n");
char *foo = queue_dequeue((queue*)tx_queue);
uart_write_blocking(UART_ID, (char*)foo, strlen(foo)); // only send as many bytes as are in the string
GandhiGandhi
  • 1,029
  • 6
  • 10