1 /*
2 * Copyright (c) 2013 - 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_SPIS_ENABLED)
37
38 #if !NRFX_FEATURE_PRESENT(NRFX_SPIS, _ENABLED)
39 #error "No enabled SPIS instances. Check <nrfx_config.h>."
40 #endif
41
42 #include <nrfx_spis.h>
43 #include "prs/nrfx_prs.h"
44
45 #define NRFX_LOG_MODULE SPIS
46 #include <nrfx_log.h>
47
48 #define EVT_TO_STR(event) \
49 (event == NRF_SPIS_EVENT_ACQUIRED ? "NRF_SPIS_EVENT_ACQUIRED" : \
50 (event == NRF_SPIS_EVENT_END ? "NRF_SPIS_EVENT_END" : \
51 "UNKNOWN ERROR"))
52
53 #define SPISX_LENGTH_VALIDATE(periph_name, prefix, i, drv_inst_idx, rx_len, tx_len) \
54 (((drv_inst_idx) == NRFX_CONCAT(NRFX_, periph_name, prefix, i, _INST_IDX)) && \
55 NRFX_EASYDMA_LENGTH_VALIDATE(NRFX_CONCAT(periph_name, prefix, i), rx_len, tx_len))
56
57 #define SPIS_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) \
58 (NRFX_FOREACH_ENABLED(SPIS, SPISX_LENGTH_VALIDATE, (||), (0), drv_inst_idx, rx_len, tx_len))
59
60 #if NRFX_CHECK(NRFX_SPIS_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
61 #include <nrfx_gpiote.h>
62 #define USE_DMA_ISSUE_WORKAROUND
63 // This handler is called by the GPIOTE driver when a falling edge is detected
64 // on the CSN line. There is no need to do anything here. The handling of the
65 // interrupt itself provides a protection for DMA transfers.
csn_event_handler(nrfx_gpiote_pin_t pin,nrfx_gpiote_trigger_t trigger,void * p_context)66 static void csn_event_handler(nrfx_gpiote_pin_t pin,
67 nrfx_gpiote_trigger_t trigger,
68 void * p_context)
69 {
70 (void)pin;
71 (void)trigger;
72 (void)p_context;
73 }
74 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
75 static nrfx_gpiote_t const gpiote = NRFX_GPIOTE_INSTANCE(0);
76 #endif
77 #endif
78
79
80 /** @brief States of the SPI transaction state machine. */
81 typedef enum
82 {
83 SPIS_STATE_INIT, /**< Initialization state. In this state the module waits for a call to @ref spi_slave_buffers_set. */
84 SPIS_BUFFER_RESOURCE_REQUESTED, /**< State where the configuration of the memory buffers, which are to be used in SPI transaction, has started. */
85 SPIS_BUFFER_RESOURCE_CONFIGURED, /**< State where the configuration of the memory buffers, which are to be used in SPI transaction, has completed. */
86 SPIS_XFER_COMPLETED /**< State where SPI transaction has been completed. */
87 } nrfx_spis_state_t;
88
89 /** @brief SPIS control block - driver instance local data. */
90 typedef struct
91 {
92 volatile uint32_t tx_buffer_size; //!< SPI slave TX buffer size in bytes.
93 volatile uint32_t rx_buffer_size; //!< SPI slave RX buffer size in bytes.
94 nrfx_spis_event_handler_t handler; //!< SPI event handler.
95 volatile const uint8_t * tx_buffer; //!< SPI slave TX buffer.
96 volatile uint8_t * rx_buffer; //!< SPI slave RX buffer.
97 nrfx_drv_state_t state; //!< driver initialization state.
98 volatile nrfx_spis_state_t spi_state; //!< SPI slave state.
99 void * p_context; //!< Context set on initialization.
100 bool skip_gpio_cfg;
101 #if defined(USE_DMA_ISSUE_WORKAROUND)
102 uint32_t csn_pin;
103 uint8_t gpiote_ch;
104 #endif
105 } spis_cb_t;
106
107 static spis_cb_t m_cb[NRFX_SPIS_ENABLED_COUNT];
108
pins_configure(nrfx_spis_config_t const * p_config)109 static void pins_configure(nrfx_spis_config_t const * p_config)
110 {
111 nrf_gpio_cfg(p_config->sck_pin,
112 NRF_GPIO_PIN_DIR_INPUT,
113 NRF_GPIO_PIN_INPUT_CONNECT,
114 NRF_GPIO_PIN_NOPULL,
115 NRF_GPIO_PIN_S0S1,
116 NRF_GPIO_PIN_NOSENSE);
117 #if NRF_GPIO_HAS_CLOCKPIN && defined(NRF_SPIS_CLOCKPIN_SCK_NEEDED)
118 nrfy_gpio_pin_clock_set(p_config->sck_pin, true);
119 #endif
120
121 if (p_config->mosi_pin != NRF_SPIS_PIN_NOT_CONNECTED)
122 {
123 nrf_gpio_cfg(p_config->mosi_pin,
124 NRF_GPIO_PIN_DIR_INPUT,
125 NRF_GPIO_PIN_INPUT_CONNECT,
126 NRF_GPIO_PIN_NOPULL,
127 NRF_GPIO_PIN_S0S1,
128 NRF_GPIO_PIN_NOSENSE);
129 }
130
131 if (p_config->miso_pin != NRF_SPIS_PIN_NOT_CONNECTED)
132 {
133 nrf_gpio_cfg(p_config->miso_pin,
134 NRF_GPIO_PIN_DIR_INPUT,
135 NRF_GPIO_PIN_INPUT_CONNECT,
136 NRF_GPIO_PIN_NOPULL,
137 p_config->miso_drive,
138 NRF_GPIO_PIN_NOSENSE);
139 #if NRF_GPIO_HAS_CLOCKPIN && defined(NRF_SPIS_CLOCKPIN_MISO_NEEDED)
140 nrfy_gpio_pin_clock_set(p_config->miso_pin, true);
141 #endif
142 }
143
144 nrf_gpio_cfg(p_config->csn_pin,
145 NRF_GPIO_PIN_DIR_INPUT,
146 NRF_GPIO_PIN_INPUT_CONNECT,
147 p_config->csn_pullup,
148 NRF_GPIO_PIN_S0S1,
149 NRF_GPIO_PIN_NOSENSE);
150 }
151
spis_configure(nrfx_spis_t const * p_instance,nrfx_spis_config_t const * p_config)152 static bool spis_configure(nrfx_spis_t const * p_instance,
153 nrfx_spis_config_t const * p_config)
154 {
155 NRF_SPIS_Type * p_spis = p_instance->p_reg;
156 if (p_config->mode > NRF_SPIS_MODE_3)
157 {
158 return false;
159 }
160
161 if (!p_config->skip_gpio_cfg)
162 {
163 pins_configure(p_config);
164 }
165
166 if (!p_config->skip_psel_cfg)
167 {
168 nrf_spis_pins_set(p_spis,
169 p_config->sck_pin,
170 p_config->mosi_pin,
171 p_config->miso_pin,
172 p_config->csn_pin);
173 }
174
175 #if defined(USE_DMA_ISSUE_WORKAROUND)
176 spis_cb_t * p_cb = &m_cb[p_instance->drv_inst_idx];
177
178 // If the GPIOTE channel was already used with a CSN pin, deinitialize it
179 // first as that pin number may be different now.
180 if (p_cb->csn_pin != NRF_SPIS_PIN_NOT_CONNECTED)
181 {
182 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
183 nrfx_gpiote_pin_uninit(&gpiote, p_cb->csn_pin);
184 #else
185 nrfx_gpiote_pin_uninit(p_cb->csn_pin);
186 #endif
187 p_cb->csn_pin = NRF_SPIS_PIN_NOT_CONNECTED;
188 }
189
190 // Get the CSN pin number from the PSEL register in the peripheral
191 // as in p_config that pin number may be omitted.
192 uint32_t csn_pin = nrf_spis_csn_pin_get(p_spis);
193
194 // Configure a GPIOTE channel to generate interrupts on each falling edge
195 // on the CSN line. Handling of these interrupts will make the CPU active
196 // and thus will protect the DMA transfers started by SPIS right after it
197 // is selected for communication.
198 nrfx_gpiote_trigger_config_t trig_config = {
199 .trigger = NRFX_GPIOTE_TRIGGER_HITOLO,
200 .p_in_channel = &p_cb->gpiote_ch
201 };
202 nrfx_gpiote_handler_config_t hndl_config = {
203 .handler = csn_event_handler
204 };
205
206 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
207 nrfx_gpiote_input_pin_config_t config = {
208 .p_pull_config = NULL,
209 .p_trigger_config = &trig_config,
210 .p_handler_config = &hndl_config
211 };
212 nrfx_err_t err_code = nrfx_gpiote_input_configure(&gpiote, csn_pin, &config);
213 #else
214 nrfx_err_t err_code = nrfx_gpiote_input_configure(csn_pin, NULL, &trig_config, &hndl_config);
215 #endif
216 if (err_code != NRFX_SUCCESS)
217 {
218 NRFX_LOG_ERROR("Function: %s, error code: %s.",
219 __func__,
220 NRFX_LOG_ERROR_STRING_GET(err_code));
221 return false;
222 }
223
224 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
225 nrfx_gpiote_trigger_enable(&gpiote, csn_pin, true);
226 #else
227 nrfx_gpiote_trigger_enable(csn_pin, true);
228 #endif
229
230 p_cb->csn_pin = csn_pin;
231 #endif
232
233 // Configure SPI mode.
234 nrf_spis_configure(p_spis, p_config->mode, p_config->bit_order);
235
236 // Configure DEF and ORC characters.
237 nrf_spis_def_set(p_spis, p_config->def);
238 nrf_spis_orc_set(p_spis, p_config->orc);
239
240 // Clear possible pending events.
241 nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_END);
242 nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_ACQUIRED);
243
244 // Enable END_ACQUIRE shortcut.
245 nrf_spis_shorts_enable(p_spis, NRF_SPIS_SHORT_END_ACQUIRE);
246
247 NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_reg), p_config->irq_priority);
248 NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_reg));
249
250 return true;
251 }
252
nrfx_spis_init(nrfx_spis_t const * p_instance,nrfx_spis_config_t const * p_config,nrfx_spis_event_handler_t event_handler,void * p_context)253 nrfx_err_t nrfx_spis_init(nrfx_spis_t const * p_instance,
254 nrfx_spis_config_t const * p_config,
255 nrfx_spis_event_handler_t event_handler,
256 void * p_context)
257 {
258 NRFX_ASSERT(p_config);
259 NRFX_ASSERT(event_handler);
260
261 spis_cb_t * p_cb = &m_cb[p_instance->drv_inst_idx];
262 nrfx_err_t err_code;
263
264 NRF_SPIS_Type * p_spis = p_instance->p_reg;
265
266 if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
267 {
268 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
269 err_code = NRFX_ERROR_ALREADY;
270 #else
271 err_code = NRFX_ERROR_INVALID_STATE;
272 #endif
273 NRFX_LOG_WARNING("Function: %s, error code: %s.",
274 __func__,
275 NRFX_LOG_ERROR_STRING_GET(err_code));
276 return err_code;
277 }
278
279 #if NRFX_CHECK(NRFX_PRS_ENABLED)
280 static nrfx_irq_handler_t const irq_handlers[NRFX_SPIS_ENABLED_COUNT] = {
281 NRFX_INSTANCE_IRQ_HANDLERS_LIST(SPIS, spis)
282 };
283 if (nrfx_prs_acquire(p_spis,
284 irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
285 {
286 err_code = NRFX_ERROR_BUSY;
287 NRFX_LOG_WARNING("Function: %s, error code: %s.",
288 __func__,
289 NRFX_LOG_ERROR_STRING_GET(err_code));
290 return err_code;
291 }
292 #endif // NRFX_CHECK(NRFX_PRS_ENABLED)
293
294 p_cb->handler = event_handler;
295 p_cb->p_context = p_context;
296
297 #if defined(USE_DMA_ISSUE_WORKAROUND)
298 p_cb->csn_pin = NRF_SPIS_PIN_NOT_CONNECTED;
299
300 // Allocate a GPIOTE channel that will be used to handle the anomaly 109
301 // (the GPIOTE driver may be already initialized at this point, by this
302 // driver when another SPIS instance is used or by an application code,
303 // so just ignore the returned value here).
304 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
305 (void)nrfx_gpiote_init(&gpiote, NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY);
306 err_code = nrfx_gpiote_channel_alloc(&gpiote, &p_cb->gpiote_ch);
307 #else
308 (void)nrfx_gpiote_init(NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY);
309 err_code = nrfx_gpiote_channel_alloc(&p_cb->gpiote_ch);
310 #endif
311
312 if (err_code != NRFX_SUCCESS)
313 {
314 #if NRFX_CHECK(NRFX_PRS_ENABLED)
315 nrfx_prs_release(p_spis);
316 #endif
317 err_code = NRFX_ERROR_INTERNAL;
318 NRFX_LOG_ERROR("Function: %s, error code: %s.",
319 __func__,
320 NRFX_LOG_ERROR_STRING_GET(err_code));
321 return err_code;
322 }
323 #endif
324
325 if (p_config)
326 {
327 p_cb->skip_gpio_cfg = p_config->skip_gpio_cfg;
328
329 if (!spis_configure(p_instance, p_config))
330 {
331 #if defined(USE_DMA_ISSUE_WORKAROUND)
332 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
333 nrfx_gpiote_channel_free(&gpiote, p_cb->gpiote_ch);
334 #else
335 nrfx_gpiote_channel_free(p_cb->gpiote_ch);
336 #endif
337 #endif
338 err_code = NRFX_ERROR_INVALID_PARAM;
339 NRFX_LOG_WARNING("Function: %s, error code: %s.",
340 __func__,
341 NRFX_LOG_ERROR_STRING_GET(err_code));
342 #if NRFX_CHECK(NRFX_PRS_ENABLED)
343 nrfx_prs_release(p_spis);
344 #endif
345 return err_code;
346 }
347 }
348
349 nrf_spis_rx_buffer_set(p_spis, NULL, 0);
350 nrf_spis_tx_buffer_set(p_spis, NULL, 0);
351
352 p_cb->spi_state = SPIS_STATE_INIT;
353 // Enable IRQ.
354 nrf_spis_int_enable(p_spis, NRF_SPIS_INT_ACQUIRED_MASK |
355 NRF_SPIS_INT_END_MASK);
356
357 p_cb->state = NRFX_DRV_STATE_INITIALIZED;
358
359 // Enable SPI slave device.
360 nrf_spis_enable(p_spis);
361
362 NRFX_LOG_INFO("Initialized.");
363 return NRFX_SUCCESS;
364 }
365
nrfx_spis_reconfigure(nrfx_spis_t const * p_instance,nrfx_spis_config_t const * p_config)366 nrfx_err_t nrfx_spis_reconfigure(nrfx_spis_t const * p_instance,
367 nrfx_spis_config_t const * p_config)
368 {
369 NRFX_ASSERT(p_config);
370
371 nrfx_err_t err_code;
372 spis_cb_t * p_cb = &m_cb[p_instance->drv_inst_idx];
373
374 if (p_cb->state == NRFX_DRV_STATE_UNINITIALIZED)
375 {
376 return NRFX_ERROR_INVALID_STATE;
377 }
378 nrf_spis_disable(p_instance->p_reg);
379 if (spis_configure(p_instance, p_config))
380 {
381 err_code = NRFX_SUCCESS;
382 }
383 else
384 {
385 err_code = NRFX_ERROR_INVALID_PARAM;
386 }
387 nrf_spis_enable(p_instance->p_reg);
388 return err_code;
389 }
390
nrfx_spis_uninit(nrfx_spis_t const * p_instance)391 void nrfx_spis_uninit(nrfx_spis_t const * p_instance)
392 {
393 spis_cb_t * p_cb = &m_cb[p_instance->drv_inst_idx];
394
395 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
396
397 NRF_SPIS_Type * p_spis = p_instance->p_reg;
398
399 #if defined(USE_DMA_ISSUE_WORKAROUND)
400 if (p_cb->csn_pin != NRF_SPIS_PIN_NOT_CONNECTED)
401 {
402 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
403 nrfx_gpiote_pin_uninit(&gpiote, p_cb->csn_pin);
404 #else
405 nrfx_gpiote_pin_uninit(p_cb->csn_pin);
406 #endif
407 }
408 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
409 nrfx_gpiote_channel_free(&gpiote, p_cb->gpiote_ch);
410 #else
411 nrfx_gpiote_channel_free(p_cb->gpiote_ch);
412 #endif
413 #endif
414
415 #define DISABLE_ALL 0xFFFFFFFF
416 nrf_spis_disable(p_spis);
417 NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_reg));
418 nrf_spis_int_disable(p_spis, DISABLE_ALL);
419 #undef DISABLE_ALL
420
421 if (!p_cb->skip_gpio_cfg)
422 {
423 nrf_gpio_cfg_default(nrf_spis_sck_pin_get(p_spis));
424 nrf_gpio_cfg_default(nrf_spis_csn_pin_get(p_spis));
425
426 uint32_t miso_pin = nrf_spis_miso_pin_get(p_spis);
427 if (miso_pin != NRF_SPIS_PIN_NOT_CONNECTED)
428 {
429 nrf_gpio_cfg_default(miso_pin);
430 }
431
432 uint32_t mosi_pin = nrf_spis_mosi_pin_get(p_spis);
433 if (mosi_pin != NRF_SPIS_PIN_NOT_CONNECTED)
434 {
435 nrf_gpio_cfg_default(mosi_pin);
436 }
437 }
438
439 #if NRFX_CHECK(NRFX_PRS_ENABLED)
440 nrfx_prs_release(p_spis);
441 #endif
442
443 p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
444 NRFX_LOG_INFO("Uninitialized.");
445 }
446
nrfx_spis_init_check(nrfx_spis_t const * p_instance)447 bool nrfx_spis_init_check(nrfx_spis_t const * p_instance)
448 {
449 spis_cb_t * p_cb = &m_cb[p_instance->drv_inst_idx];
450
451 return (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
452 }
453
454 /** @brief Function for executing the state entry action. */
spis_state_entry_action_execute(NRF_SPIS_Type * p_spis,spis_cb_t * p_cb)455 static void spis_state_entry_action_execute(NRF_SPIS_Type * p_spis,
456 spis_cb_t * p_cb)
457 {
458 nrfx_spis_evt_t event;
459
460 switch (p_cb->spi_state)
461 {
462 case SPIS_BUFFER_RESOURCE_REQUESTED:
463 nrf_spis_task_trigger(p_spis, NRF_SPIS_TASK_ACQUIRE);
464 break;
465
466 case SPIS_BUFFER_RESOURCE_CONFIGURED:
467 event.evt_type = NRFX_SPIS_BUFFERS_SET_DONE;
468 event.rx_amount = 0;
469 event.tx_amount = 0;
470
471 NRFX_ASSERT(p_cb->handler != NULL);
472 p_cb->handler(&event, p_cb->p_context);
473 break;
474
475 case SPIS_XFER_COMPLETED:
476 event.evt_type = NRFX_SPIS_XFER_DONE;
477 event.rx_amount = nrf_spis_rx_amount_get(p_spis);
478 event.tx_amount = nrf_spis_tx_amount_get(p_spis);
479
480 #if defined(__GNUC__)
481 #pragma GCC diagnostic push
482 #pragma GCC diagnostic ignored "-Wcast-qual"
483 #endif
484 event.p_tx_buf = (void *)p_cb->tx_buffer;
485 event.p_rx_buf = (void *)p_cb->rx_buffer;
486 #if defined(__GNUC__)
487 #pragma GCC diagnostic pop
488 #endif
489
490 event.tx_buf_size = p_cb->tx_buffer_size;
491 event.rx_buf_size = p_cb->rx_buffer_size;
492
493 NRFX_LOG_INFO("Transfer rx_len:%d.", event.rx_amount);
494 NRFX_LOG_DEBUG("Rx data:");
495 NRFX_LOG_HEXDUMP_DEBUG((uint8_t const *)p_cb->rx_buffer,
496 event.rx_amount * sizeof(p_cb->rx_buffer[0]));
497 NRFX_ASSERT(p_cb->handler != NULL);
498 p_cb->handler(&event, p_cb->p_context);
499 break;
500
501 default:
502 // No implementation required.
503 break;
504 }
505 }
506
507 /** @brief Function for changing the state of the SPI state machine.
508 *
509 * @param[in] p_spis SPIS instance register.
510 * @param[in] p_cb SPIS instance control block.
511 * @param[in] new_state State where the state machine transits to.
512 */
spis_state_change(NRF_SPIS_Type * p_spis,spis_cb_t * p_cb,nrfx_spis_state_t new_state)513 static void spis_state_change(NRF_SPIS_Type * p_spis,
514 spis_cb_t * p_cb,
515 nrfx_spis_state_t new_state)
516 {
517 p_cb->spi_state = new_state;
518 spis_state_entry_action_execute(p_spis, p_cb);
519 }
520
nrfx_spis_buffers_set(nrfx_spis_t const * p_instance,uint8_t const * p_tx_buffer,size_t tx_buffer_length,uint8_t * p_rx_buffer,size_t rx_buffer_length)521 nrfx_err_t nrfx_spis_buffers_set(nrfx_spis_t const * p_instance,
522 uint8_t const * p_tx_buffer,
523 size_t tx_buffer_length,
524 uint8_t * p_rx_buffer,
525 size_t rx_buffer_length)
526 {
527 spis_cb_t * p_cb = &m_cb[p_instance->drv_inst_idx];
528 nrfx_err_t err_code;
529
530 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
531 NRFX_ASSERT(p_tx_buffer != NULL || tx_buffer_length == 0);
532 NRFX_ASSERT(p_rx_buffer != NULL || rx_buffer_length == 0);
533
534 if (!SPIS_LENGTH_VALIDATE(p_instance->drv_inst_idx,
535 rx_buffer_length,
536 tx_buffer_length))
537 {
538 return NRFX_ERROR_INVALID_LENGTH;
539 }
540
541 // EasyDMA requires that transfer buffers are placed in Data RAM region;
542 // signal error if they are not.
543 if ((p_tx_buffer != NULL && !nrfx_is_in_ram(p_tx_buffer)) ||
544 (p_rx_buffer != NULL && !nrfx_is_in_ram(p_rx_buffer)))
545 {
546 err_code = NRFX_ERROR_INVALID_ADDR;
547 NRFX_LOG_WARNING("Function: %s, error code: %s.",
548 __func__,
549 NRFX_LOG_ERROR_STRING_GET(err_code));
550 return err_code;
551 }
552
553 switch (p_cb->spi_state)
554 {
555 case SPIS_STATE_INIT:
556 case SPIS_XFER_COMPLETED:
557 case SPIS_BUFFER_RESOURCE_CONFIGURED:
558 p_cb->tx_buffer = p_tx_buffer;
559 p_cb->rx_buffer = p_rx_buffer;
560 p_cb->tx_buffer_size = tx_buffer_length;
561 p_cb->rx_buffer_size = rx_buffer_length;
562 err_code = NRFX_SUCCESS;
563
564 spis_state_change(p_instance->p_reg, p_cb, SPIS_BUFFER_RESOURCE_REQUESTED);
565 break;
566
567 case SPIS_BUFFER_RESOURCE_REQUESTED:
568 err_code = NRFX_ERROR_INVALID_STATE;
569 break;
570
571 default:
572 // @note: execution of this code path would imply internal error in the design.
573 err_code = NRFX_ERROR_INTERNAL;
574 break;
575 }
576
577 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
578 return err_code;
579 }
580
irq_handler(NRF_SPIS_Type * p_spis,spis_cb_t * p_cb)581 static void irq_handler(NRF_SPIS_Type * p_spis, spis_cb_t * p_cb)
582 {
583 // @note: as multiple events can be pending for processing, the correct event processing order
584 // is as follows:
585 // - SPI semaphore acquired event.
586 // - SPI transaction complete event.
587
588 // Check for SPI semaphore acquired event.
589 if (nrf_spis_event_check(p_spis, NRF_SPIS_EVENT_ACQUIRED))
590 {
591 nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_ACQUIRED);
592 NRFX_LOG_DEBUG("SPIS: Event: %s.", EVT_TO_STR(NRF_SPIS_EVENT_ACQUIRED));
593
594 switch (p_cb->spi_state)
595 {
596 case SPIS_BUFFER_RESOURCE_REQUESTED:
597
598 #if defined(__GNUC__)
599 #pragma GCC diagnostic push
600 #pragma GCC diagnostic ignored "-Wcast-qual"
601 #endif
602
603 nrf_spis_tx_buffer_set(p_spis, (uint8_t *)p_cb->tx_buffer, p_cb->tx_buffer_size);
604 nrf_spis_rx_buffer_set(p_spis, (uint8_t *)p_cb->rx_buffer, p_cb->rx_buffer_size);
605
606 #if defined(__GNUC__)
607 #pragma GCC diagnostic pop
608 #endif
609
610 nrf_spis_task_trigger(p_spis, NRF_SPIS_TASK_RELEASE);
611
612 spis_state_change(p_spis, p_cb, SPIS_BUFFER_RESOURCE_CONFIGURED);
613 break;
614
615 default:
616 // No implementation required.
617 break;
618 }
619 }
620
621 // Check for SPI transaction complete event.
622 if (nrf_spis_event_check(p_spis, NRF_SPIS_EVENT_END))
623 {
624 nrf_spis_event_clear(p_spis, NRF_SPIS_EVENT_END);
625 NRFX_LOG_DEBUG("SPIS: Event: %s.", EVT_TO_STR(NRF_SPIS_EVENT_END));
626
627 switch (p_cb->spi_state)
628 {
629 case SPIS_BUFFER_RESOURCE_CONFIGURED:
630 spis_state_change(p_spis, p_cb, SPIS_XFER_COMPLETED);
631 break;
632
633 default:
634 // No implementation required.
635 break;
636 }
637 }
638 }
639
640 NRFX_INSTANCE_IRQ_HANDLERS(SPIS, spis)
641
642 #endif // NRFX_CHECK(NRFX_SPIS_ENABLED)
643