1 /*
2 * Copyright (c) 2015 - 2023, 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 dcx_support_mask =
112 NRFX_FEATURE_SUPPORTED_MASK(SPIM, FEATURE_DCX_PRESENT);
113 static const uint32_t hw_csn_support_mask =
114 NRFX_FEATURE_SUPPORTED_MASK(SPIM, FEATURE_HARDWARE_CSN_PRESENT);
115 static const uint32_t datarate32_support_mask =
116 NRFX_NUM_FEATURE_SUPPORTED_MASK(SPIM, MAX_DATARATE);
117 #endif
118
119 static const uint8_t easydma_support_bits[] __UNUSED =
120 NRFX_FEATURE_ARRAY_INITIALIZE(SPIM, EASYDMA_MAXCNT_SIZE);
121
122 #define SPIM_SUPPORTED_FREQ_VALIDATE(drv_inst_idx, freq) \
123 (((freq != NRFX_MHZ_TO_HZ(32)) && (freq != NRFX_MHZ_TO_HZ(16))) || \
124 ((NRFX_BIT(drv_inst_idx)) & datarate32_support_mask))
125
126 #define SPIM_DCX_PRESENT_VALIDATE(drv_inst_idx) (NRFX_BIT(drv_inst_idx) & dcx_support_mask)
127
128 #define SPIM_HW_CSN_PRESENT_VALIDATE(drv_inst_idx) (NRFX_BIT(drv_inst_idx) & hw_csn_support_mask)
129
130 #define SPIM_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) \
131 ((rx_len < NRFX_BIT(easydma_support_bits[drv_inst_idx])) && \
132 (tx_len < NRFX_BIT(easydma_support_bits[drv_inst_idx])))
133
134 // Requested pin can either match dedicated pin or be not connected at all.
135 #define SPIM_DEDICATED_PIN_VALIDATE(requested_pin, supported_pin) \
136 (((requested_pin) == NRF_SPIM_PIN_NOT_CONNECTED) || ((requested_pin) == (supported_pin)))
137
138 #if !defined(USE_WORKAROUND_FOR_ANOMALY_195) && \
139 defined(NRF52840_XXAA) && NRFX_CHECK(NRFX_SPIM3_ENABLED)
140 // Enable workaround for nRF52840 anomaly 195 (SPIM3 continues to draw current after disable).
141 #define USE_WORKAROUND_FOR_ANOMALY_195 1
142 #endif
143
144 // Control block - driver instance local data.
145 typedef struct
146 {
147 nrfx_spim_evt_handler_t handler;
148 void * p_context;
149 nrfx_spim_evt_t evt; // Keep the struct that is ready for event handler. Less memcpy.
150 nrfx_drv_state_t state;
151 volatile bool transfer_in_progress;
152 bool skip_gpio_cfg : 1;
153 bool ss_active_high;
154 uint32_t ss_pin;
155 } spim_control_block_t;
156 static spim_control_block_t m_cb[NRFX_SPIM_ENABLED_COUNT];
157
158 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
159
160 // Workaround for nRF52840 anomaly 198: SPIM3 transmit data might be corrupted.
161
162 static uint32_t m_anomaly_198_preserved_value;
163
anomaly_198_enable(uint8_t const * p_buffer,size_t buf_len)164 static void anomaly_198_enable(uint8_t const * p_buffer, size_t buf_len)
165 {
166 m_anomaly_198_preserved_value = *((volatile uint32_t *)0x40000E00);
167
168 if (buf_len == 0)
169 {
170 return;
171 }
172 uint32_t buffer_end_addr = ((uint32_t)p_buffer) + buf_len;
173 uint32_t block_addr = ((uint32_t)p_buffer) & ~0x1FFF;
174 uint32_t block_flag = (1UL << ((block_addr >> 13) & 0xFFFF));
175 uint32_t occupied_blocks = 0;
176
177 if (block_addr >= 0x20010000)
178 {
179 occupied_blocks = (1UL << 8);
180 }
181 else
182 {
183 do {
184 occupied_blocks |= block_flag;
185 block_flag <<= 1;
186 block_addr += 0x2000;
187 } while ((block_addr < buffer_end_addr) && (block_addr < 0x20012000));
188 }
189
190 *((volatile uint32_t *)0x40000E00) = occupied_blocks;
191 }
192
anomaly_198_disable(void)193 static void anomaly_198_disable(void)
194 {
195 *((volatile uint32_t *)0x40000E00) = m_anomaly_198_preserved_value;
196 }
197 #endif // NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
198
spim_abort(NRF_SPIM_Type * p_spim,spim_control_block_t * p_cb)199 static void spim_abort(NRF_SPIM_Type * p_spim, spim_control_block_t * p_cb)
200 {
201 nrfy_spim_abort(p_spim, NULL);
202 bool stopped;
203 uint32_t stopped_mask = NRFY_EVENT_TO_INT_BITMASK(NRF_SPIM_EVENT_STOPPED);
204 NRFX_WAIT_FOR(nrfy_spim_events_process(p_spim, stopped_mask, NULL), 100, 1, stopped);
205 if (!stopped)
206 {
207 NRFX_LOG_ERROR("Failed to stop instance with base address: %p.", (void *)p_spim);
208 }
209 p_cb->transfer_in_progress = false;
210 nrfy_spim_disable(p_spim);
211 }
212
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)213 static void pin_init(uint32_t pin,
214 nrf_gpio_pin_dir_t dir,
215 nrf_gpio_pin_pull_t pull,
216 nrf_gpio_pin_drive_t drive,
217 uint32_t initial_state)
218 {
219 nrf_gpio_pin_input_t input;
220
221 if (pin == NRF_SPIM_PIN_NOT_CONNECTED)
222 {
223 return;
224 }
225
226 if (dir == NRF_GPIO_PIN_DIR_OUTPUT)
227 {
228 if (initial_state)
229 {
230 nrfy_gpio_pin_set(pin);
231 }
232 else
233 {
234 nrfy_gpio_pin_clear(pin);
235 }
236 input = NRF_GPIO_PIN_INPUT_DISCONNECT;
237 }
238 else
239 {
240 input = NRF_GPIO_PIN_INPUT_CONNECT;
241 }
242
243 nrfy_gpio_cfg(pin, dir, input, pull, drive, NRF_GPIO_PIN_NOSENSE);
244 }
245
configure_pins(nrfx_spim_t const * p_instance,nrfx_spim_config_t const * p_config)246 static void configure_pins(nrfx_spim_t const * p_instance,
247 nrfx_spim_config_t const * p_config)
248 {
249 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
250
251 p_cb->ss_active_high = p_config->ss_active_high;
252
253 if (p_config->skip_gpio_cfg)
254 {
255 return;
256 }
257
258 nrf_gpio_pin_drive_t pin_drive;
259 // Configure pin drive - high drive for 32 MHz clock frequency.
260 #if (NRF_SPIM_HAS_FREQUENCY && NRF_SPIM_HAS_32_MHZ_FREQ) || NRF_SPIM_HAS_PRESCALER
261 pin_drive = (p_config->frequency == NRFX_MHZ_TO_HZ(32)) ? NRF_GPIO_PIN_H0H1 : NRF_GPIO_PIN_S0S1;
262 #else
263 pin_drive = NRF_GPIO_PIN_S0S1;
264 #endif
265 // Configure pins used by the peripheral:
266 // - SCK - output with initial value corresponding with the SPI mode used:
267 // 0 - for modes 0 and 1 (CPOL = 0), 1 - for modes 2 and 3 (CPOL = 1);
268 // according to the reference manual guidelines this pin and its input
269 // buffer must always be connected for the SPI to work.
270 uint32_t sck_val = (p_config->mode <= NRF_SPIM_MODE_1) ? 0 : 1;
271 pin_init(p_config->sck_pin, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_NOPULL, pin_drive, sck_val);
272 #if NRF_GPIO_HAS_CLOCKPIN && defined(NRF_SPIM_CLOCKPIN_SCK_NEEDED)
273 nrfy_gpio_pin_clock_set(p_config->sck_pin, true);
274 #endif
275 // - MOSI (optional) - output with initial value 0
276 pin_init(p_config->mosi_pin, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_NOPULL, pin_drive, 0);
277 #if NRF_GPIO_HAS_CLOCKPIN && defined(NRF_SPIM_CLOCKPIN_MOSI_NEEDED)
278 nrfy_gpio_pin_clock_set(p_config->mosi_pin, true);
279 #endif
280 // - MISO (optional) - input
281 pin_init(p_config->miso_pin, NRF_GPIO_PIN_DIR_INPUT, p_config->miso_pull, pin_drive, 0);
282 // - Slave Select (optional) - output with initial value 1 (inactive).
283 uint32_t ss_val = !p_config->ss_active_high;
284 pin_init(p_config->ss_pin, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_NOPULL, pin_drive, ss_val);
285 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
286 // - DCX (optional) - output.
287 pin_init(p_config->dcx_pin, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_NOPULL, pin_drive, 1);
288 #endif
289 }
290
291 #if NRF_SPIM_HAS_FREQUENCY
spim_frequency_valid_check(nrfx_spim_t const * p_instance,uint32_t frequency)292 static bool spim_frequency_valid_check(nrfx_spim_t const * p_instance, uint32_t frequency)
293 {
294 (void)p_instance;
295 switch (frequency)
296 {
297 case NRFX_KHZ_TO_HZ(125):
298 /* FALLTHROUGH */
299 case NRFX_KHZ_TO_HZ(250):
300 /* FALLTHROUGH */
301 case NRFX_KHZ_TO_HZ(500):
302 /* FALLTHROUGH */
303 case NRFX_MHZ_TO_HZ(1):
304 /* FALLTHROUGH */
305 case NRFX_MHZ_TO_HZ(2):
306 /* FALLTHROUGH */
307 case NRFX_MHZ_TO_HZ(4):
308 /* FALLTHROUGH */
309 case NRFX_MHZ_TO_HZ(8):
310 return true;
311 #if NRF_SPIM_HAS_16_MHZ_FREQ
312 case NRFX_MHZ_TO_HZ(16):
313 return true;
314 #endif
315 #if NRF_SPIM_HAS_32_MHZ_FREQ
316 case NRFX_MHZ_TO_HZ(32):
317 return true;
318 #endif
319 default:
320 return false;
321 }
322 }
323
spim_frequency_bit_decode(uint32_t frequency)324 static nrf_spim_frequency_t spim_frequency_bit_decode(uint32_t frequency)
325 {
326 switch (frequency)
327 {
328 case NRFX_KHZ_TO_HZ(125):
329 return NRF_SPIM_FREQ_125K;
330 case NRFX_KHZ_TO_HZ(250):
331 return NRF_SPIM_FREQ_250K;
332 case NRFX_KHZ_TO_HZ(500):
333 return NRF_SPIM_FREQ_500K;
334 case NRFX_MHZ_TO_HZ(1):
335 return NRF_SPIM_FREQ_1M;
336 case NRFX_MHZ_TO_HZ(2):
337 return NRF_SPIM_FREQ_2M;
338 case NRFX_MHZ_TO_HZ(4):
339 return NRF_SPIM_FREQ_4M;
340 case NRFX_MHZ_TO_HZ(8):
341 return NRF_SPIM_FREQ_8M;
342 #if NRF_SPIM_HAS_16_MHZ_FREQ
343 case NRFX_MHZ_TO_HZ(16):
344 return NRF_SPIM_FREQ_16M;
345 #endif
346 #if NRF_SPIM_HAS_32_MHZ_FREQ
347 case NRFX_MHZ_TO_HZ(32):
348 return NRF_SPIM_FREQ_32M;
349 #endif
350 default:
351 NRFX_ASSERT(false);
352 return NRF_SPIM_FREQ_4M;
353 }
354 }
355 #elif NRF_SPIM_HAS_PRESCALER
spim_frequency_valid_check(nrfx_spim_t const * p_instance,uint32_t frequency)356 static bool spim_frequency_valid_check(nrfx_spim_t const * p_instance, uint32_t frequency)
357 {
358 uint32_t base_frequency = NRFX_SPIM_BASE_FREQUENCY_GET(p_instance);
359 uint32_t prescaler = NRF_SPIM_PRESCALER_CALCULATE(p_instance->p_reg, frequency);
360
361 return ((base_frequency % frequency) < prescaler) &&
362 NRFX_IS_EVEN(prescaler) &&
363 (prescaler <= NRF_SPIM_PRESCALER_MAX_GET(p_instance->p_reg)) &&
364 (prescaler >= NRF_SPIM_PRESCALER_MIN_GET(p_instance->p_reg));
365 }
366
spim_prescaler_calculate(nrfx_spim_t const * p_instance,uint32_t frequency)367 static uint32_t spim_prescaler_calculate(nrfx_spim_t const * p_instance, uint32_t frequency)
368 {
369 return NRF_SPIM_PRESCALER_CALCULATE(p_instance->p_reg, frequency);
370 }
371 #else
372 #error "Unable to determine frequency division support type."
373 #endif
374
spim_configuration_verify(nrfx_spim_t const * p_instance,nrfx_spim_config_t const * p_config)375 static nrfx_err_t spim_configuration_verify(nrfx_spim_t const * p_instance,
376 nrfx_spim_config_t const * p_config)
377 {
378 nrfx_err_t err_code;
379 if (!spim_frequency_valid_check(p_instance, p_config->frequency))
380 {
381 err_code = NRFX_ERROR_INVALID_PARAM;
382 NRFX_LOG_WARNING("Function: %s, error code: %s.",
383 __func__,
384 NRFX_LOG_ERROR_STRING_GET(err_code));
385 return err_code;
386 }
387
388 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
389 // Check if SPIM instance supports the extended features.
390 if (!SPIM_SUPPORTED_FREQ_VALIDATE(p_instance->drv_inst_idx, p_config->frequency) ||
391 (p_config->use_hw_ss && (p_config->ss_pin != NRF_SPIM_PIN_NOT_CONNECTED) &&
392 !SPIM_HW_CSN_PRESENT_VALIDATE(p_instance->drv_inst_idx)) ||
393 ((p_config->dcx_pin != NRF_SPIM_PIN_NOT_CONNECTED) &&
394 !SPIM_DCX_PRESENT_VALIDATE(p_instance->drv_inst_idx)))
395 {
396 err_code = NRFX_ERROR_NOT_SUPPORTED;
397 NRFX_LOG_WARNING("Function: %s, error code: %s.",
398 __func__,
399 NRFX_LOG_ERROR_STRING_GET(err_code));
400 return err_code;
401 }
402
403 #if NRF_SPIM_HAS_32_MHZ_FREQ && defined(NRF5340_XXAA_APPLICATION)
404 // Check if dedicated SPIM pins are used, unless both GPIO configuration
405 // and pin selection are to be skipped (pin numbers may be not specified
406 // in such case).
407 if (!(p_config->skip_gpio_cfg && p_config->skip_psel_cfg) &&
408 (p_instance->p_reg == NRF_SPIM4) && (p_config->frequency == NRFX_MHZ_TO_HZ(32)))
409 {
410 enum {
411 SPIM_SCK_DEDICATED = NRF_GPIO_PIN_MAP(0, 8),
412 SPIM_MOSI_DEDICATED = NRF_GPIO_PIN_MAP(0, 9),
413 SPIM_MISO_DEDICATED = NRF_GPIO_PIN_MAP(0, 10),
414 SPIM_CSN_DEDICATED = NRF_GPIO_PIN_MAP(0, 11),
415 SPIM_DCX_DEDICATED = NRF_GPIO_PIN_MAP(0, 12),
416 };
417
418 if (!SPIM_DEDICATED_PIN_VALIDATE(p_config->sck_pin, SPIM_SCK_DEDICATED) ||
419 !SPIM_DEDICATED_PIN_VALIDATE(p_config->mosi_pin, SPIM_MOSI_DEDICATED) ||
420 !SPIM_DEDICATED_PIN_VALIDATE(p_config->miso_pin, SPIM_MISO_DEDICATED) ||
421 (p_config->use_hw_ss &&
422 !SPIM_DEDICATED_PIN_VALIDATE(p_config->ss_pin, SPIM_CSN_DEDICATED)) ||
423 !SPIM_DEDICATED_PIN_VALIDATE(p_config->dcx_pin, SPIM_DCX_DEDICATED))
424 {
425 err_code = NRFX_ERROR_INVALID_PARAM;
426 NRFX_LOG_WARNING("Function: %s, error code: %s.",
427 __func__,
428 NRFX_LOG_ERROR_STRING_GET(err_code));
429 return err_code;
430 }
431 }
432 #endif // NRF_SPIM_HAS_32_MHZ_FREQ && defined(NRF5340_XXAA_APPLICATION)
433
434 #else
435 (void)p_instance;
436 (void)p_config;
437 #endif // NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
438 return NRFX_SUCCESS;
439 }
440
spim_configure(nrfx_spim_t const * p_instance,nrfx_spim_config_t const * p_config)441 static void spim_configure(nrfx_spim_t const * p_instance,
442 nrfx_spim_config_t const * p_config)
443 {
444 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
445
446 #if NRF_SPIM_HAS_FREQUENCY
447 nrf_spim_frequency_t frequency = spim_frequency_bit_decode(p_config->frequency);
448 #elif NRF_SPIM_HAS_PRESCALER
449 uint32_t prescaler = spim_prescaler_calculate(p_instance, p_config->frequency);
450 #endif
451
452 p_cb->skip_gpio_cfg = p_config->skip_gpio_cfg;
453 configure_pins(p_instance, p_config);
454
455 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
456 bool ext_support = NRFX_BIT(p_instance->drv_inst_idx) & hw_csn_support_mask;
457 bool hw_csn = p_config->use_hw_ss;
458 if (ext_support && hw_csn)
459 {
460 p_cb->ss_pin = NRF_SPIM_PIN_NOT_CONNECTED;
461 }
462 else
463 #endif
464 {
465 p_cb->ss_pin = p_config->ss_pin;
466 p_cb->ss_active_high = p_config->ss_active_high;
467 }
468
469 nrfy_spim_config_t nrfy_config =
470 {
471 .pins =
472 {
473 .sck_pin = p_config->sck_pin,
474 .mosi_pin = p_config->mosi_pin,
475 .miso_pin = p_config->miso_pin
476 },
477 .orc = p_config->orc,
478 #if NRF_SPIM_HAS_FREQUENCY
479 .frequency = frequency,
480 #elif NRF_SPIM_HAS_PRESCALER
481 .prescaler = prescaler,
482 #endif
483 .mode = p_config->mode,
484 .bit_order = p_config->bit_order,
485 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
486 .ext_config =
487 {
488 .pins =
489 {
490 .dcx_pin = p_config->dcx_pin,
491 .csn_pin = p_config->use_hw_ss ? p_config->ss_pin : NRF_SPIM_PIN_NOT_CONNECTED
492 },
493 .csn_pol = p_config->ss_active_high ? NRF_SPIM_CSN_POL_HIGH : NRF_SPIM_CSN_POL_LOW,
494 .csn_duration = p_config->ss_duration,
495 .rx_delay = p_config->rx_delay
496 },
497 .ext_enable = ext_support && (hw_csn || (p_config->dcx_pin != NRF_SPIM_PIN_NOT_CONNECTED)),
498 #endif // NRFX_SPIM_EXTENDED_ENABLED
499 .skip_psel_cfg = p_config->skip_psel_cfg
500 };
501
502 nrfy_spim_periph_configure(p_instance->p_reg, &nrfy_config);
503 if (m_cb[p_instance->drv_inst_idx].handler)
504 {
505 nrfy_spim_int_init(p_instance->p_reg, 0, p_config->irq_priority, false);
506 }
507 }
508
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)509 nrfx_err_t nrfx_spim_init(nrfx_spim_t const * p_instance,
510 nrfx_spim_config_t const * p_config,
511 nrfx_spim_evt_handler_t handler,
512 void * p_context)
513 {
514 NRFX_ASSERT(p_config);
515
516 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
517 nrfx_err_t err_code;
518
519 if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
520 {
521 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
522 err_code = NRFX_ERROR_ALREADY;
523 #else
524 err_code = NRFX_ERROR_INVALID_STATE;
525 #endif
526 NRFX_LOG_WARNING("Function: %s, error code: %s.",
527 __func__,
528 NRFX_LOG_ERROR_STRING_GET(err_code));
529 return err_code;
530 }
531
532 if (p_config)
533 {
534 err_code = spim_configuration_verify(p_instance, p_config);
535 if (err_code != NRFX_SUCCESS)
536 {
537 return err_code;
538 }
539 }
540
541 #if NRFX_CHECK(NRFX_PRS_ENABLED)
542 static nrfx_irq_handler_t const irq_handlers[NRFX_SPIM_ENABLED_COUNT] = {
543 NRFX_INSTANCE_IRQ_HANDLERS_LIST(SPIM, spim)
544 };
545 if (nrfx_prs_acquire(p_instance->p_reg, irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
546 {
547 err_code = NRFX_ERROR_BUSY;
548 NRFX_LOG_WARNING("Function: %s, error code: %s.",
549 __func__,
550 NRFX_LOG_ERROR_STRING_GET(err_code));
551 return err_code;
552 }
553 #endif // NRFX_CHECK(NRFX_PRS_ENABLED)
554
555 p_cb->handler = handler;
556 p_cb->p_context = p_context;
557
558 if (p_config)
559 {
560 spim_configure(p_instance, p_config);
561 }
562
563 p_cb->transfer_in_progress = false;
564 p_cb->state = NRFX_DRV_STATE_INITIALIZED;
565
566 err_code = NRFX_SUCCESS;
567 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
568 return err_code;
569 }
570
nrfx_spim_reconfigure(nrfx_spim_t const * p_instance,nrfx_spim_config_t const * p_config)571 nrfx_err_t nrfx_spim_reconfigure(nrfx_spim_t const * p_instance,
572 nrfx_spim_config_t const * p_config)
573 {
574 NRFX_ASSERT(p_config);
575
576 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
577
578 if (p_cb->state == NRFX_DRV_STATE_UNINITIALIZED)
579 {
580 return NRFX_ERROR_INVALID_STATE;
581 }
582 if (p_cb->transfer_in_progress)
583 {
584 return NRFX_ERROR_BUSY;
585 }
586 nrfx_err_t err_code = spim_configuration_verify(p_instance, p_config);
587 if (err_code != NRFX_SUCCESS)
588 {
589 return err_code;
590 }
591
592 spim_configure(p_instance, p_config);
593
594 return NRFX_SUCCESS;
595 }
596
spim_pin_uninit(uint32_t pin)597 static void spim_pin_uninit(uint32_t pin)
598 {
599 if (pin == NRF_SPIM_PIN_NOT_CONNECTED)
600 {
601 return;
602 }
603
604 nrfy_gpio_cfg_default(pin);
605 }
606
nrfx_spim_uninit(nrfx_spim_t const * p_instance)607 void nrfx_spim_uninit(nrfx_spim_t const * p_instance)
608 {
609 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
610
611 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
612
613 nrfy_spim_int_uninit(p_instance->p_reg);
614 if (p_cb->handler)
615 {
616 nrfy_spim_int_disable(p_instance->p_reg, NRF_SPIM_ALL_INTS_MASK);
617 spim_abort(p_instance->p_reg, p_cb);
618 }
619
620 nrfy_spim_pins_t pins;
621 nrfy_spim_pins_get(p_instance->p_reg, &pins);
622
623 if (!p_cb->skip_gpio_cfg)
624 {
625 spim_pin_uninit(pins.sck_pin);
626 spim_pin_uninit(pins.miso_pin);
627 spim_pin_uninit(pins.mosi_pin);
628 spim_pin_uninit(p_cb->ss_pin);
629 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
630 if (SPIM_DCX_PRESENT_VALIDATE(p_instance->drv_inst_idx) &&
631 SPIM_HW_CSN_PRESENT_VALIDATE(p_instance->drv_inst_idx))
632 {
633 nrfy_spim_ext_pins_t ext_pins;
634 nrfy_spim_ext_pins_get(p_instance->p_reg, &ext_pins);
635 spim_pin_uninit(ext_pins.dcx_pin);
636 spim_pin_uninit(ext_pins.csn_pin);
637 }
638 #endif
639 }
640
641 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_195)
642 if (p_instance->p_reg == NRF_SPIM3)
643 {
644 *(volatile uint32_t *)0x4002F004 = 1;
645 }
646 #endif
647
648 #if NRFX_CHECK(NRFX_PRS_ENABLED)
649 nrfx_prs_release(p_instance->p_reg);
650 #endif
651
652 p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
653 NRFX_LOG_INFO("Uninitialized.");
654 }
655
nrfx_spim_init_check(nrfx_spim_t const * p_instance)656 bool nrfx_spim_init_check(nrfx_spim_t const * p_instance)
657 {
658 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
659
660 return (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
661 }
662
663 #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)664 nrfx_err_t nrfx_spim_xfer_dcx(nrfx_spim_t const * p_instance,
665 nrfx_spim_xfer_desc_t const * p_xfer_desc,
666 uint32_t flags,
667 uint8_t cmd_length)
668 {
669 (void)flags;
670
671 NRFX_ASSERT(cmd_length <= NRF_SPIM_DCX_CNT_ALL_CMD);
672
673 nrfy_spim_dcx_cnt_set((NRF_SPIM_Type *)p_instance->p_reg, cmd_length);
674 return nrfx_spim_xfer(p_instance, p_xfer_desc, 0);
675 }
676 #endif
677
set_ss_pin_state(spim_control_block_t * p_cb,bool active)678 static void set_ss_pin_state(spim_control_block_t * p_cb, bool active)
679 {
680 if (p_cb->ss_pin != NRF_SPIM_PIN_NOT_CONNECTED)
681 {
682 if (p_cb->ss_active_high)
683 {
684 if (active)
685 {
686 nrfy_gpio_pin_set(p_cb->ss_pin);
687 }
688 else
689 {
690 nrfy_gpio_pin_clear(p_cb->ss_pin);
691 }
692 }
693 else
694 {
695 if (active)
696 {
697 nrfy_gpio_pin_clear(p_cb->ss_pin);
698 }
699 else
700 {
701 nrfy_gpio_pin_set(p_cb->ss_pin);
702 }
703 }
704 }
705 }
706
finish_transfer(NRF_SPIM_Type * p_spim,spim_control_block_t * p_cb)707 static void finish_transfer(NRF_SPIM_Type * p_spim, spim_control_block_t * p_cb)
708 {
709 // If Slave Select signal is used, this is the time to deactivate it.
710 set_ss_pin_state(p_cb, false);
711
712 // By clearing this flag before calling the handler we allow subsequent
713 // transfers to be started directly from the handler function.
714 if (p_cb->transfer_in_progress)
715 {
716 spim_abort(p_spim, p_cb);
717 }
718
719 p_cb->evt.type = NRFX_SPIM_EVENT_DONE;
720 p_cb->handler(&p_cb->evt, p_cb->p_context);
721 }
722
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)723 static nrfx_err_t spim_xfer(NRF_SPIM_Type * p_spim,
724 spim_control_block_t * p_cb,
725 nrfx_spim_xfer_desc_t const * p_xfer_desc,
726 uint32_t flags)
727 {
728 nrfx_err_t err_code;
729 // EasyDMA requires that transfer buffers are placed in Data RAM region;
730 // signal error if they are not.
731 if ((p_xfer_desc->p_tx_buffer != NULL &&
732 !nrf_dma_accessible_check(p_spim, p_xfer_desc->p_tx_buffer)) ||
733 (p_xfer_desc->p_rx_buffer != NULL &&
734 !nrf_dma_accessible_check(p_spim, p_xfer_desc->p_rx_buffer)))
735 {
736 p_cb->transfer_in_progress = false;
737 err_code = NRFX_ERROR_INVALID_ADDR;
738 NRFX_LOG_WARNING("Function: %s, error code: %s.",
739 __func__,
740 NRFX_LOG_ERROR_STRING_GET(err_code));
741 return err_code;
742 }
743
744 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
745 if (p_spim == NRF_SPIM3)
746 {
747 anomaly_198_enable(p_xfer_desc->p_tx_buffer, p_xfer_desc->tx_length);
748 }
749 #endif
750
751 #if NRFY_SPIM_HAS_ARRAY_LIST
752 nrfy_spim_tx_list_set(p_spim, NRFX_SPIM_FLAG_TX_POSTINC & flags);
753 nrfy_spim_rx_list_set(p_spim, NRFX_SPIM_FLAG_RX_POSTINC & flags);
754 #endif
755
756 nrfy_spim_xfer_desc_t xfer_desc = *p_xfer_desc;
757 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
758 if (flags & NRFX_SPIM_FLAG_HOLD_XFER)
759 {
760 nrfy_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED);
761 xfer_desc.tx_length = 0;
762 xfer_desc.rx_length = 0;
763 nrfy_spim_int_enable(p_spim, NRF_SPIM_INT_STARTED_MASK);
764 }
765 #endif
766 nrfy_spim_buffers_set(p_spim, &xfer_desc);
767
768 nrfy_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
769 nrfy_spim_enable(p_spim);
770
771 if (!(flags & NRFX_SPIM_FLAG_HOLD_XFER))
772 {
773 nrfy_spim_xfer_start(p_spim, p_cb->handler ? NULL : &xfer_desc);
774 }
775
776 if (!p_cb->handler)
777 {
778 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
779 if (p_spim == NRF_SPIM3)
780 {
781 anomaly_198_disable();
782 }
783 #endif
784 set_ss_pin_state(p_cb, false);
785 if (!(flags & NRFX_SPIM_FLAG_HOLD_XFER))
786 {
787 spim_abort(p_spim, p_cb);
788 }
789 }
790 else
791 {
792 if (flags & NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER)
793 {
794 nrfy_spim_int_disable(p_spim, NRF_SPIM_INT_END_MASK);
795 }
796 else
797 {
798 nrfy_spim_int_enable(p_spim, NRF_SPIM_INT_END_MASK);
799 }
800 }
801 err_code = NRFX_SUCCESS;
802 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
803 return err_code;
804 }
805
nrfx_spim_xfer(nrfx_spim_t const * p_instance,nrfx_spim_xfer_desc_t const * p_xfer_desc,uint32_t flags)806 nrfx_err_t nrfx_spim_xfer(nrfx_spim_t const * p_instance,
807 nrfx_spim_xfer_desc_t const * p_xfer_desc,
808 uint32_t flags)
809 {
810 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
811
812 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
813 NRFX_ASSERT(p_xfer_desc->p_tx_buffer != NULL || p_xfer_desc->tx_length == 0);
814 NRFX_ASSERT(p_xfer_desc->p_rx_buffer != NULL || p_xfer_desc->rx_length == 0);
815 NRFX_ASSERT(SPIM_LENGTH_VALIDATE(p_instance->drv_inst_idx,
816 p_xfer_desc->rx_length,
817 p_xfer_desc->tx_length));
818 NRFX_ASSERT(!(flags & NRFX_SPIM_FLAG_HOLD_XFER) ||
819 (p_cb->ss_pin == NRF_SPIM_PIN_NOT_CONNECTED));
820
821 nrfx_err_t err_code = NRFX_SUCCESS;
822
823 #if !NRFY_SPIM_HAS_ARRAY_LIST
824 if ((NRFX_SPIM_FLAG_TX_POSTINC | NRFX_SPIM_FLAG_RX_POSTINC) & flags)
825 {
826 err_code = NRFX_ERROR_NOT_SUPPORTED;
827 NRFX_LOG_WARNING("Function: %s, error code: %s.",
828 __func__,
829 NRFX_LOG_ERROR_STRING_GET(err_code));
830 return err_code;
831 }
832 #endif
833
834 if (p_cb->transfer_in_progress)
835 {
836 err_code = NRFX_ERROR_BUSY;
837 NRFX_LOG_WARNING("Function: %s, error code: %s.",
838 __func__,
839 NRFX_LOG_ERROR_STRING_GET(err_code));
840 return err_code;
841 }
842 else
843 {
844 if (p_cb->handler && !(flags & (NRFX_SPIM_FLAG_REPEATED_XFER |
845 NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER)))
846 {
847 p_cb->transfer_in_progress = true;
848 }
849 }
850
851 p_cb->evt.xfer_desc = *p_xfer_desc;
852
853 set_ss_pin_state(p_cb, true);
854
855 return spim_xfer(p_instance->p_reg, p_cb, p_xfer_desc, flags);
856 }
857
nrfx_spim_abort(nrfx_spim_t const * p_instance)858 void nrfx_spim_abort(nrfx_spim_t const * p_instance)
859 {
860 spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
861
862 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
863
864 spim_abort(p_instance->p_reg, p_cb);
865 }
866
irq_handler(NRF_SPIM_Type * p_spim,spim_control_block_t * p_cb)867 static void irq_handler(NRF_SPIM_Type * p_spim, spim_control_block_t * p_cb)
868 {
869 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
870 if (nrfy_spim_int_enable_check(p_spim, NRF_SPIM_INT_STARTED_MASK) &&
871 nrfy_spim_event_check(p_spim, NRF_SPIM_EVENT_STARTED))
872 {
873 /* Handle first, zero-length, auxiliary transmission. */
874 nrfy_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED);
875 nrfy_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
876
877 NRFX_ASSERT(nrfy_spim_tx_maxcnt_get(p_spim) == 0);
878 NRFX_ASSERT(nrfy_spim_rx_maxcnt_get(p_spim) == 0);
879
880 /* Disable STARTED interrupt, used only in auxiliary transmission. */
881 nrfy_spim_int_disable(p_spim, NRF_SPIM_INT_STARTED_MASK);
882
883 /* Start the actual, glitch-free transmission. */
884 nrfy_spim_buffers_set(p_spim, &p_cb->evt.xfer_desc);
885 nrfy_spim_xfer_start(p_spim, NULL);
886 return;
887 }
888 #endif
889
890 if (nrfy_spim_events_process(p_spim,
891 NRFY_EVENT_TO_INT_BITMASK(NRF_SPIM_EVENT_END),
892 &p_cb->evt.xfer_desc))
893 {
894 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
895 if (p_spim == NRF_SPIM3)
896 {
897 anomaly_198_disable();
898 }
899 #endif
900 NRFX_ASSERT(p_cb->handler);
901 NRFX_LOG_DEBUG("Event: NRF_SPIM_EVENT_END.");
902 finish_transfer(p_spim, p_cb);
903 }
904 }
905
906 NRFX_INSTANCE_IRQ_HANDLERS(SPIM, spim)
907
908 #endif // NRFX_CHECK(NRFX_SPIM_ENABLED)
909