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_SPI_ENABLED)
37
38 #if !NRFX_FEATURE_PRESENT(NRFX_SPI, _ENABLED)
39 #error "No enabled SPI instances. Check <nrfx_config.h>."
40 #endif
41
42 #include <nrfx_spi.h>
43 #include "prs/nrfx_prs.h"
44 #include <hal/nrf_gpio.h>
45
46 #define NRFX_LOG_MODULE SPI
47 #include <nrfx_log.h>
48
49 // Control block - driver instance local data.
50 typedef struct
51 {
52 nrfx_spi_evt_handler_t handler;
53 void * p_context;
54 nrfx_spi_evt_t evt; // Keep the struct that is ready for event handler. Less memcpy.
55 nrfx_drv_state_t state;
56 volatile bool transfer_in_progress;
57
58 uint8_t ss_pin;
59 uint8_t orc;
60 size_t bytes_transferred;
61 bool abort;
62 bool skip_gpio_cfg;
63 } spi_control_block_t;
64 static spi_control_block_t m_cb[NRFX_SPI_ENABLED_COUNT];
65
pins_configure(nrfx_spi_config_t const * p_config)66 static void pins_configure(nrfx_spi_config_t const * p_config)
67 {
68 if (!p_config->skip_gpio_cfg)
69 {
70 // Configure pins used by the peripheral:
71 // - SCK - output with initial value corresponding with the SPI mode used:
72 // 0 - for modes 0 and 1 (CPOL = 0), 1 - for modes 2 and 3 (CPOL = 1);
73 // according to the reference manual guidelines this pin and its input
74 // buffer must always be connected for the SPI to work.
75 if (p_config->mode <= NRF_SPI_MODE_1)
76 {
77 nrf_gpio_pin_clear(p_config->sck_pin);
78 }
79 else
80 {
81 nrf_gpio_pin_set(p_config->sck_pin);
82 }
83 nrf_gpio_cfg(p_config->sck_pin,
84 NRF_GPIO_PIN_DIR_OUTPUT,
85 NRF_GPIO_PIN_INPUT_CONNECT,
86 NRF_GPIO_PIN_NOPULL,
87 NRF_GPIO_PIN_S0S1,
88 NRF_GPIO_PIN_NOSENSE);
89 // - MOSI (optional) - output with initial value 0,
90 if (p_config->mosi_pin != NRFX_SPI_PIN_NOT_USED)
91 {
92 nrf_gpio_pin_clear(p_config->mosi_pin);
93 nrf_gpio_cfg_output(p_config->mosi_pin);
94 }
95 // - MISO (optional) - input,
96 if (p_config->miso_pin != NRFX_SPI_PIN_NOT_USED)
97 {
98 nrf_gpio_cfg_input(p_config->miso_pin, p_config->miso_pull);
99 }
100 // - Slave Select (optional) - output with initial value 1 (inactive).
101 if (p_config->ss_pin != NRFX_SPI_PIN_NOT_USED)
102 {
103 nrf_gpio_pin_set(p_config->ss_pin);
104 nrf_gpio_cfg_output(p_config->ss_pin);
105 }
106 }
107 }
108
spi_configure(nrfx_spi_t const * p_instance,nrfx_spi_config_t const * p_config)109 static void spi_configure(nrfx_spi_t const * p_instance,
110 nrfx_spi_config_t const * p_config)
111 {
112 pins_configure(p_config);
113 m_cb[p_instance->drv_inst_idx].ss_pin = p_config->ss_pin;
114
115 if (!p_config->skip_psel_cfg)
116 {
117 uint32_t mosi_pin = p_config->mosi_pin != NRFX_SPI_PIN_NOT_USED ?
118 p_config->mosi_pin : NRF_SPI_PIN_NOT_CONNECTED;
119 uint32_t miso_pin = p_config->miso_pin != NRFX_SPI_PIN_NOT_USED ?
120 p_config->miso_pin : NRF_SPI_PIN_NOT_CONNECTED;
121
122 nrf_spi_pins_set(p_instance->p_reg, p_config->sck_pin, mosi_pin, miso_pin);
123 }
124 nrf_spi_frequency_set(p_instance->p_reg, p_config->frequency);
125 nrf_spi_configure(p_instance->p_reg, p_config->mode, p_config->bit_order);
126
127 m_cb[p_instance->drv_inst_idx].orc = p_config->orc;
128
129 if (m_cb[p_instance->drv_inst_idx].handler)
130 {
131 NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_reg),
132 p_config->irq_priority);
133 NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_reg));
134 }
135 }
136
nrfx_spi_init(nrfx_spi_t const * p_instance,nrfx_spi_config_t const * p_config,nrfx_spi_evt_handler_t handler,void * p_context)137 nrfx_err_t nrfx_spi_init(nrfx_spi_t const * p_instance,
138 nrfx_spi_config_t const * p_config,
139 nrfx_spi_evt_handler_t handler,
140 void * p_context)
141 {
142 NRFX_ASSERT(p_config);
143
144 spi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
145 nrfx_err_t err_code;
146
147 if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
148 {
149 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
150 err_code = NRFX_ERROR_ALREADY;
151 #else
152 err_code = NRFX_ERROR_INVALID_STATE;
153 #endif
154 NRFX_LOG_WARNING("Function: %s, error code: %s.",
155 __func__,
156 NRFX_LOG_ERROR_STRING_GET(err_code));
157 return err_code;
158 }
159
160 #if NRFX_CHECK(NRFX_PRS_ENABLED)
161 static nrfx_irq_handler_t const irq_handlers[NRFX_SPI_ENABLED_COUNT] = {
162 NRFX_INSTANCE_IRQ_HANDLERS_LIST(SPI, spi)
163 };
164 if (nrfx_prs_acquire(p_instance->p_reg,
165 irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
166 {
167 err_code = NRFX_ERROR_BUSY;
168 NRFX_LOG_WARNING("Function: %s, error code: %s.",
169 __func__,
170 NRFX_LOG_ERROR_STRING_GET(err_code));
171 return err_code;
172 }
173 #endif // NRFX_CHECK(NRFX_PRS_ENABLED)
174
175 p_cb->handler = handler;
176 p_cb->p_context = p_context;
177
178 if (p_config)
179 {
180 p_cb->skip_gpio_cfg = p_config->skip_gpio_cfg;
181 p_cb->ss_pin = p_config->ss_pin;
182 p_cb->orc = p_config->orc;
183
184 spi_configure(p_instance, p_config);
185 }
186 nrf_spi_enable(p_instance->p_reg);
187
188 p_cb->transfer_in_progress = false;
189 p_cb->state = NRFX_DRV_STATE_INITIALIZED;
190
191 err_code = NRFX_SUCCESS;
192 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
193 return err_code;
194 }
195
nrfx_spi_reconfigure(nrfx_spi_t const * p_instance,nrfx_spi_config_t const * p_config)196 nrfx_err_t nrfx_spi_reconfigure(nrfx_spi_t const * p_instance,
197 nrfx_spi_config_t const * p_config)
198 {
199 NRFX_ASSERT(p_config);
200
201 spi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
202
203 if (p_cb->state == NRFX_DRV_STATE_UNINITIALIZED)
204 {
205 return NRFX_ERROR_INVALID_STATE;
206 }
207 if (p_cb->transfer_in_progress)
208 {
209 return NRFX_ERROR_BUSY;
210 }
211 nrf_spi_disable(p_instance->p_reg);
212 spi_configure(p_instance, p_config);
213 nrf_spi_enable(p_instance->p_reg);
214 return NRFX_SUCCESS;
215 }
216
nrfx_spi_uninit(nrfx_spi_t const * p_instance)217 void nrfx_spi_uninit(nrfx_spi_t const * p_instance)
218 {
219 spi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
220 NRF_SPI_Type * p_spi = p_instance->p_reg;
221
222 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
223
224 if (p_cb->handler)
225 {
226 NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_reg));
227 nrf_spi_int_disable(p_spi, NRF_SPI_ALL_INTS_MASK);
228 }
229
230 nrf_spi_disable(p_spi);
231
232 if (!p_cb->skip_gpio_cfg)
233 {
234 nrf_gpio_cfg_default(nrf_spi_sck_pin_get(p_spi));
235
236 uint32_t miso_pin = nrf_spi_miso_pin_get(p_spi);
237 if (miso_pin != NRF_SPI_PIN_NOT_CONNECTED)
238 {
239 nrf_gpio_cfg_default(miso_pin);
240 }
241
242 uint32_t mosi_pin = nrf_spi_mosi_pin_get(p_spi);
243 if (mosi_pin != NRF_SPI_PIN_NOT_CONNECTED)
244 {
245 nrf_gpio_cfg_default(mosi_pin);
246 }
247
248 if (p_cb->ss_pin != NRFX_SPI_PIN_NOT_USED)
249 {
250 nrf_gpio_cfg_default(p_cb->ss_pin);
251 }
252 }
253
254 #if NRFX_CHECK(NRFX_PRS_ENABLED)
255 nrfx_prs_release(p_instance->p_reg);
256 #endif
257
258 p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
259 NRFX_LOG_INFO("Uninitialized.");
260 }
261
nrfx_spi_init_check(nrfx_spi_t const * p_instance)262 bool nrfx_spi_init_check(nrfx_spi_t const * p_instance)
263 {
264 spi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
265
266 return (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
267 }
268
finish_transfer(spi_control_block_t * p_cb)269 static void finish_transfer(spi_control_block_t * p_cb)
270 {
271 // If Slave Select signal is used, this is the time to deactivate it.
272 if (p_cb->ss_pin != NRFX_SPI_PIN_NOT_USED)
273 {
274 nrf_gpio_pin_write(p_cb->ss_pin, 1);
275 }
276
277 // By clearing this flag before calling the handler we allow subsequent
278 // transfers to be started directly from the handler function.
279 p_cb->transfer_in_progress = false;
280
281 p_cb->evt.type = NRFX_SPI_EVENT_DONE;
282 p_cb->handler(&p_cb->evt, p_cb->p_context);
283 }
284
285 // This function is called from the IRQ handler or, in blocking mode, directly
286 // from the 'spi_xfer' function.
287 // It returns true as long as the transfer should be continued, otherwise (when
288 // there is nothing more to send/receive) it returns false.
transfer_byte(NRF_SPI_Type * p_spi,spi_control_block_t * p_cb)289 static bool transfer_byte(NRF_SPI_Type * p_spi, spi_control_block_t * p_cb)
290 {
291 // Read the data byte received in this transfer (always, because no further
292 // READY event can be generated until the current byte is read out from the
293 // RXD register), and store it in the RX buffer (only when needed).
294 volatile uint8_t rx_data = nrf_spi_rxd_get(p_spi);
295 if (p_cb->bytes_transferred < p_cb->evt.xfer_desc.rx_length)
296 {
297 p_cb->evt.xfer_desc.p_rx_buffer[p_cb->bytes_transferred] = rx_data;
298 }
299
300 ++p_cb->bytes_transferred;
301
302 // Check if there are more bytes to send or receive and write proper data
303 // byte (next one from TX buffer or over-run character) to the TXD register
304 // when needed.
305 // NOTE - we've already used 'p_cb->bytes_transferred + 1' bytes from our
306 // buffers, because we take advantage of double buffering of TXD
307 // register (so in effect one byte is still being transmitted now);
308 // see how the transfer is started in the 'spi_xfer' function.
309 size_t bytes_used = p_cb->bytes_transferred + 1;
310
311 if (p_cb->abort)
312 {
313 if (bytes_used < p_cb->evt.xfer_desc.tx_length)
314 {
315 p_cb->evt.xfer_desc.tx_length = bytes_used;
316 }
317 if (bytes_used < p_cb->evt.xfer_desc.rx_length)
318 {
319 p_cb->evt.xfer_desc.rx_length = bytes_used;
320 }
321 }
322
323 if (bytes_used < p_cb->evt.xfer_desc.tx_length)
324 {
325 nrf_spi_txd_set(p_spi, p_cb->evt.xfer_desc.p_tx_buffer[bytes_used]);
326 return true;
327 }
328 else if (bytes_used < p_cb->evt.xfer_desc.rx_length)
329 {
330 nrf_spi_txd_set(p_spi, p_cb->orc);
331 return true;
332 }
333
334 return (p_cb->bytes_transferred < p_cb->evt.xfer_desc.tx_length ||
335 p_cb->bytes_transferred < p_cb->evt.xfer_desc.rx_length);
336 }
337
spi_xfer(NRF_SPI_Type * p_spi,spi_control_block_t * p_cb,nrfx_spi_xfer_desc_t const * p_xfer_desc)338 static void spi_xfer(NRF_SPI_Type * p_spi,
339 spi_control_block_t * p_cb,
340 nrfx_spi_xfer_desc_t const * p_xfer_desc)
341 {
342 p_cb->bytes_transferred = 0;
343 nrf_spi_int_disable(p_spi, NRF_SPI_INT_READY_MASK);
344
345 nrf_spi_event_clear(p_spi, NRF_SPI_EVENT_READY);
346
347 // Start the transfer by writing some byte to the TXD register;
348 // if TX buffer is not empty, take the first byte from this buffer,
349 // otherwise - use over-run character.
350 nrf_spi_txd_set(p_spi,
351 (p_xfer_desc->tx_length > 0 ? p_xfer_desc->p_tx_buffer[0] : p_cb->orc));
352
353 // TXD register is double buffered, so next byte to be transmitted can
354 // be written immediately, if needed, i.e. if TX or RX transfer is to
355 // be more that 1 byte long. Again - if there is something more in TX
356 // buffer send it, otherwise use over-run character.
357 if (p_xfer_desc->tx_length > 1)
358 {
359 nrf_spi_txd_set(p_spi, p_xfer_desc->p_tx_buffer[1]);
360 }
361 else if (p_xfer_desc->rx_length > 1)
362 {
363 nrf_spi_txd_set(p_spi, p_cb->orc);
364 }
365
366 // For blocking mode (user handler not provided) wait here for READY
367 // events (indicating that the byte from TXD register was transmitted
368 // and a new incoming byte was moved to the RXD register) and continue
369 // transaction until all requested bytes are transferred.
370 // In non-blocking mode - IRQ service routine will do this stuff.
371 if (p_cb->handler)
372 {
373 nrf_spi_int_enable(p_spi, NRF_SPI_INT_READY_MASK);
374 }
375 else
376 {
377 do {
378 while (!nrf_spi_event_check(p_spi, NRF_SPI_EVENT_READY)) {}
379 nrf_spi_event_clear(p_spi, NRF_SPI_EVENT_READY);
380 NRFX_LOG_DEBUG("SPI: Event: NRF_SPI_EVENT_READY.");
381 } while (transfer_byte(p_spi, p_cb));
382 if (p_cb->ss_pin != NRFX_SPI_PIN_NOT_USED)
383 {
384 nrf_gpio_pin_write(p_cb->ss_pin, 1);
385 }
386 }
387 }
388
nrfx_spi_xfer(nrfx_spi_t const * p_instance,nrfx_spi_xfer_desc_t const * p_xfer_desc,uint32_t flags)389 nrfx_err_t nrfx_spi_xfer(nrfx_spi_t const * p_instance,
390 nrfx_spi_xfer_desc_t const * p_xfer_desc,
391 uint32_t flags)
392 {
393 spi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
394
395 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
396 NRFX_ASSERT(p_xfer_desc->p_tx_buffer != NULL || p_xfer_desc->tx_length == 0);
397 NRFX_ASSERT(p_xfer_desc->p_rx_buffer != NULL || p_xfer_desc->rx_length == 0);
398
399 nrfx_err_t err_code = NRFX_SUCCESS;
400
401 if (p_cb->transfer_in_progress)
402 {
403 err_code = NRFX_ERROR_BUSY;
404 NRFX_LOG_WARNING("Function: %s, error code: %s.",
405 __func__,
406 NRFX_LOG_ERROR_STRING_GET(err_code));
407 return err_code;
408 }
409 else
410 {
411 if (p_cb->handler)
412 {
413 p_cb->transfer_in_progress = true;
414 }
415 }
416
417 p_cb->evt.xfer_desc = *p_xfer_desc;
418 p_cb->abort = false;
419
420 if (p_cb->ss_pin != NRFX_SPI_PIN_NOT_USED)
421 {
422 nrf_gpio_pin_write(p_cb->ss_pin, 0);
423 }
424 if (flags)
425 {
426 p_cb->transfer_in_progress = false;
427 err_code = NRFX_ERROR_NOT_SUPPORTED;
428 }
429 else
430 {
431 spi_xfer(p_instance->p_reg, p_cb, p_xfer_desc);
432 }
433 NRFX_LOG_INFO("Function: %s, error code: %s.",
434 __func__,
435 NRFX_LOG_ERROR_STRING_GET(err_code));
436 return err_code;
437 }
438
nrfx_spi_abort(nrfx_spi_t const * p_instance)439 void nrfx_spi_abort(nrfx_spi_t const * p_instance)
440 {
441 spi_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
442
443 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
444
445 p_cb->abort = true;
446 }
447
irq_handler(NRF_SPI_Type * p_spi,spi_control_block_t * p_cb)448 static void irq_handler(NRF_SPI_Type * p_spi, spi_control_block_t * p_cb)
449 {
450 NRFX_ASSERT(p_cb->handler);
451
452 nrf_spi_event_clear(p_spi, NRF_SPI_EVENT_READY);
453 NRFX_LOG_DEBUG("Event: NRF_SPI_EVENT_READY.");
454
455 if (!transfer_byte(p_spi, p_cb))
456 {
457 finish_transfer(p_cb);
458 }
459 }
460
461 NRFX_INSTANCE_IRQ_HANDLERS(SPI, spi)
462
463 #endif // NRFX_CHECK(NRFX_SPI_ENABLED)
464