I have an application where I need to periodically write a few KB of data from my nRF to a host computer. Since TXD.MAXCNT tops out at 255 bytes, I'm trying to set up all the writes to keep going until the buffer has been written out. I followed something along the lines of what I saw in the test source code that Zephyr provides for UART async, but I run into the issue where only the first 255 bytes are sent and nothing else. On investigation, I've found that the uart_tx() call is returning BUSY even though the TX_DONE event has already been issued out, and this is preventing me from writing out any more data.
I'm now stuck and am unsure how to get this piece of my application running. Is there something I'm doing wrong?
nRF52832
Zephyr RTOS
Utilizing UARTE, asynchronous mode
Below is my code - not the exact thing, but pretty much the same.
// custom structs and callbacks I use ----------------------------------------- typedef void (*pFnRxHandler)(uart_event* pEvt); typedef struct UartDevice { // TX buffer related vars uint8_t* pTxBuf; uint16_t txBytesWritten; uint16_t txBytesLeft; bool txReady; // RX buffer related vars uint8_t* pRxBuf0; uint8_t* pRxBuf1; uint8_t* pNextRxBuf; uint16_t rxBufSize; pFnRxHandler pvCallback; const struct device* ptUart; } UartDevice; // ---------------------------------------------------------------------------- const uint16_t UART_TX_BYTES_MAX = 255; const uint32_t UART_TX_TIMEOUT_MS = 100; static UartDevice uartDev; // ---------------------------------------------------------------------------- // This function return "EBUSY" after only getting the first 255 bytes out from the nRF module int32_t SendBlock(uint8_t* pBlock, uint16_t nBytes) { int32_t retVal = 0; uint16_t bytesToWrite = 0; uartDev.pTxBuf = pBlock; uartDev.txBytesWritten = 0; uartDev.txBytesLeft = nBytes; while ( uartDev.txBytesLeft ) { // Which is bigger? 255 or remaining data to write bytesToWrite = (uartDev.txBytesLeft > UART_TX_BYTES_MAX) ? (UART_TX_BYTES_MAX) : uartDev.txBytesLeft; // Blocking while loop for test purposes while I was debugging while (!uartDev.txReady) { } retVal = uart_tx(uartDev.ptUart, uartDev.pTxBuf[txBytesWritten], bytesToWrite, UART_TX_TIMEOUT_MS ); if (retVal != 0) { break; } } return retVal; } // SendBlock // Callback passed to the uart init call static void UartCallback(const struct device *unused, struct uart_event *evt, void *userData) { UartDevice* ptDev = (UartDevice*)userData; switch (evt->type) { case UART_RX_RDY: // Shove received bytes into ringbuf ptDev->pvCallback(evt); break; case UART_TX_DONE: ptDev->txBufBytesWritten += evt->data.tx.len; ptDev->txBytesLeft -= evt->data.tx.len; ptDev->txReady = true; break; case UART_TX_ABORTED: case UART_RX_BUF_REQUEST: uart_rx_buf_rsp(ptDev->ptUart, ptDev->pNextRxBuf, ptDev->rxBufSize); break; case UART_RX_BUF_RELEASED: ptDev->pNextRxBuf = evt->data.rx_buf.buf; break; case UART_RX_DISABLED: case UART_RX_STOPPED: default: break; } return; } // UartCallback()
Additionally, I've got the following in my project config file (prj.conf)
CONFIG_SERIAL=y CONFIG_UART_ASYNC_API=y # This stuff is necessary to get UART-Async properly functioning # This is what happens when this config isn't here: https://devzone.nordicsemi.com/f/nordic-q-a/72651/nrf9160-uart-loosing-data-when-rxdata-is-split-into-2-buffers-async-api CONFIG_UART_0_ASYNC=y CONFIG_UART_0_NRF_HW_ASYNC=y CONFIG_UART_0_NRF_HW_ASYNC_TIMER=1 CONFIG_UART_INTERRUPT_DRIVEN=n CONFIG_NRFX_TIMER=y CONFIG_NRFX_TIMER1=y