How to use UART_ASYNC function in UART_ISR nRF9160 based Asset_tracker_v2

I adding custom code to asset_tracker_v2. Two UARTs are required in my project. The firmware to be added to nRF9160 is already running very well in NRF5340 based UART communication. The UART communication in nRF5340 has been implemented by using both UARTs in UART_ASYNC mode and ring buffers have been used to store incoming data. Now, my problem is how to use same functionality / firmware in asset_tracker_v2 while it needs UART_INTERRUPT for AT commands. Where changes need to be done in configuration, initialization, transmit and receive sections of UART code ? The file with UART_SYNC_API based communication is attached. How to modify it for nRF9160 Asset_tracker_v2 ?

2541.serial_api.h 

//*******************serial port API **********
#include <sys/ring_buffer.h>
#include "serial_api.h"
//********************************** BMS ********************
uint8_t bms_double_buffer[2][CONFIG_BMS_UART_BUF_SIZE];
uint8_t *bms_buf_next = bms_double_buffer[1];

volatile int bms_bytes_claimed;

K_SEM_DEFINE(bms_tx_done, 1, 1);
K_SEM_DEFINE(bms_rx_disabled, 0, 1);

static const struct device *bms_uart;
bool bms_transmit_done ;

struct bms_msg_queue_item bms_incoming_message;

// UART TX fifo
RING_BUF_DECLARE(bms_tx_fifo, CONFIG_BMS_UART_TX_BUF_SIZE);

// UART RX message queue
K_MSGQ_DEFINE(bms_rx_msgq, sizeof(struct bms_msg_queue_item), CONFIG_BMS_UART_RX_MSG_QUEUE_SIZE, 2);
//******
unsigned int bms_tx_get_from_queue(void)
{
	uint8_t *data_ptr;
	// Try to claim any available bytes in the FIFO
	bms_bytes_claimed = ring_buf_get_claim(&bms_tx_fifo, &data_ptr, CONFIG_BMS_UART_TX_BUF_SIZE);

	if(bms_bytes_claimed > 0) {
		// Start a UART transmission based on the number of available bytes
		uart_tx(bms_uart, data_ptr, bms_bytes_claimed, SYS_FOREVER_MS);
	}
	return bms_bytes_claimed;
}

void bms_uart_async_callback(const struct device *uart_dev, struct uart_event *evt, void *user_data)
{
	static struct bms_msg_queue_item bms_new_message;

	switch (evt->type) {
		case UART_TX_DONE:
			// Free up the written bytes in the TX FIFO
			ring_buf_get_finish(&bms_tx_fifo, bms_bytes_claimed);

			// If there is more data in the TX fifo, start the transmission
			if(bms_tx_get_from_queue() == 0) {
				// Or release the semaphore if the TX fifo is empty
				k_sem_give(&bms_tx_done);
                                bms_transmit_done = true;
			}
			break;
		
		case UART_RX_RDY:
			memcpy(bms_new_message.bytes, evt->data.rx.buf + evt->data.rx.offset, evt->data.rx.len);
			bms_new_message.length = evt->data.rx.len;
			if(k_msgq_put(&bms_rx_msgq, &bms_new_message, K_NO_WAIT) != 0){
				/*printk("Error: Uart1 RX message queue full!\n");*/
				
			}
			break;
		
		case UART_RX_BUF_REQUEST:
			uart_rx_buf_rsp(bms_uart, bms_buf_next, CONFIG_BMS_UART_BUF_SIZE);
			break;

		case UART_RX_BUF_RELEASED:
			bms_buf_next = evt->data.rx_buf.buf;
			break;

		case UART_RX_DISABLED:
			k_sem_give(&bms_rx_disabled);
			break;
		
		default:
			break;
	}
}

 void bms_uart_init(void)
{
        
	bms_uart = device_get_binding("UART_1");
	if (bms_uart == NULL) {
		printk("Failed to get UART1 binding\n");
		
		return;        
	}
	uart_callback_set(bms_uart, bms_uart_async_callback, NULL);
	uart_rx_enable(bms_uart, bms_double_buffer[0], CONFIG_BMS_UART_BUF_SIZE, BMS_UART_RX_TIMEOUT_MS);
}

// Function to send UART data, by writing it to a ring buffer (FIFO) in the application
// WARNING: This function is not thread safe! If you want to call this function from multiple threads a semaphore should be used
unsigned int bms_uart_send(const uint8_t * data_ptr, uint32_t data_len)
{
	while(1) {
		// Try to move the data into the TX ring buffer
		uint32_t written_to_buf = ring_buf_put(&bms_tx_fifo, data_ptr, data_len);
		data_len -= written_to_buf;
		
		// In case the UART TX is idle, start transmission
		if(k_sem_take(&bms_tx_done, K_NO_WAIT) == 0) {
			bms_tx_get_from_queue();
		}	
		
		// In case all the data was written, exit the loop
		if(data_len == 0) break;

		// In case some data is still to be written, sleep for some time and run the loop one more time
		k_msleep(10);
		data_ptr += written_to_buf;
	}

	return 0;
}

  • Hi,

    Which SDK version are you using?

    What errors do you get when you enable the async API?

    I tried adding CONFIG_UART_ASYNC_API to the asset_tracker_v2 prj.conf (in NCS v1.9.0), and it built without any errors. Though it might be because I didn't add any code that used the async API.

    Another option to changing the code might be to just remove the AT-commands-over-UART feature, unless that is something you need for you application?

    Best regards,

    Didrik

  • 1. Is AT commands over-uart required for testing asset_tracker_v2 on LTE ? If yes, then this feature can not be removed.

    2. Where SDK version is shown in currently open VS project / workspace ?

    3. you just guide me how to modify the serial_api.c file. What are corresponding events in Interrupt Driven function. For example: 

    DMA   Based                                             Interrupt Based

    UART_TX_DONE                                       ?
    UART_RX_RDY                                         ?
    UART_RX_BUF_REQUEST                      ?
    UART_RX_BUF_RELEASED                    ?
    UART_RX_DISABLED                               ?
Related