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_SPIM_ENABLED)
37
38 #if !NRFX_FEATURE_PRESENT(NRFX_SPIM, _ENABLED)
39 #error "No enabled SPIM instances. Check <nrfx_config.h>."
40 #endif
41
42 #include <nrfx_spim.h>
43 #include "prs/nrfx_prs.h"
44
45 #define NRFX_LOG_MODULE SPIM
46 #include <nrfx_log.h>
47
48 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) && !NRFY_SPIM_HAS_EXTENDED
49 #error "Extended options are not available in the SoC currently in use."
50 #endif
51
52 #define _NRFX_NUM_FEATURE_TOKEN(periph, inst, feature) \
53 NRFX_CONCAT(NRFX_CONCAT(periph, _, feature, _TOKEN), NRFX_CONCAT(inst, _, feature))
54
55 #define _NRFX_NUM_FEATURE_SUPPORTED_MASK(periph, prefix, i, feature) \
56 NRFX_COND_CODE_1(_NRFX_NUM_FEATURE_TOKEN(periph, NRFX_CONCAT(periph, prefix, i), feature), \
57 ((1UL << NRFX_CONCAT(NRFX_, periph, prefix, i, _INST_IDX))), (0))
58
59 /**
60 * @brief Macro initializes a mask with n bit set if nth driver instance supports the given numeric feature.
61 *
62 * Bits associated with non existing instances are set so that if all enabled instances supports
63 * the given feature mask has all 1 (and potentially can be optimized by the compiler).
64 *
65 * In order to determine if a given flag is set to a specific numeric value a token must be defined.
66 * Token must be defined to 1 and follow the name convention \<periph_name\>_\<feature\>_TOKEN\<value\>.
67 *
68 * @param periph Peripheral name.
69 * @param feature Feature name as used in the _peripherals.h.
70 */
71 #define NRFX_NUM_FEATURE_SUPPORTED_MASK(periph, feature) \
72 (~(NRFX_BIT(NRFX_CONCAT(NRFX_, periph, _ENABLED_COUNT)) - 1) | \
73 (NRFX_FOREACH_ENABLED(periph, _NRFX_NUM_FEATURE_SUPPORTED_MASK, (|), (0), feature)))
74
75 /* Internal helper macro which returns a bit mask set if nth driver instance supports the given feature. */
76 #define _NRFX_SUPPORTED_FEATURE_MASK(periph, prefix, i, feature) \
77 NRFX_COND_CODE_1(NRFX_CONCAT(periph, prefix, i, _, feature), \
78 ((1UL << NRFX_CONCAT(NRFX_, periph, prefix, i, _INST_IDX))), (0))
79
80 /**
81 * @brief Macro initializes a mask with n bit set if nth driver instance supports the given feature.
82 *
83 * Bits associated with non existing instances are set so that if all enabled instances supports
84 * the given feature mask has all 1 (and potentially can be optimized by the compiler).
85 *
86 * @param periph Peripheral name.
87 * @param feature Feature name as used in the _peripherals.h.
88 */
89 #define NRFX_FEATURE_SUPPORTED_MASK(periph, feature) \
90 (~(NRFX_BIT(NRFX_CONCAT(NRFX_, periph, _ENABLED_COUNT)) - 1) | \
91 (NRFX_FOREACH_ENABLED(periph, _NRFX_SUPPORTED_FEATURE_MASK, (|), (0), feature)))
92
93 #define _NRFX_INST_FEATURE_FLAG(periph, prefix, i, feature) NRFX_CONCAT(periph, prefix, i, _, feature),
94
95 /**
96 * @brief Macro initializes an array with numeric, feature value for each enabled driver instance.
97 *
98 * Array can be used as a lookup table to determine how the given feature is supported by the
99 * instance.
100 *
101 * @param periph Peripheral name.
102 * @param feature Feature name as used in the _peripherals.h.
103 */
104 #define NRFX_FEATURE_ARRAY_INITIALIZE(periph, feature) \
105 { NRFX_FOREACH_ENABLED(periph, _NRFX_INST_FEATURE_FLAG, (), (), feature) }
106
107 /* Token used to determine if SPIM instance supports 32M data rate. */
108 #define SPIM_MAX_DATARATE_TOKEN32 1
109
110 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
111 static const uint32_t rxdelay_support_mask =
112 NRFX_FEATURE_SUPPORTED_MASK(SPIM, FEATURE_RXDELAY_PRESENT);
113 static const uint32_t dcx_support_mask =
114 NRFX_FEATURE_SUPPORTED_MASK(SPIM, FEATURE_HARDWARE_DCX_PRESENT) |
115 NRFX_FEATURE_SUPPORTED_MASK(SPIM, FEATURE_DCX_PRESENT);
116 static const uint32_t hw_csn_support_mask =
117 NRFX_FEATURE_SUPPORTED_MASK(SPIM, FEATURE_HARDWARE_CSN_PRESENT);
118 static const uint32_t datarate32_support_mask =
119 NRFX_NUM_FEATURE_SUPPORTED_MASK(SPIM, MAX_DATARATE);
120 #endif
121
122 static const uint8_t easydma_support_bits[] __UNUSED =
123 NRFX_FEATURE_ARRAY_INITIALIZE(SPIM, EASYDMA_MAXCNT_SIZE);
124
125 #define SPIM_SUPPORTED_FREQ_VALIDATE(drv_inst_idx, freq) \
126 (((freq != NRFX_MHZ_TO_HZ(32)) && (freq != NRFX_MHZ_TO_HZ(16))) || \
127 ((NRFX_BIT(drv_inst_idx)) & datarate32_support_mask))
128
129 #define SPIM_RXDELAY_PRESENT_VALIDATE(drv_inst_idx) (NRFX_BIT(drv_inst_idx) & rxdelay_support_mask)
130
131 #define SPIM_DCX_PRESENT_VALIDATE(drv_inst_idx) (NRFX_BIT(drv_inst_idx) & dcx_support_mask)
132
133 #define SPIM_HW_CSN_PRESENT_VALIDATE(drv_inst_idx) (NRFX_BIT(drv_inst_idx) & hw_csn_support_mask)
134
135 #define SPIM_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) \
136 ((rx_len < NRFX_BIT(easydma_support_bits[drv_inst_idx])) && \
137 (tx_len < NRFX_BIT(easydma_support_bits[drv_inst_idx])))
138
139 // Requested pin can either match dedicated pin or be not connected at all.
140 #define SPIM_DEDICATED_PIN_VALIDATE(requested_pin, supported_pin) \
141 (((requested_pin) == NRF_SPIM_PIN_NOT_CONNECTED) || ((requested_pin) == (supported_pin)))
142
143 #if !defined(USE_WORKAROUND_FOR_ANOMALY_195) && \
144 defined(NRF52840_XXAA) && NRFX_CHECK(NRFX_SPIM3_ENABLED)
145 // Enable workaround for nRF52840 anomaly 195 (SPIM3 continues to draw current after disable).
146 #define USE_WORKAROUND_FOR_ANOMALY_195 1
147 #endif
148
149 #if NRFX_CHECK(NRF54L_ERRATA_8_PRESENT) || NRFX_CHECK(NRF54H_ERRATA_212_PRESENT)
150 #define USE_WORKAROUND_FOR_ANOMALY_NRF54L_8_NRF54H_212 1
apply_errata_nrf54l_8_nrf54h_212(void)151 static inline bool apply_errata_nrf54l_8_nrf54h_212(void)
152 {
153 return (NRFX_COND_CODE_1(NRF54L_ERRATA_8_PRESENT, (nrf54l_errata_8()), (false)) ||
154 NRFX_COND_CODE_1(NRF54H_ERRATA_212_PRESENT, (nrf54h_errata_212()), (false)));
155 }
156 #endif
157
158 // Control block - driver instance local data.
159 typedef struct
160 {
161 nrfx_spim_evt_handler_t handler;
162 void * p_context;
163 nrfx_spim_evt_t evt; // Keep the struct that is ready for event handler. Less memcpy.
164 nrfx_drv_state_t state;
165 volatile bool transfer_in_progress;
166 bool skip_gpio_cfg : 1;
167 bool ss_active_high : 1;
168 bool disable_on_xfer_end : 1;
169 #ifdef USE_WORKAROUND_FOR_ANOMALY_NRF54L_8_NRF54H_212
170 bool apply_errata_8_212 : 1;
171 #endif
172 uint32_t ss_pin;
173 } spim_control_block_t;
174 static spim_control_block_t m_cb[NRFX_SPIM_ENABLED_COUNT];
175
176 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
177
178 // Workaround for nRF52840 anomaly 198: SPIM3 transmit data might be corrupted.
179
180 static uint32_t m_anomaly_198_preserved_value;
181
anomaly_198_enable(uint8_t const * p_buffer,size_t buf_len)182 static void anomaly_198_enable(uint8_t const * p_buffer, size_t buf_len)
183 {
184 m_anomaly_198_preserved_value = *((volatile uint32_t *)0x40000E00);
185
186 if (buf_len == 0)
187 {
188 return;
189 }
190 uint32_t buffer_end_addr = ((uint32_t)p_buffer) + buf_len;
191 uint32_t block_addr = ((uint32_t)p_buffer) & ~0x1FFF;
192 uint32_t block_flag = (1UL << ((block_addr >> 13) & 0xFFFF));
193 uint32_t occupied_blocks = 0;
194
195 if (block_addr >= 0x20010000)
196 {
197 occupied_blocks = (1UL << 8);
198 }
199 else
200 {
201 do {
202 occupied_blocks |= block_flag;
203 block_flag <<= 1;
204 block_addr += 0x2000;
205 } while ((block_addr < buffer_end_addr) && (block_addr < 0x20012000));
206 }
207
208 *((volatile uint32_t *)0x40000E00) = occupied_blocks;
209 }
210
anomaly_198_disable(void)211 static void anomaly_198_disable(void)
212 {
213 *((volatile uint32_t *)0x40000E00) = m_anomaly_198_preserved_value;
214 }
215 #endif // NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
216
spim_abort(NRF_SPIM_Type * p_spim,spim_control_block_t * p_cb)217 static void spim_abort(NRF_SPIM_Type * p_spim, spim_control_block_t * p_cb)
218 {
219 nrfy_spim_abort(p_spim, NULL);
220 bool stopped;
221 uint32_t stopped_mask = NRFY_EVENT_TO_INT_BITMASK(NRF_SPIM_EVENT_STOPPED);
222 NRFX_WAIT_FOR(nrfy_spim_events_process(p_spim, stopped_mask, NULL), 100, 1, stopped);
223 if (!stopped)
224 {
225 NRFX_LOG_ERROR("Failed to stop instance with base address: %p.", (void *)p_spim);
226 }
227 p_cb->transfer_in_progress = false;
228 #if defined(HALTIUM_XXAA)
229 if (p_cb->disable_on_xfer_end)
230 #endif
231 {
232 nrfy_spim_disable(p_spim);
233 }
234 }
235
pin_init(uint32_t pin,nrf_gpio_pin_dir_t dir,nrf_gpio_pin_pull_t pull,nrf_gpio_pin_drive_t drive,uint32_t initial_state)236 static void pin_init(uint32_t pin,
237 nrf_gpio_pin_dir_t dir,
238 nrf_gpio_pin_pull_t pull,
239 nrf_gpio_pin_drive_t drive,
240 uint32_t initial_state)
241 {
242 nrf_gpio_pin_input_t input;
243
244 if (pin == NRF_SPIM_PIN_NOT_CONNECTED)
245 {
246 return;
247 }
248
249 if (dir == NRF_GPIO_PIN_DIR_OUTPUT)
250 {
251 if (initial_state)
252 {
253 nrfy_gpio_pin_set(pin);
254 }
255 else
256 {
257 nrfy_gpio_pin_clear(pin);
258 }
259 input = NRF_GPIO_PIN_INPUT_DISCONNECT;
260 }
261 else
262 {
263 input = NRF_GPIO_PIN_INPUT_CONNECT;
264 }
265
266 nrfy_gpio_cfg(pin, dir, input, pull, drive, NRF_GPIO_PIN_NOSENSE);
267 }
268
configure_pins(nrfx_spim_t const * p_instance,nrfx_spim_config_t const * p_config)269 static void configure_pins(nrfx_spim_t const * p_instance,
270 nrfx_spim_config_t const * p_config)
271 {
272 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
273
274 p_cb->ss_active_high = p_config->ss_active_high;
275
276 if (p_config->skip_gpio_cfg)
277 {
278 return;
279 }
280
281 nrf_gpio_pin_drive_t pin_drive;
282 // Configure pin drive - high drive for 32 MHz clock frequency.
283 #if defined(LUMOS_XXAA)
284 pin_drive = NRF_GPIO_PIN_H0H1;
285 #elif (NRF_SPIM_HAS_FREQUENCY && NRF_SPIM_HAS_32_MHZ_FREQ) || NRF_SPIM_HAS_PRESCALER
286 pin_drive = (p_config->frequency == NRFX_MHZ_TO_HZ(32)) ? NRF_GPIO_PIN_H0H1 : NRF_GPIO_PIN_S0S1;
287 #else
288 pin_drive = NRF_GPIO_PIN_S0S1;
289 #endif
290 // Configure pins used by the peripheral:
291 // - SCK - output with initial value corresponding with the SPI mode used:
292 // 0 - for modes 0 and 1 (CPOL = 0), 1 - for modes 2 and 3 (CPOL = 1);
293 // according to the reference manual guidelines this pin and its input
294 // buffer must always be connected for the SPI to work.
295 uint32_t sck_val = (p_config->mode <= NRF_SPIM_MODE_1) ? 0 : 1;
296 pin_init(p_config->sck_pin, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_NOPULL, pin_drive, sck_val);
297 #if NRF_GPIO_HAS_CLOCKPIN && defined(NRF_SPIM_CLOCKPIN_SCK_NEEDED)
298 nrfy_gpio_pin_clock_set(p_config->sck_pin, true);
299 #endif
300 // - MOSI (optional) - output with initial value 0
301 pin_init(p_config->mosi_pin, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_NOPULL, pin_drive, 0);
302 #if NRF_GPIO_HAS_CLOCKPIN && defined(NRF_SPIM_CLOCKPIN_MOSI_NEEDED)
303 nrfy_gpio_pin_clock_set(p_config->mosi_pin, true);
304 #endif
305 // - MISO (optional) - input
306 pin_init(p_config->miso_pin, NRF_GPIO_PIN_DIR_INPUT, p_config->miso_pull, pin_drive, 0);
307 // - Slave Select (optional) - output with initial value 1 (inactive).
308 uint32_t ss_val = !p_config->ss_active_high;
309 pin_init(p_config->ss_pin, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_NOPULL, pin_drive, ss_val);
310 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
311 // - DCX (optional) - output.
312 pin_init(p_config->dcx_pin, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_NOPULL, pin_drive, 1);
313 #endif
314 }
315
316 #if NRF_SPIM_HAS_FREQUENCY
spim_frequency_valid_check(nrfx_spim_t const * p_instance,uint32_t frequency)317 static bool spim_frequency_valid_check(nrfx_spim_t const * p_instance, uint32_t frequency)
318 {
319 (void)p_instance;
320 switch (frequency)
321 {
322 case NRFX_KHZ_TO_HZ(125):
323 /* FALLTHROUGH */
324 case NRFX_KHZ_TO_HZ(250):
325 /* FALLTHROUGH */
326 case NRFX_KHZ_TO_HZ(500):
327 /* FALLTHROUGH */
328 case NRFX_MHZ_TO_HZ(1):
329 /* FALLTHROUGH */
330 case NRFX_MHZ_TO_HZ(2):
331 /* FALLTHROUGH */
332 case NRFX_MHZ_TO_HZ(4):
333 /* FALLTHROUGH */
334 case NRFX_MHZ_TO_HZ(8):
335 return true;
336 #if NRF_SPIM_HAS_16_MHZ_FREQ
337 case NRFX_MHZ_TO_HZ(16):
338 return true;
339 #endif
340 #if NRF_SPIM_HAS_32_MHZ_FREQ
341 case NRFX_MHZ_TO_HZ(32):
342 return true;
343 #endif
344 default:
345 return false;
346 }
347 }
348
spim_frequency_bit_decode(uint32_t frequency)349 static nrf_spim_frequency_t spim_frequency_bit_decode(uint32_t frequency)
350 {
351 switch (frequency)
352 {
353 case NRFX_KHZ_TO_HZ(125):
354 return NRF_SPIM_FREQ_125K;
355 case NRFX_KHZ_TO_HZ(250):
356 return NRF_SPIM_FREQ_250K;
357 case NRFX_KHZ_TO_HZ(500):
358 return NRF_SPIM_FREQ_500K;
359 case NRFX_MHZ_TO_HZ(1):
360 return NRF_SPIM_FREQ_1M;
361 case NRFX_MHZ_TO_HZ(2):
362 return NRF_SPIM_FREQ_2M;
363 case NRFX_MHZ_TO_HZ(4):
364 return NRF_SPIM_FREQ_4M;
365 case NRFX_MHZ_TO_HZ(8):
366 return NRF_SPIM_FREQ_8M;
367 #if NRF_SPIM_HAS_16_MHZ_FREQ
368 case NRFX_MHZ_TO_HZ(16):
369 return NRF_SPIM_FREQ_16M;
370 #endif
371 #if NRF_SPIM_HAS_32_MHZ_FREQ
372 case NRFX_MHZ_TO_HZ(32):
373 return NRF_SPIM_FREQ_32M;
374 #endif
375 default:
376 NRFX_ASSERT(false);
377 return NRF_SPIM_FREQ_4M;
378 }
379 }
380 #elif NRF_SPIM_HAS_PRESCALER
spim_frequency_valid_check(nrfx_spim_t const * p_instance,uint32_t frequency)381 static bool spim_frequency_valid_check(nrfx_spim_t const * p_instance, uint32_t frequency)
382 {
383 uint32_t base_frequency = NRFX_SPIM_BASE_FREQUENCY_GET(p_instance);
384 uint32_t prescaler = NRF_SPIM_PRESCALER_CALCULATE(p_instance->p_reg, frequency);
385
386 return ((base_frequency % frequency) < prescaler) &&
387 NRFX_IS_EVEN(prescaler) &&
388 (prescaler <= NRF_SPIM_PRESCALER_MAX_GET(p_instance->p_reg)) &&
389 (prescaler >= NRF_SPIM_PRESCALER_MIN_GET(p_instance->p_reg));
390 }
391
spim_prescaler_calculate(nrfx_spim_t const * p_instance,uint32_t frequency)392 static uint32_t spim_prescaler_calculate(nrfx_spim_t const * p_instance, uint32_t frequency)
393 {
394 (void)p_instance;
395 return NRF_SPIM_PRESCALER_CALCULATE(p_instance->p_reg, frequency);
396 }
397 #else
398 #error "Unable to determine frequency division support type."
399 #endif
400
spim_configuration_verify(nrfx_spim_t const * p_instance,nrfx_spim_config_t const * p_config)401 static nrfx_err_t spim_configuration_verify(nrfx_spim_t const * p_instance,
402 nrfx_spim_config_t const * p_config)
403 {
404 nrfx_err_t err_code;
405 if (!spim_frequency_valid_check(p_instance, p_config->frequency))
406 {
407 err_code = NRFX_ERROR_INVALID_PARAM;
408 NRFX_LOG_WARNING("Function: %s, error code: %s.",
409 __func__,
410 NRFX_LOG_ERROR_STRING_GET(err_code));
411 return err_code;
412 }
413
414 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
415 // Check if SPIM instance supports the extended features.
416 if (!SPIM_SUPPORTED_FREQ_VALIDATE(p_instance->drv_inst_idx, p_config->frequency) ||
417 (p_config->use_hw_ss && (p_config->ss_pin != NRF_SPIM_PIN_NOT_CONNECTED) &&
418 !SPIM_HW_CSN_PRESENT_VALIDATE(p_instance->drv_inst_idx)) ||
419 ((p_config->dcx_pin != NRF_SPIM_PIN_NOT_CONNECTED) &&
420 !SPIM_DCX_PRESENT_VALIDATE(p_instance->drv_inst_idx)))
421 {
422 err_code = NRFX_ERROR_NOT_SUPPORTED;
423 NRFX_LOG_WARNING("Function: %s, error code: %s.",
424 __func__,
425 NRFX_LOG_ERROR_STRING_GET(err_code));
426 return err_code;
427 }
428
429 #if NRF_SPIM_HAS_32_MHZ_FREQ && defined(NRF5340_XXAA_APPLICATION)
430 // Check if dedicated SPIM pins are used, unless both GPIO configuration
431 // and pin selection are to be skipped (pin numbers may be not specified
432 // in such case).
433 if (!(p_config->skip_gpio_cfg && p_config->skip_psel_cfg) &&
434 (p_instance->p_reg == NRF_SPIM4) && (p_config->frequency == NRFX_MHZ_TO_HZ(32)))
435 {
436 enum {
437 SPIM_SCK_DEDICATED = NRF_GPIO_PIN_MAP(0, 8),
438 SPIM_MOSI_DEDICATED = NRF_GPIO_PIN_MAP(0, 9),
439 SPIM_MISO_DEDICATED = NRF_GPIO_PIN_MAP(0, 10),
440 SPIM_CSN_DEDICATED = NRF_GPIO_PIN_MAP(0, 11),
441 SPIM_DCX_DEDICATED = NRF_GPIO_PIN_MAP(0, 12),
442 };
443
444 if (!SPIM_DEDICATED_PIN_VALIDATE(p_config->sck_pin, SPIM_SCK_DEDICATED) ||
445 !SPIM_DEDICATED_PIN_VALIDATE(p_config->mosi_pin, SPIM_MOSI_DEDICATED) ||
446 !SPIM_DEDICATED_PIN_VALIDATE(p_config->miso_pin, SPIM_MISO_DEDICATED) ||
447 (p_config->use_hw_ss &&
448 !SPIM_DEDICATED_PIN_VALIDATE(p_config->ss_pin, SPIM_CSN_DEDICATED)) ||
449 !SPIM_DEDICATED_PIN_VALIDATE(p_config->dcx_pin, SPIM_DCX_DEDICATED))
450 {
451 err_code = NRFX_ERROR_INVALID_PARAM;
452 NRFX_LOG_WARNING("Function: %s, error code: %s.",
453 __func__,
454 NRFX_LOG_ERROR_STRING_GET(err_code));
455 return err_code;
456 }
457 }
458 #endif // NRF_SPIM_HAS_32_MHZ_FREQ && defined(NRF5340_XXAA_APPLICATION)
459
460 #else
461 (void)p_instance;
462 (void)p_config;
463 #endif // NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
464 return NRFX_SUCCESS;
465 }
466
spim_configure(nrfx_spim_t const * p_instance,nrfx_spim_config_t const * p_config)467 static void spim_configure(nrfx_spim_t const * p_instance,
468 nrfx_spim_config_t const * p_config)
469 {
470 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
471 bool hw_csn_supported = SPIM_HW_CSN_PRESENT_VALIDATE(p_instance->drv_inst_idx);
472 bool use_csn = hw_csn_supported && p_config->use_hw_ss;
473 #endif
474 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
475 uint8_t csn_duration = NRFX_COND_CODE_1(NRFX_SPIM_EXTENDED_ENABLED,
476 (use_csn ? p_config->ss_duration : NRF_SPIM_CSNDUR_DEFAULT),
477 (0));
478
479 #if NRF_SPIM_HAS_FREQUENCY
480 nrf_spim_frequency_t frequency = spim_frequency_bit_decode(p_config->frequency);
481 #elif NRF_SPIM_HAS_PRESCALER
482 uint32_t prescaler = spim_prescaler_calculate(p_instance, p_config->frequency);
483 #endif
484
485 #ifdef USE_WORKAROUND_FOR_ANOMALY_NRF54L_8_NRF54H_212
486 if (apply_errata_nrf54l_8_nrf54h_212())
487 {
488 /* Workaround must be applied only if PRESCALER is larger than 2 and CPHA=0 */
489 if ((prescaler > 2) &&
490 ((p_config->mode == NRF_SPIM_MODE_0) || (p_config->mode == NRF_SPIM_MODE_2)))
491 {
492 uint8_t min_dur = (uint8_t)((prescaler / 2) + 1);
493 csn_duration = NRFX_MAX(csn_duration, min_dur);
494 p_cb->apply_errata_8_212 = 1;
495 }
496 else
497 {
498 p_cb->apply_errata_8_212 = 0;
499 }
500 }
501 #else
502 (void)csn_duration;
503 #endif
504
505 p_cb->skip_gpio_cfg = p_config->skip_gpio_cfg;
506 configure_pins(p_instance, p_config);
507
508 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
509 if (use_csn)
510 {
511 p_cb->ss_pin = NRF_SPIM_PIN_NOT_CONNECTED;
512 }
513 else
514 #endif
515 {
516 p_cb->ss_pin = p_config->ss_pin;
517 p_cb->ss_active_high = p_config->ss_active_high;
518 }
519
520 nrfy_spim_config_t nrfy_config =
521 {
522 .pins =
523 {
524 .sck_pin = p_config->sck_pin,
525 .mosi_pin = p_config->mosi_pin,
526 .miso_pin = p_config->miso_pin
527 },
528 .orc = p_config->orc,
529 #if NRF_SPIM_HAS_FREQUENCY
530 .frequency = frequency,
531 #elif NRF_SPIM_HAS_PRESCALER
532 .prescaler = prescaler,
533 #endif
534 .mode = p_config->mode,
535 .bit_order = p_config->bit_order,
536 #if NRFY_SPIM_HAS_EXTENDED
537 /* Extended config is applied even if only single instance supports it.
538 For other instances, and also when NRFX_SPIM_EXTENDED_ENABLED is 0,
539 apply default configuration. */
540 .ext_config =
541 {
542 .pins =
543 {
544 #if NRFY_SPIM_HAS_DCX
545 .dcx_pin = NRFX_COND_CODE_1(NRFX_SPIM_EXTENDED_ENABLED,
546 (p_config->dcx_pin,),
547 (NRF_SPIM_DCX_DEFAULT,))
548 #endif
549 #if NRFY_SPIM_HAS_HW_CSN
550 .csn_pin = NRFX_COND_CODE_1(NRFX_SPIM_EXTENDED_ENABLED,
551 (use_csn ? p_config->ss_pin : NRF_SPIM_CSN_DEFAULT,),
552 (NRF_SPIM_CSN_DEFAULT,))
553 #endif
554 },
555 #if NRFY_SPIM_HAS_HW_CSN
556 .csn_pol = NRFX_COND_CODE_1(NRFX_SPIM_EXTENDED_ENABLED,
557 (use_csn ?
558 (p_config->ss_active_high ?
559 NRF_SPIM_CSN_POL_HIGH : NRF_SPIM_CSN_POL_LOW) :
560 (nrf_spim_csn_pol_t)NRF_SPIM_CSNPOL_DEFAULT,),
561 ((nrf_spim_csn_pol_t)NRF_SPIM_CSNPOL_DEFAULT,))
562 .csn_duration = csn_duration,
563 #endif
564 #if NRFY_SPIM_HAS_RXDELAY
565 .rx_delay = NRFX_COND_CODE_1(NRFX_SPIM_EXTENDED_ENABLED,
566 (SPIM_RXDELAY_PRESENT_VALIDATE(p_instance->drv_inst_idx) ?
567 p_config->rx_delay : NRF_SPIM_RXDELAY_DEFAULT,),
568 (NRF_SPIM_RXDELAY_DEFAULT,))
569 #endif
570 },
571 #endif // NRFY_SPIM_HAS_EXTENDED
572 .skip_psel_cfg = p_config->skip_psel_cfg
573 };
574
575 nrfy_spim_periph_configure(p_instance->p_reg, &nrfy_config);
576 if (m_cb[p_instance->drv_inst_idx].handler)
577 {
578 nrfy_spim_int_init(p_instance->p_reg, 0, p_config->irq_priority, false);
579 }
580 }
581
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)582 nrfx_err_t nrfx_spim_init(nrfx_spim_t const * p_instance,
583 nrfx_spim_config_t const * p_config,
584 nrfx_spim_evt_handler_t handler,
585 void * p_context)
586 {
587 NRFX_ASSERT(p_config);
588
589 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
590 nrfx_err_t err_code;
591
592 if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
593 {
594 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
595 err_code = NRFX_ERROR_ALREADY;
596 #else
597 err_code = NRFX_ERROR_INVALID_STATE;
598 #endif
599 NRFX_LOG_WARNING("Function: %s, error code: %s.",
600 __func__,
601 NRFX_LOG_ERROR_STRING_GET(err_code));
602 return err_code;
603 }
604
605 if (p_config)
606 {
607 err_code = spim_configuration_verify(p_instance, p_config);
608 if (err_code != NRFX_SUCCESS)
609 {
610 return err_code;
611 }
612 }
613
614 #if NRFX_CHECK(NRFX_PRS_ENABLED)
615 static nrfx_irq_handler_t const irq_handlers[NRFX_SPIM_ENABLED_COUNT] = {
616 NRFX_INSTANCE_IRQ_HANDLERS_LIST(SPIM, spim)
617 };
618 if (nrfx_prs_acquire(p_instance->p_reg, irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
619 {
620 err_code = NRFX_ERROR_BUSY;
621 NRFX_LOG_WARNING("Function: %s, error code: %s.",
622 __func__,
623 NRFX_LOG_ERROR_STRING_GET(err_code));
624 return err_code;
625 }
626 #endif // NRFX_CHECK(NRFX_PRS_ENABLED)
627
628 p_cb->handler = handler;
629 p_cb->p_context = p_context;
630
631 if (p_config)
632 {
633 spim_configure(p_instance, p_config);
634 }
635
636 p_cb->transfer_in_progress = false;
637 p_cb->state = NRFX_DRV_STATE_INITIALIZED;
638
639 err_code = NRFX_SUCCESS;
640 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
641 return err_code;
642 }
643
nrfx_spim_reconfigure(nrfx_spim_t const * p_instance,nrfx_spim_config_t const * p_config)644 nrfx_err_t nrfx_spim_reconfigure(nrfx_spim_t const * p_instance,
645 nrfx_spim_config_t const * p_config)
646 {
647 NRFX_ASSERT(p_config);
648
649 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
650
651 if (p_cb->state == NRFX_DRV_STATE_UNINITIALIZED)
652 {
653 return NRFX_ERROR_INVALID_STATE;
654 }
655 if (p_cb->transfer_in_progress)
656 {
657 return NRFX_ERROR_BUSY;
658 }
659 nrfx_err_t err_code = spim_configuration_verify(p_instance, p_config);
660 if (err_code != NRFX_SUCCESS)
661 {
662 return err_code;
663 }
664
665 spim_configure(p_instance, p_config);
666
667 return NRFX_SUCCESS;
668 }
669
spim_pin_uninit(uint32_t pin)670 static void spim_pin_uninit(uint32_t pin)
671 {
672 if (pin == NRF_SPIM_PIN_NOT_CONNECTED)
673 {
674 return;
675 }
676
677 nrfy_gpio_cfg_default(pin);
678 }
679
nrfx_spim_uninit(nrfx_spim_t const * p_instance)680 void nrfx_spim_uninit(nrfx_spim_t const * p_instance)
681 {
682 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
683
684 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
685
686 nrfy_spim_int_uninit(p_instance->p_reg);
687 if (p_cb->handler)
688 {
689 nrfy_spim_int_disable(p_instance->p_reg, NRF_SPIM_ALL_INTS_MASK);
690 spim_abort(p_instance->p_reg, p_cb);
691 }
692
693 nrfy_spim_pins_t pins;
694 nrfy_spim_pins_get(p_instance->p_reg, &pins);
695
696 if (!p_cb->skip_gpio_cfg)
697 {
698 spim_pin_uninit(pins.sck_pin);
699 spim_pin_uninit(pins.miso_pin);
700 spim_pin_uninit(pins.mosi_pin);
701 spim_pin_uninit(p_cb->ss_pin);
702 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
703 if (SPIM_DCX_PRESENT_VALIDATE(p_instance->drv_inst_idx) &&
704 SPIM_HW_CSN_PRESENT_VALIDATE(p_instance->drv_inst_idx))
705 {
706 nrfy_spim_ext_pins_t ext_pins;
707 nrfy_spim_ext_pins_get(p_instance->p_reg, &ext_pins);
708 #if NRFY_SPIM_HAS_DCX
709 spim_pin_uninit(ext_pins.dcx_pin);
710 #endif
711 #if NRFY_SPIM_HAS_HW_CSN
712 spim_pin_uninit(ext_pins.csn_pin);
713 #endif
714 }
715 #endif
716 }
717
718 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_195)
719 if (p_instance->p_reg == NRF_SPIM3)
720 {
721 *(volatile uint32_t *)0x4002F004 = 1;
722 }
723 #endif
724
725 #if NRFX_CHECK(NRFX_PRS_ENABLED)
726 nrfx_prs_release(p_instance->p_reg);
727 #endif
728
729 p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
730 NRFX_LOG_INFO("Uninitialized.");
731 }
732
nrfx_spim_init_check(nrfx_spim_t const * p_instance)733 bool nrfx_spim_init_check(nrfx_spim_t const * p_instance)
734 {
735 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
736
737 return (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
738 }
739
740 #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)741 nrfx_err_t nrfx_spim_xfer_dcx(nrfx_spim_t const * p_instance,
742 nrfx_spim_xfer_desc_t const * p_xfer_desc,
743 uint32_t flags,
744 uint8_t cmd_length)
745 {
746 (void)flags;
747
748 NRFX_ASSERT(cmd_length <= NRF_SPIM_DCX_CNT_ALL_CMD);
749
750 nrfy_spim_dcx_cnt_set((NRF_SPIM_Type *)p_instance->p_reg, cmd_length);
751 return nrfx_spim_xfer(p_instance, p_xfer_desc, 0);
752 }
753 #endif
754
set_ss_pin_state(spim_control_block_t * p_cb,bool active)755 static void set_ss_pin_state(spim_control_block_t * p_cb, bool active)
756 {
757 if (p_cb->ss_pin != NRF_SPIM_PIN_NOT_CONNECTED)
758 {
759 if (p_cb->ss_active_high)
760 {
761 if (active)
762 {
763 nrfy_gpio_pin_set(p_cb->ss_pin);
764 }
765 else
766 {
767 nrfy_gpio_pin_clear(p_cb->ss_pin);
768 }
769 }
770 else
771 {
772 if (active)
773 {
774 nrfy_gpio_pin_clear(p_cb->ss_pin);
775 }
776 else
777 {
778 nrfy_gpio_pin_set(p_cb->ss_pin);
779 }
780 }
781 }
782 }
783
finish_transfer(NRF_SPIM_Type * p_spim,spim_control_block_t * p_cb)784 static void finish_transfer(NRF_SPIM_Type * p_spim, spim_control_block_t * p_cb)
785 {
786 // If Slave Select signal is used, this is the time to deactivate it.
787 set_ss_pin_state(p_cb, false);
788
789 // By clearing this flag before calling the handler we allow subsequent
790 // transfers to be started directly from the handler function.
791 if (p_cb->transfer_in_progress)
792 {
793 spim_abort(p_spim, p_cb);
794 }
795
796 p_cb->evt.type = NRFX_SPIM_EVENT_DONE;
797 p_cb->handler(&p_cb->evt, p_cb->p_context);
798 }
799
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)800 static nrfx_err_t spim_xfer(NRF_SPIM_Type * p_spim,
801 spim_control_block_t * p_cb,
802 nrfx_spim_xfer_desc_t const * p_xfer_desc,
803 uint32_t flags)
804 {
805 nrfx_err_t err_code;
806 // EasyDMA requires that transfer buffers are placed in Data RAM region;
807 // signal error if they are not.
808 if ((p_xfer_desc->p_tx_buffer != NULL &&
809 !nrf_dma_accessible_check(p_spim, p_xfer_desc->p_tx_buffer)) ||
810 (p_xfer_desc->p_rx_buffer != NULL &&
811 !nrf_dma_accessible_check(p_spim, p_xfer_desc->p_rx_buffer)))
812 {
813 p_cb->transfer_in_progress = false;
814 err_code = NRFX_ERROR_INVALID_ADDR;
815 NRFX_LOG_WARNING("Function: %s, error code: %s.",
816 __func__,
817 NRFX_LOG_ERROR_STRING_GET(err_code));
818 return err_code;
819 }
820
821 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
822 if (p_spim == NRF_SPIM3)
823 {
824 anomaly_198_enable(p_xfer_desc->p_tx_buffer, p_xfer_desc->tx_length);
825 }
826 #endif
827
828 #if NRFY_SPIM_HAS_ARRAY_LIST
829 nrfy_spim_tx_list_set(p_spim, NRFX_SPIM_FLAG_TX_POSTINC & flags);
830 nrfy_spim_rx_list_set(p_spim, NRFX_SPIM_FLAG_RX_POSTINC & flags);
831 #endif
832
833 nrfy_spim_xfer_desc_t xfer_desc = *p_xfer_desc;
834 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
835 if (flags & NRFX_SPIM_FLAG_HOLD_XFER)
836 {
837 nrfy_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED);
838 xfer_desc.tx_length = 0;
839 xfer_desc.rx_length = 0;
840 nrfy_spim_int_enable(p_spim, NRF_SPIM_INT_STARTED_MASK);
841 }
842 #endif
843 nrfy_spim_buffers_set(p_spim, &xfer_desc);
844
845 nrfy_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
846 #if defined(HALTIUM_XXAA)
847 p_cb->disable_on_xfer_end = (flags & (NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER |
848 NRFX_SPIM_FLAG_HOLD_XFER |
849 NRFX_SPIM_FLAG_REPEATED_XFER)) ?
850 true : !nrfy_spim_enable_check(p_spim);
851 #endif
852 nrfy_spim_enable(p_spim);
853 #ifdef USE_WORKAROUND_FOR_ANOMALY_NRF54L_8_NRF54H_212
854 if (apply_errata_nrf54l_8_nrf54h_212() && p_cb->apply_errata_8_212)
855 {
856 *(volatile uint32_t *)((uintptr_t)p_spim + 0xc84) = 0x82;
857 if (p_cb->handler)
858 {
859 nrfy_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED);
860 nrfy_spim_int_enable(p_spim, NRF_SPIM_INT_STARTED_MASK);
861 }
862 }
863 #endif
864
865 if (!(flags & NRFX_SPIM_FLAG_HOLD_XFER))
866 {
867 nrfy_spim_xfer_start(p_spim, p_cb->handler ? NULL : &xfer_desc);
868 }
869
870 if (!p_cb->handler)
871 {
872 #ifdef USE_WORKAROUND_FOR_ANOMALY_NRF54L_8_NRF54H_212
873 if (apply_errata_nrf54l_8_nrf54h_212() && p_cb->apply_errata_8_212)
874 {
875 *(volatile uint32_t *)((uintptr_t)p_spim + 0xc84) = 0;
876 }
877 #endif
878
879 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
880 if (p_spim == NRF_SPIM3)
881 {
882 anomaly_198_disable();
883 }
884 #endif
885 set_ss_pin_state(p_cb, false);
886 if (!(flags & NRFX_SPIM_FLAG_HOLD_XFER))
887 {
888 spim_abort(p_spim, p_cb);
889 }
890 }
891 else
892 {
893 if (flags & NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER)
894 {
895 nrfy_spim_int_disable(p_spim, NRF_SPIM_INT_END_MASK);
896 }
897 else
898 {
899 nrfy_spim_int_enable(p_spim, NRF_SPIM_INT_END_MASK);
900 }
901 }
902 err_code = NRFX_SUCCESS;
903 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
904 return err_code;
905 }
906
nrfx_spim_xfer(nrfx_spim_t const * p_instance,nrfx_spim_xfer_desc_t const * p_xfer_desc,uint32_t flags)907 nrfx_err_t nrfx_spim_xfer(nrfx_spim_t const * p_instance,
908 nrfx_spim_xfer_desc_t const * p_xfer_desc,
909 uint32_t flags)
910 {
911 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
912
913 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
914 NRFX_ASSERT(p_xfer_desc->p_tx_buffer != NULL || p_xfer_desc->tx_length == 0);
915 NRFX_ASSERT(p_xfer_desc->p_rx_buffer != NULL || p_xfer_desc->rx_length == 0);
916 NRFX_ASSERT(SPIM_LENGTH_VALIDATE(p_instance->drv_inst_idx,
917 p_xfer_desc->rx_length,
918 p_xfer_desc->tx_length));
919 NRFX_ASSERT(!(flags & NRFX_SPIM_FLAG_HOLD_XFER) ||
920 (p_cb->ss_pin == NRF_SPIM_PIN_NOT_CONNECTED));
921
922 nrfx_err_t err_code = NRFX_SUCCESS;
923
924 #if !NRFY_SPIM_HAS_ARRAY_LIST
925 if ((NRFX_SPIM_FLAG_TX_POSTINC | NRFX_SPIM_FLAG_RX_POSTINC) & flags)
926 {
927 err_code = NRFX_ERROR_NOT_SUPPORTED;
928 NRFX_LOG_WARNING("Function: %s, error code: %s.",
929 __func__,
930 NRFX_LOG_ERROR_STRING_GET(err_code));
931 return err_code;
932 }
933 #endif
934
935 if (p_cb->transfer_in_progress)
936 {
937 err_code = NRFX_ERROR_BUSY;
938 NRFX_LOG_WARNING("Function: %s, error code: %s.",
939 __func__,
940 NRFX_LOG_ERROR_STRING_GET(err_code));
941 return err_code;
942 }
943 else
944 {
945 if (p_cb->handler && !(flags & (NRFX_SPIM_FLAG_REPEATED_XFER |
946 NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER)))
947 {
948 p_cb->transfer_in_progress = true;
949 }
950 }
951
952 p_cb->evt.xfer_desc = *p_xfer_desc;
953
954 set_ss_pin_state(p_cb, true);
955
956 return spim_xfer(p_instance->p_reg, p_cb, p_xfer_desc, flags);
957 }
958
nrfx_spim_abort(nrfx_spim_t const * p_instance)959 void nrfx_spim_abort(nrfx_spim_t const * p_instance)
960 {
961 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
962
963 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
964
965 spim_abort(p_instance->p_reg, p_cb);
966 }
967
irq_handler(NRF_SPIM_Type * p_spim,spim_control_block_t * p_cb)968 static void irq_handler(NRF_SPIM_Type * p_spim, spim_control_block_t * p_cb)
969 {
970 #ifdef USE_WORKAROUND_FOR_ANOMALY_NRF54L_8_NRF54H_212
971 if (apply_errata_nrf54l_8_nrf54h_212() && p_cb->apply_errata_8_212)
972 {
973 if (nrfy_spim_int_enable_check(p_spim, NRF_SPIM_INT_STARTED_MASK) &&
974 nrfy_spim_event_check(p_spim, NRF_SPIM_EVENT_STARTED))
975 {
976 nrfy_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED);
977 *(volatile uint32_t *)((uintptr_t)p_spim + 0xc84) = 0;
978 nrfy_spim_int_disable(p_spim, NRF_SPIM_INT_STARTED_MASK);
979 }
980 }
981 #endif
982
983 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
984 if (nrfy_spim_int_enable_check(p_spim, NRF_SPIM_INT_STARTED_MASK) &&
985 nrfy_spim_event_check(p_spim, NRF_SPIM_EVENT_STARTED))
986 {
987 /* Handle first, zero-length, auxiliary transmission. */
988 nrfy_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED);
989 nrfy_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
990
991 NRFX_ASSERT(nrfy_spim_tx_maxcnt_get(p_spim) == 0);
992 NRFX_ASSERT(nrfy_spim_rx_maxcnt_get(p_spim) == 0);
993
994 /* Disable STARTED interrupt, used only in auxiliary transmission. */
995 nrfy_spim_int_disable(p_spim, NRF_SPIM_INT_STARTED_MASK);
996
997 /* Start the actual, glitch-free transmission. */
998 nrfy_spim_buffers_set(p_spim, &p_cb->evt.xfer_desc);
999 nrfy_spim_xfer_start(p_spim, NULL);
1000 return;
1001 }
1002 #endif
1003
1004 if (nrfy_spim_events_process(p_spim,
1005 NRFY_EVENT_TO_INT_BITMASK(NRF_SPIM_EVENT_END),
1006 &p_cb->evt.xfer_desc))
1007 {
1008 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
1009 if (p_spim == NRF_SPIM3)
1010 {
1011 anomaly_198_disable();
1012 }
1013 #endif
1014 NRFX_ASSERT(p_cb->handler);
1015 NRFX_LOG_DEBUG("Event: NRF_SPIM_EVENT_END.");
1016 finish_transfer(p_spim, p_cb);
1017 }
1018 }
1019
1020 NRFX_INSTANCE_IRQ_HANDLERS(SPIM, spim)
1021
1022 #endif // NRFX_CHECK(NRFX_SPIM_ENABLED)
1023