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 uint8_t *txData, *rxData;
530 uint32_t fifoDepth;
531 #if SPI_RETRY_TIMES
532 uint32_t waitTimes = SPI_RETRY_TIMES;
533 #endif
534
535 /* check params */
536 assert(!((NULL == base) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData))));
537 if ((NULL == base) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData)))
538 {
539 return kStatus_InvalidArgument;
540 }
541
542 fifoDepth = SPI_FIFO_DEPTH(base);
543 txData = xfer->txData;
544 rxData = xfer->rxData;
545 txRemainingBytes = (txData != NULL) ? xfer->dataSize : 0U;
546 rxRemainingBytes = (rxData != NULL) ? xfer->dataSize : 0U;
547
548 instance = SPI_GetInstance(base);
549 dataWidth = (uint32_t)(g_configs[instance].dataWidth);
550
551 /* dataSize (in bytes) is not aligned to 16bit (2B) transfer */
552 if ((dataWidth > (uint32_t)kSPI_Data8Bits) && ((xfer->dataSize & 0x1U) != 0U))
553 {
554 return kStatus_InvalidArgument;
555 }
556
557 /* clear tx/rx errors and empty FIFOs */
558 base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
559 base->FIFOSTAT |= SPI_FIFOSTAT_TXERR_MASK | SPI_FIFOSTAT_RXERR_MASK;
560 /* select slave to talk with */
561 tx_ctrl |= (SPI_DEASSERT_ALL & (~SPI_DEASSERTNUM_SSEL((uint32_t)(g_configs[instance].sselNum))));
562 /* set width of data - range asserted at entry */
563 tx_ctrl |= SPI_FIFOWR_LEN(dataWidth);
564 /* delay for frames */
565 tx_ctrl |= ((xfer->configFlags & (uint32_t)kSPI_FrameDelay) != 0U) ? (uint32_t)kSPI_FrameDelay : 0U;
566 /* end of transfer */
567 last_ctrl |= ((xfer->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) ? (uint32_t)kSPI_FrameAssert : 0U;
568 /* last index of loop */
569 while ((txRemainingBytes != 0U) || (rxRemainingBytes != 0U) || (toReceiveCount != 0U))
570 {
571 #if SPI_RETRY_TIMES
572 if (--waitTimes == 0U)
573 {
574 return kStatus_SPI_Timeout;
575 }
576 #endif
577 /* if rxFIFO is not empty */
578 if ((base->FIFOSTAT & SPI_FIFOSTAT_RXNOTEMPTY_MASK) != 0U)
579 {
580 tmp32 = base->FIFORD;
581 /* rxBuffer is not empty */
582 if (rxRemainingBytes != 0U)
583 {
584 *(rxData++) = (uint8_t)tmp32;
585 rxRemainingBytes--;
586 /* read 16 bits at once */
587 if (dataWidth > 8U)
588 {
589 *(rxData++) = (uint8_t)(tmp32 >> 8);
590 rxRemainingBytes--;
591 }
592 }
593 /* decrease number of data expected to receive */
594 toReceiveCount -= 1U;
595 }
596 /* transmit if txFIFO is not full and data to receive does not exceed FIFO depth */
597 if (((base->FIFOSTAT & SPI_FIFOSTAT_TXNOTFULL_MASK) != 0U) && (toReceiveCount < fifoDepth) &&
598 ((txRemainingBytes != 0U) || (rxRemainingBytes >= SPI_COUNT_TO_BYTES(dataWidth, toReceiveCount + 1U))))
599 {
600 /* txBuffer is not empty */
601 if (txRemainingBytes != 0U)
602 {
603 tmp32 = *(txData++);
604 txRemainingBytes--;
605 /* write 16 bit at once */
606 if (dataWidth > 8U)
607 {
608 tmp32 |= ((uint32_t)(*(txData++))) << 8U;
609 txRemainingBytes--;
610 }
611 if (txRemainingBytes == 0U)
612 {
613 tx_ctrl |= last_ctrl;
614 }
615 }
616 else
617 {
618 tmp32 = (uint32_t)s_dummyData[instance];
619 tmp32 |= (uint32_t)s_dummyData[instance] << 8U;
620 /* last transfer */
621 if (rxRemainingBytes == SPI_COUNT_TO_BYTES(dataWidth, toReceiveCount + 1U))
622 {
623 tx_ctrl |= last_ctrl;
624 }
625 }
626 /* send data */
627 tmp32 = tx_ctrl | tmp32;
628 base->FIFOWR = tmp32;
629 toReceiveCount += 1U;
630 }
631 }
632 /* wait if TX FIFO of previous transfer is not empty */
633 #if SPI_RETRY_TIMES
634 waitTimes = SPI_RETRY_TIMES;
635 while ((0U == (base->FIFOSTAT & SPI_FIFOSTAT_TXEMPTY_MASK)) && (0U != --waitTimes))
636 #else
637 while (0U == (base->FIFOSTAT & SPI_FIFOSTAT_TXEMPTY_MASK))
638 #endif
639 {
640 }
641 #if SPI_RETRY_TIMES
642 if (waitTimes == 0U)
643 {
644 return kStatus_SPI_Timeout;
645 }
646 #endif
647 return kStatus_Success;
648 }
649
650 /*!
651 * brief Performs a non-blocking SPI interrupt transfer.
652 *
653 * param base SPI peripheral base address.
654 * param handle pointer to spi_master_handle_t structure which stores the transfer state
655 * param xfer pointer to spi_xfer_config_t structure
656 * retval kStatus_Success Successfully start a transfer.
657 * retval kStatus_InvalidArgument Input argument is invalid.
658 * retval kStatus_SPI_Busy SPI is not idle, is running another transfer.
659 */
SPI_MasterTransferNonBlocking(SPI_Type * base,spi_master_handle_t * handle,spi_transfer_t * xfer)660 status_t SPI_MasterTransferNonBlocking(SPI_Type *base, spi_master_handle_t *handle, spi_transfer_t *xfer)
661 {
662 /* check params */
663 assert(
664 !((NULL == base) || (NULL == handle) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData))));
665 if ((NULL == base) || (NULL == handle) || (NULL == xfer) || ((NULL == xfer->txData) && (NULL == xfer->rxData)))
666 {
667 return kStatus_InvalidArgument;
668 }
669
670 /* dataSize (in bytes) is not aligned to 16bit (2B) transfer */
671 assert(!((handle->dataWidth > (uint8_t)kSPI_Data8Bits) && ((xfer->dataSize & 0x1U) != 0U)));
672 if ((handle->dataWidth > (uint8_t)kSPI_Data8Bits) && ((xfer->dataSize & 0x1U) != 0U))
673 {
674 return kStatus_InvalidArgument;
675 }
676
677 /* Check if SPI is busy */
678 if (handle->state == (uint32_t)kStatus_SPI_Busy)
679 {
680 return kStatus_SPI_Busy;
681 }
682
683 /* Set the handle information */
684 handle->txData = xfer->txData;
685 handle->rxData = xfer->rxData;
686 /* set count */
687 handle->txRemainingBytes = (xfer->txData != NULL) ? xfer->dataSize : 0U;
688 handle->rxRemainingBytes = (xfer->rxData != NULL) ? xfer->dataSize : 0U;
689 handle->totalByteCount = xfer->dataSize;
690 /* other options */
691 handle->toReceiveCount = 0;
692 handle->configFlags = xfer->configFlags;
693 /* Set the SPI state to busy */
694 handle->state = (uint32_t)kStatus_SPI_Busy;
695 /* clear FIFOs when transfer starts */
696 base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
697 base->FIFOSTAT |= SPI_FIFOSTAT_TXERR_MASK | SPI_FIFOSTAT_RXERR_MASK;
698 /* enable generating txIRQ and rxIRQ, first transfer is fired by empty txFIFO */
699 base->FIFOINTENSET |= SPI_FIFOINTENSET_TXLVL_MASK | SPI_FIFOINTENSET_RXLVL_MASK;
700 return kStatus_Success;
701 }
702
703 /*!
704 * brief Transfers a block of data using a polling method.
705 *
706 * This function will do a half-duplex transfer for SPI master, This is a blocking function,
707 * which does not retuen until all transfer have been completed. And data transfer mechanism is half-duplex,
708 * users can set transmit first or receive first.
709 *
710 * param base SPI base pointer
711 * param xfer pointer to spi_half_duplex_transfer_t structure
712 * return status of status_t.
713 */
SPI_MasterHalfDuplexTransferBlocking(SPI_Type * base,spi_half_duplex_transfer_t * xfer)714 status_t SPI_MasterHalfDuplexTransferBlocking(SPI_Type *base, spi_half_duplex_transfer_t *xfer)
715 {
716 assert(xfer != NULL);
717
718 spi_transfer_t tempXfer = {0};
719 status_t status;
720
721 if (xfer->isTransmitFirst)
722 {
723 tempXfer.txData = xfer->txData;
724 tempXfer.rxData = NULL;
725 tempXfer.dataSize = xfer->txDataSize;
726 }
727 else
728 {
729 tempXfer.txData = NULL;
730 tempXfer.rxData = xfer->rxData;
731 tempXfer.dataSize = xfer->rxDataSize;
732 }
733 /* If the pcs pin keep assert between transmit and receive. */
734 if (xfer->isPcsAssertInTransfer)
735 {
736 tempXfer.configFlags = (xfer->configFlags) & (~(uint32_t)kSPI_FrameAssert);
737 }
738 else
739 {
740 tempXfer.configFlags = (xfer->configFlags) | (uint32_t)kSPI_FrameAssert;
741 }
742
743 status = SPI_MasterTransferBlocking(base, &tempXfer);
744
745 if (status != kStatus_Success)
746 {
747 return status;
748 }
749
750 if (xfer->isTransmitFirst)
751 {
752 tempXfer.txData = NULL;
753 tempXfer.rxData = xfer->rxData;
754 tempXfer.dataSize = xfer->rxDataSize;
755 }
756 else
757 {
758 tempXfer.txData = xfer->txData;
759 tempXfer.rxData = NULL;
760 tempXfer.dataSize = xfer->txDataSize;
761 }
762 tempXfer.configFlags = xfer->configFlags;
763
764 /* SPI transfer blocking. */
765 status = SPI_MasterTransferBlocking(base, &tempXfer);
766
767 return status;
768 }
769
770 /*!
771 * brief Performs a non-blocking SPI interrupt transfer.
772 *
773 * This function using polling way to do the first half transimission and using interrupts to
774 * do the second half transimission, the transfer mechanism is half-duplex.
775 * When do the second half transimission, code will return right away. When all data is transferred,
776 * the callback function is called.
777 *
778 * param base SPI peripheral base address.
779 * param handle pointer to spi_master_handle_t structure which stores the transfer state
780 * param xfer pointer to spi_half_duplex_transfer_t structure
781 * return status of status_t.
782 */
SPI_MasterHalfDuplexTransferNonBlocking(SPI_Type * base,spi_master_handle_t * handle,spi_half_duplex_transfer_t * xfer)783 status_t SPI_MasterHalfDuplexTransferNonBlocking(SPI_Type *base,
784 spi_master_handle_t *handle,
785 spi_half_duplex_transfer_t *xfer)
786 {
787 assert(xfer != NULL);
788 assert(handle != NULL);
789 spi_transfer_t tempXfer = {0};
790 status_t status;
791
792 if (xfer->isTransmitFirst)
793 {
794 tempXfer.txData = xfer->txData;
795 tempXfer.rxData = NULL;
796 tempXfer.dataSize = xfer->txDataSize;
797 }
798 else
799 {
800 tempXfer.txData = NULL;
801 tempXfer.rxData = xfer->rxData;
802 tempXfer.dataSize = xfer->rxDataSize;
803 }
804 /* If the PCS pin keep assert between transmit and receive. */
805 if (xfer->isPcsAssertInTransfer)
806 {
807 tempXfer.configFlags = (xfer->configFlags) & (~(uint32_t)kSPI_FrameAssert);
808 }
809 else
810 {
811 tempXfer.configFlags = (xfer->configFlags) | (uint32_t)kSPI_FrameAssert;
812 }
813
814 status = SPI_MasterTransferBlocking(base, &tempXfer);
815 if (status != kStatus_Success)
816 {
817 return status;
818 }
819
820 if (xfer->isTransmitFirst)
821 {
822 tempXfer.txData = NULL;
823 tempXfer.rxData = xfer->rxData;
824 tempXfer.dataSize = xfer->rxDataSize;
825 }
826 else
827 {
828 tempXfer.txData = xfer->txData;
829 tempXfer.rxData = NULL;
830 tempXfer.dataSize = xfer->txDataSize;
831 }
832 tempXfer.configFlags = xfer->configFlags;
833
834 status = SPI_MasterTransferNonBlocking(base, handle, &tempXfer);
835
836 return status;
837 }
838
839 /*!
840 * brief Gets the master transfer count.
841 *
842 * This function gets the master transfer count.
843 *
844 * param base SPI peripheral base address.
845 * param handle Pointer to the spi_master_handle_t structure which stores the transfer state.
846 * param count The number of bytes transferred by using the non-blocking transaction.
847 * return status of status_t.
848 */
SPI_MasterTransferGetCount(SPI_Type * base,spi_master_handle_t * handle,size_t * count)849 status_t SPI_MasterTransferGetCount(SPI_Type *base, spi_master_handle_t *handle, size_t *count)
850 {
851 assert(NULL != handle);
852
853 if (NULL == count)
854 {
855 return kStatus_InvalidArgument;
856 }
857
858 /* Catch when there is not an active transfer. */
859 if (handle->state != (uint32_t)kStatus_SPI_Busy)
860 {
861 *count = 0;
862 return kStatus_NoTransferInProgress;
863 }
864
865 *count = handle->totalByteCount - handle->rxRemainingBytes;
866 return kStatus_Success;
867 }
868
869 /*!
870 * brief SPI master aborts a transfer using an interrupt.
871 *
872 * This function aborts a transfer using an interrupt.
873 *
874 * param base SPI peripheral base address.
875 * param handle Pointer to the spi_master_handle_t structure which stores the transfer state.
876 */
SPI_MasterTransferAbort(SPI_Type * base,spi_master_handle_t * handle)877 void SPI_MasterTransferAbort(SPI_Type *base, spi_master_handle_t *handle)
878 {
879 assert(NULL != handle);
880
881 /* Disable interrupt requests*/
882 base->FIFOINTENSET &= ~(SPI_FIFOINTENSET_TXLVL_MASK | SPI_FIFOINTENSET_RXLVL_MASK);
883 /* Empty FIFOs */
884 base->FIFOCFG |= SPI_FIFOCFG_EMPTYTX_MASK | SPI_FIFOCFG_EMPTYRX_MASK;
885
886 handle->state = (uint32_t)kStatus_SPI_Idle;
887 handle->txRemainingBytes = 0U;
888 handle->rxRemainingBytes = 0U;
889 }
890
SPI_TransferHandleIRQInternal(SPI_Type * base,spi_master_handle_t * handle)891 static void SPI_TransferHandleIRQInternal(SPI_Type *base, spi_master_handle_t *handle)
892 {
893 uint32_t tx_ctrl = 0U, last_ctrl = 0U, tmp32;
894 bool loopContinue;
895 uint32_t fifoDepth;
896 /* Get flexcomm instance by 'base' param */
897 uint32_t instance = SPI_GetInstance(base);
898 size_t txRemainingBytes;
899 size_t rxRemainingBytes;
900 uint8_t toReceiveCount;
901
902 /* check params */
903 assert((NULL != base) && (NULL != handle) && ((NULL != handle->txData) || (NULL != handle->rxData)));
904
905 fifoDepth = SPI_FIFO_DEPTH(base);
906 /* select slave to talk with */
907 tx_ctrl |= ((uint32_t)SPI_DEASSERT_ALL & (uint32_t)SPI_ASSERTNUM_SSEL(handle->sselNum));
908 /* set width of data */
909 tx_ctrl |= SPI_FIFOWR_LEN(handle->dataWidth);
910 /* delay for frames */
911 tx_ctrl |= ((handle->configFlags & (uint32_t)kSPI_FrameDelay) != 0U) ? (uint32_t)kSPI_FrameDelay : 0U;
912 /* end of transfer */
913 last_ctrl |= ((handle->configFlags & (uint32_t)kSPI_FrameAssert) != 0U) ? (uint32_t)kSPI_FrameAssert : 0U;
914 do
915 {
916 loopContinue = false;
917
918 /* rxFIFO is not empty */
919 if ((base->FIFOSTAT & SPI_FIFOSTAT_RXNOTEMPTY_MASK) != 0U)
920 {
921 tmp32 = base->FIFORD;
922 /* rxBuffer is not empty */
923 if (handle->rxRemainingBytes != 0U)
924 {
925 /* low byte must go first */
926 *(handle->rxData++) = (uint8_t)tmp32;
927 handle->rxRemainingBytes--;
928 /* read 16 bits at once */
929 if (handle->dataWidth > (uint8_t)kSPI_Data8Bits)
930 {
931 *(handle->rxData++) = (uint8_t)(tmp32 >> 8);
932 handle->rxRemainingBytes--;
933 }
934 }
935
936 /* decrease number of data expected to receive */
937 handle->toReceiveCount -= 1;
938 loopContinue = true;
939 }
940
941 /* - txFIFO is not full
942 * - we cannot cause rxFIFO overflow by sending more data than is the depth of FIFO
943 * - txBuffer is not empty or the next 'toReceiveCount' data can fit into rxBuffer
944 */
945 txRemainingBytes = handle->txRemainingBytes;
946 rxRemainingBytes = handle->rxRemainingBytes;
947 toReceiveCount = (handle->toReceiveCount > 0) ? (uint8_t)handle->toReceiveCount : 0U;
948 if (((base->FIFOSTAT & SPI_FIFOSTAT_TXNOTFULL_MASK) != 0U) && ((uint32_t)toReceiveCount < fifoDepth) &&
949 ((txRemainingBytes != 0U) ||
950 (rxRemainingBytes >= SPI_COUNT_TO_BYTES(handle->dataWidth, (uint32_t)toReceiveCount + 1U))))
951 {
952 /* txBuffer is not empty */
953 if ((txRemainingBytes != 0U) && (handle->txData != NULL))
954 {
955 /* low byte must go first */
956 tmp32 = *(handle->txData++);
957 handle->txRemainingBytes--;
958 txRemainingBytes = handle->txRemainingBytes;
959 /* write 16 bit at once */
960 if (handle->dataWidth > (uint8_t)kSPI_Data8Bits)
961 {
962 tmp32 |= ((uint32_t)(*(handle->txData++))) << 8U;
963 handle->txRemainingBytes--;
964 txRemainingBytes = handle->txRemainingBytes;
965 }
966 /* last transfer */
967 if (handle->txRemainingBytes == 0U)
968 {
969 tx_ctrl |= last_ctrl;
970 }
971 }
972 else
973 {
974 tmp32 = (uint32_t)s_dummyData[instance];
975 tmp32 |= (uint32_t)s_dummyData[instance] << 8U;
976 /* last transfer */
977 if (rxRemainingBytes == SPI_COUNT_TO_BYTES(handle->dataWidth, (uint32_t)toReceiveCount + 1U))
978 {
979 tx_ctrl |= last_ctrl;
980 }
981 }
982 /* send data */
983 tmp32 = tx_ctrl | tmp32;
984 base->FIFOWR = tmp32;
985 /* increase number of expected data to receive */
986 handle->toReceiveCount += 1;
987 toReceiveCount = (handle->toReceiveCount > 0) ? (uint8_t)handle->toReceiveCount : 0U;
988 loopContinue = true;
989 }
990 } while (loopContinue);
991 }
992
993 /*!
994 * brief Interrupts the handler for the SPI.
995 *
996 * param base SPI peripheral base address.
997 * param handle pointer to spi_master_handle_t structure which stores the transfer state.
998 */
SPI_MasterTransferHandleIRQ(SPI_Type * base,spi_master_handle_t * handle)999 void SPI_MasterTransferHandleIRQ(SPI_Type *base, spi_master_handle_t *handle)
1000 {
1001 assert((NULL != base) && (NULL != handle));
1002 size_t txRemainingBytes;
1003 uint8_t toReceiveCount;
1004
1005 /* IRQ behaviour:
1006 * - first interrupt is triggered by empty txFIFO. The transfer function
1007 * then tries empty rxFIFO and fill txFIFO interleaved that results to
1008 * strategy to process as many items as possible.
1009 * - the next IRQs can be:
1010 * rxIRQ from nonempty rxFIFO which requires to empty rxFIFO.
1011 * txIRQ from empty txFIFO which requires to refill txFIFO.
1012 * - last interrupt is triggered by empty txFIFO. The last state is
1013 * known by empty rxBuffer and txBuffer. If there is nothing to receive
1014 * or send - both operations have been finished and interrupts can be
1015 * disabled.
1016 */
1017
1018 /* Data to send or read or expected to receive */
1019 if ((handle->txRemainingBytes != 0U) || (handle->rxRemainingBytes != 0U) || (handle->toReceiveCount != 0))
1020 {
1021 /* Transmit or receive data */
1022 SPI_TransferHandleIRQInternal(base, handle);
1023 /* No data to send or read or receive. Transfer ends. Set txTrigger to 0 level and
1024 * enable txIRQ to confirm when txFIFO becomes empty */
1025 if ((0U == handle->txRemainingBytes) && (0U == handle->rxRemainingBytes) && (0 == handle->toReceiveCount))
1026 {
1027 base->FIFOTRIG = base->FIFOTRIG & (~SPI_FIFOTRIG_TXLVL_MASK);
1028 base->FIFOINTENSET |= SPI_FIFOINTENSET_TXLVL_MASK;
1029 }
1030 else
1031 {
1032 uint32_t rxRemainingCount = SPI_BYTES_TO_COUNT(handle->dataWidth, handle->rxRemainingBytes);
1033 /* If, there are no data to send or rxFIFO is already filled with necessary number of dummy data,
1034 * disable txIRQ. From this point only rxIRQ is used to receive data without any transmission */
1035 toReceiveCount = (handle->toReceiveCount > 0) ? (uint8_t)handle->toReceiveCount : 0U;
1036 if ((0U == handle->txRemainingBytes) && (rxRemainingCount <= toReceiveCount))
1037 {
1038 base->FIFOINTENCLR = SPI_FIFOINTENCLR_TXLVL_MASK;
1039 }
1040 /* Nothing to receive or transmit, but we still have pending data which are bellow rxLevel.
1041 * Cannot clear rxFIFO, txFIFO might be still active */
1042 if (rxRemainingCount == 0U)
1043 {
1044 txRemainingBytes = handle->txRemainingBytes;
1045 if ((txRemainingBytes == 0U) && (toReceiveCount != 0U) &&
1046 (toReceiveCount < SPI_FIFOTRIG_RXLVL_GET(base) + 1U))
1047 {
1048 base->FIFOTRIG = (base->FIFOTRIG & (~SPI_FIFOTRIG_RXLVL_MASK)) |
1049 SPI_FIFOTRIG_RXLVL((uint32_t)toReceiveCount - 1U);
1050 }
1051 }
1052 else
1053 {
1054 /* Expected to receive less data than rxLevel value, we have to update rxLevel */
1055 if (rxRemainingCount < (SPI_FIFOTRIG_RXLVL_GET(base) + 1U))
1056 {
1057 base->FIFOTRIG =
1058 (base->FIFOTRIG & (~SPI_FIFOTRIG_RXLVL_MASK)) | SPI_FIFOTRIG_RXLVL(rxRemainingCount - 1U);
1059 }
1060 }
1061 }
1062 }
1063 else
1064 {
1065 /* Empty txFIFO is confirmed. Disable IRQs and restore triggers values */
1066 base->FIFOINTENCLR = SPI_FIFOINTENCLR_RXLVL_MASK | SPI_FIFOINTENCLR_TXLVL_MASK;
1067 base->FIFOTRIG = (base->FIFOTRIG & (~(SPI_FIFOTRIG_RXLVL_MASK | SPI_FIFOTRIG_RXLVL_MASK))) |
1068 SPI_FIFOTRIG_RXLVL(handle->rxWatermark) | SPI_FIFOTRIG_TXLVL(handle->txWatermark);
1069 /* set idle state and call user callback */
1070 handle->state = (uint32_t)kStatus_SPI_Idle;
1071 if (handle->callback != NULL)
1072 {
1073 (handle->callback)(base, handle, handle->state, handle->userData);
1074 }
1075 }
1076 }
1077