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) || NRFX_CHECK(NRFX_TWIM1_ENABLED))
37 #error "No enabled TWIM instances. Check <nrfx_config.h>."
38 #endif
39
40 #include <nrfx_twim.h>
41 #include <hal/nrf_gpio.h>
42 #include "prs/nrfx_prs.h"
43
44 #define NRFX_LOG_MODULE TWIM
45 #include <nrfx_log.h>
46
47 #define EVT_TO_STR(event) \
48 (event == NRFX_TWIM_EVT_DONE ? "EVT_DONE" : \
49 (event == NRFX_TWIM_EVT_ADDRESS_NACK ? "EVT_ADDRESS_NACK" : \
50 (event == NRFX_TWIM_EVT_DATA_NACK ? "EVT_DATA_NACK" : \
51 "UNKNOWN ERROR")))
52
53 #define EVT_TO_STR_TWIM(event) \
54 (event == NRF_TWIM_EVENT_STOPPED ? "NRF_TWIM_EVENT_STOPPED" : \
55 (event == NRF_TWIM_EVENT_ERROR ? "NRF_TWIM_EVENT_ERROR" : \
56 (event == NRF_TWIM_EVENT_SUSPENDED ? "NRF_TWIM_EVENT_SUSPENDED" : \
57 (event == NRF_TWIM_EVENT_RXSTARTED ? "NRF_TWIM_EVENT_RXSTARTED" : \
58 (event == NRF_TWIM_EVENT_TXSTARTED ? "NRF_TWIM_EVENT_TXSTARTED" : \
59 (event == NRF_TWIM_EVENT_LASTRX ? "NRF_TWIM_EVENT_LASTRX" : \
60 (event == NRF_TWIM_EVENT_LASTTX ? "NRF_TWIM_EVENT_LASTTX" : \
61 "UNKNOWN ERROR")))))))
62
63 #define TRANSFER_TO_STR(type) \
64 (type == NRFX_TWIM_XFER_TX ? "XFER_TX" : \
65 (type == NRFX_TWIM_XFER_RX ? "XFER_RX" : \
66 (type == NRFX_TWIM_XFER_TXRX ? "XFER_TXRX" : \
67 (type == NRFX_TWIM_XFER_TXTX ? "XFER_TXTX" : \
68 "UNKNOWN TRANSFER TYPE"))))
69
70 #define TWIM_PIN_INIT(_pin) nrf_gpio_cfg((_pin), \
71 NRF_GPIO_PIN_DIR_INPUT, \
72 NRF_GPIO_PIN_INPUT_CONNECT, \
73 NRF_GPIO_PIN_PULLUP, \
74 NRF_GPIO_PIN_S0D1, \
75 NRF_GPIO_PIN_NOSENSE)
76
77 #define TWIMX_LENGTH_VALIDATE(peripheral, drv_inst_idx, len1, len2) \
78 (((drv_inst_idx) == NRFX_CONCAT_3(NRFX_, peripheral, _INST_IDX)) && \
79 NRFX_EASYDMA_LENGTH_VALIDATE(peripheral, len1, len2))
80
81 #if NRFX_CHECK(NRFX_TWIM0_ENABLED)
82 #define TWIM0_LENGTH_VALIDATE(...) TWIMX_LENGTH_VALIDATE(TWIM0, __VA_ARGS__)
83 #else
84 #define TWIM0_LENGTH_VALIDATE(...) 0
85 #endif
86
87 #if NRFX_CHECK(NRFX_TWIM1_ENABLED)
88 #define TWIM1_LENGTH_VALIDATE(...) TWIMX_LENGTH_VALIDATE(TWIM1, __VA_ARGS__)
89 #else
90 #define TWIM1_LENGTH_VALIDATE(...) 0
91 #endif
92
93 #define TWIM_LENGTH_VALIDATE(drv_inst_idx, len1, len2) \
94 (TWIM0_LENGTH_VALIDATE(drv_inst_idx, len1, len2) || \
95 TWIM1_LENGTH_VALIDATE(drv_inst_idx, len1, len2))
96
97 // Control block - driver instance local data.
98 typedef struct
99 {
100 nrfx_twim_evt_handler_t handler;
101 void * p_context;
102 volatile uint32_t int_mask;
103 nrfx_twim_xfer_desc_t xfer_desc;
104 uint32_t flags;
105 uint8_t * p_curr_buf;
106 size_t curr_length;
107 bool curr_no_stop;
108 nrfx_drv_state_t state;
109 bool error;
110 volatile bool busy;
111 bool repeated;
112 uint8_t bytes_transferred;
113 bool hold_bus_uninit;
114 #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
115 nrf_twim_frequency_t bus_frequency;
116 #endif
117 } twim_control_block_t;
118
119 static twim_control_block_t m_cb[NRFX_TWIM_ENABLED_COUNT];
120
twi_process_error(uint32_t errorsrc)121 static nrfx_err_t twi_process_error(uint32_t errorsrc)
122 {
123 nrfx_err_t ret = NRFX_ERROR_INTERNAL;
124
125 if (errorsrc & NRF_TWIM_ERROR_ADDRESS_NACK)
126 {
127 ret = NRFX_ERROR_DRV_TWI_ERR_ANACK;
128 }
129
130 if (errorsrc & NRF_TWIM_ERROR_DATA_NACK)
131 {
132 ret = NRFX_ERROR_DRV_TWI_ERR_DNACK;
133 }
134
135 return ret;
136 }
137
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)138 nrfx_err_t nrfx_twim_init(nrfx_twim_t const * p_instance,
139 nrfx_twim_config_t const * p_config,
140 nrfx_twim_evt_handler_t event_handler,
141 void * p_context)
142 {
143 NRFX_ASSERT(p_config);
144 NRFX_ASSERT(p_config->scl != p_config->sda);
145 twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
146 nrfx_err_t err_code;
147
148 if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
149 {
150 err_code = NRFX_ERROR_INVALID_STATE;
151 NRFX_LOG_WARNING("Function: %s, error code: %s.",
152 __func__,
153 NRFX_LOG_ERROR_STRING_GET(err_code));
154 return err_code;
155 }
156
157 #if NRFX_CHECK(NRFX_PRS_ENABLED)
158 static nrfx_irq_handler_t const irq_handlers[NRFX_TWIM_ENABLED_COUNT] = {
159 #if NRFX_CHECK(NRFX_TWIM0_ENABLED)
160 nrfx_twim_0_irq_handler,
161 #endif
162 #if NRFX_CHECK(NRFX_TWIM1_ENABLED)
163 nrfx_twim_1_irq_handler,
164 #endif
165 };
166 if (nrfx_prs_acquire(p_instance->p_twim,
167 irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
168 {
169 err_code = NRFX_ERROR_BUSY;
170 NRFX_LOG_WARNING("Function: %s, error code: %s.",
171 __func__,
172 NRFX_LOG_ERROR_STRING_GET(err_code));
173 return err_code;
174 }
175 #endif // NRFX_CHECK(NRFX_PRS_ENABLED)
176
177 p_cb->handler = event_handler;
178 p_cb->p_context = p_context;
179 p_cb->int_mask = 0;
180 p_cb->repeated = false;
181 p_cb->busy = false;
182 p_cb->hold_bus_uninit = p_config->hold_bus_uninit;
183 #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
184 p_cb->bus_frequency = (nrf_twim_frequency_t)p_config->frequency;
185 #endif
186
187 /* To secure correct signal levels on the pins used by the TWI
188 master when the system is in OFF mode, and when the TWI master is
189 disabled, these pins must be configured in the GPIO peripheral.
190 */
191 TWIM_PIN_INIT(p_config->scl);
192 TWIM_PIN_INIT(p_config->sda);
193
194 NRF_TWIM_Type * p_twim = p_instance->p_twim;
195 nrf_twim_pins_set(p_twim, p_config->scl, p_config->sda);
196 nrf_twim_frequency_set(p_twim,
197 (nrf_twim_frequency_t)p_config->frequency);
198
199 if (p_cb->handler)
200 {
201 NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_twim),
202 p_config->interrupt_priority);
203 NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_twim));
204 }
205
206 p_cb->state = NRFX_DRV_STATE_INITIALIZED;
207
208 err_code = NRFX_SUCCESS;
209 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
210 return err_code;
211 }
212
nrfx_twim_uninit(nrfx_twim_t const * p_instance)213 void nrfx_twim_uninit(nrfx_twim_t const * p_instance)
214 {
215 twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
216 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
217
218 if (p_cb->handler)
219 {
220 NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_twim));
221 }
222 nrfx_twim_disable(p_instance);
223
224 #if NRFX_CHECK(NRFX_PRS_ENABLED)
225 nrfx_prs_release(p_instance->p_twim);
226 #endif
227
228 if (!p_cb->hold_bus_uninit)
229 {
230 nrf_gpio_cfg_default(p_instance->p_twim->PSEL.SCL);
231 nrf_gpio_cfg_default(p_instance->p_twim->PSEL.SDA);
232 }
233
234 p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
235 NRFX_LOG_INFO("Instance uninitialized: %d.", p_instance->drv_inst_idx);
236 }
237
nrfx_twim_enable(nrfx_twim_t const * p_instance)238 void nrfx_twim_enable(nrfx_twim_t const * p_instance)
239 {
240 twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
241 NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED);
242
243 nrf_twim_enable(p_instance->p_twim);
244
245 p_cb->state = NRFX_DRV_STATE_POWERED_ON;
246 NRFX_LOG_INFO("Instance enabled: %d.", p_instance->drv_inst_idx);
247 }
248
nrfx_twim_disable(nrfx_twim_t const * p_instance)249 void nrfx_twim_disable(nrfx_twim_t const * p_instance)
250 {
251 twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
252 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
253
254 NRF_TWIM_Type * p_twim = p_instance->p_twim;
255 p_cb->int_mask = 0;
256 nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
257 nrf_twim_shorts_disable(p_twim, NRF_TWIM_ALL_SHORTS_MASK);
258 nrf_twim_disable(p_twim);
259
260 p_cb->state = NRFX_DRV_STATE_INITIALIZED;
261 NRFX_LOG_INFO("Instance disabled: %d.", p_instance->drv_inst_idx);
262 }
263
264
nrfx_twim_is_busy(nrfx_twim_t const * p_instance)265 bool nrfx_twim_is_busy(nrfx_twim_t const * p_instance)
266 {
267 twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
268 return p_cb->busy;
269 }
270
271
twim_list_enable_handle(NRF_TWIM_Type * p_twim,uint32_t flags)272 __STATIC_INLINE void twim_list_enable_handle(NRF_TWIM_Type * p_twim, uint32_t flags)
273 {
274 if (NRFX_TWIM_FLAG_TX_POSTINC & flags)
275 {
276 nrf_twim_tx_list_enable(p_twim);
277 }
278 else
279 {
280 nrf_twim_tx_list_disable(p_twim);
281 }
282
283 if (NRFX_TWIM_FLAG_RX_POSTINC & flags)
284 {
285 nrf_twim_rx_list_enable(p_twim);
286 }
287 else
288 {
289 nrf_twim_rx_list_disable(p_twim);
290 }
291 }
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)292 __STATIC_INLINE nrfx_err_t twim_xfer(twim_control_block_t * p_cb,
293 NRF_TWIM_Type * p_twim,
294 nrfx_twim_xfer_desc_t const * p_xfer_desc,
295 uint32_t flags)
296 {
297 nrfx_err_t err_code = NRFX_SUCCESS;
298 nrf_twim_task_t start_task = NRF_TWIM_TASK_STARTTX;
299 nrf_twim_event_t evt_to_wait = NRF_TWIM_EVENT_STOPPED;
300
301 if (!nrfx_is_in_ram(p_xfer_desc->p_primary_buf))
302 {
303 err_code = NRFX_ERROR_INVALID_ADDR;
304 NRFX_LOG_WARNING("Function: %s, error code: %s.",
305 __func__,
306 NRFX_LOG_ERROR_STRING_GET(err_code));
307 return err_code;
308 }
309 /* Block TWI interrupts to ensure that function is not interrupted by TWI interrupt. */
310 nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
311 if (p_cb->busy)
312 {
313 nrf_twim_int_enable(p_twim, p_cb->int_mask);
314 err_code = NRFX_ERROR_BUSY;
315 NRFX_LOG_WARNING("Function: %s, error code: %s.",
316 __func__,
317 NRFX_LOG_ERROR_STRING_GET(err_code));
318 return err_code;
319 }
320 else
321 {
322 p_cb->busy = ((NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER & flags) ||
323 (NRFX_TWIM_FLAG_REPEATED_XFER & flags)) ? false: true;
324 }
325
326 p_cb->xfer_desc = *p_xfer_desc;
327 p_cb->repeated = (flags & NRFX_TWIM_FLAG_REPEATED_XFER) ? true : false;
328 nrf_twim_address_set(p_twim, p_xfer_desc->address);
329
330 nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_STOPPED);
331 nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_ERROR);
332
333 twim_list_enable_handle(p_twim, flags);
334 switch (p_xfer_desc->type)
335 {
336 case NRFX_TWIM_XFER_TXTX:
337 NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_REPEATED_XFER));
338 NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_HOLD_XFER));
339 NRFX_ASSERT(!(flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER));
340 if (!nrfx_is_in_ram(p_xfer_desc->p_secondary_buf))
341 {
342 err_code = NRFX_ERROR_INVALID_ADDR;
343 NRFX_LOG_WARNING("Function: %s, error code: %s.",
344 __func__,
345 NRFX_LOG_ERROR_STRING_GET(err_code));
346 return err_code;
347 }
348 nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_SUSPEND_MASK);
349 nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
350 nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
351 nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTTX);
352 nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED);
353 nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
354 nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STARTTX);
355 while (!nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_TXSTARTED))
356 {}
357 NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_TXSTARTED));
358 nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
359 nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_secondary_buf, p_xfer_desc->secondary_length);
360 p_cb->int_mask = NRF_TWIM_INT_SUSPENDED_MASK | NRF_TWIM_INT_ERROR_MASK;
361 break;
362 case NRFX_TWIM_XFER_TXRX:
363 nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
364 if (!nrfx_is_in_ram(p_xfer_desc->p_secondary_buf))
365 {
366 err_code = NRFX_ERROR_INVALID_ADDR;
367 NRFX_LOG_WARNING("Function: %s, error code: %s.",
368 __func__,
369 NRFX_LOG_ERROR_STRING_GET(err_code));
370 return err_code;
371 }
372 nrf_twim_rx_buffer_set(p_twim, p_xfer_desc->p_secondary_buf, p_xfer_desc->secondary_length);
373 nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STARTRX_MASK |
374 NRF_TWIM_SHORT_LASTRX_STOP_MASK);
375 p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK;
376 nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
377 break;
378 case NRFX_TWIM_XFER_TX:
379 nrf_twim_tx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
380 if (NRFX_TWIM_FLAG_TX_NO_STOP & flags)
381 {
382 nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_SUSPEND_MASK);
383 p_cb->int_mask = NRF_TWIM_INT_SUSPENDED_MASK | NRF_TWIM_INT_ERROR_MASK;
384 nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED);
385 evt_to_wait = NRF_TWIM_EVENT_SUSPENDED;
386 }
387 else
388 {
389 nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STOP_MASK);
390 p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK;
391 }
392 nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
393 break;
394 case NRFX_TWIM_XFER_RX:
395 nrf_twim_rx_buffer_set(p_twim, p_xfer_desc->p_primary_buf, p_xfer_desc->primary_length);
396 nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTRX_STOP_MASK);
397 p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK;
398 start_task = NRF_TWIM_TASK_STARTRX;
399 nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
400 break;
401 default:
402 err_code = NRFX_ERROR_INVALID_PARAM;
403 break;
404 }
405
406 if (!(flags & NRFX_TWIM_FLAG_HOLD_XFER) && (p_xfer_desc->type != NRFX_TWIM_XFER_TXTX))
407 {
408 nrf_twim_task_trigger(p_twim, start_task);
409 }
410
411 if (p_cb->handler)
412 {
413 if (flags & NRFX_TWIM_FLAG_NO_XFER_EVT_HANDLER)
414 {
415 p_cb->int_mask = NRF_TWIM_INT_ERROR_MASK;
416 }
417 nrf_twim_int_enable(p_twim, p_cb->int_mask);
418
419 #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
420 if ((flags & NRFX_TWIM_FLAG_HOLD_XFER) && ((p_xfer_desc->type == NRFX_TWIM_XFER_TX) ||
421 (p_xfer_desc->type == NRFX_TWIM_XFER_TXRX)))
422 {
423 p_cb->flags = flags;
424 twim_list_enable_handle(p_twim, 0);
425 p_twim->FREQUENCY = 0;
426 nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
427 nrf_twim_int_enable(p_twim, NRF_TWIM_INT_TXSTARTED_MASK);
428 }
429 #endif
430 }
431 else
432 {
433 while (!nrf_twim_event_check(p_twim, evt_to_wait))
434 {
435 if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_ERROR))
436 {
437 NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_ERROR));
438 nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_ERROR);
439 nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
440 nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STOP);
441 evt_to_wait = NRF_TWIM_EVENT_STOPPED;
442 }
443 }
444
445 uint32_t errorsrc = nrf_twim_errorsrc_get_and_clear(p_twim);
446
447 p_cb->busy = false;
448
449 if (errorsrc)
450 {
451 err_code = twi_process_error(errorsrc);
452 }
453 }
454 return err_code;
455 }
456
457
nrfx_twim_xfer(nrfx_twim_t const * p_instance,nrfx_twim_xfer_desc_t const * p_xfer_desc,uint32_t flags)458 nrfx_err_t nrfx_twim_xfer(nrfx_twim_t const * p_instance,
459 nrfx_twim_xfer_desc_t const * p_xfer_desc,
460 uint32_t flags)
461 {
462 NRFX_ASSERT(TWIM_LENGTH_VALIDATE(p_instance->drv_inst_idx,
463 p_xfer_desc->primary_length,
464 p_xfer_desc->secondary_length));
465
466 nrfx_err_t err_code = NRFX_SUCCESS;
467 twim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
468
469 // TXRX and TXTX transfers are supported only in non-blocking mode.
470 NRFX_ASSERT( !((p_cb->handler == NULL) && (p_xfer_desc->type == NRFX_TWIM_XFER_TXRX)));
471 NRFX_ASSERT( !((p_cb->handler == NULL) && (p_xfer_desc->type == NRFX_TWIM_XFER_TXTX)));
472
473 NRFX_LOG_INFO("Transfer type: %s.", TRANSFER_TO_STR(p_xfer_desc->type));
474 NRFX_LOG_INFO("Transfer buffers length: primary: %d, secondary: %d.",
475 p_xfer_desc->primary_length,
476 p_xfer_desc->secondary_length);
477 NRFX_LOG_DEBUG("Primary buffer data:");
478 NRFX_LOG_HEXDUMP_DEBUG(p_xfer_desc->p_primary_buf,
479 p_xfer_desc->primary_length * sizeof(p_xfer_desc->p_primary_buf[0]));
480 NRFX_LOG_DEBUG("Secondary buffer data:");
481 NRFX_LOG_HEXDUMP_DEBUG(p_xfer_desc->p_secondary_buf,
482 p_xfer_desc->secondary_length * sizeof(p_xfer_desc->p_secondary_buf[0]));
483
484 err_code = twim_xfer(p_cb, (NRF_TWIM_Type *)p_instance->p_twim, p_xfer_desc, flags);
485 NRFX_LOG_WARNING("Function: %s, error code: %s.",
486 __func__,
487 NRFX_LOG_ERROR_STRING_GET(err_code));
488 return err_code;
489 }
490
nrfx_twim_tx(nrfx_twim_t const * p_instance,uint8_t address,uint8_t const * p_data,size_t length,bool no_stop)491 nrfx_err_t nrfx_twim_tx(nrfx_twim_t const * p_instance,
492 uint8_t address,
493 uint8_t const * p_data,
494 size_t length,
495 bool no_stop)
496 {
497 nrfx_twim_xfer_desc_t xfer = NRFX_TWIM_XFER_DESC_TX(address, (uint8_t*)p_data, length);
498
499 return nrfx_twim_xfer(p_instance, &xfer, no_stop ? NRFX_TWIM_FLAG_TX_NO_STOP : 0);
500 }
501
nrfx_twim_rx(nrfx_twim_t const * p_instance,uint8_t address,uint8_t * p_data,size_t length)502 nrfx_err_t nrfx_twim_rx(nrfx_twim_t const * p_instance,
503 uint8_t address,
504 uint8_t * p_data,
505 size_t length)
506 {
507 nrfx_twim_xfer_desc_t xfer = NRFX_TWIM_XFER_DESC_RX(address, p_data, length);
508 return nrfx_twim_xfer(p_instance, &xfer, 0);
509 }
510
nrfx_twim_start_task_get(nrfx_twim_t const * p_instance,nrfx_twim_xfer_type_t xfer_type)511 uint32_t nrfx_twim_start_task_get(nrfx_twim_t const * p_instance,
512 nrfx_twim_xfer_type_t xfer_type)
513 {
514 return (uint32_t)nrf_twim_task_address_get(p_instance->p_twim,
515 (xfer_type != NRFX_TWIM_XFER_RX) ? NRF_TWIM_TASK_STARTTX : NRF_TWIM_TASK_STARTRX);
516 }
517
nrfx_twim_stopped_event_get(nrfx_twim_t const * p_instance)518 uint32_t nrfx_twim_stopped_event_get(nrfx_twim_t const * p_instance)
519 {
520 return (uint32_t)nrf_twim_event_address_get(p_instance->p_twim, NRF_TWIM_EVENT_STOPPED);
521 }
522
twim_irq_handler(NRF_TWIM_Type * p_twim,twim_control_block_t * p_cb)523 static void twim_irq_handler(NRF_TWIM_Type * p_twim, twim_control_block_t * p_cb)
524 {
525
526 #if NRFX_CHECK(NRFX_TWIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
527 /* Handle only workaround case. Can be used without TWIM handler in IRQs. */
528 if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_TXSTARTED))
529 {
530 nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_TXSTARTED);
531 nrf_twim_int_disable(p_twim, NRF_TWIM_INT_TXSTARTED_MASK);
532 if (p_twim->FREQUENCY == 0)
533 {
534 // Set enable to zero to reset TWIM internal state.
535 nrf_twim_disable(p_twim);
536 nrf_twim_enable(p_twim);
537
538 // Set proper frequency.
539 nrf_twim_frequency_set(p_twim, p_cb->bus_frequency);
540 twim_list_enable_handle(p_twim, p_cb->flags);
541
542 // Start proper transmission.
543 nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STARTTX);
544 return;
545 }
546 }
547 #endif
548
549 NRFX_ASSERT(p_cb->handler);
550
551 if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_ERROR))
552 {
553 nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_ERROR);
554 NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_ERROR));
555 if (!nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_STOPPED))
556 {
557 nrf_twim_int_disable(p_twim, p_cb->int_mask);
558 p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK;
559 nrf_twim_int_enable(p_twim, p_cb->int_mask);
560
561 nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
562 nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STOP);
563 return;
564 }
565 }
566
567 nrfx_twim_evt_t event;
568
569 if (nrf_twim_event_check(p_twim, NRF_TWIM_EVENT_STOPPED))
570 {
571 NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_STOPPED));
572 nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_STOPPED);
573 event.xfer_desc = p_cb->xfer_desc;
574 if (p_cb->error)
575 {
576
577 event.xfer_desc.primary_length = (p_cb->xfer_desc.type == NRFX_TWIM_XFER_RX) ?
578 nrf_twim_rxd_amount_get(p_twim) : nrf_twim_txd_amount_get(p_twim);
579 event.xfer_desc.secondary_length = (p_cb->xfer_desc.type == NRFX_TWIM_XFER_TXRX) ?
580 nrf_twim_rxd_amount_get(p_twim) : nrf_twim_txd_amount_get(p_twim);
581
582 }
583 nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTTX);
584 nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_LASTRX);
585 if (!p_cb->repeated || p_cb->error)
586 {
587 nrf_twim_shorts_set(p_twim, 0);
588 p_cb->int_mask = 0;
589 nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
590 }
591 }
592 else
593 {
594 nrf_twim_event_clear(p_twim, NRF_TWIM_EVENT_SUSPENDED);
595 NRFX_LOG_DEBUG("TWIM: Event: %s.", EVT_TO_STR_TWIM(NRF_TWIM_EVENT_SUSPENDED));
596 if (p_cb->xfer_desc.type == NRFX_TWIM_XFER_TX)
597 {
598 event.xfer_desc = p_cb->xfer_desc;
599 if (!p_cb->repeated)
600 {
601 nrf_twim_shorts_set(p_twim, 0);
602 p_cb->int_mask = 0;
603 nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
604 }
605 }
606 else
607 {
608 nrf_twim_shorts_set(p_twim, NRF_TWIM_SHORT_LASTTX_STOP_MASK);
609 p_cb->int_mask = NRF_TWIM_INT_STOPPED_MASK | NRF_TWIM_INT_ERROR_MASK;
610 nrf_twim_int_disable(p_twim, NRF_TWIM_ALL_INTS_MASK);
611 nrf_twim_int_enable(p_twim, p_cb->int_mask);
612 nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_STARTTX);
613 nrf_twim_task_trigger(p_twim, NRF_TWIM_TASK_RESUME);
614 return;
615 }
616 }
617
618 uint32_t errorsrc = nrf_twim_errorsrc_get_and_clear(p_twim);
619 if (errorsrc & NRF_TWIM_ERROR_ADDRESS_NACK)
620 {
621 event.type = NRFX_TWIM_EVT_ADDRESS_NACK;
622 NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_ADDRESS_NACK));
623 }
624 else if (errorsrc & NRF_TWIM_ERROR_DATA_NACK)
625 {
626 event.type = NRFX_TWIM_EVT_DATA_NACK;
627 NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_DATA_NACK));
628 }
629 else
630 {
631 event.type = NRFX_TWIM_EVT_DONE;
632 NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRFX_TWIM_EVT_DONE));
633 }
634
635 if (!p_cb->repeated)
636 {
637 p_cb->busy = false;
638 }
639 p_cb->handler(&event, p_cb->p_context);
640 }
641
642 #if NRFX_CHECK(NRFX_TWIM0_ENABLED)
nrfx_twim_0_irq_handler(void)643 void nrfx_twim_0_irq_handler(void)
644 {
645 twim_irq_handler(NRF_TWIM0, &m_cb[NRFX_TWIM0_INST_IDX]);
646 }
647 #endif
648
649 #if NRFX_CHECK(NRFX_TWIM1_ENABLED)
nrfx_twim_1_irq_handler(void)650 void nrfx_twim_1_irq_handler(void)
651 {
652 twim_irq_handler(NRF_TWIM1, &m_cb[NRFX_TWIM1_INST_IDX]);
653 }
654 #endif
655
656 #endif // NRFX_CHECK(NRFX_TWIM_ENABLED)
657