UART(E): Add Loopback backend
Add a new minimal overhead backend which connects a UART in loopback. Signed-off-by: Alberto Escolar Piedras <alberto.escolar.piedras@nordicsemi.no>
This commit is contained in:
parent
bc648f255d
commit
8b0819f405
16
docs/UART.md
16
docs/UART.md
|
@ -33,8 +33,14 @@ bytes into the UART peripheral like if they arrived thru the Rx line.
|
|||
|
||||
### Backends:
|
||||
|
||||
Today there is only 1 backend to choose from:
|
||||
* The FIFO backend.
|
||||
Today there are 2 backends to choose from:
|
||||
* The loopback backend
|
||||
* The FIFO backend
|
||||
|
||||
#### The Loopback backend
|
||||
|
||||
This backend just connects an instance Tx to its Rx, including the RTS and CTS signals.
|
||||
While having minimal overhead.
|
||||
|
||||
#### The FIFO backend
|
||||
|
||||
|
@ -73,10 +79,12 @@ It is possible to connect a UART instance Tx directly to its Rx (or to another i
|
|||
and have the RTR propagated to the CTS.
|
||||
To do this, just configure the same FIFO file name for both the Rx and Tx, for example like:
|
||||
`-uart0_fifob_rxfile=looped_back -uart0_fifob_txfile=looped_back`
|
||||
Note that you can also use the loopback backend when connecting a single instance in loopback,
|
||||
and have the same result with lower overhead, and no files created on disk.
|
||||
|
||||
**IMPOTANT**:
|
||||
Do not connect both devices which are connected thru the UART to the Physical layer
|
||||
simulation. Connect only the one which has the BLE/15.4 controller.
|
||||
Do not connect both devices which are connected thru the UART FIFO backend to the Physical layer
|
||||
simulation simultaneously. Connect only the one which has the BLE/15.4 controller.
|
||||
Otherwise, with the current implementation the simulation will deadlock with very high
|
||||
likelihood, and if it does not deadlock it will slow down the simulation considerably.
|
||||
You can still provide the sim_id and an unused device number to the other device, but
|
||||
|
|
|
@ -25,6 +25,7 @@ src/HW_models/NHW_TEMP.c
|
|||
src/HW_models/NHW_TIMER.c
|
||||
src/HW_models/NHW_UART.c
|
||||
src/HW_models/NHW_UART_backend_fifo.c
|
||||
src/HW_models/NHW_UART_be_loopb.c
|
||||
src/HW_models/bs_compat.c
|
||||
src/HW_models/NHW_52_FICR.c
|
||||
src/HW_models/NRF_GPIOTE.c
|
||||
|
|
|
@ -30,5 +30,6 @@ src/HW_models/NHW_TIMER.c
|
|||
src/HW_models/NHW_TEMP.c
|
||||
src/HW_models/NHW_UART.c
|
||||
src/HW_models/NHW_UART_backend_fifo.c
|
||||
src/HW_models/NHW_UART_be_loopb.c
|
||||
src/HW_models/NHW_VREQCTRL.c
|
||||
src/HW_models/weak_stubs.c
|
||||
|
|
|
@ -185,6 +185,9 @@ uart_rtxb_cb_f nhw_uarte_register_rx_cb(int inst, uart_rtxb_cb_f cb, bool Rx_Not
|
|||
void nhw_UARTE_backend_register(uint inst, struct backend_if *backend) {
|
||||
struct uarte_status *u_el = &nhw_uarte_st[inst];
|
||||
|
||||
if (u_el->backend.tx_byte_f != NULL) {
|
||||
bs_trace_warning_line("UART%i backend selection overwritten\n", inst);
|
||||
}
|
||||
memcpy(&u_el->backend, backend, sizeof(struct backend_if));
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Backend for the UART(E) which connects the Tx and Rx of the same UART instance in loopback
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "bs_tracing.h"
|
||||
#include "bs_cmd_line.h"
|
||||
#include "bs_utils.h"
|
||||
#include "bs_dynargs.h"
|
||||
#include "NHW_config.h"
|
||||
#include "NHW_peri_types.h"
|
||||
#include "NHW_UART_backend_if.h"
|
||||
#include "nsi_tasks.h"
|
||||
#include "nsi_hw_scheduler.h"
|
||||
#include "nsi_hws_models_if.h"
|
||||
|
||||
static bs_time_t Timer_ULoopback = TIME_NEVER;
|
||||
|
||||
struct ublb_st_t {
|
||||
bool enabled;
|
||||
bs_time_t Timer;
|
||||
|
||||
char rx_byte;
|
||||
} ublb_st[NHW_UARTE_TOTAL_INST];
|
||||
|
||||
static void nhw_ublb_tx_byte(uint inst, uint8_t data);
|
||||
static void nhw_ublb_RTS_pin_toggle(uint inst, bool new_level);
|
||||
|
||||
static void nhw_ublb_init(void) {
|
||||
|
||||
struct backend_if st;
|
||||
st.tx_byte_f = nhw_ublb_tx_byte;
|
||||
st.RTS_pin_toggle_f = nhw_ublb_RTS_pin_toggle;
|
||||
st.uart_enable_notify_f = NULL;
|
||||
|
||||
for (int i = 0; i < NHW_UARTE_TOTAL_INST; i++) {
|
||||
|
||||
ublb_st[i].Timer = TIME_NEVER;
|
||||
|
||||
if (!ublb_st[i].enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nhw_UARTE_backend_register(i, &st);
|
||||
nhw_UARTE_CTS_raised(i);
|
||||
}
|
||||
}
|
||||
|
||||
NSI_TASK(nhw_ublb_init, HW_INIT, 100); /* this must be before the uart itself */
|
||||
|
||||
static void nhw_ublb_register_cmdline(void) {
|
||||
static bs_args_struct_t args[NHW_UARTE_TOTAL_INST + 1 /* End marker */];
|
||||
static char descr[] = "Connect this UART instance in loopback (Tx->Rx, RTS->CTS)";
|
||||
#define OPTION_LEN (4 + 2 + 9 + 1)
|
||||
static char options[NHW_UARTE_TOTAL_INST][OPTION_LEN];
|
||||
|
||||
for (int i = 0 ; i < NHW_UARTE_TOTAL_INST; i++) {
|
||||
snprintf(options[i], OPTION_LEN, "uart%i_loopback", i);
|
||||
|
||||
args[i].is_switch = true;
|
||||
args[i].option = options[i];
|
||||
args[i].type = 'b';
|
||||
args[i].dest = &ublb_st[i].enabled;
|
||||
args[i].descript = descr;
|
||||
}
|
||||
|
||||
bs_add_extra_dynargs(args);
|
||||
}
|
||||
|
||||
NSI_TASK(nhw_ublb_register_cmdline, PRE_BOOT_1, 200);
|
||||
|
||||
static void nhw_ublb_update_timer(void) {
|
||||
Timer_ULoopback = TIME_NEVER;
|
||||
for (int i = 0; i < NHW_UARTE_TOTAL_INST; i++) {
|
||||
if (!ublb_st[i].enabled) {
|
||||
continue;
|
||||
}
|
||||
Timer_ULoopback = BS_MIN(ublb_st[i].Timer, Timer_ULoopback);
|
||||
}
|
||||
nsi_hws_find_next_event();
|
||||
}
|
||||
|
||||
static void nhw_ublb_tx_byte(uint inst, uint8_t data) {
|
||||
if (ublb_st[inst].Timer != TIME_NEVER) {
|
||||
bs_trace_error_time_line("%s: Unexpected error\n", __func__);
|
||||
}
|
||||
ublb_st[inst].rx_byte = data;
|
||||
ublb_st[inst].Timer = nsi_hws_get_time() + nhw_uarte_one_byte_time(inst);
|
||||
nhw_ublb_update_timer();
|
||||
}
|
||||
|
||||
static void nhw_ublb_RTS_pin_toggle(uint inst, bool new_level) {
|
||||
if (new_level){
|
||||
nhw_UARTE_CTS_raised(inst);
|
||||
} else {
|
||||
nhw_UARTE_CTS_lowered(inst);
|
||||
}
|
||||
}
|
||||
|
||||
static void nhw_ublb_timer_triggered(void) {
|
||||
bs_time_t current_time = Timer_ULoopback;
|
||||
for (int i = 0; i < NHW_UARTE_TOTAL_INST; i++) {
|
||||
if (ublb_st[i].Timer == current_time) {
|
||||
nhw_UARTE_digest_Rx_byte(i, ublb_st[i].rx_byte);
|
||||
ublb_st[i].Timer = TIME_NEVER;
|
||||
}
|
||||
}
|
||||
nhw_ublb_update_timer();
|
||||
}
|
||||
|
||||
NSI_HW_EVENT(Timer_ULoopback, nhw_ublb_timer_triggered, 40); /* Before the UART itself */
|
Loading…
Reference in New Issue