mike603
Posts: 7
Joined: Fri Jan 17, 2020 2:06 pm

Non Blocking (interrupt driven) UART functions

Tue Jun 22, 2021 2:57 am

Looking at the SDK documentation I could not find non-blocking interrupt driven routines.

Does calling uart_set_irq_enables() turn the blocking routines into interrupt driven?

Also, is there any SDK support for DMA driven UART Tx or Rx?

pidd
Posts: 2275
Joined: Fri May 29, 2020 8:29 pm
Location: Wirral, UK
Contact: Website

Re: Non Blocking (interrupt driven) UART functions

Tue Jun 22, 2021 12:52 pm

If the interrupt tells you that a character is ready then a you can call a blocking fetch routine to get that character, it will not be blocking because you know a character is ready.

Generally you still poll for character availability before calling a blocking fetch routine because there may be more than one character available and also it avoids blocking. ie you treat the interrupt as advisory rather than absolute.

I generally poll everything and don't use interrupts but if the data is high speed or the polling latency is too slow then it is sometimes a solution - but it may not always the fastest in extreme circumstances.

kilograham
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 712
Joined: Fri Apr 12, 2019 11:00 am
Location: austin tx

Re: Non Blocking (interrupt driven) UART functions

Tue Jun 22, 2021 1:00 pm

mike603 wrote:
Tue Jun 22, 2021 2:57 am
Looking at the SDK documentation I could not find non-blocking interrupt driven routines.

Does calling uart_set_irq_enables() turn the blocking routines into interrupt driven?

Also, is there any SDK support for DMA driven UART Tx or Rx?
There is no common asynchronous IO support in the SDK API currently

The SDK gives you all the building blocks to build your own , and yes you can DMA to/from UART.

uart_set_irq_enables just sets the hardware interrupt enables

You might want to check out https://datasheets.raspberrypi.org/pico ... -c-sdk.pdf section 2.3 on library structure. hardware_ libraries provide thin wrappers over the hardware. pico_ provide higher level stuff at a more "OS" level but bear in mind this is a small SDK on a small microcontroller.

matherp
Posts: 46
Joined: Tue May 02, 2017 10:54 am

Re: Non Blocking (interrupt driven) UART functions

Tue Jun 22, 2021 4:53 pm

I do this:

Code: Select all

[
unsigned char *com2Rx_buf;											// pointer to the buffer for received characters
volatile int com2Rx_head, com2Rx_tail;								// head and tail of the ring buffer for com2 Rx
unsigned char *com2Tx_buf;											// pointer to the buffer for transmitted characters
volatile int com2Tx_head, com2Tx_tail;								// head and tail of the ring buffer for com2 Tx

/***************************************************************************************************
Initialise the serial function including the interrupts.
****************************************************************************************************/
#define UART_ID  (uart ? uart1: uart0)
void setupuart(int uart, int s2,int parity, int b7, int baud){
	uart_init(UART_ID,baud);
    uart_set_hw_flow(UART_ID, false, false);
    uart_set_format(UART_ID, b7, s2, parity);
    uart_set_fifo_enabled(UART_ID, false);
    int UART_IRQ = (UART_ID == uart0 ? UART0_IRQ : UART1_IRQ);
    if(uart){
		irq_set_exclusive_handler(UART_IRQ, on_uart_irq1);
    	irq_set_enabled(UART_IRQ, true);
	} else {
		irq_set_exclusive_handler(UART_IRQ, on_uart_irq0);
    	irq_set_enabled(UART_IRQ, true);
	}
    uart_set_irq_enables(UART_ID, true, false);
}
/***************************************************************************************************
Add a character to the serial output buffer.
****************************************************************************************************/
unsigned char SerialPutchar(int comnbr, unsigned char c) {
        int empty=uart_is_writable(uart0);
		if(com1Tx_tail == ((com1Tx_head + 1) % TX_BUFFER_SIZE)); //wait if buffer full
		com1Tx_buf[com1Tx_head] = c;							// add the char
		com1Tx_head = (com1Tx_head + 1) % TX_BUFFER_SIZE;		   // advance the head of the queue
		if(empty){
	        	uart_set_irq_enables(uart0, true, true);
			irq_set_pending(UART0_IRQ);
		}
	}
	int SerialGetchar(int comnbr) {
	int c;
    	c = -1;                                                         // -1 is no data
	    uart_set_irq_enables(uart0, false, true);
		if(com1Rx_head != com1Rx_tail) {                            // if the queue has something in it
			c = com1Rx_buf[com1Rx_tail];                            // get the char
 			com1Rx_tail = (com1Rx_tail + 1) % com1_buf_size;        // and remove from the buffer
		}
		uart_set_irq_enables(uart0, true, true);
	}
void on_uart_irq0() {
    if(uart_is_readable(uart0)) {
		com1Rx_buf[com1Rx_head]  = uart_getc(uart0);   // store the byte in the ring buffer
		com1Rx_head = (com1Rx_head + 1) % com1_buf_size;     // advance the head of the queue
		if(com1Rx_head == com1Rx_tail) {                           // if the buffer has overflowed
			com1Rx_tail = (com1Rx_tail + 1) % com1_buf_size; // throw away the oldest char
		}
    }
    if(uart_is_writable(uart0)){
		if(com1Tx_head != com1Tx_tail) {
			uart_putc_raw(uart0,com1Tx_buf[com1Tx_tail]);
			com1Tx_tail = (com1Tx_tail + 1) % TX_BUFFER_SIZE;       // advance the tail of the queue
		} else {
			uart_set_irq_enables(uart0, true, false);
		}
    }
}
void on_uart_irq1() {
	    while (uart_is_readable(uart1)) {
		com2Rx_buf[com2Rx_head]  = uart_getc(uart1);   // store the byte in the ring buffer
		com2Rx_head = (com2Rx_head + 1) % com2_buf_size;     // advance the head of the queue
		if(com2Rx_head == com2Rx_tail) {                           // if the buffer has overflowed
			com2Rx_tail = (com2Rx_tail + 1) % com2_buf_size; // throw away the oldest char
		}
    }
    if(uart_is_writable(uart1)){
		if(com2Tx_head != com2Tx_tail) {
			uart_putc_raw(uart1,com2Tx_buf[com2Tx_tail]);
			com2Tx_tail = (com2Tx_tail + 1) % TX_BUFFER_SIZE;       // advance the tail of the queue
		} else {
			uart_set_irq_enables(uart1, true, false);
		}
    }

/code]

carlk3
Posts: 59
Joined: Wed Feb 17, 2021 8:46 pm

Re: Non Blocking (interrupt driven) UART functions

Sun Jul 25, 2021 2:52 am

matherp wrote:
Tue Jun 22, 2021 4:53 pm
I do this:

...
I like that! I would like to use something like that for the command line terminal user interface in my FreeRTOS-FAT-CLI-for-RPi-Pico project. This is a solution for a UART-connected terminal. However, I would like to maintain the ability to change the destination for stdin and stdout using CMake directives, with input/output directed to UART or USB CDC. Can something similar be done for USB CDC?

Looping waiting for a character works poorly in a multi-tasking OS, so my current solution is to move the looping to core1 and set up a fifo and interrupt for core0. (Currently, the OS is only running on core0.)

Return to “SDK”