RPI PICO UART TX RX tasks

Hey, Im trying to setup some sample code to test the following. Separate tasks for UART TX and RX. Circular bufffer contains data to TX over UART (byte by byte). Separate task to RX data (again byte by byte).
To test, the UART TX/RX pins on the RPI-PICO board are connected.
code:

/*
 * UART Transport Layer Task FreeRTOS
 */

#include "uarttransportlayer.h"
#include <string.h>
volatile TaskHandle_t xTaskToNotify_UART = NULL;

uint8_t rxChar = 'b';
CIRCBUF_DEF(UartMsg, uart_tx_buff, 10);

CIRCBUF_DEF_FUNCS(UartMsg, uart_tx_buff, 10);


void initUART() {
	// Set up our UART
	uart_init(UART_ID, BAUD_RATE);
	// Set the TX and RX pins by using the function select on the GPIO
	// Set datasheet for more information on function select
	gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
	gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);
	// Set data format
	uart_set_format(UART_ID, DATA_BITS, STOP_BITS, PARITY);        
	// Turn off FIFO's - we want to do this character by character
	uart_set_fifo_enabled(UART_ID, false);
	// Set up a RX interrupt
	// We need to set up the handler first
	// Select correct interrupt for the UART we are using
	int UART_IRQ = UART_ID == uart0 ? UART0_IRQ : UART1_IRQ;
	// And set up and enable the interrupt handlers
	irq_set_exclusive_handler(UART_IRQ, UART_Isr);
	irq_set_enabled(UART_IRQ, true);
}

void uart_task(void *pvParameters) {

    	gpio_init(6);
    	gpio_set_dir(6, 1);
    	gpio_put(6, 0);
	/* To avoid compiler warnings */
	(UartMsg*) pvParameters;
	uint32_t ulNotificationValue;
	xTaskToNotify_UART = NULL;
	int counter = 0;
	UartMsg tmp;
	memset(&tmp, 0, sizeof(UartMsg));
        CIRCBUF_POP(uart_tx_buff, &tmp);
		if (uart_is_writable(UART_ID) ) {
			uart_putc(UART_ID, *((char*)(&tmp+counter)));
		       counter++;	// echo incoming char
			if (counter == sizeof(UartMsg)-1){
		      		counter =0;
	              		memset(&tmp, 0, sizeof(UartMsg));
		      		CIRCBUF_POP(uart_tx_buff, &tmp);
			}
					// 
		}

	// TODO semaphore

	while (true) {
		/* Start the receiving from UART. */
		UART_receive();
		//This write is for testing - in real word other HW would be doing the writes...

		/* Wait to be notified that the receive is complete.  Note
		   the first parameter is pdTRUE, which has the effect of clearing
		   the task's notification value back to 0, making the notification
		   value act like a binary (rather than a counting) semaphore.  */
		ulNotificationValue = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);

		if (ulNotificationValue == 1) {
			/* Handle received data */
			if (uart_is_readable(UART_ID)) {
				rxChar = uart_getc(UART_ID);
			}
			//if (rxChar == 'h') {
				gpio_xor_mask(1u << 6); // toggle led
				gpio_xor_mask(1u << PICO_DEFAULT_LED_PIN); // toggle led
			//}
		}
	}
}
void uart_tx_task(void *pvParameters) {

	/* To avoid compiler warnings */
	(UartMsg*) pvParameters;
	UartMsg tmp;
	memset(&tmp, 0, sizeof(UartMsg));
        CIRCBUF_POP(uart_tx_buff, &tmp);
	int counter = 0;
	//int size = sizeof(uart_msg);

	// TODO semaphore

	while (true) {
		vTaskDelay(500);
		if (uart_is_writable(UART_ID) ) {
			uart_putc(UART_ID, *((char*)(&tmp+counter)));
		       counter++;	// echo incoming char
			if (counter == sizeof(UartMsg)-1){
		      		counter =0;
	              		memset(&tmp, 0, sizeof(UartMsg));
		      		CIRCBUF_POP(uart_tx_buff, &tmp);
			}
					// 
		}
	}
}
// UART activate a receive with interrupt. Wait for ever for UART_BUFFER_SIZE bytes
void UART_receive() {
	/* At this point xTaskToNotify should be NULL as no receive
	   is in progress.  A mutex can be used to guard access to the
	   peripheral if necessary. */
	configASSERT(xTaskToNotify_UART == NULL);

	/* Store the handle of the calling task. */
	xTaskToNotify_UART = xTaskGetCurrentTaskHandle();
	// Now enable the UART to send interrupts - RX only
	uart_set_irq_enables(UART_ID, true, false);
}
void UART_Isr() {
	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
	// Now disable the UART to send interrupts
	uart_set_irq_enables(UART_ID, false, false);

	if (xTaskToNotify_UART != NULL) {

		/* Notify the task that the receive is complete. */
		vTaskNotifyGiveFromISR(xTaskToNotify_UART, &xHigherPriorityTaskWoken);
		/* There are no receive in progress, so no tasks to notify. */
		xTaskToNotify_UART = NULL;

		/* If xHigherPriorityTaskWoken is now set to pdTRUE then a
		   context switch should be performed to ensure the interrupt
		   returns directly to the highest priority task.  The macro used
		   for this purpose is dependent on the port in use and may be
		   called portEND_SWITCHING_ISR(). */
		portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
	}
}```
Please help me understand how these tasks get locked up.. and what the best way would be to setup the example so that tx/rx happens infinitely and the test LED blinks. thanks!

do not use multiple tasks to acces the uart. Query the forum for that issue, we have discussed it way too many times already, the last time just two days ago. You will also find suggestions for proper synchronization if you feel you must use multiple tasks.

even with just one task, I cant get my test led blinking reliably:

void uart_task(void *pvParameters) {

        gpio_init(6);
        gpio_set_dir(6, 1);
        gpio_put(6, 0);
        /* To avoid compiler warnings */
        (UartMsg*) pvParameters;
        uint32_t ulNotificationValue;
        xTaskToNotify_UART = NULL;

        // TODO semaphore
        UartMsg tmp;

        memset(&tmp, 0, sizeof(UartMsg));
        CIRCBUF_POP(uart_tx_buff, &tmp);
        int counter = 0;
        while (true) {
                if (uart_is_writable(UART_ID) ) {
                        uart_putc(UART_ID, *((char*)(&tmp.data+counter)));
                        counter++;      // echo incoming char
                }
                /* Start the receiving from UART. */
                UART_receive();
                //This write is for testing - in real word other HW would be doing the writes...

                /* Wait to be notified that the receive is complete.  Note
                   the first parameter is pdTRUE, which has the effect of clearing
                   the task's notification value back to 0, making the notification
                   value act like a binary (rather than a counting) semaphore.  */
                ulNotificationValue = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);

                if (ulNotificationValue == 1) {
                        /* Handle received data */
                        if (uart_is_readable(UART_ID)) {
                                rxChar = uart_getc(UART_ID);
                        }
                        if (rxChar == 'w') {
                                gpio_xor_mask(1u << 6); // toggle led
                                gpio_xor_mask(1u << PICO_DEFAULT_LED_PIN); // toggle led
                        }
                }
                if (counter == tmp.len){
                        counter =0;
                        memset(&tmp, 0, sizeof(UartMsg));
                        CIRCBUF_POP(uart_tx_buff, &tmp);
                }
//      CIRCBUF_PUSH(uart_tx_buff, (void *)&tmp);
        }
}
vo```

well, if you don’t specify what “reliably” means (does anything crash or fault, or do you simply experience unwanted timing behavior) nor publish the code of the numerous funtions you call, how do you expect a usable answer?

I can see a whole bunch of potential problems in your code, but I do not see a point in pursuing them if I don’t know what the functions you call are doing.

There’s a hyperlink in the previous post to the entire repo. By reliably what I mean is that sometimes after a power cycle I see the test LED blink, sometimes o don’t. For this test I’m trying to do is throw a bunch of characters in a circular buffer: Tx the characters, and on reception of a particular char toggle the test LED. Here is the link to the repo again. https://github.com/sotaoverride/pico-freertos-sample/commit/e64a6a3ac2bcb45982fda8667c3d4ebd0699acc6 Thanks

oh, one further clarification: I’m testing this out using just one RPI PICO board (have the TX pin connected to RX…)

I’d suggest to first make UART Tx and Rx separately:

  1. Do Tx on the device and use a UART-2-USB to receive the data on PC using a serial program.
  2. Next, do Rx on the device and transmit data from a serial program on PC.

Once these 2 work in isolation, connect the Tx and Rx pins and see if it works then.

Thanks Gaurav. I think I have the code setup to do the little test I had in mind (toggle the led when the uart task rx/tx a byte) https://github.com/sotaoverride/pico-freertos-sample/commit/39793e9a96d1c760d2c0fdf900538c52caa5887a Thanks for the pointers!