1 /***************************************************************************//**
2 * \file cyhal_spi.c
3 *
4 * \brief
5 * Provides a high level interface for interacting with the Infineon SPI. This is
6 * a wrapper around the lower level PDL API.
7 *
8 ********************************************************************************
9 * \copyright
10 * Copyright 2018-2022 Cypress Semiconductor Corporation (an Infineon company) or
11 * an affiliate of Cypress Semiconductor Corporation
12 *
13 * SPDX-License-Identifier: Apache-2.0
14 *
15 * Licensed under the Apache License, Version 2.0 (the "License");
16 * you may not use this file except in compliance with the License.
17 * You may obtain a copy of the License at
18 *
19 * http://www.apache.org/licenses/LICENSE-2.0
20 *
21 * Unless required by applicable law or agreed to in writing, software
22 * distributed under the License is distributed on an "AS IS" BASIS,
23 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24 * See the License for the specific language governing permissions and
25 * limitations under the License.
26 *******************************************************************************/
27
28 /**
29 * \addtogroup group_hal_impl_spi SPI (Serial Peripheral Interface)
30 * \ingroup group_hal_impl
31 * \{
32 * \section section_hal_impl_spi_init_cfg Configurator-generated features limitations
33 * List of SPI personality items, which are currently not supported in SPI HAL driver on CAT1/CAT2 devices:
34 * - Modes: TI (Start Coincides), TI (Start Precedes), National Semiconductor (Microwire)
35 * - Low-level RX Interrupt sources
36 * - Low-level TX Interrupt sources
37 * - SPI Done Master interrupt source
38 * - Different data width for RX and TX
39 *
40 * \section section_hal_impl_spi_data_width Supported transfer data width options
41 * Next transfer data width options are supported by next devices:
42 * - CAT1 devices with MXSCB block version 2 and further (value of CY_IP_MXSCB_VERSION) support next data width range: 4 - 32 (included) with step 1
43 * - CAT1 devices with MXSCB block version 1 (value of CY_IP_MXSCB_VERSION) support next data width range: 4 - 16 (included) with step 1
44 * - CAT2 devices support next data width range : 4-16 (included) with step 1
45 *
46 * \} group_hal_impl_spi
47 */
48
49 #include <stdlib.h>
50 #include <string.h>
51 #include "cyhal_spi.h"
52 #include "cyhal_scb_common.h"
53 #include "cyhal_gpio.h"
54 #include "cyhal_system_impl.h"
55 #include "cyhal_hwmgr.h"
56 #include "cyhal_system.h"
57 #include "cyhal_syspm.h"
58 #include "cyhal_clock.h"
59 #include "cyhal_irq_impl.h"
60
61 #if (CYHAL_DRIVER_AVAILABLE_SPI)
62
63 #if defined(__cplusplus)
64 extern "C"
65 {
66 #endif
67
68 #define _CYHAL_SPI_DEFAULT_SPEED 100000
69
70 #define _CYHAL_SPI_WAIT_OP_RD_BUSY 1
71 #define _CYHAL_SPI_WAIT_OP_RD_NOT_BUSY 2
72 #define _CYHAL_SPI_WAIT_OP_WR 3
73 #define _CYHAL_SPI_WAIT_OP_VALID(op) ((op) > 0 && (op) <= _CYHAL_SPI_WAIT_OP_WR)
74
75 #define _CYHAL_SPI_OVERSAMPLE_MIN 4
76 #define _CYHAL_SPI_OVERSAMPLE_MAX 16
77 #define _CYHAL_SPI_SSEL_NUM 4
78
79 #define _CYHAL_SPI_PENDING_NONE 0
80 #define _CYHAL_SPI_PENDING_RX 1
81 #define _CYHAL_SPI_PENDING_TX 2
82 #define _CYHAL_SPI_PENDING_TX_RX 3
83
84 #define _CYHAL_SPI_SSEL_ACTIVATE true
85 #define _CYHAL_SPI_SSEL_DEACTIVATE false
86
87
88 /* Default SPI configuration */
89 static const cy_stc_scb_spi_config_t _cyhal_spi_default_config =
90 {
91 .spiMode = CY_SCB_SPI_MASTER,
92 .subMode = CY_SCB_SPI_MOTOROLA,
93 .sclkMode = CY_SCB_SPI_CPHA0_CPOL0,
94 #if defined (COMPONENT_CAT2) || (CY_IP_MXSCB_VERSION >= 3) || (CY_IP_MXS22SCB_VERSION >= 1)
95 .parity = CY_SCB_SPI_PARITY_NONE,
96 .dropOnParityError = false,
97 #endif /* defined (COMPONENT_CAT2) || (CY_IP_MXSCB_VERSION >= 3) */
98 .oversample = _CYHAL_SPI_OVERSAMPLE_MIN,
99 .rxDataWidth = 8,
100 .txDataWidth = 8,
101 .enableMsbFirst = true,
102 .enableFreeRunSclk = false,
103 .enableInputFilter = false,
104 #if (CY_IP_MXSCB_VERSION >= 3) || (CY_IP_MXS22SCB_VERSION >= 1)
105 /* Setting this to true leads to incorrect slave communication */
106 .enableMisoLateSample = false,
107 #else
108 .enableMisoLateSample = true,
109 #endif
110 .enableTransferSeperation = false,
111 .enableWakeFromSleep = false,
112 .ssPolarity = CY_SCB_SPI_ACTIVE_LOW,
113 #if defined (COMPONENT_CAT2) || (CY_IP_MXSCB_VERSION >= 3) || (CY_IP_MXS22SCB_VERSION >= 1)
114 .ssSetupDelay = false,
115 .ssHoldDelay = false,
116 #endif /* defined (COMPONENT_CAT2) || (CY_IP_MXSCB_VERSION >= 3) || (CY_IP_MXS22SCB_VERSION >= 1) */
117 #if defined (COMPONENT_CAT1) && ((CY_IP_MXSCB_VERSION >= 3) || (CY_IP_MXS22SCB_VERSION >= 1))
118 .ssInterFrameDelay = false,
119 #elif defined (COMPONENT_CAT2)
120 .ssInterDataframeDelay = false,
121 #endif /* defined (COMPONENT_CAT1) && ((CY_IP_MXSCB_VERSION >= 3) || (CY_IP_MXS22SCB_VERSION >= 1)) or defined (COMPONENT_CAT2) */
122 .rxFifoTriggerLevel = 0,
123 .rxFifoIntEnableMask = 0,
124 .txFifoTriggerLevel = 0,
125 .txFifoIntEnableMask = 0,
126 .masterSlaveIntEnableMask = 0
127 };
128
129 /* The PDL clears the IRQ status during Cy_SCB_SPI_Interrupt which prevents _cyhal_scb_get_irq_obj()
130 * from working properly in _cyhal_spi_cb_wrapper on devices with muxed IRQs, because they can't tell
131 * at that point which system IRQ caused the CPU IRQ. So we need to save this value at the beginning of the
132 * IRQ handler when we are able to determine what it is */
133 static volatile cyhal_spi_t* _cyhal_spi_irq_obj = NULL;
134
135 static void _cyhal_ssel_switch_state(cyhal_spi_t *obj, uint8_t ssel_idx, bool ssel_activate);
136
_cyhal_spi_int_frequency(cyhal_spi_t * obj,uint32_t hz,uint8_t * over_sample_val)137 static cy_rslt_t _cyhal_spi_int_frequency(cyhal_spi_t *obj, uint32_t hz, uint8_t *over_sample_val)
138 {
139 CY_ASSERT(NULL != obj);
140 cy_rslt_t result = CY_RSLT_SUCCESS;
141 uint8_t oversample_value;
142 uint32_t divider_value;
143 uint32_t last_diff = 0xFFFFFFFFU;
144 uint8_t last_ovrsmpl_val = 0;
145 uint32_t last_dvdr_val = 0;
146 uint32_t oversampled_freq = 0;
147 uint32_t divided_freq = 0;
148 uint32_t diff = 0;
149
150 uint32_t peri_freq = _cyhal_utils_get_peripheral_clock_frequency(&(obj->resource));
151 if (!obj->is_slave)
152 {
153 for (oversample_value = _CYHAL_SPI_OVERSAMPLE_MIN; oversample_value <= _CYHAL_SPI_OVERSAMPLE_MAX; oversample_value++)
154 {
155 oversampled_freq = hz * oversample_value;
156 if ((hz * oversample_value > peri_freq) && (_CYHAL_SPI_OVERSAMPLE_MIN == oversample_value))
157 {
158 return CYHAL_SPI_RSLT_CLOCK_ERROR;
159 }
160 else if (hz * oversample_value > peri_freq)
161 {
162 continue;
163 }
164
165 divider_value = _cyhal_utils_divider_value(&(obj->resource), hz * oversample_value, 0);
166 #if defined(COMPONENT_CAT5)
167 if(!_cyhal_clock_is_divider_valid(&(obj->resource), divider_value))
168 {
169 continue;
170 }
171 #endif
172 divided_freq = peri_freq / divider_value;
173 diff = (oversampled_freq > divided_freq)
174 ? oversampled_freq - divided_freq
175 : divided_freq - oversampled_freq;
176
177 if (diff < last_diff)
178 {
179 last_diff = diff;
180 last_ovrsmpl_val = oversample_value;
181 last_dvdr_val = divider_value;
182 if (0 == diff)
183 {
184 break;
185 }
186 }
187 }
188 *over_sample_val = last_ovrsmpl_val;
189 }
190 else
191 {
192 /* Slave requires such frequency: required_frequency = N / ((0.5 * desired_period) – 20 nsec - tDSI,
193 * N is 3 when "Enable Input Glitch Filter" is false and 4 when true.
194 * tDSI Is external master delay which is assumed to be 16.66 nsec */
195
196 /* Divided by 2 desired period to avoid dividing in required_frequency formula */
197 float desired_period_us_divided = 5e5f * (1 / (float)hz);
198 uint32_t required_frequency = (uint32_t)(3e6f / (desired_period_us_divided - 36.66f / 1e3f));
199
200 if (required_frequency > peri_freq)
201 {
202 return CYHAL_SPI_RSLT_CLOCK_ERROR;
203 }
204
205 /* Use maximum available clock for slave to make it able to work with any master environment */
206 #if defined(COMPONENT_CAT5)
207 /* On CAT5, frequency is set to (hz * oversample). Set to max oversample so the slave can match any master equal or slower
208 * than it. On other devices, last_dvdr_val is set to 1 to minimize the divider thus max the frequency, to the same effect. */
209 last_ovrsmpl_val = _CYHAL_SPI_OVERSAMPLE_MAX;
210 CY_UNUSED_PARAMETER(last_dvdr_val);
211 #else
212 last_dvdr_val = 1;
213 CY_UNUSED_PARAMETER(last_ovrsmpl_val);
214 #endif
215 }
216
217 #if defined (COMPONENT_CAT5)
218 if (last_ovrsmpl_val == 0)
219 {
220 result = CYHAL_SPI_RSLT_ERR_CFG_NOT_SUPPORTED;
221 }
222 else
223 {
224 _cyhal_utils_peri_pclk_disable_divider(_cyhal_scb_get_clock_index(obj->resource.block_num), &(obj->clock));
225 result = _cyhal_utils_peri_pclk_set_freq(_cyhal_scb_get_clock_index(obj->resource.block_num), &(obj->clock), hz, last_ovrsmpl_val);
226 if (CY_RSLT_SUCCESS == result)
227 {
228 _cyhal_utils_peri_pclk_enable_divider(_cyhal_scb_get_clock_index(obj->resource.block_num), &(obj->clock));
229 }
230 }
231 #else
232 result = cyhal_clock_set_enabled(&(obj->clock), false, false);
233 if (result == CY_RSLT_SUCCESS)
234 {
235 result = cyhal_clock_set_divider(&(obj->clock), last_dvdr_val);
236 }
237 if (result == CY_RSLT_SUCCESS)
238 {
239 result = cyhal_clock_set_enabled(&(obj->clock), true, false);
240 }
241 #endif
242
243 return result;
244 }
245
_cyhal_spi_convert_interrupt_cause(uint32_t pdl_cause)246 static inline cyhal_spi_event_t _cyhal_spi_convert_interrupt_cause(uint32_t pdl_cause)
247 {
248 static const uint32_t status_map[] =
249 {
250 (uint32_t)CYHAL_SPI_IRQ_ERROR, // Default error if unknown value is set
251 (uint32_t)CYHAL_SPI_IRQ_DATA_IN_FIFO, // CY_SCB_SPI_TRANSFER_IN_FIFO_EVENT
252 (uint32_t)CYHAL_SPI_IRQ_DONE, // CY_SCB_SPI_TRANSFER_CMPLT_EVENT
253 (uint32_t)CYHAL_SPI_IRQ_ERROR, // CY_SCB_SPI_TRANSFER_ERR_EVENT
254 };
255 return (cyhal_spi_event_t)_cyhal_utils_convert_flags(status_map, sizeof(status_map) / sizeof(uint32_t), pdl_cause);
256 }
257
258 #if defined (COMPONENT_CAT5)
_cyhal_spi_irq_handler(_cyhal_system_irq_t irqn)259 static void _cyhal_spi_irq_handler(_cyhal_system_irq_t irqn)
260 #else
261 static void _cyhal_spi_irq_handler(void)
262 #endif
263 {
264 /* Save the old value and store it aftewards in case we get into a nested IRQ situation */
265 /* Safe to cast away volatile because we don't expect this pointer to be changed while we're in here, they
266 * just might change where the original pointer points */
267 cyhal_spi_t* old_irq_obj = (cyhal_spi_t*)_cyhal_spi_irq_obj;
268 #if defined (COMPONENT_CAT5)
269 _cyhal_spi_irq_obj = (cyhal_spi_t*) _cyhal_scb_get_irq_obj(irqn);
270 #else
271 _cyhal_spi_irq_obj = (cyhal_spi_t*) _cyhal_scb_get_irq_obj();
272 #endif
273 cyhal_spi_t* obj = (cyhal_spi_t*)_cyhal_spi_irq_obj;
274
275 if (NULL == obj)
276 {
277 return;
278 }
279
280 Cy_SCB_SPI_Interrupt(obj->base, &(obj->context));
281
282 if (!obj->is_async)
283 {
284 return;
285 }
286
287 if (0 == (Cy_SCB_SPI_GetTransferStatus(obj->base, &obj->context) & CY_SCB_SPI_TRANSFER_ACTIVE))
288 {
289 if (NULL != obj->tx_buffer)
290 {
291 /* Start TX Transfer */
292 obj->pending = _CYHAL_SPI_PENDING_TX;
293 const uint8_t *buf = obj->tx_buffer;
294 obj->tx_buffer = NULL;
295
296 Cy_SCB_SPI_Transfer(obj->base, (uint8_t *)buf, NULL, obj->tx_buffer_size, &obj->context);
297 }
298 else if (NULL != obj->rx_buffer)
299 {
300 /* Start RX Transfer */
301 obj->pending = _CYHAL_SPI_PENDING_RX;
302 uint8_t *rx_buf = obj->rx_buffer;
303 uint8_t *tx_buf;
304 size_t trx_size = obj->rx_buffer_size;
305
306 if (obj->rx_buffer_size > 1)
307 {
308 /* In this case we don't have a transmit buffer; we only have a receive buffer. While the PDL
309 * is fine with passing NULL for transmit, we don't get to control what data it is sending in
310 * that case, which we allowed the user to set. To honor the user's request, we reuse the rx
311 * buffer as the tx buffer too. We set all bytes beyond the one we will start filling in with
312 * the user provided 'write_fill'. This means the tx buffer is 1 element smaller than the rx
313 * buffer. As a result, we must therefore transfer 1 less element then we really want to in
314 * this transfer. When this transfer is complete, it will call into this again to receive the
315 * final element.
316 */
317 trx_size -= 1; // Transfer everything left except for the last byte
318
319 uint8_t **rx_buffer_p = (uint8_t **) &obj->rx_buffer;
320
321 tx_buf = *rx_buffer_p + 1; // Start at second byte to avoid trying to transmit and receive the same byte
322 memset(tx_buf, obj->write_fill, trx_size);
323
324 *rx_buffer_p += trx_size; // Move to 1 byte before end
325 obj->rx_buffer_size = 1; // Transfer the last byte on the next interrupt
326 }
327 else
328 {
329 tx_buf = &obj->write_fill;
330
331 obj->rx_buffer = NULL;
332 }
333
334 Cy_SCB_SPI_Transfer(obj->base, tx_buf, rx_buf, trx_size, &obj->context);
335 }
336 else
337 {
338 /* Finish Async Transfer */
339 obj->pending = _CYHAL_SPI_PENDING_NONE;
340 obj->is_async = false;
341 _cyhal_ssel_switch_state(obj, obj->active_ssel, _CYHAL_SPI_SSEL_DEACTIVATE);
342 }
343 }
344
345 _cyhal_spi_irq_obj = old_irq_obj;
346 }
347
348 #if defined (COMPONENT_CAT5)
_cyhal_spi0_irq_handler(void)349 static void _cyhal_spi0_irq_handler(void)
350 {
351 _cyhal_spi_irq_handler(scb_0_interrupt_IRQn);
352 Cy_SCB_EnableInterrupt(SCB0);
353 }
354
_cyhal_spi1_irq_handler(void)355 static void _cyhal_spi1_irq_handler(void)
356 {
357 _cyhal_spi_irq_handler(scb_1_interrupt_IRQn);
358 Cy_SCB_EnableInterrupt(SCB1);
359 }
360
_cyhal_spi2_irq_handler(void)361 static void _cyhal_spi2_irq_handler(void)
362 {
363 _cyhal_spi_irq_handler(scb_2_interrupt_IRQn);
364 Cy_SCB_EnableInterrupt(SCB2);
365 }
366
367 static CY_SCB_IRQ_THREAD_CB_t _cyhal_irq_cb[3] = {_cyhal_spi0_irq_handler, _cyhal_spi1_irq_handler, _cyhal_spi2_irq_handler};
368 #endif
369
_cyhal_spi_cb_wrapper(uint32_t event)370 static void _cyhal_spi_cb_wrapper(uint32_t event)
371 {
372 /* Safe to cast away volatile because we don't expect this pointer to be changed while we're in here, they
373 * just might change where the original pointer points */
374 cyhal_spi_t *obj = (cyhal_spi_t*)_cyhal_spi_irq_obj;
375 cyhal_spi_event_t anded_events = (cyhal_spi_event_t) (obj->irq_cause & (uint32_t) _cyhal_spi_convert_interrupt_cause(event));
376
377 // Don't call the callback until the final transfer has put everything in the FIFO/completed
378 if ((anded_events & (CYHAL_SPI_IRQ_DATA_IN_FIFO | CYHAL_SPI_IRQ_DONE)) && !(obj->rx_buffer == NULL && obj->tx_buffer == NULL))
379 {
380 return;
381 }
382
383 if (anded_events)
384 {
385 /* Indicates read/write operations will be in a callback */
386 obj->op_in_callback = true;
387 cyhal_spi_event_callback_t callback = (cyhal_spi_event_callback_t) obj->callback_data.callback;
388 callback(obj->callback_data.callback_arg, anded_events);
389 obj->op_in_callback = false;
390 }
391 }
392
_cyhal_convert_mode_sclk(cyhal_spi_mode_t mode)393 static cy_en_scb_spi_sclk_mode_t _cyhal_convert_mode_sclk(cyhal_spi_mode_t mode)
394 {
395 uint8_t sclk_mode = (mode & (CYHAL_SPI_MODE_FLAG_CPOL | CYHAL_SPI_MODE_FLAG_CPHA));
396
397 switch (sclk_mode)
398 {
399 case CYHAL_SPI_MODE_FLAG_CPOL | CYHAL_SPI_MODE_FLAG_CPHA:
400 return (CY_SCB_SPI_CPHA1_CPOL1);
401 case CYHAL_SPI_MODE_FLAG_CPOL:
402 return (CY_SCB_SPI_CPHA0_CPOL1);
403 case CYHAL_SPI_MODE_FLAG_CPHA:
404 return (CY_SCB_SPI_CPHA1_CPOL0);
405 default:
406 return (CY_SCB_SPI_CPHA0_CPOL0);
407 }
408 }
409
_is_cyhal_mode_msb(cyhal_spi_mode_t mode)410 static inline bool _is_cyhal_mode_msb(cyhal_spi_mode_t mode)
411 {
412 return ((mode & CYHAL_SPI_MODE_FLAG_LSB) != CYHAL_SPI_MODE_FLAG_LSB);
413 }
414
_cyhal_spi_mode_pdl_to_hal(const cy_stc_scb_spi_config_t * pdl_cfg)415 static cyhal_spi_mode_t _cyhal_spi_mode_pdl_to_hal(const cy_stc_scb_spi_config_t *pdl_cfg)
416 {
417 cy_en_scb_spi_sclk_mode_t clk_mode = pdl_cfg->sclkMode;
418 return (cyhal_spi_mode_t)(CYHAL_SPI_MODE(
419 ((uint8_t)((clk_mode == CY_SCB_SPI_CPHA0_CPOL1) || (clk_mode == CY_SCB_SPI_CPHA1_CPOL1))),
420 ((uint8_t)((clk_mode == CY_SCB_SPI_CPHA1_CPOL0) || (clk_mode == CY_SCB_SPI_CPHA1_CPOL1))),
421 ((uint8_t) !pdl_cfg->enableMsbFirst)));
422 }
423
_cyhal_spi_pm_callback_instance(void * obj_ptr,cyhal_syspm_callback_state_t state,cy_en_syspm_callback_mode_t pdl_mode)424 static bool _cyhal_spi_pm_callback_instance(void *obj_ptr, cyhal_syspm_callback_state_t state, cy_en_syspm_callback_mode_t pdl_mode)
425 {
426 cyhal_spi_t *obj = (cyhal_spi_t *)obj_ptr;
427 bool allow = true;
428 cy_stc_syspm_callback_params_t spi_callback_params = {
429 .base = (void *) (obj->base),
430 .context = (void *) &(obj->context)
431 };
432
433 if ((CYHAL_SYSPM_CB_CPU_DEEPSLEEP == state) || (CYHAL_SYSPM_CB_CPU_DEEPSLEEP_RAM == state))
434 allow = (CY_SYSPM_SUCCESS == Cy_SCB_SPI_DeepSleepCallback(&spi_callback_params, pdl_mode));
435 #if defined(COMPONENT_CAT1A) || defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1D)
436 else if (CYHAL_SYSPM_CB_SYSTEM_HIBERNATE == state)
437 allow = (CY_SYSPM_SUCCESS == Cy_SCB_SPI_HibernateCallback(&spi_callback_params, pdl_mode));
438 #endif
439
440 return allow;
441 }
442
_cyhal_spi_get_ssel_map_idx(cyhal_gpio_t ssel,const cyhal_resource_pin_mapping_t ** ssel_map,uint8_t * idx,const cyhal_resource_inst_t * target_blk)443 static cy_rslt_t _cyhal_spi_get_ssel_map_idx(cyhal_gpio_t ssel, const cyhal_resource_pin_mapping_t **ssel_map,
444 uint8_t *idx, const cyhal_resource_inst_t *target_blk)
445 {
446 static const cyhal_resource_pin_mapping_t *ssel_s_pin_maps[] = {
447 #if defined(CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_S_SELECT0)
448 cyhal_pin_map_scb_spi_s_select0,
449 #endif
450 #if defined(CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_S_SELECT1)
451 cyhal_pin_map_scb_spi_s_select1,
452 #endif
453 #if defined(CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_S_SELECT2)
454 cyhal_pin_map_scb_spi_s_select2,
455 #endif
456 #if defined(CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_S_SELECT3)
457 cyhal_pin_map_scb_spi_s_select3
458 #endif
459 };
460 static const size_t ssel_s_pin_maps_sizes_bytes[] = {
461 #if defined(CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_S_SELECT0)
462 sizeof(cyhal_pin_map_scb_spi_s_select0),
463 #endif
464 #if defined(CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_S_SELECT1)
465 sizeof(cyhal_pin_map_scb_spi_s_select1),
466 #endif
467 #if defined(CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_S_SELECT2)
468 sizeof(cyhal_pin_map_scb_spi_s_select2),
469 #endif
470 #if defined(CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_S_SELECT3)
471 sizeof(cyhal_pin_map_scb_spi_s_select3)
472 #endif
473 };
474
475 for (uint8_t i = 0; i < sizeof(ssel_s_pin_maps) / sizeof(ssel_s_pin_maps[0]); i++)
476 {
477 *ssel_map = _cyhal_scb_find_map(ssel, ssel_s_pin_maps[i],
478 ssel_s_pin_maps_sizes_bytes[i] / sizeof(cyhal_resource_pin_mapping_t), target_blk);
479 if (NULL != *ssel_map)
480 {
481 *idx = i;
482 return CY_RSLT_SUCCESS;
483 }
484 }
485 return CYHAL_SPI_RSLT_ERR_CANNOT_CONFIG_SSEL;
486 }
487
_cyhal_spi_pol_from_hal_to_pdl(cyhal_spi_ssel_polarity_t hal_polarity)488 static inline cy_en_scb_spi_polarity_t _cyhal_spi_pol_from_hal_to_pdl(cyhal_spi_ssel_polarity_t hal_polarity)
489 {
490 return (hal_polarity == CYHAL_SPI_SSEL_ACTIVE_HIGH) ? CY_SCB_SPI_ACTIVE_HIGH : CY_SCB_SPI_ACTIVE_LOW;
491 }
492
_cyhal_spi_ssel_config(cyhal_spi_t * obj,cyhal_gpio_t ssel,cyhal_spi_ssel_polarity_t polarity,bool reserve_n_connect)493 static cy_rslt_t _cyhal_spi_ssel_config(cyhal_spi_t *obj, cyhal_gpio_t ssel,
494 cyhal_spi_ssel_polarity_t polarity, bool reserve_n_connect)
495 {
496 cy_rslt_t result = CYHAL_SPI_RSLT_ERR_CANNOT_CONFIG_SSEL;
497 uint8_t found_idx = 0;
498 bool configuring_existing = false;
499 if ((NC != ssel) && (_CYHAL_SPI_PENDING_NONE == obj->pending))
500 {
501 for (uint8_t i = 0; i < _CYHAL_SPI_SSEL_NUM; i++)
502 {
503 if ((configuring_existing = (ssel == obj->pin_ssel[i])))
504 {
505 result = CY_RSLT_SUCCESS;
506 found_idx = i;
507 break;
508 }
509 if (!obj->is_slave)
510 {
511 /* Looking for first available ssel slot */
512 if ((NC == obj->pin_ssel[i]))
513 {
514 result = reserve_n_connect ? cyhal_gpio_init(ssel, CYHAL_GPIO_DIR_OUTPUT, CYHAL_GPIO_DRIVE_STRONG,
515 (polarity == CYHAL_SPI_SSEL_ACTIVE_LOW) ? true : false) : CY_RSLT_SUCCESS;
516 found_idx = i;
517 break;
518 }
519 }
520 }
521 if (!configuring_existing && (obj->is_slave))
522 {
523 const cyhal_resource_pin_mapping_t *ssel_map = NULL;
524 if (CY_RSLT_SUCCESS == _cyhal_spi_get_ssel_map_idx(ssel, &ssel_map, &found_idx, &(obj->resource)))
525 {
526 /* Ensure the block_num and channel_num for ssel matches the block_num and channel_num of the SPI resource */
527 if ((NULL != ssel_map) && (NC == obj->pin_ssel[found_idx]) &&
528 (ssel_map->block_num == obj->resource.block_num) &&
529 (ssel_map->channel_num == obj->resource.channel_num))
530 {
531 result = reserve_n_connect
532 ? _cyhal_utils_reserve_and_connect(ssel_map, (uint8_t)CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_S_SELECT0)
533 : CY_RSLT_SUCCESS;
534 }
535 }
536 }
537 if (CY_RSLT_SUCCESS == result)
538 {
539 if (!configuring_existing)
540 obj->pin_ssel[found_idx] = ssel;
541 obj->ssel_pol[found_idx] = _cyhal_spi_pol_from_hal_to_pdl(polarity);
542
543 /* Immediately apply updated slave select polarity */
544 Cy_SCB_SPI_SetActiveSlaveSelectPolarity(obj->base, (cy_en_scb_spi_slave_select_t)found_idx, obj->ssel_pol[found_idx]);
545 if (!obj->is_slave)
546 {
547 _cyhal_ssel_switch_state(obj, found_idx, _CYHAL_SPI_SSEL_DEACTIVATE);
548 }
549 }
550 }
551 return result;
552 }
553
554 /* Wait untill SPI is busy for some time (timeout > 0) or no wait (timeout == 0). */
_cyhal_spi_wait_for_op(cyhal_spi_t * obj,uint8_t op,uint32_t * timeout)555 static cy_rslt_t _cyhal_spi_wait_for_op(cyhal_spi_t *obj, uint8_t op, uint32_t* timeout)
556 {
557 CY_ASSERT(_CYHAL_SPI_WAIT_OP_VALID(op));
558
559 cy_rslt_t result = CY_RSLT_SUCCESS;
560 uint32_t timeout_us = _CYHAL_UTILS_US_PER_MS;
561 bool op_condition = true;
562
563 if (!(obj->op_in_callback) && *timeout > 0)
564 {
565 while (op_condition && *timeout > 0)
566 {
567 switch (op)
568 {
569 case _CYHAL_SPI_WAIT_OP_RD_BUSY:
570 op_condition = (cyhal_spi_readable(obj) == 0 && !cyhal_spi_is_busy(obj));
571 break;
572 case _CYHAL_SPI_WAIT_OP_RD_NOT_BUSY:
573 op_condition = (cyhal_spi_readable(obj) == 0 || cyhal_spi_is_busy(obj));
574 break;
575 case _CYHAL_SPI_WAIT_OP_WR:
576 op_condition = ((cyhal_spi_writable(obj) < Cy_SCB_GetFifoSize(obj->base)) || cyhal_spi_is_busy(obj));
577 break;
578 default:
579 op_condition = false;
580 break;
581 }
582
583 if (timeout_us > 0)
584 {
585 cyhal_system_delay_us(_CYHAL_UTILS_ONE_TIME_UNIT);
586 --timeout_us;
587 }
588 else
589 {
590 timeout_us = _CYHAL_UTILS_US_PER_MS;
591 (*timeout)--;
592 }
593 }
594 result = (*timeout > 0) ? CY_RSLT_SUCCESS : CYHAL_SPI_RSLT_WARN_TIMEOUT;
595 }
596 return result;
597 }
598
_cyhal_spi_setup_resources(cyhal_spi_t * obj,cyhal_gpio_t mosi,cyhal_gpio_t miso,cyhal_gpio_t sclk,cyhal_gpio_t ssel,const cyhal_clock_t * clk,uint32_t ssPolarity)599 static cy_rslt_t _cyhal_spi_setup_resources(cyhal_spi_t *obj, cyhal_gpio_t mosi, cyhal_gpio_t miso, cyhal_gpio_t sclk, cyhal_gpio_t ssel,
600 const cyhal_clock_t *clk, uint32_t ssPolarity)
601 {
602 cy_rslt_t result = CY_RSLT_SUCCESS;
603
604 obj->resource.type = CYHAL_RSC_INVALID;
605 obj->pending = _CYHAL_SPI_PENDING_NONE;
606 obj->write_fill = (uint8_t) CY_SCB_SPI_DEFAULT_TX;
607 obj->oversample_value = _CYHAL_SPI_OVERSAMPLE_MIN;
608
609 obj->pin_mosi = NC;
610 obj->pin_miso = NC;
611 obj->pin_sclk = NC;
612
613 uint32_t saved_intr_status = cyhal_system_critical_section_enter();
614
615 // pins_blocks will contain bit representation of blocks, that are connected to specified pin
616 // 1 block - 1 bit, so, for example, pin_blocks = 0x00000006 means that certain pin
617 // can belong to next non-reserved blocks SCB2 and SCB1
618 uint32_t pins_blocks = _CYHAL_SCB_AVAILABLE_BLOCKS_MASK;
619 uint8_t found_block_idx = 0;
620 if (obj->is_slave)
621 {
622 if (NC != sclk)
623 {
624 pins_blocks &= _CYHAL_SCB_CHECK_AFFILIATION(sclk, cyhal_pin_map_scb_spi_s_clk);
625 }
626 if (NC != miso)
627 {
628 pins_blocks &= _CYHAL_SCB_CHECK_AFFILIATION(miso, cyhal_pin_map_scb_spi_s_miso);
629 }
630 if (NC != mosi)
631 {
632 pins_blocks &= _CYHAL_SCB_CHECK_AFFILIATION(mosi, cyhal_pin_map_scb_spi_s_mosi);
633 }
634 if (NC != ssel)
635 {
636 uint32_t ss_pins_blocks = 0;
637
638 #ifdef CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_S_SELECT0
639 ss_pins_blocks |= _CYHAL_SCB_CHECK_AFFILIATION(ssel, cyhal_pin_map_scb_spi_s_select0);
640 #endif /* (CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_S_SELECT0) */
641
642 #ifdef CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_S_SELECT1
643 ss_pins_blocks |= _CYHAL_SCB_CHECK_AFFILIATION(ssel, cyhal_pin_map_scb_spi_s_select1);
644 #endif /* (CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_S_SELECT1) */
645
646 #ifdef CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_S_SELECT2
647 ss_pins_blocks |= _CYHAL_SCB_CHECK_AFFILIATION(ssel, cyhal_pin_map_scb_spi_s_select2);
648 #endif /* (CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_S_SELECT2) */
649
650 #ifdef CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_S_SELECT3
651 ss_pins_blocks |= _CYHAL_SCB_CHECK_AFFILIATION(ssel, cyhal_pin_map_scb_spi_s_select3);
652 #endif /* (CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_S_SELECT3) */
653
654 pins_blocks &= ss_pins_blocks;
655 }
656 }
657 else
658 {
659 if (NC != sclk)
660 {
661 pins_blocks &= _CYHAL_SCB_CHECK_AFFILIATION(sclk, cyhal_pin_map_scb_spi_m_clk);
662 }
663 if (NC != miso)
664 {
665 pins_blocks &= _CYHAL_SCB_CHECK_AFFILIATION(miso, cyhal_pin_map_scb_spi_m_miso);
666 }
667 if (NC != mosi)
668 {
669 pins_blocks &= _CYHAL_SCB_CHECK_AFFILIATION(mosi, cyhal_pin_map_scb_spi_m_mosi);
670 }
671 /* No need to check SSEL for SPI master as the SS pin can be any */
672 }
673
674 if (0 == pins_blocks)
675 {
676 // One (or more) pin does not belong to any SCB instance or all corresponding SCB instances
677 // are reserved
678 result = CYHAL_SPI_RSLT_ERR_INVALID_PIN;
679 }
680 else
681 {
682 while(((pins_blocks >> found_block_idx) & 0x1) == 0)
683 {
684 found_block_idx++;
685 }
686 }
687
688 /* Get pin configurations */
689 const cyhal_resource_pin_mapping_t *mosi_map = NULL;
690 const cyhal_resource_pin_mapping_t *miso_map = NULL;
691 const cyhal_resource_pin_mapping_t *sclk_map = NULL;
692 const cyhal_resource_pin_mapping_t *ssel_map = NULL;
693 uint8_t mosi_dm = 0, miso_dm = 0, sclk_dm = 0;
694
695 const cyhal_resource_inst_t default_spi_inst = { CYHAL_RSC_SCB, found_block_idx, 0 };
696 const cyhal_resource_inst_t* spi_inst_p = &default_spi_inst;
697
698 if (CY_RSLT_SUCCESS == result)
699 {
700 if (obj->is_slave)
701 {
702 mosi_map = _CYHAL_SCB_FIND_MAP_BLOCK(mosi, cyhal_pin_map_scb_spi_s_mosi, spi_inst_p);
703 miso_map = _CYHAL_SCB_FIND_MAP_BLOCK(miso, cyhal_pin_map_scb_spi_s_miso, spi_inst_p);
704 sclk_map = _CYHAL_SCB_FIND_MAP_BLOCK(sclk, cyhal_pin_map_scb_spi_s_clk, spi_inst_p);
705 mosi_dm = (uint8_t)CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_S_MOSI;
706 miso_dm = (uint8_t)CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_S_MISO;
707 sclk_dm = (uint8_t)CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_S_CLK;
708 result = _cyhal_spi_get_ssel_map_idx(ssel, &ssel_map, &obj->active_ssel, spi_inst_p);
709 }
710 else
711 {
712 mosi_map = _CYHAL_SCB_FIND_MAP_BLOCK(mosi, cyhal_pin_map_scb_spi_m_mosi, spi_inst_p);
713 miso_map = _CYHAL_SCB_FIND_MAP_BLOCK(miso, cyhal_pin_map_scb_spi_m_miso, spi_inst_p);
714 sclk_map = _CYHAL_SCB_FIND_MAP_BLOCK(sclk, cyhal_pin_map_scb_spi_m_clk, spi_inst_p);
715 mosi_dm = (uint8_t)CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_M_MOSI;
716 miso_dm = (uint8_t)CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_M_MISO;
717 sclk_dm = (uint8_t)CYHAL_PIN_MAP_DRIVE_MODE_SCB_SPI_M_CLK;
718 /* No need to find maps for ssel pins, as GPIO used */
719 }
720
721 const cyhal_resource_pin_mapping_t *base_map = (NC != mosi)
722 ? (mosi_map != NULL ? mosi_map : NULL)
723 : (miso_map != NULL ? miso_map : NULL);
724
725 /* Validate pins mapping */
726 if((NC != mosi) || (NC != miso))
727 {
728 if (NULL == base_map ||
729 ((NC != mosi) && ((NULL == mosi_map) || !_cyhal_utils_map_resources_equal(base_map, mosi_map))) ||
730 ((NC != miso) && ((NULL == miso_map) || !_cyhal_utils_map_resources_equal(base_map, miso_map))) ||
731 ((NC != sclk) && ((NULL == sclk_map) || !_cyhal_utils_map_resources_equal(base_map, sclk_map))) ||
732 ((obj->is_slave) && ((NC != ssel) && ((NULL == ssel_map) || !_cyhal_utils_map_resources_equal(base_map, ssel_map)))))
733 {
734 result = CYHAL_SPI_RSLT_ERR_INVALID_PIN;
735 }
736 }
737 }
738
739 if (CY_RSLT_SUCCESS == result)
740 {
741 if (false == obj->dc_configured)
742 {
743 cyhal_resource_inst_t rsc_to_reserve = { CYHAL_RSC_SCB, _cyhal_scb_get_block_index(spi_inst_p->block_num), 0 };
744 result = cyhal_hwmgr_reserve(&rsc_to_reserve);
745 }
746 }
747
748 cyhal_system_critical_section_exit(saved_intr_status);
749
750 if (CY_RSLT_SUCCESS == result)
751 {
752 obj->resource = *spi_inst_p;
753 uint8_t scb_arr_index = _cyhal_scb_get_block_index(obj->resource.block_num);
754 obj->base = _CYHAL_SCB_BASE_ADDRESSES[scb_arr_index];
755 #if defined(COMPONENT_CAT5)
756 // Check if either clock hasn't been provided thus not initialized (clock == NULL), or the user has not yet
757 // set the clock frequency (which enables it).
758 if(clk == NULL)
759 {
760 result = _cyhal_utils_allocate_clock(&(obj->clock), &(obj->resource), CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT, true);
761 obj->alloc_clock = true;
762 result = _cyhal_spi_int_frequency(obj, _CYHAL_SPI_DEFAULT_SPEED, &obj->oversample_value);
763 }
764 if((clk != NULL) && (_cyhal_utils_peri_pclk_get_freq(0, clk) == 0))
765 {
766 obj->clock = *clk;
767 obj->alloc_clock = false;
768 result = _cyhal_spi_int_frequency(obj, _CYHAL_SPI_DEFAULT_SPEED, &obj->oversample_value);
769 }
770 #endif
771 }
772
773 // reserve the MOSI pin
774 if (result == CY_RSLT_SUCCESS)
775 {
776 if (NC != mosi)
777 {
778 if (false == obj->dc_configured)
779 {
780 result = _cyhal_utils_reserve_and_connect(mosi_map, mosi_dm);
781 }
782 if (result == CY_RSLT_SUCCESS)
783 {
784 obj->pin_mosi = mosi;
785 }
786 }
787 }
788
789 // reserve the MISO pin
790 if (result == CY_RSLT_SUCCESS)
791 {
792 if (NC != miso)
793 {
794 if (false == obj->dc_configured)
795 {
796 result = _cyhal_utils_reserve_and_connect(miso_map, miso_dm);
797 }
798 if (result == CY_RSLT_SUCCESS)
799 {
800 obj->pin_miso = miso;
801 }
802 }
803 }
804
805 // reserve the SCLK pin
806 if (result == CY_RSLT_SUCCESS)
807 {
808 if (NC != sclk)
809 {
810 if (false == obj->dc_configured)
811 {
812 result = _cyhal_utils_reserve_and_connect(sclk_map, sclk_dm);
813 }
814 if (result == CY_RSLT_SUCCESS)
815 {
816 obj->pin_sclk = sclk;
817 }
818 }
819 }
820
821 // reserve and configure the SSEL pin
822 if ((result == CY_RSLT_SUCCESS) && (NC != ssel))
823 {
824 result = _cyhal_spi_ssel_config(obj, ssel,
825 (cyhal_spi_ssel_polarity_t)((ssPolarity >> obj->active_ssel) & 0x1), !obj->dc_configured);
826 }
827
828 #if !defined(COMPONENT_CAT5)
829 // Already handled above for CAT5
830 if (result == CY_RSLT_SUCCESS)
831 {
832 if (clk == NULL)
833 {
834 result = _cyhal_utils_allocate_clock(&(obj->clock), &(obj->resource), CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT, true);
835 obj->alloc_clock = true;
836 }
837 else
838 {
839 obj->clock = *clk;
840 obj->alloc_clock = false;
841
842 /* Per CDT 315848 and 002-20730 Rev. *E:
843 * For SPI, an integer clock divider must be used for both master and slave. */
844 if ((_CYHAL_PERIPHERAL_GROUP_GET_DIVIDER_TYPE(obj->clock.block) == (cy_en_divider_types_t)CYHAL_CLOCK_BLOCK_PERIPHERAL_16_5BIT) ||
845 (_CYHAL_PERIPHERAL_GROUP_GET_DIVIDER_TYPE(obj->clock.block) == (cy_en_divider_types_t)CYHAL_CLOCK_BLOCK_PERIPHERAL_24_5BIT))
846 {
847 result = CYHAL_SPI_RSLT_CLOCK_NOT_SUPPORTED;
848 }
849 }
850 }
851 #endif
852 if (result == CY_RSLT_SUCCESS)
853 {
854 result = _cyhal_utils_peri_pclk_assign_divider(_cyhal_scb_get_clock_index(obj->resource.block_num), &(obj->clock));
855
856 if ((result == CY_RSLT_SUCCESS) && obj->alloc_clock)
857 {
858 result = _cyhal_spi_int_frequency(obj, _CYHAL_SPI_DEFAULT_SPEED, &obj->oversample_value);
859 }
860 }
861
862 return result;
863 }
864
_cyhal_spi_init_hw(cyhal_spi_t * obj,cy_stc_scb_spi_config_t * cfg)865 static cy_rslt_t _cyhal_spi_init_hw(cyhal_spi_t *obj, cy_stc_scb_spi_config_t *cfg)
866 {
867 cy_rslt_t result = CY_RSLT_SUCCESS;
868
869 _cyhal_scb_update_instance_data(obj->resource.block_num, (void*)obj, &_cyhal_spi_pm_callback_instance);
870 if ((false != obj->dc_configured) || !(obj->alloc_clock))
871 {
872 obj->oversample_value = cfg->oversample;
873 }
874 obj->data_bits = cfg->txDataWidth;
875 obj->msb_first = cfg->enableMsbFirst;
876 obj->clk_mode = cfg->sclkMode;
877 obj->mode = (uint8_t) _cyhal_spi_mode_pdl_to_hal(cfg);
878
879 result = (cy_rslt_t)Cy_SCB_SPI_Init(obj->base, cfg, &(obj->context));
880
881 if (result == CY_RSLT_SUCCESS)
882 {
883 /* Activating specified by user ssel after init */
884 if (NC != obj->pin_ssel[obj->active_ssel])
885 {
886 result = cyhal_spi_select_active_ssel(obj, obj->pin_ssel[obj->active_ssel]);
887 }
888 }
889
890 if (result == CY_RSLT_SUCCESS)
891 {
892 uint8_t scb_arr_index = _cyhal_scb_get_block_index(obj->resource.block_num);
893
894 obj->callback_data.callback = NULL;
895 obj->callback_data.callback_arg = NULL;
896 obj->irq_cause = 0;
897
898 #if defined (COMPONENT_CAT5)
899 Cy_SCB_RegisterInterruptCallback(obj->base, _cyhal_irq_cb[obj->resource.block_num]);
900 Cy_SCB_EnableInterrupt(obj->base);
901 #endif
902
903 _cyhal_irq_register(_CYHAL_SCB_IRQ_N[scb_arr_index], CYHAL_ISR_PRIORITY_DEFAULT, (cy_israddress)_cyhal_spi_irq_handler );
904 _cyhal_irq_enable(_CYHAL_SCB_IRQ_N[scb_arr_index]);
905 Cy_SCB_SPI_Enable(obj->base);
906 }
907 else
908 {
909 cyhal_spi_free(obj);
910 }
911 return result;
912 }
913
cyhal_spi_init(cyhal_spi_t * obj,cyhal_gpio_t mosi,cyhal_gpio_t miso,cyhal_gpio_t sclk,cyhal_gpio_t ssel,const cyhal_clock_t * clk,uint8_t bits,cyhal_spi_mode_t mode,bool is_slave)914 cy_rslt_t cyhal_spi_init(cyhal_spi_t *obj, cyhal_gpio_t mosi, cyhal_gpio_t miso, cyhal_gpio_t sclk, cyhal_gpio_t ssel,
915 const cyhal_clock_t *clk, uint8_t bits, cyhal_spi_mode_t mode, bool is_slave)
916 {
917 CY_ASSERT(NULL != obj);
918 memset(obj, 0, sizeof(cyhal_spi_t));
919
920 cy_stc_scb_spi_config_t driver_config = _cyhal_spi_default_config;
921 driver_config.spiMode = is_slave == 0
922 ? CY_SCB_SPI_MASTER
923 : CY_SCB_SPI_SLAVE;
924 driver_config.enableMsbFirst = _is_cyhal_mode_msb(mode);
925 driver_config.sclkMode = _cyhal_convert_mode_sclk(mode);
926 driver_config.rxDataWidth = bits;
927 driver_config.txDataWidth = bits;
928 driver_config.ssPolarity = ((CY_SCB_SPI_ACTIVE_LOW << CY_SCB_SPI_SLAVE_SELECT0) | \
929 (CY_SCB_SPI_ACTIVE_LOW << CY_SCB_SPI_SLAVE_SELECT1) | \
930 (CY_SCB_SPI_ACTIVE_LOW << CY_SCB_SPI_SLAVE_SELECT2) | \
931 (CY_SCB_SPI_ACTIVE_LOW << CY_SCB_SPI_SLAVE_SELECT3));
932
933 cy_rslt_t result = CY_RSLT_SUCCESS;
934
935 // Explicitly marked not allocated resources as invalid to prevent freeing them.
936 for (uint8_t i = 0; i < _CYHAL_SPI_SSEL_NUM; i++)
937 {
938 obj->pin_ssel[i] = NC;
939 obj->ssel_pol[i] = CY_SCB_SPI_ACTIVE_LOW;
940 }
941
942 obj->active_ssel = 0;
943 obj->is_slave = is_slave;
944
945 result = _cyhal_spi_setup_resources(obj, mosi, miso, sclk, ssel, clk, driver_config.ssPolarity);
946
947 if (result == CY_RSLT_SUCCESS)
948 {
949 result = _cyhal_spi_init_hw(obj, &driver_config);
950 }
951 else
952 {
953 cyhal_spi_free(obj);
954 }
955 return result;
956 }
957
cyhal_spi_init_cfg(cyhal_spi_t * obj,const cyhal_spi_configurator_t * cfg)958 cy_rslt_t cyhal_spi_init_cfg(cyhal_spi_t *obj, const cyhal_spi_configurator_t *cfg)
959 {
960 CY_ASSERT(NULL != obj);
961 CY_ASSERT(NULL != cfg);
962 CY_ASSERT(NULL != cfg->config);
963
964 memset(obj, 0, sizeof(cyhal_spi_t));
965
966 obj->dc_configured = (NULL != cfg->resource);
967 cy_stc_scb_spi_config_t cfg_local = *cfg->config;
968
969 if (obj->dc_configured &&
970 ((cfg_local.subMode != CY_SCB_SPI_MOTOROLA) ||
971 (cfg_local.rxFifoIntEnableMask != 0) ||
972 (cfg_local.txFifoIntEnableMask != 0) ||
973 (cfg_local.masterSlaveIntEnableMask != 0) ||
974 (cfg_local.rxDataWidth != cfg_local.txDataWidth)))
975 {
976 /* Next SPI personality (device configurator) items are NOT supported by SPI HAL:
977 - Modes: TI (Start Coincides), TI (Start Precedes), National Semiconductor (Microwire)
978 - Low-level RX Interrupt sources
979 - Low-level TX Interrupt sources
980 - SPI Done Master interrupt source
981 - Different data width for RX and TX
982 */
983 return CYHAL_SPI_RSLT_ERR_CFG_NOT_SUPPORTED;
984 }
985
986 cy_rslt_t result = CY_RSLT_SUCCESS;
987 bool is_slave = (cfg_local.spiMode == CY_SCB_SPI_SLAVE);
988
989 // Explicitly marked not allocated resources as invalid to prevent freeing them.
990 for (uint8_t i = 0; i < _CYHAL_SPI_SSEL_NUM; i++)
991 {
992 obj->pin_ssel[i] = NC;
993 obj->ssel_pol[i] = CY_SCB_SPI_ACTIVE_LOW;
994 }
995
996 obj->resource = *cfg->resource;
997 uint8_t scb_arr_index = _cyhal_scb_get_block_index(obj->resource.block_num);
998 obj->base = _CYHAL_SCB_BASE_ADDRESSES[scb_arr_index];
999
1000 obj->active_ssel = 0;
1001 obj->is_slave = is_slave;
1002 obj->write_fill = (uint8_t) CY_SCB_SPI_DEFAULT_TX;
1003
1004 //Copy pins from configurator object
1005 obj->pin_mosi = cfg->gpios.mosi;
1006 obj->pin_miso = cfg->gpios.miso;
1007 obj->pin_sclk = cfg->gpios.sclk;
1008 for (size_t ssel_idx = 0; ssel_idx < sizeof(cfg->gpios.ssel) / sizeof(cfg->gpios.ssel[0]); ++ssel_idx)
1009 {
1010 if (NC != cfg->gpios.ssel[ssel_idx])
1011 {
1012 obj->pin_ssel[ssel_idx] = cfg->gpios.ssel[ssel_idx];
1013 obj->active_ssel = ssel_idx;
1014 result = _cyhal_spi_ssel_config(obj, obj->pin_ssel[ssel_idx],
1015 (cyhal_spi_ssel_polarity_t)((obj->ssel_pol[ssel_idx] >> obj->active_ssel) & 0x1), !obj->dc_configured);
1016 break;
1017 }
1018 }
1019
1020
1021 #if !defined(COMPONENT_CAT5)
1022 if (result == CY_RSLT_SUCCESS)
1023 {
1024 if (cfg->clock == NULL)
1025 {
1026 result = _cyhal_utils_allocate_clock(&(obj->clock), &(obj->resource), CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT, true);
1027 obj->alloc_clock = true;
1028
1029 if (result == CY_RSLT_SUCCESS)
1030 {
1031 result = _cyhal_utils_peri_pclk_assign_divider(_cyhal_scb_get_clock_index(obj->resource.block_num), &(obj->clock));
1032 }
1033
1034 if (result == CY_RSLT_SUCCESS)
1035 {
1036 result = _cyhal_spi_int_frequency(obj, _CYHAL_SPI_DEFAULT_SPEED, &obj->oversample_value);
1037 }
1038 }
1039 else
1040 {
1041 obj->clock = *cfg->clock;
1042 obj->alloc_clock = false;
1043
1044 /* Per CDT 315848 and 002-20730 Rev. *E:
1045 * For SPI, an integer clock divider must be used for both master and slave. */
1046 if ((_CYHAL_PERIPHERAL_GROUP_GET_DIVIDER_TYPE(obj->clock.block) == (cy_en_divider_types_t)CYHAL_CLOCK_BLOCK_PERIPHERAL_16_5BIT) ||
1047 (_CYHAL_PERIPHERAL_GROUP_GET_DIVIDER_TYPE(obj->clock.block) == (cy_en_divider_types_t)CYHAL_CLOCK_BLOCK_PERIPHERAL_24_5BIT))
1048 {
1049 result = CYHAL_SPI_RSLT_CLOCK_NOT_SUPPORTED;
1050 }
1051 }
1052 }
1053 #endif
1054
1055 if( result == CY_RSLT_SUCCESS)
1056 {
1057 result = _cyhal_spi_init_hw(obj, &cfg_local);
1058 }
1059
1060 /* Configuring rest of provided ssel signals */
1061 size_t ssel_idx = obj->active_ssel;
1062 while ((result == CY_RSLT_SUCCESS) && ((ssel_idx + 1) < sizeof(cfg->gpios.ssel) / sizeof(cfg->gpios.ssel[0])))
1063 {
1064 ++ssel_idx;
1065 if (NC != cfg->gpios.ssel[ssel_idx])
1066 {
1067 result = _cyhal_spi_ssel_config(obj, cfg->gpios.ssel[ssel_idx],
1068 (cyhal_spi_ssel_polarity_t)((cfg->config->ssPolarity >> ssel_idx) & 0x1),
1069 !obj->dc_configured);
1070 }
1071 }
1072 if(result != CY_RSLT_SUCCESS)
1073 {
1074 cyhal_spi_free(obj);
1075 }
1076 return result;
1077 }
1078
cyhal_spi_free(cyhal_spi_t * obj)1079 void cyhal_spi_free(cyhal_spi_t *obj)
1080 {
1081 if (NULL != obj->base)
1082 {
1083 _cyhal_scb_update_instance_data(obj->resource.block_num, NULL, NULL);
1084 Cy_SCB_SPI_Disable(obj->base, NULL);
1085 Cy_SCB_SPI_DeInit(obj->base);
1086 obj->base = NULL;
1087 }
1088
1089 if (obj->resource.type != CYHAL_RSC_INVALID)
1090 {
1091 uint8_t scb_arr_index = _cyhal_scb_get_block_index(obj->resource.block_num);
1092 _cyhal_system_irq_t irqn = _CYHAL_SCB_IRQ_N[scb_arr_index];
1093 _cyhal_irq_free(irqn);
1094
1095 if (false == obj->dc_configured)
1096 {
1097 cyhal_resource_inst_t rsc_to_free = { CYHAL_RSC_SCB, _cyhal_scb_get_block_index(obj->resource.block_num), obj->resource.channel_num };
1098 cyhal_hwmgr_free(&(rsc_to_free));
1099 }
1100 obj->resource.type = CYHAL_RSC_INVALID;
1101 }
1102
1103 if (false == obj->dc_configured)
1104 {
1105 _cyhal_utils_release_if_used(&(obj->pin_miso));
1106 _cyhal_utils_release_if_used(&(obj->pin_mosi));
1107 _cyhal_utils_release_if_used(&(obj->pin_sclk));
1108 for (uint8_t i = 0; i < _CYHAL_SPI_SSEL_NUM; i++)
1109 {
1110 #if defined(COMPONENT_CAT5)
1111 if(obj->is_slave == false)
1112 {
1113 // In master mode, we have reserved this via cyhal_gpio_init which logs it as reserved
1114 // in cyhal_gpio.c static arrays. Need to free it similarly to mark it unreserved
1115
1116 // Potential side effects: gpio free also unregisters any callback and disconnects the pin.
1117 // If this becomes problematic, add new gpio free_btss function to unset those arrays
1118 cyhal_gpio_free((obj->pin_ssel[i]));
1119 }
1120 else
1121 #endif
1122 {
1123 _cyhal_utils_release_if_used(&(obj->pin_ssel[i]));
1124 }
1125 }
1126 }
1127
1128 if (obj->alloc_clock)
1129 {
1130 cyhal_clock_free(&(obj->clock));
1131 obj->alloc_clock = false;
1132 }
1133 }
1134
_cyhal_ssel_switch_state(cyhal_spi_t * obj,uint8_t ssel_idx,bool ssel_activate)1135 static void _cyhal_ssel_switch_state(cyhal_spi_t *obj, uint8_t ssel_idx, bool ssel_activate)
1136 {
1137 if ((!obj->is_slave) && (CYHAL_NC_PIN_VALUE != obj->pin_ssel[ssel_idx]))
1138 {
1139 /* Situations described:
1140 * ssel_activate = true (need to set SSEL into active state)
1141 * CY_SCB_SPI_ACTIVE_LOW - writing 0 to ssel pin
1142 * CY_SCB_SPI_ACTIVE_HIGH - writing 1 to ssel pin
1143 * ssel_activate = false (need to set SSEL into inactive state)
1144 * CY_SCB_SPI_ACTIVE_LOW - writing 1 to ssel pin
1145 * CY_SCB_SPI_ACTIVE_HIGH - writing 0 to ssel pin */
1146 bool ssel_state = (CY_SCB_SPI_ACTIVE_LOW == obj->ssel_pol[ssel_idx]) ? !ssel_activate : ssel_activate;
1147 cyhal_gpio_write(obj->pin_ssel[ssel_idx], ssel_state);
1148 }
1149 }
1150
cyhal_spi_set_frequency(cyhal_spi_t * obj,uint32_t hz)1151 cy_rslt_t cyhal_spi_set_frequency(cyhal_spi_t *obj, uint32_t hz)
1152 {
1153 cy_rslt_t result = CY_RSLT_SUCCESS;
1154 cy_rslt_t scb_init_result = CY_RSLT_SUCCESS;
1155 uint8_t ovr_sample_val;
1156
1157 if (NULL == obj)
1158 {
1159 return CYHAL_SPI_RSLT_BAD_ARGUMENT;
1160 }
1161
1162 /* HAL is allowed to change clock settings since it owns the clock */
1163 if (obj->alloc_clock)
1164 {
1165 Cy_SCB_SPI_Disable(obj->base, &obj->context);
1166 result = _cyhal_spi_int_frequency(obj, hz, &ovr_sample_val);
1167
1168 /* No need to reconfigure slave since oversample value, that was changed in _cyhal_spi_int_frequency, in slave is ignored */
1169 if ((CY_RSLT_SUCCESS == result) && !obj->is_slave && (obj->oversample_value != ovr_sample_val))
1170 {
1171 cy_stc_scb_spi_config_t config_structure = _cyhal_spi_default_config;
1172 Cy_SCB_SPI_DeInit(obj->base);
1173 config_structure.spiMode = obj->is_slave == false
1174 ? CY_SCB_SPI_MASTER
1175 : CY_SCB_SPI_SLAVE;
1176 config_structure.enableMsbFirst = obj->msb_first;
1177 config_structure.sclkMode = obj->clk_mode;
1178 config_structure.rxDataWidth = obj->data_bits;
1179 config_structure.txDataWidth = obj->data_bits;
1180 config_structure.oversample = ovr_sample_val;
1181 obj->oversample_value = ovr_sample_val;
1182 scb_init_result = (cy_rslt_t)Cy_SCB_SPI_Init(obj->base, &config_structure, &(obj->context));
1183 }
1184 if(CY_RSLT_SUCCESS == scb_init_result)
1185 {
1186 Cy_SCB_SPI_Enable(obj->base);
1187 }
1188 }
1189 else
1190 {
1191 result = CYHAL_SPI_RSLT_CLOCK_ERROR;
1192 }
1193
1194 return result;
1195 }
1196
cyhal_spi_select_active_ssel(cyhal_spi_t * obj,cyhal_gpio_t ssel)1197 cy_rslt_t cyhal_spi_select_active_ssel(cyhal_spi_t *obj, cyhal_gpio_t ssel)
1198 {
1199 CY_ASSERT(NULL != obj);
1200 CY_ASSERT(NULL != obj->base);
1201
1202 // If all obj->pin_ssel[] = NC then return Error code
1203 bool nc_flag = true;
1204 for (uint8_t ssel_idx = 0; ssel_idx < _CYHAL_SPI_SSEL_NUM; ssel_idx++)
1205 {
1206 if(obj->pin_ssel[ssel_idx] != NC)
1207 {
1208 nc_flag = false;
1209 break;
1210 }
1211 }
1212
1213 if(nc_flag)
1214 {
1215 return CYHAL_SPI_RSLT_ERR_CANNOT_SWITCH_SSEL;
1216 }
1217
1218 if ((NC != ssel) && (_CYHAL_SPI_PENDING_NONE == obj->pending))
1219 {
1220 for (uint8_t i = 0; i < _CYHAL_SPI_SSEL_NUM; i++)
1221 {
1222 if(obj->pin_ssel[i] == ssel)
1223 {
1224 Cy_SCB_SPI_SetActiveSlaveSelect(obj->base, (cy_en_scb_spi_slave_select_t)i);
1225 obj->active_ssel = i;
1226 return CY_RSLT_SUCCESS;
1227 }
1228 }
1229 }
1230 return CYHAL_SPI_RSLT_ERR_CANNOT_SWITCH_SSEL;
1231 }
1232
cyhal_spi_slave_select_config(cyhal_spi_t * obj,cyhal_gpio_t ssel,cyhal_spi_ssel_polarity_t polarity)1233 cy_rslt_t cyhal_spi_slave_select_config(cyhal_spi_t *obj, cyhal_gpio_t ssel, cyhal_spi_ssel_polarity_t polarity)
1234 {
1235 CY_ASSERT(NULL != obj);
1236 return _cyhal_spi_ssel_config(obj, ssel, polarity, true);
1237 }
1238
cyhal_spi_recv(cyhal_spi_t * obj,uint32_t * value)1239 cy_rslt_t cyhal_spi_recv(cyhal_spi_t *obj, uint32_t *value)
1240 {
1241 if (NULL == obj)
1242 return CYHAL_SPI_RSLT_BAD_ARGUMENT;
1243
1244 if (_cyhal_scb_pm_transition_pending())
1245 return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
1246
1247 uint32_t read_value = CY_SCB_SPI_RX_NO_DATA;
1248 const uint32_t fill_in = 0xffffffffUL; /* PDL Fill in value */
1249 uint32_t count = 0;
1250
1251 if (!obj->is_slave)
1252 {
1253 _cyhal_ssel_switch_state(obj, obj->active_ssel, _CYHAL_SPI_SSEL_ACTIVATE);
1254
1255 /* Clear FIFOs */
1256 Cy_SCB_SPI_ClearTxFifo(obj->base);
1257 Cy_SCB_SPI_ClearRxFifo(obj->base);
1258
1259 while (count == 0)
1260 {
1261 count = Cy_SCB_SPI_Write(obj->base, fill_in);
1262 }
1263
1264 while (Cy_SCB_SPI_IsTxComplete(obj->base) == false) { }
1265 while (Cy_SCB_SPI_GetNumInRxFifo(obj->base) == 0) { } /* Wait for RX FIFO not empty */
1266 _cyhal_ssel_switch_state(obj, obj->active_ssel, _CYHAL_SPI_SSEL_DEACTIVATE);
1267 }
1268
1269 while (read_value == CY_SCB_SPI_RX_NO_DATA)
1270 {
1271 read_value = Cy_SCB_SPI_Read(obj->base);
1272 }
1273 *value = read_value;
1274 return CY_RSLT_SUCCESS;
1275 }
1276
cyhal_spi_send(cyhal_spi_t * obj,uint32_t value)1277 cy_rslt_t cyhal_spi_send(cyhal_spi_t *obj, uint32_t value)
1278 {
1279 if (NULL == obj)
1280 return CYHAL_SPI_RSLT_BAD_ARGUMENT;
1281
1282 if (_cyhal_scb_pm_transition_pending())
1283 return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
1284
1285 uint32_t count = 0;
1286 cy_rslt_t result = CY_RSLT_SUCCESS;
1287
1288 if (!obj->is_slave)
1289 {
1290 _cyhal_ssel_switch_state(obj, obj->active_ssel, _CYHAL_SPI_SSEL_ACTIVATE);
1291
1292 /* Clear FIFOs */
1293 Cy_SCB_SPI_ClearTxFifo(obj->base);
1294 Cy_SCB_SPI_ClearRxFifo(obj->base);
1295 }
1296
1297 while (count == 0)
1298 {
1299 count = Cy_SCB_SPI_Write(obj->base, value);
1300 }
1301
1302 if (!obj->is_slave)
1303 {
1304 while (Cy_SCB_SPI_IsTxComplete(obj->base) == false) { }
1305 while (Cy_SCB_SPI_GetNumInRxFifo(obj->base) == 0) { } /* Wait for RX FIFO not empty */
1306 _cyhal_ssel_switch_state(obj, obj->active_ssel, _CYHAL_SPI_SSEL_DEACTIVATE);
1307 (void)Cy_SCB_SPI_Read(obj->base);
1308 }
1309
1310 return result;
1311 }
1312
1313
cyhal_spi_slave_read(cyhal_spi_t * obj,uint8_t * dst_buff,uint16_t * size,uint32_t timeout)1314 cy_rslt_t cyhal_spi_slave_read(cyhal_spi_t *obj, uint8_t *dst_buff, uint16_t *size, uint32_t timeout)
1315 {
1316 cy_rslt_t status = CYHAL_SPI_RSLT_BAD_ARGUMENT;
1317
1318 if ((dst_buff != NULL) && (size != NULL))
1319 {
1320 /* Wait until the master start writing or any data will be in the slave RX buffer */
1321 status = _cyhal_spi_wait_for_op(obj, _CYHAL_SPI_WAIT_OP_RD_NOT_BUSY, &timeout);
1322
1323 if (CY_RSLT_SUCCESS == status)
1324 {
1325 /* Wait until the master finish writing */
1326 status = _cyhal_spi_wait_for_op(obj, _CYHAL_SPI_WAIT_OP_RD_BUSY, &timeout);
1327 }
1328
1329 if (CY_RSLT_SUCCESS == status)
1330 {
1331 *size = _CYHAL_SCB_BYTES_TO_COPY(cyhal_spi_readable(obj), *size);
1332 *size = Cy_SCB_SPI_ReadArray(obj->base, (void*)dst_buff, (uint32_t)*size);
1333 }
1334 }
1335 return status;
1336 }
1337
cyhal_spi_slave_write(cyhal_spi_t * obj,const uint8_t * src_buff,uint16_t * size,uint32_t timeout)1338 cy_rslt_t cyhal_spi_slave_write(cyhal_spi_t *obj, const uint8_t *src_buff, uint16_t *size, uint32_t timeout)
1339 {
1340 cy_rslt_t status = CYHAL_SPI_RSLT_BAD_ARGUMENT;
1341
1342 if ((src_buff != NULL) && (size != NULL))
1343 {
1344 status = cyhal_spi_transfer_async(obj, src_buff, (size_t)*size, NULL, 0U);
1345
1346 if (CY_RSLT_SUCCESS == status)
1347 {
1348 /* Wait until the slave finish writing */
1349 status = _cyhal_spi_wait_for_op(obj, _CYHAL_SPI_WAIT_OP_WR, &timeout);
1350 }
1351 }
1352 return status;
1353 }
1354
cyhal_spi_transfer(cyhal_spi_t * obj,const uint8_t * tx,size_t tx_length,uint8_t * rx,size_t rx_length,uint8_t write_fill)1355 cy_rslt_t cyhal_spi_transfer(cyhal_spi_t *obj, const uint8_t *tx, size_t tx_length, uint8_t *rx, size_t rx_length, uint8_t write_fill)
1356 {
1357 if (NULL == obj)
1358 return CYHAL_SPI_RSLT_BAD_ARGUMENT;
1359
1360 if (_cyhal_scb_pm_transition_pending())
1361 return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
1362
1363 obj->write_fill = write_fill;
1364 cy_rslt_t rslt = cyhal_spi_transfer_async(obj, tx, tx_length, rx, rx_length);
1365 if (rslt == CY_RSLT_SUCCESS)
1366 {
1367 while (obj->pending != _CYHAL_SPI_PENDING_NONE) { } /* Wait for async transfer to complete */
1368 }
1369 obj->write_fill = (uint8_t) CY_SCB_SPI_DEFAULT_TX;
1370 return rslt;
1371 }
1372
cyhal_spi_transfer_async(cyhal_spi_t * obj,const uint8_t * tx,size_t tx_length,uint8_t * rx,size_t rx_length)1373 cy_rslt_t cyhal_spi_transfer_async(cyhal_spi_t *obj, const uint8_t *tx, size_t tx_length, uint8_t *rx, size_t rx_length)
1374 {
1375 if (NULL == obj)
1376 return CYHAL_SPI_RSLT_BAD_ARGUMENT;
1377
1378 if (_cyhal_scb_pm_transition_pending())
1379 return CYHAL_SYSPM_RSLT_ERR_PM_PENDING;
1380
1381 cy_en_scb_spi_status_t spi_status;
1382
1383 _cyhal_ssel_switch_state(obj, obj->active_ssel, _CYHAL_SPI_SSEL_ACTIVATE);
1384 obj->is_async = true;
1385
1386 uint8_t arr_size_modifier = 0;
1387 if (obj->data_bits <= 8)
1388 {
1389 arr_size_modifier = 1;
1390 }
1391 else if (obj->data_bits <= 16)
1392 {
1393 arr_size_modifier = 2;
1394 }
1395 else
1396 {
1397 arr_size_modifier = 4;
1398 }
1399
1400
1401 /* Setup transfer */
1402 if (tx_length > rx_length)
1403 {
1404 if (rx_length > 0)
1405 {
1406 /* I) write + read, II) write only */
1407 obj->pending = _CYHAL_SPI_PENDING_TX_RX;
1408 obj->rx_buffer = NULL;
1409
1410 obj->tx_buffer = tx + (rx_length * arr_size_modifier);
1411 obj->tx_buffer_size = tx_length - rx_length;
1412
1413 tx_length = rx_length; // Use tx_length to store entire transfer length
1414 }
1415 else
1416 {
1417 /* I) write only */
1418 obj->pending = _CYHAL_SPI_PENDING_TX;
1419 obj->rx_buffer = NULL;
1420 obj->tx_buffer = NULL;
1421
1422 rx = NULL;
1423 }
1424 }
1425 else if (rx_length > tx_length)
1426 {
1427 if (tx_length > 0)
1428 {
1429 /* I) write + read, II) read only */
1430 obj->pending = _CYHAL_SPI_PENDING_TX_RX;
1431 obj->tx_buffer = NULL;
1432
1433 obj->rx_buffer = rx + (tx_length * arr_size_modifier);
1434 obj->rx_buffer_size = rx_length - tx_length;
1435 }
1436 else
1437 {
1438 /* I) read only. */
1439 obj->pending = _CYHAL_SPI_PENDING_RX;
1440 obj->tx_buffer = NULL;
1441
1442 obj->rx_buffer = rx_length > 1 ? rx + 1 : NULL;
1443 obj->rx_buffer_size = rx_length - 1;
1444 tx = &obj->write_fill;
1445 tx_length = 1;
1446 }
1447 }
1448 else
1449 {
1450 /* RX and TX of the same size: I) write + read. */
1451 obj->pending = _CYHAL_SPI_PENDING_TX_RX;
1452 obj->rx_buffer = NULL;
1453 obj->tx_buffer = NULL;
1454 }
1455 spi_status = Cy_SCB_SPI_Transfer(obj->base, (void *)tx, rx, tx_length, &obj->context);
1456 return spi_status == CY_SCB_SPI_SUCCESS
1457 ? CY_RSLT_SUCCESS
1458 : CYHAL_SPI_RSLT_TRANSFER_ERROR;
1459 }
1460
cyhal_spi_is_busy(cyhal_spi_t * obj)1461 bool cyhal_spi_is_busy(cyhal_spi_t *obj)
1462 {
1463 return Cy_SCB_SPI_IsBusBusy(obj->base) || (_CYHAL_SPI_PENDING_NONE != obj->pending);
1464 }
1465
cyhal_spi_abort_async(cyhal_spi_t * obj)1466 cy_rslt_t cyhal_spi_abort_async(cyhal_spi_t *obj)
1467 {
1468 if (NULL == obj)
1469 {
1470 return CYHAL_SPI_RSLT_BAD_ARGUMENT;
1471 }
1472
1473 Cy_SCB_SPI_AbortTransfer(obj->base, &(obj->context));
1474 obj->pending = _CYHAL_SPI_PENDING_NONE;
1475 return CY_RSLT_SUCCESS;
1476 }
1477
cyhal_spi_register_callback(cyhal_spi_t * obj,cyhal_spi_event_callback_t callback,void * callback_arg)1478 void cyhal_spi_register_callback(cyhal_spi_t *obj, cyhal_spi_event_callback_t callback, void *callback_arg)
1479 {
1480 uint32_t savedIntrStatus = cyhal_system_critical_section_enter();
1481 obj->callback_data.callback = (cy_israddress) callback;
1482 obj->callback_data.callback_arg = callback_arg;
1483 cyhal_system_critical_section_exit(savedIntrStatus);
1484 Cy_SCB_SPI_RegisterCallback(obj->base, _cyhal_spi_cb_wrapper, &(obj->context));
1485
1486 obj->irq_cause = 0;
1487 }
1488
cyhal_spi_enable_event(cyhal_spi_t * obj,cyhal_spi_event_t event,uint8_t intr_priority,bool enable)1489 void cyhal_spi_enable_event(cyhal_spi_t *obj, cyhal_spi_event_t event, uint8_t intr_priority, bool enable)
1490 {
1491 if (enable)
1492 {
1493 obj->irq_cause |= event;
1494 }
1495 else
1496 {
1497 obj->irq_cause &= ~event;
1498 }
1499
1500 uint8_t scb_arr_index = _cyhal_scb_get_block_index(obj->resource.block_num);
1501 _cyhal_system_irq_t irqn = _CYHAL_SCB_IRQ_N[scb_arr_index];
1502 _cyhal_irq_set_priority(irqn, intr_priority);
1503 }
1504
cyhal_spi_set_fifo_level(cyhal_spi_t * obj,cyhal_spi_fifo_type_t type,uint16_t level)1505 cy_rslt_t cyhal_spi_set_fifo_level(cyhal_spi_t *obj, cyhal_spi_fifo_type_t type, uint16_t level)
1506 {
1507 return _cyhal_scb_set_fifo_level(obj->base, (cyhal_scb_fifo_type_t)type, level);
1508 }
1509
cyhal_spi_enable_output(cyhal_spi_t * obj,cyhal_spi_output_t output,cyhal_source_t * source)1510 cy_rslt_t cyhal_spi_enable_output(cyhal_spi_t *obj, cyhal_spi_output_t output, cyhal_source_t *source)
1511 {
1512 return _cyhal_scb_enable_output(obj->resource, (cyhal_scb_output_t)output, source);
1513 }
1514
cyhal_spi_disable_output(cyhal_spi_t * obj,cyhal_spi_output_t output)1515 cy_rslt_t cyhal_spi_disable_output(cyhal_spi_t *obj, cyhal_spi_output_t output)
1516 {
1517 CY_UNUSED_PARAMETER(obj);
1518 return _cyhal_scb_disable_output((cyhal_scb_output_t)output);
1519 }
1520
cyhal_spi_readable(cyhal_spi_t * obj)1521 uint32_t cyhal_spi_readable(cyhal_spi_t *obj)
1522 {
1523 return Cy_SCB_SPI_GetNumInRxFifo(obj->base);
1524 }
1525
cyhal_spi_writable(cyhal_spi_t * obj)1526 uint32_t cyhal_spi_writable(cyhal_spi_t *obj)
1527 {
1528 return Cy_SCB_GetFifoSize(obj->base) - Cy_SCB_SPI_GetNumInTxFifo(obj->base);
1529 }
1530
cyhal_spi_clear(cyhal_spi_t * obj)1531 cy_rslt_t cyhal_spi_clear(cyhal_spi_t *obj)
1532 {
1533 Cy_SCB_SPI_ClearRxFifo(obj->base);
1534 Cy_SCB_SPI_ClearTxFifo(obj->base);
1535
1536 return CY_RSLT_SUCCESS;
1537 }
1538
1539 #if defined(__cplusplus)
1540 }
1541 #endif
1542
1543 #endif /* CYHAL_DRIVER_AVAILABLE_SPI */
1544