xref: /nrf52832-nimble/nordic/nrfx/drivers/src/nrfx_spim.c (revision 150812a83cab50279bd772ef6db1bfaf255f2c5b)
1 /*
2  * Copyright (c) 2015 - 2018, Nordic Semiconductor ASA
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this
9  *    list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its
16  *    contributors may be used to endorse or promote products derived from this
17  *    software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <nrfx.h>
33 
34 #if NRFX_CHECK(NRFX_SPIM_ENABLED)
35 
36 #if !(NRFX_CHECK(NRFX_SPIM0_ENABLED) || NRFX_CHECK(NRFX_SPIM1_ENABLED) || \
37       NRFX_CHECK(NRFX_SPIM2_ENABLED) || NRFX_CHECK(NRFX_SPIM3_ENABLED))
38 #error "No enabled SPIM instances. Check <nrfx_config.h>."
39 #endif
40 
41 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED) && !NRFX_CHECK(NRFX_SPIM3_ENABLED)
42 #error "Extended options are available only in SPIM3 on the nRF52840 SoC."
43 #endif
44 
45 #include <nrfx_spim.h>
46 #include "prs/nrfx_prs.h"
47 #include <hal/nrf_gpio.h>
48 
49 #define NRFX_LOG_MODULE SPIM
50 #include <nrfx_log.h>
51 
52 #define SPIMX_LENGTH_VALIDATE(peripheral, drv_inst_idx, rx_len, tx_len) \
53     (((drv_inst_idx) == NRFX_CONCAT_3(NRFX_, peripheral, _INST_IDX)) && \
54      NRFX_EASYDMA_LENGTH_VALIDATE(peripheral, rx_len, tx_len))
55 
56 #if NRFX_CHECK(NRFX_SPIM0_ENABLED)
57 #define SPIM0_LENGTH_VALIDATE(...)  SPIMX_LENGTH_VALIDATE(SPIM0, __VA_ARGS__)
58 #else
59 #define SPIM0_LENGTH_VALIDATE(...)  0
60 #endif
61 
62 #if NRFX_CHECK(NRFX_SPIM1_ENABLED)
63 #define SPIM1_LENGTH_VALIDATE(...)  SPIMX_LENGTH_VALIDATE(SPIM1, __VA_ARGS__)
64 #else
65 #define SPIM1_LENGTH_VALIDATE(...)  0
66 #endif
67 
68 #if NRFX_CHECK(NRFX_SPIM2_ENABLED)
69 #define SPIM2_LENGTH_VALIDATE(...)  SPIMX_LENGTH_VALIDATE(SPIM2, __VA_ARGS__)
70 #else
71 #define SPIM2_LENGTH_VALIDATE(...)  0
72 #endif
73 
74 #if NRFX_CHECK(NRFX_SPIM3_ENABLED)
75 #define SPIM3_LENGTH_VALIDATE(...)  SPIMX_LENGTH_VALIDATE(SPIM3, __VA_ARGS__)
76 #else
77 #define SPIM3_LENGTH_VALIDATE(...)  0
78 #endif
79 
80 #define SPIM_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len)  \
81     (SPIM0_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \
82      SPIM1_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \
83      SPIM2_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len) || \
84      SPIM3_LENGTH_VALIDATE(drv_inst_idx, rx_len, tx_len))
85 
86 #if defined(NRF52840_XXAA) && (NRFX_CHECK(NRFX_SPIM3_ENABLED))
87 // Enable workaround for nRF52840 anomaly 195 (SPIM3 continues to draw current after disable).
88 #define USE_WORKAROUND_FOR_ANOMALY_195
89 #endif
90 
91 // Control block - driver instance local data.
92 typedef struct
93 {
94     nrfx_spim_evt_handler_t handler;
95     void *                  p_context;
96     nrfx_spim_evt_t         evt;  // Keep the struct that is ready for event handler. Less memcpy.
97     nrfx_drv_state_t        state;
98     volatile bool           transfer_in_progress;
99 
100 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
101     bool                    use_hw_ss;
102 #endif
103 
104     // [no need for 'volatile' attribute for the following members, as they
105     //  are not concurrently used in IRQ handlers and main line code]
106     bool            ss_active_high;
107     uint8_t         ss_pin;
108     uint8_t         miso_pin;
109     uint8_t         orc;
110 
111 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
112     size_t          tx_length;
113     size_t          rx_length;
114 #endif
115 } spim_control_block_t;
116 static spim_control_block_t m_cb[NRFX_SPIM_ENABLED_COUNT];
117 
118 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
119 
120 // Workaround for nRF52840 anomaly 198: SPIM3 transmit data might be corrupted.
121 
122 static uint32_t m_anomaly_198_preserved_value;
123 
anomaly_198_enable(uint8_t const * p_buffer,size_t buf_len)124 static void anomaly_198_enable(uint8_t const * p_buffer, size_t buf_len)
125 {
126     m_anomaly_198_preserved_value = *((volatile uint32_t *)0x40000E00);
127 
128     if (buf_len == 0)
129     {
130         return;
131     }
132     uint32_t buffer_end_addr = ((uint32_t)p_buffer) + buf_len;
133     uint32_t block_addr      = ((uint32_t)p_buffer) & ~0x1FFF;
134     uint32_t block_flag      = (1UL << ((block_addr >> 13) & 0xFFFF));
135     uint32_t occupied_blocks = 0;
136 
137     if (block_addr >= 0x20010000)
138     {
139         occupied_blocks = (1UL << 8);
140     }
141     else
142     {
143         do {
144             occupied_blocks |= block_flag;
145             block_flag <<= 1;
146             block_addr  += 0x2000;
147         } while ((block_addr < buffer_end_addr) && (block_addr < 0x20012000));
148     }
149 
150     *((volatile uint32_t *)0x40000E00) = occupied_blocks;
151 }
152 
anomaly_198_disable(void)153 static void anomaly_198_disable(void)
154 {
155     *((volatile uint32_t *)0x40000E00) = m_anomaly_198_preserved_value;
156 }
157 #endif // NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
158 
nrfx_spim_init(nrfx_spim_t const * const p_instance,nrfx_spim_config_t const * p_config,nrfx_spim_evt_handler_t handler,void * p_context)159 nrfx_err_t nrfx_spim_init(nrfx_spim_t  const * const p_instance,
160                           nrfx_spim_config_t const * p_config,
161                           nrfx_spim_evt_handler_t    handler,
162                           void                     * p_context)
163 {
164     NRFX_ASSERT(p_config);
165     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
166     nrfx_err_t err_code;
167 
168     if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
169     {
170         err_code = NRFX_ERROR_INVALID_STATE;
171         NRFX_LOG_WARNING("Function: %s, error code: %s.",
172                          __func__,
173                          NRFX_LOG_ERROR_STRING_GET(err_code));
174         return err_code;
175     }
176 
177 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
178     // Currently, only SPIM3 in nRF52840 supports the extended features.
179     // Other instances must be checked.
180     if ((p_instance->drv_inst_idx != NRFX_SPIM3_INST_IDX) &&
181         ((p_config->dcx_pin   != NRFX_SPIM_PIN_NOT_USED) ||
182          (p_config->frequency == NRF_SPIM_FREQ_16M)      ||
183          (p_config->frequency == NRF_SPIM_FREQ_32M)      ||
184          (p_config->use_hw_ss)))
185     {
186         err_code = NRFX_ERROR_NOT_SUPPORTED;
187         NRFX_LOG_WARNING("Function: %s, error code: %s.",
188                          __func__,
189                          NRFX_LOG_ERROR_STRING_GET(err_code));
190         return err_code;
191     }
192 #endif
193 
194     NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg;
195 
196 #if NRFX_CHECK(NRFX_PRS_ENABLED)
197     static nrfx_irq_handler_t const irq_handlers[NRFX_SPIM_ENABLED_COUNT] = {
198         #if NRFX_CHECK(NRFX_SPIM0_ENABLED)
199         nrfx_spim_0_irq_handler,
200         #endif
201         #if NRFX_CHECK(NRFX_SPIM1_ENABLED)
202         nrfx_spim_1_irq_handler,
203         #endif
204         #if NRFX_CHECK(NRFX_SPIM2_ENABLED)
205         nrfx_spim_2_irq_handler,
206         #endif
207         #if NRFX_CHECK(NRFX_SPIM3_ENABLED)
208         nrfx_spim_3_irq_handler,
209         #endif
210     };
211     if (nrfx_prs_acquire(p_instance->p_reg,
212             irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
213     {
214         err_code = NRFX_ERROR_BUSY;
215         NRFX_LOG_WARNING("Function: %s, error code: %s.",
216                          __func__,
217                          NRFX_LOG_ERROR_STRING_GET(err_code));
218         return err_code;
219     }
220 #endif // NRFX_CHECK(NRFX_PRS_ENABLED)
221 
222     p_cb->handler = handler;
223     p_cb->p_context = p_context;
224 
225     uint32_t mosi_pin;
226     uint32_t miso_pin;
227     // Configure pins used by the peripheral:
228     // - SCK - output with initial value corresponding with the SPI mode used:
229     //   0 - for modes 0 and 1 (CPOL = 0), 1 - for modes 2 and 3 (CPOL = 1);
230     //   according to the reference manual guidelines this pin and its input
231     //   buffer must always be connected for the SPI to work.
232     if (p_config->mode <= NRF_SPIM_MODE_1)
233     {
234         nrf_gpio_pin_clear(p_config->sck_pin);
235     }
236     else
237     {
238         nrf_gpio_pin_set(p_config->sck_pin);
239     }
240     nrf_gpio_cfg(p_config->sck_pin,
241                  NRF_GPIO_PIN_DIR_OUTPUT,
242                  NRF_GPIO_PIN_INPUT_CONNECT,
243                  NRF_GPIO_PIN_NOPULL,
244                  NRF_GPIO_PIN_S0S1,
245                  NRF_GPIO_PIN_NOSENSE);
246     // - MOSI (optional) - output with initial value 0,
247     if (p_config->mosi_pin != NRFX_SPIM_PIN_NOT_USED)
248     {
249         mosi_pin = p_config->mosi_pin;
250         nrf_gpio_pin_clear(mosi_pin);
251         nrf_gpio_cfg_output(mosi_pin);
252     }
253     else
254     {
255         mosi_pin = NRF_SPIM_PIN_NOT_CONNECTED;
256     }
257     // - MISO (optional) - input,
258     if (p_config->miso_pin != NRFX_SPIM_PIN_NOT_USED)
259     {
260         miso_pin = p_config->miso_pin;
261         nrf_gpio_cfg_input(miso_pin, (nrf_gpio_pin_pull_t)NRFX_SPIM_MISO_PULL_CFG);
262     }
263     else
264     {
265         miso_pin = NRF_SPIM_PIN_NOT_CONNECTED;
266     }
267     p_cb->miso_pin = p_config->miso_pin;
268     // - Slave Select (optional) - output with initial value 1 (inactive).
269 
270     // 'p_cb->ss_pin' variable is used during transfers to check if SS pin should be toggled,
271     // so this field needs to be initialized even if the pin is not used.
272     p_cb->ss_pin = p_config->ss_pin;
273 
274     if (p_config->ss_pin != NRFX_SPIM_PIN_NOT_USED)
275     {
276         if (p_config->ss_active_high)
277         {
278             nrf_gpio_pin_clear(p_config->ss_pin);
279         }
280         else
281         {
282             nrf_gpio_pin_set(p_config->ss_pin);
283         }
284         nrf_gpio_cfg_output(p_config->ss_pin);
285 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
286         if (p_config->use_hw_ss)
287         {
288             p_cb->use_hw_ss = p_config->use_hw_ss;
289             nrf_spim_csn_configure(p_spim,
290                                    p_config->ss_pin,
291                                    (p_config->ss_active_high == true ?
292                                         NRF_SPIM_CSN_POL_HIGH : NRF_SPIM_CSN_POL_LOW),
293                                    p_config->ss_duration);
294         }
295 #endif
296         p_cb->ss_active_high = p_config->ss_active_high;
297     }
298 
299 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
300     // - DCX (optional) - output.
301     if (p_config->dcx_pin != NRFX_SPIM_PIN_NOT_USED)
302     {
303         nrf_gpio_pin_set(p_config->dcx_pin);
304         nrf_gpio_cfg_output(p_config->dcx_pin);
305         nrf_spim_dcx_pin_set(p_spim, p_config->dcx_pin);
306     }
307 
308     // Change rx delay
309     nrf_spim_iftiming_set(p_spim, p_config->rx_delay);
310 #endif
311 
312 
313     nrf_spim_pins_set(p_spim, p_config->sck_pin, mosi_pin, miso_pin);
314     nrf_spim_frequency_set(p_spim, p_config->frequency);
315     nrf_spim_configure(p_spim, p_config->mode, p_config->bit_order);
316 
317     nrf_spim_orc_set(p_spim, p_config->orc);
318 
319     if (p_cb->handler)
320     {
321         nrf_spim_int_enable(p_spim, NRF_SPIM_INT_END_MASK);
322     }
323 
324     nrf_spim_enable(p_spim);
325 
326     if (p_cb->handler)
327     {
328         NRFX_IRQ_PRIORITY_SET(nrfx_get_irq_number(p_instance->p_reg),
329             p_config->irq_priority);
330         NRFX_IRQ_ENABLE(nrfx_get_irq_number(p_instance->p_reg));
331     }
332 
333     p_cb->transfer_in_progress = false;
334     p_cb->state = NRFX_DRV_STATE_INITIALIZED;
335 
336     err_code = NRFX_SUCCESS;
337     NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
338     return err_code;
339 }
340 
nrfx_spim_uninit(nrfx_spim_t const * const p_instance)341 void nrfx_spim_uninit(nrfx_spim_t const * const p_instance)
342 {
343     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
344     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
345 
346     if (p_cb->handler)
347     {
348         NRFX_IRQ_DISABLE(nrfx_get_irq_number(p_instance->p_reg));
349     }
350 
351     NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg;
352     if (p_cb->handler)
353     {
354         nrf_spim_int_disable(p_spim, NRF_SPIM_ALL_INTS_MASK);
355         if (p_cb->transfer_in_progress)
356         {
357             // Ensure that SPI is not performing any transfer.
358             nrf_spim_task_trigger(p_spim, NRF_SPIM_TASK_STOP);
359             while (!nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_STOPPED))
360             {}
361             p_cb->transfer_in_progress = false;
362         }
363     }
364 
365     if (p_cb->miso_pin != NRFX_SPIM_PIN_NOT_USED)
366     {
367         nrf_gpio_cfg_default(p_cb->miso_pin);
368     }
369     nrf_spim_disable(p_spim);
370 
371 #ifdef USE_WORKAROUND_FOR_ANOMALY_195
372     if (p_spim == NRF_SPIM3)
373     {
374         *(volatile uint32_t *)0x4002F004 = 1;
375     }
376 #endif
377 
378 #if NRFX_CHECK(NRFX_PRS_ENABLED)
379     nrfx_prs_release(p_instance->p_reg);
380 #endif
381 
382     p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
383 }
384 
385 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
nrfx_spim_xfer_dcx(nrfx_spim_t const * const p_instance,nrfx_spim_xfer_desc_t const * p_xfer_desc,uint32_t flags,uint8_t cmd_length)386 nrfx_err_t nrfx_spim_xfer_dcx(nrfx_spim_t const * const     p_instance,
387                               nrfx_spim_xfer_desc_t const * p_xfer_desc,
388                               uint32_t                      flags,
389                               uint8_t                       cmd_length)
390 {
391     NRFX_ASSERT(cmd_length <= NRF_SPIM_DCX_CNT_ALL_CMD);
392     nrf_spim_dcx_cnt_set((NRF_SPIM_Type *)p_instance->p_reg, cmd_length);
393     return nrfx_spim_xfer(p_instance, p_xfer_desc, 0);
394 }
395 #endif
396 
finish_transfer(spim_control_block_t * p_cb)397 static void finish_transfer(spim_control_block_t * p_cb)
398 {
399     // If Slave Select signal is used, this is the time to deactivate it.
400     if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED)
401     {
402 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
403         if (!p_cb->use_hw_ss)
404 #endif
405         {
406             if (p_cb->ss_active_high)
407             {
408                 nrf_gpio_pin_clear(p_cb->ss_pin);
409             }
410             else
411             {
412                 nrf_gpio_pin_set(p_cb->ss_pin);
413             }
414         }
415     }
416 
417     // By clearing this flag before calling the handler we allow subsequent
418     // transfers to be started directly from the handler function.
419     p_cb->transfer_in_progress = false;
420 
421     p_cb->evt.type = NRFX_SPIM_EVENT_DONE;
422     p_cb->handler(&p_cb->evt, p_cb->p_context);
423 }
424 
spim_int_enable(NRF_SPIM_Type * p_spim,bool enable)425 __STATIC_INLINE void spim_int_enable(NRF_SPIM_Type * p_spim, bool enable)
426 {
427     if (!enable)
428     {
429         nrf_spim_int_disable(p_spim, NRF_SPIM_INT_END_MASK);
430     }
431     else
432     {
433         nrf_spim_int_enable(p_spim, NRF_SPIM_INT_END_MASK);
434     }
435 }
436 
spim_list_enable_handle(NRF_SPIM_Type * p_spim,uint32_t flags)437 __STATIC_INLINE void spim_list_enable_handle(NRF_SPIM_Type * p_spim, uint32_t flags)
438 {
439     if (NRFX_SPIM_FLAG_TX_POSTINC & flags)
440     {
441         nrf_spim_tx_list_enable(p_spim);
442     }
443     else
444     {
445         nrf_spim_tx_list_disable(p_spim);
446     }
447 
448     if (NRFX_SPIM_FLAG_RX_POSTINC & flags)
449     {
450         nrf_spim_rx_list_enable(p_spim);
451     }
452     else
453     {
454         nrf_spim_rx_list_disable(p_spim);
455     }
456 }
457 
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)458 static nrfx_err_t spim_xfer(NRF_SPIM_Type               * p_spim,
459                             spim_control_block_t        * p_cb,
460                             nrfx_spim_xfer_desc_t const * p_xfer_desc,
461                             uint32_t                      flags)
462 {
463     nrfx_err_t err_code;
464     // EasyDMA requires that transfer buffers are placed in Data RAM region;
465     // signal error if they are not.
466     if ((p_xfer_desc->p_tx_buffer != NULL && !nrfx_is_in_ram(p_xfer_desc->p_tx_buffer)) ||
467         (p_xfer_desc->p_rx_buffer != NULL && !nrfx_is_in_ram(p_xfer_desc->p_rx_buffer)))
468     {
469         p_cb->transfer_in_progress = false;
470         err_code = NRFX_ERROR_INVALID_ADDR;
471         NRFX_LOG_WARNING("Function: %s, error code: %s.",
472                          __func__,
473                          NRFX_LOG_ERROR_STRING_GET(err_code));
474         return err_code;
475     }
476 
477 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
478     p_cb->tx_length = 0;
479     p_cb->rx_length = 0;
480 #endif
481 
482     nrf_spim_tx_buffer_set(p_spim, p_xfer_desc->p_tx_buffer, p_xfer_desc->tx_length);
483     nrf_spim_rx_buffer_set(p_spim, p_xfer_desc->p_rx_buffer, p_xfer_desc->rx_length);
484 
485 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
486     if (p_spim == NRF_SPIM3)
487     {
488         anomaly_198_enable(p_xfer_desc->p_tx_buffer, p_xfer_desc->tx_length);
489     }
490 #endif
491 
492     nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
493 
494     spim_list_enable_handle(p_spim, flags);
495 
496     if (!(flags & NRFX_SPIM_FLAG_HOLD_XFER))
497     {
498         nrf_spim_task_trigger(p_spim, NRF_SPIM_TASK_START);
499     }
500 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
501     if (flags & NRFX_SPIM_FLAG_HOLD_XFER)
502     {
503         nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED);
504         p_cb->tx_length = p_xfer_desc->tx_length;
505         p_cb->rx_length = p_xfer_desc->rx_length;
506         nrf_spim_tx_buffer_set(p_spim, p_xfer_desc->p_tx_buffer, 0);
507         nrf_spim_rx_buffer_set(p_spim, p_xfer_desc->p_rx_buffer, 0);
508         nrf_spim_int_enable(p_spim, NRF_SPIM_INT_STARTED_MASK);
509     }
510 #endif
511 
512     if (!p_cb->handler)
513     {
514         while (!nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_END)){}
515 
516 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
517         if (p_spim == NRF_SPIM3)
518         {
519             anomaly_198_disable();
520         }
521 #endif
522         if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED)
523         {
524 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
525             if (!p_cb->use_hw_ss)
526 #endif
527             {
528                 if (p_cb->ss_active_high)
529                 {
530                     nrf_gpio_pin_clear(p_cb->ss_pin);
531                 }
532                 else
533                 {
534                     nrf_gpio_pin_set(p_cb->ss_pin);
535                 }
536             }
537         }
538     }
539     else
540     {
541         spim_int_enable(p_spim, !(flags & NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER));
542     }
543     err_code = NRFX_SUCCESS;
544     NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
545     return err_code;
546 }
547 
nrfx_spim_xfer(nrfx_spim_t const * const p_instance,nrfx_spim_xfer_desc_t const * p_xfer_desc,uint32_t flags)548 nrfx_err_t nrfx_spim_xfer(nrfx_spim_t     const * const p_instance,
549                           nrfx_spim_xfer_desc_t const * p_xfer_desc,
550                           uint32_t                      flags)
551 {
552     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
553     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
554     NRFX_ASSERT(p_xfer_desc->p_tx_buffer != NULL || p_xfer_desc->tx_length == 0);
555     NRFX_ASSERT(p_xfer_desc->p_rx_buffer != NULL || p_xfer_desc->rx_length == 0);
556     NRFX_ASSERT(SPIM_LENGTH_VALIDATE(p_instance->drv_inst_idx,
557                                      p_xfer_desc->rx_length,
558                                      p_xfer_desc->tx_length));
559 
560     nrfx_err_t err_code = NRFX_SUCCESS;
561 
562     if (p_cb->transfer_in_progress)
563     {
564         err_code = NRFX_ERROR_BUSY;
565         NRFX_LOG_WARNING("Function: %s, error code: %s.",
566                          __func__,
567                          NRFX_LOG_ERROR_STRING_GET(err_code));
568         return err_code;
569     }
570     else
571     {
572         if (p_cb->handler && !(flags & (NRFX_SPIM_FLAG_REPEATED_XFER |
573                                         NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER)))
574         {
575             p_cb->transfer_in_progress = true;
576         }
577     }
578 
579     p_cb->evt.xfer_desc = *p_xfer_desc;
580 
581     if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED)
582     {
583 #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
584         if (!p_cb->use_hw_ss)
585 #endif
586         {
587             if (p_cb->ss_active_high)
588             {
589                 nrf_gpio_pin_set(p_cb->ss_pin);
590             }
591             else
592             {
593                 nrf_gpio_pin_clear(p_cb->ss_pin);
594             }
595         }
596     }
597 
598     return spim_xfer(p_instance->p_reg, p_cb,  p_xfer_desc, flags);
599 }
600 
nrfx_spim_abort(nrfx_spim_t const * p_instance)601 void nrfx_spim_abort(nrfx_spim_t const * p_instance)
602 {
603     spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
604     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
605 
606     nrf_spim_task_trigger(p_instance->p_reg, NRF_SPIM_TASK_STOP);
607     while (!nrf_spim_event_check(p_instance->p_reg, NRF_SPIM_EVENT_STOPPED))
608     {}
609     p_cb->transfer_in_progress = false;
610 }
611 
nrfx_spim_start_task_get(nrfx_spim_t const * p_instance)612 uint32_t nrfx_spim_start_task_get(nrfx_spim_t const * p_instance)
613 {
614     NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg;
615     return nrf_spim_task_address_get(p_spim, NRF_SPIM_TASK_START);
616 }
617 
nrfx_spim_end_event_get(nrfx_spim_t const * p_instance)618 uint32_t nrfx_spim_end_event_get(nrfx_spim_t const * p_instance)
619 {
620     NRF_SPIM_Type * p_spim = (NRF_SPIM_Type *)p_instance->p_reg;
621     return nrf_spim_event_address_get(p_spim, NRF_SPIM_EVENT_END);
622 }
623 
irq_handler(NRF_SPIM_Type * p_spim,spim_control_block_t * p_cb)624 static void irq_handler(NRF_SPIM_Type * p_spim, spim_control_block_t * p_cb)
625 {
626 
627 #if NRFX_CHECK(NRFX_SPIM_NRF52_ANOMALY_109_WORKAROUND_ENABLED)
628     if ((nrf_spim_int_enable_check(p_spim, NRF_SPIM_INT_STARTED_MASK)) &&
629         (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_STARTED)) )
630     {
631         /* Handle first, zero-length, auxiliary transmission. */
632         nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_STARTED);
633         nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
634 
635         NRFX_ASSERT(p_spim->TXD.MAXCNT == 0);
636         p_spim->TXD.MAXCNT = p_cb->tx_length;
637 
638         NRFX_ASSERT(p_spim->RXD.MAXCNT == 0);
639         p_spim->RXD.MAXCNT = p_cb->rx_length;
640 
641         /* Disable STARTED interrupt, used only in auxiliary transmission. */
642         nrf_spim_int_disable(p_spim, NRF_SPIM_INT_STARTED_MASK);
643 
644         /* Start the actual, glitch-free transmission. */
645         nrf_spim_task_trigger(p_spim, NRF_SPIM_TASK_START);
646         return;
647     }
648 #endif
649 
650     if (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_END))
651     {
652 #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
653         if (p_spim == NRF_SPIM3)
654         {
655             anomaly_198_disable();
656         }
657 #endif
658         nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
659         NRFX_ASSERT(p_cb->handler);
660         NRFX_LOG_DEBUG("Event: NRF_SPIM_EVENT_END.");
661         finish_transfer(p_cb);
662     }
663 }
664 
665 #if NRFX_CHECK(NRFX_SPIM0_ENABLED)
nrfx_spim_0_irq_handler(void)666 void nrfx_spim_0_irq_handler(void)
667 {
668     irq_handler(NRF_SPIM0, &m_cb[NRFX_SPIM0_INST_IDX]);
669 }
670 #endif
671 
672 #if NRFX_CHECK(NRFX_SPIM1_ENABLED)
nrfx_spim_1_irq_handler(void)673 void nrfx_spim_1_irq_handler(void)
674 {
675     irq_handler(NRF_SPIM1, &m_cb[NRFX_SPIM1_INST_IDX]);
676 }
677 #endif
678 
679 #if NRFX_CHECK(NRFX_SPIM2_ENABLED)
nrfx_spim_2_irq_handler(void)680 void nrfx_spim_2_irq_handler(void)
681 {
682     irq_handler(NRF_SPIM2, &m_cb[NRFX_SPIM2_INST_IDX]);
683 }
684 #endif
685 
686 #if NRFX_CHECK(NRFX_SPIM3_ENABLED)
nrfx_spim_3_irq_handler(void)687 void nrfx_spim_3_irq_handler(void)
688 {
689     irq_handler(NRF_SPIM3, &m_cb[NRFX_SPIM3_INST_IDX]);
690 }
691 #endif
692 
693 #endif // NRFX_CHECK(NRFX_SPIM_ENABLED)
694