static void interrupts_enable(nrfx_uarte_t const * p_instance, uint8_t interrupt_priority) { nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_ENDRX); nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_ENDTX); nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_ERROR); nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_RXTO); nrf_uarte_int_enable(p_instance->p_reg, NRF_UARTE_INT_ENDRX_MASK | NRF_UARTE_INT_ENDTX_MASK | NRF_UARTE_INT_ERROR_MASK | NRF_UARTE_INT_RXTO_MASK); NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number((void *)p_instance->p_reg), interrupt_priority); NRFX_IRQ_ENABLE(nrfx_get_irq_number((void *)p_instance->p_reg)); }
/** Interrupt driven FIFO fill function */ static int uarte_nrfx_fifo_fill(struct device *dev, const u8_t *tx_data, int len) { NRF_UARTE_Type *uarte = get_uarte_instance(dev); struct uarte_nrfx_data *data = get_dev_data(dev); const struct uarte_nrfx_config *config = get_dev_config(dev); if (len > config->tx_buff_size) { len = config->tx_buff_size; } nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_ENDTX); /* Copy data to RAM buffer for EasyDMA transfer */ for (int i = 0; i < len; i++) { data->tx_buffer[i] = tx_data[i]; } nrf_uarte_tx_buffer_set(uarte, data->tx_buffer, len); nrf_uarte_task_trigger(uarte, NRF_UARTE_TASK_STARTTX); return len; }
void nrfx_uarte_tx_abort(nrfx_uarte_t const * p_instance) { uarte_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_TXSTOPPED); nrf_uarte_task_trigger(p_instance->p_reg, NRF_UARTE_TASK_STOPTX); if (p_cb->handler == NULL) { while (!nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_TXSTOPPED)) {} } NRFX_LOG_INFO("TX transaction aborted."); }
/** * @brief Poll the device for input. * * @param dev UARTE device struct * @param c Pointer to character * * @return 0 if a character arrived, -1 if the input buffer is empty. */ static int uarte_nrfx_poll_in(struct device *dev, unsigned char *c) { const struct uarte_nrfx_data *data = get_dev_data(dev); NRF_UARTE_Type *uarte = get_uarte_instance(dev); if (!nrf_uarte_event_check(uarte, NRF_UARTE_EVENT_ENDRX)) { return -1; } *c = data->rx_data; /* clear the interrupt */ nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_ENDRX); nrf_uarte_task_trigger(uarte, NRF_UARTE_TASK_STARTRX); return 0; }
/** Interrupt driven FIFO read function */ static int uarte_nrfx_fifo_read(struct device *dev, u8_t *rx_data, const int size) { int num_rx = 0; NRF_UARTE_Type *uarte = get_uarte_instance(dev); const struct uarte_nrfx_data *data = get_dev_data(dev); if (nrf_uarte_event_check(uarte, NRF_UARTE_EVENT_ENDRX)) { /* Clear the interrupt */ nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_ENDRX); /* Receive a character */ rx_data[num_rx++] = (u8_t)data->rx_data; nrf_uarte_task_trigger(uarte, NRF_UARTE_TASK_STARTRX); } return num_rx; }
/** * @brief Output a character in polled mode. * * @param dev UARTE device struct * @param c Character to send * * @return Sent character */ static unsigned char uarte_nrfx_poll_out(struct device *dev, unsigned char c) { NRF_UARTE_Type *uarte = get_uarte_instance(dev); /* The UART API dictates that poll_out should wait for the transmitter * to be empty before sending a character. However, the only way of * telling if the transmitter became empty in the UARTE peripheral is * to check if the ENDTX event for the previous transmission was set. * Since this event is not cleared automatically when a new transmission * is started, it must be cleared in software, and this leads to a rare * yet possible race condition if the thread is preempted right after * clearing the event but before sending a new character. The preempting * thread, if it also called poll_out, would then wait for the ENDTX * event that had no chance to become set. * Because of this race condition, the while loop has to be placed * after the write to TXD, and we can't wait for an empty transmitter * before writing. This is a trade-off between losing a byte once in a * blue moon against hanging up the whole thread permanently */ /* reset transmitter ready state */ nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_ENDTX); /* send a character */ nrf_uarte_tx_buffer_set(uarte, &c, 1); nrf_uarte_task_trigger(uarte, NRF_UARTE_TASK_STARTTX); /* Wait for transmitter to be ready */ while (!nrf_uarte_event_check(uarte, NRF_UARTE_EVENT_ENDTX)) { } /* If there is nothing to send, driver will save an energy * when TX is stopped. */ nrf_uarte_task_trigger(uarte, NRF_UARTE_TASK_STOPTX); return c; }
static int uarte_instance_init(struct device *dev, const struct uarte_init_config *config, u8_t interrupts_active) { int err; NRF_UARTE_Type *uarte = get_uarte_instance(dev); struct uarte_nrfx_data *data = get_dev_data(dev); nrf_gpio_pin_write(config->pseltxd, 1); nrf_gpio_cfg_output(config->pseltxd); nrf_gpio_cfg_input(config->pselrxd, NRF_GPIO_PIN_NOPULL); nrf_uarte_txrx_pins_set(uarte, config->pseltxd, config->pselrxd); if (config->hwfc == NRF_UARTE_HWFC_ENABLED) { nrf_gpio_pin_write(config->pselrts, 1); nrf_gpio_cfg_output(config->pselrts); nrf_gpio_cfg_input(config->pselcts, NRF_GPIO_PIN_NOPULL); nrf_uarte_hwfc_pins_set(uarte, config->pselrts, config->pselcts); } /* Configure flow control and parity checking */ nrf_uarte_configure(uarte, config->parity, config->hwfc); err = baudrate_set(dev, config->baudrate); if (err) { return err; } /* Enable receiver and transmitter */ nrf_uarte_enable(uarte); nrf_uarte_event_clear(uarte, NRF_UARTE_EVENT_ENDRX); nrf_uarte_rx_buffer_set(uarte, &data->rx_data, 1); nrf_uarte_task_trigger(uarte, NRF_UARTE_TASK_STARTRX); #if UARTE_INTERRUPT_DRIVEN if (interrupts_active) { /* Set ENDTX event by requesting fake (zero-length) transfer. * Pointer to RAM variable (data->tx_buffer) is set because * otherwise such operation may result in HardFault or RAM * corruption. */ nrf_uarte_tx_buffer_set(uarte, data->tx_buffer, 0); nrf_uarte_task_trigger(uarte, NRF_UARTE_TASK_STARTTX); /* switch off transmitter to save an energy */ nrf_uarte_task_trigger(uarte, NRF_UARTE_TASK_STOPTX); } #endif /* UARTE_INTERRUPT_DRIVEN */ return 0; }
static void uarte_irq_handler(NRF_UARTE_Type * p_uarte, uarte_control_block_t * p_cb) { if (nrf_uarte_event_check(p_uarte, NRF_UARTE_EVENT_ERROR)) { nrfx_uarte_event_t event; nrf_uarte_event_clear(p_uarte, NRF_UARTE_EVENT_ERROR); event.type = NRFX_UARTE_EVT_ERROR; event.data.error.error_mask = nrf_uarte_errorsrc_get_and_clear(p_uarte); event.data.error.rxtx.bytes = nrf_uarte_rx_amount_get(p_uarte); event.data.error.rxtx.p_data = p_cb->p_rx_buffer; // Abort transfer. p_cb->rx_buffer_length = 0; p_cb->rx_secondary_buffer_length = 0; p_cb->handler(&event, p_cb->p_context); } else if (nrf_uarte_event_check(p_uarte, NRF_UARTE_EVENT_ENDRX)) { nrf_uarte_event_clear(p_uarte, NRF_UARTE_EVENT_ENDRX); size_t amount = nrf_uarte_rx_amount_get(p_uarte); // If the transfer was stopped before completion, amount of transfered bytes // will not be equal to the buffer length. Interrupted transfer is ignored. if (amount == p_cb->rx_buffer_length) { if (p_cb->rx_secondary_buffer_length) { uint8_t * p_data = p_cb->p_rx_buffer; nrf_uarte_shorts_disable(p_uarte, NRF_UARTE_SHORT_ENDRX_STARTRX); p_cb->rx_buffer_length = p_cb->rx_secondary_buffer_length; p_cb->p_rx_buffer = p_cb->p_rx_secondary_buffer; p_cb->rx_secondary_buffer_length = 0; rx_done_event(p_cb, amount, p_data); } else { p_cb->rx_buffer_length = 0; rx_done_event(p_cb, amount, p_cb->p_rx_buffer); } } } if (nrf_uarte_event_check(p_uarte, NRF_UARTE_EVENT_RXTO)) { nrf_uarte_event_clear(p_uarte, NRF_UARTE_EVENT_RXTO); if (p_cb->rx_buffer_length) { p_cb->rx_buffer_length = 0; rx_done_event(p_cb, nrf_uarte_rx_amount_get(p_uarte), p_cb->p_rx_buffer); } } if (nrf_uarte_event_check(p_uarte, NRF_UARTE_EVENT_ENDTX)) { nrf_uarte_event_clear(p_uarte, NRF_UARTE_EVENT_ENDTX); if (p_cb->tx_buffer_length) { tx_done_event(p_cb, nrf_uarte_tx_amount_get(p_uarte)); } } }
uint32_t nrfx_uarte_errorsrc_get(nrfx_uarte_t const * p_instance) { nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_ERROR); return nrf_uarte_errorsrc_get_and_clear(p_instance->p_reg); }
nrfx_err_t nrfx_uarte_rx(nrfx_uarte_t const * p_instance, uint8_t * p_data, size_t length) { uarte_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state == NRFX_DRV_STATE_INITIALIZED); NRFX_ASSERT(p_data); NRFX_ASSERT(length > 0); NRFX_ASSERT(UARTE_LENGTH_VALIDATE(p_instance->drv_inst_idx, length)); nrfx_err_t err_code; // EasyDMA requires that transfer buffers are placed in DataRAM, // signal error if the are not. if (!nrfx_is_in_ram(p_data)) { err_code = NRFX_ERROR_INVALID_ADDR; NRFX_LOG_WARNING("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); return err_code; } bool second_buffer = false; if (p_cb->handler) { nrf_uarte_int_disable(p_instance->p_reg, NRF_UARTE_INT_ERROR_MASK | NRF_UARTE_INT_ENDRX_MASK); } if (p_cb->rx_buffer_length != 0) { if (p_cb->rx_secondary_buffer_length != 0) { if (p_cb->handler) { nrf_uarte_int_enable(p_instance->p_reg, NRF_UARTE_INT_ERROR_MASK | NRF_UARTE_INT_ENDRX_MASK); } err_code = NRFX_ERROR_BUSY; NRFX_LOG_WARNING("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); return err_code; } second_buffer = true; } if (!second_buffer) { p_cb->rx_buffer_length = length; p_cb->p_rx_buffer = p_data; p_cb->rx_secondary_buffer_length = 0; } else { p_cb->p_rx_secondary_buffer = p_data; p_cb->rx_secondary_buffer_length = length; } NRFX_LOG_INFO("Transfer rx_len: %d.", length); err_code = NRFX_SUCCESS; nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_ENDRX); nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_RXTO); nrf_uarte_rx_buffer_set(p_instance->p_reg, p_data, length); if (!second_buffer) { nrf_uarte_task_trigger(p_instance->p_reg, NRF_UARTE_TASK_STARTRX); } else { nrf_uarte_shorts_enable(p_instance->p_reg, NRF_UARTE_SHORT_ENDRX_STARTRX); } if (m_cb[p_instance->drv_inst_idx].handler == NULL) { bool endrx; bool rxto; bool error; do { endrx = nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_ENDRX); rxto = nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_RXTO); error = nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_ERROR); } while ((!endrx) && (!rxto) && (!error)); m_cb[p_instance->drv_inst_idx].rx_buffer_length = 0; if (error) { err_code = NRFX_ERROR_INTERNAL; } if (rxto) { err_code = NRFX_ERROR_FORBIDDEN; } } else { nrf_uarte_int_enable(p_instance->p_reg, NRF_UARTE_INT_ERROR_MASK | NRF_UARTE_INT_ENDRX_MASK); } NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); return err_code; }
nrfx_err_t nrfx_uarte_tx(nrfx_uarte_t const * p_instance, uint8_t const * p_data, size_t length) { uarte_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx]; NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED); NRFX_ASSERT(p_data); NRFX_ASSERT(length > 0); NRFX_ASSERT(UARTE_LENGTH_VALIDATE(p_instance->drv_inst_idx, length)); nrfx_err_t err_code; // EasyDMA requires that transfer buffers are placed in DataRAM, // signal error if the are not. if (!nrfx_is_in_ram(p_data)) { err_code = NRFX_ERROR_INVALID_ADDR; NRFX_LOG_WARNING("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); return err_code; } if (nrfx_uarte_tx_in_progress(p_instance)) { err_code = NRFX_ERROR_BUSY; NRFX_LOG_WARNING("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); return err_code; } p_cb->tx_buffer_length = length; p_cb->p_tx_buffer = p_data; NRFX_LOG_INFO("Transfer tx_len: %d.", p_cb->tx_buffer_length); NRFX_LOG_DEBUG("Tx data:"); NRFX_LOG_HEXDUMP_DEBUG(p_cb->p_tx_buffer, p_cb->tx_buffer_length * sizeof(p_cb->p_tx_buffer[0])); err_code = NRFX_SUCCESS; nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_ENDTX); nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_TXSTOPPED); nrf_uarte_tx_buffer_set(p_instance->p_reg, p_cb->p_tx_buffer, p_cb->tx_buffer_length); nrf_uarte_task_trigger(p_instance->p_reg, NRF_UARTE_TASK_STARTTX); if (p_cb->handler == NULL) { bool endtx; bool txstopped; do { endtx = nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_ENDTX); txstopped = nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_TXSTOPPED); } while ((!endtx) && (!txstopped)); if (txstopped) { err_code = NRFX_ERROR_FORBIDDEN; } p_cb->tx_buffer_length = 0; } NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code)); return err_code; }