0

I have a Raspberry Pi Pico whose Tx and Rx pins are wired to the Rx and Tx pins of a Wemos D1 Mini development board. The Wemos and the Pico are powered via an external 5V power supply (common ground). The Wemos board connects to the Internet, reads a topic off of a MQTT broker (publish/subscribe protocol), reports its status to another MQTT topic, and prints that which it has read from the broker, to Serial, which addresses the Pico.

Printing the message to Serial sends data over the Tx pin of the Wemos, to the Rx pin of the Pico. My aim is to control the onboard LED of the Pico: When a string printed to Serial contains the substring “device=on” the LED is on; and the opposite when “device=off”. The Pico also echoes every message it receives back to the Wemos over UART, and the Wemos then publishes that on an MQTT topic.

My attempt in C is below. I have found that this code works when mounted on the Pico, but only if around 20 characters are first printed to UART via uart_puts, as "padding". If there are fewer characters than this, uart_getc does not seem to read the incoming characters (“device=on” for instance) completely.

But there are issues with reading regardless of whether "padding" is placed or not. Whatever the Pico prints, it seems to do so 4 times. Of those 4 times, in only one of them is the actual message that it received from the Wemos, and this message is only partially formed.

int main() {
stdio_init_all(); 

// setting up UART
uart_init(UART_ID, baud);
uart_set_format(UART_ID, data, stop, UART_PARITY_NONE);
gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);

// the LED
gpio_init(LED_PIN);
gpio_set_dir(LED_PIN, GPIO_OUT);   

uart_puts(UART_ID, "PICO INIT LINE 1\n");

while (1) {
    if (uart_is_readable(UART_ID)) {
        int i = 0;
        while (uart_is_readable(UART_ID)) {             
            char ch = uart_getc(UART_ID);
            if(ch!='\n' && ch!='\r') {
                tmp_msg[i++] = ch;
            } else {
                tmp_msg[i] = '\0'; 
                break;
            }
        }

        /* Even though 20 characters are put, around 4x more are received by Wemos */
        uart_puts(UART_ID, "xxxxxxxxxx");

        /* This is also duplicated when sent. */
        uart_puts(UART_ID, "\nPICO_ECHO: ");    
        uart_puts(UART_ID, tmp_msg);
    
        // check if msg fits on/off template
        if (strstr(tmp_msg, device_on) != NULL) {gpio_put(LED_PIN, 1);}
        if (strstr(tmp_msg, device_off) != NULL) {gpio_put(LED_PIN, 0);} 
    } 
}

}

Here I send “device=off” to MQTT. This is what is echoed by the Pico, then published to MQTT, when some number of characters is first fed to uart_puts as “padding”. What seems to be happening is that whatever gets passed to uart_puts is quadrupled, except for the message read via uart_getc, which gets formed only once.

xxxxxxxxxx PICO_ECHO: xxxxxxxxxx PICO_ECHO: xxxxxxxxxx PICO_ECHO: device=off xxxxxxxxxx PICO_ECHO:

And this is what happens when the buffer is omitted (I remove uart_puts(UART_ID, "xxxxxxxxxx") from the code above). In this case, there is still duplication, but the message that the Pico reads over UART seems to be badly formed. The message is "dvice=off" instead of "device=off". So it seems that the data read by uart_getc() also gets garbled somehow, when the "padding" is omitted.

PICO_ECHO: PICO_ECHO: PICO_ECHO: dvice=off PICO_ECHO: evice=off PICO_ECHO:

Sending other texts of different length has similar results. Why does this happen when the Pico is programmed in C, and how can it be prevented?

Note: I have done this in MicroPython and the reading/writing over UART behaves exactly as expected, no issues or duplications, and no need for "padding". Here is the Micropython code:

from machine import UART, Pin
from time import sleep

uart0 = UART(0, baudrate=115200, bits=8, parity=None, stop=1, tx=Pin(0), rx=Pin(1))
led = Pin(25, Pin.OUT)

while True:
    while uart0.any() > 0:
        try:
            msg = str(uart0.read(), 'utf-8')
            uart0.write('PICO_ECHO: ' + msg)
            if "device=off" in msg:
                led.value(0)
            if "device=on" in msg:
                led.value(1)
        except:
            pass
3
  • 2
    Your C code has a number of bugs. A big one is that if a partial string is received (assuming the while loop reads it faster than the serial gets it), then it can exit leaving the partial buffer not null terminated and then resets the buffer before the rest is read.
    – user10489
    Apr 26 at 11:27
  • So the partial string should be accumulated over several while loops if need be? How would I detect a partial string being received, in order to handle it? Thank you.
    – straits
    Apr 26 at 12:51
  • You should null terminate the string at the end of the while loop, and overwrite the null in the next collection pass. You detect a partial string by it not all being there. :) Typically, you'd look for a termination character....like a newline.
    – user10489
    Apr 27 at 2:07

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.