xref: /nrf52832-nimble/nordic/nrfx/drivers/src/nrfx_twim.c (revision 150812a83cab50279bd772ef6db1bfaf255f2c5b)
1 /*
2  * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this
9  *    list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its
16  *    contributors may be used to endorse or promote products derived from this
17  *    software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <nrfx.h>
33 
34 #if NRFX_CHECK(NRFX_TWIM_ENABLED)
35 
36 #if !(NRFX_CHECK(NRFX_TWIM0_ENABLED) || \
37       NRFX_CHECK(NRFX_TWIM1_ENABLED) || \
38       NRFX_CHECK(NRFX_TWIM2_ENABLED) || \
39       NRFX_CHECK(NRFX_TWIM3_ENABLED))
40 #error "No enabled TWIM instances. Check <nrfx_config.h>."
41 #endif
42 
43 #include <nrfx_twim.h>
44 #include <hal/nrf_gpio.h>
45 #include "prs/nrfx_prs.h"
46 
47 #define NRFX_LOG_MODULE TWIM
48 #include <nrfx_log.h>
49 
50 #define EVT_TO_STR(event)                                       \
51     (event == NRFX_TWIM_EVT_DONE         ? "EVT_DONE"         : \
52     (event == NRFX_TWIM_EVT_ADDRESS_NACK ? "EVT_ADDRESS_NACK" : \
53     (event == NRFX_TWIM_EVT_DATA_NACK    ? "EVT_DATA_NACK"    : \
54                                            "UNKNOWN ERROR")))
55 
56 #define EVT_TO_STR_TWIM(event)                                        \
57     (event == NRF_TWIM_EVENT_STOPPED   ? "NRF_TWIM_EVENT_STOPPED"   : \
58     (event == NRF_TWIM_EVENT_ERROR     ? "NRF_TWIM_EVENT_ERROR"     : \
59     (event == NRF_TWIM_EVENT_SUSPENDED ? "NRF_TWIM_EVENT_SUSPENDED" : \
60     (event == NRF_TWIM_EVENT_RXSTARTED ? "NRF_TWIM_EVENT_RXSTARTED" : \
61     (event == NRF_TWIM_EVENT_TXSTARTED ? "NRF_TWIM_EVENT_TXSTARTED" : \
62     (event == NRF_TWIM_EVENT_LASTRX    ? "NRF_TWIM_EVENT_LASTRX"    : \
63     (event == NRF_TWIM_EVENT_LASTTX    ? "NRF_TWIM_EVENT_LASTTX"    : \
64                                          "UNKNOWN ERROR")))))))
65 
66 #define TRANSFER_TO_STR(type)                    \
67     (type == NRFX_TWIM_XFER_TX   ? "XFER_TX"   : \
68     (type == NRFX_TWIM_XFER_RX   ? "XFER_RX"   : \
69     (type == NRFX_TWIM_XFER_TXRX ? "XFER_TXRX" : \
70     (type == NRFX_TWIM_XFER_TXTX ? "XFER_TXTX" : \
71                                    "UNKNOWN TRANSFER TYPE"))))
72 
73 #define TWIM_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 TWIMX_LENGTH_VALIDATE(peripheral, drv_inst_idx, len1, len2)     \
81     (((drv_inst_idx) == NRFX_CONCAT_3(NRFX_, peripheral, _INST_IDX)) && \
82      NRFX_EASYDMA_LENGTH_VALIDATE(peripheral, len1, len2))
83 
84 #if NRFX_CHECK(NRFX_TWIM0_ENABLED)
85 #define TWIM0_LENGTH_VALIDATE(...)  TWIMX_LENGTH_VALIDATE(TWIM0, __VA_ARGS__)
86 #else
87 #define TWIM0_LENGTH_VALIDATE(...)  0
88 #endif
89 
90 #if NRFX_CHECK(NRFX_TWIM1_ENABLED)
91 #define TWIM1_LENGTH_VALIDATE(...)  TWIMX_LENGTH_VALIDATE(TWIM1, __VA_ARGS__)
92 #else
93 #define TWIM1_LENGTH_VALIDATE(...)  0
94 #endif
95 
96 #if NRFX_CHECK(NRFX_TWIM2_ENABLED)
97 #define TWIM2_LENGTH_VALIDATE(...)  TWIMX_LENGTH_VALIDATE(TWIM2, __VA_ARGS__)
98 #else
99 #define TWIM2_LENGTH_VALIDATE(...)  0
100 #endif
101 
102 #if NRFX_CHECK(NRFX_TWIM3_ENABLED)
103 #define TWIM3_LENGTH_VALIDATE(...)  TWIMX_LENGTH_VALIDATE(TWIM3, __VA_ARGS__)
104 #else
105 #define TWIM3_LENGTH_VALIDATE(...)  0
106 #endif
107 
108 #define TWIM_LENGTH_VALIDATE(drv_inst_idx, len1, len2)  \
109     (TWIM0_LENGTH_VALIDATE(drv_inst_idx, len1, len2) || \
110      TWIM1_LENGTH_VALIDATE(drv_inst_idx, len1, len2) || \
111      TWIM2_LENGTH_VALIDATE(drv_inst_idx, len1, len2) || \
112      TWIM3_LENGTH_VALIDATE(drv_inst_idx, len1, len2))
113 
114 // Control block - driver instance local data.
115 typedef struct
116 {
117     nrfx_twim_evt_handler_t handler;
118     void *                  p_context;
119     volatile uint32_t       int_mask;
120     nrfx_twim_xfer_desc_t   xfer_desc;
121     uint32_t                flags;
122     uint8_t *               p_curr_buf;
123     size_t                  curr_length;
124     bool                    curr_no_stop;
125     nrfx_drv_state_t        state;
126     bool                    error;
127     volatile bool           busy;
128     bool                    repeated;
129     uint8_t                 bytes_transferred;
130     bool                    hold_bus_uninit;
131 #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
132     nrf_twim_frequency_t    bus_frequency;
133 #endif
134 } twim_control_block_t;
135 
136 static twim_control_block_t m_cb[NRFX_TWIM_ENABLED_COUNT];
137 
twi_process_error(uint32_t errorsrc)138 static nrfx_err_t twi_process_error(uint32_t errorsrc)
139 {
140     nrfx_err_t ret = NRFX_ERROR_INTERNAL;
141 
142     if (errorsrc & NRF_TWIM_ERROR_ADDRESS_NACK)
143     {
144         ret = NRFX_ERROR_DRV_TWI_ERR_ANACK;
145     }
146 
147     if (errorsrc & NRF_TWIM_ERROR_DATA_NACK)
148     {
149         ret = NRFX_ERROR_DRV_TWI_ERR_DNACK;
150     }
151 
152     return ret;
153 }
154 
nrfx_twim_init(nrfx_twim_t const * p_instance,nrfx_twim_config_t const * p_config,nrfx_twim_evt_handler_t event_handler,void * p_context)155 nrfx_err_t nrfx_twim_init(nrfx_twim_t const *        p_instance,
156                           nrfx_twim_config_t const * p_config,
157                           nrfx_twim_evt_handler_t    event_handler,
158                           void *                     p_context)
159 {
160     NRFX_ASSERT(p_config);
161     NRFX_ASSERT(p_config->scl != p_config->sda);
162     twim_control_block_t * p_cb  = &m_cb[p_instance->drv_inst_idx];
163     nrfx_err_t err_code;
164 
165     if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
166     {
167         err_code = NRFX_ERROR_INVALID_STATE;
168         NRFX_LOG_WARNING("Function: %s, error code: %s.",
169                          __func__,
170                          NRFX_LOG_ERROR_STRING_GET(err_code));
171         return err_code;
172     }
173 
174 #if NRFX_CHECK(NRFX_PRS_ENABLED)
175     static nrfx_irq_handler_t const irq_handlers[NRFX_TWIM_ENABLED_COUNT] = {
176         #if NRFX_CHECK(NRFX_TWIM0_ENABLED)
177         nrfx_twim_0_irq_handler,
178         #endif
179         #if NRFX_CHECK(NRFX_TWIM1_ENABLED)
180         nrfx_twim_1_irq_handler,
181         #endif
182         #if NRFX_CHECK(NRFX_TWIM2_ENABLED)
183         nrfx_twim_2_irq_handler,
184         #endif
185         #if NRFX_CHECK(NRFX_TWIM3_ENABLED)
186         nrfx_twim_3_irq_handler,
187         #endif
188     };
189     if (nrfx_prs_acquire(p_instance->p_twim,
190             irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
191     {
192         err_code = NRFX_ERROR_BUSY;
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 #endif // NRFX_CHECK(NRFX_PRS_ENABLED)
199 
200     p_cb->handler         = event_handler;
201     p_cb->p_context       = p_context;
202     p_cb->int_mask        = 0;
203     p_cb->repeated        = false;
204     p_cb->busy            = false;
205     p_cb->hold_bus_uninit = p_config->hold_bus_uninit;
206 #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
207     p_cb->bus_frequency   = (nrf_twim_frequency_t)p_config->frequency;
208 #endif
209 
210     /* To secure correct signal levels on the pins used by the TWI
211        master when the system is in OFF mode, and when the TWI master is
212        disabled, these pins must be configured in the GPIO peripheral.
213     */
214     TWIM_PIN_INIT(p_config->scl);
215     TWIM_PIN_INIT(p_config->sda);
216 
217     NRF_TWIM_Type * p_twim = p_instance->p_twim;
218     nrf_twim_pins_set(p_twim, p_config->scl, p_config->sda);
219     nrf_twim_frequency_set(p_twim,
220         (nrf_twim_frequency_t)p_config->frequency);
221 
222     if (p_cb->handler)
223     {
224         NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_twim),
225             p_config->interrupt_priority);
226         NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_twim));
227     }
228 
229     p_cb->state = NRFX_DRV_STATE_INITIALIZED;
230 
231     err_code = NRFX_SUCCESS;
232     NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
233     return err_code;
234 }
235 
nrfx_twim_uninit(nrfx_twim_t const * p_instance)236 void nrfx_twim_uninit(nrfx_twim_t const * p_instance)
237 {
238     twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
239     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
240 
241     if (p_cb->handler)
242     {
243         NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_twim));
244     }
245     nrfx_twim_disable(p_instance);
246 
247 #if NRFX_CHECK(NRFX_PRS_ENABLED)
248     nrfx_prs_release(p_instance->p_twim);
249 #endif
250 
251     if (!p_cb->hold_bus_uninit)
252     {
253         nrf_gpio_cfg_default(p_instance->p_twim->PSEL.SCL);
254         nrf_gpio_cfg_default(p_instance->p_twim->PSEL.SDA);
255     }
256 
257     p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
258     NRFX_LOG_INFO("Instance uninitialized: %d.", p_instance->drv_inst_idx);
259 }
260 
nrfx_twim_enable(nrfx_twim_t const * p_instance)261 void nrfx_twim_enable(nrfx_twim_t const * p_instance)
262 {
263     twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
264     NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED);
265 
266     nrf_twim_enable(p_instance->p_twim);
267 
268     p_cb->state = NRFX_DRV_STATE_POWERED_ON;
269     NRFX_LOG_INFO("Instance enabled: %d.", p_instance->drv_inst_idx);
270 }
271 
nrfx_twim_disable(nrfx_twim_t const * p_instance)272 void nrfx_twim_disable(nrfx_twim_t const * p_instance)
273 {
274     twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
275     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
276 
277     NRF_TWIM_Type * p_twim = p_instance->p_twim;
278     p_cb->int_mask = 0;
279     nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
280     nrf_twim_shorts_disable(p_twim, NRF_TWIM_ALL_SHORTS_MASK);
281     nrf_twim_disable(p_twim);
282 
283     p_cb->state = NRFX_DRV_STATE_INITIALIZED;
284     NRFX_LOG_INFO("Instance disabled: %d.", p_instance->drv_inst_idx);
285 }
286 
287 
nrfx_twim_is_busy(nrfx_twim_t const * p_instance)288 bool nrfx_twim_is_busy(nrfx_twim_t const * p_instance)
289 {
290     twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
291     return p_cb->busy;
292 }
293 
294 
twim_list_enable_handle(NRF_TWIM_Type * p_twim,uint32_t flags)295 __STATIC_INLINE void twim_list_enable_handle(NRF_TWIM_Type * p_twim, uint32_t flags)
296 {
297     if (NRFX_TWIM_FLAG_TX_POSTINC & flags)
298     {
299         nrf_twim_tx_list_enable(p_twim);
300     }
301     else
302     {
303         nrf_twim_tx_list_disable(p_twim);
304     }
305 
306     if (NRFX_TWIM_FLAG_RX_POSTINC & flags)
307     {
308         nrf_twim_rx_list_enable(p_twim);
309     }
310     else
311     {
312         nrf_twim_rx_list_disable(p_twim);
313     }
314 }
twim_xfer(twim_control_block_t * p_cb,NRF_TWIM_Type * p_twim,nrfx_twim_xfer_desc_t const * p_xfer_desc,uint32_t flags)315 __STATIC_INLINE nrfx_err_t twim_xfer(twim_control_block_t        * p_cb,
316                                      NRF_TWIM_Type               * p_twim,
317                                      nrfx_twim_xfer_desc_t const * p_xfer_desc,
318                                      uint32_t                      flags)
319 {
320     nrfx_err_t err_code = NRFX_SUCCESS;
321     nrf_twim_task_t  start_task = NRF_TWIM_TASK_STARTTX;
322     nrf_twim_event_t evt_to_wait = NRF_TWIM_EVENT_STOPPED;
323 
324     if (!nrfx_is_in_ram(p_xfer_desc->p_primary_buf))
325     {
326         err_code = NRFX_ERROR_INVALID_ADDR;
327         NRFX_LOG_WARNING("Function: %s, error code: %s.",
328                          __func__,
329                          NRFX_LOG_ERROR_STRING_GET(err_code));
330         return err_code;
331     }
332     /* Block TWI interrupts to ensure that function is not interrupted by TWI interrupt. */
333     nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
334     if (p_cb->busy)
335     {
336         nrf_twim_int_enable(p_twim, p_cb->int_mask);
337         err_code = NRFX_ERROR_BUSY;
338         NRFX_LOG_WARNING("Function: %s, error code: %s.",
339                          __func__,
340                          NRFX_LOG_ERROR_STRING_GET(err_code));
341         return err_code;
342     }
343     else
344     {
345         p_cb->busy = ((NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER & flags) ||
346                       (NRFX_TWIM_FLAG_REPEATED_XFER & flags)) ? false: true;
347     }
348 
349     p_cb->xfer_desc = *p_xfer_desc;
350     p_cb->repeated = (flags & NRFX_TWIM_FLAG_REPEATED_XFER) ? true : false;
351     nrf_twim_address_set(p_twim, p_xfer_desc->address);
352 
353     nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_STOPPED);
354     nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_ERROR);
355 
356     twim_list_enable_handle(p_twim, flags);
357     switch (p_xfer_desc->type)
358     {
359     case NRFX_TWIM_XFER_TXTX:
360         NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_REPEATED_XFER));
361         NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_HOLD_XFER));
362         NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER));
363         if (!nrfx_is_in_ram(p_xfer_desc->p_secondary_buf))
364         {
365             err_code = NRFX_ERROR_INVALID_ADDR;
366             NRFX_LOG_WARNING("Function: %s, error code: %s.",
367                              __func__,
368                              NRFX_LOG_ERROR_STRING_GET(err_code));
369             return err_code;
370         }
371         nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_SUSPEND_MASK);
372         nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
373         nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
374         nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTTX);
375         nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED);
376         nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
377         nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STARTTX);
378         while (!nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_TXSTARTED))
379         {}
380         NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_TXSTARTED));
381         nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
382         nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_secondary_buf, p_xfer_desc->secondary_length);
383         p_cb->int_mask = NRF_TWIM_INT_SUSPENDED_MASK | NRF_TWIM_INT_ERROR_MASK;
384         break;
385     case NRFX_TWIM_XFER_TXRX:
386         nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
387         if (!nrfx_is_in_ram(p_xfer_desc->p_secondary_buf))
388         {
389             err_code = NRFX_ERROR_INVALID_ADDR;
390             NRFX_LOG_WARNING("Function: %s, error code: %s.",
391                              __func__,
392                              NRFX_LOG_ERROR_STRING_GET(err_code));
393             return err_code;
394         }
395         nrf_twim_rx_buffer_set(p_twim, p_xfer_desc->p_secondary_buf, p_xfer_desc->secondary_length);
396         nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STARTRX_MASK |
397                                     NRF_TWIM_SHORT_LASTRX_STOP_MASK);
398         p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK;
399         nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
400         break;
401     case NRFX_TWIM_XFER_TX:
402         nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
403         if (NRFX_TWIM_FLAG_TX_NO_STOP & flags)
404         {
405             nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_SUSPEND_MASK);
406             p_cb->int_mask = NRF_TWIM_INT_SUSPENDED_MASK | NRF_TWIM_INT_ERROR_MASK;
407             nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED);
408             evt_to_wait = NRF_TWIM_EVENT_SUSPENDED;
409         }
410         else
411         {
412             nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STOP_MASK);
413             p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK;
414         }
415         nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
416         break;
417     case NRFX_TWIM_XFER_RX:
418         nrf_twim_rx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
419         nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTRX_STOP_MASK);
420         p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK;
421         start_task = NRF_TWIM_TASK_STARTRX;
422         nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
423         break;
424     default:
425         err_code = NRFX_ERROR_INVALID_PARAM;
426         break;
427     }
428 
429     if (!(flags & NRFX_TWIM_FLAG_HOLD_XFER) && (p_xfer_desc->type != NRFX_TWIM_XFER_TXTX))
430     {
431         nrf_twim_task_trigger(p_twim, start_task);
432     }
433 
434     if (p_cb->handler)
435     {
436         if (flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER)
437         {
438             p_cb->int_mask = NRF_TWIM_INT_ERROR_MASK;
439         }
440         nrf_twim_int_enable(p_twim, p_cb->int_mask);
441 
442 #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
443         if ((flags & NRFX_TWIM_FLAG_HOLD_XFER) && ((p_xfer_desc->type == NRFX_TWIM_XFER_TX) ||
444                                                    (p_xfer_desc->type == NRFX_TWIM_XFER_TXRX)))
445         {
446             p_cb->flags = flags;
447             twim_list_enable_handle(p_twim, 0);
448             p_twim->FREQUENCY = 0;
449             nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
450             nrf_twim_int_enable(p_twim, NRF_TWIM_INT_TXSTARTED_MASK);
451         }
452 #endif
453     }
454     else
455     {
456         while (!nrf_twim_event_check(p_twim, evt_to_wait))
457         {
458             if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_ERROR))
459             {
460                 NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_ERROR));
461                 nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_ERROR);
462                 nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
463                 nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STOP);
464                 evt_to_wait = NRF_TWIM_EVENT_STOPPED;
465             }
466         }
467 
468         uint32_t errorsrc =  nrf_twim_errorsrc_get_and_clear(p_twim);
469 
470         p_cb->busy = false;
471 
472         if (errorsrc)
473         {
474             err_code = twi_process_error(errorsrc);
475         }
476     }
477     return err_code;
478 }
479 
480 
nrfx_twim_xfer(nrfx_twim_t const * p_instance,nrfx_twim_xfer_desc_t const * p_xfer_desc,uint32_t flags)481 nrfx_err_t nrfx_twim_xfer(nrfx_twim_t           const * p_instance,
482                           nrfx_twim_xfer_desc_t const * p_xfer_desc,
483                           uint32_t                      flags)
484 {
485     NRFX_ASSERT(TWIM_LENGTH_VALIDATE(p_instance->drv_inst_idx,
486                                      p_xfer_desc->primary_length,
487                                      p_xfer_desc->secondary_length));
488 
489     nrfx_err_t err_code = NRFX_SUCCESS;
490     twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
491 
492     // TXRX and TXTX transfers are supported only in non-blocking mode.
493     NRFX_ASSERT( !((p_cb->handler == NULL) && (p_xfer_desc->type == NRFX_TWIM_XFER_TXRX)));
494     NRFX_ASSERT( !((p_cb->handler == NULL) && (p_xfer_desc->type == NRFX_TWIM_XFER_TXTX)));
495 
496     NRFX_LOG_INFO("Transfer type: %s.", TRANSFER_TO_STR(p_xfer_desc->type));
497     NRFX_LOG_INFO("Transfer buffers length: primary: %d, secondary: %d.",
498                   p_xfer_desc->primary_length,
499                   p_xfer_desc->secondary_length);
500     NRFX_LOG_DEBUG("Primary buffer data:");
501     NRFX_LOG_HEXDUMP_DEBUG(p_xfer_desc->p_primary_buf,
502                            p_xfer_desc->primary_length * sizeof(p_xfer_desc->p_primary_buf[0]));
503     NRFX_LOG_DEBUG("Secondary buffer data:");
504     NRFX_LOG_HEXDUMP_DEBUG(p_xfer_desc->p_secondary_buf,
505                            p_xfer_desc->secondary_length * sizeof(p_xfer_desc->p_secondary_buf[0]));
506 
507     err_code = twim_xfer(p_cb, (NRF_TWIM_Type *)p_instance->p_twim, p_xfer_desc, flags);
508     NRFX_LOG_WARNING("Function: %s, error code: %s.",
509                      __func__,
510                      NRFX_LOG_ERROR_STRING_GET(err_code));
511     return err_code;
512 }
513 
nrfx_twim_tx(nrfx_twim_t const * p_instance,uint8_t address,uint8_t const * p_data,size_t length,bool no_stop)514 nrfx_err_t nrfx_twim_tx(nrfx_twim_t const * p_instance,
515                         uint8_t             address,
516                         uint8_t     const * p_data,
517                         size_t              length,
518                         bool                no_stop)
519 {
520     nrfx_twim_xfer_desc_t xfer = NRFX_TWIM_XFER_DESC_TX(address, (uint8_t*)p_data, length);
521 
522     return nrfx_twim_xfer(p_instance, &xfer, no_stop ? NRFX_TWIM_FLAG_TX_NO_STOP : 0);
523 }
524 
nrfx_twim_rx(nrfx_twim_t const * p_instance,uint8_t address,uint8_t * p_data,size_t length)525 nrfx_err_t nrfx_twim_rx(nrfx_twim_t const * p_instance,
526                         uint8_t             address,
527                         uint8_t *           p_data,
528                         size_t              length)
529 {
530     nrfx_twim_xfer_desc_t xfer = NRFX_TWIM_XFER_DESC_RX(address, p_data, length);
531     return nrfx_twim_xfer(p_instance, &xfer, 0);
532 }
533 
nrfx_twim_start_task_get(nrfx_twim_t const * p_instance,nrfx_twim_xfer_type_t xfer_type)534 uint32_t nrfx_twim_start_task_get(nrfx_twim_t const * p_instance,
535                                   nrfx_twim_xfer_type_t xfer_type)
536 {
537     return (uint32_t)nrf_twim_task_address_get(p_instance->p_twim,
538         (xfer_type != NRFX_TWIM_XFER_RX) ? NRF_TWIM_TASK_STARTTX : NRF_TWIM_TASK_STARTRX);
539 }
540 
nrfx_twim_stopped_event_get(nrfx_twim_t const * p_instance)541 uint32_t nrfx_twim_stopped_event_get(nrfx_twim_t const * p_instance)
542 {
543     return (uint32_t)nrf_twim_event_address_get(p_instance->p_twim, NRF_TWIM_EVENT_STOPPED);
544 }
545 
twim_irq_handler(NRF_TWIM_Type * p_twim,twim_control_block_t * p_cb)546 static void twim_irq_handler(NRF_TWIM_Type * p_twim, twim_control_block_t * p_cb)
547 {
548 
549 #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
550     /* Handle only workaround case. Can be used without TWIM handler in IRQs. */
551     if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_TXSTARTED))
552     {
553         nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
554         nrf_twim_int_disable(p_twim, NRF_TWIM_INT_TXSTARTED_MASK);
555         if (p_twim->FREQUENCY == 0)
556         {
557             // Set enable to zero to reset TWIM internal state.
558             nrf_twim_disable(p_twim);
559             nrf_twim_enable(p_twim);
560 
561             // Set proper frequency.
562             nrf_twim_frequency_set(p_twim, p_cb->bus_frequency);
563             twim_list_enable_handle(p_twim, p_cb->flags);
564 
565             // Start proper transmission.
566             nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STARTTX);
567             return;
568         }
569     }
570 #endif
571 
572     NRFX_ASSERT(p_cb->handler);
573 
574     if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_ERROR))
575     {
576         nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_ERROR);
577         NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_ERROR));
578         if (!nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_STOPPED))
579         {
580             nrf_twim_int_disable(p_twim, p_cb->int_mask);
581             p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK;
582             nrf_twim_int_enable(p_twim, p_cb->int_mask);
583 
584             nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
585             nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STOP);
586             return;
587         }
588     }
589 
590     nrfx_twim_evt_t event;
591 
592     if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_STOPPED))
593     {
594         NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_STOPPED));
595         nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_STOPPED);
596         event.xfer_desc = p_cb->xfer_desc;
597         if (p_cb->error)
598         {
599 
600             event.xfer_desc.primary_length = (p_cb->xfer_desc.type == NRFX_TWIM_XFER_RX) ?
601                 nrf_twim_rxd_amount_get(p_twim) : nrf_twim_txd_amount_get(p_twim);
602             event.xfer_desc.secondary_length = (p_cb->xfer_desc.type == NRFX_TWIM_XFER_TXRX) ?
603                 nrf_twim_rxd_amount_get(p_twim) : nrf_twim_txd_amount_get(p_twim);
604 
605         }
606         nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTTX);
607         nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTRX);
608         if (!p_cb->repeated || p_cb->error)
609         {
610             nrf_twim_shorts_set(p_twim, 0);
611             p_cb->int_mask = 0;
612             nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
613         }
614     }
615     else
616     {
617         nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED);
618         NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_SUSPENDED));
619         if (p_cb->xfer_desc.type == NRFX_TWIM_XFER_TX)
620         {
621             event.xfer_desc = p_cb->xfer_desc;
622             if (!p_cb->repeated)
623             {
624                 nrf_twim_shorts_set(p_twim, 0);
625                 p_cb->int_mask = 0;
626                 nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
627             }
628         }
629         else
630         {
631             nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STOP_MASK);
632             p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK;
633             nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
634             nrf_twim_int_enable(p_twim, p_cb->int_mask);
635             nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STARTTX);
636             nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
637             return;
638         }
639     }
640 
641     uint32_t errorsrc = nrf_twim_errorsrc_get_and_clear(p_twim);
642     if (errorsrc & NRF_TWIM_ERROR_ADDRESS_NACK)
643     {
644         event.type = NRFX_TWIM_EVT_ADDRESS_NACK;
645         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_ADDRESS_NACK));
646     }
647     else if (errorsrc & NRF_TWIM_ERROR_DATA_NACK)
648     {
649         event.type = NRFX_TWIM_EVT_DATA_NACK;
650         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_DATA_NACK));
651     }
652     else
653     {
654         event.type = NRFX_TWIM_EVT_DONE;
655         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_DONE));
656     }
657 
658     if (!p_cb->repeated)
659     {
660         p_cb->busy = false;
661     }
662     p_cb->handler(&event, p_cb->p_context);
663 }
664 
665 #if NRFX_CHECK(NRFX_TWIM0_ENABLED)
nrfx_twim_0_irq_handler(void)666 void nrfx_twim_0_irq_handler(void)
667 {
668     twim_irq_handler(NRF_TWIM0, &m_cb[NRFX_TWIM0_INST_IDX]);
669 }
670 #endif
671 
672 #if NRFX_CHECK(NRFX_TWIM1_ENABLED)
nrfx_twim_1_irq_handler(void)673 void nrfx_twim_1_irq_handler(void)
674 {
675     twim_irq_handler(NRF_TWIM1, &m_cb[NRFX_TWIM1_INST_IDX]);
676 }
677 #endif
678 
679 #if NRFX_CHECK(NRFX_TWIM2_ENABLED)
nrfx_twim_2_irq_handler(void)680 void nrfx_twim_2_irq_handler(void)
681 {
682     twim_irq_handler(NRF_TWIM2, &m_cb[NRFX_TWIM2_INST_IDX]);
683 }
684 #endif
685 
686 #if NRFX_CHECK(NRFX_TWIM3_ENABLED)
nrfx_twim_3_irq_handler(void)687 void nrfx_twim_3_irq_handler(void)
688 {
689     twim_irq_handler(NRF_TWIM3, &m_cb[NRFX_TWIM3_INST_IDX]);
690 }
691 #endif
692 
693 #endif // NRFX_CHECK(NRFX_TWIM_ENABLED)
694