1 /*
2 * Copyright (c) 2015 - 2020, 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_SPIM_ENABLED)
35
36 #if !(NRFX_CHECK(NRFX_SPIM0_ENABLED) || NRFX_CHECK(NRFX_SPIM1_ENABLED) || \
37 NRFX_CHECK(NRFX_SPIM2_ENABLED) || NRFX_CHECK(NRFX_SPIM3_ENABLED) || \
38 NRFX_CHECK(NRFX_SPIM4_ENABLED))
39 #error "No enabled SPIM instances. Check <nrfx_config.h>."
40 #endif
41
42
43 #include <nrfx_spim.h>
44 #include "prs/nrfx_prs.h"
45 #include <hal/nrf_gpio.h>
46
47 #define NRFX_LOG_MODULE SPIM
48 #include <nrfx_log.h>
49
50 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) && \
51 ((!NRF_SPIM_HW_CSN_PRESENT) || !(NRF_SPIM_DCX_PRESENT) || !(NRF_SPIM_RXDELAY_PRESENT))
52 #error "Extended options are not available in the SoC currently in use."
53 #endif
54
55 #define SPIMX_LENGTH_VALIDATE(peripheral, drv_inst_idx, rx_len, tx_len) \
56 (((drv_inst_idx) == NRFX_CONCAT_3(NRFX_, peripheral, _INST_IDX)) && \
57 NRFX_EASYDMA_LENGTH_VALIDATE(peripheral, rx_len, tx_len))
58
59 #define SPIMX_HW_CSN_PRESENT_VALIDATE(peripheral, drv_inst_idx) \
60 (((drv_inst_idx) == NRFX_CONCAT_3(NRFX_, peripheral, _INST_IDX)) && \
61 NRFX_CONCAT_2(peripheral, _FEATURE_HARDWARE_CSN_PRESENT))
62
63 #define SPIMX_DCX_PRESENT_VALIDATE(peripheral, drv_inst_idx) \
64 (((drv_inst_idx) == NRFX_CONCAT_3(NRFX_, peripheral, _INST_IDX)) && \
65 NRFX_CONCAT_2(peripheral, _FEATURE_DCX_PRESENT))
66
67 #define SPIMX_SUPPORTED_FREQ_VALIDATE(peripheral, drv_inst_idx, freq) \
68 ( \
69 ((drv_inst_idx) == NRFX_CONCAT_3(NRFX_, peripheral, _INST_IDX)) && \
70 ( \
71 (((freq) != NRF_SPIM_FREQ_16M) && ((freq) != NRF_SPIM_FREQ_32M)) || \
72 (((freq) == NRF_SPIM_FREQ_16M) && ((NRFX_CONCAT_2(peripheral, _MAX_DATARATE) >= 16))) || \
73 (((freq) == NRF_SPIM_FREQ_32M) && ((NRFX_CONCAT_2(peripheral, _MAX_DATARATE) >= 32))) \
74 ) \
75 )
76
77 #if NRFX_CHECK(NRFX_SPIM0_ENABLED)
78 #define SPIM0_LENGTH_VALIDATE(...) SPIMX_LENGTH_VALIDATE(SPIM0, __VA_ARGS__)
79 #define SPIM0_HW_CSN_PRESENT_VALIDATE(...) SPIMX_HW_CSN_PRESENT_VALIDATE(SPIM0, __VA_ARGS__)
80 #define SPIM0_DCX_PRESENT_VALIDATE(...) SPIMX_DCX_PRESENT_VALIDATE(SPIM0, __VA_ARGS__)
81 #define SPIM0_SUPPORTED_FREQ_VALIDATE(...) SPIMX_SUPPORTED_FREQ_VALIDATE(SPIM0, __VA_ARGS__)
82 #else
83 #define SPIM0_LENGTH_VALIDATE(...) 0
84 #define SPIM0_HW_CSN_PRESENT_VALIDATE(...) 0
85 #define SPIM0_DCX_PRESENT_VALIDATE(...) 0
86 #define SPIM0_SUPPORTED_FREQ_VALIDATE(...) 0
87 #endif
88
89 #if NRFX_CHECK(NRFX_SPIM1_ENABLED)
90 #define SPIM1_LENGTH_VALIDATE(...) SPIMX_LENGTH_VALIDATE(SPIM1, __VA_ARGS__)
91 #define SPIM1_HW_CSN_PRESENT_VALIDATE(...) SPIMX_HW_CSN_PRESENT_VALIDATE(SPIM1, __VA_ARGS__)
92 #define SPIM1_DCX_PRESENT_VALIDATE(...) SPIMX_DCX_PRESENT_VALIDATE(SPIM1, __VA_ARGS__)
93 #define SPIM1_SUPPORTED_FREQ_VALIDATE(...) SPIMX_SUPPORTED_FREQ_VALIDATE(SPIM1, __VA_ARGS__)
94 #else
95 #define SPIM1_LENGTH_VALIDATE(...) 0
96 #define SPIM1_HW_CSN_PRESENT_VALIDATE(...) 0
97 #define SPIM1_DCX_PRESENT_VALIDATE(...) 0
98 #define SPIM1_SUPPORTED_FREQ_VALIDATE(...) 0
99 #endif
100
101 #if NRFX_CHECK(NRFX_SPIM2_ENABLED)
102 #define SPIM2_LENGTH_VALIDATE(...) SPIMX_LENGTH_VALIDATE(SPIM2, __VA_ARGS__)
103 #define SPIM2_HW_CSN_PRESENT_VALIDATE(...) SPIMX_HW_CSN_PRESENT_VALIDATE(SPIM2, __VA_ARGS__)
104 #define SPIM2_DCX_PRESENT_VALIDATE(...) SPIMX_DCX_PRESENT_VALIDATE(SPIM2, __VA_ARGS__)
105 #define SPIM2_SUPPORTED_FREQ_VALIDATE(...) SPIMX_SUPPORTED_FREQ_VALIDATE(SPIM2, __VA_ARGS__)
106 #else
107 #define SPIM2_LENGTH_VALIDATE(...) 0
108 #define SPIM2_HW_CSN_PRESENT_VALIDATE(...) 0
109 #define SPIM2_DCX_PRESENT_VALIDATE(...) 0
110 #define SPIM2_SUPPORTED_FREQ_VALIDATE(...) 0
111 #endif
112
113 #if NRFX_CHECK(NRFX_SPIM3_ENABLED)
114 #define SPIM3_LENGTH_VALIDATE(...) SPIMX_LENGTH_VALIDATE(SPIM3, __VA_ARGS__)
115 #define SPIM3_HW_CSN_PRESENT_VALIDATE(...) SPIMX_HW_CSN_PRESENT_VALIDATE(SPIM3, __VA_ARGS__)
116 #define SPIM3_DCX_PRESENT_VALIDATE(...) SPIMX_DCX_PRESENT_VALIDATE(SPIM3, __VA_ARGS__)
117 #define SPIM3_SUPPORTED_FREQ_VALIDATE(...) SPIMX_SUPPORTED_FREQ_VALIDATE(SPIM3, __VA_ARGS__)
118 #else
119 #define SPIM3_LENGTH_VALIDATE(...) 0
120 #define SPIM3_HW_CSN_PRESENT_VALIDATE(...) 0
121 #define SPIM3_DCX_PRESENT_VALIDATE(...) 0
122 #define SPIM3_SUPPORTED_FREQ_VALIDATE(...) 0
123 #endif
124
125 #if NRFX_CHECK(NRFX_SPIM4_ENABLED)
126 #define SPIM4_LENGTH_VALIDATE(...) SPIMX_LENGTH_VALIDATE(SPIM4, __VA_ARGS__)
127 #define SPIM4_HW_CSN_PRESENT_VALIDATE(...) SPIMX_HW_CSN_PRESENT_VALIDATE(SPIM4, __VA_ARGS__)
128 #define SPIM4_DCX_PRESENT_VALIDATE(...) SPIMX_DCX_PRESENT_VALIDATE(SPIM4, __VA_ARGS__)
129 #define SPIM4_SUPPORTED_FREQ_VALIDATE(...) SPIMX_SUPPORTED_FREQ_VALIDATE(SPIM4, __VA_ARGS__)
130 #else
131 #define SPIM4_LENGTH_VALIDATE(...) 0
132 #define SPIM4_HW_CSN_PRESENT_VALIDATE(...) 0
133 #define SPIM4_DCX_PRESENT_VALIDATE(...) 0
134 #define SPIM4_SUPPORTED_FREQ_VALIDATE(...) 0
135 #endif
136
137 #define SPIM_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) \
138 (SPIM0_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \
139 SPIM1_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \
140 SPIM2_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \
141 SPIM3_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \
142 SPIM4_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len))
143
144 #define SPIM_HW_CSN_PRESENT_VALIDATE(drv_inst_idx) \
145 (SPIM0_HW_CSN_PRESENT_VALIDATE(drv_inst_idx) || \
146 SPIM1_HW_CSN_PRESENT_VALIDATE(drv_inst_idx) || \
147 SPIM2_HW_CSN_PRESENT_VALIDATE(drv_inst_idx) || \
148 SPIM3_HW_CSN_PRESENT_VALIDATE(drv_inst_idx) || \
149 SPIM4_HW_CSN_PRESENT_VALIDATE(drv_inst_idx))
150
151 #define SPIM_DCX_PRESENT_VALIDATE(drv_inst_idx) \
152 (SPIM0_DCX_PRESENT_VALIDATE(drv_inst_idx) || \
153 SPIM1_DCX_PRESENT_VALIDATE(drv_inst_idx) || \
154 SPIM2_DCX_PRESENT_VALIDATE(drv_inst_idx) || \
155 SPIM3_DCX_PRESENT_VALIDATE(drv_inst_idx) || \
156 SPIM4_DCX_PRESENT_VALIDATE(drv_inst_idx))
157
158 #define SPIM_SUPPORTED_FREQ_VALIDATE(drv_inst_idx, freq) \
159 (SPIM0_SUPPORTED_FREQ_VALIDATE(drv_inst_idx, freq) || \
160 SPIM1_SUPPORTED_FREQ_VALIDATE(drv_inst_idx, freq) || \
161 SPIM2_SUPPORTED_FREQ_VALIDATE(drv_inst_idx, freq) || \
162 SPIM3_SUPPORTED_FREQ_VALIDATE(drv_inst_idx, freq) || \
163 SPIM4_SUPPORTED_FREQ_VALIDATE(drv_inst_idx, freq))
164
165 #if defined(NRF52840_XXAA) && (NRFX_CHECK(NRFX_SPIM3_ENABLED))
166 // Enable workaround for nRF52840 anomaly 195 (SPIM3 continues to draw current after disable).
167 #define USE_WORKAROUND_FOR_ANOMALY_195
168 #endif
169
170
171 // Control block - driver instance local data.
172 typedef struct
173 {
174 nrfx_spim_evt_handler_t handler;
175 void * p_context;
176 nrfx_spim_evt_t evt; // Keep the struct that is ready for event handler. Less memcpy.
177 nrfx_drv_state_t state;
178 volatile bool transfer_in_progress;
179
180 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
181 bool use_hw_ss;
182 #endif
183
184 // [no need for 'volatile' attribute for the following members, as they
185 // are not concurrently used in IRQ handlers and main line code]
186 bool ss_active_high;
187 uint8_t ss_pin;
188 uint8_t orc;
189
190 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
191 size_t tx_length;
192 size_t rx_length;
193 #endif
194 } spim_control_block_t;
195 static spim_control_block_t m_cb[NRFX_SPIM_ENABLED_COUNT];
196
197 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
198
199 // Workaround for nRF52840 anomaly 198: SPIM3 transmit data might be corrupted.
200
201 static uint32_t m_anomaly_198_preserved_value;
202
anomaly_198_enable(uint8_t const * p_buffer,size_t buf_len)203 static void anomaly_198_enable(uint8_t const * p_buffer, size_t buf_len)
204 {
205 m_anomaly_198_preserved_value = *((volatile uint32_t *)0x40000E00);
206
207 if (buf_len == 0)
208 {
209 return;
210 }
211 uint32_t buffer_end_addr = ((uint32_t)p_buffer) + buf_len;
212 uint32_t block_addr = ((uint32_t)p_buffer) & ~0x1FFF;
213 uint32_t block_flag = (1UL << ((block_addr >> 13) & 0xFFFF));
214 uint32_t occupied_blocks = 0;
215
216 if (block_addr >= 0x20010000)
217 {
218 occupied_blocks = (1UL << 8);
219 }
220 else
221 {
222 do {
223 occupied_blocks |= block_flag;
224 block_flag <<= 1;
225 block_addr += 0x2000;
226 } while ((block_addr < buffer_end_addr) && (block_addr < 0x20012000));
227 }
228
229 *((volatile uint32_t *)0x40000E00) = occupied_blocks;
230 }
231
anomaly_198_disable(void)232 static void anomaly_198_disable(void)
233 {
234 *((volatile uint32_t *)0x40000E00) = m_anomaly_198_preserved_value;
235 }
236 #endif // NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
237
spim_abort(NRF_SPIM_Type * p_spim,spim_control_block_t * p_cb)238 static void spim_abort(NRF_SPIM_Type * p_spim, spim_control_block_t * p_cb)
239 {
240 nrf_spim_task_trigger(p_spim, NRF_SPIM_TASK_STOP);
241 bool stopped;
242 NRFX_WAIT_FOR(nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_STOPPED), 100, 1, stopped);
243 if (!stopped)
244 {
245 NRFX_LOG_ERROR("Failed to stop instance with base address: %p.", (void *)p_spim);
246 }
247 p_cb->transfer_in_progress = false;
248 }
249
nrfx_spim_init(nrfx_spim_t const * p_instance,nrfx_spim_config_t const * p_config,nrfx_spim_evt_handler_t handler,void * p_context)250 nrfx_err_t nrfx_spim_init(nrfx_spim_t const * p_instance,
251 nrfx_spim_config_t const * p_config,
252 nrfx_spim_evt_handler_t handler,
253 void * p_context)
254 {
255 NRFX_ASSERT(p_config);
256 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
257 nrfx_err_t err_code;
258
259 if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
260 {
261 err_code = NRFX_ERROR_INVALID_STATE;
262 NRFX_LOG_WARNING("Function: %s, error code: %s.",
263 __func__,
264 NRFX_LOG_ERROR_STRING_GET(err_code));
265 return err_code;
266 }
267
268 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
269 // Check if SPIM instance supports the extended features.
270 if (
271 (!SPIM_SUPPORTED_FREQ_VALIDATE(p_instance->drv_inst_idx, p_config->frequency)) ||
272 ((p_config->use_hw_ss) &&
273 !SPIM_HW_CSN_PRESENT_VALIDATE(p_instance->drv_inst_idx)) ||
274 ((p_config->dcx_pin != NRFX_SPIM_PIN_NOT_USED) &&
275 !SPIM_DCX_PRESENT_VALIDATE(p_instance->drv_inst_idx))
276 )
277 {
278 err_code = NRFX_ERROR_NOT_SUPPORTED;
279 NRFX_LOG_WARNING("Function: %s, error code: %s.",
280 __func__,
281 NRFX_LOG_ERROR_STRING_GET(err_code));
282 return err_code;
283 }
284 #endif
285
286 NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg;
287
288 #if NRFX_CHECK(NRFX_PRS_ENABLED)
289 static nrfx_irq_handler_t const irq_handlers[NRFX_SPIM_ENABLED_COUNT] = {
290 #if NRFX_CHECK(NRFX_SPIM0_ENABLED)
291 nrfx_spim_0_irq_handler,
292 #endif
293 #if NRFX_CHECK(NRFX_SPIM1_ENABLED)
294 nrfx_spim_1_irq_handler,
295 #endif
296 #if NRFX_CHECK(NRFX_SPIM2_ENABLED)
297 nrfx_spim_2_irq_handler,
298 #endif
299 #if NRFX_CHECK(NRFX_SPIM3_ENABLED)
300 nrfx_spim_3_irq_handler,
301 #endif
302 #if NRFX_CHECK(NRFX_SPIM4_ENABLED)
303 nrfx_spim_4_irq_handler,
304 #endif
305 };
306 if (nrfx_prs_acquire(p_instance->p_reg,
307 irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
308 {
309 err_code = NRFX_ERROR_BUSY;
310 NRFX_LOG_WARNING("Function: %s, error code: %s.",
311 __func__,
312 NRFX_LOG_ERROR_STRING_GET(err_code));
313 return err_code;
314 }
315 #endif // NRFX_CHECK(NRFX_PRS_ENABLED)
316
317 p_cb->handler = handler;
318 p_cb->p_context = p_context;
319
320 uint32_t mosi_pin;
321 uint32_t miso_pin;
322 // Configure pins used by the peripheral:
323 // - SCK - output with initial value corresponding with the SPI mode used:
324 // 0 - for modes 0 and 1 (CPOL = 0), 1 - for modes 2 and 3 (CPOL = 1);
325 // according to the reference manual guidelines this pin and its input
326 // buffer must always be connected for the SPI to work.
327 if (p_config->mode <= NRF_SPIM_MODE_1)
328 {
329 nrf_gpio_pin_clear(p_config->sck_pin);
330 }
331 else
332 {
333 nrf_gpio_pin_set(p_config->sck_pin);
334 }
335 nrf_gpio_cfg(p_config->sck_pin,
336 NRF_GPIO_PIN_DIR_OUTPUT,
337 NRF_GPIO_PIN_INPUT_CONNECT,
338 NRF_GPIO_PIN_NOPULL,
339 NRF_GPIO_PIN_S0S1,
340 NRF_GPIO_PIN_NOSENSE);
341 // - MOSI (optional) - output with initial value 0,
342 if (p_config->mosi_pin != NRFX_SPIM_PIN_NOT_USED)
343 {
344 mosi_pin = p_config->mosi_pin;
345 nrf_gpio_pin_clear(mosi_pin);
346 nrf_gpio_cfg_output(mosi_pin);
347 }
348 else
349 {
350 mosi_pin = NRF_SPIM_PIN_NOT_CONNECTED;
351 }
352 // - MISO (optional) - input,
353 if (p_config->miso_pin != NRFX_SPIM_PIN_NOT_USED)
354 {
355 miso_pin = p_config->miso_pin;
356 nrf_gpio_cfg_input(miso_pin, p_config->miso_pull);
357 }
358 else
359 {
360 miso_pin = NRF_SPIM_PIN_NOT_CONNECTED;
361 }
362 // - Slave Select (optional) - output with initial value 1 (inactive).
363
364 // 'p_cb->ss_pin' variable is used during transfers to check if SS pin should be toggled,
365 // so this field needs to be initialized even if the pin is not used.
366 p_cb->ss_pin = p_config->ss_pin;
367
368 if (p_config->ss_pin != NRFX_SPIM_PIN_NOT_USED)
369 {
370 if (p_config->ss_active_high)
371 {
372 nrf_gpio_pin_clear(p_config->ss_pin);
373 }
374 else
375 {
376 nrf_gpio_pin_set(p_config->ss_pin);
377 }
378 nrf_gpio_cfg_output(p_config->ss_pin);
379 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
380 if (p_config->use_hw_ss)
381 {
382 p_cb->use_hw_ss = p_config->use_hw_ss;
383 nrf_spim_csn_configure(p_spim,
384 p_config->ss_pin,
385 (p_config->ss_active_high == true ?
386 NRF_SPIM_CSN_POL_HIGH : NRF_SPIM_CSN_POL_LOW),
387 p_config->ss_duration);
388 }
389 #endif
390 p_cb->ss_active_high = p_config->ss_active_high;
391 }
392
393 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
394 // - DCX (optional) - output.
395 if (p_config->dcx_pin != NRFX_SPIM_PIN_NOT_USED)
396 {
397 nrf_gpio_pin_set(p_config->dcx_pin);
398 nrf_gpio_cfg_output(p_config->dcx_pin);
399 nrf_spim_dcx_pin_set(p_spim, p_config->dcx_pin);
400 }
401
402 // Change rx delay
403 nrf_spim_iftiming_set(p_spim, p_config->rx_delay);
404 #endif
405
406
407 nrf_spim_pins_set(p_spim, p_config->sck_pin, mosi_pin, miso_pin);
408 nrf_spim_frequency_set(p_spim, p_config->frequency);
409 nrf_spim_configure(p_spim, p_config->mode, p_config->bit_order);
410
411 nrf_spim_orc_set(p_spim, p_config->orc);
412
413 nrf_spim_enable(p_spim);
414
415 if (p_cb->handler)
416 {
417 NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_reg),
418 p_config->irq_priority);
419 NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_reg));
420 }
421
422 p_cb->transfer_in_progress = false;
423 p_cb->state = NRFX_DRV_STATE_INITIALIZED;
424
425 err_code = NRFX_SUCCESS;
426 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
427 return err_code;
428 }
429
nrfx_spim_uninit(nrfx_spim_t const * p_instance)430 void nrfx_spim_uninit(nrfx_spim_t const * p_instance)
431 {
432 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
433 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
434 NRF_SPIM_Type * p_spim = p_instance->p_reg;
435
436 if (p_cb->handler)
437 {
438 NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_reg));
439 nrf_spim_int_disable(p_spim, NRF_SPIM_ALL_INTS_MASK);
440 if (p_cb->transfer_in_progress)
441 {
442 // Ensure that SPI is not performing any transfer.
443 spim_abort(p_spim, p_cb);
444 }
445 }
446
447 nrf_spim_disable(p_spim);
448
449 nrf_gpio_cfg_default(nrf_spim_sck_pin_get(p_spim));
450
451 uint32_t miso_pin = nrf_spim_miso_pin_get(p_spim);
452 if (miso_pin != NRF_SPIM_PIN_NOT_CONNECTED)
453 {
454 nrf_gpio_cfg_default(miso_pin);
455 }
456
457 uint32_t mosi_pin = nrf_spim_mosi_pin_get(p_spim);
458 if (mosi_pin != NRF_SPIM_PIN_NOT_CONNECTED)
459 {
460 nrf_gpio_cfg_default(mosi_pin);
461 }
462
463 if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED)
464 {
465 nrf_gpio_cfg_default(p_cb->ss_pin);
466 }
467
468 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
469 uint32_t dcx_pin = nrf_spim_dcx_pin_get(p_spim);
470 if (dcx_pin != NRF_SPIM_PIN_NOT_CONNECTED)
471 {
472 nrf_gpio_cfg_default(dcx_pin);
473 }
474 #endif
475
476 #ifdef USE_WORKAROUND_FOR_ANOMALY_195
477 if (p_spim == NRF_SPIM3)
478 {
479 *(volatile uint32_t *)0x4002F004 = 1;
480 }
481 #endif
482
483 #if NRFX_CHECK(NRFX_PRS_ENABLED)
484 nrfx_prs_release(p_instance->p_reg);
485 #endif
486
487 p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
488 }
489
490 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
nrfx_spim_xfer_dcx(nrfx_spim_t const * p_instance,nrfx_spim_xfer_desc_t const * p_xfer_desc,uint32_t flags,uint8_t cmd_length)491 nrfx_err_t nrfx_spim_xfer_dcx(nrfx_spim_t const * p_instance,
492 nrfx_spim_xfer_desc_t const * p_xfer_desc,
493 uint32_t flags,
494 uint8_t cmd_length)
495 {
496 NRFX_ASSERT(cmd_length <= NRF_SPIM_DCX_CNT_ALL_CMD);
497 nrf_spim_dcx_cnt_set((NRF_SPIM_Type *)p_instance->p_reg, cmd_length);
498 return nrfx_spim_xfer(p_instance, p_xfer_desc, 0);
499 }
500 #endif
501
finish_transfer(spim_control_block_t * p_cb)502 static void finish_transfer(spim_control_block_t * p_cb)
503 {
504 // If Slave Select signal is used, this is the time to deactivate it.
505 if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED)
506 {
507 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
508 if (!p_cb->use_hw_ss)
509 #endif
510 {
511 if (p_cb->ss_active_high)
512 {
513 nrf_gpio_pin_clear(p_cb->ss_pin);
514 }
515 else
516 {
517 nrf_gpio_pin_set(p_cb->ss_pin);
518 }
519 }
520 }
521
522 // By clearing this flag before calling the handler we allow subsequent
523 // transfers to be started directly from the handler function.
524 p_cb->transfer_in_progress = false;
525
526 p_cb->evt.type = NRFX_SPIM_EVENT_DONE;
527 p_cb->handler(&p_cb->evt, p_cb->p_context);
528 }
529
spim_int_enable(NRF_SPIM_Type * p_spim,bool enable)530 static void spim_int_enable(NRF_SPIM_Type * p_spim, bool enable)
531 {
532 if (!enable)
533 {
534 nrf_spim_int_disable(p_spim, NRF_SPIM_INT_END_MASK);
535 }
536 else
537 {
538 nrf_spim_int_enable(p_spim, NRF_SPIM_INT_END_MASK);
539 }
540 }
541
spim_list_enable_handle(NRF_SPIM_Type * p_spim,uint32_t flags)542 static void spim_list_enable_handle(NRF_SPIM_Type * p_spim, uint32_t flags)
543 {
544 if (NRFX_SPIM_FLAG_TX_POSTINC & flags)
545 {
546 nrf_spim_tx_list_enable(p_spim);
547 }
548 else
549 {
550 nrf_spim_tx_list_disable(p_spim);
551 }
552
553 if (NRFX_SPIM_FLAG_RX_POSTINC & flags)
554 {
555 nrf_spim_rx_list_enable(p_spim);
556 }
557 else
558 {
559 nrf_spim_rx_list_disable(p_spim);
560 }
561 }
562
spim_xfer(NRF_SPIM_Type * p_spim,spim_control_block_t * p_cb,nrfx_spim_xfer_desc_t const * p_xfer_desc,uint32_t flags)563 static nrfx_err_t spim_xfer(NRF_SPIM_Type * p_spim,
564 spim_control_block_t * p_cb,
565 nrfx_spim_xfer_desc_t const * p_xfer_desc,
566 uint32_t flags)
567 {
568 nrfx_err_t err_code;
569 // EasyDMA requires that transfer buffers are placed in Data RAM region;
570 // signal error if they are not.
571 if ((p_xfer_desc->p_tx_buffer != NULL && !nrfx_is_in_ram(p_xfer_desc->p_tx_buffer)) ||
572 (p_xfer_desc->p_rx_buffer != NULL && !nrfx_is_in_ram(p_xfer_desc->p_rx_buffer)))
573 {
574 p_cb->transfer_in_progress = false;
575 err_code = NRFX_ERROR_INVALID_ADDR;
576 NRFX_LOG_WARNING("Function: %s, error code: %s.",
577 __func__,
578 NRFX_LOG_ERROR_STRING_GET(err_code));
579 return err_code;
580 }
581
582 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
583 p_cb->tx_length = 0;
584 p_cb->rx_length = 0;
585 #endif
586
587 nrf_spim_tx_buffer_set(p_spim, p_xfer_desc->p_tx_buffer, p_xfer_desc->tx_length);
588 nrf_spim_rx_buffer_set(p_spim, p_xfer_desc->p_rx_buffer, p_xfer_desc->rx_length);
589
590 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
591 if (p_spim == NRF_SPIM3)
592 {
593 anomaly_198_enable(p_xfer_desc->p_tx_buffer, p_xfer_desc->tx_length);
594 }
595 #endif
596
597 nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
598
599 spim_list_enable_handle(p_spim, flags);
600
601 if (!(flags & NRFX_SPIM_FLAG_HOLD_XFER))
602 {
603 nrf_spim_task_trigger(p_spim, NRF_SPIM_TASK_START);
604 }
605 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
606 if (flags & NRFX_SPIM_FLAG_HOLD_XFER)
607 {
608 nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED);
609 p_cb->tx_length = p_xfer_desc->tx_length;
610 p_cb->rx_length = p_xfer_desc->rx_length;
611 nrf_spim_tx_buffer_set(p_spim, p_xfer_desc->p_tx_buffer, 0);
612 nrf_spim_rx_buffer_set(p_spim, p_xfer_desc->p_rx_buffer, 0);
613 nrf_spim_int_enable(p_spim, NRF_SPIM_INT_STARTED_MASK);
614 }
615 #endif
616
617 if (!p_cb->handler)
618 {
619 if (!(flags & NRFX_SPIM_FLAG_HOLD_XFER))
620 {
621 while (!nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_END))
622 {}
623 }
624
625 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
626 if (p_spim == NRF_SPIM3)
627 {
628 anomaly_198_disable();
629 }
630 #endif
631 if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED)
632 {
633 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
634 if (!p_cb->use_hw_ss)
635 #endif
636 {
637 if (p_cb->ss_active_high)
638 {
639 nrf_gpio_pin_clear(p_cb->ss_pin);
640 }
641 else
642 {
643 nrf_gpio_pin_set(p_cb->ss_pin);
644 }
645 }
646 }
647 }
648 else
649 {
650 spim_int_enable(p_spim, !(flags & NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER));
651 }
652 err_code = NRFX_SUCCESS;
653 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
654 return err_code;
655 }
656
nrfx_spim_xfer(nrfx_spim_t const * p_instance,nrfx_spim_xfer_desc_t const * p_xfer_desc,uint32_t flags)657 nrfx_err_t nrfx_spim_xfer(nrfx_spim_t const * p_instance,
658 nrfx_spim_xfer_desc_t const * p_xfer_desc,
659 uint32_t flags)
660 {
661 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
662 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
663 NRFX_ASSERT(p_xfer_desc->p_tx_buffer != NULL || p_xfer_desc->tx_length == 0);
664 NRFX_ASSERT(p_xfer_desc->p_rx_buffer != NULL || p_xfer_desc->rx_length == 0);
665 NRFX_ASSERT(SPIM_LENGTH_VALIDATE(p_instance->drv_inst_idx,
666 p_xfer_desc->rx_length,
667 p_xfer_desc->tx_length));
668 NRFX_ASSERT(!(flags & NRFX_SPIM_FLAG_HOLD_XFER) ||
669 (p_cb->ss_pin == NRFX_SPIM_PIN_NOT_USED));
670
671 nrfx_err_t err_code = NRFX_SUCCESS;
672
673 if (p_cb->transfer_in_progress)
674 {
675 err_code = NRFX_ERROR_BUSY;
676 NRFX_LOG_WARNING("Function: %s, error code: %s.",
677 __func__,
678 NRFX_LOG_ERROR_STRING_GET(err_code));
679 return err_code;
680 }
681 else
682 {
683 if (p_cb->handler && !(flags & (NRFX_SPIM_FLAG_REPEATED_XFER |
684 NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER)))
685 {
686 p_cb->transfer_in_progress = true;
687 }
688 }
689
690 p_cb->evt.xfer_desc = *p_xfer_desc;
691
692 if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED)
693 {
694 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
695 if (!p_cb->use_hw_ss)
696 #endif
697 {
698 if (p_cb->ss_active_high)
699 {
700 nrf_gpio_pin_set(p_cb->ss_pin);
701 }
702 else
703 {
704 nrf_gpio_pin_clear(p_cb->ss_pin);
705 }
706 }
707 }
708
709 return spim_xfer(p_instance->p_reg, p_cb, p_xfer_desc, flags);
710 }
711
nrfx_spim_abort(nrfx_spim_t const * p_instance)712 void nrfx_spim_abort(nrfx_spim_t const * p_instance)
713 {
714 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
715 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
716
717 spim_abort(p_instance->p_reg, p_cb);
718 }
719
nrfx_spim_start_task_get(nrfx_spim_t const * p_instance)720 uint32_t nrfx_spim_start_task_get(nrfx_spim_t const * p_instance)
721 {
722 NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg;
723 return nrf_spim_task_address_get(p_spim, NRF_SPIM_TASK_START);
724 }
725
nrfx_spim_end_event_get(nrfx_spim_t const * p_instance)726 uint32_t nrfx_spim_end_event_get(nrfx_spim_t const * p_instance)
727 {
728 NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg;
729 return nrf_spim_event_address_get(p_spim, NRF_SPIM_EVENT_END);
730 }
731
irq_handler(NRF_SPIM_Type * p_spim,spim_control_block_t * p_cb)732 static void irq_handler(NRF_SPIM_Type * p_spim, spim_control_block_t * p_cb)
733 {
734
735 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
736 if ((nrf_spim_int_enable_check(p_spim, NRF_SPIM_INT_STARTED_MASK)) &&
737 (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_STARTED)) )
738 {
739 /* Handle first, zero-length, auxiliary transmission. */
740 nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED);
741 nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
742
743 NRFX_ASSERT(p_spim->TXD.MAXCNT == 0);
744 p_spim->TXD.MAXCNT = p_cb->tx_length;
745
746 NRFX_ASSERT(p_spim->RXD.MAXCNT == 0);
747 p_spim->RXD.MAXCNT = p_cb->rx_length;
748
749 /* Disable STARTED interrupt, used only in auxiliary transmission. */
750 nrf_spim_int_disable(p_spim, NRF_SPIM_INT_STARTED_MASK);
751
752 /* Start the actual, glitch-free transmission. */
753 nrf_spim_task_trigger(p_spim, NRF_SPIM_TASK_START);
754 return;
755 }
756 #endif
757
758 if (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_END))
759 {
760 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
761 if (p_spim == NRF_SPIM3)
762 {
763 anomaly_198_disable();
764 }
765 #endif
766 nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
767 NRFX_ASSERT(p_cb->handler);
768 NRFX_LOG_DEBUG("Event: NRF_SPIM_EVENT_END.");
769 finish_transfer(p_cb);
770 }
771 }
772
773 #if NRFX_CHECK(NRFX_SPIM0_ENABLED)
nrfx_spim_0_irq_handler(void)774 void nrfx_spim_0_irq_handler(void)
775 {
776 irq_handler(NRF_SPIM0, &m_cb[NRFX_SPIM0_INST_IDX]);
777 }
778 #endif
779
780 #if NRFX_CHECK(NRFX_SPIM1_ENABLED)
nrfx_spim_1_irq_handler(void)781 void nrfx_spim_1_irq_handler(void)
782 {
783 irq_handler(NRF_SPIM1, &m_cb[NRFX_SPIM1_INST_IDX]);
784 }
785 #endif
786
787 #if NRFX_CHECK(NRFX_SPIM2_ENABLED)
nrfx_spim_2_irq_handler(void)788 void nrfx_spim_2_irq_handler(void)
789 {
790 irq_handler(NRF_SPIM2, &m_cb[NRFX_SPIM2_INST_IDX]);
791 }
792 #endif
793
794 #if NRFX_CHECK(NRFX_SPIM3_ENABLED)
nrfx_spim_3_irq_handler(void)795 void nrfx_spim_3_irq_handler(void)
796 {
797 irq_handler(NRF_SPIM3, &m_cb[NRFX_SPIM3_INST_IDX]);
798 }
799 #endif
800
801 #if NRFX_CHECK(NRFX_SPIM4_ENABLED)
nrfx_spim_4_irq_handler(void)802 void nrfx_spim_4_irq_handler(void)
803 {
804 irq_handler(NRF_SPIM4, &m_cb[NRFX_SPIM4_INST_IDX]);
805 }
806 #endif
807
808 #endif // NRFX_CHECK(NRFX_SPIM_ENABLED)
809