1 /*
2 * Copyright (c) 2016, Freescale Semiconductor, Inc.
3 * Copyright 2016-2020,2022 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_spi.h"
10 #include "fsl_flexcomm.h"
11
12 /*******************************************************************************
13 * Definitions
14 ******************************************************************************/
15
16 /* Component ID definition, used by tools. */
17 #ifndef FSL_COMPONENT_ID
18 #define FSL_COMPONENT_ID "platform.drivers.flexcomm_spi"
19 #endif
20
21 /* Note: FIFOCFG[SIZE] has always value 1 = 8 items depth */
22
23 #if defined(FSL_FEATURE_SPI_FIFOSIZE_CFG) && (FSL_FEATURE_SPI_FIFOSIZE_CFG)
24 #define SPI_FIFO_DEPTH(base) 4
25 #else
26 #define SPI_FIFO_DEPTH(base) ((((base)->FIFOCFG & SPI_FIFOCFG_SIZE_MASK) >> SPI_FIFOCFG_SIZE_SHIFT) << 3)
27 #endif /*FSL_FEATURE_SPI_FIFOSIZE_CFG*/
28
29 /* Convert transfer count to transfer bytes. dataWidth is a
30 * range <0,15>. Range <8,15> represents 2B transfer */
31 #define SPI_COUNT_TO_BYTES(dataWidth, count) ((count) << ((dataWidth) >> 3U))
32 #define SPI_BYTES_TO_COUNT(dataWidth, bytes) ((bytes) >> ((dataWidth) >> 3U))
33 #if defined(FSL_FEATURE_SPI_IS_SSEL_PIN_COUNT_EQUAL_TO_THREE) && (FSL_FEATURE_SPI_IS_SSEL_PIN_COUNT_EQUAL_TO_THREE)
34 #define SPI_SSELPOL_MASK ((SPI_CFG_SPOL0_MASK) | (SPI_CFG_SPOL1_MASK) | (SPI_CFG_SPOL2_MASK))
35 #else
36 #if (defined(FSL_FEATURE_SPI_SSEL_COUNT) && (FSL_FEATURE_SPI_SSEL_COUNT == 2))
37 #define SPI_SSELPOL_MASK ((SPI_CFG_SPOL0_MASK) | (SPI_CFG_SPOL1_MASK))
38 #else
39 #define SPI_SSELPOL_MASK ((SPI_CFG_SPOL0_MASK) | (SPI_CFG_SPOL1_MASK) | (SPI_CFG_SPOL2_MASK) | (SPI_CFG_SPOL3_MASK))
40 #endif /* FSL_FEATURE_SPI_SSEL_COUNT == 2 */
41 #endif /*FSL_FEATURE_SPI_IS_SSEL_PIN_COUNT_EQUAL_TO_THREE*/
42
43 /*!
44 * @brief Used for conversion from `flexcomm_irq_handler_t` to `flexcomm_spi_master_irq_handler_t` and
45 * `flexcomm_spi_slave_irq_handler_t`.
46 */
47 typedef union spi_to_flexcomm
48 {
49 flexcomm_spi_master_irq_handler_t spi_master_handler;
50 flexcomm_spi_slave_irq_handler_t spi_slave_handler;
51 flexcomm_irq_handler_t flexcomm_handler;
52 } spi_to_flexcomm_t;
53
54 /*******************************************************************************
55 * Variables
56 ******************************************************************************/
57 /*! @brief internal SPI config array */
58 static spi_config_t g_configs[FSL_FEATURE_SOC_SPI_COUNT] = {(spi_data_width_t)0};
59
60 /*! @brief Array to map SPI instance number to base address. */
61 static const uint32_t s_spiBaseAddrs[FSL_FEATURE_SOC_SPI_COUNT] = SPI_BASE_ADDRS;
62
63 /*! @brief IRQ name array */
64 static const IRQn_Type s_spiIRQ[] = SPI_IRQS;
65
66 /* @brief Dummy data for each instance. This data is used when user's tx buffer is NULL*/
67 volatile uint8_t s_dummyData[FSL_FEATURE_SOC_SPI_COUNT] = {0};
68 /*******************************************************************************
69 * Code
70 ******************************************************************************/
71
72 /* Get the index corresponding to the FLEXCOMM */
73 /*! brief Returns instance number for SPI peripheral base address. */
SPI_GetInstance(SPI_Type * base)74 uint32_t SPI_GetInstance(SPI_Type *base)
75 {
76 uint32_t i;
77
78 for (i = 0U; i < (uint32_t)FSL_FEATURE_SOC_SPI_COUNT; i++)
79 {
80 if ((uint32_t)base == s_spiBaseAddrs[i])
81 {
82 break;
83 }
84 }
85
86 assert(i < (uint32_t)FSL_FEATURE_SOC_SPI_COUNT);
87 return i;
88 }
89
90 /*!
91 * brief Set up the dummy data.
92 *
93 * param base SPI peripheral address.
94 * param dummyData Data to be transferred when tx buffer is NULL.
95 */
SPI_SetDummyData(SPI_Type * base,uint8_t dummyData)96 void SPI_SetDummyData(SPI_Type *base, uint8_t dummyData)
97 {
98 uint32_t instance = SPI_GetInstance(base);
99 s_dummyData[instance] = dummyData;
100 }
101
102 /*!
103 * brief Returns the configurations.
104 *
105 * param base SPI peripheral address.
106 * return return configurations which contain datawidth and SSEL numbers.
107 * return data type is a pointer of spi_config_t.
108 */
SPI_GetConfig(SPI_Type * base)109 void *SPI_GetConfig(SPI_Type *base)
110 {
111 uint32_t instance;
112 instance = SPI_GetInstance(base);
113 return &g_configs[instance];
114 }
115
116 /*!
117 * brief Sets the SPI master configuration structure to default values.
118 *
119 * The purpose of this API is to get the configuration structure initialized for use in SPI_MasterInit().
120 * User may use the initialized structure unchanged in SPI_MasterInit(), or modify
121 * some fields of the structure before calling SPI_MasterInit(). After calling this API,
122 * the master is ready to transfer.
123 * Example:
124 code
125 spi_master_config_t config;
126 SPI_MasterGetDefaultConfig(&config);
127 endcode
128 *
129 * param config pointer to master config structure
130 */
SPI_MasterGetDefaultConfig(spi_master_config_t * config)131 void SPI_MasterGetDefaultConfig(spi_master_config_t *config)
132 {
133 assert(NULL != config);
134
135 /* Initializes the configure structure to zero. */
136 (void)memset(config, 0, sizeof(*config));
137
138 config->enableLoopback = false;
139 config->enableMaster = true;
140 config->polarity = kSPI_ClockPolarityActiveHigh;
141 config->phase = kSPI_ClockPhaseFirstEdge;
142 config->direction = kSPI_MsbFirst;
143 config->baudRate_Bps = 500000U;
144 config->dataWidth = kSPI_Data8Bits;
145 config->sselNum = kSPI_Ssel0;
146 config->txWatermark = (uint8_t)kSPI_TxFifo0;
147 config->rxWatermark = (uint8_t)kSPI_RxFifo1;
148 config->sselPol = kSPI_SpolActiveAllLow;
149 config->delayConfig.preDelay = 0U;
150 config->delayConfig.postDelay = 0U;
151 config->delayConfig.frameDelay = 0U;
152 config->delayConfig.transferDelay = 0U;
153 }
154
155 /*!
156 * brief Initializes the SPI with master configuration.
157 *
158 * The configuration structure can be filled by user from scratch, or be set with default
159 * values by SPI_MasterGetDefaultConfig(). After calling this API, the slave is ready to transfer.
160 * Example
161 code
162 spi_master_config_t config = {
163 .baudRate_Bps = 400000,
164 ...
165 };
166 SPI_MasterInit(SPI0, &config);
167 endcode
168 *
169 * param base SPI base pointer
170 * param config pointer to master configuration structure
171 * param srcClock_Hz Source clock frequency.
172 */
SPI_MasterInit(SPI_Type * base,const spi_master_config_t * config,uint32_t srcClock_Hz)173 status_t SPI_MasterInit(SPI_Type *base, const spi_master_config_t *config, uint32_t srcClock_Hz)
174 {
175 status_t result = kStatus_Success;
176 uint32_t instance;
177 uint32_t tmpConfig;
178
179 /* assert params */
180 assert(!((NULL == base) || (NULL == config) || (0U == srcClock_Hz)));
181 if ((NULL == base) || (NULL == config) || (0U == srcClock_Hz))
182 {
183 return kStatus_InvalidArgument;
184 }
185
186 /* initialize flexcomm to SPI mode */
187 result = FLEXCOMM_Init(base, FLEXCOMM_PERIPH_SPI);
188 if (kStatus_Success != result)
189 {
190 return result;
191 }
192
193 /* set divider */
194 result = SPI_MasterSetBaud(base, config->baudRate_Bps, srcClock_Hz);
195 if (kStatus_Success != result)
196 {
197 return result;
198 }
199
200 /* get instance number */
201 instance = SPI_GetInstance(base);
202
203 /* configure SPI mode */
204 tmpConfig = base->CFG;
205 tmpConfig &= ~(SPI_CFG_MASTER_MASK | SPI_CFG_LSBF_MASK | SPI_CFG_CPHA_MASK | SPI_CFG_CPOL_MASK | SPI_CFG_LOOP_MASK |
206 SPI_CFG_ENABLE_MASK | SPI_SSELPOL_MASK);
207 /* phase */
208 tmpConfig |= SPI_CFG_CPHA(config->phase);
209 /* polarity */
210 tmpConfig |= SPI_CFG_CPOL(config->polarity);
211 /* direction */
212 tmpConfig |= SPI_CFG_LSBF(config->direction);
213 /* master mode */
214 tmpConfig |= SPI_CFG_MASTER(1);
215 /* loopback */
216 tmpConfig |= SPI_CFG_LOOP(config->enableLoopback);
217 /* configure active level for all CS */
218 tmpConfig |= ((uint32_t)config->sselPol & (SPI_SSELPOL_MASK));
219 base->CFG = tmpConfig;
220
221 /* store configuration */
222 g_configs[instance].dataWidth = config->dataWidth;
223 g_configs[instance].sselNum = config->sselNum;
224 /* enable FIFOs */
225 base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
226 base->FIFOCFG |= SPI_FIFOCFG_ENABLETX_MASK | SPI_FIFOCFG_ENABLERX_MASK;
227 /* trigger level - empty txFIFO, one item in rxFIFO */
228 tmpConfig = base->FIFOTRIG & (~(SPI_FIFOTRIG_RXLVL_MASK | SPI_FIFOTRIG_TXLVL_MASK));
229 tmpConfig |= SPI_FIFOTRIG_TXLVL(config->txWatermark) | SPI_FIFOTRIG_RXLVL(config->rxWatermark);
230 /* enable generating interrupts for FIFOTRIG levels */
231 tmpConfig |= SPI_FIFOTRIG_TXLVLENA_MASK | SPI_FIFOTRIG_RXLVLENA_MASK;
232 /* set FIFOTRIG */
233 base->FIFOTRIG = tmpConfig;
234
235 /* Set the delay configuration. */
236 SPI_SetTransferDelay(base, &config->delayConfig);
237 /* Set the dummy data. */
238 SPI_SetDummyData(base, (uint8_t)SPI_DUMMYDATA);
239
240 SPI_Enable(base, config->enableMaster);
241 return kStatus_Success;
242 }
243
244 /*!
245 * brief Sets the SPI slave configuration structure to default values.
246 *
247 * The purpose of this API is to get the configuration structure initialized for use in SPI_SlaveInit().
248 * Modify some fields of the structure before calling SPI_SlaveInit().
249 * Example:
250 code
251 spi_slave_config_t config;
252 SPI_SlaveGetDefaultConfig(&config);
253 endcode
254 *
255 * param config pointer to slave configuration structure
256 */
SPI_SlaveGetDefaultConfig(spi_slave_config_t * config)257 void SPI_SlaveGetDefaultConfig(spi_slave_config_t *config)
258 {
259 assert(NULL != config);
260
261 /* Initializes the configure structure to zero. */
262 (void)memset(config, 0, sizeof(*config));
263
264 config->enableSlave = true;
265 config->polarity = kSPI_ClockPolarityActiveHigh;
266 config->phase = kSPI_ClockPhaseFirstEdge;
267 config->direction = kSPI_MsbFirst;
268 config->dataWidth = kSPI_Data8Bits;
269 config->txWatermark = (uint8_t)kSPI_TxFifo0;
270 config->rxWatermark = (uint8_t)kSPI_RxFifo1;
271 config->sselPol = kSPI_SpolActiveAllLow;
272 }
273
274 /*!
275 * brief Initializes the SPI with slave configuration.
276 *
277 * The configuration structure can be filled by user from scratch or be set with
278 * default values by SPI_SlaveGetDefaultConfig().
279 * After calling this API, the slave is ready to transfer.
280 * Example
281 code
282 spi_slave_config_t config = {
283 .polarity = flexSPIClockPolarity_ActiveHigh;
284 .phase = flexSPIClockPhase_FirstEdge;
285 .direction = flexSPIMsbFirst;
286 ...
287 };
288 SPI_SlaveInit(SPI0, &config);
289 endcode
290 *
291 * param base SPI base pointer
292 * param config pointer to slave configuration structure
293 */
SPI_SlaveInit(SPI_Type * base,const spi_slave_config_t * config)294 status_t SPI_SlaveInit(SPI_Type *base, const spi_slave_config_t *config)
295 {
296 status_t result = kStatus_Success;
297 uint32_t instance;
298 uint32_t tmpConfig;
299
300 /* assert params */
301 assert(!((NULL == base) || (NULL == config)));
302 if ((NULL == base) || (NULL == config))
303 {
304 return kStatus_InvalidArgument;
305 }
306 /* configure flexcomm to SPI, enable clock gate */
307 result = FLEXCOMM_Init(base, FLEXCOMM_PERIPH_SPI);
308 if (kStatus_Success != result)
309 {
310 return result;
311 }
312
313 instance = SPI_GetInstance(base);
314
315 /* configure SPI mode */
316 tmpConfig = base->CFG;
317 tmpConfig &= ~(SPI_CFG_MASTER_MASK | SPI_CFG_LSBF_MASK | SPI_CFG_CPHA_MASK | SPI_CFG_CPOL_MASK |
318 SPI_CFG_ENABLE_MASK | SPI_SSELPOL_MASK);
319 /* phase */
320 tmpConfig |= SPI_CFG_CPHA(config->phase);
321 /* polarity */
322 tmpConfig |= SPI_CFG_CPOL(config->polarity);
323 /* direction */
324 tmpConfig |= SPI_CFG_LSBF(config->direction);
325 /* configure active level for all CS */
326 tmpConfig |= ((uint32_t)config->sselPol & (SPI_SSELPOL_MASK));
327 base->CFG = tmpConfig;
328
329 /* store configuration */
330 g_configs[instance].dataWidth = config->dataWidth;
331 /* empty and enable FIFOs */
332 base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
333 base->FIFOCFG |= SPI_FIFOCFG_ENABLETX_MASK | SPI_FIFOCFG_ENABLERX_MASK;
334 /* trigger level - empty txFIFO, one item in rxFIFO */
335 tmpConfig = base->FIFOTRIG & (~(SPI_FIFOTRIG_RXLVL_MASK | SPI_FIFOTRIG_TXLVL_MASK));
336 tmpConfig |= SPI_FIFOTRIG_TXLVL(config->txWatermark) | SPI_FIFOTRIG_RXLVL(config->rxWatermark);
337 /* enable generating interrupts for FIFOTRIG levels */
338 tmpConfig |= SPI_FIFOTRIG_TXLVLENA_MASK | SPI_FIFOTRIG_RXLVLENA_MASK;
339 /* set FIFOTRIG */
340 base->FIFOTRIG = tmpConfig;
341
342 SPI_SetDummyData(base, (uint8_t)SPI_DUMMYDATA);
343
344 SPI_Enable(base, config->enableSlave);
345 return kStatus_Success;
346 }
347
348 /*!
349 * brief De-initializes the SPI.
350 *
351 * Calling this API resets the SPI module, gates the SPI clock.
352 * The SPI module can't work unless calling the SPI_MasterInit/SPI_SlaveInit to initialize module.
353 *
354 * param base SPI base pointer
355 */
SPI_Deinit(SPI_Type * base)356 void SPI_Deinit(SPI_Type *base)
357 {
358 /* Assert arguments */
359 assert(NULL != base);
360 /* Disable interrupts, disable dma requests, disable peripheral */
361 base->FIFOINTENCLR = SPI_FIFOINTENCLR_TXERR_MASK | SPI_FIFOINTENCLR_RXERR_MASK | SPI_FIFOINTENCLR_TXLVL_MASK |
362 SPI_FIFOINTENCLR_RXLVL_MASK;
363 base->FIFOCFG &= ~(SPI_FIFOCFG_DMATX_MASK | SPI_FIFOCFG_DMARX_MASK);
364 base->CFG &= ~(SPI_CFG_ENABLE_MASK);
365 }
366
367 /*!
368 * brief Enables the DMA request from SPI txFIFO.
369 *
370 * param base SPI base pointer
371 * param enable True means enable DMA, false means disable DMA
372 */
SPI_EnableTxDMA(SPI_Type * base,bool enable)373 void SPI_EnableTxDMA(SPI_Type *base, bool enable)
374 {
375 if (enable)
376 {
377 base->FIFOCFG |= SPI_FIFOCFG_DMATX_MASK;
378 }
379 else
380 {
381 base->FIFOCFG &= ~SPI_FIFOCFG_DMATX_MASK;
382 }
383 }
384
385 /*!
386 * brief Enables the DMA request from SPI rxFIFO.
387 *
388 * param base SPI base pointer
389 * param enable True means enable DMA, false means disable DMA
390 */
SPI_EnableRxDMA(SPI_Type * base,bool enable)391 void SPI_EnableRxDMA(SPI_Type *base, bool enable)
392 {
393 if (enable)
394 {
395 base->FIFOCFG |= SPI_FIFOCFG_DMARX_MASK;
396 }
397 else
398 {
399 base->FIFOCFG &= ~SPI_FIFOCFG_DMARX_MASK;
400 }
401 }
402
403 /*!
404 * brief Sets the baud rate for SPI transfer. This is only used in master.
405 *
406 * param base SPI base pointer
407 * param baudrate_Bps baud rate needed in Hz.
408 * param srcClock_Hz SPI source clock frequency in Hz.
409 */
SPI_MasterSetBaud(SPI_Type * base,uint32_t baudrate_Bps,uint32_t srcClock_Hz)410 status_t SPI_MasterSetBaud(SPI_Type *base, uint32_t baudrate_Bps, uint32_t srcClock_Hz)
411 {
412 uint32_t tmpDiv;
413
414 /* assert params */
415 assert(!((NULL == base) || (0U == baudrate_Bps) || (0U == srcClock_Hz)));
416 if ((NULL == base) || (0U == baudrate_Bps) || (0U == srcClock_Hz))
417 {
418 return kStatus_InvalidArgument;
419 }
420
421 /* calculate baudrate, round up the result */
422 tmpDiv = ((srcClock_Hz * 10U) / baudrate_Bps + 5U) / 10U - 1U;
423 if (tmpDiv > 0xFFFFU)
424 {
425 return kStatus_SPI_BaudrateNotSupport;
426 }
427 base->DIV &= ~SPI_DIV_DIVVAL_MASK;
428 base->DIV |= SPI_DIV_DIVVAL(tmpDiv);
429 return kStatus_Success;
430 }
431
432 /*!
433 * brief Writes a data into the SPI data register.
434 *
435 * param base SPI base pointer
436 * param data needs to be write.
437 * param configFlags transfer configuration options ref spi_xfer_option_t
438 */
SPI_WriteData(SPI_Type * base,uint16_t data,uint32_t configFlags)439 void SPI_WriteData(SPI_Type *base, uint16_t data, uint32_t configFlags)
440 {
441 uint32_t control = 0U;
442 uint32_t instance;
443
444 /* check params */
445 assert(NULL != base);
446 /* get and check instance */
447 instance = SPI_GetInstance(base);
448
449 /* set data width */
450 control |= (uint32_t)SPI_FIFOWR_LEN((g_configs[instance].dataWidth));
451 /* set sssel */
452 control |= (SPI_DEASSERT_ALL & (~SPI_DEASSERTNUM_SSEL((uint32_t)(g_configs[instance].sselNum))));
453 /* mask configFlags */
454 control |= (configFlags & (uint32_t)SPI_FIFOWR_FLAGS_MASK);
455 /* control should not affect lower 16 bits */
456 assert(0U == (control & 0xFFFFU));
457 base->FIFOWR = data | control;
458 }
459
460 /*!
461 * brief Initializes the SPI master handle.
462 *
463 * This function initializes the SPI master handle which can be used for other SPI master transactional APIs. Usually,
464 * for a specified SPI instance, call this API once to get the initialized handle.
465 *
466 * param base SPI peripheral base address.
467 * param handle SPI handle pointer.
468 * param callback Callback function.
469 * param userData User data.
470 */
SPI_MasterTransferCreateHandle(SPI_Type * base,spi_master_handle_t * handle,spi_master_callback_t callback,void * userData)471 status_t SPI_MasterTransferCreateHandle(SPI_Type *base,
472 spi_master_handle_t *handle,
473 spi_master_callback_t callback,
474 void *userData)
475 {
476 /* check 'base' */
477 assert(NULL != base);
478 /* check 'handle' */
479 assert(NULL != handle);
480
481 uint32_t instance;
482 spi_to_flexcomm_t handler;
483
484 /* get flexcomm instance by 'base' param */
485 instance = SPI_GetInstance(base);
486
487 (void)memset(handle, 0, sizeof(*handle));
488 /* Initialize the handle */
489 if ((base->CFG & SPI_CFG_MASTER_MASK) != 0U)
490 {
491 handler.spi_master_handler = SPI_MasterTransferHandleIRQ;
492 FLEXCOMM_SetIRQHandler(base, handler.flexcomm_handler, handle);
493 }
494 else
495 {
496 handler.spi_slave_handler = SPI_SlaveTransferHandleIRQ;
497 FLEXCOMM_SetIRQHandler(base, handler.flexcomm_handler, handle);
498 }
499
500 handle->dataWidth = (uint8_t)(g_configs[instance].dataWidth);
501 /* in slave mode, the sselNum is not important */
502 handle->sselNum = (uint8_t)(g_configs[instance].sselNum);
503 handle->txWatermark = (uint8_t)SPI_FIFOTRIG_TXLVL_GET(base);
504 handle->rxWatermark = (uint8_t)SPI_FIFOTRIG_RXLVL_GET(base);
505 handle->callback = callback;
506 handle->userData = userData;
507
508 /* Enable SPI NVIC */
509 (void)EnableIRQ(s_spiIRQ[instance]);
510
511 return kStatus_Success;
512 }
513
514 /*!
515 * brief Transfers a block of data using a polling method.
516 *
517 * param base SPI base pointer
518 * param xfer pointer to spi_xfer_config_t structure
519 * retval kStatus_Success Successfully start a transfer.
520 * retval kStatus_InvalidArgument Input argument is invalid.
521 * retval kStatus_SPI_Timeout The transfer timed out and was aborted.
522 */
SPI_MasterTransferBlocking(SPI_Type * base,spi_transfer_t * xfer)523 status_t SPI_MasterTransferBlocking(SPI_Type *base, spi_transfer_t *xfer)
524 {
525 uint32_t instance;
526 uint32_t tx_ctrl = 0U, last_ctrl = 0U;
527 uint32_t tmp32, rxRemainingBytes, txRemainingBytes, dataWidth;
528 uint32_t toReceiveCount = 0;
529 const uint8_t *txData;
530 uint8_t *rxData;
531 uint32_t fifoDepth;
532 #if SPI_RETRY_TIMES
533 uint32_t waitTimes = SPI_RETRY_TIMES;
534 #endif
535
536 /* check params */
537 assert(!((NULL == base) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData))));
538 if ((NULL == base) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData)))
539 {
540 return kStatus_InvalidArgument;
541 }
542
543 fifoDepth = SPI_FIFO_DEPTH(base);
544 txData = xfer->txData;
545 rxData = xfer->rxData;
546 txRemainingBytes = (txData != NULL) ? xfer->dataSize : 0U;
547 rxRemainingBytes = (rxData != NULL) ? xfer->dataSize : 0U;
548
549 instance = SPI_GetInstance(base);
550 dataWidth = (uint32_t)(g_configs[instance].dataWidth);
551
552 /* dataSize (in bytes) is not aligned to 16bit (2B) transfer */
553 if ((dataWidth > (uint32_t)kSPI_Data8Bits) && ((xfer->dataSize & 0x1U) != 0U))
554 {
555 return kStatus_InvalidArgument;
556 }
557
558 /* clear tx/rx errors and empty FIFOs */
559 base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
560 base->FIFOSTAT |= SPI_FIFOSTAT_TXERR_MASK | SPI_FIFOSTAT_RXERR_MASK;
561 /* select slave to talk with */
562 tx_ctrl |= (SPI_DEASSERT_ALL & (~SPI_DEASSERTNUM_SSEL((uint32_t)(g_configs[instance].sselNum))));
563 /* set width of data - range asserted at entry */
564 tx_ctrl |= SPI_FIFOWR_LEN(dataWidth);
565 /* delay for frames */
566 tx_ctrl |= ((xfer->configFlags & (uint32_t)kSPI_FrameDelay) != 0U) ? (uint32_t)kSPI_FrameDelay : 0U;
567 /* end of transfer */
568 last_ctrl |= ((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) ? (uint32_t)kSPI_FrameAssert : 0U;
569 /* last index of loop */
570 while ((txRemainingBytes != 0U) || (rxRemainingBytes != 0U) || (toReceiveCount != 0U))
571 {
572 #if SPI_RETRY_TIMES
573 if (--waitTimes == 0U)
574 {
575 return kStatus_SPI_Timeout;
576 }
577 #endif
578 /* if rxFIFO is not empty */
579 if ((base->FIFOSTAT & SPI_FIFOSTAT_RXNOTEMPTY_MASK) != 0U)
580 {
581 tmp32 = base->FIFORD;
582 /* rxBuffer is not empty */
583 if (rxRemainingBytes != 0U)
584 {
585 *(rxData++) = (uint8_t)tmp32;
586 rxRemainingBytes--;
587 /* read 16 bits at once */
588 if (dataWidth > 8U)
589 {
590 *(rxData++) = (uint8_t)(tmp32 >> 8);
591 rxRemainingBytes--;
592 }
593 }
594 /* decrease number of data expected to receive */
595 toReceiveCount -= 1U;
596 }
597 /* transmit if txFIFO is not full and data to receive does not exceed FIFO depth */
598 if (((base->FIFOSTAT & SPI_FIFOSTAT_TXNOTFULL_MASK) != 0U) && (toReceiveCount < fifoDepth) &&
599 ((txRemainingBytes != 0U) || (rxRemainingBytes >= SPI_COUNT_TO_BYTES(dataWidth, toReceiveCount + 1U))))
600 {
601 /* txBuffer is not empty */
602 if (txRemainingBytes != 0U)
603 {
604 tmp32 = *(txData++);
605 txRemainingBytes--;
606 /* write 16 bit at once */
607 if (dataWidth > 8U)
608 {
609 tmp32 |= ((uint32_t)(*(txData++))) << 8U;
610 txRemainingBytes--;
611 }
612 if (txRemainingBytes == 0U)
613 {
614 tx_ctrl |= last_ctrl;
615 }
616 }
617 else
618 {
619 tmp32 = (uint32_t)s_dummyData[instance];
620 tmp32 |= (uint32_t)s_dummyData[instance] << 8U;
621 /* last transfer */
622 if (rxRemainingBytes == SPI_COUNT_TO_BYTES(dataWidth, toReceiveCount + 1U))
623 {
624 tx_ctrl |= last_ctrl;
625 }
626 }
627 /* send data */
628 tmp32 = tx_ctrl | tmp32;
629 base->FIFOWR = tmp32;
630 toReceiveCount += 1U;
631 }
632 }
633 /* wait if TX FIFO of previous transfer is not empty */
634 #if SPI_RETRY_TIMES
635 waitTimes = SPI_RETRY_TIMES;
636 while ((0U == (base->FIFOSTAT & SPI_FIFOSTAT_TXEMPTY_MASK)) && (0U != --waitTimes))
637 #else
638 while (0U == (base->FIFOSTAT & SPI_FIFOSTAT_TXEMPTY_MASK))
639 #endif
640 {
641 }
642 #if SPI_RETRY_TIMES
643 if (waitTimes == 0U)
644 {
645 return kStatus_SPI_Timeout;
646 }
647 #endif
648 return kStatus_Success;
649 }
650
651 /*!
652 * brief Performs a non-blocking SPI interrupt transfer.
653 *
654 * param base SPI peripheral base address.
655 * param handle pointer to spi_master_handle_t structure which stores the transfer state
656 * param xfer pointer to spi_xfer_config_t structure
657 * retval kStatus_Success Successfully start a transfer.
658 * retval kStatus_InvalidArgument Input argument is invalid.
659 * retval kStatus_SPI_Busy SPI is not idle, is running another transfer.
660 */
SPI_MasterTransferNonBlocking(SPI_Type * base,spi_master_handle_t * handle,spi_transfer_t * xfer)661 status_t SPI_MasterTransferNonBlocking(SPI_Type *base, spi_master_handle_t *handle, spi_transfer_t *xfer)
662 {
663 /* check params */
664 assert(
665 !((NULL == base) || (NULL == handle) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData))));
666 if ((NULL == base) || (NULL == handle) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData)))
667 {
668 return kStatus_InvalidArgument;
669 }
670
671 /* dataSize (in bytes) is not aligned to 16bit (2B) transfer */
672 assert(!((handle->dataWidth > (uint8_t)kSPI_Data8Bits) && ((xfer->dataSize & 0x1U) != 0U)));
673 if ((handle->dataWidth > (uint8_t)kSPI_Data8Bits) && ((xfer->dataSize & 0x1U) != 0U))
674 {
675 return kStatus_InvalidArgument;
676 }
677
678 /* Check if SPI is busy */
679 if (handle->state == (uint32_t)kStatus_SPI_Busy)
680 {
681 return kStatus_SPI_Busy;
682 }
683
684 /* Set the handle information */
685 handle->txData = xfer->txData;
686 handle->rxData = xfer->rxData;
687 /* set count */
688 handle->txRemainingBytes = (xfer->txData != NULL) ? xfer->dataSize : 0U;
689 handle->rxRemainingBytes = (xfer->rxData != NULL) ? xfer->dataSize : 0U;
690 handle->totalByteCount = xfer->dataSize;
691 /* other options */
692 handle->toReceiveCount = 0;
693 handle->configFlags = xfer->configFlags;
694 /* Set the SPI state to busy */
695 handle->state = (uint32_t)kStatus_SPI_Busy;
696 /* clear FIFOs when transfer starts */
697 base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
698 base->FIFOSTAT |= SPI_FIFOSTAT_TXERR_MASK | SPI_FIFOSTAT_RXERR_MASK;
699 /* enable generating txIRQ and rxIRQ, first transfer is fired by empty txFIFO */
700 base->FIFOINTENSET |= SPI_FIFOINTENSET_TXLVL_MASK | SPI_FIFOINTENSET_RXLVL_MASK;
701 return kStatus_Success;
702 }
703
704 /*!
705 * brief Transfers a block of data using a polling method.
706 *
707 * This function will do a half-duplex transfer for SPI master, This is a blocking function,
708 * which does not retuen until all transfer have been completed. And data transfer mechanism is half-duplex,
709 * users can set transmit first or receive first.
710 *
711 * param base SPI base pointer
712 * param xfer pointer to spi_half_duplex_transfer_t structure
713 * return status of status_t.
714 */
SPI_MasterHalfDuplexTransferBlocking(SPI_Type * base,spi_half_duplex_transfer_t * xfer)715 status_t SPI_MasterHalfDuplexTransferBlocking(SPI_Type *base, spi_half_duplex_transfer_t *xfer)
716 {
717 assert(xfer != NULL);
718
719 spi_transfer_t tempXfer = {0};
720 status_t status;
721
722 if (xfer->isTransmitFirst)
723 {
724 tempXfer.txData = xfer->txData;
725 tempXfer.rxData = NULL;
726 tempXfer.dataSize = xfer->txDataSize;
727 }
728 else
729 {
730 tempXfer.txData = NULL;
731 tempXfer.rxData = xfer->rxData;
732 tempXfer.dataSize = xfer->rxDataSize;
733 }
734 /* If the pcs pin keep assert between transmit and receive. */
735 if (xfer->isPcsAssertInTransfer)
736 {
737 tempXfer.configFlags = (xfer->configFlags) & (~(uint32_t)kSPI_FrameAssert);
738 }
739 else
740 {
741 tempXfer.configFlags = (xfer->configFlags) | (uint32_t)kSPI_FrameAssert;
742 }
743
744 status = SPI_MasterTransferBlocking(base, &tempXfer);
745
746 if (status != kStatus_Success)
747 {
748 return status;
749 }
750
751 if (xfer->isTransmitFirst)
752 {
753 tempXfer.txData = NULL;
754 tempXfer.rxData = xfer->rxData;
755 tempXfer.dataSize = xfer->rxDataSize;
756 }
757 else
758 {
759 tempXfer.txData = xfer->txData;
760 tempXfer.rxData = NULL;
761 tempXfer.dataSize = xfer->txDataSize;
762 }
763 tempXfer.configFlags = xfer->configFlags;
764
765 /* SPI transfer blocking. */
766 status = SPI_MasterTransferBlocking(base, &tempXfer);
767
768 return status;
769 }
770
771 /*!
772 * brief Performs a non-blocking SPI interrupt transfer.
773 *
774 * This function using polling way to do the first half transimission and using interrupts to
775 * do the second half transimission, the transfer mechanism is half-duplex.
776 * When do the second half transimission, code will return right away. When all data is transferred,
777 * the callback function is called.
778 *
779 * param base SPI peripheral base address.
780 * param handle pointer to spi_master_handle_t structure which stores the transfer state
781 * param xfer pointer to spi_half_duplex_transfer_t structure
782 * return status of status_t.
783 */
SPI_MasterHalfDuplexTransferNonBlocking(SPI_Type * base,spi_master_handle_t * handle,spi_half_duplex_transfer_t * xfer)784 status_t SPI_MasterHalfDuplexTransferNonBlocking(SPI_Type *base,
785 spi_master_handle_t *handle,
786 spi_half_duplex_transfer_t *xfer)
787 {
788 assert(xfer != NULL);
789 assert(handle != NULL);
790 spi_transfer_t tempXfer = {0};
791 status_t status;
792
793 if (xfer->isTransmitFirst)
794 {
795 tempXfer.txData = xfer->txData;
796 tempXfer.rxData = NULL;
797 tempXfer.dataSize = xfer->txDataSize;
798 }
799 else
800 {
801 tempXfer.txData = NULL;
802 tempXfer.rxData = xfer->rxData;
803 tempXfer.dataSize = xfer->rxDataSize;
804 }
805 /* If the PCS pin keep assert between transmit and receive. */
806 if (xfer->isPcsAssertInTransfer)
807 {
808 tempXfer.configFlags = (xfer->configFlags) & (~(uint32_t)kSPI_FrameAssert);
809 }
810 else
811 {
812 tempXfer.configFlags = (xfer->configFlags) | (uint32_t)kSPI_FrameAssert;
813 }
814
815 status = SPI_MasterTransferBlocking(base, &tempXfer);
816 if (status != kStatus_Success)
817 {
818 return status;
819 }
820
821 if (xfer->isTransmitFirst)
822 {
823 tempXfer.txData = NULL;
824 tempXfer.rxData = xfer->rxData;
825 tempXfer.dataSize = xfer->rxDataSize;
826 }
827 else
828 {
829 tempXfer.txData = xfer->txData;
830 tempXfer.rxData = NULL;
831 tempXfer.dataSize = xfer->txDataSize;
832 }
833 tempXfer.configFlags = xfer->configFlags;
834
835 status = SPI_MasterTransferNonBlocking(base, handle, &tempXfer);
836
837 return status;
838 }
839
840 /*!
841 * brief Gets the master transfer count.
842 *
843 * This function gets the master transfer count.
844 *
845 * param base SPI peripheral base address.
846 * param handle Pointer to the spi_master_handle_t structure which stores the transfer state.
847 * param count The number of bytes transferred by using the non-blocking transaction.
848 * return status of status_t.
849 */
SPI_MasterTransferGetCount(SPI_Type * base,spi_master_handle_t * handle,size_t * count)850 status_t SPI_MasterTransferGetCount(SPI_Type *base, spi_master_handle_t *handle, size_t *count)
851 {
852 assert(NULL != handle);
853
854 if (NULL == count)
855 {
856 return kStatus_InvalidArgument;
857 }
858
859 /* Catch when there is not an active transfer. */
860 if (handle->state != (uint32_t)kStatus_SPI_Busy)
861 {
862 *count = 0;
863 return kStatus_NoTransferInProgress;
864 }
865
866 *count = handle->totalByteCount - handle->rxRemainingBytes;
867 return kStatus_Success;
868 }
869
870 /*!
871 * brief SPI master aborts a transfer using an interrupt.
872 *
873 * This function aborts a transfer using an interrupt.
874 *
875 * param base SPI peripheral base address.
876 * param handle Pointer to the spi_master_handle_t structure which stores the transfer state.
877 */
SPI_MasterTransferAbort(SPI_Type * base,spi_master_handle_t * handle)878 void SPI_MasterTransferAbort(SPI_Type *base, spi_master_handle_t *handle)
879 {
880 assert(NULL != handle);
881
882 /* Disable interrupt requests*/
883 base->FIFOINTENSET &= ~(SPI_FIFOINTENSET_TXLVL_MASK | SPI_FIFOINTENSET_RXLVL_MASK);
884 /* Empty FIFOs */
885 base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
886
887 handle->state = (uint32_t)kStatus_SPI_Idle;
888 handle->txRemainingBytes = 0U;
889 handle->rxRemainingBytes = 0U;
890 }
891
SPI_TransferHandleIRQInternal(SPI_Type * base,spi_master_handle_t * handle)892 static void SPI_TransferHandleIRQInternal(SPI_Type *base, spi_master_handle_t *handle)
893 {
894 uint32_t tx_ctrl = 0U, last_ctrl = 0U, tmp32;
895 bool loopContinue;
896 uint32_t fifoDepth;
897 /* Get flexcomm instance by 'base' param */
898 uint32_t instance = SPI_GetInstance(base);
899 size_t txRemainingBytes;
900 size_t rxRemainingBytes;
901 uint8_t toReceiveCount;
902
903 /* check params */
904 assert((NULL != base) && (NULL != handle) && ((NULL != handle->txData) || (NULL != handle->rxData)));
905
906 fifoDepth = SPI_FIFO_DEPTH(base);
907 /* select slave to talk with */
908 tx_ctrl |= ((uint32_t)SPI_DEASSERT_ALL & (uint32_t)SPI_ASSERTNUM_SSEL(handle->sselNum));
909 /* set width of data */
910 tx_ctrl |= SPI_FIFOWR_LEN(handle->dataWidth);
911 /* delay for frames */
912 tx_ctrl |= ((handle->configFlags & (uint32_t)kSPI_FrameDelay) != 0U) ? (uint32_t)kSPI_FrameDelay : 0U;
913 /* end of transfer */
914 last_ctrl |= ((handle->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) ? (uint32_t)kSPI_FrameAssert : 0U;
915 do
916 {
917 loopContinue = false;
918
919 /* rxFIFO is not empty */
920 if ((base->FIFOSTAT & SPI_FIFOSTAT_RXNOTEMPTY_MASK) != 0U)
921 {
922 tmp32 = base->FIFORD;
923 /* rxBuffer is not empty */
924 if (handle->rxRemainingBytes != 0U)
925 {
926 /* low byte must go first */
927 *(handle->rxData++) = (uint8_t)tmp32;
928 handle->rxRemainingBytes--;
929 /* read 16 bits at once */
930 if (handle->dataWidth > (uint8_t)kSPI_Data8Bits)
931 {
932 *(handle->rxData++) = (uint8_t)(tmp32 >> 8);
933 handle->rxRemainingBytes--;
934 }
935 }
936
937 /* decrease number of data expected to receive */
938 handle->toReceiveCount -= 1;
939 loopContinue = true;
940 }
941
942 /* - txFIFO is not full
943 * - we cannot cause rxFIFO overflow by sending more data than is the depth of FIFO
944 * - txBuffer is not empty or the next 'toReceiveCount' data can fit into rxBuffer
945 */
946 txRemainingBytes = handle->txRemainingBytes;
947 rxRemainingBytes = handle->rxRemainingBytes;
948 toReceiveCount = (handle->toReceiveCount > 0) ? (uint8_t)handle->toReceiveCount : 0U;
949 if (((base->FIFOSTAT & SPI_FIFOSTAT_TXNOTFULL_MASK) != 0U) && ((uint32_t)toReceiveCount < fifoDepth) &&
950 ((txRemainingBytes != 0U) ||
951 (rxRemainingBytes >= SPI_COUNT_TO_BYTES(handle->dataWidth, (uint32_t)toReceiveCount + 1U))))
952 {
953 /* txBuffer is not empty */
954 if ((txRemainingBytes != 0U) && (handle->txData != NULL))
955 {
956 /* low byte must go first */
957 tmp32 = *(handle->txData++);
958 handle->txRemainingBytes--;
959 txRemainingBytes = handle->txRemainingBytes;
960 /* write 16 bit at once */
961 if (handle->dataWidth > (uint8_t)kSPI_Data8Bits)
962 {
963 tmp32 |= ((uint32_t)(*(handle->txData++))) << 8U;
964 handle->txRemainingBytes--;
965 txRemainingBytes = handle->txRemainingBytes;
966 }
967 /* last transfer */
968 if (handle->txRemainingBytes == 0U)
969 {
970 tx_ctrl |= last_ctrl;
971 }
972 }
973 else
974 {
975 tmp32 = (uint32_t)s_dummyData[instance];
976 tmp32 |= (uint32_t)s_dummyData[instance] << 8U;
977 /* last transfer */
978 if (rxRemainingBytes == SPI_COUNT_TO_BYTES(handle->dataWidth, (uint32_t)toReceiveCount + 1U))
979 {
980 tx_ctrl |= last_ctrl;
981 }
982 }
983 /* send data */
984 tmp32 = tx_ctrl | tmp32;
985 base->FIFOWR = tmp32;
986 /* increase number of expected data to receive */
987 handle->toReceiveCount += 1;
988 toReceiveCount = (handle->toReceiveCount > 0) ? (uint8_t)handle->toReceiveCount : 0U;
989 loopContinue = true;
990 }
991 } while (loopContinue);
992 }
993
994 /*!
995 * brief Interrupts the handler for the SPI.
996 *
997 * param base SPI peripheral base address.
998 * param handle pointer to spi_master_handle_t structure which stores the transfer state.
999 */
SPI_MasterTransferHandleIRQ(SPI_Type * base,spi_master_handle_t * handle)1000 void SPI_MasterTransferHandleIRQ(SPI_Type *base, spi_master_handle_t *handle)
1001 {
1002 assert((NULL != base) && (NULL != handle));
1003 size_t txRemainingBytes;
1004 uint8_t toReceiveCount;
1005
1006 /* IRQ behaviour:
1007 * - first interrupt is triggered by empty txFIFO. The transfer function
1008 * then tries empty rxFIFO and fill txFIFO interleaved that results to
1009 * strategy to process as many items as possible.
1010 * - the next IRQs can be:
1011 * rxIRQ from nonempty rxFIFO which requires to empty rxFIFO.
1012 * txIRQ from empty txFIFO which requires to refill txFIFO.
1013 * - last interrupt is triggered by empty txFIFO. The last state is
1014 * known by empty rxBuffer and txBuffer. If there is nothing to receive
1015 * or send - both operations have been finished and interrupts can be
1016 * disabled.
1017 */
1018
1019 /* Data to send or read or expected to receive */
1020 if ((handle->txRemainingBytes != 0U) || (handle->rxRemainingBytes != 0U) || (handle->toReceiveCount != 0))
1021 {
1022 /* Transmit or receive data */
1023 SPI_TransferHandleIRQInternal(base, handle);
1024 /* No data to send or read or receive. Transfer ends. Set txTrigger to 0 level and
1025 * enable txIRQ to confirm when txFIFO becomes empty */
1026 if ((0U == handle->txRemainingBytes) && (0U == handle->rxRemainingBytes) && (0 == handle->toReceiveCount))
1027 {
1028 base->FIFOTRIG = base->FIFOTRIG & (~SPI_FIFOTRIG_TXLVL_MASK);
1029 base->FIFOINTENSET |= SPI_FIFOINTENSET_TXLVL_MASK;
1030 }
1031 else
1032 {
1033 uint32_t rxRemainingCount = SPI_BYTES_TO_COUNT(handle->dataWidth, handle->rxRemainingBytes);
1034 /* If, there are no data to send or rxFIFO is already filled with necessary number of dummy data,
1035 * disable txIRQ. From this point only rxIRQ is used to receive data without any transmission */
1036 toReceiveCount = (handle->toReceiveCount > 0) ? (uint8_t)handle->toReceiveCount : 0U;
1037 if ((0U == handle->txRemainingBytes) && (rxRemainingCount <= toReceiveCount))
1038 {
1039 base->FIFOINTENCLR = SPI_FIFOINTENCLR_TXLVL_MASK;
1040 }
1041 /* Nothing to receive or transmit, but we still have pending data which are bellow rxLevel.
1042 * Cannot clear rxFIFO, txFIFO might be still active */
1043 if (rxRemainingCount == 0U)
1044 {
1045 txRemainingBytes = handle->txRemainingBytes;
1046 if ((txRemainingBytes == 0U) && (toReceiveCount != 0U) &&
1047 (toReceiveCount < SPI_FIFOTRIG_RXLVL_GET(base) + 1U))
1048 {
1049 base->FIFOTRIG = (base->FIFOTRIG & (~SPI_FIFOTRIG_RXLVL_MASK)) |
1050 SPI_FIFOTRIG_RXLVL((uint32_t)toReceiveCount - 1U);
1051 }
1052 }
1053 else
1054 {
1055 /* Expected to receive less data than rxLevel value, we have to update rxLevel */
1056 if (rxRemainingCount < (SPI_FIFOTRIG_RXLVL_GET(base) + 1U))
1057 {
1058 base->FIFOTRIG =
1059 (base->FIFOTRIG & (~SPI_FIFOTRIG_RXLVL_MASK)) | SPI_FIFOTRIG_RXLVL(rxRemainingCount - 1U);
1060 }
1061 }
1062 }
1063 }
1064 else
1065 {
1066 /* Empty txFIFO is confirmed. Disable IRQs and restore triggers values */
1067 base->FIFOINTENCLR = SPI_FIFOINTENCLR_RXLVL_MASK | SPI_FIFOINTENCLR_TXLVL_MASK;
1068 base->FIFOTRIG = (base->FIFOTRIG & (~(SPI_FIFOTRIG_RXLVL_MASK | SPI_FIFOTRIG_RXLVL_MASK))) |
1069 SPI_FIFOTRIG_RXLVL(handle->rxWatermark) | SPI_FIFOTRIG_TXLVL(handle->txWatermark);
1070 /* set idle state and call user callback */
1071 handle->state = (uint32_t)kStatus_SPI_Idle;
1072 if (handle->callback != NULL)
1073 {
1074 (handle->callback)(base, handle, handle->state, handle->userData);
1075 }
1076 }
1077 }
1078