初始版本
This commit is contained in:
679
components/libraries/libuarte/nrf_libuarte_async.c
Normal file
679
components/libraries/libuarte/nrf_libuarte_async.c
Normal file
@@ -0,0 +1,679 @@
|
||||
/**
|
||||
* Copyright (c) 2019 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
#include "sdk_config.h"
|
||||
#include "nrf_libuarte_async.h"
|
||||
#include "app_error.h"
|
||||
#include "nrf_balloc.h"
|
||||
#include "nrfx_timer.h"
|
||||
#include "nrfx_rtc.h"
|
||||
#include "nrfx_ppi.h"
|
||||
#include "nrf_uart.h"
|
||||
#include "nrf_queue.h"
|
||||
#define NRF_LOG_MODULE_NAME libUARTE_async
|
||||
#if NRF_LIBUARTE_CONFIG_LOG_ENABLED
|
||||
#define NRF_LOG_LEVEL NRF_LIBUARTE_CONFIG_LOG_LEVEL
|
||||
#define NRF_LOG_INFO_COLOR NRF_LIBUARTE_CONFIG_INFO_COLOR
|
||||
#define NRF_LOG_DEBUG_COLOR NRF_LIBUARTE_CONFIG_DEBUG_COLOR
|
||||
#else // NRF_LIBUARTE_CONFIG_LOG_ENABLED
|
||||
#define NRF_LOG_LEVEL 0
|
||||
#endif // NRF_LIBUARTE_CONFIG_LOG_ENABLED
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
#if defined(NRFX_RTC_ENABLED) && NRFX_RTC_ENABLED
|
||||
#define RTC_IN_USE 1
|
||||
#else
|
||||
#define RTC_IN_USE 0
|
||||
#endif
|
||||
|
||||
#if defined(NRFX_TIMER_ENABLED) && NRFX_TIMER_ENABLED
|
||||
#define TIMER_IN_USE 1
|
||||
#else
|
||||
#define TIMER_IN_USE 0
|
||||
#endif
|
||||
|
||||
#define FAULT_IRQ_LEVEL 0xFF
|
||||
|
||||
/** Macro is setting up PPI channel set which consist of event, task and optional fork.
|
||||
*
|
||||
* @param _ch Channel.
|
||||
* @param _evt Event.
|
||||
* @param _tsk Task.
|
||||
* @param _fork Fork. If NULL fork is not configured.
|
||||
*/
|
||||
#define PPI_CH_SETUP(_ch, _evt, _tsk, _fork) \
|
||||
ret = nrfx_ppi_channel_assign(_ch, _evt, _tsk); \
|
||||
if (ret != NRF_SUCCESS) \
|
||||
{ \
|
||||
return NRF_ERROR_INTERNAL; \
|
||||
} \
|
||||
if (_fork) \
|
||||
{ \
|
||||
ret = nrfx_ppi_channel_fork_assign(_ch, _fork); \
|
||||
if (ret != NRF_SUCCESS) \
|
||||
{ \
|
||||
return NRF_ERROR_INTERNAL; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* @brief Function returns interrupt level which is the next,lower priority.
|
||||
*
|
||||
* If SoftDevice is present then it takes into account which priorities are used
|
||||
* by the SoftDevice.
|
||||
*
|
||||
* @note Caller of this function does not check if error is returned. Error is returned if input
|
||||
* priority belongs to SoftDevice. In that case SoftDevice will detect attempt to interrupt level
|
||||
* misuse.
|
||||
*
|
||||
* @param prio Interrupt priority.
|
||||
*
|
||||
* @return Priority which is one level lower or fault indicator (0xFF).
|
||||
*/
|
||||
static uint8_t irq_prio_inc(uint8_t prio)
|
||||
{
|
||||
#ifdef SOFTDEVICE_PRESENT
|
||||
static const uint8_t sd_next_irq_lut[] = {
|
||||
FAULT_IRQ_LEVEL, /* 0 used by softdevice */
|
||||
FAULT_IRQ_LEVEL, /* 1 used by softdevice */
|
||||
APP_IRQ_PRIORITY_MID, /* 2 + 1 = 3 */
|
||||
APP_IRQ_PRIORITY_LOW_MID, /* 3 + 1 = 5 as 4 is used by softdevice */
|
||||
FAULT_IRQ_LEVEL, /* 4 used by softdevice */
|
||||
APP_IRQ_PRIORITY_LOW /* 5 + 1 = 6 */,
|
||||
APP_IRQ_PRIORITY_LOWEST, /* 6 + 1 = 7 */
|
||||
};
|
||||
return sd_next_irq_lut[prio];
|
||||
#else
|
||||
return prio + 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if NRF_LIBUARTE_ASYNC_WITH_APP_TIMER
|
||||
static void app_timer_handler(void * p_context);
|
||||
#define local_app_timer_cnt_get() app_timer_cnt_get()
|
||||
#define local_app_timer_start(p_timer, ticks, p_context) app_timer_start(p_timer, ticks, p_context)
|
||||
#define local_app_timer_stop(p_timer) app_timer_stop(p_timer)
|
||||
#define local_app_timer_create(p_timer) app_timer_create(p_timer, APP_TIMER_MODE_SINGLE_SHOT, app_timer_handler)
|
||||
#define local_app_timer_cnt_diff_compute(to, from) app_timer_cnt_diff_compute(to, from)
|
||||
#else
|
||||
#ifndef APP_TIMER_CONFIG_RTC_FREQUENCY
|
||||
#define APP_TIMER_CONFIG_RTC_FREQUENCY 0
|
||||
#endif
|
||||
|
||||
#ifndef APP_TIMER_CLOCK_FREQ
|
||||
#define APP_TIMER_CLOCK_FREQ 1
|
||||
#endif
|
||||
|
||||
#ifndef APP_TIMER_MIN_TIMEOUT_TICKS
|
||||
#define APP_TIMER_MIN_TIMEOUT_TICKS 0
|
||||
#endif
|
||||
|
||||
#ifndef APP_TIMER_CONFIG_IRQ_PRIORITY
|
||||
#define APP_TIMER_CONFIG_IRQ_PRIORITY 1
|
||||
#endif
|
||||
static void app_timer_handler(void * p_context) __attribute__((unused));
|
||||
#define local_app_timer_cnt_get() 0
|
||||
#define local_app_timer_start(p_timer, ticks, p_context) NRF_SUCCESS
|
||||
#define local_app_timer_stop(p_timer) NRF_SUCCESS
|
||||
#define local_app_timer_create(p_timer) NRF_SUCCESS
|
||||
#define local_app_timer_cnt_diff_compute(to, from) 0
|
||||
#endif
|
||||
|
||||
static uint32_t app_timer_ticks_to_us(uint32_t ticks)
|
||||
{
|
||||
return (uint32_t)(((uint64_t)ticks * 1000000 * (APP_TIMER_CONFIG_RTC_FREQUENCY + 1)) /
|
||||
APP_TIMER_CLOCK_FREQ);
|
||||
}
|
||||
|
||||
static uint32_t app_timer_us_to_ticks(uint32_t us)
|
||||
{
|
||||
return (uint32_t)((((uint64_t)APP_TIMER_CLOCK_FREQ/(APP_TIMER_CONFIG_RTC_FREQUENCY + 1)) * us) /
|
||||
1000000);
|
||||
}
|
||||
|
||||
static bool rx_buffer_schedule(const nrf_libuarte_async_t * p_libuarte)
|
||||
{
|
||||
uint8_t * p_data = nrf_balloc_alloc(p_libuarte->p_rx_pool);
|
||||
|
||||
if (p_data == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ret_code_t ret = nrf_queue_push(p_libuarte->p_rx_queue, &p_data);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("RX buffer queue full.");
|
||||
return false;
|
||||
}
|
||||
|
||||
p_libuarte->p_ctrl_blk->alloc_cnt++;
|
||||
nrf_libuarte_drv_rx_buf_rsp(p_libuarte->p_libuarte, p_data, p_libuarte->rx_buf_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void uart_evt_handler(void * context, nrf_libuarte_drv_evt_t * p_evt)
|
||||
{
|
||||
ret_code_t ret;
|
||||
const nrf_libuarte_async_t * p_libuarte = (const nrf_libuarte_async_t *)context;
|
||||
|
||||
switch (p_evt->type)
|
||||
{
|
||||
case NRF_LIBUARTE_DRV_EVT_TX_DONE:
|
||||
{
|
||||
NRF_LOG_DEBUG("(evt) TX completed (%d)", p_evt->data.rxtx.length);
|
||||
nrf_libuarte_async_evt_t evt = {
|
||||
.type = NRF_LIBUARTE_ASYNC_EVT_TX_DONE,
|
||||
.data = {
|
||||
.rxtx = {
|
||||
.p_data = p_evt->data.rxtx.p_data,
|
||||
.length = p_evt->data.rxtx.length,
|
||||
}
|
||||
}
|
||||
};
|
||||
p_libuarte->p_ctrl_blk->evt_handler(p_libuarte->p_ctrl_blk->context, &evt);
|
||||
break;
|
||||
}
|
||||
case NRF_LIBUARTE_DRV_EVT_RX_BUF_REQ:
|
||||
{
|
||||
if (p_libuarte->p_ctrl_blk->rx_halted)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (rx_buffer_schedule(p_libuarte) == false)
|
||||
{
|
||||
if (p_libuarte->p_ctrl_blk->hwfc)
|
||||
{
|
||||
p_libuarte->p_ctrl_blk->rx_halted = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_ERROR("(evt) Failed to allocate buffer for RX.");
|
||||
APP_ERROR_CHECK_BOOL(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NRF_LIBUARTE_DRV_EVT_RX_DATA:
|
||||
{
|
||||
|
||||
uint32_t rx_amount = p_evt->data.rxtx.length - p_libuarte->p_ctrl_blk->sub_rx_count;
|
||||
if (rx_amount)
|
||||
{
|
||||
p_libuarte->p_ctrl_blk->rx_count += rx_amount;
|
||||
nrf_libuarte_async_evt_t evt = {
|
||||
.type = NRF_LIBUARTE_ASYNC_EVT_RX_DATA,
|
||||
.data = {
|
||||
.rxtx = {
|
||||
.p_data = &p_evt->data.rxtx.p_data[p_libuarte->p_ctrl_blk->sub_rx_count],
|
||||
.length = rx_amount,
|
||||
}
|
||||
}
|
||||
};
|
||||
NRF_LOG_DEBUG("(evt) RX: %d (addr:0x%08X, internal index: %d)",
|
||||
rx_amount,
|
||||
p_evt->data.rxtx.p_data,
|
||||
p_libuarte->p_ctrl_blk->sub_rx_count);
|
||||
|
||||
p_libuarte->p_ctrl_blk->sub_rx_count = 0;
|
||||
|
||||
if(p_evt->data.rxtx.p_data != p_libuarte->p_ctrl_blk->p_curr_rx_buf)
|
||||
{
|
||||
NRF_LOG_ERROR("(evt) RX buffer address mismatch");
|
||||
}
|
||||
|
||||
ret = nrf_queue_pop(p_libuarte->p_rx_queue, &p_libuarte->p_ctrl_blk->p_curr_rx_buf);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
NRF_LOG_ERROR("RX buffer queue empty.");
|
||||
APP_ERROR_CHECK_BOOL(false);
|
||||
}
|
||||
|
||||
p_libuarte->p_ctrl_blk->evt_handler(p_libuarte->p_ctrl_blk->context, &evt);
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_ERROR("(evt) RX with 0 length: 0x%08X", p_evt->data.rxtx.p_data);
|
||||
//zero length packet is freed immediately and not forwarded to the application.
|
||||
APP_ERROR_CHECK_BOOL(false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NRF_LIBUARTE_DRV_EVT_ERROR:
|
||||
{
|
||||
nrf_libuarte_async_evt_t evt = {
|
||||
.type = NRF_LIBUARTE_ASYNC_EVT_ERROR,
|
||||
.data = {
|
||||
.errorsrc = p_evt->data.errorsrc
|
||||
}
|
||||
};
|
||||
p_libuarte->p_ctrl_blk->evt_handler(p_libuarte->p_ctrl_blk->context, &evt);
|
||||
break;
|
||||
}
|
||||
case NRF_LIBUARTE_DRV_EVT_OVERRUN_ERROR:
|
||||
{
|
||||
NRF_LOG_WARNING("Overrun error - data loss due to UARTE interrupt not handled on time.");
|
||||
uint32_t rx_amount = p_evt->data.overrun_err.overrun_length - p_libuarte->p_ctrl_blk->sub_rx_count;
|
||||
p_libuarte->p_ctrl_blk->rx_count += rx_amount;
|
||||
nrf_libuarte_async_evt_t evt = {
|
||||
.type = NRF_LIBUARTE_ASYNC_EVT_OVERRUN_ERROR,
|
||||
.data = {
|
||||
.overrun_err = { .overrun_length = p_evt->data.overrun_err.overrun_length}
|
||||
}
|
||||
};
|
||||
p_libuarte->p_ctrl_blk->evt_handler(p_libuarte->p_ctrl_blk->context, &evt);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
APP_ERROR_CHECK_BOOL(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void nrf_libuarte_async_timeout_handler(const nrf_libuarte_async_t * p_libuarte)
|
||||
{
|
||||
NRFX_IRQ_DISABLE((IRQn_Type)NRFX_IRQ_NUMBER_GET(p_libuarte->p_libuarte->uarte));
|
||||
|
||||
uint32_t capt_rx_count = p_libuarte->p_libuarte->timer.p_reg->CC[3];
|
||||
|
||||
if (capt_rx_count > p_libuarte->p_ctrl_blk->rx_count)
|
||||
{
|
||||
uint32_t rx_amount = capt_rx_count - p_libuarte->p_ctrl_blk->rx_count;
|
||||
nrf_libuarte_async_evt_t evt = {
|
||||
.type = NRF_LIBUARTE_ASYNC_EVT_RX_DATA,
|
||||
.data = {
|
||||
.rxtx = {
|
||||
.p_data = &p_libuarte->p_ctrl_blk->p_curr_rx_buf[p_libuarte->p_ctrl_blk->sub_rx_count],
|
||||
.length = rx_amount,
|
||||
}
|
||||
}
|
||||
};
|
||||
NRF_LOG_DEBUG("(tmr evt) RX: %d (addr:0x%08X, internal index: %d)",
|
||||
rx_amount,
|
||||
evt.data.rxtx.p_data,
|
||||
p_libuarte->p_ctrl_blk->sub_rx_count);
|
||||
|
||||
p_libuarte->p_ctrl_blk->sub_rx_count += rx_amount;
|
||||
p_libuarte->p_ctrl_blk->rx_count = capt_rx_count;
|
||||
p_libuarte->p_ctrl_blk->evt_handler(p_libuarte->p_ctrl_blk->context, &evt);
|
||||
}
|
||||
|
||||
NRFX_IRQ_ENABLE((IRQn_Type)NRFX_IRQ_NUMBER_GET(p_libuarte->p_libuarte->uarte));
|
||||
}
|
||||
|
||||
static void tmr_evt_handler(nrf_timer_event_t event_type, void * p_context)
|
||||
{
|
||||
nrf_libuarte_async_timeout_handler((const nrf_libuarte_async_t *)p_context);
|
||||
}
|
||||
|
||||
static void app_timer_handler(void * p_context)
|
||||
{
|
||||
const nrf_libuarte_async_t * p_libuarte = p_context;
|
||||
uint32_t current_rx_count;
|
||||
uint32_t counter = local_app_timer_cnt_get();
|
||||
uint32_t ticks = app_timer_us_to_ticks(p_libuarte->p_ctrl_blk->timeout_us)/2;
|
||||
ticks = MAX(APP_TIMER_MIN_TIMEOUT_TICKS, ticks);
|
||||
|
||||
if (p_libuarte->p_ctrl_blk->enabled == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
nrf_timer_task_trigger( p_libuarte->p_libuarte->timer.p_reg, NRF_TIMER_TASK_CAPTURE3);
|
||||
current_rx_count = p_libuarte->p_libuarte->timer.p_reg->CC[3];
|
||||
UNUSED_RETURN_VALUE(local_app_timer_start(*p_libuarte->p_app_timer, ticks, (void *)p_libuarte));
|
||||
|
||||
if (p_libuarte->p_app_timer_ctrl_blk->rx_count != current_rx_count) {
|
||||
p_libuarte->p_app_timer_ctrl_blk->rx_count = current_rx_count;
|
||||
/* if number of bytes received changed reset timestamp and activate waiting
|
||||
* for silent period.
|
||||
*/
|
||||
p_libuarte->p_app_timer_ctrl_blk->timestamp = counter;
|
||||
p_libuarte->p_app_timer_ctrl_blk->activate = true;
|
||||
} else {
|
||||
uint32_t diff;
|
||||
|
||||
/* In case of detected silent period check if its length exceeds configured
|
||||
* timeout. If yes trigger timeout handler.
|
||||
*/
|
||||
diff = local_app_timer_cnt_diff_compute(counter,
|
||||
p_libuarte->p_app_timer_ctrl_blk->timestamp);
|
||||
if (p_libuarte->p_app_timer_ctrl_blk->activate &&
|
||||
(app_timer_ticks_to_us(diff) > p_libuarte->p_ctrl_blk->timeout_us)) {
|
||||
p_libuarte->p_app_timer_ctrl_blk->activate = false;
|
||||
nrf_libuarte_async_timeout_handler(p_libuarte);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret_code_t nrf_libuarte_async_init(const nrf_libuarte_async_t * const p_libuarte,
|
||||
nrf_libuarte_async_config_t const * p_config,
|
||||
nrf_libuarte_async_evt_handler_t evt_handler,
|
||||
void * context)
|
||||
{
|
||||
ret_code_t ret;
|
||||
|
||||
if (p_config->int_prio == APP_IRQ_PRIORITY_LOWEST ||
|
||||
((p_libuarte->p_app_timer && NRF_LIBUARTE_ASYNC_WITH_APP_TIMER) &&
|
||||
(p_config->int_prio >= APP_TIMER_CONFIG_IRQ_PRIORITY))) {
|
||||
NRF_LOG_ERROR("Too low priority. Lowest possible priority is %d", APP_IRQ_PRIORITY_LOW);
|
||||
return NRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (p_libuarte->p_ctrl_blk->enabled)
|
||||
{
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
p_libuarte->p_ctrl_blk->evt_handler = evt_handler;
|
||||
p_libuarte->p_ctrl_blk->rx_count = 0;
|
||||
p_libuarte->p_ctrl_blk->p_curr_rx_buf = NULL;
|
||||
p_libuarte->p_ctrl_blk->rx_free_cnt = 0;
|
||||
p_libuarte->p_ctrl_blk->sub_rx_count = 0;
|
||||
p_libuarte->p_ctrl_blk->alloc_cnt = 0;
|
||||
p_libuarte->p_ctrl_blk->context = context;
|
||||
p_libuarte->p_ctrl_blk->timeout_us = p_config->timeout_us;
|
||||
p_libuarte->p_ctrl_blk->rx_halted = false;
|
||||
p_libuarte->p_ctrl_blk->hwfc = (p_config->hwfc == NRF_UARTE_HWFC_ENABLED);
|
||||
|
||||
uint32_t i;
|
||||
|
||||
uint32_t tmr_start_tsk = 0;
|
||||
uint32_t tmr_clear_tsk = 0;
|
||||
uint32_t tmr_stop_tsk = 0;
|
||||
uint32_t tmr_compare_evt = 0;
|
||||
|
||||
if (p_libuarte->p_rtc && RTC_IN_USE)
|
||||
{
|
||||
nrfx_rtc_config_t rtc_config = NRFX_RTC_DEFAULT_CONFIG;
|
||||
rtc_config.interrupt_priority = irq_prio_inc(p_config->int_prio);
|
||||
|
||||
rtc_config.prescaler = 0;
|
||||
ret = nrfx_rtc_init(p_libuarte->p_rtc, &rtc_config, p_libuarte->rtc_handler);
|
||||
if (ret != NRFX_SUCCESS)
|
||||
{
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
ret = nrfx_rtc_cc_set(p_libuarte->p_rtc, 0, p_config->timeout_us/32, true);
|
||||
if (ret != NRFX_SUCCESS)
|
||||
{
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
tmr_start_tsk = nrfx_rtc_task_address_get(p_libuarte->p_rtc, NRF_RTC_TASK_START);
|
||||
tmr_clear_tsk = nrfx_rtc_task_address_get(p_libuarte->p_rtc, NRF_RTC_TASK_CLEAR);
|
||||
tmr_stop_tsk = nrfx_rtc_task_address_get(p_libuarte->p_rtc, NRF_RTC_TASK_STOP);
|
||||
tmr_compare_evt = nrfx_rtc_event_address_get(p_libuarte->p_rtc, NRF_RTC_EVENT_COMPARE_0);
|
||||
}
|
||||
else if (p_libuarte->p_timer && TIMER_IN_USE)
|
||||
{
|
||||
nrfx_timer_config_t tmr_config = NRFX_TIMER_DEFAULT_CONFIG;
|
||||
tmr_config.frequency = NRF_TIMER_FREQ_1MHz;
|
||||
tmr_config.p_context = (void *)p_libuarte;
|
||||
tmr_config.interrupt_priority = irq_prio_inc(p_config->int_prio);
|
||||
|
||||
ret = nrfx_timer_init(p_libuarte->p_timer, &tmr_config, tmr_evt_handler);
|
||||
if (ret != NRFX_SUCCESS)
|
||||
{
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
nrfx_timer_compare(p_libuarte->p_timer, NRF_TIMER_CC_CHANNEL0, p_config->timeout_us, true);
|
||||
|
||||
tmr_start_tsk = nrfx_timer_task_address_get(p_libuarte->p_timer, NRF_TIMER_TASK_START);
|
||||
tmr_clear_tsk = nrfx_timer_task_address_get(p_libuarte->p_timer, NRF_TIMER_TASK_CLEAR);
|
||||
tmr_stop_tsk = nrfx_timer_task_address_get(p_libuarte->p_timer, NRF_TIMER_TASK_SHUTDOWN);
|
||||
tmr_compare_evt = nrfx_timer_compare_event_address_get(p_libuarte->p_timer, 0);
|
||||
}
|
||||
else if (p_libuarte->p_app_timer && NRF_LIBUARTE_ASYNC_WITH_APP_TIMER) {
|
||||
/* app_timer in use */
|
||||
if(!p_libuarte->p_ctrl_blk->app_timer_created)
|
||||
{
|
||||
ret = local_app_timer_create(p_libuarte->p_app_timer);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
p_libuarte->p_ctrl_blk->app_timer_created = true;
|
||||
}
|
||||
p_libuarte->p_app_timer_ctrl_blk->activate = false;
|
||||
p_libuarte->p_app_timer_ctrl_blk->rx_count = 0;
|
||||
p_libuarte->p_app_timer_ctrl_blk->timestamp = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_ERROR("No timer or rtc defined");
|
||||
APP_ERROR_CHECK_BOOL(false);
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
/* if RTC or TIMER is used then PPI channels are allocated. */
|
||||
if (p_libuarte->p_app_timer == NULL || !NRF_LIBUARTE_ASYNC_WITH_APP_TIMER)
|
||||
{
|
||||
for (i = 0; i < NRF_LIBUARTE_ASYNC_PPI_CH_MAX; i++)
|
||||
{
|
||||
ret = nrfx_ppi_channel_alloc(&p_libuarte->p_ctrl_blk->ppi_channels[i]);
|
||||
if (ret != NRFX_SUCCESS)
|
||||
{
|
||||
//we don't free already allocated channels, system is wrongly configured.
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
/*lint -save -e666 */
|
||||
PPI_CH_SETUP(p_libuarte->p_ctrl_blk->ppi_channels[NRF_LIBUARTE_ASYNC_PPI_CH_RXRDY_CLEAR],
|
||||
nrf_uarte_event_address_get(p_libuarte->p_libuarte->uarte, NRF_UARTE_EVENT_RXDRDY),
|
||||
tmr_start_tsk,
|
||||
tmr_clear_tsk);
|
||||
|
||||
PPI_CH_SETUP(p_libuarte->p_ctrl_blk->ppi_channels[NRF_LIBUARTE_ASYNC_PPI_CH_COMPARE_SHUTDOWN],
|
||||
tmr_compare_evt,
|
||||
tmr_stop_tsk,
|
||||
(uint32_t)&p_libuarte->p_libuarte->timer.p_reg->TASKS_CAPTURE[3]);
|
||||
/*lint -restore */
|
||||
}
|
||||
|
||||
nrf_libuarte_drv_config_t uart_config = {
|
||||
.tx_pin = p_config->tx_pin,
|
||||
.rx_pin = p_config->rx_pin,
|
||||
.cts_pin = p_config->cts_pin,
|
||||
.rts_pin = p_config->rts_pin,
|
||||
.startrx_evt = nrf_uarte_event_address_get(p_libuarte->p_libuarte->uarte, NRF_UARTE_EVENT_ENDRX),
|
||||
.endrx_evt = 0,
|
||||
.rxstarted_tsk = 0,
|
||||
.rxdone_tsk = 0,
|
||||
.hwfc = p_config->hwfc,
|
||||
.parity = p_config->parity,
|
||||
.baudrate = p_config->baudrate,
|
||||
.irq_priority = p_config->int_prio,
|
||||
.pullup_rx = p_config->pullup_rx,
|
||||
};
|
||||
|
||||
ret = nrf_libuarte_drv_init(p_libuarte->p_libuarte, &uart_config, uart_evt_handler, (void *)p_libuarte);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = nrf_balloc_init(p_libuarte->p_rx_pool);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
nrf_queue_reset(p_libuarte->p_rx_queue);
|
||||
p_libuarte->p_ctrl_blk->enabled = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void nrf_libuarte_async_uninit(const nrf_libuarte_async_t * const p_libuarte)
|
||||
{
|
||||
if (p_libuarte->p_ctrl_blk->enabled == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
p_libuarte->p_ctrl_blk->enabled = false;
|
||||
|
||||
/* if HW timeout was used */
|
||||
if (p_libuarte->p_app_timer == NULL || !NRF_LIBUARTE_ASYNC_WITH_APP_TIMER)
|
||||
{
|
||||
uint32_t i;
|
||||
ret_code_t ret;
|
||||
for (i = 0; i < NRF_LIBUARTE_ASYNC_PPI_CH_MAX; i++)
|
||||
{
|
||||
ret = nrfx_ppi_channel_disable(p_libuarte->p_ctrl_blk->ppi_channels[i]);
|
||||
ASSERT(ret == NRF_SUCCESS)
|
||||
ret = nrfx_ppi_channel_free(p_libuarte->p_ctrl_blk->ppi_channels[i]);
|
||||
ASSERT(ret == NRF_SUCCESS)
|
||||
}
|
||||
}
|
||||
|
||||
if (p_libuarte->p_rtc && RTC_IN_USE)
|
||||
{
|
||||
nrfx_rtc_disable(p_libuarte->p_rtc);
|
||||
nrfx_rtc_uninit(p_libuarte->p_rtc);
|
||||
}
|
||||
else if (p_libuarte->p_timer && TIMER_IN_USE)
|
||||
{
|
||||
nrfx_timer_disable(p_libuarte->p_timer);
|
||||
nrfx_timer_uninit(p_libuarte->p_timer);
|
||||
}
|
||||
else if (p_libuarte->p_app_timer && NRF_LIBUARTE_ASYNC_WITH_APP_TIMER)
|
||||
{
|
||||
UNUSED_RETURN_VALUE(local_app_timer_stop(*p_libuarte->p_app_timer));
|
||||
}
|
||||
|
||||
nrf_libuarte_drv_uninit(p_libuarte->p_libuarte);
|
||||
}
|
||||
|
||||
void nrf_libuarte_async_enable(const nrf_libuarte_async_t * const p_libuarte)
|
||||
{
|
||||
uint8_t * p_data;
|
||||
p_data = nrf_balloc_alloc(p_libuarte->p_rx_pool);
|
||||
p_libuarte->p_ctrl_blk->alloc_cnt++;
|
||||
if (p_data == NULL)
|
||||
{
|
||||
APP_ERROR_CHECK_BOOL(false);
|
||||
}
|
||||
|
||||
if (p_libuarte->p_rtc && RTC_IN_USE)
|
||||
{
|
||||
nrfx_rtc_counter_clear(p_libuarte->p_rtc);
|
||||
}
|
||||
else if (p_libuarte->p_timer && TIMER_IN_USE)
|
||||
{
|
||||
nrfx_timer_clear(p_libuarte->p_timer);
|
||||
}
|
||||
|
||||
if (!(p_libuarte->p_app_timer && NRF_LIBUARTE_ASYNC_WITH_APP_TIMER))
|
||||
{
|
||||
nrfx_err_t err;
|
||||
|
||||
err = nrfx_ppi_channel_enable(p_libuarte->p_ctrl_blk->ppi_channels[NRF_LIBUARTE_ASYNC_PPI_CH_RXRDY_CLEAR]);
|
||||
APP_ERROR_CHECK_BOOL(err == NRFX_SUCCESS);
|
||||
err = nrfx_ppi_channel_enable(p_libuarte->p_ctrl_blk->ppi_channels[NRF_LIBUARTE_ASYNC_PPI_CH_COMPARE_SHUTDOWN]);
|
||||
APP_ERROR_CHECK_BOOL(err == NRFX_SUCCESS);
|
||||
}
|
||||
|
||||
p_libuarte->p_ctrl_blk->p_curr_rx_buf = p_data;
|
||||
ret_code_t ret = nrf_libuarte_drv_rx_start(p_libuarte->p_libuarte, p_data, p_libuarte->rx_buf_size, false);
|
||||
APP_ERROR_CHECK_BOOL(ret == NRF_SUCCESS);
|
||||
|
||||
if (p_libuarte->p_app_timer && NRF_LIBUARTE_ASYNC_WITH_APP_TIMER)
|
||||
{
|
||||
uint32_t ticks = app_timer_us_to_ticks(p_libuarte->p_ctrl_blk->timeout_us)/2;
|
||||
ticks = MAX(APP_TIMER_MIN_TIMEOUT_TICKS, ticks);
|
||||
UNUSED_RETURN_VALUE(local_app_timer_start(*p_libuarte->p_app_timer, ticks, (void *)p_libuarte));
|
||||
}
|
||||
}
|
||||
|
||||
ret_code_t nrf_libuarte_async_tx(const nrf_libuarte_async_t * const p_libuarte, uint8_t * p_data, size_t length)
|
||||
{
|
||||
return nrf_libuarte_drv_tx(p_libuarte->p_libuarte, p_data, length);
|
||||
}
|
||||
|
||||
void nrf_libuarte_async_rx_free(const nrf_libuarte_async_t * const p_libuarte, uint8_t * p_data, size_t length)
|
||||
{
|
||||
p_libuarte->p_ctrl_blk->rx_free_cnt += length;
|
||||
if (p_libuarte->p_ctrl_blk->rx_free_cnt == p_libuarte->rx_buf_size)
|
||||
{
|
||||
p_data -= (p_libuarte->p_ctrl_blk->rx_free_cnt - length);
|
||||
p_libuarte->p_ctrl_blk->rx_free_cnt = 0;
|
||||
nrf_balloc_free(p_libuarte->p_rx_pool, p_data);
|
||||
|
||||
p_libuarte->p_ctrl_blk->alloc_cnt--;
|
||||
if (p_libuarte->p_ctrl_blk->alloc_cnt<0)
|
||||
{
|
||||
NRF_LOG_ERROR("Freeing more RX buffers than allocated.");
|
||||
APP_ERROR_CHECK_BOOL(false);
|
||||
}
|
||||
NRF_LOG_INFO("Freeing full buffer 0x%08X, %d, (currently allocated:%d).",p_data, length, p_libuarte->p_ctrl_blk->alloc_cnt);
|
||||
|
||||
if (p_libuarte->p_ctrl_blk->rx_halted)
|
||||
{
|
||||
bool ret = rx_buffer_schedule(p_libuarte);
|
||||
ASSERT(ret);
|
||||
p_libuarte->p_ctrl_blk->rx_halted = false;
|
||||
}
|
||||
}
|
||||
else if (p_libuarte->p_ctrl_blk->rx_free_cnt > p_libuarte->rx_buf_size)
|
||||
{
|
||||
NRF_LOG_ERROR("Unexpected RX free input parameter.");
|
||||
APP_ERROR_CHECK_BOOL(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_INFO("Freeing partial buffer: 0x%08X, length:%d", p_data, length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void nrf_libuarte_async_rts_clear(const nrf_libuarte_async_t * const p_libuarte)
|
||||
{
|
||||
nrf_libuarte_drv_rts_clear(p_libuarte->p_libuarte);
|
||||
}
|
||||
|
||||
void nrf_libuarte_async_rts_set(const nrf_libuarte_async_t * const p_libuarte)
|
||||
{
|
||||
nrf_libuarte_drv_rts_set(p_libuarte->p_libuarte);
|
||||
}
|
||||
385
components/libraries/libuarte/nrf_libuarte_async.h
Normal file
385
components/libraries/libuarte/nrf_libuarte_async.h
Normal file
@@ -0,0 +1,385 @@
|
||||
/**
|
||||
* Copyright (c) 2019 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
#ifndef UART_ASYNC_H
|
||||
#define UART_ASYNC_H
|
||||
#include <stdint.h>
|
||||
#include "sdk_errors.h"
|
||||
#include "nrf_balloc.h"
|
||||
#include "nrf_queue.h"
|
||||
#include "nrfx_ppi.h"
|
||||
#include "nrfx_timer.h"
|
||||
#include "nrfx_rtc.h"
|
||||
#include "nrf_libuarte_drv.h"
|
||||
#include <hal/nrf_uarte.h>
|
||||
|
||||
/**
|
||||
* @defgroup nrf_libuarte_async libUARTE asynchronous library
|
||||
* @ingroup app_common
|
||||
*
|
||||
* @brief Module for reliable communication over UARTE.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Safe guard for sdk_config.h now up to date. */
|
||||
#ifndef NRF_LIBUARTE_ASYNC_WITH_APP_TIMER
|
||||
#warning "sdk_config.h is missing NRF_LIBUARTE_ASYNC_WITH_APP_TIMER option"
|
||||
#define NRF_LIBUARTE_ASYNC_WITH_APP_TIMER 0
|
||||
#endif
|
||||
|
||||
#if NRF_LIBUARTE_ASYNC_WITH_APP_TIMER
|
||||
#include "app_timer.h"
|
||||
#endif
|
||||
|
||||
/** @brief Types of libuarte driver events. */
|
||||
typedef enum
|
||||
{
|
||||
NRF_LIBUARTE_ASYNC_EVT_RX_DATA, ///< Requested TX transfer completed.
|
||||
NRF_LIBUARTE_ASYNC_EVT_TX_DONE, ///< Requested RX transfer completed.
|
||||
NRF_LIBUARTE_ASYNC_EVT_ERROR, ///< Error reported by UARTE peripheral.
|
||||
NRF_LIBUARTE_ASYNC_EVT_OVERRUN_ERROR ///< Error reported by the driver.
|
||||
} nrf_libuarte_async_evt_type_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NRF_LIBUARTE_ASYNC_PPI_CH_RXRDY_CLEAR,
|
||||
NRF_LIBUARTE_ASYNC_PPI_CH_COMPARE_SHUTDOWN,
|
||||
NRF_LIBUARTE_ASYNC_PPI_CH_MAX
|
||||
} nrf_libuarte_async_ppi_channel_t;
|
||||
|
||||
/** @brief Structure for libuarte async transfer completion event. */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t * p_data; ///< Pointer to memory used for transfer.
|
||||
size_t length; ///< Number of bytes transfered.
|
||||
} nrf_libuarte_async_data_t;
|
||||
|
||||
/** @brief Structu for software error event. */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t overrun_length; ///< Number of bytes lost due to overrun.
|
||||
} nrf_libuarte_async_overrun_err_evt_t;
|
||||
|
||||
/** @brief Structure for libuarte error event. */
|
||||
typedef struct
|
||||
{
|
||||
nrf_libuarte_async_evt_type_t type; ///< Event type.
|
||||
union {
|
||||
nrf_libuarte_async_data_t rxtx; ///< RXD/TXD data.
|
||||
uint8_t errorsrc; ///< Error source.
|
||||
nrf_libuarte_async_overrun_err_evt_t overrun_err; ///< Overrun error data.
|
||||
} data; ///< Union with data.
|
||||
} nrf_libuarte_async_evt_t;
|
||||
|
||||
/**
|
||||
* @brief Interrupt event handler.
|
||||
*
|
||||
* @param[in] p_evt Pointer to event structure. Event is allocated on the stack so it is available
|
||||
* only within the context of the event handler.
|
||||
*/
|
||||
typedef void (*nrf_libuarte_async_evt_handler_t)(void * context, nrf_libuarte_async_evt_t * p_evt);
|
||||
|
||||
/** @brief Structure for libuarte async configuration. */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t rx_pin; ///< RXD pin number.
|
||||
uint32_t tx_pin; ///< TXD pin number.
|
||||
uint32_t cts_pin; ///< CTS pin number.
|
||||
uint32_t rts_pin; ///< RTS pin number.
|
||||
uint32_t timeout_us; ///< Receiver timeout in us unit.
|
||||
nrf_uarte_hwfc_t hwfc; ///< Flow control configuration.
|
||||
nrf_uarte_parity_t parity; ///< Parity configuration.
|
||||
nrf_uarte_baudrate_t baudrate; ///< Baudrate.
|
||||
bool pullup_rx; ///< Pull up on RX pin.
|
||||
uint8_t int_prio; ///< Interrupt priority of UARTE (RTC, TIMER have int_prio - 1)
|
||||
} nrf_libuarte_async_config_t;
|
||||
|
||||
/**
|
||||
* @brief nrf_libuarte_async control block (placed in RAM).
|
||||
*/
|
||||
typedef struct {
|
||||
nrf_libuarte_async_evt_handler_t evt_handler;
|
||||
void * context;
|
||||
nrf_ppi_channel_t ppi_channels[NRF_LIBUARTE_ASYNC_PPI_CH_MAX];
|
||||
int32_t alloc_cnt;
|
||||
uint32_t rx_count;
|
||||
uint32_t sub_rx_count;
|
||||
uint8_t * p_curr_rx_buf;
|
||||
uint32_t rx_free_cnt;
|
||||
uint32_t timeout_us;
|
||||
bool app_timer_created;
|
||||
bool hwfc;
|
||||
bool rx_halted;
|
||||
bool enabled;
|
||||
} nrf_libuarte_async_ctrl_blk_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t rx_count;
|
||||
uint32_t timestamp;
|
||||
bool activate;
|
||||
} nrf_libuarte_app_timer_ctrl_blk_t;
|
||||
|
||||
/**
|
||||
* @brief nrf_libuarte_async instance structure (placed in ROM).
|
||||
*/
|
||||
typedef struct {
|
||||
const nrf_balloc_t * p_rx_pool;
|
||||
const nrf_queue_t * p_rx_queue;
|
||||
const nrfx_rtc_t * p_rtc;
|
||||
const nrfx_timer_t * p_timer;
|
||||
#if NRF_LIBUARTE_ASYNC_WITH_APP_TIMER
|
||||
const app_timer_id_t * p_app_timer;
|
||||
#else
|
||||
void ** p_app_timer;
|
||||
#endif
|
||||
nrf_libuarte_app_timer_ctrl_blk_t * p_app_timer_ctrl_blk;
|
||||
const nrf_libuarte_drv_t * p_libuarte;
|
||||
nrf_libuarte_async_ctrl_blk_t * p_ctrl_blk;
|
||||
nrfx_rtc_handler_t rtc_handler;
|
||||
uint32_t rx_buf_size;
|
||||
} nrf_libuarte_async_t;
|
||||
|
||||
void nrf_libuarte_async_timeout_handler(const nrf_libuarte_async_t * p_libuarte);
|
||||
|
||||
#define NRF_LIBUARTE_PERIPHERAL_NOT_USED 255
|
||||
|
||||
#define LIBUARTE_ASYNC_DEBRACKET(...) __VA_ARGS__
|
||||
|
||||
#define __LIBUARTE_ASYNC_ARG_2(ignore_this, val, ...) val
|
||||
#define __LIBUARTE_ASYNC_ARG_2_DEBRACKET(ignore_this, val, ...) LIBUARTE_ASYNC_DEBRACKET val
|
||||
|
||||
/* Macro for injecting code based on flag evaluation. If flag exists and equals 1
|
||||
* then first code is compiled in, else second option. Note that code must be
|
||||
* in the brackets. Example usage:
|
||||
* _LIBUARTE_ASYNC_EVAL(MY_FLAG, (foo();), () )
|
||||
* If MY_FLAG exists and equals 1 then macros resolves to foo(); call, else it resolves to
|
||||
* empty line.
|
||||
*
|
||||
* @param _eval_level Flag to be evaluated. It's positively evaluated if exists and equals 1.
|
||||
* @param _iftrue Macro is resolved to that code on positive flag evaluation. Code must be
|
||||
* in the brackets.
|
||||
* @param _iffalse Macro is resolved to that code on negative flag evaluation. Code must be
|
||||
* in the brackets.
|
||||
*/
|
||||
#define _LIBUARTE_ASYNC_EVAL(_eval_flag, _iftrue, _iffalse) \
|
||||
_LIBUARTE_ASYNC_EVAL1(_eval_flag, _iftrue, _iffalse)
|
||||
|
||||
#define _LIBUARTE_ASYNC_EVAL1(_eval_flag, _iftrue, _iffalse) \
|
||||
_LIBUARTE_ASYNC_EVAL2(_LIBUARTE_ASYNC_ZZZZ##_eval_flag, _iftrue, _iffalse)
|
||||
|
||||
#define _LIBUARTE_ASYNC_ZZZZ1 _LIBUARTE_ASYNC_YYYY,
|
||||
|
||||
#define _LIBUARTE_ASYNC_EVAL2(one_or_two_args, _iftrue, _iffalse) \
|
||||
__LIBUARTE_ASYNC_ARG_2_DEBRACKET(one_or_two_args _iftrue, _iffalse)
|
||||
|
||||
/**
|
||||
* @brief Macro for creating instance of libuarte_async.
|
||||
*
|
||||
* Libuarte_async requires one timer-like peripheral (RTC or TIMER) for triggering RX timeout.
|
||||
* Macro will create instance only for peripheral which is used.
|
||||
*
|
||||
* @param _name Instance name.
|
||||
* @param _uarte_idx UARTE instance used.
|
||||
* @param _timer0_idx TIMER instance used by libuarte for bytes counting.
|
||||
* @param _rtc1_idx RTC instance used for timeout. If set to NRF_LIBUARTE_PERIPHERAL_NOT_USED
|
||||
* then TIMER instance is used or app_timer instance if _timer1_idx is also set
|
||||
* to NRF_LIBUARTE_PERIPHERAL_NOT_USED.
|
||||
* @param _timer1_idx TIMER instance used for timeout. If set to NRF_LIBUARTE_PERIPHERAL_NOT_USED
|
||||
* then RTC instance is used or app_timer instance if _rtc1_idx is also set
|
||||
* to NRF_LIBUARTE_PERIPHERAL_NOT_USED.
|
||||
* @param _rx_buf_size Size of single RX buffer. Size impacts accepted latency between buffer
|
||||
* request and providing next buffer. Next must be provided within before
|
||||
* _rx_buf_size bytes is received.
|
||||
* @param _rx_buf_cnt Number of buffers in the RX buffer pool. Size impacts accepted latency
|
||||
* between NRF_LIBUARTE_ASYNC_EVT_RX_DATA event and
|
||||
* @ref nrf_libuarte_async_rx_free.
|
||||
*/
|
||||
#define NRF_LIBUARTE_ASYNC_DEFINE(_name, _uarte_idx, _timer0_idx,\
|
||||
_rtc1_idx, _timer1_idx,\
|
||||
_rx_buf_size, _rx_buf_cnt) \
|
||||
STATIC_ASSERT(_rx_buf_cnt >= 3, "Wrong number of RX buffers");\
|
||||
STATIC_ASSERT(!((NRF_LIBUARTE_ASYNC_WITH_APP_TIMER == 0) && \
|
||||
(_rtc1_idx == NRF_LIBUARTE_PERIPHERAL_NOT_USED) && \
|
||||
(_timer1_idx == NRF_LIBUARTE_PERIPHERAL_NOT_USED)), \
|
||||
"App timer support disabled");\
|
||||
NRF_LIBUARTE_DRV_DEFINE(CONCAT_2(_name, _libuarte), _uarte_idx, _timer0_idx);\
|
||||
NRF_QUEUE_DEF(uint8_t *, CONCAT_2(_name,_rxdata_queue), _rx_buf_cnt, NRF_QUEUE_MODE_NO_OVERFLOW);\
|
||||
NRF_BALLOC_DEF(CONCAT_2(_name,_rx_pool), _rx_buf_size, _rx_buf_cnt);\
|
||||
/* Create TIMER instance only if _timer1_idx != NRF_LIBUARTE_PERIPHERAL_NOT_USED */ \
|
||||
_LIBUARTE_ASYNC_EVAL(\
|
||||
NRFX_CONCAT_3(NRFX_TIMER, _timer1_idx, _ENABLED),\
|
||||
(STATIC_ASSERT((_timer1_idx == NRF_LIBUARTE_PERIPHERAL_NOT_USED) || (CONCAT_3(NRFX_TIMER,_timer1_idx, _ENABLED) == 1), "TIMER instance not enabled");\
|
||||
static const nrfx_timer_t CONCAT_2(_name, _timer) = NRFX_TIMER_INSTANCE(_timer1_idx);),\
|
||||
(/* empty */))\
|
||||
/* Create RTC instance only if _timer1_idx != NRF_LIBUARTE_PERIPHERAL_NOT_USED */ \
|
||||
_LIBUARTE_ASYNC_EVAL(\
|
||||
NRFX_CONCAT_3(NRFX_RTC, _rtc1_idx, _ENABLED),\
|
||||
(STATIC_ASSERT((_rtc1_idx == NRF_LIBUARTE_PERIPHERAL_NOT_USED) || (CONCAT_3(NRFX_RTC,_rtc1_idx, _ENABLED) == 1), "RTC instance not enabled");\
|
||||
static const nrfx_rtc_t CONCAT_2(_name, _rtc) = NRFX_RTC_INSTANCE(_rtc1_idx);),\
|
||||
(/* empty */))\
|
||||
_LIBUARTE_ASYNC_EVAL(NRFX_CONCAT_3(NRFX_TIMER, _timer1_idx, _ENABLED),\
|
||||
(/* empty */),\
|
||||
(_LIBUARTE_ASYNC_EVAL(NRFX_CONCAT_3(NRFX_RTC, _rtc1_idx, _ENABLED),(/* empty */), \
|
||||
(APP_TIMER_DEF(CONCAT_2(_name,_app_timer)); \
|
||||
nrf_libuarte_app_timer_ctrl_blk_t CONCAT_2(_name,_app_timer_ctrl_blk);))) \
|
||||
)\
|
||||
static nrf_libuarte_async_ctrl_blk_t CONCAT_2(_name, ctrl_blk);\
|
||||
_LIBUARTE_ASYNC_EVAL(\
|
||||
NRFX_CONCAT_3(NRFX_RTC, _rtc1_idx, _ENABLED), \
|
||||
(static void CONCAT_2(_name, _rtc_handler)(nrfx_rtc_int_type_t int_type);),\
|
||||
(/* empty */)) \
|
||||
\
|
||||
static const nrf_libuarte_async_t _name = {\
|
||||
.p_rx_pool = &CONCAT_2(_name,_rx_pool),\
|
||||
.p_rx_queue = &CONCAT_2(_name,_rxdata_queue),\
|
||||
/* If p_rtc is not NULL it means that RTC is used for RX timeout */ \
|
||||
.p_rtc = _LIBUARTE_ASYNC_EVAL(NRFX_CONCAT_3(NRFX_RTC, _rtc1_idx, _ENABLED), (&CONCAT_2(_name, _rtc)), (NULL)),\
|
||||
/* If p_timer is not NULL it means that RTC is used for RX timeout */ \
|
||||
.p_timer = _LIBUARTE_ASYNC_EVAL(NRFX_CONCAT_3(NRFX_TIMER, _timer1_idx, _ENABLED), (&CONCAT_2(_name, _timer)), (NULL)),\
|
||||
/* If p_time and p_rtc is NULL it means that app_timer is used for RX timeout */ \
|
||||
.p_app_timer = _LIBUARTE_ASYNC_EVAL(NRFX_CONCAT_3(NRFX_TIMER, _timer1_idx, _ENABLED),\
|
||||
(NULL),\
|
||||
(_LIBUARTE_ASYNC_EVAL(NRFX_CONCAT_3(NRFX_RTC, _rtc1_idx, _ENABLED),(NULL), \
|
||||
(&CONCAT_2(_name,_app_timer)))) \
|
||||
),\
|
||||
.p_app_timer_ctrl_blk = _LIBUARTE_ASYNC_EVAL(NRFX_CONCAT_3(NRFX_TIMER, _timer1_idx, _ENABLED),\
|
||||
(NULL),\
|
||||
(_LIBUARTE_ASYNC_EVAL(NRFX_CONCAT_3(NRFX_RTC, _rtc1_idx, _ENABLED),(NULL), \
|
||||
(&CONCAT_2(_name,_app_timer_ctrl_blk)))) \
|
||||
),\
|
||||
.p_libuarte = &CONCAT_2(_name, _libuarte),\
|
||||
.p_ctrl_blk = &CONCAT_2(_name, ctrl_blk),\
|
||||
.rx_buf_size = _rx_buf_size,\
|
||||
_LIBUARTE_ASYNC_EVAL(\
|
||||
NRFX_CONCAT_3(NRFX_RTC, _rtc1_idx, _ENABLED),\
|
||||
(.rtc_handler =CONCAT_2(_name, _rtc_handler)),\
|
||||
()\
|
||||
)\
|
||||
};\
|
||||
/* RTC compare event is not periodic but need to be enabled again in the callback. */ \
|
||||
_LIBUARTE_ASYNC_EVAL(\
|
||||
NRFX_CONCAT_3(NRFX_RTC, _rtc1_idx, _ENABLED),\
|
||||
(\
|
||||
static void CONCAT_2(_name, _rtc_handler)(nrfx_rtc_int_type_t int_type)\
|
||||
{ \
|
||||
(void)nrfx_rtc_cc_set(_name.p_rtc, 0, _name.p_ctrl_blk->timeout_us/32, true);\
|
||||
nrf_libuarte_async_timeout_handler(&_name);\
|
||||
}\
|
||||
),\
|
||||
()\
|
||||
)
|
||||
|
||||
|
||||
/**
|
||||
* @brief Function for initializing the libuarte async library.
|
||||
*
|
||||
* @param[in] p_libuarte Libuarte_async instance.
|
||||
* @param[in] p_config Pointer to the structure with initial configuration.
|
||||
* @param[in] evt_handler Event handler provided by the user. Must not be NULL.
|
||||
* @param[in] context User context passed to the event handler.
|
||||
*
|
||||
* @return NRF_SUCCESS when properly initialized. NRF_ERROR_INTERNAL otherwise.
|
||||
*/
|
||||
ret_code_t nrf_libuarte_async_init(const nrf_libuarte_async_t * const p_libuarte,
|
||||
nrf_libuarte_async_config_t const * p_config,
|
||||
nrf_libuarte_async_evt_handler_t evt_handler,
|
||||
void * context);
|
||||
|
||||
/** @brief Function for uninitializing the libuarte async library.
|
||||
*
|
||||
* @param[in] p_libuarte Libuarte_async instance.
|
||||
*/
|
||||
void nrf_libuarte_async_uninit(const nrf_libuarte_async_t * const p_libuarte);
|
||||
|
||||
/**
|
||||
* @brief Function for enabling receiver.
|
||||
*
|
||||
* @param p_libuarte Libuarte_async instance.
|
||||
*/
|
||||
void nrf_libuarte_async_enable(const nrf_libuarte_async_t * const p_libuarte);
|
||||
|
||||
/**
|
||||
* @brief Function for deasserting RTS to pause the transmission.
|
||||
*
|
||||
* Flow control must be enabled.
|
||||
*
|
||||
* @param p_libuarte Libuarte_async instance.
|
||||
*/
|
||||
void nrf_libuarte_async_rts_clear(const nrf_libuarte_async_t * const p_libuarte);
|
||||
|
||||
/**
|
||||
* @brief Function for asserting RTS to restart the transmission.
|
||||
*
|
||||
* Flow control must be enabled.
|
||||
*
|
||||
* @param p_libuarte Libuarte_async instance.
|
||||
*/
|
||||
void nrf_libuarte_async_rts_set(const nrf_libuarte_async_t * const p_libuarte);
|
||||
|
||||
/**
|
||||
* @brief Function for sending data asynchronously over UARTE.
|
||||
*
|
||||
* @param[in] p_libuarte Libuarte_async instance.
|
||||
* @param[in] p_data Pointer to data.
|
||||
* @param[in] length Number of bytes to send. Maximum possible length is
|
||||
* dependent on the used SoC (see the MAXCNT register
|
||||
* description in the Product Specification). The library
|
||||
* checks it with assertion.
|
||||
*
|
||||
* @retval NRF_ERROR_BUSY Data is transferring.
|
||||
* @retval NRF_ERROR_INTERNAL Error during configuration.
|
||||
* @retval NRF_SUCCESS Buffer set for sending.
|
||||
*/
|
||||
ret_code_t nrf_libuarte_async_tx(const nrf_libuarte_async_t * const p_libuarte,
|
||||
uint8_t * p_data, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Function for deallocating received buffer data.
|
||||
*
|
||||
* @param[in] p_libuarte Libuarte_async instance.
|
||||
* @param[in] p_data Pointer to data.
|
||||
* @param[in] length Number of bytes to free.
|
||||
*/
|
||||
void nrf_libuarte_async_rx_free(const nrf_libuarte_async_t * const p_libuarte,
|
||||
uint8_t * p_data, size_t length);
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif //UART_ASYNC_H
|
||||
868
components/libraries/libuarte/nrf_libuarte_drv.c
Normal file
868
components/libraries/libuarte/nrf_libuarte_drv.c
Normal file
@@ -0,0 +1,868 @@
|
||||
/**
|
||||
* Copyright (c) 2019 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
#include "sdk_config.h"
|
||||
#include "nrf_libuarte_drv.h"
|
||||
#include "nrf_uarte.h"
|
||||
#include "nrf_gpio.h"
|
||||
#include <nrfx_gpiote.h>
|
||||
#include <../src/prs/nrfx_prs.h>
|
||||
|
||||
#define NRF_LOG_MODULE_NAME libUARTE
|
||||
#if NRF_LIBUARTE_CONFIG_LOG_ENABLED
|
||||
#define NRF_LOG_LEVEL NRF_LIBUARTE_CONFIG_LOG_LEVEL
|
||||
#define NRF_LOG_INFO_COLOR NRF_LIBUARTE_CONFIG_INFO_COLOR
|
||||
#define NRF_LOG_DEBUG_COLOR NRF_LIBUARTE_CONFIG_DEBUG_COLOR
|
||||
#else // NRF_LIBUARTE_CONFIG_LOG_ENABLED
|
||||
#define NRF_LOG_LEVEL 0
|
||||
#endif // NRF_LIBUARTE_CONFIG_LOG_ENABLED
|
||||
#include "nrf_log.h"
|
||||
NRF_LOG_MODULE_REGISTER();
|
||||
|
||||
#define MAX_DMA_XFER_LEN ((1UL << UARTE0_EASYDMA_MAXCNT_SIZE) - 1)
|
||||
|
||||
#define INTERRUPTS_MASK \
|
||||
(NRF_UARTE_INT_ENDRX_MASK | NRF_UARTE_INT_RXSTARTED_MASK | NRF_UARTE_INT_ERROR_MASK | \
|
||||
NRF_UARTE_INT_ENDTX_MASK | NRF_UARTE_INT_TXSTOPPED_MASK)
|
||||
|
||||
static const nrf_libuarte_drv_t * m_libuarte_instance[2];
|
||||
|
||||
/* if it is defined it means that PRS for uart is not used. */
|
||||
#ifdef nrfx_uarte_0_irq_handler
|
||||
#define libuarte_0_irq_handler UARTE0_UART0_IRQHandler
|
||||
#endif
|
||||
|
||||
#if NRFX_CHECK(NRF_LIBUARTE_DRV_UARTE0)
|
||||
void libuarte_0_irq_handler(void);
|
||||
#endif
|
||||
|
||||
#if NRFX_CHECK(NRF_LIBUARTE_DRV_UARTE1)
|
||||
void libuarte_1_irq_handler(void);
|
||||
#endif
|
||||
|
||||
#if defined(NRF_LIBUARTE_DRV_HWFC_ENABLED)
|
||||
#define LIBUARTE_DRV_WITH_HWFC NRF_LIBUARTE_DRV_HWFC_ENABLED
|
||||
#else
|
||||
#define LIBUARTE_DRV_WITH_HWFC 1
|
||||
#endif
|
||||
|
||||
#define RTS_PIN_DISABLED 0xff
|
||||
|
||||
/** @brief Macro executes given function on every allocated channel in the list between provided
|
||||
* indexes.
|
||||
*/
|
||||
#define PPI_CHANNEL_FOR_M_N(p_libuarte, m, n, func) \
|
||||
for (int i = m; i < n; i++) \
|
||||
{ \
|
||||
if (p_libuarte->ctrl_blk->ppi_channels[i] < PPI_CH_NUM) \
|
||||
{ func(&p_libuarte->ctrl_blk->ppi_channels[i]); } \
|
||||
}
|
||||
|
||||
/** @brief Macro executes provided function on every allocated PPI channel. */
|
||||
#define PPI_CHANNEL_FOR_ALL(p_libuarte, func) \
|
||||
PPI_CHANNEL_FOR_M_N(p_libuarte, 0, NRF_LIBUARTE_DRV_PPI_CH_MAX, func)
|
||||
|
||||
/** @brief Macro executes provided function on every allocated group in the list. */
|
||||
#define PPI_GROUP_FOR_ALL(p_libuarte, func) \
|
||||
for (int i = 0; i < NRF_LIBUARTE_DRV_PPI_GROUP_MAX; i++) \
|
||||
{ \
|
||||
if (p_libuarte->ctrl_blk->ppi_groups[i] < PPI_GROUP_NUM) \
|
||||
{ func(&p_libuarte->ctrl_blk->ppi_groups[i]); } \
|
||||
}
|
||||
|
||||
/** @brief Allocate and configure PPI channel. Fork is optional and it's not set if NULL.
|
||||
* Channel parameter is field by the function.
|
||||
*/
|
||||
static ret_code_t ppi_channel_configure(nrf_ppi_channel_t * p_ch, uint32_t evt,
|
||||
uint32_t task, uint32_t fork)
|
||||
{
|
||||
nrfx_err_t err;
|
||||
|
||||
err = nrfx_ppi_channel_alloc(p_ch);
|
||||
if (err != NRFX_SUCCESS)
|
||||
{
|
||||
return NRF_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
err = nrfx_ppi_channel_assign(*p_ch, evt, task);
|
||||
if (err != NRFX_SUCCESS)
|
||||
{
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
if (fork)
|
||||
{
|
||||
err = nrfx_ppi_channel_fork_assign(*p_ch, fork);
|
||||
if (err != NRFX_SUCCESS)
|
||||
{
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
/** @brief Allocate and configure group with one channel. Fetch addresses of enable/disable tasks.*/
|
||||
static ret_code_t ppi_group_configure(nrf_ppi_channel_group_t * p_ppi_group, nrf_ppi_channel_t ch,
|
||||
uint32_t * p_en_task, uint32_t * p_dis_task, bool en)
|
||||
{
|
||||
nrfx_err_t err;
|
||||
|
||||
err = nrfx_ppi_group_alloc(p_ppi_group);
|
||||
if (err != NRFX_SUCCESS)
|
||||
{
|
||||
return NRF_ERROR_NO_MEM;
|
||||
}
|
||||
|
||||
err = nrfx_ppi_channel_include_in_group(ch, *p_ppi_group);
|
||||
if (err != NRFX_SUCCESS)
|
||||
{
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
if (en)
|
||||
{
|
||||
err = nrfx_ppi_group_enable(*p_ppi_group);
|
||||
if (err != NRFX_SUCCESS)
|
||||
{
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
*p_en_task = nrfx_ppi_task_addr_group_enable_get(*p_ppi_group);
|
||||
*p_dis_task = nrfx_ppi_task_addr_group_disable_get(*p_ppi_group);
|
||||
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
/** @brief Disable and free PPI channel. */
|
||||
static void ppi_ch_free(nrf_ppi_channel_t * p_ch)
|
||||
{
|
||||
nrfx_err_t err;
|
||||
err = nrfx_ppi_channel_disable(*p_ch);
|
||||
ASSERT(err == NRFX_SUCCESS);
|
||||
err = nrfx_ppi_channel_free(*p_ch);
|
||||
ASSERT(err == NRFX_SUCCESS);
|
||||
*p_ch = (nrf_ppi_channel_t)PPI_CH_NUM;
|
||||
}
|
||||
|
||||
/** @brief Disable and free PPI group. */
|
||||
static void ppi_group_free(nrf_ppi_channel_group_t * p_group)
|
||||
{
|
||||
nrfx_err_t err;
|
||||
err = nrfx_ppi_group_free(*p_group);
|
||||
ASSERT(err == NRFX_SUCCESS);
|
||||
*p_group = (nrf_ppi_channel_group_t)PPI_GROUP_NUM;
|
||||
|
||||
}
|
||||
|
||||
/** @brief Free all channels. */
|
||||
static void ppi_free(const nrf_libuarte_drv_t * const p_libuarte)
|
||||
{
|
||||
PPI_CHANNEL_FOR_ALL(p_libuarte, ppi_ch_free);
|
||||
PPI_GROUP_FOR_ALL(p_libuarte, ppi_group_free);
|
||||
}
|
||||
|
||||
/** @brief Enable PPI channel. */
|
||||
static void ppi_ch_enable(nrf_ppi_channel_t * p_ch)
|
||||
{
|
||||
nrfx_err_t err;
|
||||
err = nrfx_ppi_channel_enable(*p_ch);
|
||||
ASSERT(err == NRFX_SUCCESS);
|
||||
}
|
||||
|
||||
/** @brief Disable PPI channel. */
|
||||
static void ppi_ch_disable(nrf_ppi_channel_t * p_ch)
|
||||
{
|
||||
nrfx_err_t err;
|
||||
err = nrfx_ppi_channel_disable(*p_ch);
|
||||
ASSERT(err == NRFX_SUCCESS);
|
||||
}
|
||||
|
||||
/** @brief Enable PPI channels for RX. */
|
||||
static void rx_ppi_enable(const nrf_libuarte_drv_t * const p_libuarte)
|
||||
{
|
||||
PPI_CHANNEL_FOR_M_N(p_libuarte, 0, NRF_LIBUARTE_DRV_PPI_CH_RX_GROUP_MAX, ppi_ch_enable);
|
||||
}
|
||||
|
||||
/** @brief Disable PPI channels for RX. */
|
||||
static void rx_ppi_disable(const nrf_libuarte_drv_t * const p_libuarte)
|
||||
{
|
||||
PPI_CHANNEL_FOR_M_N(p_libuarte, 0, NRF_LIBUARTE_DRV_PPI_CH_RX_GROUP_MAX, ppi_ch_disable);
|
||||
}
|
||||
|
||||
/** @brief Enable PPI channels for TX. */
|
||||
static void tx_ppi_enable(const nrf_libuarte_drv_t * const p_libuarte)
|
||||
{
|
||||
PPI_CHANNEL_FOR_M_N(p_libuarte, NRF_LIBUARTE_DRV_PPI_CH_RX_GROUP_MAX,
|
||||
NRF_LIBUARTE_DRV_PPI_CH_MAX, ppi_ch_enable);
|
||||
}
|
||||
|
||||
/** @brief Disable PPI channels for TX. */
|
||||
static void tx_ppi_disable(const nrf_libuarte_drv_t * const p_libuarte)
|
||||
{
|
||||
PPI_CHANNEL_FOR_M_N(p_libuarte, NRF_LIBUARTE_DRV_PPI_CH_RX_GROUP_MAX,
|
||||
NRF_LIBUARTE_DRV_PPI_CH_MAX, ppi_ch_disable);
|
||||
}
|
||||
|
||||
static ret_code_t ppi_configure(const nrf_libuarte_drv_t * const p_libuarte,
|
||||
nrf_libuarte_drv_config_t * p_config)
|
||||
{
|
||||
ret_code_t ret;
|
||||
uint32_t gr0_en_task = 0;
|
||||
uint32_t gr0_dis_task = 0;
|
||||
uint32_t gr1_en_task = 0;
|
||||
uint32_t gr1_dis_task = 0;
|
||||
|
||||
for (int i = 0; i < NRF_LIBUARTE_DRV_PPI_CH_MAX; i++)
|
||||
{
|
||||
/* set to invalid value */
|
||||
p_libuarte->ctrl_blk->ppi_channels[i] = (nrf_ppi_channel_t)PPI_CH_NUM;
|
||||
}
|
||||
|
||||
for (int i = 0; i < NRF_LIBUARTE_DRV_PPI_GROUP_MAX; i++)
|
||||
{
|
||||
/* set to invalid value */
|
||||
p_libuarte->ctrl_blk->ppi_groups[i] = (nrf_ppi_channel_group_t)PPI_GROUP_NUM;
|
||||
}
|
||||
|
||||
if (MAX_DMA_XFER_LEN < UINT16_MAX)
|
||||
{
|
||||
ret = ppi_channel_configure(
|
||||
&p_libuarte->ctrl_blk->ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_ENDTX_STARTTX],
|
||||
nrf_uarte_event_address_get(p_libuarte->uarte, NRF_UARTE_EVENT_ENDTX),
|
||||
nrf_uarte_task_address_get(p_libuarte->uarte, NRF_UARTE_TASK_STARTTX),
|
||||
0);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
goto complete_config;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ppi_channel_configure(
|
||||
&p_libuarte->ctrl_blk->ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_RXRDY_TIMER_COUNT],
|
||||
nrf_uarte_event_address_get(p_libuarte->uarte, NRF_UARTE_EVENT_RXDRDY),
|
||||
nrfx_timer_task_address_get(&p_libuarte->timer, NRF_TIMER_TASK_COUNT),
|
||||
0);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
goto complete_config;
|
||||
}
|
||||
|
||||
ret = ppi_channel_configure(
|
||||
&p_libuarte->ctrl_blk->ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_ENDRX_STARTRX],
|
||||
nrf_uarte_event_address_get(p_libuarte->uarte, NRF_UARTE_EVENT_ENDRX),
|
||||
nrf_uarte_task_address_get(p_libuarte->uarte, NRF_UARTE_TASK_STARTRX),
|
||||
nrfx_timer_capture_task_address_get(&p_libuarte->timer, 0));
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
goto complete_config;
|
||||
}
|
||||
|
||||
if (p_config->endrx_evt && p_config->rxdone_tsk)
|
||||
{
|
||||
ret = ppi_channel_configure(
|
||||
&p_libuarte->ctrl_blk->ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_ENDRX_EXT_TSK],
|
||||
nrf_uarte_event_address_get(p_libuarte->uarte, NRF_UARTE_EVENT_ENDRX),
|
||||
nrfx_timer_capture_task_address_get(&p_libuarte->timer, 0),
|
||||
p_config->rxdone_tsk);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
goto complete_config;
|
||||
}
|
||||
|
||||
ret = ppi_group_configure(&p_libuarte->ctrl_blk->ppi_groups[NRF_LIBUARTE_DRV_PPI_GROUP_ENDRX_STARTRX],
|
||||
p_libuarte->ctrl_blk->ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_ENDRX_STARTRX],
|
||||
&gr0_en_task, &gr0_dis_task, true);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
goto complete_config;
|
||||
}
|
||||
|
||||
ret = ppi_group_configure(&p_libuarte->ctrl_blk->ppi_groups[NRF_LIBUARTE_DRV_PPI_GROUP_ENDRX_EXT_RXDONE_TSK],
|
||||
p_libuarte->ctrl_blk->ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_ENDRX_EXT_TSK],
|
||||
&gr1_en_task, &gr1_dis_task, false);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
goto complete_config;
|
||||
}
|
||||
|
||||
ret = ppi_channel_configure(
|
||||
&p_libuarte->ctrl_blk->ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_EXT_STOP_STOPRX],
|
||||
p_config->endrx_evt,
|
||||
nrf_uarte_task_address_get(p_libuarte->uarte, NRF_UARTE_TASK_STOPRX),
|
||||
nrfx_timer_capture_task_address_get(&p_libuarte->timer, 1));
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
goto complete_config;
|
||||
}
|
||||
|
||||
ret = ppi_channel_configure(
|
||||
&p_libuarte->ctrl_blk->ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_EXT_STOP_GROUPS_EN],
|
||||
p_config->endrx_evt,
|
||||
gr0_dis_task,
|
||||
gr1_en_task);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
goto complete_config;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_config->rxstarted_tsk || gr1_dis_task)
|
||||
{
|
||||
ret = ppi_channel_configure(
|
||||
&p_libuarte->ctrl_blk->ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_RXSTARTED_EXT_TSK],
|
||||
nrf_uarte_event_address_get(p_libuarte->uarte, NRF_UARTE_EVENT_RXSTARTED),
|
||||
gr1_dis_task ? gr1_dis_task : p_config->rxstarted_tsk,
|
||||
gr1_dis_task ? p_config->rxstarted_tsk : 0);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
goto complete_config;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_config->startrx_evt)
|
||||
{
|
||||
ret = ppi_channel_configure(
|
||||
&p_libuarte->ctrl_blk->ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_EXT_TRIGGER_STARTRX_EN_ENDRX_STARTX],
|
||||
p_config->startrx_evt,
|
||||
nrf_uarte_task_address_get(p_libuarte->uarte, NRF_UARTE_TASK_STARTRX),
|
||||
gr0_en_task);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
goto complete_config;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_config->endrx_evt)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (LIBUARTE_DRV_WITH_HWFC && (p_config->rts_pin != NRF_UARTE_PSEL_DISCONNECTED))
|
||||
{
|
||||
ret = ppi_channel_configure(&p_libuarte->ctrl_blk->ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_RTS_PIN],
|
||||
nrfx_timer_compare_event_address_get(&p_libuarte->timer, 2),
|
||||
nrfx_gpiote_set_task_addr_get(p_config->rts_pin),
|
||||
0);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
goto complete_config;
|
||||
}
|
||||
}
|
||||
|
||||
complete_config:
|
||||
if (ret == NRF_SUCCESS)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ppi_free(p_libuarte);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void tmr_evt_handler(nrf_timer_event_t event_type, void * p_context)
|
||||
{
|
||||
UNUSED_PARAMETER(event_type);
|
||||
UNUSED_PARAMETER(p_context);
|
||||
}
|
||||
|
||||
ret_code_t nrf_libuarte_drv_init(const nrf_libuarte_drv_t * const p_libuarte,
|
||||
nrf_libuarte_drv_config_t * p_config,
|
||||
nrf_libuarte_drv_evt_handler_t evt_handler,
|
||||
void * context)
|
||||
{
|
||||
ret_code_t ret;
|
||||
IRQn_Type irqn = nrfx_get_irq_number(p_libuarte->uarte);
|
||||
|
||||
if (p_libuarte->ctrl_blk->enabled)
|
||||
{
|
||||
return NRF_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
p_libuarte->ctrl_blk->evt_handler = evt_handler;
|
||||
p_libuarte->ctrl_blk->p_cur_rx = NULL;
|
||||
p_libuarte->ctrl_blk->p_next_rx = NULL;
|
||||
p_libuarte->ctrl_blk->p_next_next_rx = NULL;
|
||||
p_libuarte->ctrl_blk->p_tx = NULL;
|
||||
p_libuarte->ctrl_blk->context = context;
|
||||
p_libuarte->ctrl_blk->rts_pin = RTS_PIN_DISABLED;
|
||||
|
||||
m_libuarte_instance[p_libuarte->uarte == NRF_UARTE0 ? 0 : 1] = p_libuarte;
|
||||
|
||||
//UART init
|
||||
nrf_gpio_pin_set(p_config->tx_pin);
|
||||
nrf_gpio_cfg_output(p_config->tx_pin);
|
||||
nrf_gpio_cfg_input(p_config->rx_pin, p_config->pullup_rx ?
|
||||
NRF_GPIO_PIN_PULLUP : NRF_GPIO_PIN_NOPULL);
|
||||
nrf_uarte_baudrate_set(p_libuarte->uarte, p_config->baudrate);
|
||||
nrf_uarte_configure(p_libuarte->uarte, p_config->parity, p_config->hwfc);
|
||||
nrf_uarte_txrx_pins_set(p_libuarte->uarte, p_config->tx_pin, p_config->rx_pin);
|
||||
|
||||
if (LIBUARTE_DRV_WITH_HWFC && (p_config->hwfc == NRF_UARTE_HWFC_ENABLED))
|
||||
{
|
||||
if (p_config->cts_pin != NRF_UARTE_PSEL_DISCONNECTED)
|
||||
{
|
||||
nrf_gpio_cfg_input(p_config->cts_pin, NRF_GPIO_PIN_PULLUP);
|
||||
}
|
||||
if (p_config->rts_pin != NRF_UARTE_PSEL_DISCONNECTED)
|
||||
{
|
||||
nrfx_gpiote_out_config_t out_config = NRFX_GPIOTE_CONFIG_OUT_TASK_TOGGLE(true);
|
||||
|
||||
nrfx_err_t err = nrfx_gpiote_init();
|
||||
if ((err != NRFX_SUCCESS) && (err != NRFX_ERROR_INVALID_STATE))
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
err = nrfx_gpiote_out_init(p_config->rts_pin, &out_config);
|
||||
if (err != NRFX_SUCCESS)
|
||||
{
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
nrfx_gpiote_out_task_enable(p_config->rts_pin);
|
||||
nrf_gpio_cfg_output(p_config->rts_pin);
|
||||
p_libuarte->ctrl_blk->rts_pin = p_config->rts_pin;
|
||||
}
|
||||
|
||||
nrf_uarte_hwfc_pins_set(p_libuarte->uarte, NRF_UARTE_PSEL_DISCONNECTED, p_config->cts_pin);
|
||||
}
|
||||
else if ((p_config->hwfc == NRF_UARTE_HWFC_ENABLED) && !LIBUARTE_DRV_WITH_HWFC)
|
||||
{
|
||||
return NRFX_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
#if NRFX_CHECK(NRFX_PRS_ENABLED) && NRFX_CHECK(NRF_LIBUARTE_DRV_UARTE0)
|
||||
if (irqn == UARTE0_UART0_IRQn)
|
||||
{
|
||||
if (nrfx_prs_acquire(p_libuarte->uarte, libuarte_0_irq_handler) != NRFX_SUCCESS)
|
||||
{
|
||||
return NRF_ERROR_BUSY;
|
||||
}
|
||||
}
|
||||
#endif // NRFX_CHECK(NRFX_PRS_ENABLED) && NRFX_CHECK(NRF_LIBUARTE_DRV_UARTE0)
|
||||
|
||||
nrf_uarte_int_enable(p_libuarte->uarte, INTERRUPTS_MASK);
|
||||
|
||||
NVIC_SetPriority(irqn, p_config->irq_priority);
|
||||
NVIC_ClearPendingIRQ(irqn);
|
||||
NVIC_EnableIRQ(irqn);
|
||||
|
||||
nrf_uarte_enable(p_libuarte->uarte);
|
||||
|
||||
nrfx_timer_config_t tmr_config = NRFX_TIMER_DEFAULT_CONFIG;
|
||||
tmr_config.mode = NRF_TIMER_MODE_COUNTER;
|
||||
tmr_config.bit_width = NRF_TIMER_BIT_WIDTH_32;
|
||||
ret = nrfx_timer_init(&p_libuarte->timer, &tmr_config, tmr_evt_handler);
|
||||
if (ret != NRFX_SUCCESS)
|
||||
{
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
ret = ppi_configure(p_libuarte, p_config);
|
||||
if (ret != NRF_SUCCESS)
|
||||
{
|
||||
return NRF_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
p_libuarte->ctrl_blk->enabled = true;
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
void nrf_libuarte_drv_uninit(const nrf_libuarte_drv_t * const p_libuarte)
|
||||
{
|
||||
IRQn_Type irqn = nrfx_get_irq_number(p_libuarte->uarte);
|
||||
|
||||
if (p_libuarte->ctrl_blk->enabled == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
p_libuarte->ctrl_blk->enabled = false;
|
||||
|
||||
NVIC_DisableIRQ(irqn);
|
||||
|
||||
rx_ppi_disable(p_libuarte);
|
||||
tx_ppi_disable(p_libuarte);
|
||||
|
||||
nrf_uarte_int_disable(p_libuarte->uarte, 0xFFFFFFFF);
|
||||
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTOPPED);
|
||||
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_RXTO);
|
||||
|
||||
nrf_uarte_task_trigger(p_libuarte->uarte, NRF_UARTE_TASK_STOPTX);
|
||||
nrf_uarte_task_trigger(p_libuarte->uarte, NRF_UARTE_TASK_STOPRX);
|
||||
|
||||
while ( (p_libuarte->ctrl_blk->p_tx && !nrf_uarte_event_check(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTOPPED)) ||
|
||||
(p_libuarte->ctrl_blk->p_cur_rx && !nrf_uarte_event_check(p_libuarte->uarte, NRF_UARTE_EVENT_RXTO)))
|
||||
{}
|
||||
|
||||
p_libuarte->ctrl_blk->p_tx = NULL;
|
||||
p_libuarte->ctrl_blk->p_cur_rx = NULL;
|
||||
|
||||
nrf_uarte_disable(p_libuarte->uarte);
|
||||
|
||||
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTARTED);
|
||||
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTOPPED);
|
||||
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_ENDTX);
|
||||
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_ENDRX);
|
||||
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_RXSTARTED);
|
||||
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_RXTO);
|
||||
|
||||
#if NRFX_CHECK(NRFX_PRS_ENABLED) && NRFX_CHECK(NRF_LIBUARTE_DRV_UARTE0)
|
||||
if (irqn == UARTE0_UART0_IRQn)
|
||||
{
|
||||
nrfx_prs_release(p_libuarte->uarte);
|
||||
}
|
||||
#endif // NRFX_CHECK(NRFX_PRS_ENABLED) && NRFX_CHECK(NRF_LIBUARTE_DRV_UARTE0)
|
||||
|
||||
nrfx_timer_disable(&p_libuarte->timer);
|
||||
nrfx_timer_uninit(&p_libuarte->timer);
|
||||
|
||||
if (LIBUARTE_DRV_WITH_HWFC && (p_libuarte->ctrl_blk->rts_pin != RTS_PIN_DISABLED))
|
||||
{
|
||||
nrfx_gpiote_out_uninit(p_libuarte->ctrl_blk->rts_pin);
|
||||
}
|
||||
ppi_free(p_libuarte);
|
||||
}
|
||||
|
||||
ret_code_t nrf_libuarte_drv_tx(const nrf_libuarte_drv_t * const p_libuarte,
|
||||
uint8_t * p_data, size_t len)
|
||||
{
|
||||
if (p_libuarte->ctrl_blk->p_tx)
|
||||
{
|
||||
return NRF_ERROR_BUSY;
|
||||
}
|
||||
p_libuarte->ctrl_blk->p_tx = p_data;
|
||||
p_libuarte->ctrl_blk->tx_len = len;
|
||||
p_libuarte->ctrl_blk->tx_cur_idx = 0;
|
||||
uint16_t first_chunk;
|
||||
|
||||
if ((MAX_DMA_XFER_LEN <= UINT16_MAX) && (len <= MAX_DMA_XFER_LEN))
|
||||
{
|
||||
first_chunk = len;
|
||||
p_libuarte->ctrl_blk->tx_chunk8 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t num_of_chunks = CEIL_DIV(len, MAX_DMA_XFER_LEN);
|
||||
p_libuarte->ctrl_blk->tx_chunk8 = len/num_of_chunks;
|
||||
first_chunk = p_libuarte->ctrl_blk->tx_chunk8 + len%p_libuarte->ctrl_blk->tx_chunk8;
|
||||
}
|
||||
|
||||
NRF_LOG_WARNING("Started TX total length:%d, first chunk:%d", len, first_chunk);
|
||||
nrf_uarte_tx_buffer_set(p_libuarte->uarte, p_data, first_chunk);
|
||||
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTARTED);
|
||||
nrf_uarte_task_trigger(p_libuarte->uarte, NRF_UARTE_TASK_STARTTX);
|
||||
|
||||
if ((MAX_DMA_XFER_LEN <= UINT16_MAX) && (len > MAX_DMA_XFER_LEN))
|
||||
{
|
||||
while(nrf_uarte_event_check(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTARTED) == 0)
|
||||
{
|
||||
}
|
||||
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTARTED);
|
||||
tx_ppi_enable(p_libuarte);
|
||||
|
||||
nrf_uarte_tx_buffer_set(p_libuarte->uarte, &p_libuarte->ctrl_blk->p_tx[first_chunk], p_libuarte->ctrl_blk->tx_chunk8);
|
||||
}
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
ret_code_t nrf_libuarte_drv_rx_start(const nrf_libuarte_drv_t * const p_libuarte,
|
||||
uint8_t * p_data, size_t len, bool ext_trigger_en)
|
||||
{
|
||||
ASSERT(len <= MAX_DMA_XFER_LEN);
|
||||
|
||||
if (p_libuarte->ctrl_blk->p_cur_rx)
|
||||
{
|
||||
return NRF_ERROR_BUSY;
|
||||
}
|
||||
|
||||
p_libuarte->ctrl_blk->chunk_size = len;
|
||||
|
||||
if (p_data)
|
||||
{
|
||||
p_libuarte->ctrl_blk->p_cur_rx = p_data;
|
||||
nrf_uarte_rx_buffer_set(p_libuarte->uarte, p_data, len);
|
||||
}
|
||||
|
||||
/* Reset byte counting */
|
||||
nrfx_timer_enable(&p_libuarte->timer);
|
||||
nrfx_timer_clear(&p_libuarte->timer);
|
||||
p_libuarte->ctrl_blk->last_rx_byte_cnt = 0;
|
||||
p_libuarte->ctrl_blk->last_pin_rx_byte_cnt = 0;
|
||||
|
||||
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_ENDRX);
|
||||
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_RXSTARTED);
|
||||
|
||||
rx_ppi_enable(p_libuarte);
|
||||
|
||||
if (LIBUARTE_DRV_WITH_HWFC && (p_libuarte->ctrl_blk->rts_pin != RTS_PIN_DISABLED))
|
||||
{
|
||||
uint32_t rx_limit = len - NRF_LIBUARTE_DRV_HWFC_BYTE_LIMIT;
|
||||
*(uint32_t *)nrfx_gpiote_clr_task_addr_get(p_libuarte->ctrl_blk->rts_pin) = 1;
|
||||
nrfx_timer_compare(&p_libuarte->timer, NRF_TIMER_CC_CHANNEL2, rx_limit, false);
|
||||
}
|
||||
|
||||
if (!ext_trigger_en)
|
||||
{
|
||||
nrf_uarte_task_trigger(p_libuarte->uarte, NRF_UARTE_TASK_STARTRX);
|
||||
}
|
||||
NRF_LOG_DEBUG("Start continues RX. Provided buffer:0x%08X", p_data);
|
||||
return NRF_SUCCESS;
|
||||
}
|
||||
|
||||
void nrf_libuarte_drv_rx_buf_rsp(const nrf_libuarte_drv_t * const p_libuarte,
|
||||
uint8_t * p_data, size_t len)
|
||||
{
|
||||
if (p_libuarte->ctrl_blk->p_next_rx == NULL)
|
||||
{
|
||||
p_libuarte->ctrl_blk->p_next_rx = p_data;
|
||||
NRF_LOG_DEBUG("RX buf response (next). Provided buffer:0x%08X", p_data);
|
||||
nrf_uarte_rx_buffer_set(p_libuarte->uarte, p_data, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
NRF_LOG_DEBUG("RX buf response (mp_next_rx not NULL:0x%08X), Provided buffer:0x%08X",
|
||||
p_libuarte->ctrl_blk->p_next_rx, p_data);
|
||||
p_libuarte->ctrl_blk->p_next_next_rx = p_data;
|
||||
}
|
||||
|
||||
if (LIBUARTE_DRV_WITH_HWFC && (p_libuarte->ctrl_blk->rts_pin != RTS_PIN_DISABLED))
|
||||
{
|
||||
uint32_t rx_limit = nrfx_timer_capture_get(&p_libuarte->timer, NRF_TIMER_CC_CHANNEL0) +
|
||||
2*len - NRF_LIBUARTE_DRV_HWFC_BYTE_LIMIT;
|
||||
nrfx_timer_compare(&p_libuarte->timer, NRF_TIMER_CC_CHANNEL2, rx_limit, false);
|
||||
if (p_libuarte->ctrl_blk->rts_manual == false)
|
||||
{
|
||||
*(uint32_t *)nrfx_gpiote_clr_task_addr_get(p_libuarte->ctrl_blk->rts_pin) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nrf_libuarte_drv_rx_stop(const nrf_libuarte_drv_t * const p_libuarte)
|
||||
{
|
||||
rx_ppi_disable(p_libuarte);
|
||||
|
||||
NRF_LOG_DEBUG("RX stopped.");
|
||||
if (LIBUARTE_DRV_WITH_HWFC && (p_libuarte->ctrl_blk->rts_pin != RTS_PIN_DISABLED))
|
||||
{
|
||||
*(uint32_t *)nrfx_gpiote_set_task_addr_get(p_libuarte->ctrl_blk->rts_pin) = 1;
|
||||
}
|
||||
p_libuarte->ctrl_blk->p_cur_rx = NULL;
|
||||
nrf_uarte_task_trigger(p_libuarte->uarte, NRF_UARTE_TASK_STOPRX);
|
||||
}
|
||||
|
||||
void nrf_libuarte_drv_rts_clear(const nrf_libuarte_drv_t * const p_libuarte)
|
||||
{
|
||||
if (LIBUARTE_DRV_WITH_HWFC && (p_libuarte->ctrl_blk->rts_pin != RTS_PIN_DISABLED))
|
||||
{
|
||||
*(uint32_t *)nrfx_gpiote_clr_task_addr_get(p_libuarte->ctrl_blk->rts_pin) = 1;
|
||||
p_libuarte->ctrl_blk->rts_manual = false;
|
||||
}
|
||||
}
|
||||
|
||||
void nrf_libuarte_drv_rts_set(const nrf_libuarte_drv_t * const p_libuarte)
|
||||
{
|
||||
if (LIBUARTE_DRV_WITH_HWFC && (p_libuarte->ctrl_blk->rts_pin != RTS_PIN_DISABLED))
|
||||
{
|
||||
p_libuarte->ctrl_blk->rts_manual = true;
|
||||
*(uint32_t *)nrfx_gpiote_set_task_addr_get(p_libuarte->ctrl_blk->rts_pin) = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void irq_handler(const nrf_libuarte_drv_t * const p_libuarte)
|
||||
{
|
||||
if (nrf_uarte_event_check(p_libuarte->uarte, NRF_UARTE_EVENT_ERROR))
|
||||
{
|
||||
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_ERROR);
|
||||
nrf_libuarte_drv_evt_t evt = {
|
||||
.type = NRF_LIBUARTE_DRV_EVT_ERROR,
|
||||
.data = { .errorsrc = nrf_uarte_errorsrc_get_and_clear(p_libuarte->uarte) }
|
||||
};
|
||||
p_libuarte->ctrl_blk->evt_handler(p_libuarte->ctrl_blk->context, &evt);
|
||||
}
|
||||
|
||||
if (nrf_uarte_event_check(p_libuarte->uarte, NRF_UARTE_EVENT_RXSTARTED))
|
||||
{
|
||||
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_RXSTARTED);
|
||||
|
||||
nrf_libuarte_drv_evt_t evt = {
|
||||
.type = NRF_LIBUARTE_DRV_EVT_RX_BUF_REQ,
|
||||
};
|
||||
p_libuarte->ctrl_blk->evt_handler(p_libuarte->ctrl_blk->context, &evt);
|
||||
}
|
||||
|
||||
if (nrf_uarte_event_check(p_libuarte->uarte, NRF_UARTE_EVENT_ENDRX))
|
||||
{
|
||||
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_ENDRX);
|
||||
|
||||
uint32_t endrx_byte_cnt = nrfx_timer_capture_get(&p_libuarte->timer, NRF_TIMER_CC_CHANNEL0);
|
||||
uint32_t stop_byte_cnt = nrfx_timer_capture_get(&p_libuarte->timer, NRF_TIMER_CC_CHANNEL1);
|
||||
|
||||
uint32_t dma_amount = endrx_byte_cnt - p_libuarte->ctrl_blk->last_rx_byte_cnt;
|
||||
uint32_t pin_amount = stop_byte_cnt - p_libuarte->ctrl_blk->last_pin_rx_byte_cnt;
|
||||
NRF_LOG_DEBUG("(evt) RX dma_cnt:%d, endrx_cnt:%d, stop_cnt:%d",
|
||||
dma_amount,
|
||||
endrx_byte_cnt,
|
||||
stop_byte_cnt);
|
||||
p_libuarte->ctrl_blk->last_rx_byte_cnt = endrx_byte_cnt;
|
||||
p_libuarte->ctrl_blk->last_pin_rx_byte_cnt = stop_byte_cnt;
|
||||
|
||||
if (dma_amount || pin_amount)
|
||||
{
|
||||
uint32_t chunk0 = (dma_amount > p_libuarte->ctrl_blk->chunk_size) ?
|
||||
p_libuarte->ctrl_blk->chunk_size : dma_amount;
|
||||
uint32_t chunk1 = dma_amount - chunk0;
|
||||
|
||||
NRF_LOG_DEBUG("RX END chunk0:%d, chunk1:%d, data[0]=%d %d",
|
||||
chunk0,
|
||||
chunk1,
|
||||
p_libuarte->ctrl_blk->p_cur_rx[0],
|
||||
p_libuarte->ctrl_blk->p_cur_rx[1]);
|
||||
nrf_libuarte_drv_evt_t evt = {
|
||||
.type = NRF_LIBUARTE_DRV_EVT_RX_DATA,
|
||||
.data = {
|
||||
.rxtx = {
|
||||
.p_data = p_libuarte->ctrl_blk->p_cur_rx,
|
||||
.length = chunk0
|
||||
}
|
||||
}
|
||||
};
|
||||
p_libuarte->ctrl_blk->p_cur_rx = p_libuarte->ctrl_blk->p_next_rx;
|
||||
p_libuarte->ctrl_blk->p_next_rx = NULL;
|
||||
if (p_libuarte->ctrl_blk->p_next_next_rx)
|
||||
{
|
||||
p_libuarte->ctrl_blk->p_next_rx = p_libuarte->ctrl_blk->p_next_next_rx;
|
||||
p_libuarte->ctrl_blk->p_next_next_rx = NULL;
|
||||
nrf_uarte_rx_buffer_set(p_libuarte->uarte,
|
||||
p_libuarte->ctrl_blk->p_next_rx,
|
||||
p_libuarte->ctrl_blk->chunk_size);
|
||||
}
|
||||
p_libuarte->ctrl_blk->evt_handler(p_libuarte->ctrl_blk->context, &evt);
|
||||
|
||||
if ( chunk1 ||
|
||||
((dma_amount == p_libuarte->ctrl_blk->chunk_size) && (endrx_byte_cnt == stop_byte_cnt)))
|
||||
{
|
||||
NRF_LOG_WARNING("RX END Chunk1:%d", chunk1);
|
||||
|
||||
nrf_libuarte_drv_evt_t err_evt = {
|
||||
.type = NRF_LIBUARTE_DRV_EVT_OVERRUN_ERROR,
|
||||
.data = {
|
||||
.overrun_err = {
|
||||
.overrun_length = chunk1
|
||||
}
|
||||
}
|
||||
};
|
||||
p_libuarte->ctrl_blk->evt_handler(p_libuarte->ctrl_blk->context, &err_evt);
|
||||
|
||||
p_libuarte->ctrl_blk->p_cur_rx = p_libuarte->ctrl_blk->p_next_rx;
|
||||
p_libuarte->ctrl_blk->p_next_rx = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nrf_uarte_event_check(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTOPPED))
|
||||
{
|
||||
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTOPPED);
|
||||
nrf_libuarte_drv_evt_t evt = {
|
||||
.type = NRF_LIBUARTE_DRV_EVT_TX_DONE,
|
||||
.data = {
|
||||
.rxtx = {
|
||||
.p_data = p_libuarte->ctrl_blk->p_tx,
|
||||
.length = p_libuarte->ctrl_blk->tx_len
|
||||
}
|
||||
}
|
||||
};
|
||||
p_libuarte->ctrl_blk->p_tx = NULL;
|
||||
p_libuarte->ctrl_blk->evt_handler(p_libuarte->ctrl_blk->context, &evt);
|
||||
}
|
||||
|
||||
if (nrf_uarte_event_check(p_libuarte->uarte, NRF_UARTE_EVENT_ENDTX))
|
||||
{
|
||||
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_ENDTX);
|
||||
size_t amount = nrf_uarte_tx_amount_get(p_libuarte->uarte);
|
||||
|
||||
NRF_LOG_DEBUG("(evt) TX completed (%d)", amount);
|
||||
p_libuarte->ctrl_blk->tx_cur_idx += amount;
|
||||
if (p_libuarte->ctrl_blk->tx_cur_idx == p_libuarte->ctrl_blk->tx_len)
|
||||
{
|
||||
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTOPPED);
|
||||
nrf_uarte_task_trigger(p_libuarte->uarte, NRF_UARTE_TASK_STOPTX);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t rem_len = (p_libuarte->ctrl_blk->tx_len - p_libuarte->ctrl_blk->tx_cur_idx);
|
||||
if ( rem_len <= MAX_DMA_XFER_LEN)
|
||||
{
|
||||
tx_ppi_disable(p_libuarte);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t * p_buffer = &p_libuarte->ctrl_blk->p_tx[
|
||||
p_libuarte->ctrl_blk->tx_cur_idx +
|
||||
p_libuarte->ctrl_blk->tx_chunk8];
|
||||
if (nrf_uarte_event_check(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTARTED) == 0)
|
||||
{
|
||||
NRF_LOG_ERROR("Tx not started yet!");
|
||||
ASSERT(false);
|
||||
}
|
||||
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTARTED);
|
||||
nrf_uarte_tx_buffer_set(p_libuarte->uarte,
|
||||
p_buffer,
|
||||
p_libuarte->ctrl_blk->tx_chunk8);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if NRF_LIBUARTE_DRV_UARTE0
|
||||
void libuarte_0_irq_handler(void)
|
||||
{
|
||||
irq_handler(m_libuarte_instance[0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NRF_LIBUARTE_DRV_UARTE1
|
||||
void UARTE1_IRQHandler(void)
|
||||
{
|
||||
irq_handler(m_libuarte_instance[1]);
|
||||
}
|
||||
#endif
|
||||
279
components/libraries/libuarte/nrf_libuarte_drv.h
Normal file
279
components/libraries/libuarte/nrf_libuarte_drv.h
Normal file
@@ -0,0 +1,279 @@
|
||||
/**
|
||||
* Copyright (c) 2018 - 2020, Nordic Semiconductor ASA
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form, except as embedded into a Nordic
|
||||
* Semiconductor ASA integrated circuit in a product or a software update for
|
||||
* such product, must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other
|
||||
* materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* 4. This software, with or without modification, must only be used with a
|
||||
* Nordic Semiconductor ASA integrated circuit.
|
||||
*
|
||||
* 5. Any software provided in binary form under this license must not be reverse
|
||||
* engineered, decompiled, modified and/or disassembled.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
#ifndef NRF_LIBUARTE_DRV_H
|
||||
#define NRF_LIBUARTE_DRV_H
|
||||
|
||||
#include "sdk_errors.h"
|
||||
#include "nrf_uarte.h"
|
||||
#include "nrfx_ppi.h"
|
||||
#include "nrfx_timer.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* @defgroup nrf_libuarte_drv libUARTE driver
|
||||
* @ingroup app_common
|
||||
*
|
||||
* @brief Module for reliable communication over UARTE.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* Number of bytes available in the buffer when RTS line is set. */
|
||||
#define NRF_LIBUARTE_DRV_HWFC_BYTE_LIMIT 4
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NRF_LIBUARTE_DRV_EVT_RX_DATA, ///< Data received.
|
||||
NRF_LIBUARTE_DRV_EVT_RX_BUF_REQ, ///< Requesting new buffer for receiving data.
|
||||
NRF_LIBUARTE_DRV_EVT_TX_DONE, ///< Requested TX transfer completed.
|
||||
NRF_LIBUARTE_DRV_EVT_ERROR, ///< Error reported by the UARTE peripheral.
|
||||
NRF_LIBUARTE_DRV_EVT_OVERRUN_ERROR ///< Error reported by the driver.
|
||||
} nrf_libuarte_drv_evt_type_t;
|
||||
|
||||
/**
|
||||
* @brief PPI channels used by libuarte
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NRF_LIBUARTE_DRV_PPI_CH_EXT_TRIGGER_STARTRX_EN_ENDRX_STARTX,
|
||||
NRF_LIBUARTE_DRV_PPI_CH_RXSTARTED_EXT_TSK,
|
||||
NRF_LIBUARTE_DRV_PPI_CH_EXT_STOP_STOPRX,
|
||||
NRF_LIBUARTE_DRV_PPI_CH_EXT_STOP_GROUPS_EN,
|
||||
NRF_LIBUARTE_DRV_PPI_CH_RXRDY_TIMER_COUNT,
|
||||
|
||||
NRF_LIBUARTE_DRV_PPI_CH_ENDRX_STARTRX,
|
||||
NRF_LIBUARTE_DRV_PPI_CH_ENDRX_EXT_TSK,
|
||||
|
||||
NRF_LIBUARTE_DRV_PPI_CH_RTS_PIN,
|
||||
NRF_LIBUARTE_DRV_PPI_CH_RX_MAX,
|
||||
NRF_LIBUARTE_DRV_PPI_CH_RX_GROUP_MAX = NRF_LIBUARTE_DRV_PPI_CH_RX_MAX,
|
||||
|
||||
NRF_LIBUARTE_DRV_PPI_CH_ENDTX_STARTTX = NRF_LIBUARTE_DRV_PPI_CH_RX_GROUP_MAX,
|
||||
|
||||
NRF_LIBUARTE_DRV_PPI_CH_MAX
|
||||
} nrf_libuarte_drv_ppi_channel_t;
|
||||
|
||||
/**
|
||||
* @brief PPI groups used by libuarte
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NRF_LIBUARTE_DRV_PPI_GROUP_ENDRX_STARTRX, ///< Group used for controlling PPI connection between ENDRX and STARTRX
|
||||
NRF_LIBUARTE_DRV_PPI_GROUP_ENDRX_EXT_RXDONE_TSK, ///< Group used for controlling PPI connection between ENDRX and RXDONE
|
||||
NRF_LIBUARTE_DRV_PPI_GROUP_MAX
|
||||
} nrf_libuarte_drv_ppi_group_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t * p_data; ///< Pointer to the data to be sent or received.
|
||||
size_t length; ///< Length of the data.
|
||||
} nrf_libuarte_drv_data_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t overrun_length;
|
||||
} nrf_libuarte_drv_overrun_err_evt_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
nrf_libuarte_drv_evt_type_t type; ///< Event type.
|
||||
union {
|
||||
nrf_libuarte_drv_data_t rxtx; ///< Data provided for transfer completion events.
|
||||
uint8_t errorsrc; ///< Error source flags.
|
||||
nrf_libuarte_drv_overrun_err_evt_t overrun_err; ///< SW Error structure.
|
||||
} data;
|
||||
} nrf_libuarte_drv_evt_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t tx_pin; ///< TXD pin number.
|
||||
uint32_t rx_pin; ///< RXD pin number.
|
||||
uint32_t cts_pin; ///< CTS pin number.
|
||||
uint32_t rts_pin; ///< RTS pin number.
|
||||
uint32_t startrx_evt; ///< Event to trigger STARTRX task in UARTE.
|
||||
uint32_t endrx_evt; ///< Event to trigger STOPRX task in UARTE.
|
||||
uint32_t rxstarted_tsk; ///< Task to be triggered when RXSTARTED UARTE event occurs.
|
||||
uint32_t rxdone_tsk; ///< Task to be triggered when ENDRX UARTE event occurs.
|
||||
nrf_uarte_hwfc_t hwfc; ///< Flow control configuration.
|
||||
nrf_uarte_parity_t parity; ///< Parity configuration.
|
||||
nrf_uarte_baudrate_t baudrate; ///< Baud rate.
|
||||
uint8_t irq_priority; ///< Interrupt priority.
|
||||
bool pullup_rx; ///< Pull up on RX pin.
|
||||
} nrf_libuarte_drv_config_t;
|
||||
|
||||
typedef void (*nrf_libuarte_drv_evt_handler_t)(void * context,
|
||||
nrf_libuarte_drv_evt_t * p_evt);
|
||||
|
||||
extern const IRQn_Type libuarte_irqn[];
|
||||
|
||||
typedef struct {
|
||||
nrf_ppi_channel_t ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_MAX];
|
||||
nrf_ppi_channel_group_t ppi_groups[NRF_LIBUARTE_DRV_PPI_GROUP_MAX];
|
||||
|
||||
uint8_t * p_tx;
|
||||
size_t tx_len;
|
||||
size_t tx_cur_idx;
|
||||
|
||||
uint8_t * p_cur_rx;
|
||||
uint8_t * p_next_rx;
|
||||
uint8_t * p_next_next_rx;
|
||||
nrf_libuarte_drv_evt_handler_t evt_handler;
|
||||
uint32_t last_rx_byte_cnt;
|
||||
uint32_t last_pin_rx_byte_cnt;
|
||||
uint32_t chunk_size;
|
||||
void * context;
|
||||
uint16_t tx_chunk8;
|
||||
uint8_t rts_pin;
|
||||
bool rts_manual;
|
||||
bool enabled;
|
||||
} nrf_libuarte_drv_ctrl_blk_t;
|
||||
|
||||
typedef struct {
|
||||
nrf_libuarte_drv_ctrl_blk_t * ctrl_blk;
|
||||
nrfx_timer_t timer;
|
||||
NRF_UARTE_Type * uarte;
|
||||
} nrf_libuarte_drv_t;
|
||||
|
||||
#define NRF_LIBUARTE_DRV_DEFINE(_name, _uarte_idx, _timer_idx) \
|
||||
STATIC_ASSERT(_uarte_idx < UARTE_COUNT, "UARTE instance not present");\
|
||||
STATIC_ASSERT(CONCAT_2(NRF_LIBUARTE_DRV_UARTE,_uarte_idx) == 1, "UARTE instance not enabled");\
|
||||
STATIC_ASSERT(CONCAT_3(NRFX_TIMER,_timer_idx, _ENABLED) == 1, "Timer instance not enabled");\
|
||||
static nrf_libuarte_drv_ctrl_blk_t CONCAT_2(_name, ctrl_blk); \
|
||||
static const nrf_libuarte_drv_t _name = { \
|
||||
.ctrl_blk = &CONCAT_2(_name, ctrl_blk), \
|
||||
.timer = NRFX_TIMER_INSTANCE(_timer_idx), \
|
||||
.uarte = CONCAT_2(NRF_UARTE, _uarte_idx),\
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function for initializing the libUARTE library.
|
||||
*
|
||||
* @param[in] p_libuarte Pointer to libuarte instance.
|
||||
* @param[in] p_config Pointer to the structure with initial configuration.
|
||||
* @param[in] evt_handler Event handler provided by the user. Must not be NULL.
|
||||
* @param[in] context User context passed in the callback.
|
||||
*
|
||||
* @return NRF_SUCCESS when properly initialized. NRF_ERROR_INTERNAL otherwise.
|
||||
*/
|
||||
ret_code_t nrf_libuarte_drv_init(const nrf_libuarte_drv_t * const p_libuarte,
|
||||
nrf_libuarte_drv_config_t * p_config,
|
||||
nrf_libuarte_drv_evt_handler_t evt_handler, void * context);
|
||||
|
||||
/**
|
||||
* @brief Function for uninitializing the libUARTE library.
|
||||
*
|
||||
* @param[in] p_libuarte Pointer to libuarte instance.
|
||||
*/
|
||||
void nrf_libuarte_drv_uninit(const nrf_libuarte_drv_t * const p_libuarte);
|
||||
|
||||
/**
|
||||
* @brief Function for sending data over UARTE using EasyDMA.
|
||||
*
|
||||
* @param[in] p_libuarte Pointer to libuarte instance.
|
||||
* @param[in] p_data Pointer to data.
|
||||
* @param[in] len Number of bytes to send.
|
||||
*
|
||||
* @retval NRF_ERROR_BUSY Data is transferring.
|
||||
* @retval NRF_ERROR_INTERNAL Error during PPI channel configuration.
|
||||
* @retval NRF_SUCCESS Buffer set for sending.
|
||||
*/
|
||||
ret_code_t nrf_libuarte_drv_tx(const nrf_libuarte_drv_t * const p_libuarte,
|
||||
uint8_t * p_data, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Function for starting receiving data with additional configuration of external
|
||||
* trigger to start receiving.
|
||||
*
|
||||
* @param p_libuarte Pointer to libuarte instance.
|
||||
* @param p_data Pointer to data.
|
||||
* @param len Number of bytes to receive. Maximum possible length is
|
||||
* dependent on the used SoC (see the MAXCNT register
|
||||
* description in the Product Specification). The library
|
||||
* checks it with an assertion.
|
||||
* @param ext_trigger_en True to disable immediate start.
|
||||
*
|
||||
* @retval NRF_ERROR_INTERNAL Error during PPI channel configuration.
|
||||
* @retval NRF_SUCCESS Buffer set for receiving.
|
||||
*/
|
||||
ret_code_t nrf_libuarte_drv_rx_start(const nrf_libuarte_drv_t * const p_libuarte,
|
||||
uint8_t * p_data, size_t len, bool ext_trigger_en);
|
||||
|
||||
/**
|
||||
* @brief Function for setting a buffer for data that will be later received in UARTE.
|
||||
*
|
||||
* @param p_libuarte Pointer to libuarte instance.
|
||||
* @param p_data Pointer to data.
|
||||
* @param len Number of bytes to receive. Maximum possible length is
|
||||
* dependent on the used SoC (see the MAXCNT register
|
||||
* description in the Product Specification). The library
|
||||
* checks it with an assertion.
|
||||
*/
|
||||
void nrf_libuarte_drv_rx_buf_rsp(const nrf_libuarte_drv_t * const p_libuarte,
|
||||
uint8_t * p_data, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Function for stopping receiving data over UARTE.
|
||||
*
|
||||
* @param p_libuarte Pointer to libuarte instance.
|
||||
*/
|
||||
void nrf_libuarte_drv_rx_stop(const nrf_libuarte_drv_t * const p_libuarte);
|
||||
|
||||
/**
|
||||
* @brief Function for deasserting RTS to pause the transmission.
|
||||
*
|
||||
* Flow control must be enabled.
|
||||
*
|
||||
* @param p_libuarte Pointer to libuarte instance.
|
||||
*/
|
||||
void nrf_libuarte_drv_rts_clear(const nrf_libuarte_drv_t * const p_libuarte);
|
||||
|
||||
/**
|
||||
* @brief Function for asserting RTS to restart the transmission.
|
||||
*
|
||||
* Flow control must be enabled.
|
||||
*
|
||||
* @param p_libuarte Pointer to libuarte instance.
|
||||
*/
|
||||
void nrf_libuarte_drv_rts_set(const nrf_libuarte_drv_t * const p_libuarte);
|
||||
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif //NRF_LIBUARTE_DRV_H
|
||||
Reference in New Issue
Block a user