Zephyr/UARTE uart_tx reports BUSY after receiving TX_DONE

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

Parents Reply Children
No Data
Related