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_TWIM_ENABLED)
37
38 #if !NRFX_FEATURE_PRESENT(NRFX_TWIM, _ENABLED)
39 #error "No enabled TWIM instances. Check <nrfx_config.h>."
40 #endif
41
42 #include <nrfx_twim.h>
43 #include <haly/nrfy_gpio.h>
44 #include "prs/nrfx_prs.h"
45
46 #define NRFX_LOG_MODULE TWIM
47 #include <nrfx_log.h>
48
49 #define EVT_TO_STR(event) \
50 (event == NRFX_TWIM_EVT_DONE ? "EVT_DONE" : \
51 (event == NRFX_TWIM_EVT_ADDRESS_NACK ? "EVT_ADDRESS_NACK" : \
52 (event == NRFX_TWIM_EVT_DATA_NACK ? "EVT_DATA_NACK" : \
53 (event == NRFX_TWIM_EVT_OVERRUN ? "EVT_OVERRUN" : \
54 (event == NRFX_TWIM_EVT_BUS_ERROR ? "EVT_BUS_ERROR" : \
55 "UNKNOWN ERROR")))))
56
57 #define EVT_TO_STR_TWIM(event) \
58 (event == NRF_TWIM_EVENT_STOPPED ? "NRF_TWIM_EVENT_STOPPED" : \
59 (event == NRF_TWIM_EVENT_ERROR ? "NRF_TWIM_EVENT_ERROR" : \
60 (event == NRF_TWIM_EVENT_SUSPENDED ? "NRF_TWIM_EVENT_SUSPENDED" : \
61 (event == NRF_TWIM_EVENT_RXSTARTED ? "NRF_TWIM_EVENT_RXSTARTED" : \
62 (event == NRF_TWIM_EVENT_TXSTARTED ? "NRF_TWIM_EVENT_TXSTARTED" : \
63 (event == NRF_TWIM_EVENT_LASTRX ? "NRF_TWIM_EVENT_LASTRX" : \
64 (event == NRF_TWIM_EVENT_LASTTX ? "NRF_TWIM_EVENT_LASTTX" : \
65 "UNKNOWN ERROR")))))))
66
67 #define TRANSFER_TO_STR(type) \
68 (type == NRFX_TWIM_XFER_TX ? "XFER_TX" : \
69 (type == NRFX_TWIM_XFER_RX ? "XFER_RX" : \
70 (type == NRFX_TWIM_XFER_TXRX ? "XFER_TXRX" : \
71 (type == NRFX_TWIM_XFER_TXTX ? "XFER_TXTX" : \
72 "UNKNOWN TRANSFER TYPE"))))
73
74 #define TWIM_PIN_INIT(_pin, _drive) nrfy_gpio_cfg((_pin), \
75 NRF_GPIO_PIN_DIR_INPUT, \
76 NRF_GPIO_PIN_INPUT_CONNECT, \
77 NRF_GPIO_PIN_PULLUP, \
78 (_drive), \
79 NRF_GPIO_PIN_NOSENSE)
80
81 #define TWIMX_LENGTH_VALIDATE(periph_name, prefix, i, drv_inst_idx, len1, len2) \
82 (((drv_inst_idx) == NRFX_CONCAT(NRFX_, periph_name, prefix, i, _INST_IDX)) && \
83 NRFX_EASYDMA_LENGTH_VALIDATE(NRFX_CONCAT(periph_name, prefix, i), len1, len2))
84
85 #define TWIM_LENGTH_VALIDATE(drv_inst_idx, len1, len2) \
86 (NRFX_FOREACH_ENABLED(TWIM, TWIMX_LENGTH_VALIDATE, (||), (0), drv_inst_idx, len1, len2))
87
88 // Control block - driver instance local data.
89 typedef struct
90 {
91 nrfx_twim_evt_handler_t handler;
92 void * p_context;
93 volatile uint32_t int_mask;
94 nrfy_twim_xfer_desc_t xfer_desc_primary;
95 nrfy_twim_xfer_desc_t xfer_desc_secondary;
96 uint32_t flags;
97 nrfx_twim_xfer_type_t xfer_type;
98 uint8_t address;
99 nrfx_drv_state_t state;
100 bool error;
101 volatile bool busy;
102 bool repeated;
103 bool hold_bus_uninit;
104 bool skip_gpio_cfg;
105 #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
106 nrf_twim_frequency_t bus_frequency;
107 #endif
108 } twim_control_block_t;
109
110 static twim_control_block_t m_cb[NRFX_TWIM_ENABLED_COUNT];
111
twi_process_error(uint32_t errorsrc)112 static nrfx_err_t twi_process_error(uint32_t errorsrc)
113 {
114 nrfx_err_t ret = NRFX_ERROR_INTERNAL;
115
116 if (errorsrc & NRF_TWIM_ERROR_OVERRUN)
117 {
118 ret = NRFX_ERROR_DRV_TWI_ERR_OVERRUN;
119 }
120
121 if (errorsrc & NRF_TWIM_ERROR_ADDRESS_NACK)
122 {
123 ret = NRFX_ERROR_DRV_TWI_ERR_ANACK;
124 }
125
126 if (errorsrc & NRF_TWIM_ERROR_DATA_NACK)
127 {
128 ret = NRFX_ERROR_DRV_TWI_ERR_DNACK;
129 }
130
131 return ret;
132 }
133
xfer_completeness_check(NRF_TWIM_Type * p_twim,twim_control_block_t const * p_cb)134 static bool xfer_completeness_check(NRF_TWIM_Type * p_twim, twim_control_block_t const * p_cb)
135 {
136 // If the actual number of transferred bytes is not equal to what was requested,
137 // but there was no error signaled by the peripheral, this means that something
138 // unexpected, like a premature STOP condition, was received on the bus.
139 // In such case the peripheral has to be disabled and re-enabled, so that its
140 // internal state machine is reinitialized.
141
142 bool transfer_complete = true;
143 switch (p_cb->xfer_type)
144 {
145 case NRFX_TWIM_XFER_TXTX:
146 // int_mask variable is used to determine which length should be checked
147 // against number of bytes latched in EasyDMA.
148 // NRF_TWIM_INT_SUSPENDED_MASK is configured only in first TX of TXTX transfer.
149 if (((p_cb->int_mask & NRF_TWIM_INT_SUSPENDED_MASK) &&
150 (nrfy_twim_txd_amount_get(p_twim) != p_cb->xfer_desc_primary.length)) ||
151 (!(p_cb->int_mask & NRF_TWIM_INT_SUSPENDED_MASK) &&
152 (nrfy_twim_txd_amount_get(p_twim) != p_cb->xfer_desc_secondary.length)))
153 {
154 transfer_complete = false;
155 }
156 break;
157 case NRFX_TWIM_XFER_TXRX:
158 if ((nrfy_twim_txd_amount_get(p_twim) != p_cb->xfer_desc_primary.length) ||
159 (nrfy_twim_rxd_amount_get(p_twim) != p_cb->xfer_desc_secondary.length))
160 {
161 transfer_complete = false;
162 }
163 break;
164 case NRFX_TWIM_XFER_TX:
165 if (nrfy_twim_txd_amount_get(p_twim) != p_cb->xfer_desc_primary.length)
166 {
167 transfer_complete = false;
168 }
169 break;
170 case NRFX_TWIM_XFER_RX:
171 if (nrfy_twim_rxd_amount_get(p_twim) != p_cb->xfer_desc_primary.length)
172 {
173 transfer_complete = false;
174 }
175 break;
176 default:
177 break;
178 }
179
180 if (!transfer_complete)
181 {
182 nrfy_twim_disable(p_twim);
183 nrfy_twim_enable(p_twim);
184 }
185
186 return transfer_complete;
187 }
188
twim_configure(nrfx_twim_t const * p_instance,nrfx_twim_config_t const * p_config)189 static void twim_configure(nrfx_twim_t const * p_instance,
190 nrfx_twim_config_t const * p_config)
191 {
192 nrfy_twim_config_t nrfy_config =
193 {
194 .pins = {
195 .scl_pin = p_config->scl_pin,
196 .sda_pin = p_config->sda_pin
197 },
198 .frequency = p_config->frequency,
199 .skip_psel_cfg = p_config->skip_psel_cfg
200 };
201
202 nrfy_twim_periph_configure(p_instance->p_twim, &nrfy_config);
203 if (m_cb[p_instance->drv_inst_idx].handler)
204 {
205 nrfy_twim_int_init(p_instance->p_twim, 0, p_config->interrupt_priority, false);
206 }
207 }
208
pins_configure(nrfx_twim_config_t const * p_config)209 static bool pins_configure(nrfx_twim_config_t const * p_config)
210 {
211 nrf_gpio_pin_drive_t pin_drive;
212
213 if (p_config->skip_psel_cfg && p_config->skip_gpio_cfg)
214 {
215 return true;
216 }
217
218 #if NRF_TWIM_HAS_1000_KHZ_FREQ && defined(NRF5340_XXAA)
219 if (p_config->frequency >= NRF_TWIM_FREQ_1000K)
220 {
221 /* When using 1 Mbps mode, two high-speed pins have to be used with extra high drive. */
222 pin_drive = NRF_GPIO_PIN_E0E1;
223
224 uint32_t e0e1_pin_1 = NRF_GPIO_PIN_MAP(1, 2);
225 uint32_t e0e1_pin_2 = NRF_GPIO_PIN_MAP(1, 3);
226
227 /* Check whether provided pins have the extra high drive capabilities. */
228 if (((p_config->scl_pin != e0e1_pin_1) ||
229 (p_config->sda_pin != e0e1_pin_2)) &&
230 ((p_config->scl_pin != e0e1_pin_2) ||
231 (p_config->sda_pin != e0e1_pin_1)))
232 {
233 return false;
234 }
235 }
236 else
237 #endif
238 {
239 pin_drive = NRF_GPIO_PIN_S0D1;
240 }
241
242 /* To secure correct signal levels on the pins used by the TWI
243 master when the system is in OFF mode, and when the TWI master is
244 disabled, these pins must be configured in the GPIO peripheral.
245 */
246 if (!p_config->skip_gpio_cfg)
247 {
248 NRFX_ASSERT(p_config->scl_pin != p_config->sda_pin);
249 TWIM_PIN_INIT(p_config->scl_pin, pin_drive);
250 TWIM_PIN_INIT(p_config->sda_pin, pin_drive);
251 #if NRF_GPIO_HAS_CLOCKPIN
252 #if defined(NRF_TWIM_CLOCKPIN_SCL_NEEDED)
253 nrfy_gpio_pin_clock_set(p_config->scl_pin, true);
254 #endif
255 #if defined(NRF_TWIM_CLOCKPIN_SDA_NEEDED)
256 nrfy_gpio_pin_clock_set(p_config->sda_pin, true);
257 #endif
258 #endif
259 }
260 return true;
261 }
262
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)263 nrfx_err_t nrfx_twim_init(nrfx_twim_t const * p_instance,
264 nrfx_twim_config_t const * p_config,
265 nrfx_twim_evt_handler_t event_handler,
266 void * p_context)
267 {
268 NRFX_ASSERT(p_config);
269
270 twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
271 nrfx_err_t err_code;
272
273 if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
274 {
275 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
276 err_code = NRFX_ERROR_ALREADY;
277 #else
278 err_code = NRFX_ERROR_INVALID_STATE;
279 #endif
280 NRFX_LOG_WARNING("Function: %s, error code: %s.",
281 __func__,
282 NRFX_LOG_ERROR_STRING_GET(err_code));
283 return err_code;
284 }
285
286 #if NRFX_CHECK(NRFX_PRS_ENABLED)
287 static nrfx_irq_handler_t const irq_handlers[NRFX_TWIM_ENABLED_COUNT] = {
288 NRFX_INSTANCE_IRQ_HANDLERS_LIST(TWIM, twim)
289 };
290 if (nrfx_prs_acquire(p_instance->p_twim,
291 irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
292 {
293 err_code = NRFX_ERROR_BUSY;
294 NRFX_LOG_WARNING("Function: %s, error code: %s.",
295 __func__,
296 NRFX_LOG_ERROR_STRING_GET(err_code));
297 return err_code;
298 }
299 #endif // NRFX_CHECK(NRFX_PRS_ENABLED)
300
301 p_cb->handler = event_handler;
302 p_cb->p_context = p_context;
303 p_cb->int_mask = 0;
304 p_cb->repeated = false;
305 p_cb->busy = false;
306
307 if (p_config)
308 {
309 p_cb->skip_gpio_cfg = p_config->skip_gpio_cfg;
310 if (!pins_configure(p_config))
311 {
312 #if NRFX_CHECK(NRFX_PRS_ENABLED)
313 nrfx_prs_release(p_instance->p_twim);
314 #endif
315 return NRFX_ERROR_INVALID_PARAM;
316 }
317
318 p_cb->hold_bus_uninit = p_config->hold_bus_uninit;
319 #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
320 p_cb->bus_frequency = (nrf_twim_frequency_t)p_config->frequency;
321 #endif
322
323 twim_configure(p_instance, p_config);
324 }
325
326 p_cb->state = NRFX_DRV_STATE_INITIALIZED;
327
328 err_code = NRFX_SUCCESS;
329 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
330 return err_code;
331 }
332
nrfx_twim_reconfigure(nrfx_twim_t const * p_instance,nrfx_twim_config_t const * p_config)333 nrfx_err_t nrfx_twim_reconfigure(nrfx_twim_t const * p_instance,
334 nrfx_twim_config_t const * p_config)
335 {
336 NRFX_ASSERT(p_config);
337
338 twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
339
340 if (p_cb->state == NRFX_DRV_STATE_UNINITIALIZED)
341 {
342 return NRFX_ERROR_INVALID_STATE;
343 }
344 if (p_cb->busy)
345 {
346 return NRFX_ERROR_BUSY;
347 }
348
349 nrfx_err_t err_code = NRFX_SUCCESS;
350 nrfy_twim_disable(p_instance->p_twim);
351 if (pins_configure(p_config))
352 {
353 twim_configure(p_instance, p_config);
354 }
355 else
356 {
357 err_code = NRFX_ERROR_INVALID_PARAM;
358 }
359 nrfy_twim_enable(p_instance->p_twim);
360 return err_code;
361 }
362
nrfx_twim_uninit(nrfx_twim_t const * p_instance)363 void nrfx_twim_uninit(nrfx_twim_t const * p_instance)
364 {
365 twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
366
367 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
368
369 nrfy_twim_int_uninit(p_instance->p_twim);
370 nrfx_twim_disable(p_instance);
371
372 #if NRFX_CHECK(NRFX_PRS_ENABLED)
373 nrfx_prs_release(p_instance->p_twim);
374 #endif
375
376 if (!p_cb->skip_gpio_cfg && !p_cb->hold_bus_uninit)
377 {
378 nrfy_twim_pins_t pins;
379
380 nrfy_twim_pins_get(p_instance->p_twim, &pins);
381 nrfy_gpio_cfg_default(pins.scl_pin);
382 nrfy_gpio_cfg_default(pins.sda_pin);
383 }
384
385 p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
386 NRFX_LOG_INFO("Instance uninitialized: %d.", p_instance->drv_inst_idx);
387 }
388
nrfx_twim_init_check(nrfx_twim_t const * p_instance)389 bool nrfx_twim_init_check(nrfx_twim_t const * p_instance)
390 {
391 twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
392
393 return (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
394 }
395
nrfx_twim_enable(nrfx_twim_t const * p_instance)396 void nrfx_twim_enable(nrfx_twim_t const * p_instance)
397 {
398 twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
399 NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED);
400
401 nrfy_twim_enable(p_instance->p_twim);
402
403 p_cb->state = NRFX_DRV_STATE_POWERED_ON;
404 NRFX_LOG_INFO("Instance enabled: %d.", p_instance->drv_inst_idx);
405 }
406
nrfx_twim_disable(nrfx_twim_t const * p_instance)407 void nrfx_twim_disable(nrfx_twim_t const * p_instance)
408 {
409 twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
410
411 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
412
413 p_cb->int_mask = 0;
414 nrfy_twim_stop(p_instance->p_twim);
415 p_cb->state = NRFX_DRV_STATE_INITIALIZED;
416 p_cb->busy = false;
417 NRFX_LOG_INFO("Instance disabled: %d.", p_instance->drv_inst_idx);
418 }
419
nrfx_twim_is_busy(nrfx_twim_t const * p_instance)420 bool nrfx_twim_is_busy(nrfx_twim_t const * p_instance)
421 {
422 twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
423 return p_cb->busy;
424 }
425
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)426 static nrfx_err_t twim_xfer(twim_control_block_t * p_cb,
427 NRF_TWIM_Type * p_twim,
428 nrfx_twim_xfer_desc_t const * p_xfer_desc,
429 uint32_t flags)
430 {
431 nrfx_err_t err_code = NRFX_SUCCESS;
432 p_cb->error = false;
433
434 if (p_xfer_desc->primary_length != 0 &&
435 !nrfx_is_in_ram(p_xfer_desc->p_primary_buf))
436 {
437 err_code = NRFX_ERROR_INVALID_ADDR;
438 NRFX_LOG_WARNING("Function: %s, error code: %s.",
439 __func__,
440 NRFX_LOG_ERROR_STRING_GET(err_code));
441 return err_code;
442 }
443
444 if ((p_xfer_desc->type == NRFX_TWIM_XFER_TXTX ||
445 p_xfer_desc->type == NRFX_TWIM_XFER_TXRX) &&
446 !nrfx_is_in_ram(p_xfer_desc->p_secondary_buf))
447 {
448 err_code = NRFX_ERROR_INVALID_ADDR;
449 NRFX_LOG_WARNING("Function: %s, error code: %s.",
450 __func__,
451 NRFX_LOG_ERROR_STRING_GET(err_code));
452 return err_code;
453 }
454
455 #if !NRFY_TWIM_HAS_ARRAY_LIST
456 if ((NRFX_TWIM_FLAG_TX_POSTINC | NRFX_TWIM_FLAG_RX_POSTINC) & flags)
457 {
458 err_code = NRFX_ERROR_NOT_SUPPORTED;
459 NRFX_LOG_WARNING("Function: %s, error code: %s.",
460 __func__,
461 NRFX_LOG_ERROR_STRING_GET(err_code));
462 return err_code;
463 }
464 #endif
465
466 /* Block TWI interrupts to ensure that function is not interrupted by TWI interrupt. */
467 nrfy_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
468 if (p_cb->busy)
469 {
470 nrfy_twim_int_enable(p_twim, p_cb->int_mask);
471 err_code = NRFX_ERROR_BUSY;
472 NRFX_LOG_WARNING("Function: %s, error code: %s.",
473 __func__,
474 NRFX_LOG_ERROR_STRING_GET(err_code));
475 return err_code;
476 }
477 else
478 {
479 p_cb->busy = ((NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER & flags) ||
480 (NRFX_TWIM_FLAG_REPEATED_XFER & flags)) ? false : true;
481 }
482
483 p_cb->xfer_type = p_xfer_desc->type;
484 p_cb->address = p_xfer_desc->address;
485 p_cb->xfer_desc_primary.p_buffer = p_xfer_desc->p_primary_buf;
486 p_cb->xfer_desc_primary.length = p_xfer_desc->primary_length;
487 p_cb->xfer_desc_secondary.p_buffer = p_xfer_desc->p_secondary_buf;
488 p_cb->xfer_desc_secondary.length = p_xfer_desc->secondary_length;
489 p_cb->repeated = (flags & NRFX_TWIM_FLAG_REPEATED_XFER) ? true : false;
490 p_cb->flags = flags;
491 nrfy_twim_address_set(p_twim, p_xfer_desc->address);
492
493 nrfy_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTTX);
494 nrfy_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED);
495 nrfy_twim_event_clear(p_twim, NRF_TWIM_EVENT_ERROR);
496 nrfy_twim_event_clear(p_twim, NRF_TWIM_EVENT_STOPPED);
497
498 #if NRFY_TWIM_HAS_ARRAY_LIST
499 nrfy_twim_tx_list_set(p_twim, NRFX_TWIM_FLAG_TX_POSTINC & flags);
500 nrfy_twim_rx_list_set(p_twim, NRFX_TWIM_FLAG_RX_POSTINC & flags);
501 #endif
502 switch (p_xfer_desc->type)
503 {
504 case NRFX_TWIM_XFER_TXTX:
505 NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_REPEATED_XFER));
506 NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_HOLD_XFER));
507 NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER));
508 nrfy_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_SUSPEND_MASK);
509 nrfy_twim_tx_buffer_set(p_twim, &p_cb->xfer_desc_primary);
510 nrfy_twim_tx_start(p_twim, NULL);
511 while (nrfy_twim_events_process(p_twim,
512 NRFY_EVENT_TO_INT_BITMASK(NRF_TWIM_EVENT_TXSTARTED),
513 NULL))
514 {}
515 nrfy_twim_tx_buffer_set(p_twim, &p_cb->xfer_desc_secondary);
516 NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_TXSTARTED));
517 p_cb->int_mask = NRF_TWIM_INT_SUSPENDED_MASK;
518 break;
519 case NRFX_TWIM_XFER_TXRX:
520 nrfy_twim_tx_buffer_set(p_twim, &p_cb->xfer_desc_primary);
521 nrfy_twim_rx_buffer_set(p_twim, &p_cb->xfer_desc_secondary);
522 nrfy_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STARTRX_MASK |
523 NRF_TWIM_SHORT_LASTRX_STOP_MASK);
524 nrfy_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
525 p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK;
526 break;
527 case NRFX_TWIM_XFER_TX:
528 nrfy_twim_tx_buffer_set(p_twim, &p_cb->xfer_desc_primary);
529 if (NRFX_TWIM_FLAG_TX_NO_STOP & flags)
530 {
531 nrfy_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_SUSPEND_MASK);
532 p_cb->int_mask = NRF_TWIM_INT_SUSPENDED_MASK;
533 }
534 else
535 {
536 nrfy_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STOP_MASK);
537 p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK;
538 }
539 nrfy_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
540 break;
541 case NRFX_TWIM_XFER_RX:
542 nrfy_twim_rx_buffer_set(p_twim, &p_cb->xfer_desc_primary);
543 nrfy_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTRX_STOP_MASK);
544 nrfy_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
545 p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK;
546 break;
547 default:
548 err_code = NRFX_ERROR_INVALID_PARAM;
549 break;
550 }
551
552 if (!(flags & NRFX_TWIM_FLAG_HOLD_XFER) && (p_xfer_desc->type != NRFX_TWIM_XFER_TXTX))
553 {
554 if (p_xfer_desc->type == NRFX_TWIM_XFER_RX)
555 {
556 nrfy_twim_rx_start(p_twim, p_cb->handler ? NULL : &p_cb->xfer_desc_primary);
557 }
558 else
559 {
560 nrfy_twim_tx_start(p_twim, p_cb->handler ? NULL : &p_cb->xfer_desc_primary);
561 }
562 /* Handling zero length transfers in non-blocking mode.
563 In blocking mode zero length transfer is handled in
564 @ref{nrfy_twim_tx_start} and @ref{nrfy_twim_rx_start}
565 */
566 if (p_xfer_desc->primary_length == 0 && p_cb->handler)
567 {
568 nrfy_twim_task_trigger(p_twim, NRF_TWIM_TASK_STOP);
569 }
570 }
571
572 if (p_cb->handler)
573 {
574 if (flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER)
575 {
576 p_cb->int_mask = 0;
577 }
578
579 if (!(flags & NRFX_TWIM_FLAG_NO_SPURIOUS_STOP_CHECK))
580 {
581 p_cb->int_mask |= NRF_TWIM_INT_STOPPED_MASK;
582 }
583
584 // Interrupts for ERROR are implicitly enabled, regardless of driver configuration.
585 p_cb->int_mask |= NRF_TWIM_INT_ERROR_MASK;
586 nrfy_twim_int_enable(p_twim, p_cb->int_mask);
587
588 #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
589 if ((flags & NRFX_TWIM_FLAG_HOLD_XFER) && (p_xfer_desc->type != NRFX_TWIM_XFER_RX))
590 {
591 nrfy_twim_tx_list_set(p_twim, false);
592 nrfy_twim_rx_list_set(p_twim, false);
593 p_twim->FREQUENCY = 0;
594 nrfy_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
595 nrfy_twim_int_enable(p_twim, NRF_TWIM_INT_TXSTARTED_MASK);
596 }
597 else
598 {
599 nrfy_twim_frequency_set(p_twim, p_cb->bus_frequency);
600 }
601 #endif
602 }
603 else
604 {
605 uint32_t errorsrc = nrfy_twim_errorsrc_get_and_clear(p_twim);
606
607 p_cb->busy = false;
608
609 if (errorsrc)
610 {
611 err_code = twi_process_error(errorsrc);
612 }
613 else
614 {
615 if (!(flags & NRFX_TWIM_FLAG_NO_SPURIOUS_STOP_CHECK) &&
616 !xfer_completeness_check(p_twim, p_cb))
617 {
618 err_code = NRFX_ERROR_INTERNAL;
619 }
620 }
621 }
622
623 NRFX_LOG_INFO("Function: %s, error code: %s.",
624 __func__,
625 NRFX_LOG_ERROR_STRING_GET(err_code));
626 return err_code;
627 }
628
629
nrfx_twim_xfer(nrfx_twim_t const * p_instance,nrfx_twim_xfer_desc_t const * p_xfer_desc,uint32_t flags)630 nrfx_err_t nrfx_twim_xfer(nrfx_twim_t const * p_instance,
631 nrfx_twim_xfer_desc_t const * p_xfer_desc,
632 uint32_t flags)
633 {
634 NRFX_ASSERT(TWIM_LENGTH_VALIDATE(p_instance->drv_inst_idx,
635 p_xfer_desc->primary_length,
636 p_xfer_desc->secondary_length));
637
638 twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
639
640 NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_POWERED_ON);
641
642 // TXRX and TXTX transfers are supported only in non-blocking mode.
643 NRFX_ASSERT( !((p_cb->handler == NULL) && (p_xfer_desc->type == NRFX_TWIM_XFER_TXRX)));
644 NRFX_ASSERT( !((p_cb->handler == NULL) && (p_xfer_desc->type == NRFX_TWIM_XFER_TXTX)));
645
646 NRFX_LOG_INFO("Transfer type: %s.", TRANSFER_TO_STR(p_xfer_desc->type));
647 NRFX_LOG_INFO("Transfer buffers length: primary: %d, secondary: %d.",
648 p_xfer_desc->primary_length,
649 p_xfer_desc->secondary_length);
650 NRFX_LOG_DEBUG("Primary buffer data:");
651 NRFX_LOG_HEXDUMP_DEBUG(p_xfer_desc->p_primary_buf,
652 p_xfer_desc->primary_length *
653 sizeof(p_xfer_desc->p_primary_buf[0]));
654 NRFX_LOG_DEBUG("Secondary buffer data:");
655 NRFX_LOG_HEXDUMP_DEBUG(p_xfer_desc->p_secondary_buf,
656 p_xfer_desc->secondary_length *
657 sizeof(p_xfer_desc->p_secondary_buf[0]));
658
659 return twim_xfer(p_cb, p_instance->p_twim, p_xfer_desc, flags);
660 }
661
nrfx_twim_start_task_address_get(nrfx_twim_t const * p_instance,nrfx_twim_xfer_type_t xfer_type)662 uint32_t nrfx_twim_start_task_address_get(nrfx_twim_t const * p_instance,
663 nrfx_twim_xfer_type_t xfer_type)
664 {
665 NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state != NRFX_DRV_STATE_UNINITIALIZED);
666
667 return nrfy_twim_task_address_get(p_instance->p_twim,
668 (xfer_type != NRFX_TWIM_XFER_RX) ? NRF_TWIM_TASK_STARTTX : NRF_TWIM_TASK_STARTRX);
669 }
670
nrfx_twim_stopped_event_address_get(nrfx_twim_t const * p_instance)671 uint32_t nrfx_twim_stopped_event_address_get(nrfx_twim_t const * p_instance)
672 {
673 NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state != NRFX_DRV_STATE_UNINITIALIZED);
674
675 return nrfy_twim_event_address_get(p_instance->p_twim, NRF_TWIM_EVENT_STOPPED);
676 }
677
irq_handler(NRF_TWIM_Type * p_twim,twim_control_block_t * p_cb)678 static void irq_handler(NRF_TWIM_Type * p_twim, twim_control_block_t * p_cb)
679 {
680 nrfy_twim_xfer_desc_t * p_xfer = p_cb->xfer_type == NRFX_TWIM_XFER_RX ?
681 &p_cb->xfer_desc_primary :
682 &p_cb->xfer_desc_secondary;
683 #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
684 if (nrfy_twim_events_process(p_twim,
685 NRFY_EVENT_TO_INT_BITMASK(NRF_TWIM_EVENT_TXSTARTED),
686 NULL))
687 {
688 nrfy_twim_int_disable(p_twim, NRF_TWIM_INT_TXSTARTED_MASK);
689 if (p_twim->FREQUENCY == 0)
690 {
691 // Set enable to zero to reset TWIM internal state.
692 nrfy_twim_disable(p_twim);
693 nrfy_twim_enable(p_twim);
694
695 // Set proper frequency.
696 nrfy_twim_frequency_set(p_twim, p_cb->bus_frequency);
697 nrfy_twim_tx_list_set(p_twim, NRFX_TWIM_FLAG_TX_POSTINC & p_cb->flags);
698 nrfy_twim_rx_list_set(p_twim, NRFX_TWIM_FLAG_RX_POSTINC & p_cb->flags);
699 // Start proper transmission.
700 nrfy_twim_task_trigger(p_twim, NRF_TWIM_TASK_STARTTX);
701 return;
702 }
703 }
704 #endif
705 NRFX_ASSERT(p_cb->handler);
706
707 bool stopped = nrfy_twim_events_process(p_twim,
708 NRFY_EVENT_TO_INT_BITMASK(NRF_TWIM_EVENT_STOPPED),
709 p_xfer);
710
711 if (nrfy_twim_events_process(p_twim,
712 NRFY_EVENT_TO_INT_BITMASK(NRF_TWIM_EVENT_ERROR),
713 p_xfer))
714 {
715 NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_ERROR));
716 if (!stopped)
717 {
718 nrfy_twim_int_disable(p_twim, p_cb->int_mask);
719 p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK;
720 nrfy_twim_int_enable(p_twim, p_cb->int_mask);
721
722 if (!(nrfy_twim_events_process(p_twim,
723 NRFY_EVENT_TO_INT_BITMASK(NRF_TWIM_EVENT_LASTTX),
724 NULL) &&
725 (nrfy_twim_shorts_get(p_twim) & NRF_TWIM_SHORT_LASTTX_STOP_MASK)))
726 {
727 nrfy_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
728 nrfy_twim_task_trigger(p_twim, NRF_TWIM_TASK_STOP);
729 }
730
731 p_cb->error = true;
732 return;
733 }
734 }
735
736 nrfx_twim_evt_t event;
737
738 if (stopped)
739 {
740 NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_STOPPED));
741
742 if (!(p_cb->flags & NRFX_TWIM_FLAG_NO_SPURIOUS_STOP_CHECK) && !p_cb->error)
743 {
744 p_cb->error = !xfer_completeness_check(p_twim, p_cb);
745 }
746
747 // Further processing of STOPPED event is valid only if NO_XFER_EVT_HANDLER
748 // setting is not used.
749 if (!(p_cb->flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER))
750 {
751 nrfy_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTTX);
752 nrfy_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTRX);
753 if (!p_cb->repeated || p_cb->error)
754 {
755 nrfy_twim_shorts_set(p_twim, 0);
756 p_cb->int_mask = 0;
757 nrfy_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
758
759 // At this point interrupt handler should not be invoked again for current transfer.
760 // If STOPPED arrived during ERROR processing,
761 // its pending interrupt should be ignored.
762 // Otherwise spurious NRFX_TWIM_EVT_DONE or NRFX_TWIM_EVT_BUS_ERROR
763 // would be passed to user's handler.
764 NRFY_IRQ_PENDING_CLEAR(nrfx_get_irq_number(p_twim));
765 }
766
767 event.xfer_desc.type = p_cb->xfer_type;
768 event.xfer_desc.address = p_cb->address;
769 event.xfer_desc.p_primary_buf = p_cb->xfer_desc_primary.p_buffer;
770 event.xfer_desc.primary_length = p_cb->xfer_desc_primary.length;
771 event.xfer_desc.p_secondary_buf = p_cb->xfer_desc_secondary.p_buffer;
772 event.xfer_desc.secondary_length = p_cb->xfer_desc_secondary.length;
773 }
774
775 #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
776 else if (p_cb->xfer_type != NRFX_TWIM_XFER_RX)
777 {
778 /* Add Anomaly 109 workaround for each potential repeated transfer starting from TX. */
779 nrfy_twim_tx_list_set(p_twim, false);
780 nrfy_twim_rx_list_set(p_twim, false);
781 nrfy_twim_frequency_set(p_twim, (nrf_twim_frequency_t)0);
782 nrfy_twim_int_enable(p_twim, NRF_TWIM_INT_TXSTARTED_MASK);
783 }
784 #endif
785 }
786 else
787 {
788 (void)nrfy_twim_events_process(p_twim,
789 NRFY_EVENT_TO_INT_BITMASK(NRF_TWIM_EVENT_SUSPENDED),
790 p_xfer);
791 NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_SUSPENDED));
792 if (p_cb->xfer_type == NRFX_TWIM_XFER_TX)
793 {
794 if (!p_cb->repeated)
795 {
796 nrfy_twim_shorts_set(p_twim, 0);
797 p_cb->int_mask = 0;
798 nrfy_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
799
800 // At this point interrupt handler should not be invoked again for current transfer.
801 // If STOPPED arrived during SUSPENDED processing,
802 // its pending interrupt should be ignored.
803 // Otherwise spurious NRFX_TWIM_EVT_DONE or NRFX_TWIM_EVT_BUS_ERROR
804 // would be passed to user's handler.
805 NRFY_IRQ_PENDING_CLEAR(nrfx_get_irq_number(p_twim));
806 }
807
808 event.xfer_desc.type = p_cb->xfer_type;
809 event.xfer_desc.address = p_cb->address;
810 event.xfer_desc.p_primary_buf = p_cb->xfer_desc_primary.p_buffer;
811 event.xfer_desc.primary_length = p_cb->xfer_desc_primary.length;
812 event.xfer_desc.p_secondary_buf = p_cb->xfer_desc_secondary.p_buffer;
813 event.xfer_desc.secondary_length = p_cb->xfer_desc_secondary.length;
814 }
815 else
816 {
817 nrfy_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STOP_MASK);
818 p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK;
819 nrfy_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
820 nrfy_twim_int_enable(p_twim, p_cb->int_mask);
821 nrfy_twim_task_trigger(p_twim, NRF_TWIM_TASK_STARTTX);
822 nrfy_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
823 return;
824 }
825 }
826
827 uint32_t errorsrc = nrfy_twim_errorsrc_get_and_clear(p_twim);
828 if (errorsrc & NRF_TWIM_ERROR_ADDRESS_NACK)
829 {
830 event.type = NRFX_TWIM_EVT_ADDRESS_NACK;
831 NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_ADDRESS_NACK));
832 }
833 else if (errorsrc & NRF_TWIM_ERROR_DATA_NACK)
834 {
835 event.type = NRFX_TWIM_EVT_DATA_NACK;
836 NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_DATA_NACK));
837 }
838 else if (errorsrc & NRF_TWIM_ERROR_OVERRUN)
839 {
840 event.type = NRFX_TWIM_EVT_OVERRUN;
841 NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_OVERRUN));
842 }
843 else if (p_cb->error)
844 {
845 event.type = NRFX_TWIM_EVT_BUS_ERROR;
846 NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_BUS_ERROR));
847 }
848 else
849 {
850 event.type = NRFX_TWIM_EVT_DONE;
851 NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_DONE));
852 }
853
854 if (!p_cb->repeated)
855 {
856 p_cb->busy = false;
857 }
858
859 if (!(p_cb->flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER) || p_cb->error)
860 {
861 p_cb->handler(&event, p_cb->p_context);
862 }
863 }
864
865 NRFX_INSTANCE_IRQ_HANDLERS(TWIM, twim)
866
867 #endif // NRFX_CHECK(NRFX_TWIM_ENABLED)
868