Dear Sir,
we are developing an application on the nRF52840 kit with SDK 15.0.0. We are using Keil as compiler. In our application we need to receive data from two uart together. If we use only one uart the application work fine, but if we add the second uart the firmware have a strange behavior: one of the two uart after a certain time stops to work. The time and the uart that stops are not always the same, it seems casual.
What can happen?
Attached you can find the files main.c, the nrf_serial library and the file sdk_config.h.
Please, help us because we are very worry, we need to complete the project soon.
#include <stdint.h> #include <stdbool.h> #include <stddef.h> #include "nrf.h" #include "nrf_drv_clock.h" #include "nrf_gpio.h" #include "nrf_delay.h" #include "nrf_log.h" #include "nrf_log_ctrl.h" #include "nrf_drv_power.h" #include "nrf_serial.h" #include "app_timer.h" #include "app_error.h" #include "app_util.h" #include "boards.h" /** @file * @defgroup nrf_serial_example main.c * @{ * @ingroup nrf_serial_example * @brief Example of @ref nrf_serial usage. Simple loopback. * */ #define OP_QUEUES_SIZE 3 #define APP_TIMER_PRESCALER NRF_SERIAL_APP_TIMER_PRESCALER static void sleep_handler(void) { __WFE(); __SEV(); __WFE(); } NRF_SERIAL_DRV_UART_CONFIG_DEF ( m_uart0_drv_config, RX_PIN_NUMBER, TX_PIN_NUMBER, RTS_PIN_NUMBER, CTS_PIN_NUMBER, NRF_UART_HWFC_DISABLED, NRF_UART_PARITY_EXCLUDED, NRF_UART_BAUDRATE_9600, UART_DEFAULT_CONFIG_IRQ_PRIORITY); NRF_SERIAL_DRV_UART_CONFIG_DEF ( m_serial_uart_badge_reading_drv_config , 3 , 4 , // Rx pin = P0.03 -- Tx pin = P0.04 RTS_PIN_NUMBER , CTS_PIN_NUMBER , NRF_UART_HWFC_DISABLED , NRF_UART_PARITY_EXCLUDED , NRF_UART_BAUDRATE_115200 , UART_DEFAULT_CONFIG_IRQ_PRIORITY ) ; #define SERIAL_FIFO_TX_SIZE 32 #define SERIAL_FIFO_RX_SIZE 32 NRF_SERIAL_QUEUES_DEF(serial_queues, SERIAL_FIFO_TX_SIZE, SERIAL_FIFO_RX_SIZE); NRF_SERIAL_QUEUES_DEF ( serial_uart_badge_reading_queues , SERIAL_FIFO_TX_SIZE , SERIAL_FIFO_RX_SIZE ) ; #define SERIAL_BUFF_TX_SIZE 1 #define SERIAL_BUFF_RX_SIZE 1 NRF_SERIAL_BUFFERS_DEF(serial_buffs, SERIAL_BUFF_TX_SIZE, SERIAL_BUFF_RX_SIZE); // Configuro i buffer delle seriali NRF_SERIAL_BUFFERS_DEF ( serial_uart_badge_reading_buffs , SERIAL_BUFF_TX_SIZE , SERIAL_BUFF_RX_SIZE ) ; NRF_SERIAL_CONFIG_DEF(serial_config, NRF_SERIAL_MODE_IRQ, &serial_queues, &serial_buffs, NULL, sleep_handler); // Configuro le seriali NRF_SERIAL_CONFIG_DEF ( serial_uart_badge_reading_config , NRF_SERIAL_MODE_IRQ , &serial_uart_badge_reading_queues , &serial_uart_badge_reading_buffs , NULL , sleep_handler ) ; // sostituito NULL ( il secondo ) a sleep_handlerù NRF_SERIAL_UART_DEF ( serial_uart , 0 ) ; NRF_SERIAL_UART_DEF ( serial_uart_badge_reading , 1 ) ; char buff_received_uart_badge [ 30 ] = "" ; char tmp_buff_debug [ 50 ] = "" ; char UID_badge [ 10 ] = "" ; int main(void) { ret_code_t ret ; ret_code_t ret_loop ; ret = nrf_drv_clock_init(); APP_ERROR_CHECK(ret); ret = nrf_drv_power_init(NULL); APP_ERROR_CHECK(ret); nrf_drv_clock_lfclk_request(NULL); ret = app_timer_init(); APP_ERROR_CHECK(ret); // Initialize LEDs and buttons. bsp_board_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS); ret = nrf_serial_init(&serial_uart, &m_uart0_drv_config, &serial_config); APP_ERROR_CHECK(ret); // Inizializzo la seriale ret = nrf_serial_init ( &serial_uart_badge_reading , &m_serial_uart_badge_reading_drv_config , &serial_uart_badge_reading_config ) ; APP_ERROR_CHECK(ret); static char tx_message[] = "Hello nrf_serial 1!\n\r"; ret = nrf_serial_write(&serial_uart, tx_message, strlen(tx_message), NULL, NRF_SERIAL_MAX_TIMEOUT); APP_ERROR_CHECK(ret); while (true) { char a ; /********************* Seriale 1. ********************* */ ret_loop = nrf_serial_read ( &serial_uart_badge_reading , &a , sizeof ( a ) , NULL , 5 ) ; if ( ret_loop == NRF_SUCCESS ) { ( void ) nrf_serial_write ( &serial_uart , &a , sizeof ( a ) , NULL , 0 ) ; nrf_serial_flush ( &serial_uart_badge_reading , 5 ) ; } char c ; /********************* Seriale 2. ********************* */ ret = nrf_serial_read ( &serial_uart , &c , sizeof ( c ) , NULL , 5 ) ; if ( ret == NRF_SUCCESS ) { ( void ) nrf_serial_write ( &serial_uart , &c , sizeof ( c ) , NULL , 0 ) ; nrf_serial_flush ( &serial_uart , 5 ) ; } } } /** @} */
/*$$$LICENCE_NORDIC_STANDARD<2016>$$$*/ #include "sdk_common.h" #if NRF_MODULE_ENABLED(NRF_SERIAL) #include "nrf_serial.h" #if defined (UART_PRESENT) static void event_handler(nrf_serial_t const * p_serial, nrf_serial_event_t event) { if (p_serial->p_ctx->p_config->ev_handler) { p_serial->p_ctx->p_config->ev_handler(p_serial, event); } } static void sleep_handler(nrf_serial_t const * p_serial) { if (p_serial->p_ctx->p_config->mode == NRF_SERIAL_MODE_POLLING) { return; } if (p_serial->p_ctx->p_config->sleep_handler) { p_serial->p_ctx->p_config->sleep_handler(); } } static size_t serial_rx(nrf_serial_t const * p_serial, uint8_t * p_buff, size_t length) { if (p_serial->p_ctx->p_config->mode == NRF_SERIAL_MODE_POLLING) { size_t rx_len = MIN(length, UINT8_MAX); size_t len = rx_len; while (nrfx_uarte_rx_ready(&p_serial->instance) && len) { ret_code_t ret = nrfx_uarte_rx(&p_serial->instance, p_buff, 1); if (ret != NRF_SUCCESS) { break; } p_buff++; len--; } return rx_len - len; } nrf_queue_t const * p_rxq = p_serial->p_ctx->p_config->p_queues->p_rxq; return nrf_queue_out(p_rxq, p_buff, length); } static size_t serial_tx(nrf_serial_t const * p_serial, uint8_t const * p_buff, size_t length) { size_t tx_len = 0; if (p_serial->p_ctx->p_config->mode == NRF_SERIAL_MODE_POLLING) { tx_len = MIN(length, UINT8_MAX); ret_code_t ret = nrfx_uarte_tx(&p_serial->instance, p_buff, tx_len); ASSERT(ret == NRF_SUCCESS) return tx_len; } nrf_queue_t const * p_txq = p_serial->p_ctx->p_config->p_queues->p_txq; nrf_serial_buffers_t const * p_buffs = p_serial->p_ctx->p_config->p_buffers; /* Try to enqueue data. */ size_t queue_in_len = nrf_queue_in(p_txq, p_buff, length); if (nrfx_uarte_tx_in_progress(&p_serial->instance)) { return queue_in_len; } size_t len = nrf_queue_out(p_txq, p_buffs->p_txb, p_buffs->tx_size); ASSERT(len > 0); ret_code_t ret = nrfx_uarte_tx(&p_serial->instance, p_buffs->p_txb, len); ASSERT(ret == NRF_SUCCESS); return queue_in_len; } static void uart_event_handler(nrfx_uarte_event_t const * p_event, void * p_context) { uint32_t ret; nrf_serial_t const * p_serial = p_context; switch (p_event->type) { case NRFX_UARTE_EVT_RX_DONE: { nrf_queue_t const * p_rxq = p_serial->p_ctx->p_config->p_queues->p_rxq; size_t len = nrf_queue_in(p_rxq, p_event->data.rxtx.p_data, p_event->data.rxtx.bytes); if (len < p_event->data.rxtx.bytes) { event_handler(p_serial, NRF_SERIAL_EVENT_FIFO_ERR); break; } event_handler(p_serial, NRF_SERIAL_EVENT_RX_DATA); nrf_serial_buffers_t const * p_buffs = p_serial->p_ctx->p_config->p_buffers; ret = nrfx_uarte_rx(&p_serial->instance, p_buffs->p_rxb, p_buffs->rx_size); ASSERT(ret == NRF_SUCCESS); break; } case NRFX_UARTE_EVT_ERROR: { event_handler(p_serial, NRF_SERIAL_EVENT_DRV_ERR); break; } case NRFX_UARTE_EVT_TX_DONE: { nrf_queue_t const * p_txq = p_serial->p_ctx->p_config->p_queues->p_txq; nrf_serial_buffers_t const * p_buffs = p_serial->p_ctx->p_config->p_buffers; event_handler(p_serial, NRF_SERIAL_EVENT_TX_DONE); size_t len = nrf_queue_out(p_txq, p_buffs->p_txb, p_buffs->tx_size); if (len == 0) { break; } ret = nrfx_uarte_tx(&p_serial->instance, p_buffs->p_txb, len); ASSERT(ret == NRF_SUCCESS); break; } default: break; } } ret_code_t nrf_serial_init(nrf_serial_t const * p_serial, nrfx_uarte_config_t const * p_drv_uart_config, nrf_serial_config_t const * p_config) { ret_code_t ret; ASSERT(p_serial && p_drv_uart_config && p_config); if (p_serial->p_ctx->p_config) { /*Already initialized.*/ return NRF_ERROR_MODULE_ALREADY_INITIALIZED; } if (p_config->mode != NRF_SERIAL_MODE_POLLING) { ASSERT(p_config->p_queues && p_config->p_buffers); } nrfx_uarte_config_t drv_config; memcpy(&drv_config, p_drv_uart_config, sizeof(nrf_drv_uart_config_t)); drv_config.p_context = (void *)p_serial; #if 0 #if defined(UARTE_PRESENT) && defined(UART_PRESENT) drv_config.use_easy_dma = (p_config->mode == NRF_SERIAL_MODE_DMA); #endif #endif ret = nrfx_uarte_init(&p_serial->instance, &drv_config, p_config->mode == NRF_SERIAL_MODE_POLLING ? NULL : uart_event_handler); if (ret != NRF_SUCCESS) { return ret; } p_serial->p_ctx->p_config = p_config; if (p_serial->p_ctx->p_config->p_queues) { nrf_queue_reset(p_serial->p_ctx->p_config->p_queues->p_txq); nrf_queue_reset(p_serial->p_ctx->p_config->p_queues->p_rxq); } nrf_mtx_init(&p_serial->p_ctx->read_lock); nrf_mtx_init(&p_serial->p_ctx->write_lock); p_serial->p_ctx->flags = NRF_SERIAL_RX_ENABLED_FLAG | NRF_SERIAL_TX_ENABLED_FLAG; if (drv_config.pseltxd == NRF_UART_PSEL_DISCONNECTED) { p_serial->p_ctx->flags &= ~NRF_SERIAL_TX_ENABLED_FLAG; } if (drv_config.pselrxd == NRF_UART_PSEL_DISCONNECTED) { p_serial->p_ctx->flags &= ~NRF_SERIAL_RX_ENABLED_FLAG; return NRF_SUCCESS; } #if 0 if (p_serial->p_ctx->p_config->mode != NRF_SERIAL_MODE_DMA) { nrfx_uart_rx_enable(&p_serial->instance); if (p_serial->p_ctx->p_config->mode == NRF_SERIAL_MODE_POLLING) { return NRF_SUCCESS; } } #endif return nrfx_uarte_rx(&p_serial->instance, p_serial->p_ctx->p_config->p_buffers->p_rxb, p_serial->p_ctx->p_config->p_buffers->rx_size); } ret_code_t nrf_serial_uninit(nrf_serial_t const * p_serial) { ASSERT(p_serial); if (!p_serial->p_ctx->p_config) { /*Already uninitialized.*/ return NRF_ERROR_MODULE_NOT_INITIALIZED; } if (!nrf_mtx_trylock(&p_serial->p_ctx->write_lock)) { return NRF_ERROR_BUSY; } if (!nrf_mtx_trylock(&p_serial->p_ctx->read_lock)) { nrf_mtx_unlock(&p_serial->p_ctx->write_lock); return NRF_ERROR_BUSY; } nrfx_uarte_uninit(&p_serial->instance); if (p_serial->p_ctx->p_config->p_queues) { nrf_queue_reset(p_serial->p_ctx->p_config->p_queues->p_txq); nrf_queue_reset(p_serial->p_ctx->p_config->p_queues->p_rxq); } memset(p_serial->p_ctx, 0, sizeof(nrf_serial_ctx_t)); return NRF_SUCCESS; } typedef struct { volatile bool expired; } nrf_serial_timeout_ctx_t; static void serial_timeout_handler(void * p_context) { nrf_serial_timeout_ctx_t * p_tout_ctx = p_context; p_tout_ctx->expired = true; } static ret_code_t timeout_setup(nrf_serial_t const * p_serial, app_timer_id_t const * p_timer_id, uint32_t timeout_ms, nrf_serial_timeout_ctx_t * p_tout_ctx) { uint32_t ticks = APP_TIMER_TICKS(timeout_ms); if (ticks < APP_TIMER_MIN_TIMEOUT_TICKS) { p_tout_ctx->expired = true; return NRF_SUCCESS; } ret_code_t ret = app_timer_create(p_timer_id, APP_TIMER_MODE_SINGLE_SHOT, serial_timeout_handler); if (ret != NRF_SUCCESS) { return ret; } return app_timer_start(*p_timer_id, ticks, p_tout_ctx); } ret_code_t nrf_serial_write(nrf_serial_t const * p_serial, void const * p_data, size_t size, size_t * p_written, uint32_t timeout_ms) { ret_code_t ret; ASSERT(p_serial); if (!p_serial->p_ctx->p_config) { return NRF_ERROR_MODULE_NOT_INITIALIZED; } if (!(p_serial->p_ctx->flags & NRF_SERIAL_TX_ENABLED_FLAG)) { return NRF_ERROR_INVALID_STATE; } if (size == 0) { return NRF_SUCCESS; } if (!nrfx_is_in_ram(p_data) && p_serial->p_ctx->p_config->mode == NRF_SERIAL_MODE_DMA) { return NRF_ERROR_INVALID_ADDR; } if (!nrf_mtx_trylock(&p_serial->p_ctx->write_lock)) { return NRF_ERROR_BUSY; } nrf_serial_timeout_ctx_t tout_ctx = { .expired = false, }; if (timeout_ms != NRF_SERIAL_MAX_TIMEOUT) { ret = timeout_setup(p_serial, p_serial->p_tx_timer, timeout_ms, &tout_ctx); if (ret != NRF_SUCCESS) { nrf_mtx_unlock(&p_serial->p_ctx->write_lock); return ret; } } size_t left = size; uint8_t const * p_buff = p_data; do { size_t wcnt = serial_tx(p_serial, p_buff, left); left -= wcnt; p_buff += wcnt; if (!left) { break; } sleep_handler(p_serial); } while (!tout_ctx.expired); if (p_written) { *p_written = size - left; } if (!tout_ctx.expired && (timeout_ms != NRF_SERIAL_MAX_TIMEOUT)) { (void)app_timer_stop(*p_serial->p_tx_timer); } nrf_mtx_unlock(&p_serial->p_ctx->write_lock); if (left && tout_ctx.expired) { return NRF_ERROR_TIMEOUT; } return NRF_SUCCESS; } ret_code_t nrf_serial_read(nrf_serial_t const * p_serial, void * p_data, size_t size, size_t * p_read, uint32_t timeout_ms) { ret_code_t ret; ASSERT(p_serial); if (!p_serial->p_ctx->p_config) { return NRF_ERROR_MODULE_NOT_INITIALIZED; } if (!(p_serial->p_ctx->flags & NRF_SERIAL_RX_ENABLED_FLAG)) { return NRF_ERROR_INVALID_STATE; } if (size == 0) { return NRF_SUCCESS; } if (!nrf_mtx_trylock(&p_serial->p_ctx->read_lock)) { return NRF_ERROR_BUSY; } nrf_serial_timeout_ctx_t tout_ctx = { .expired = false, }; if (timeout_ms != NRF_SERIAL_MAX_TIMEOUT) { ret = timeout_setup(p_serial, p_serial->p_rx_timer, timeout_ms, &tout_ctx); if (ret != NRF_SUCCESS) { nrf_mtx_unlock(&p_serial->p_ctx->read_lock); return ret; } } size_t left = size; uint8_t * p_buff = p_data; do { size_t rcnt = serial_rx(p_serial, p_buff, left); left -= rcnt; p_buff += rcnt; if (!left) { break; } if (tout_ctx.expired) { if (p_serial->p_ctx->p_config->mode != NRF_SERIAL_MODE_POLLING) { nrfx_uarte_rx_abort(&p_serial->instance); } break; } sleep_handler(p_serial); } while (1); if (p_read) { *p_read = size - left; } if (!tout_ctx.expired && (timeout_ms != NRF_SERIAL_MAX_TIMEOUT)) { (void)app_timer_stop(*p_serial->p_rx_timer); } nrf_mtx_unlock(&p_serial->p_ctx->read_lock); if (left && tout_ctx.expired) { return NRF_ERROR_TIMEOUT; } return NRF_SUCCESS; } ret_code_t nrf_serial_flush(nrf_serial_t const * p_serial, uint32_t timeout_ms) { ret_code_t ret; ASSERT(p_serial); if (!p_serial->p_ctx->p_config) { return NRF_ERROR_MODULE_NOT_INITIALIZED; } if (!(p_serial->p_ctx->flags & NRF_SERIAL_TX_ENABLED_FLAG)) { return NRF_ERROR_INVALID_STATE; } if (p_serial->p_ctx->p_config->mode == NRF_SERIAL_MODE_POLLING) { return NRF_SUCCESS; } if (!nrf_mtx_trylock(&p_serial->p_ctx->write_lock)) { return NRF_ERROR_BUSY; } nrf_serial_timeout_ctx_t tout_ctx = { .expired = false, }; if (timeout_ms != NRF_SERIAL_MAX_TIMEOUT) { ret = timeout_setup(p_serial, p_serial->p_tx_timer, timeout_ms, &tout_ctx); if (ret != NRF_SUCCESS) { nrf_mtx_unlock(&p_serial->p_ctx->write_lock); return ret; } } bool empty; do { empty = nrf_queue_is_empty(p_serial->p_ctx->p_config->p_queues->p_txq) && !nrfx_uarte_tx_in_progress(&p_serial->instance); if (empty) { break; } sleep_handler(p_serial); } while (!tout_ctx.expired); if (!tout_ctx.expired && (timeout_ms != NRF_SERIAL_MAX_TIMEOUT)) { (void)app_timer_stop(*p_serial->p_tx_timer); } nrf_mtx_unlock(&p_serial->p_ctx->write_lock); if (!empty && tout_ctx.expired) { return NRF_ERROR_TIMEOUT; } return NRF_SUCCESS; } ret_code_t nrf_serial_tx_abort(nrf_serial_t const * p_serial) { ASSERT(p_serial); if (!p_serial->p_ctx->p_config) { return NRF_ERROR_MODULE_NOT_INITIALIZED; } if (!(p_serial->p_ctx->flags & NRF_SERIAL_TX_ENABLED_FLAG)) { return NRF_ERROR_INVALID_STATE; } if (!nrf_mtx_trylock(&p_serial->p_ctx->write_lock)) { return NRF_ERROR_BUSY; } nrfx_uarte_tx_abort(&p_serial->instance); if (p_serial->p_ctx->p_config->p_queues->p_txq) { nrf_queue_reset(p_serial->p_ctx->p_config->p_queues->p_txq); } nrf_mtx_unlock(&p_serial->p_ctx->write_lock); return NRF_SUCCESS; } ret_code_t nrf_serial_rx_drain(nrf_serial_t const * p_serial) { ASSERT(p_serial); if (!p_serial->p_ctx->p_config) { return NRF_ERROR_MODULE_NOT_INITIALIZED; } if (!(p_serial->p_ctx->flags & NRF_SERIAL_RX_ENABLED_FLAG)) { return NRF_ERROR_INVALID_STATE; } if (!nrf_mtx_trylock(&p_serial->p_ctx->read_lock)) { return NRF_ERROR_BUSY; } uint8_t c; /*Drain HW FIFO*/ while (serial_rx(p_serial, &c, sizeof(c))) { } /*Drain SW FIFO*/ if (p_serial->p_ctx->p_config->p_queues->p_rxq) { nrf_queue_reset(p_serial->p_ctx->p_config->p_queues->p_rxq); } nrf_mtx_unlock(&p_serial->p_ctx->read_lock); return NRF_SUCCESS; } #else ret_code_t nrf_serial_init(nrf_serial_t const * p_serial, nrf_drv_uart_config_t const * p_drv_uart_config, nrf_serial_config_t const * p_config) { return NRF_ERROR_NOT_SUPPORTED; } ret_code_t nrf_serial_uninit(nrf_serial_t const * p_serial) { return NRF_ERROR_NOT_SUPPORTED; } ret_code_t nrf_serial_write(nrf_serial_t const * p_serial, void const * p_data, size_t size, size_t * p_written, uint32_t timeout_ms) { return NRF_ERROR_NOT_SUPPORTED; } ret_code_t nrf_serial_read(nrf_serial_t const * p_serial, void * p_data, size_t size, size_t * p_read, uint32_t timeout_ms) { return NRF_ERROR_NOT_SUPPORTED; } ret_code_t nrf_serial_flush(nrf_serial_t const * p_serial, uint32_t timeout_ms) { return NRF_ERROR_NOT_SUPPORTED; } ret_code_t nrf_serial_tx_abort(nrf_serial_t const * p_serial) { return NRF_ERROR_NOT_SUPPORTED; } ret_code_t nrf_serial_rx_drain(nrf_serial_t const * p_serial) { return NRF_ERROR_NOT_SUPPORTED; } #endif // UART_PRESENT #endif //NRF_MODULE_ENABLED(NRF_SERIAL)