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 #include <nrfx.h>
35 
36 #if NRFX_CHECK(NRFX_TWI_ENABLED)
37 
38 #if !NRFX_FEATURE_PRESENT(NRFX_TWI, _ENABLED)
39 #error "No enabled TWI instances. Check <nrfx_config.h>."
40 #endif
41 
42 #include <nrfx_twi.h>
43 #include <hal/nrf_gpio.h>
44 #include "prs/nrfx_prs.h"
45 
46 #define NRFX_LOG_MODULE TWI
47 #include <nrfx_log.h>
48 
49 #define EVT_TO_STR(event)                                      \
50     (event == NRFX_TWI_EVT_DONE         ? "EVT_DONE"         : \
51     (event == NRFX_TWI_EVT_ADDRESS_NACK ? "EVT_ADDRESS_NACK" : \
52     (event == NRFX_TWI_EVT_DATA_NACK    ? "EVT_DATA_NACK"    : \
53     (event == NRFX_TWI_EVT_OVERRUN      ? "EVT_OVERRUN"      : \
54     (event == NRFX_TWI_EVT_BUS_ERROR    ? "EVT_BUS_ERROR"    : \
55                                           "UNKNOWN ERROR")))))
56 
57 #define EVT_TO_STR_TWI(event)                                       \
58     (event == NRF_TWI_EVENT_STOPPED   ? "NRF_TWI_EVENT_STOPPED"   : \
59     (event == NRF_TWI_EVENT_RXDREADY  ? "NRF_TWI_EVENT_RXDREADY"  : \
60     (event == NRF_TWI_EVENT_TXDSENT   ? "NRF_TWI_EVENT_TXDSENT"   : \
61     (event == NRF_TWI_EVENT_ERROR     ? "NRF_TWI_EVENT_ERROR"     : \
62     (event == NRF_TWI_EVENT_BB        ? "NRF_TWI_EVENT_BB"        : \
63     (event == NRF_TWI_EVENT_SUSPENDED ? "NRF_TWI_EVENT_SUSPENDED" : \
64                                         "UNKNOWN ERROR"))))))
65 
66 #define TRANSFER_TO_STR(type)                   \
67     (type == NRFX_TWI_XFER_TX   ? "XFER_TX"   : \
68     (type == NRFX_TWI_XFER_RX   ? "XFER_RX"   : \
69     (type == NRFX_TWI_XFER_TXRX ? "XFER_TXRX" : \
70     (type == NRFX_TWI_XFER_TXTX ? "XFER_TXTX" : \
71                                   "UNKNOWN TRANSFER TYPE"))))
72 
73 #define TWI_PIN_INIT(_pin) nrf_gpio_cfg((_pin),                     \
74                                         NRF_GPIO_PIN_DIR_INPUT,     \
75                                         NRF_GPIO_PIN_INPUT_CONNECT, \
76                                         NRF_GPIO_PIN_PULLUP,        \
77                                         NRF_GPIO_PIN_S0D1,          \
78                                         NRF_GPIO_PIN_NOSENSE)
79 
80 #define TWI_FLAG_NO_STOP(flags)             (flags & NRFX_TWI_FLAG_TX_NO_STOP)
81 #define TWI_FLAG_SUSPEND(flags)             (flags & NRFX_TWI_FLAG_SUSPEND)
82 #define TWI_FLAG_NO_HANDLER_IN_USE(flags)   (flags & NRFX_TWI_FLAG_NO_XFER_EVT_HANDLER)
83 
84 #define HW_TIMEOUT      100000
85 
86 /* TWI master driver suspend types. */
87 typedef enum
88 {
89     TWI_NO_SUSPEND, //< Last transfer was not suspended.
90     TWI_SUSPEND_TX, //< Last transfer was TX and was suspended.
91     TWI_SUSPEND_RX  //< Last transfer was RX and was suspended.
92 } twi_suspend_t;
93 
94 // Control block - driver instance local data.
95 typedef struct
96 {
97     nrfx_twi_evt_handler_t  handler;
98     void *                  p_context;
99     volatile uint32_t       int_mask;
100     nrfx_twi_xfer_desc_t    xfer_desc;
101     uint32_t                flags;
102     uint8_t *               p_curr_buf;
103     size_t                  curr_length;
104     bool                    curr_tx_no_stop;
105     twi_suspend_t           prev_suspend;
106     nrfx_drv_state_t        state;
107     bool                    error;
108     volatile bool           busy;
109     bool                    repeated;
110     size_t                  bytes_transferred;
111     bool                    hold_bus_uninit;
112     bool                    skip_gpio_cfg;
113 } twi_control_block_t;
114 
115 static twi_control_block_t m_cb[NRFX_TWI_ENABLED_COUNT];
116 
twi_process_error(uint32_t errorsrc)117 static nrfx_err_t twi_process_error(uint32_t errorsrc)
118 {
119     nrfx_err_t ret = NRFX_ERROR_INTERNAL;
120 
121     if (errorsrc & NRF_TWI_ERROR_OVERRUN)
122     {
123         ret = NRFX_ERROR_DRV_TWI_ERR_OVERRUN;
124     }
125 
126     if (errorsrc & NRF_TWI_ERROR_ADDRESS_NACK)
127     {
128         ret = NRFX_ERROR_DRV_TWI_ERR_ANACK;
129     }
130 
131     if (errorsrc & NRF_TWI_ERROR_DATA_NACK)
132     {
133         ret = NRFX_ERROR_DRV_TWI_ERR_DNACK;
134     }
135 
136     return ret;
137 }
138 
xfer_completeness_check(NRF_TWI_Type * p_twi,twi_control_block_t const * p_cb)139 static bool xfer_completeness_check(NRF_TWI_Type * p_twi, twi_control_block_t const * p_cb)
140 {
141     // If the actual number of transferred bytes is not equal to what was requested,
142     // but there was no error signaled by the peripheral, this means that something
143     // unexpected, like a premature STOP condition, was received on the bus.
144     // In such case the peripheral has to be disabled and re-enabled, so that its
145     // internal state machine is reinitialized.
146 
147     if (p_cb->bytes_transferred != p_cb->curr_length)
148     {
149         nrf_twi_disable(p_twi);
150         nrf_twi_enable(p_twi);
151         return false;
152     }
153     else
154     {
155         return true;
156     }
157 }
158 
twi_configure(nrfx_twi_t const * p_instance,nrfx_twi_config_t const * p_config)159 static void twi_configure(nrfx_twi_t const *        p_instance,
160                           nrfx_twi_config_t const * p_config)
161 {
162     if (!p_config->skip_psel_cfg)
163     {
164         nrf_twi_pins_set(p_instance->p_twi, p_config->scl, p_config->sda);
165     }
166     nrf_twi_frequency_set(p_instance->p_twi, p_config->frequency);
167 
168     if (m_cb[p_instance->drv_inst_idx].handler)
169     {
170         NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_twi),
171                               p_config->interrupt_priority);
172         NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_twi));
173     }
174 }
175 
nrfx_twi_init(nrfx_twi_t const * p_instance,nrfx_twi_config_t const * p_config,nrfx_twi_evt_handler_t event_handler,void * p_context)176 nrfx_err_t nrfx_twi_init(nrfx_twi_t const *        p_instance,
177                          nrfx_twi_config_t const * p_config,
178                          nrfx_twi_evt_handler_t    event_handler,
179                          void *                    p_context)
180 {
181     NRFX_ASSERT(p_config);
182 
183     twi_control_block_t * p_cb  = &m_cb[p_instance->drv_inst_idx];
184     nrfx_err_t err_code;
185 
186     if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
187     {
188 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
189         err_code = NRFX_ERROR_ALREADY;
190 #else
191         err_code = NRFX_ERROR_INVALID_STATE;
192 #endif
193         NRFX_LOG_WARNING("Function: %s, error code: %s.",
194                          __func__,
195                          NRFX_LOG_ERROR_STRING_GET(err_code));
196         return err_code;
197     }
198 
199 #if NRFX_CHECK(NRFX_PRS_ENABLED)
200     static nrfx_irq_handler_t const irq_handlers[NRFX_TWI_ENABLED_COUNT] = {
201         NRFX_INSTANCE_IRQ_HANDLERS_LIST(TWI, twi)
202     };
203     if (nrfx_prs_acquire(p_instance->p_twi,
204             irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
205     {
206         err_code = NRFX_ERROR_BUSY;
207         NRFX_LOG_WARNING("Function: %s, error code: %s.",
208                          __func__,
209                          NRFX_LOG_ERROR_STRING_GET(err_code));
210         return err_code;
211     }
212 #endif // NRFX_CHECK(NRFX_PRS_ENABLED)
213 
214     p_cb->handler         = event_handler;
215     p_cb->p_context       = p_context;
216     p_cb->int_mask        = 0;
217     p_cb->prev_suspend    = TWI_NO_SUSPEND;
218     p_cb->repeated        = false;
219     p_cb->busy            = false;
220 
221     if (p_config)
222     {
223         p_cb->hold_bus_uninit = p_config->hold_bus_uninit;
224         p_cb->skip_gpio_cfg   = p_config->skip_gpio_cfg;
225 
226         /* To secure correct signal levels on the pins used by the TWI
227            master when the system is in OFF mode, and when the TWI master is
228            disabled, these pins must be configured in the GPIO peripheral.
229         */
230         if (!p_config->skip_gpio_cfg)
231         {
232             NRFX_ASSERT(p_config->scl != p_config->sda);
233             TWI_PIN_INIT(p_config->scl);
234             TWI_PIN_INIT(p_config->sda);
235         }
236         twi_configure(p_instance, p_config);
237     }
238 
239     p_cb->state = NRFX_DRV_STATE_INITIALIZED;
240 
241     err_code = NRFX_SUCCESS;
242     NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
243     return err_code;
244 }
245 
nrfx_twi_reconfigure(nrfx_twi_t const * p_instance,nrfx_twi_config_t const * p_config)246 nrfx_err_t nrfx_twi_reconfigure(nrfx_twi_t const *        p_instance,
247                                 nrfx_twi_config_t const * p_config)
248 {
249     NRFX_ASSERT(p_config);
250 
251     twi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
252 
253     if (p_cb->state == NRFX_DRV_STATE_UNINITIALIZED)
254     {
255         return NRFX_ERROR_INVALID_STATE;
256     }
257     if (p_cb->busy)
258     {
259         return NRFX_ERROR_BUSY;
260     }
261     nrf_twi_disable(p_instance->p_twi);
262     p_cb->hold_bus_uninit = p_config->hold_bus_uninit;
263     twi_configure(p_instance, p_config);
264     nrf_twi_enable(p_instance->p_twi);
265     return NRFX_SUCCESS;
266 }
267 
nrfx_twi_uninit(nrfx_twi_t const * p_instance)268 void nrfx_twi_uninit(nrfx_twi_t const * p_instance)
269 {
270     twi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
271 
272     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
273 
274     if (p_cb->handler)
275     {
276         NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_twi));
277     }
278     nrfx_twi_disable(p_instance);
279 
280 #if NRFX_CHECK(NRFX_PRS_ENABLED)
281     nrfx_prs_release(p_instance->p_twi);
282 #endif
283 
284     if (!p_cb->skip_gpio_cfg && !p_cb->hold_bus_uninit)
285     {
286         nrf_gpio_cfg_default(nrf_twi_scl_pin_get(p_instance->p_twi));
287         nrf_gpio_cfg_default(nrf_twi_sda_pin_get(p_instance->p_twi));
288     }
289 
290     p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
291     NRFX_LOG_INFO("Instance uninitialized: %d.", p_instance->drv_inst_idx);
292 }
293 
nrfx_twi_init_check(nrfx_twi_t const * p_instance)294 bool nrfx_twi_init_check(nrfx_twi_t const * p_instance)
295 {
296     twi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
297 
298     return (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
299 }
300 
nrfx_twi_enable(nrfx_twi_t const * p_instance)301 void nrfx_twi_enable(nrfx_twi_t const * p_instance)
302 {
303     twi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
304 
305     NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED);
306 
307     NRF_TWI_Type * p_twi = p_instance->p_twi;
308     nrf_twi_enable(p_twi);
309 
310     p_cb->state = NRFX_DRV_STATE_POWERED_ON;
311     NRFX_LOG_INFO("Instance enabled: %d.", p_instance->drv_inst_idx);
312 }
313 
nrfx_twi_disable(nrfx_twi_t const * p_instance)314 void nrfx_twi_disable(nrfx_twi_t const * p_instance)
315 {
316     twi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
317 
318     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
319 
320     NRF_TWI_Type * p_twi = p_instance->p_twi;
321     nrf_twi_int_disable(p_twi, NRF_TWI_ALL_INTS_MASK);
322     nrf_twi_shorts_disable(p_twi, NRF_TWI_ALL_SHORTS_MASK);
323     nrf_twi_disable(p_twi);
324 
325     p_cb->state = NRFX_DRV_STATE_INITIALIZED;
326     p_cb->busy = false;
327     NRFX_LOG_INFO("Instance disabled: %d.", p_instance->drv_inst_idx);
328 }
329 
twi_send_byte(NRF_TWI_Type * p_twi,twi_control_block_t * p_cb)330 static bool twi_send_byte(NRF_TWI_Type          * p_twi,
331                           twi_control_block_t   * p_cb)
332 {
333     if (p_cb->bytes_transferred < p_cb->curr_length)
334     {
335         nrf_twi_txd_set(p_twi, p_cb->p_curr_buf[p_cb->bytes_transferred]);
336     }
337     else
338     {
339         if (p_cb->curr_tx_no_stop)
340         {
341             nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_SUSPEND);
342             return false;
343         }
344         else if(TWI_FLAG_SUSPEND(p_cb->flags))
345         {
346             nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_SUSPEND);
347             p_cb->prev_suspend = TWI_SUSPEND_TX;
348             return false;
349         }
350         else
351         {
352             nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STOP);
353         }
354     }
355     return true;
356 }
357 
twi_receive_byte(NRF_TWI_Type * p_twi,twi_control_block_t * p_cb)358 static bool twi_receive_byte(NRF_TWI_Type         * p_twi,
359                              twi_control_block_t  * p_cb)
360 {
361     if (p_cb->bytes_transferred < p_cb->curr_length)
362     {
363         p_cb->p_curr_buf[p_cb->bytes_transferred] = nrf_twi_rxd_get(p_twi);
364 
365         ++(p_cb->bytes_transferred);
366 
367         if ((p_cb->bytes_transferred == p_cb->curr_length - 1) && (!TWI_FLAG_SUSPEND(p_cb->flags)))
368         {
369             nrf_twi_shorts_set(p_twi, NRF_TWI_SHORT_BB_STOP_MASK);
370         }
371         else if (p_cb->bytes_transferred == p_cb->curr_length && (!TWI_FLAG_SUSPEND(p_cb->flags)))
372         {
373             return true;
374         }
375         else if (p_cb->bytes_transferred == p_cb->curr_length && TWI_FLAG_SUSPEND(p_cb->flags))
376         {
377             p_cb->prev_suspend = TWI_SUSPEND_RX;
378             return false;
379         }
380 
381         nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_RESUME);
382     }
383     return true;
384 }
385 
twi_transfer(NRF_TWI_Type * p_twi,twi_control_block_t * p_cb)386 static bool twi_transfer(NRF_TWI_Type           * p_twi,
387                          twi_control_block_t    * p_cb)
388 {
389     bool stopped = false;
390     if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_STOPPED))
391     {
392         nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_STOPPED);
393         NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_STOPPED));
394 
395         // Delay handling of STOPPED event till the end of events processing procedure.
396         // If penultimate byte is received and function gets interrupted for long enough
397         // after enabling BB_STOP shortcut, RXDREADY for last byte as well as STOPPED
398         // may be active at the same time. Therefore RXREADY has to be processed before STOPPED to
399         // acquire last byte before finishing transmission by returning 'false'.
400         stopped = true;
401     }
402 
403     if (p_cb->error)
404     {
405         nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR);
406         nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_TXDSENT);
407         nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_RXDREADY);
408     }
409     else if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_ERROR))
410     {
411         nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR);
412         NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_ERROR));
413         nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STOP);
414         p_cb->error = true;
415     }
416     else
417     {
418         if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_TXDSENT))
419         {
420             nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_TXDSENT);
421             ++(p_cb->bytes_transferred);
422             NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_TXDSENT));
423             if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_ERROR))
424             {
425                 nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR);
426                 NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_ERROR));
427                 nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STOP);
428                 p_cb->error = true;
429             }
430             else
431             {
432                 if (!twi_send_byte(p_twi, p_cb))
433                 {
434                     return false;
435                 }
436             }
437         }
438         else if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_RXDREADY))
439         {
440             nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_RXDREADY);
441             NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_RXDREADY));
442             if (nrf_twi_event_check(p_twi, NRF_TWI_EVENT_ERROR))
443             {
444                 NRFX_LOG_DEBUG("TWI: Event: %s.", EVT_TO_STR_TWI(NRF_TWI_EVENT_ERROR));
445                 nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR);
446                 nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STOP);
447                 p_cb->error = true;
448             }
449             else
450             {
451                 if (!twi_receive_byte(p_twi, p_cb))
452                 {
453                     return false;
454                 }
455             }
456         }
457     }
458 
459     if (stopped)
460     {
461         p_cb->prev_suspend = TWI_NO_SUSPEND;
462         if (!p_cb->error)
463         {
464             p_cb->error = !xfer_completeness_check(p_twi, p_cb);
465         }
466         return false;
467     }
468 
469     return true;
470 }
471 
twi_tx_start_transfer(NRF_TWI_Type * p_twi,twi_control_block_t * p_cb)472 static nrfx_err_t twi_tx_start_transfer(NRF_TWI_Type        * p_twi,
473                                         twi_control_block_t * p_cb)
474 {
475     nrfx_err_t ret_code = NRFX_SUCCESS;
476     volatile int32_t hw_timeout;
477 
478     hw_timeout = HW_TIMEOUT;
479 
480     nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_STOPPED);
481     nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR);
482     nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_TXDSENT);
483     nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_RXDREADY);
484     nrf_twi_shorts_set(p_twi, 0);
485 
486     p_cb->bytes_transferred = 0;
487     p_cb->error             = false;
488 
489     // In case TWI is suspended resume its operation.
490     nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_RESUME);
491 
492     if (p_cb->prev_suspend != TWI_SUSPEND_TX)
493     {
494         nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STARTTX);
495     }
496 
497     (void)twi_send_byte(p_twi, p_cb);
498 
499     if (p_cb->handler)
500     {
501         p_cb->int_mask = NRF_TWI_INT_STOPPED_MASK   |
502                          NRF_TWI_INT_ERROR_MASK     |
503                          NRF_TWI_INT_TXDSENT_MASK   |
504                          NRF_TWI_INT_RXDREADY_MASK;
505 
506         nrf_twi_int_enable(p_twi, p_cb->int_mask);
507     }
508     else
509     {
510         while ((hw_timeout > 0) &&
511                twi_transfer(p_twi, p_cb))
512         {
513             hw_timeout--;
514         }
515 
516         if (p_cb->error)
517         {
518             uint32_t errorsrc =  nrf_twi_errorsrc_get_and_clear(p_twi);
519 
520             if (errorsrc)
521             {
522                 ret_code = twi_process_error(errorsrc);
523             }
524             else
525             {
526                 ret_code = NRFX_ERROR_INTERNAL;
527             }
528         }
529 
530         if (hw_timeout <= 0)
531         {
532             nrf_twi_disable(p_twi);
533             nrf_twi_enable(p_twi);
534             ret_code = NRFX_ERROR_INTERNAL;
535         }
536 
537     }
538     return ret_code;
539 }
540 
twi_rx_start_transfer(NRF_TWI_Type * p_twi,twi_control_block_t * p_cb)541 static nrfx_err_t twi_rx_start_transfer(NRF_TWI_Type        * p_twi,
542                                         twi_control_block_t * p_cb)
543 {
544     nrfx_err_t ret_code = NRFX_SUCCESS;
545     volatile int32_t hw_timeout;
546 
547     hw_timeout = HW_TIMEOUT;
548 
549     nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_STOPPED);
550     nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR);
551     nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_TXDSENT);
552     nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_RXDREADY);
553 
554     p_cb->bytes_transferred = 0;
555     p_cb->error             = false;
556 
557     if ((p_cb->curr_length == 1) && (!TWI_FLAG_SUSPEND(p_cb->flags)))
558     {
559         nrf_twi_shorts_set(p_twi, NRF_TWI_SHORT_BB_STOP_MASK);
560     }
561     else
562     {
563         nrf_twi_shorts_set(p_twi, NRF_TWI_SHORT_BB_SUSPEND_MASK);
564     }
565     // In case TWI is suspended resume its operation.
566     nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_RESUME);
567 
568     if (p_cb->prev_suspend != TWI_SUSPEND_RX)
569     {
570         nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STARTRX);
571     }
572 
573     if (p_cb->handler)
574     {
575         p_cb->int_mask = NRF_TWI_INT_STOPPED_MASK   |
576                         NRF_TWI_INT_ERROR_MASK     |
577                         NRF_TWI_INT_TXDSENT_MASK   |
578                         NRF_TWI_INT_RXDREADY_MASK;
579         nrf_twi_int_enable(p_twi, p_cb->int_mask);
580     }
581     else
582     {
583         while ((hw_timeout > 0) &&
584                twi_transfer(p_twi, p_cb))
585         {
586                hw_timeout--;
587         }
588 
589         if (p_cb->error)
590         {
591             uint32_t errorsrc =  nrf_twi_errorsrc_get_and_clear(p_twi);
592 
593             if (errorsrc)
594             {
595                 ret_code = twi_process_error(errorsrc);
596             }
597             else
598             {
599                 ret_code = NRFX_ERROR_INTERNAL;
600             }
601         }
602         if (hw_timeout <= 0)
603         {
604             nrf_twi_disable(p_twi);
605             nrf_twi_enable(p_twi);
606             ret_code = NRFX_ERROR_INTERNAL;
607         }
608     }
609     return ret_code;
610 }
611 
twi_xfer(NRF_TWI_Type * p_twi,twi_control_block_t * p_cb,nrfx_twi_xfer_desc_t const * p_xfer_desc,uint32_t flags)612 static nrfx_err_t twi_xfer(NRF_TWI_Type               * p_twi,
613                            twi_control_block_t        * p_cb,
614                            nrfx_twi_xfer_desc_t const * p_xfer_desc,
615                            uint32_t                     flags)
616 {
617     nrfx_err_t err_code = NRFX_SUCCESS;
618 
619     if ((p_cb->prev_suspend == TWI_SUSPEND_TX) && (p_xfer_desc->type == NRFX_TWI_XFER_RX))
620     {
621         /* RX is invalid after TX suspend */
622         return NRFX_ERROR_INVALID_STATE;
623     }
624     else if ((p_cb->prev_suspend == TWI_SUSPEND_RX) && (p_xfer_desc->type != NRFX_TWI_XFER_RX))
625     {
626         /* TX, TXRX and TXTX are invalid after RX suspend */
627         return NRFX_ERROR_INVALID_STATE;
628     }
629 
630     /* Block TWI interrupts to ensure that function is not interrupted by TWI interrupt. */
631     nrf_twi_int_disable(p_twi, NRF_TWI_ALL_INTS_MASK);
632 
633     if (p_cb->busy)
634     {
635         nrf_twi_int_enable(p_twi, p_cb->int_mask);
636         err_code = NRFX_ERROR_BUSY;
637         NRFX_LOG_WARNING("Function: %s, error code: %s.",
638                          __func__,
639                          NRFX_LOG_ERROR_STRING_GET(err_code));
640         return err_code;
641     }
642     else
643     {
644         p_cb->busy = (TWI_FLAG_NO_HANDLER_IN_USE(flags)) ? false : true;
645     }
646 
647     p_cb->flags       = flags;
648     p_cb->xfer_desc   = *p_xfer_desc;
649     p_cb->curr_length = p_xfer_desc->primary_length;
650     p_cb->p_curr_buf  = p_xfer_desc->p_primary_buf;
651     nrf_twi_address_set(p_twi, p_xfer_desc->address);
652 
653     if (p_xfer_desc->type != NRFX_TWI_XFER_RX)
654     {
655         p_cb->curr_tx_no_stop = ((p_xfer_desc->type == NRFX_TWI_XFER_TX) &&
656                                  !(flags & NRFX_TWI_FLAG_TX_NO_STOP)) ? false : true;
657 
658         err_code = twi_tx_start_transfer(p_twi, p_cb);
659     }
660     else
661     {
662         err_code = twi_rx_start_transfer(p_twi, p_cb);
663     }
664     if (p_cb->handler == NULL)
665     {
666         p_cb->busy = false;
667     }
668     return err_code;
669 }
670 
nrfx_twi_is_busy(nrfx_twi_t const * p_instance)671 bool nrfx_twi_is_busy(nrfx_twi_t const * p_instance)
672 {
673     twi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
674     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
675 
676     return p_cb->busy;
677 }
678 
nrfx_twi_xfer(nrfx_twi_t const * p_instance,nrfx_twi_xfer_desc_t const * p_xfer_desc,uint32_t flags)679 nrfx_err_t nrfx_twi_xfer(nrfx_twi_t const *           p_instance,
680                          nrfx_twi_xfer_desc_t const * p_xfer_desc,
681                          uint32_t                     flags)
682 {
683     nrfx_err_t err_code = NRFX_SUCCESS;
684     twi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
685 
686     NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_POWERED_ON);
687     NRFX_ASSERT(p_xfer_desc->p_primary_buf != NULL || p_xfer_desc->primary_length == 0);
688     NRFX_ASSERT(p_xfer_desc->p_secondary_buf != NULL || p_xfer_desc->secondary_length == 0);
689 
690     // TXRX and TXTX transfers are supported only in non-blocking mode.
691     NRFX_ASSERT( !((p_cb->handler == NULL) && (p_xfer_desc->type == NRFX_TWI_XFER_TXRX)));
692     NRFX_ASSERT( !((p_cb->handler == NULL) && (p_xfer_desc->type == NRFX_TWI_XFER_TXTX)));
693 
694     NRFX_LOG_INFO("Transfer type: %s.", TRANSFER_TO_STR(p_xfer_desc->type));
695     NRFX_LOG_INFO("Transfer buffers length: primary: %d, secondary: %d.",
696                   p_xfer_desc->primary_length,
697                   p_xfer_desc->secondary_length);
698     NRFX_LOG_DEBUG("Primary buffer data:");
699     NRFX_LOG_HEXDUMP_DEBUG(p_xfer_desc->p_primary_buf,
700                            p_xfer_desc->primary_length * sizeof(p_xfer_desc->p_primary_buf[0]));
701     NRFX_LOG_DEBUG("Secondary buffer data:");
702     NRFX_LOG_HEXDUMP_DEBUG(p_xfer_desc->p_secondary_buf,
703                            p_xfer_desc->secondary_length * sizeof(p_xfer_desc->p_secondary_buf[0]));
704 
705     err_code = twi_xfer((NRF_TWI_Type  *)p_instance->p_twi, p_cb, p_xfer_desc, flags);
706     NRFX_LOG_WARNING("Function: %s, error code: %s.",
707                      __func__,
708                      NRFX_LOG_ERROR_STRING_GET(err_code));
709     return err_code;
710 }
711 
nrfx_twi_data_count_get(nrfx_twi_t const * p_instance)712 size_t nrfx_twi_data_count_get(nrfx_twi_t const * p_instance)
713 {
714     NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state != NRFX_DRV_STATE_UNINITIALIZED);
715 
716     return m_cb[p_instance->drv_inst_idx].bytes_transferred;
717 }
718 
nrfx_twi_stopped_event_get(nrfx_twi_t const * p_instance)719 uint32_t nrfx_twi_stopped_event_get(nrfx_twi_t const * p_instance)
720 {
721     NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state != NRFX_DRV_STATE_UNINITIALIZED);
722 
723     return nrf_twi_event_address_get(p_instance->p_twi, NRF_TWI_EVENT_STOPPED);
724 }
725 
irq_handler(NRF_TWI_Type * p_twi,twi_control_block_t * p_cb)726 static void irq_handler(NRF_TWI_Type * p_twi, twi_control_block_t * p_cb)
727 {
728     NRFX_ASSERT(p_cb->handler);
729 
730     if (twi_transfer(p_twi, p_cb))
731     {
732         return;
733     }
734 
735     if (!p_cb->error &&
736         ((p_cb->xfer_desc.type == NRFX_TWI_XFER_TXRX) ||
737          (p_cb->xfer_desc.type == NRFX_TWI_XFER_TXTX)) &&
738         p_cb->p_curr_buf == p_cb->xfer_desc.p_primary_buf)
739     {
740         p_cb->p_curr_buf      = p_cb->xfer_desc.p_secondary_buf;
741         p_cb->curr_length     = p_cb->xfer_desc.secondary_length;
742         p_cb->curr_tx_no_stop = (p_cb->flags & NRFX_TWI_FLAG_TX_NO_STOP);
743         p_cb->prev_suspend    = TWI_NO_SUSPEND;
744 
745         if (p_cb->xfer_desc.type == NRFX_TWI_XFER_TXTX)
746         {
747             (void)twi_tx_start_transfer(p_twi, p_cb);
748         }
749         else
750         {
751             (void)twi_rx_start_transfer(p_twi, p_cb);
752         }
753     }
754     else
755     {
756         nrfx_twi_evt_t event;
757         event.xfer_desc = p_cb->xfer_desc;
758 
759         if (p_cb->error)
760         {
761             uint32_t errorsrc = nrf_twi_errorsrc_get_and_clear(p_twi);
762             if (errorsrc & NRF_TWI_ERROR_ADDRESS_NACK)
763             {
764                 event.type = NRFX_TWI_EVT_ADDRESS_NACK;
765                 NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWI_EVT_ADDRESS_NACK));
766             }
767             else if (errorsrc & NRF_TWI_ERROR_DATA_NACK)
768             {
769                 event.type = NRFX_TWI_EVT_DATA_NACK;
770                 NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWI_EVT_DATA_NACK));
771             }
772             else if (errorsrc & NRF_TWI_ERROR_OVERRUN)
773             {
774                 event.type = NRFX_TWI_EVT_OVERRUN;
775                 NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWI_EVT_OVERRUN));
776             }
777             else
778             {
779                 event.type = NRFX_TWI_EVT_BUS_ERROR;
780                 NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWI_EVT_BUS_ERROR));
781             }
782         }
783         else
784         {
785             event.type = NRFX_TWI_EVT_DONE;
786             NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWI_EVT_DONE));
787         }
788 
789         p_cb->busy = false;
790 
791         if (!(TWI_FLAG_NO_HANDLER_IN_USE(p_cb->flags)) || p_cb->error)
792         {
793             p_cb->handler(&event, p_cb->p_context);
794         }
795     }
796 }
797 
798 NRFX_INSTANCE_IRQ_HANDLERS(TWI, twi)
799 
800 #endif // NRFX_CHECK(NRFX_TWI_ENABLED)
801