Skip to content

Commit 7b45c6a

Browse files
lib: bm_spi_mngr: add bare metal SPI transaction manager
Add a bare metal SPI transaction manager library on top of the nrfx SPIM driver. The library serializes work on a single SPIM instance by keeping pending transactions in a FIFO queue and running them back-to-back on the bus. Each transaction is a sequence of one or more TX/RX transfers with optional begin and end callbacks. It exposes both a non-blocking API (bm_spi_mngr_schedule) and a blocking API (bm_spi_mngr_perform) on top of a shared scheduling engine. Each transaction may carry its own SPIM configuration, in which case the driver is reinitialized before the first transfer if the configuration differs from the one currently in use. The library is functionally equivalent to the legacy nRF5 SDK nrf_spi_mngr module, ported to NCS conventions. Signed-off-by: Martynas Smilingis <martynas.smilingis@nordicsemi.no>
1 parent 4ced319 commit 7b45c6a

10 files changed

Lines changed: 869 additions & 0 deletions

File tree

CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
/lib/bm_timer/ @nrfconnect/ncs-bm
6464
/lib/boot_banner/ @nrfconnect/ncs-bm
6565
/lib/bm_scheduler/ @nrfconnect/ncs-bm
66+
/lib/bm_spi_mngr/ @nrfconnect/ncs-bm
6667
/lib/sensorsim/ @nrfconnect/ncs-bm
6768
/lib/zephyr_queue/ @nrfconnect/ncs-eris
6869

doc/nrf-bm/api/api.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,13 @@ Bare Metal Zephyr Memory Storage (ZMS)
145145

146146
.. doxygengroup:: bm_zms
147147

148+
.. _api_bm_spi_mngr:
149+
150+
SPI transaction manager
151+
=======================
152+
153+
.. doxygengroup:: bm_spi_mngr
154+
148155
.. _api_ble_gatt_queue:
149156

150157
GATT Queue
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
.. _lib_bm_spi_mngr:
2+
3+
SPI transaction manager
4+
#######################
5+
6+
.. contents::
7+
:local:
8+
:depth: 2
9+
10+
This library runs SPI master (SPIM) work on a single hardware instance, one job at a time.
11+
12+
Overview
13+
********
14+
15+
Applications describe work as *transactions*, where each transaction is one or more *transfers* (TX/RX steps) that run in order on the bus.
16+
The library keeps pending transactions in a FIFO queue and runs them one after another, so the application can keep scheduling work without waiting for the bus to be free.
17+
18+
The library sits on top of the nrfx SPIM driver and offers both a non-blocking mode that queues work and returns immediately, and a blocking mode that waits until the work is done.
19+
Both share the same queue and scheduling engine.
20+
21+
Each transaction can use the default SPIM configuration or supply its own.
22+
This makes it possible to share one SPIM instance between several devices on the same bus, for example by giving each device its own chip select pin.
23+
24+
Configuration
25+
*************
26+
27+
Set the :kconfig:option:`CONFIG_BM_SPI_MNGR` Kconfig option to enable the library.
28+
29+
The option depends on :kconfig:option:`CONFIG_NRFX_SPIM` and selects :kconfig:option:`CONFIG_RING_BUFFER` for the internal queue.
30+
31+
Initialization
32+
==============
33+
34+
The manager instance is declared using the :c:macro:`BM_SPI_MNGR_DEF` macro, specifying the instance name, queue size, and SPIM instance.
35+
The queue size is the number of transactions that can wait in the queue, not counting the one currently running.
36+
37+
Before initializing, connect and enable the SPIM interrupt for the chosen instance, for example with :c:macro:`BM_IRQ_DIRECT_CONNECT`.
38+
The interrupt handler must forward the event to the nrfx SPIM driver.
39+
40+
To initialize the manager, call the :c:func:`bm_spi_mngr_init` function with an :c:type:`nrfx_spim_config_t` configuration, created with :c:macro:`NRFX_SPIM_DEFAULT_CONFIG` and customized as needed.
41+
42+
The following example shows how to declare, connect, and initialize a manager instance:
43+
44+
.. code-block:: c
45+
46+
#include <bm/bm_spi_mngr.h>
47+
48+
BM_SPI_MNGR_DEF(spi_mgr, 4, SPIM_INST);
49+
50+
static nrfx_spim_config_t spim_cfg = NRFX_SPIM_DEFAULT_CONFIG(PIN_SCK, PIN_MOSI, PIN_MISO, PIN_CSN);
51+
52+
ISR_DIRECT_DECLARE(spim_isr)
53+
{
54+
nrfx_spim_irq_handler(spi_mgr.spim);
55+
return 0;
56+
}
57+
58+
BM_IRQ_DIRECT_CONNECT(NRFX_IRQ_NUMBER_GET(SPIM_INST), IRQ_PRIO_LOWEST, spim_isr, 0);
59+
irq_enable(NRFX_IRQ_NUMBER_GET(SPIM_INST));
60+
61+
bm_spi_mngr_init(&spi_mgr, &spim_cfg);
62+
63+
You can uninitialize a manager instance with the :c:func:`bm_spi_mngr_uninit` function.
64+
Do not call it while a transaction is running or while a caller is blocked in :c:func:`bm_spi_mngr_perform`, as it does not cancel pending work or release blocked callers.
65+
66+
Usage
67+
*****
68+
69+
Work is described in a :c:struct:`bm_spi_mngr_transaction` structure, holding an array of transfers and the number of transfers.
70+
Use the :c:macro:`BM_SPI_MNGR_TRANSFER` macro to set up each transfer.
71+
72+
A transaction can optionally provide a begin callback, an end callback, and a per-transaction SPIM configuration.
73+
Both callbacks may run from the SPIM interrupt handler, so keep them short, for example setting a flag.
74+
75+
.. note::
76+
77+
The transaction descriptor and any configuration it points to must stay valid until the transaction finishes, because the library stores only a pointer to it.
78+
79+
The following is a list of operations you can perform with this library.
80+
81+
Schedule (non-blocking)
82+
=======================
83+
84+
Use the :c:func:`bm_spi_mngr_schedule` function to add a transaction to the queue and return immediately.
85+
The transaction starts at once if the bus is idle, otherwise it runs after the transactions ahead of it.
86+
The completion of the transaction is reported by the optional end callback.
87+
88+
Perform (blocking)
89+
==================
90+
91+
Use the :c:func:`bm_spi_mngr_perform` function to schedule a single transaction and wait until it completes.
92+
93+
While waiting, the function can call an optional idle function repeatedly.
94+
Because the function blocks until the transaction finishes, do not call it from an interrupt handler.
95+
96+
Busy state
97+
==========
98+
99+
Use the :c:func:`bm_spi_mngr_is_idle` function to check whether all scheduled work has finished.
100+
101+
Dependencies
102+
************
103+
104+
This library has the following |BMshort| dependencies:
105+
106+
* nrfx SPIM - :kconfig:option:`CONFIG_NRFX_SPIM`
107+
* Zephyr ring buffer - :kconfig:option:`CONFIG_RING_BUFFER`
108+
109+
API documentation
110+
*****************
111+
112+
| Header file: :file:`include/bm/bm_spi_mngr.h`
113+
| Source files: :file:`lib/bm_spi_mngr/`
114+
115+
:ref:`SPI transaction manager API reference <api_bm_spi_mngr>`

doc/nrf-bm/release_notes/release_notes_changelog.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ Libraries
8181
* An issue where the :c:func:`ble_conn_params_phy_radio_mode_get` function would incorrectly return the PHY mode mask of a pending update rather than the currently active PHY mode if a PHY update initiated by the :c:func:`ble_conn_params_phy_radio_mode_set` function was still in progress.
8282
* An issue where the SoftDevice define :c:macro:`BLE_GAP_PHYS_SUPPORTED` was used instead of the PHY preferences set with Kconfig when initiating or responding to a PHY update procedure.
8383

84+
* Added the :ref:`lib_bm_spi_mngr` library for queued SPI master transactions on a single SPIM instance.
85+
Enable it with the :kconfig:option:`CONFIG_BM_SPI_MNGR` Kconfig option.
86+
See :ref:`lib_bm_spi_mngr` for an overview and :ref:`SPI transaction manager API reference <api_bm_spi_mngr>` for the full API.
87+
8488
Bluetooth LE Services
8589
---------------------
8690

0 commit comments

Comments
 (0)