I need a UARTE driver that does a few things differently to the provided UARTE driver and hence I am writing my own based on nrfx_uarte.c. At the moment I am testing the code which initialises and deinitialises my driver: no data transmission or reception has actually occurred, just a call of the init and deinit functions of my driver code.
The pattern in nrfx_uarte_uninit() is to disable interrupts, i.e.:
nrf_uarte_int_disable(pReg, NRF_UARTE_INT_ENDRX_MASK | NRF_UARTE_INT_ENDTX_MASK | NRF_UARTE_INT_ERROR_MASK | NRF_UARTE_INT_RXTO_MASK | NRF_UARTE_INT_TXSTOPPED_MASK); NRFX_IRQ_DISABLE(nrfx_get_irq_number((void *) (pReg)));
...and then do the following:
// Make sure all transfers are finished before UARTE is // disabled to achieve the lowest power consumption nrf_uarte_shorts_disable(pReg, NRF_UARTE_SHORT_ENDRX_STARTRX); nrf_uarte_task_trigger(pReg, NRF_UARTE_TASK_STOPRX); nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_TXSTOPPED); nrf_uarte_task_trigger(pReg, NRF_UARTE_TASK_STOPTX); while (!nrf_uarte_event_check(pReg, NRF_UARTE_EVENT_TXSTOPPED)) {}
In my test I find that my code hangs at the line:
while (!nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_TXSTOPPED))
{}
What might I be doing wrong? I don't think it can be to do with my interrupt handler as interrupts have just been disabled but here is that code anyway (noting that my Tx is always blocking, hence there is no Tx data event forwarding).
// The interrupt handler: only handles Rx data as Tx is blocking. static void irqHandler(NRF_UARTE_Type *pReg, CellularPortUartBuffer_t *pRxBuffer) { size_t length; bool wasRxEvent = false; if (nrf_uarte_event_check(pReg, NRF_UARTE_EVENT_ERROR)) { // Clear any errors nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_ERROR); nrf_uarte_errorsrc_get_and_clear(pReg); wasRxEvent = true; } else if (nrf_uarte_event_check(pReg, NRF_UARTE_EVENT_ENDRX)) { // Clear Rx event and grab bytes used nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_ENDRX); pRxBuffer->bytesUsed += nrf_uarte_rx_amount_get(pReg); wasRxEvent = true; } if (nrf_uarte_event_check(pReg, NRF_UARTE_EVENT_RXTO)) { // Clear time-out event nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_RXTO); } if (nrf_uarte_event_check(pReg, NRF_UARTE_EVENT_ENDTX)) { nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_ENDTX); // Transmitter has to be stopped by triggering STOPTX task to achieve // the lowest possible level of the UARTE power consumption. nrf_uarte_task_trigger(pReg, NRF_UARTE_TASK_STOPTX); } if (nrf_uarte_event_check(pReg, NRF_UARTE_EVENT_TXSTOPPED)) { nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_TXSTOPPED); } if (wasRxEvent) { // Start the next receive length = CELLULAR_PORT_UART_RX_BUFFER_SIZE - pRxBuffer->bytesUsed; if (length > DMA_MAX_LEN) { length = DMA_MAX_LEN; } nrf_uarte_rx_buffer_set(pReg, pRxBuffer->pBufferStart + pRxBuffer->bytesUsed, length); nrf_uarte_task_trigger(pReg, NRF_UARTE_TASK_STARTRX); } }
And, to complete the picture, here's the relevant part of the initialisation function also:
// Set baud rate nrf_uarte_baudrate_set(pReg, baudRateNrf); // Set Tx/Rx pins nrf_gpio_pin_set(pinTx); nrf_gpio_cfg_output(pinTx); nrf_gpio_cfg_input(pinRx, NRF_GPIO_PIN_NOPULL); nrf_uarte_txrx_pins_set(pReg, pinTx, pinRx); // Set flow control if (pinCts >= 0) { pinCtsNrf = pinCts; nrf_gpio_cfg_input(pinCtsNrf, NRF_GPIO_PIN_NOPULL); hwfc = NRF_UARTE_HWFC_ENABLED; } if (pinRts >= 0) { pinRtsNrf = pinRts; nrf_gpio_pin_set(pinRtsNrf); nrf_gpio_cfg_output(pinRtsNrf); hwfc = NRF_UARTE_HWFC_ENABLED; } if (hwfc == NRF_UARTE_HWFC_ENABLED) { nrf_uarte_hwfc_pins_set(pReg, pinRtsNrf, pinCtsNrf); } nrf_uarte_configure(pReg, NRF_UARTE_PARITY_EXCLUDED, hwfc); // Set interrupts and buffer and let it go nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_ENDRX); nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_ENDTX); nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_ERROR); nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_RXTO); nrf_uarte_event_clear(pReg, NRF_UARTE_EVENT_TXSTOPPED); nrf_uarte_rx_buffer_set(pReg, gUartData[uart].rxBuffer.pBufferStart, DMA_MAX_LEN); nrf_uarte_task_trigger(pReg, NRF_UARTE_TASK_STARTRX); nrf_uarte_int_enable(pReg, NRF_UARTE_INT_ENDRX_MASK | NRF_UARTE_INT_ENDTX_MASK | NRF_UARTE_INT_ERROR_MASK | NRF_UARTE_INT_RXTO_MASK | NRF_UARTE_INT_TXSTOPPED_MASK); NRFX_IRQ_PRIORITY_SET(getIrqNumber((void *) pReg), NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY); NRFX_IRQ_ENABLE(getIrqNumber((void *) (pReg)));
EDIT: I must be doing something really basic wrong so, in order to make this really simple for you to look at, find below a ZIP file containing a stand-alone build, just one source file, showing what I'm doing. In this build I initialise the UARTE, attempt to transmit a few bytes of data through it and then deinitialise it. My code gets stuck during my attempt to transmit the bytes, while waiting for the event NRF_UARTE_EVENT_ENDTX.
Rob