Skip to content

Commit 636960a

Browse files
samples: bluetooth: ble_nus: add LPUARTE support
Add support for LPUARTE to NUS sample. Co-authored-by: Andreas Moltumyr <[email protected]> Signed-off-by: Eivind Jølsgard <[email protected]>
1 parent a846dba commit 636960a

File tree

6 files changed

+189
-38
lines changed

6 files changed

+189
-38
lines changed

samples/bluetooth/ble_nus/Kconfig

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,35 @@
66

77
menu "BLE NUS sample"
88

9-
config BLE_UART_IRQ_PRIO
10-
int "BLE UART IRQ priority"
9+
config NUS_UART_IRQ_PRIO
10+
int "NUS UART IRQ priority"
1111
default 3
1212

13-
config BLE_UART_PARITY
13+
config NUS_UART_PARITY
1414
bool "BLE UART use parity"
1515

16-
config BLE_UART_HWFC
17-
bool "BLE UART use HWFC"
16+
config NUS_LPUARTE
17+
bool "NUS Low Power UARTE"
18+
19+
if NUS_LPUARTE
20+
21+
config GPIOTE_IRQ_PRIO
22+
int "GPIOTE IRQ priority"
23+
default 3
24+
25+
endif # NUS_LPUARTE
26+
27+
config NUS_UART_HWFC
28+
bool "NUS UART use HWFC"
29+
depends on !NUS_LPUARTE
30+
default y
31+
32+
config NUS_UART_RX_BUF_SIZE
33+
int "NUS UART receive buffer size"
34+
default 128 if NUS_LPUARTE
35+
default 1
36+
help
37+
UART RX is double buffered, so the actual buffer will be twice as large.
1838

1939
endmenu # "BLE NUS sample"
2040

samples/bluetooth/ble_nus/README.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,24 @@ This sample can be found under :file:`samples/bluetooth/ble_nus/` in the |BMshor
6060

6161
.. include:: /includes/program_sample.txt
6262

63+
Building and running with LPUARTE
64+
*********************************
65+
66+
The :file:`lpuarte.conf` file configures the sample to use the :ref:`LPUARTE <driver_lpuarte>` driver for the NUS Service.
67+
This is useful for reducing the power consumption.
68+
The file must be added to the build configuration is VS Code or as an extra argument to west: ``-DEXTRA_CONF_FILE="lpuarte.conf"``.
69+
70+
To test the NUS sample with the :ref:`LPUARTE <driver_lpuarte>` driver in loopback mode, connect pin ``P1.08`` (REQ) with ``P1.09`` (RDY) and ``P1.10`` (RX) with ``P1.11`` (TX) on the nRF54L15DK, as given in the :file:`board-config.h`.
71+
It is also possible to test between two devices running NUS with LPUART by connecting the above mentioned pins and ``GND`` between the devices.
72+
Make sure the ``REQ`` pin on one board is connected to the ``RDY`` on the other board, and vice versa.
73+
6374
Testing
6475
=======
6576

6677
1. Compile and program the application.
6778
#. Connect the device to the computer to access UART 0 and UART 1.
6879
If you use a development kit, UART 0 and 1 are forwarded as COM ports (Windows) or ttyACM devices (Linux) after you connect the development kit over USB.
80+
One instance is used for logging (if enabled), the other for the NUS service.
6981
#. Connect to the kit with a terminal emulator (for example, the `Serial Terminal app`_) to both UARTs.
7082
#. Reset the kit.
7183
#. Observe that the device is advertising under the default name ``nRF_BM_NUS``.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# This file enables Low Power UARTE (LPUARTE) driver for the NUS UART instance.
2+
CONFIG_BM_SW_LPUARTE=y
3+
CONFIG_BM_TIMER=y
4+
5+
CONFIG_NUS_LPUARTE=y
6+
7+
# Set number of event handlers used by the LPUART driver
8+
CONFIG_NRFX_GPIOTE_NUM_OF_EVT_HANDLERS=2

samples/bluetooth/ble_nus/prj.conf

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ CONFIG_BLE_CONN_PARAMS=y
1414

1515
# Nordic UART service
1616
CONFIG_BLE_NUS=y
17-
CONFIG_BLE_UART_HWFC=y
1817

1918
# NUS depends on the Queued Writes module
2019
CONFIG_BLE_QWR=y

samples/bluetooth/ble_nus/sample.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,29 @@ tests:
44
sample.ble_nus:
55
build_only: true
66
integration_platforms:
7+
- bm_nrf54l15dk/nrf54l05/cpuapp/s115_softdevice/mcuboot
8+
- bm_nrf54l15dk/nrf54l10/cpuapp/s115_softdevice
9+
- bm_nrf54l15dk/nrf54l15/cpuapp/s115_softdevice
10+
platform_allow:
711
- bm_nrf54l15dk/nrf54l05/cpuapp/s115_softdevice
812
- bm_nrf54l15dk/nrf54l10/cpuapp/s115_softdevice
913
- bm_nrf54l15dk/nrf54l15/cpuapp/s115_softdevice
1014
- bm_nrf54l15dk/nrf54l05/cpuapp/s115_softdevice/mcuboot
1115
- bm_nrf54l15dk/nrf54l10/cpuapp/s115_softdevice/mcuboot
1216
- bm_nrf54l15dk/nrf54l15/cpuapp/s115_softdevice/mcuboot
17+
tags: ci_build
18+
sample.ble_nus.lpuarte:
19+
build_only: true
20+
integration_platforms:
21+
- bm_nrf54l15dk/nrf54l05/cpuapp/s115_softdevice/mcuboot
22+
- bm_nrf54l15dk/nrf54l10/cpuapp/s115_softdevice
23+
- bm_nrf54l15dk/nrf54l15/cpuapp/s115_softdevice
1324
platform_allow:
1425
- bm_nrf54l15dk/nrf54l05/cpuapp/s115_softdevice
1526
- bm_nrf54l15dk/nrf54l10/cpuapp/s115_softdevice
1627
- bm_nrf54l15dk/nrf54l15/cpuapp/s115_softdevice
1728
- bm_nrf54l15dk/nrf54l05/cpuapp/s115_softdevice/mcuboot
1829
- bm_nrf54l15dk/nrf54l10/cpuapp/s115_softdevice/mcuboot
1930
- bm_nrf54l15dk/nrf54l15/cpuapp/s115_softdevice/mcuboot
31+
extra_args: EXTRA_CONF_FILE="lpuarte.conf"
2032
tags: ci_build

samples/bluetooth/ble_nus/src/main.c

Lines changed: 132 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
#include <zephyr/logging/log.h>
1919
#include <zephyr/logging/log_ctrl.h>
2020
#include <zephyr/sys/util.h>
21+
#if defined(CONFIG_NUS_LPUARTE)
22+
#include <bm_lpuarte.h>
23+
#endif
2124

2225
#include <board-config.h>
2326

@@ -30,16 +33,32 @@ BLE_QWR_DEF(ble_qwr); /* BLE QWR instance */
3033
/** Handle of the current connection. */
3134
static uint16_t conn_handle = BLE_CONN_HANDLE_INVALID;
3235

33-
/** NUS UARTE instance */
34-
static const nrfx_uarte_t uarte_inst = NRF_UARTE_INST_GET(BOARD_APP_UARTE_INST);
36+
/** NUS UARTE instance and board config */
37+
#if defined(CONFIG_NUS_LPUARTE)
38+
#define NUS_UARTE_INST BOARD_APP_LPUARTE_INST
39+
#define NUS_UARTE_PIN_TX BOARD_APP_LPUARTE_PIN_TX
40+
#define NUS_UARTE_PIN_RX BOARD_APP_LPUARTE_PIN_RX
41+
#define NUS_UARTE_PIN_RDY BOARD_APP_LPUARTE_PIN_RDY
42+
#define NUS_UARTE_PIN_REQ BOARD_APP_LPUARTE_PIN_REQ
43+
44+
struct bm_lpuarte lpu;
45+
#else
46+
#define NUS_UARTE_INST BOARD_APP_UARTE_INST
47+
#define NUS_UARTE_PIN_TX BOARD_APP_UARTE_PIN_TX
48+
#define NUS_UARTE_PIN_RX BOARD_APP_UARTE_PIN_RX
49+
#define NUS_UARTE_PIN_CTS BOARD_APP_UARTE_PIN_CTS
50+
#define NUS_UARTE_PIN_RTS BOARD_APP_UARTE_PIN_RTS
51+
52+
static const nrfx_uarte_t nus_uarte_inst = NRFX_UARTE_INSTANCE(NUS_UARTE_INST);
53+
#endif /* CONFIG_NUS_LPUARTE */
3554

3655
/* Maximum length of data (in bytes) that can be transmitted to the peer by the
3756
* Nordic UART service module.
3857
*/
3958
static volatile uint16_t ble_nus_max_data_len = BLE_NUS_MAX_DATA_LEN_CALC(BLE_GATT_ATT_MTU_DEFAULT);
4059

41-
/* Receive buffer used in UART ISR callback */
42-
static uint8_t uarte_rx_buf[4];
60+
/* Receive buffers used in UART ISR callback. */
61+
static uint8_t uarte_rx_buf[CONFIG_NUS_UART_RX_BUF_SIZE][2];
4362
static int buf_idx;
4463

4564
/**
@@ -48,6 +67,26 @@ static int buf_idx;
4867
* @param[in] data Data received.
4968
* @param[in] data_len Size of data.
5069
*/
70+
#if defined(CONFIG_NUS_LPUARTE)
71+
static void lpuarte_rx_handler(char *data, size_t data_len)
72+
{
73+
int err;
74+
uint16_t len = data_len;
75+
76+
LOG_INF("Sending data over BLE NUS, len %d", len);
77+
78+
do {
79+
err = ble_nus_data_send(&ble_nus, data, &len, conn_handle);
80+
if ((err != 0) &&
81+
(err != -EPIPE) &&
82+
(err != -EAGAIN) &&
83+
(err != -EBADF)) {
84+
LOG_ERR("Failed to send NUS data, err %d", err);
85+
return;
86+
}
87+
} while (err == -EAGAIN);
88+
}
89+
#else
5190
static void uarte_rx_handler(char *data, size_t data_len)
5291
{
5392
int err;
@@ -96,6 +135,7 @@ static void uarte_rx_handler(char *data, size_t data_len)
96135
}
97136
}
98137
}
138+
#endif
99139

100140
/**
101141
* @brief UARTE event handler
@@ -107,18 +147,29 @@ static void uarte_evt_handler(nrfx_uarte_event_t const *event, void *ctx)
107147
{
108148
switch (event->type) {
109149
case NRFX_UARTE_EVT_RX_DONE:
110-
LOG_DBG("Received data from UART: %c", event->data.rx.p_buffer[0]);
150+
LOG_DBG("Received data from UART: %.*s (%d)",
151+
event->data.rx.length, event->data.rx.p_buffer, event->data.rx.length);
111152
if (event->data.rx.length > 0) {
153+
#if defined(CONFIG_NUS_LPUARTE)
154+
lpuarte_rx_handler(event->data.rx.p_buffer, event->data.rx.length);
155+
#else
112156
uarte_rx_handler(event->data.rx.p_buffer, event->data.rx.length);
157+
#endif
113158
}
114159

115-
nrfx_uarte_rx_enable(&uarte_inst, 0);
160+
#if !defined(CONFIG_NUS_LPUARTE)
161+
nrfx_uarte_rx_enable(&nus_uarte_inst, 0);
162+
#endif
116163
break;
117164
case NRFX_UARTE_EVT_RX_BUF_REQUEST:
118-
nrfx_uarte_rx_buffer_set(&uarte_inst, &uarte_rx_buf[buf_idx], 1);
165+
#if defined(CONFIG_NUS_LPUARTE)
166+
bm_lpuarte_rx_buffer_set(&lpu, uarte_rx_buf[buf_idx], CONFIG_NUS_UART_RX_BUF_SIZE);
167+
#else
168+
nrfx_uarte_rx_buffer_set(&nus_uarte_inst, uarte_rx_buf[buf_idx],
169+
CONFIG_NUS_UART_RX_BUF_SIZE);
170+
#endif
119171

120-
buf_idx++;
121-
buf_idx = (buf_idx < sizeof(uarte_rx_buf)) ? buf_idx : 0;
172+
buf_idx = buf_idx ? 0 : 1;
122173
break;
123174
case NRFX_UARTE_EVT_ERROR:
124175
LOG_ERR("uarte error %#x", event->data.error.error_mask);
@@ -264,20 +315,36 @@ uint16_t ble_qwr_evt_handler(struct ble_qwr *qwr, const struct ble_qwr_evt *qwr_
264315
static void ble_nus_evt_handler(const struct ble_nus_evt *evt)
265316
{
266317
const char newline = '\n';
318+
uint32_t err;
267319

268320
if (evt->type != BLE_NUS_EVT_RX_DATA) {
269321
return;
270322
}
271323

272324
/* Handle incoming data */
273-
LOG_DBG("Received data from BLE NUS: %s", evt->params.rx_data.data);
325+
LOG_DBG("Received data from BLE NUS: %.*s (%d)",
326+
evt->params.rx_data.length, evt->params.rx_data.data, evt->params.rx_data.length);
274327

275-
for (uint32_t i = 0; i < evt->params.rx_data.length; i++) {
276-
nrfx_uarte_tx(&uarte_inst, &evt->params.rx_data.data[i], 1, NRFX_UARTE_TX_BLOCKING);
328+
#if defined(CONFIG_NUS_LPUARTE)
329+
err = bm_lpuarte_tx(&lpu, evt->params.rx_data.data, evt->params.rx_data.length, 3000);
330+
if (err != NRFX_SUCCESS) {
331+
LOG_ERR("bm_lpuarte_tx failed, nrfx_err %#x", err);
277332
}
333+
#else
334+
err = nrfx_uarte_tx(&nus_uarte_inst, evt->params.rx_data.data,
335+
evt->params.rx_data.length, NRFX_UARTE_TX_BLOCKING);
336+
if (err != NRFX_SUCCESS) {
337+
LOG_ERR("nrfx_uarte_tx failed, nrfx_err %#x", err);
338+
}
339+
#endif
340+
278341

279342
if (evt->params.rx_data.data[evt->params.rx_data.length - 1] == '\r') {
280-
nrfx_uarte_tx(&uarte_inst, &newline, 1, NRFX_UARTE_TX_BLOCKING);
343+
#if defined(CONFIG_NUS_LPUARTE)
344+
bm_lpuarte_tx(&lpu, &newline, 1, 3000);
345+
#else
346+
nrfx_uarte_tx(&nus_uarte_inst, &newline, 1, NRFX_UARTE_TX_BLOCKING);
347+
#endif
281348
}
282349
}
283350

@@ -287,33 +354,62 @@ static void ble_nus_evt_handler(const struct ble_nus_evt *evt)
287354
static int uarte_init(void)
288355
{
289356
int err;
357+
nrfx_uarte_config_t *uarte_cfg;
358+
#if defined(CONFIG_NUS_LPUARTE)
359+
struct bm_lpuarte_config lpu_cfg = {
360+
.uarte_inst = NRFX_UARTE_INSTANCE(NUS_UARTE_INST),
361+
.uarte_cfg = NRFX_UARTE_DEFAULT_CONFIG(NUS_UARTE_PIN_TX,
362+
NUS_UARTE_PIN_RX),
363+
.req_pin = BOARD_APP_LPUARTE_PIN_REQ,
364+
.rdy_pin = BOARD_APP_LPUARTE_PIN_RDY,
365+
};
290366

291-
nrfx_uarte_config_t uarte_config = NRFX_UARTE_DEFAULT_CONFIG(BOARD_APP_UARTE_PIN_TX,
292-
BOARD_APP_UARTE_PIN_RX);
367+
uarte_cfg = &lpu_cfg.uarte_cfg;
368+
#else
369+
nrfx_uarte_config_t uarte_config = NRFX_UARTE_DEFAULT_CONFIG(NUS_UARTE_PIN_TX,
370+
NUS_UARTE_PIN_RX);
293371

294-
#if defined(CONFIG_BLE_UART_HWFC)
295-
uarte_config.config.hwfc = NRF_UARTE_HWFC_ENABLED;
296-
uarte_config.cts_pin = BOARD_APP_UARTE_PIN_CTS;
297-
uarte_config.rts_pin = BOARD_APP_UARTE_PIN_RTS;
298-
#endif
372+
uarte_cfg = &uarte_config;
373+
374+
#if defined(CONFIG_NUS_UART_HWFC)
375+
uarte_cfg->config.hwfc = NRF_UARTE_HWFC_ENABLED;
376+
uarte_cfg->cts_pin = NUS_UARTE_PIN_CTS;
377+
uarte_cfg->rts_pin = NUS_UARTE_PIN_RTS;
378+
#endif /* CONFIG_NUS_UART_HWFC */
379+
#endif /* CONFIG_NUS_LPUARTE */
299380

300-
#if defined(CONFIG_BLE_UART_PARITY)
301-
uarte_config.parity = NRF_UARTE_PARITY_INCLUDED;
381+
#if defined(CONFIG_NUS_UART_PARITY)
382+
uarte_cfg->parity = NRF_UARTE_PARITY_INCLUDED;
302383
#endif
303384

304-
uarte_config.interrupt_priority = CONFIG_BLE_UART_IRQ_PRIO;
385+
uarte_cfg->interrupt_priority = CONFIG_NUS_UART_IRQ_PRIO;
305386

306387
/** We need to connect the IRQ ourselves. */
307-
IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_UARTE_INST_GET(BOARD_APP_UARTE_INST)), CONFIG_BLE_UART_IRQ_PRIO,
308-
NRFX_UARTE_INST_HANDLER_GET(BOARD_APP_UARTE_INST), 0, 0);
309388

310-
irq_enable(NRFX_IRQ_NUMBER_GET(NRF_UARTE_INST_GET(BOARD_APP_UARTE_INST)));
389+
IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_UARTE_INST_GET(NUS_UARTE_INST)),
390+
CONFIG_NUS_UART_IRQ_PRIO, NRFX_UARTE_INST_HANDLER_GET(NUS_UARTE_INST), 0, 0);
311391

312-
err = nrfx_uarte_init(&uarte_inst, &uarte_config, uarte_evt_handler);
392+
irq_enable(NRFX_IRQ_NUMBER_GET(NRF_UARTE_INST_GET(NUS_UARTE_INST)));
393+
394+
#if defined(CONFIG_NUS_LPUARTE)
395+
IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_GPIOTE_INST_GET(20)) + NRF_GPIOTE_IRQ_GROUP,
396+
CONFIG_GPIOTE_IRQ_PRIO, NRFX_GPIOTE_INST_HANDLER_GET(20), 0, 0);
397+
398+
IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_GPIOTE_INST_GET(30)) + NRF_GPIOTE_IRQ_GROUP,
399+
CONFIG_GPIOTE_IRQ_PRIO, NRFX_GPIOTE_INST_HANDLER_GET(30), 0, 0);
400+
401+
err = bm_lpuarte_init(&lpu, &lpu_cfg, uarte_evt_handler);
402+
if (err != NRFX_SUCCESS) {
403+
LOG_ERR("Failed to initialize UART, nrfx err %d", err);
404+
return err;
405+
}
406+
#else
407+
err = nrfx_uarte_init(&nus_uarte_inst, &uarte_config, uarte_evt_handler);
313408
if (err != NRFX_SUCCESS) {
314409
LOG_ERR("Failed to initialize UART, nrfx err %d", err);
315410
return err;
316411
}
412+
#endif /* CONFIG_NUS_LPUARTE */
317413

318414
return 0;
319415
}
@@ -395,18 +491,25 @@ int main(void)
395491
goto idle;
396492
}
397493

494+
#if defined(CONFIG_NUS_LPUARTE)
495+
err = bm_lpuarte_rx_enable(&lpu);
496+
if (err != NRFX_SUCCESS) {
497+
LOG_ERR("UART RX failed, nrfx err %d", err);
498+
}
499+
#else
398500
const uint8_t out[] = "UART started.\r\n";
399501

400-
err = nrfx_uarte_tx(&uarte_inst, out, sizeof(out), NRFX_UARTE_TX_BLOCKING);
502+
err = nrfx_uarte_tx(&nus_uarte_inst, out, sizeof(out), NRFX_UARTE_TX_BLOCKING);
401503
if (err != NRFX_SUCCESS) {
402504
LOG_ERR("UARTE TX failed, nrfx err %d", err);
403505
goto idle;
404506
}
405507

406-
err = nrfx_uarte_rx_enable(&uarte_inst, 0);
508+
err = nrfx_uarte_rx_enable(&nus_uarte_inst, 0);
407509
if (err != NRFX_SUCCESS) {
408510
LOG_ERR("UART RX failed, nrfx err %d", err);
409511
}
512+
#endif
410513

411514
err = ble_adv_start(&ble_adv, BLE_ADV_MODE_FAST);
412515
if (err) {
@@ -415,9 +518,6 @@ int main(void)
415518
}
416519

417520
LOG_INF("Advertising as %s", CONFIG_BLE_ADV_NAME);
418-
#if defined(CONFIG_SOC_SERIES_NRF54LX)
419-
LOG_INF("The NUS service is handled at a separate uart instance");
420-
#endif
421521

422522
idle:
423523
while (true) {

0 commit comments

Comments
 (0)