1 /*
2  * Copyright (c) 2015 - 2025, Nordic Semiconductor ASA
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice, this
11  *    list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its
18  *    contributors may be used to endorse or promote products derived from this
19  *    software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #ifndef NRFX_TWI_H__
35 #define NRFX_TWI_H__
36 
37 #include <nrfx.h>
38 #include <nrfx_twi_twim.h>
39 #include <hal/nrf_twi.h>
40 
41 #ifdef __cplusplus
42 extern "C" {
43 #endif
44 
45 /**
46  * @defgroup nrfx_twi TWI driver
47  * @{
48  * @ingroup nrf_twi
49  * @brief   Two Wire Interface master (TWI) peripheral driver.
50  */
51 
52 /**
53  * @brief Structure for the TWI master driver instance.
54  */
55 typedef struct
56 {
57     NRF_TWI_Type * p_twi;        ///< Pointer to a structure with TWI registers.
58     uint8_t        drv_inst_idx; ///< Index of the driver instance. For internal use only.
59 } nrfx_twi_t;
60 
61 /** @brief Macro for creating a TWI master driver instance. */
62 #define NRFX_TWI_INSTANCE(id)                               \
63 {                                                           \
64     .p_twi        = NRFX_CONCAT(NRF_, TWI, id),             \
65     .drv_inst_idx = NRFX_CONCAT(NRFX_TWI, id, _INST_IDX),   \
66 }
67 
68 #ifndef __NRFX_DOXYGEN__
69 enum {
70     /* List all enabled driver instances (in the format NRFX_\<instance_name\>_INST_IDX). */
71     NRFX_INSTANCE_ENUM_LIST(TWI)
72     NRFX_TWI_ENABLED_COUNT
73 };
74 #endif
75 
76 /** @brief Structure for the configuration of the TWI master driver instance. */
77 typedef struct
78 {
79     uint32_t            scl;                ///< SCL pin number.
80     uint32_t            sda;                ///< SDA pin number.
81     nrf_twi_frequency_t frequency;          ///< TWI frequency.
82     uint8_t             interrupt_priority; ///< Interrupt priority.
83     bool                hold_bus_uninit;    ///< Hold pull up state on GPIO pins after uninit.
84     bool                skip_gpio_cfg;      ///< Skip GPIO configuration of pins.
85                                             /**< When set to true, the driver does not modify
86                                              *   any GPIO parameters of the used pins. Those
87                                              *   parameters are supposed to be configured
88                                              *   externally before the driver is initialized. */
89     bool                skip_psel_cfg;      ///< Skip pin selection configuration.
90                                             /**< When set to true, the driver does not modify
91                                              *   pin select registers in the peripheral.
92                                              *   Those registers are supposed to be set up
93                                              *   externally before the driver is initialized.
94                                              *   @note When both GPIO configuration and pin
95                                              *   selection are to be skipped, the structure
96                                              *   fields that specify pins can be omitted,
97                                              *   as they are ignored anyway. */
98 } nrfx_twi_config_t;
99 
100 /**
101  * @brief TWI master driver instance default configuration.
102  *
103  * This configuration sets up TWI with the following options:
104  * - clock frequency: 100 kHz
105  * - disable bus holding after uninit
106  *
107  * @param[in] _pin_scl SCL pin.
108  * @param[in] _pin_sda SDA pin.
109  */
110 #define NRFX_TWI_DEFAULT_CONFIG(_pin_scl, _pin_sda)              \
111 {                                                                \
112     .scl                = _pin_scl,                              \
113     .sda                = _pin_sda,                              \
114     .frequency          = NRF_TWI_FREQ_100K,                     \
115     .interrupt_priority = NRFX_TWI_DEFAULT_CONFIG_IRQ_PRIORITY,  \
116     .hold_bus_uninit    = false,                                 \
117 }
118 
119 /** @brief Flag indicating that the interrupt after each transfer will be suppressed, and the event handler will not be called. */
120 #define NRFX_TWI_FLAG_NO_XFER_EVT_HANDLER (1UL << 2)
121 /** @brief Flag indicating that the TX transfer will not end with a stop condition. */
122 #define NRFX_TWI_FLAG_TX_NO_STOP          (1UL << 5)
123 /** @brief Flag indicating that the transfer will be suspended. */
124 #define NRFX_TWI_FLAG_SUSPEND             (1UL << 6)
125 
126 /** @brief TWI master driver event types. */
127 typedef enum
128 {
129     NRFX_TWI_EVT_DONE,         ///< Transfer completed event.
130     NRFX_TWI_EVT_ADDRESS_NACK, ///< Error event: NACK received after sending the address.
131     NRFX_TWI_EVT_DATA_NACK,    ///< Error event: NACK received after sending a data byte.
132     NRFX_TWI_EVT_OVERRUN,      ///< Error event: The unread data is replaced by new data.
133     NRFX_TWI_EVT_BUS_ERROR     ///< Error event: An unexpected transition occurred on the bus.
134 } nrfx_twi_evt_type_t;
135 
136 /** @brief TWI master driver transfer types. */
137 typedef enum
138 {
139     NRFX_TWI_XFER_TX,   ///< TX transfer.
140     NRFX_TWI_XFER_RX,   ///< RX transfer.
141     NRFX_TWI_XFER_TXRX, ///< TX transfer followed by RX transfer with repeated start.
142     NRFX_TWI_XFER_TXTX  ///< TX transfer followed by TX transfer with repeated start.
143 } nrfx_twi_xfer_type_t;
144 
145 /** @brief Structure for a TWI transfer descriptor. */
146 typedef struct
147 {
148     nrfx_twi_xfer_type_t    type;             ///< Type of transfer.
149     uint8_t                 address;          ///< Slave address.
150     size_t                  primary_length;   ///< Number of bytes transferred.
151     size_t                  secondary_length; ///< Number of bytes transferred.
152     uint8_t *               p_primary_buf;    ///< Pointer to transferred data.
153     uint8_t *               p_secondary_buf;  ///< Pointer to transferred data.
154 } nrfx_twi_xfer_desc_t;
155 
156 
157 /** @brief Macro for setting the TX transfer descriptor. */
158 #define NRFX_TWI_XFER_DESC_TX(addr, p_data, length) \
159 {                                                   \
160     .type             = NRFX_TWI_XFER_TX,           \
161     .address          = (addr),                     \
162     .primary_length   = (length),                   \
163     .secondary_length = 0,                          \
164     .p_primary_buf    = (p_data),                   \
165     .p_secondary_buf  = NULL,                       \
166 }
167 
168 /** @brief Macro for setting the RX transfer descriptor. */
169 #define NRFX_TWI_XFER_DESC_RX(addr, p_data, length) \
170 {                                                   \
171     .type             = NRFX_TWI_XFER_RX,           \
172     .address          = (addr),                     \
173     .primary_length   = (length),                   \
174     .secondary_length = 0,                          \
175     .p_primary_buf    = (p_data),                   \
176     .p_secondary_buf  = NULL,                       \
177 }
178 
179 /** @brief Macro for setting the TX-RX transfer descriptor. */
180 #define NRFX_TWI_XFER_DESC_TXRX(addr, p_tx, tx_len, p_rx, rx_len) \
181 {                                                                 \
182     .type             = NRFX_TWI_XFER_TXRX,                       \
183     .address          = (addr),                                   \
184     .primary_length   = (tx_len),                                 \
185     .secondary_length = (rx_len),                                 \
186     .p_primary_buf    = (p_tx),                                   \
187     .p_secondary_buf  = (p_rx),                                   \
188 }
189 
190 /** @brief Macro for setting the TX-TX transfer descriptor. */
191 #define NRFX_TWI_XFER_DESC_TXTX(addr, p_tx, tx_len, p_tx2, tx_len2) \
192 {                                                                   \
193     .type             = NRFX_TWI_XFER_TXTX,                         \
194     .address          = (addr),                                     \
195     .primary_length   = (tx_len),                                   \
196     .secondary_length = (tx_len2),                                  \
197     .p_primary_buf    = (p_tx),                                     \
198     .p_secondary_buf  = (p_tx2),                                    \
199 }
200 
201 /** @brief Structure for a TWI event. */
202 typedef struct
203 {
204     nrfx_twi_evt_type_t  type;      ///< Event type.
205     nrfx_twi_xfer_desc_t xfer_desc; ///< Transfer details.
206 } nrfx_twi_evt_t;
207 
208 /** @brief TWI event handler prototype. */
209 typedef void (* nrfx_twi_evt_handler_t)(nrfx_twi_evt_t const * p_event,
210                                         void *                 p_context);
211 
212 /**
213  * @brief Function for initializing the TWI driver instance.
214  *
215  * @param[in] p_instance    Pointer to the driver instance structure.
216  * @param[in] p_config      Pointer to the structure with the initial configuration.
217  * @param[in] event_handler Event handler provided by the user. If NULL, blocking mode is enabled.
218  * @param[in] p_context     Context passed to event handler.
219  *
220  * @retval NRFX_SUCCESS             Initialization is successful.
221  * @retval NRFX_ERROR_ALREADY       The driver is already initialized.
222  * @retval NRFX_ERROR_INVALID_STATE The driver is already initialized.
223  *                                  Deprecated - use @ref NRFX_ERROR_ALREADY instead.
224  * @retval NRFX_ERROR_BUSY          Some other peripheral with the same
225  *                                  instance ID is already in use. This is
226  *                                  possible only if @ref nrfx_prs module
227  *                                  is enabled.
228  */
229 nrfx_err_t nrfx_twi_init(nrfx_twi_t const *        p_instance,
230                          nrfx_twi_config_t const * p_config,
231                          nrfx_twi_evt_handler_t    event_handler,
232                          void *                    p_context);
233 
234 /**
235  * @brief Function for reconfiguring the TWI instance.
236  *
237  * @param[in] p_instance Pointer to the driver instance structure.
238  * @param[in] p_config   Pointer to the structure with the configuration.
239  *
240  * @retval NRFX_SUCCESS             Reconfiguration was successful.
241  * @retval NRFX_ERROR_BUSY          The driver is during transaction.
242  * @retval NRFX_ERROR_INVALID_STATE The driver is uninitialized.
243  */
244 nrfx_err_t nrfx_twi_reconfigure(nrfx_twi_t const *        p_instance,
245                                 nrfx_twi_config_t const * p_config);
246 
247 /**
248  * @brief Function for uninitializing the TWI instance.
249  *
250  * @param[in] p_instance Pointer to the driver instance structure.
251  */
252 void nrfx_twi_uninit(nrfx_twi_t const * p_instance);
253 
254 /**
255  * @brief Function for checking if the TWI driver instance is initialized.
256  *
257  * @param[in] p_instance Pointer to the driver instance structure.
258  *
259  * @retval true  Instance is already initialized.
260  * @retval false Instance is not initialized.
261  */
262 bool nrfx_twi_init_check(nrfx_twi_t const * p_instance);
263 
264 /**
265  * @brief Function for enabling the TWI instance.
266  *
267  * @param[in] p_instance Pointer to the driver instance structure.
268  */
269 void nrfx_twi_enable(nrfx_twi_t const * p_instance);
270 
271 /**
272  * @brief Function for disabling the TWI instance.
273  *
274  * @param[in] p_instance Pointer to the driver instance structure.
275  */
276 void nrfx_twi_disable(nrfx_twi_t const * p_instance);
277 
278 /**
279  * @brief Function for performing a TWI transfer.
280  *
281  * The following transfer types can be configured (@ref nrfx_twi_xfer_desc_t.type):
282  * - @ref NRFX_TWI_XFER_TXRX - Write operation followed by a read operation (without STOP condition in between).
283  * - @ref NRFX_TWI_XFER_TXTX - Write operation followed by a write operation (without STOP condition in between).
284  * - @ref NRFX_TWI_XFER_TX - Write operation (with or without STOP condition).
285  * - @ref NRFX_TWI_XFER_RX - Read operation  (with STOP condition).
286  *
287  * @note TX-RX and TX-TX transfers are supported only in non-blocking mode.
288  *
289  * Additional options are provided using the flags parameter:
290  * - @ref NRFX_TWI_FLAG_NO_XFER_EVT_HANDLER - No user event handler after transfer completion. In most cases, this also means no interrupt at the end of the transfer.
291  * - @ref NRFX_TWI_FLAG_TX_NO_STOP - No stop condition after TX transfer.
292  * - @ref NRFX_TWI_FLAG_SUSPEND - Transfer will be suspended. This allows for combining multiple transfers into one transaction.
293  *                                Only transactions with the same direction can be combined. To finish the transaction, call the function without this flag.
294  *
295  * @note
296  * Some flag combinations are invalid:
297  * - @ref NRFX_TWI_FLAG_TX_NO_STOP with @ref nrfx_twi_xfer_desc_t.type different than @ref NRFX_TWI_XFER_TX
298  *
299  * @param[in] p_instance  Pointer to the driver instance structure.
300  * @param[in] p_xfer_desc Pointer to the transfer descriptor.
301  * @param[in] flags       Transfer options (0 for default settings).
302  *
303  * @retval NRFX_SUCCESS                   The procedure is successful.
304  * @retval NRFX_ERROR_BUSY                The driver is not ready for a new transfer.
305  * @retval NRFX_ERROR_NOT_SUPPORTED       The provided parameters are not supported.
306  * @retval NRFX_ERROR_INTERNAL            An unexpected transition occurred on the bus.
307  * @retval NRFX_ERROR_INVALID_STATE       Other direction of transaction is suspended on the bus.
308  * @retval NRFX_ERROR_DRV_TWI_ERR_OVERRUN The unread data is replaced by new data (TXRX and RX)
309  * @retval NRFX_ERROR_DRV_TWI_ERR_ANACK   Negative acknowledgement (NACK) is received after sending
310  *                                        the address in polling mode.
311  * @retval NRFX_ERROR_DRV_TWI_ERR_DNACK   Negative acknowledgement (NACK) is received after sending
312  *                                        a data byte in polling mode.
313  */
314 nrfx_err_t nrfx_twi_xfer(nrfx_twi_t           const * p_instance,
315                          nrfx_twi_xfer_desc_t const * p_xfer_desc,
316                          uint32_t                     flags);
317 
318 /**
319  * @brief Function for checking the TWI driver state.
320  *
321  * @param[in] p_instance TWI instance.
322  *
323  * @retval true  The TWI driver is currently busy performing a transfer.
324  * @retval false The TWI driver is ready for a new transfer.
325  */
326 bool nrfx_twi_is_busy(nrfx_twi_t const * p_instance);
327 
328 /**
329  * @brief Function for getting the transferred data count.
330  *
331  * @param[in] p_instance Pointer to the driver instance structure.
332  *
333  * @return Data count.
334  */
335 size_t nrfx_twi_data_count_get(nrfx_twi_t const * p_instance);
336 
337 /**
338  * @brief Function for returning the address of a STOPPED TWI event.
339  *
340  * A STOPPED event can be used to detect the end of a transfer if the @ref NRFX_TWI_FLAG_NO_XFER_EVT_HANDLER
341  * option is used.
342  *
343  * @param[in] p_instance Pointer to the driver instance structure.
344  *
345  * @return STOPPED event address.
346  */
347 uint32_t nrfx_twi_stopped_event_get(nrfx_twi_t const * p_instance);
348 
349 /**
350  * @brief Function for recovering the bus.
351  *
352  * This function checks if the bus is not stuck because of a slave holding the SDA line in the low state,
353  * and if needed it performs required number of pulses on the SCL line to make the slave release the SDA line.
354  * Finally, the function generates a STOP condition on the bus to put it into a known state.
355  *
356  * @note This function can be used only if the TWI driver is uninitialized.
357  *
358  * @param[in] scl_pin SCL pin number.
359  * @param[in] sda_pin SDA pin number.
360  *
361  * @retval NRFX_SUCCESS        Bus recovery was successful.
362  * @retval NRFX_ERROR_INTERNAL Bus recovery failed.
363  */
364 NRFX_STATIC_INLINE nrfx_err_t nrfx_twi_bus_recover(uint32_t scl_pin, uint32_t sda_pin);
365 
366 #ifndef NRFX_DECLARE_ONLY
nrfx_twi_bus_recover(uint32_t scl_pin,uint32_t sda_pin)367 NRFX_STATIC_INLINE nrfx_err_t nrfx_twi_bus_recover(uint32_t scl_pin, uint32_t sda_pin)
368 {
369     return nrfx_twi_twim_bus_recover(scl_pin, sda_pin);
370 }
371 #endif
372 
373 /**
374  * @brief Macro returning TWI interrupt handler.
375  *
376  * param[in] idx TWI index.
377  *
378  * @return Interrupt handler.
379  */
380 #define NRFX_TWI_INST_HANDLER_GET(idx) NRFX_CONCAT_3(nrfx_twi_, idx, _irq_handler)
381 
382 /** @} */
383 
384 /*
385  * Declare interrupt handlers for all enabled driver instances in the following format:
386  * nrfx_\<periph_name\>_\<idx\>_irq_handler (for example, nrfx_twi_0_irq_handler).
387  *
388  * A specific interrupt handler for the driver instance can be retrieved by using
389  * the NRFX_TWI_INST_HANDLER_GET macro.
390  *
391  * Here is a sample of using the NRFX_TWI_INST_HANDLER_GET macro to map an interrupt handler
392  * in a Zephyr application:
393  *
394  * IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_TWI_INST_GET(\<instance_index\>)), \<priority\>,
395  *             NRFX_TWI_INST_HANDLER_GET(\<instance_index\>), 0, 0);
396  */
397 NRFX_INSTANCE_IRQ_HANDLERS_DECLARE(TWI, twi)
398 
399 #ifdef __cplusplus
400 }
401 #endif
402 
403 #endif // NRFX_TWI_H__
404