Skip to content

Commit 634c88c

Browse files
olivier-le-sagenordicjm
authored andcommitted
mpsl: cx: Add a generic coex variant using a single GPIO
This 1-wire coex variant is based on mpsl_cx_abstract_interface.h and follows the requirements/recommendations for the nrf9160 LTE modem. Unlike CONFIG_MPSL_CX_BT_1WIRE, it supports nrf53 and non-bluetooth use-cases. Signed-off-by: Olivier Lesage <[email protected]>
1 parent 65d1773 commit 634c88c

File tree

7 files changed

+291
-21
lines changed

7 files changed

+291
-21
lines changed

doc/nrf/app_dev/device_guides/wifi_coex.rst

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,77 @@ To enable the generic three-wire coexistence, do the following:
242242
* :kconfig:option:`CONFIG_MPSL_CX`
243243
* :kconfig:option:`CONFIG_MPSL_CX_3WIRE`
244244

245+
.. _ug_radio_mpsl_cx_generic_1wire:
246+
247+
Generic one wire coexistence
248+
============================
249+
250+
Refer to :ref:`ug_radio_coex_mpsl_cx_based` for the general requirements of this implementation.
251+
252+
An example use-case of the generic one wire coexistence interface is to allow a protocol implementation to coexist alongside an LTE device on a separate chip, such as the nRF91 Series SiP.
253+
254+
Hardware description
255+
--------------------
256+
257+
The generic one wire interface consists of the signals listed in the table below.
258+
The *Pin* is a generic pin name of a PTA, identified rather by its function.
259+
The *Direction* is from the point of view of the SoC running the coexistence protocol.
260+
The *DT property* is the name of the devicetree node property that configures the connection between the SoC running the coexistence protocol and the other device.
261+
262+
.. table:: Generic one wire coexistence protocol pins
263+
264+
============ ========= ================================= ==============
265+
Pin Direction Description DT property
266+
============ ========= ================================= ==============
267+
GRANT In Grant signal grant-gpios
268+
============ ========= ================================= ==============
269+
270+
In cases where the GPIO is asserted after the radio activity has begun, the ``GRANT`` signal triggers a software interrupt, which in turn disables the radio.
271+
No guarantee is made on the latency of this interrupt, but the ISR priority is configurable.
272+
273+
Enabling generic one wire coexistence
274+
-------------------------------------
275+
276+
To enable the generic one wire coexistence, do the following:
277+
278+
279+
1. Add the following node to the devicetree source file:
280+
281+
.. code-block::
282+
283+
/ {
284+
nrf_radio_coex: radio_coex_one_wire {
285+
status = "okay";
286+
compatible = "generic-radio-coex-one-wire";
287+
grant-gpios = <&gpio0 25 GPIO_ACTIVE_LOW>;
288+
concurrency-mode = <0>;
289+
};
290+
};
291+
292+
The ``concurrency-mode`` property is optional and can be removed.
293+
By default, or when set to 0, the ``GRANT`` signal will prevent both TX and RX.
294+
When set to 1, it will only prevent TX.
295+
296+
#. Optionally, if not using the nRF91 Series SiP, the ``GRANT`` signal may be configured active-high using ``GPIO_ACTIVE_HIGH``
297+
#. Optionally, replace the node name ``radio_coex_one_wire`` with a custom one.
298+
#. If not already present in the device tree, the GPIOTE interrupt may additionally be configured as follows (the first element is the IRQn, and the second is the priority):
299+
300+
.. code-block::
301+
302+
&gpiote {
303+
interrupts = < 6 3 >;
304+
};
305+
306+
#. Replace the pin number provided for the ``grant-gpios`` property:
307+
This is the GPIO characteristic of the device that interfaces with the ``GRANT`` signal of the PTA (RF medium access granted).
308+
309+
The first element ``&gpio0`` indicates the GPIO port (``port 0`` has been selected in the example shown).
310+
The second element is the pin number on that port.
311+
312+
#. Enable the following Kconfig options:
313+
314+
* :kconfig:option:`CONFIG_MPSL_CX`
315+
* :kconfig:option:`CONFIG_MPSL_CX_1WIRE`
245316

246317
.. _ug_radio_mpsl_cx_custom:
247318

doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,9 @@ Multiprotocol Service Layer libraries
579579
-------------------------------------
580580

581581
* The Kconfig option ``CONFIG_MPSL_CX_THREAD`` has been renamed to :kconfig:option:`CONFIG_MPSL_CX_3WIRE` to better indicate multiprotocol compatibility.
582+
* Added:
583+
584+
* A 1-wire coexistence implementation which can be enabled using the Kconfig option :kconfig:option:`CONFIG_MPSL_CX_1WIRE`.
582585

583586
Libraries for networking
584587
------------------------

dts/bindings/radio_coex/generic-radio-coex-one-wire.yaml

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,27 @@
22
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
33

44
description: |
5-
This is a representation of an external radio coexistence setup that has a
6-
one-pin control interface (GRANT).
5+
This is a representation of an external radio coexistence setup that has a
6+
one-pin control interface (GRANT).
77
88
compatible: "generic-radio-coex-one-wire"
99

1010
include: base.yaml
1111

1212
properties:
13-
grant-gpios:
14-
type: phandle-array
15-
required: true
16-
description: |
17-
GPIO of the SOC connected to the PTA's GRANT pin.
13+
concurrency-mode:
14+
type: int
15+
required: true
16+
description: |
17+
Concurrency mode with the external modem supported by 1-wire coexistence.
18+
The possible values are:
19+
0: 1-wire configuration to allow no concurrency with the external modem
20+
when the grant line is asserted.
21+
1: 1-wire configuration to allow RX mode concurrency
22+
with the external modem when the grant line is asserted.
23+
24+
grant-gpios:
25+
type: phandle-array
26+
required: true
27+
description: |
28+
GPIO of the SOC connected to the PTA's GRANT pin.

dts/bindings/radio_coex/sdc-radio-coex-one-wire.yaml

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,8 @@
33

44
description: |
55
This is a representation of an external radio coexistence setup that has a
6-
one-pin control interface (GRANT). This extends that interface with
7-
additional parameters.
6+
one-pin control interface (GRANT).
87
98
compatible: "sdc-radio-coex-one-wire"
109

1110
include: generic-radio-coex-one-wire.yaml
12-
13-
properties:
14-
concurrency-mode:
15-
type: int
16-
required: true
17-
description: |
18-
Concurrency mode with the external modem supported by 1-wire coexistence.
19-
The possible values are:
20-
0: 1-wire configuration to allow no concurrency with the external modem
21-
when the grant line is asserted.
22-
1: 1-wire configuration to allow the radio to allow RX mode concurrency
23-
with the external modem when the grant line is asserted.
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
/*
2+
* Copyright (c) 2024 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
/**
8+
* @file
9+
* This file implements a generic 1-wire coexistence interface.
10+
*/
11+
12+
#if defined(CONFIG_MPSL_CX_PIN_FORWARDER)
13+
#include <string.h>
14+
#include <soc_secure.h>
15+
#else
16+
#include <mpsl_cx_abstract_interface.h>
17+
#endif
18+
19+
#include <stddef.h>
20+
#include <stdint.h>
21+
22+
#include <zephyr/device.h>
23+
#include <zephyr/devicetree.h>
24+
#include <zephyr/drivers/gpio.h>
25+
26+
#include "hal/nrf_gpio.h"
27+
#include <nrfx_gpiote.h>
28+
29+
#if DT_NODE_EXISTS(DT_NODELABEL(nrf_radio_coex))
30+
#define CX_NODE DT_NODELABEL(nrf_radio_coex)
31+
#else
32+
#define CX_NODE DT_INVALID_NODE
33+
#error No enabled coex nodes registered in DTS.
34+
#endif
35+
36+
#if DT_NODE_HAS_PROP(CX_NODE, concurrency_mode)
37+
#define ALLOW_RX DT_PROP(CX_NODE, concurrency_mode)
38+
#else
39+
#define ALLOW_RX false
40+
#endif
41+
42+
#if !(DT_NODE_HAS_COMPAT(CX_NODE, generic_radio_coex_one_wire))
43+
#error Selected coex node is not compatible with generic-radio-coex-one-wire.
44+
#endif
45+
46+
#if !defined(CONFIG_MPSL_CX_PIN_FORWARDER)
47+
48+
#define GRANT_PIN_PORT_NO DT_PROP(DT_GPIO_CTLR(CX_NODE, grant_gpios), port)
49+
#define GRANT_PIN_PIN_NO DT_GPIO_PIN(CX_NODE, grant_gpios)
50+
51+
static const nrfx_gpiote_t gpiote =
52+
NRFX_GPIOTE_INSTANCE(NRF_DT_GPIOTE_INST(CX_NODE, grant_gpios));
53+
54+
static const struct gpio_dt_spec gra_spec = GPIO_DT_SPEC_GET(CX_NODE, grant_gpios);
55+
56+
static mpsl_cx_cb_t callback;
57+
static struct gpio_callback grant_cb;
58+
static uint32_t grant_abs_pin;
59+
60+
static bool grant_pin_is_asserted(void)
61+
{
62+
int ret = gpio_pin_get_dt(&gra_spec);
63+
64+
__ASSERT(ret >= 0, "Error while reading GPIO state.");
65+
66+
return ret;
67+
}
68+
69+
static mpsl_cx_op_map_t granted_ops_map_get(void)
70+
{
71+
#if ALLOW_RX
72+
mpsl_cx_op_map_t granted_ops = MPSL_CX_OP_IDLE_LISTEN | MPSL_CX_OP_RX;
73+
#else
74+
mpsl_cx_op_map_t granted_ops = MPSL_CX_OP_IDLE_LISTEN;
75+
#endif
76+
77+
if (grant_pin_is_asserted()) {
78+
granted_ops |= MPSL_CX_OP_TX | MPSL_CX_OP_RX;
79+
}
80+
81+
return granted_ops;
82+
}
83+
84+
static int32_t granted_ops_get(mpsl_cx_op_map_t *granted_ops)
85+
{
86+
*granted_ops = granted_ops_map_get();
87+
return 0;
88+
}
89+
90+
static void gpiote_irq_handler(const struct device *gpiob, struct gpio_callback *cb, uint32_t pins)
91+
{
92+
ARG_UNUSED(gpiob);
93+
ARG_UNUSED(cb);
94+
ARG_UNUSED(pins);
95+
96+
if (callback) {
97+
mpsl_cx_op_map_t granted_ops = granted_ops_map_get();
98+
99+
callback(granted_ops);
100+
}
101+
}
102+
103+
static int32_t request(const mpsl_cx_request_t *req_params)
104+
{
105+
ARG_UNUSED(req_params);
106+
return 0;
107+
}
108+
109+
static int32_t release(void)
110+
{
111+
return 0;
112+
}
113+
114+
static uint32_t req_grant_delay_get(void)
115+
{
116+
return 0;
117+
}
118+
119+
static int32_t register_callback(mpsl_cx_cb_t cb)
120+
{
121+
callback = cb;
122+
123+
if (cb) {
124+
nrfx_gpiote_trigger_enable(&gpiote, grant_abs_pin, true);
125+
} else {
126+
nrfx_gpiote_trigger_disable(&gpiote, grant_abs_pin);
127+
}
128+
129+
return 0;
130+
}
131+
132+
static const mpsl_cx_interface_t m_mpsl_cx_methods = {
133+
.p_request = request,
134+
.p_release = release,
135+
.p_granted_ops_get = granted_ops_get,
136+
.p_req_grant_delay_get = req_grant_delay_get,
137+
.p_register_callback = register_callback,
138+
};
139+
140+
static int mpsl_cx_init(void)
141+
{
142+
int32_t ret;
143+
144+
callback = NULL;
145+
146+
ret = mpsl_cx_interface_set(&m_mpsl_cx_methods);
147+
if (ret != 0) {
148+
return ret;
149+
}
150+
151+
ret = gpio_pin_configure_dt(&gra_spec, GPIO_INPUT);
152+
if (ret != 0) {
153+
return ret;
154+
}
155+
156+
ret = gpio_pin_interrupt_configure_dt(&gra_spec,
157+
GPIO_INT_ENABLE | GPIO_INT_EDGE | GPIO_INT_EDGE_BOTH);
158+
if (ret != 0) {
159+
return ret;
160+
}
161+
162+
grant_abs_pin = NRF_GPIO_PIN_MAP(GRANT_PIN_PORT_NO, GRANT_PIN_PIN_NO);
163+
nrfx_gpiote_trigger_disable(&gpiote, grant_abs_pin);
164+
165+
gpio_init_callback(&grant_cb, gpiote_irq_handler, BIT(gra_spec.pin));
166+
gpio_add_callback(gra_spec.port, &grant_cb);
167+
168+
return 0;
169+
}
170+
171+
SYS_INIT(mpsl_cx_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
172+
173+
#else /* !defined(CONFIG_MPSL_CX_PIN_FORWARDER) */
174+
static int mpsl_cx_init(void)
175+
{
176+
#if DT_NODE_HAS_PROP(CX_NODE, grant_gpios)
177+
uint8_t grant_pin = NRF_DT_GPIOS_TO_PSEL(CX_NODE, grant_gpios);
178+
179+
soc_secure_gpio_pin_mcu_select(grant_pin, NRF_GPIO_PIN_SEL_NETWORK);
180+
#endif
181+
182+
return 0;
183+
}
184+
185+
SYS_INIT(mpsl_cx_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
186+
187+
#endif /* !defined(CONFIG_MPSL_CX_PIN_FORWARDER) */

subsys/mpsl/cx/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
#
66

77
if (CONFIG_MPSL_CX_3WIRE OR
8+
CONFIG_MPSL_CX_1WIRE OR
89
CONFIG_MPSL_CX_BT_1WIRE OR
910
CONFIG_MPSL_CX_NRF700X OR
1011
CONFIG_MPSL_CX_SOFTWARE)
1112
zephyr_library()
1213

1314
zephyr_library_sources_ifdef(CONFIG_MPSL_CX_3WIRE 3wire/mpsl_cx_3wire.c)
1415
zephyr_library_sources_ifdef(CONFIG_MPSL_CX_BT_1WIRE bluetooth/mpsl_cx_1w_bluetooth.c)
16+
zephyr_library_sources_ifdef(CONFIG_MPSL_CX_1WIRE 1wire/mpsl_cx_1wire.c)
1517
zephyr_library_sources_ifdef(CONFIG_MPSL_CX_NRF700X nrf700x/mpsl_cx_nrf700x.c)
1618
zephyr_library_sources_ifdef(CONFIG_MPSL_CX_SOFTWARE_RPC software/mpsl_cx_software_rpc.c)
1719
endif()

subsys/mpsl/cx/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,15 @@ config MPSL_CX_BT_1WIRE
8585
Radio Coexistence interface implementation using a simple 1-wire PTA
8686
implementation for co-located radios.
8787

88+
config MPSL_CX_1WIRE
89+
select NRFX_GPIOTE if !MPSL_CX_PIN_FORWARDER
90+
select GPIO if !MPSL_CX_PIN_FORWARDER
91+
bool "1-Wire Radio Coexistence [EXPERIMENTAL]"
92+
select EXPERIMENTAL
93+
help
94+
Radio Coexistence interface implementation using a simple 1-wire PTA
95+
implementation for co-located radios.
96+
8897
config MPSL_CX_SOFTWARE
8998
bool "Software Coexistence"
9099
depends on MPSL_CX_SOFTWARE_SUPPORT

0 commit comments

Comments
 (0)