1 | /* |
2 | * Copyright (c) 2015, Freescale Semiconductor, Inc. |
3 | * Copyright 2016-2020,2021 NXP |
4 | * All rights reserved. |
5 | * |
6 | * SPDX-License-Identifier: BSD-3-Clause |
7 | */ |
8 | |
9 | #include "fsl_lpspi.h" |
10 | |
11 | /******************************************************************************* |
12 | * Definitions |
13 | ******************************************************************************/ |
14 | |
15 | /* Component ID definition, used by tools. */ |
16 | #ifndef FSL_COMPONENT_ID |
17 | #define FSL_COMPONENT_ID "platform.drivers.lpspi" |
18 | #endif |
19 | |
20 | /*! |
21 | * @brief Default watermark values. |
22 | * |
23 | * The default watermarks are set to zero. |
24 | */ |
25 | enum _lpspi_default_watermarks |
26 | { |
27 | kLpspiDefaultTxWatermark = 0, |
28 | kLpspiDefaultRxWatermark = 0, |
29 | }; |
30 | |
31 | /*! @brief Typedef for master interrupt handler. */ |
32 | typedef void (*lpspi_master_isr_t)(LPSPI_Type *base, lpspi_master_handle_t *handle); |
33 | |
34 | /*! @brief Typedef for slave interrupt handler. */ |
35 | typedef void (*lpspi_slave_isr_t)(LPSPI_Type *base, lpspi_slave_handle_t *handle); |
36 | |
37 | /******************************************************************************* |
38 | * Prototypes |
39 | ******************************************************************************/ |
40 | |
41 | /*! |
42 | * @brief Configures the LPSPI peripheral chip select polarity. |
43 | * |
44 | * This function takes in the desired peripheral chip select (Pcs) and it's corresponding desired polarity and |
45 | * configures the Pcs signal to operate with the desired characteristic. |
46 | * |
47 | * @param base LPSPI peripheral address. |
48 | * @param pcs The particular peripheral chip select (parameter value is of type lpspi_which_pcs_t) for which we wish to |
49 | * apply the active high or active low characteristic. |
50 | * @param activeLowOrHigh The setting for either "active high, inactive low (0)" or "active low, inactive high(1)" of |
51 | * type lpspi_pcs_polarity_config_t. |
52 | */ |
53 | static void LPSPI_SetOnePcsPolarity(LPSPI_Type *base, |
54 | lpspi_which_pcs_t pcs, |
55 | lpspi_pcs_polarity_config_t activeLowOrHigh); |
56 | |
57 | /*! |
58 | * @brief Combine the write data for 1 byte to 4 bytes. |
59 | * This is not a public API. |
60 | */ |
61 | static uint32_t LPSPI_CombineWriteData(uint8_t *txData, uint8_t bytesEachWrite, bool isByteSwap); |
62 | |
63 | /*! |
64 | * @brief Separate the read data for 1 byte to 4 bytes. |
65 | * This is not a public API. |
66 | */ |
67 | static void LPSPI_SeparateReadData(uint8_t *rxData, uint32_t readData, uint8_t bytesEachRead, bool isByteSwap); |
68 | |
69 | /*! |
70 | * @brief Wait for tx FIFO to be empty. |
71 | * This is not a public API. |
72 | * @param base LPSPI peripheral address. |
73 | * @return true for the tx FIFO is ready, false is not. |
74 | */ |
75 | static bool LPSPI_TxFifoReady(LPSPI_Type *base); |
76 | |
77 | /*! |
78 | * @brief Master fill up the TX FIFO with data. |
79 | * This is not a public API. |
80 | */ |
81 | static void LPSPI_MasterTransferFillUpTxFifo(LPSPI_Type *base, lpspi_master_handle_t *handle); |
82 | |
83 | /*! |
84 | * @brief Master finish up a transfer. |
85 | * It would call back if there is callback function and set the state to idle. |
86 | * This is not a public API. |
87 | */ |
88 | static void LPSPI_MasterTransferComplete(LPSPI_Type *base, lpspi_master_handle_t *handle); |
89 | |
90 | /*! |
91 | * @brief Slave fill up the TX FIFO with data. |
92 | * This is not a public API. |
93 | */ |
94 | static void LPSPI_SlaveTransferFillUpTxFifo(LPSPI_Type *base, lpspi_slave_handle_t *handle); |
95 | |
96 | /*! |
97 | * @brief Slave finish up a transfer. |
98 | * It would call back if there is callback function and set the state to idle. |
99 | * This is not a public API. |
100 | */ |
101 | static void LPSPI_SlaveTransferComplete(LPSPI_Type *base, lpspi_slave_handle_t *handle); |
102 | |
103 | /*! |
104 | * @brief LPSPI common interrupt handler. |
105 | * |
106 | * @param handle pointer to s_lpspiHandle which stores the transfer state. |
107 | */ |
108 | static void LPSPI_CommonIRQHandler(LPSPI_Type *base, void *param); |
109 | |
110 | /******************************************************************************* |
111 | * Variables |
112 | ******************************************************************************/ |
113 | |
114 | /* Defines constant value arrays for the baud rate pre-scalar and scalar divider values.*/ |
115 | static const uint8_t s_baudratePrescaler[] = {1, 2, 4, 8, 16, 32, 64, 128}; |
116 | |
117 | /*! @brief Pointers to lpspi bases for each instance. */ |
118 | static LPSPI_Type *const s_lpspiBases[] = LPSPI_BASE_PTRS; |
119 | |
120 | /*! @brief Pointers to lpspi IRQ number for each instance. */ |
121 | static const IRQn_Type s_lpspiIRQ[] = LPSPI_IRQS; |
122 | |
123 | #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) |
124 | /*! @brief Pointers to lpspi clocks for each instance. */ |
125 | static const clock_ip_name_t s_lpspiClocks[] = LPSPI_CLOCKS; |
126 | |
127 | #if defined(LPSPI_PERIPH_CLOCKS) |
128 | static const clock_ip_name_t s_LpspiPeriphClocks[] = LPSPI_PERIPH_CLOCKS; |
129 | #endif |
130 | |
131 | #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ |
132 | |
133 | /*! @brief Pointers to lpspi handles for each instance. */ |
134 | static void *s_lpspiHandle[ARRAY_SIZE(s_lpspiBases)]; |
135 | |
136 | /*! @brief Pointer to master IRQ handler for each instance. */ |
137 | static lpspi_master_isr_t s_lpspiMasterIsr; |
138 | /*! @brief Pointer to slave IRQ handler for each instance. */ |
139 | static lpspi_slave_isr_t s_lpspiSlaveIsr; |
140 | /* @brief Dummy data for each instance. This data is used when user's tx buffer is NULL*/ |
141 | volatile uint8_t g_lpspiDummyData[ARRAY_SIZE(s_lpspiBases)] = {0}; |
142 | |
143 | /********************************************************************************************************************** |
144 | * Code |
145 | *********************************************************************************************************************/ |
146 | |
147 | /*! |
148 | * brief Get the LPSPI instance from peripheral base address. |
149 | * |
150 | * param base LPSPI peripheral base address. |
151 | * return LPSPI instance. |
152 | */ |
153 | uint32_t LPSPI_GetInstance(LPSPI_Type *base) |
154 | { |
155 | uint8_t instance = 0; |
156 | |
157 | /* Find the instance index from base address mappings. */ |
158 | for (instance = 0; instance < ARRAY_SIZE(s_lpspiBases); instance++) |
159 | { |
160 | if (s_lpspiBases[instance] == base) |
161 | { |
162 | break; |
163 | } |
164 | } |
165 | |
166 | assert(instance < ARRAY_SIZE(s_lpspiBases)); |
167 | |
168 | return instance; |
169 | } |
170 | |
171 | /*! |
172 | * brief Set up the dummy data. |
173 | * |
174 | * param base LPSPI peripheral address. |
175 | * param dummyData Data to be transferred when tx buffer is NULL. |
176 | * Note: |
177 | * This API has no effect when LPSPI in slave interrupt mode, because driver |
178 | * will set the TXMSK bit to 1 if txData is NULL, no data is loaded from transmit |
179 | * FIFO and output pin is tristated. |
180 | */ |
181 | void LPSPI_SetDummyData(LPSPI_Type *base, uint8_t dummyData) |
182 | { |
183 | uint32_t instance = LPSPI_GetInstance(base); |
184 | g_lpspiDummyData[instance] = dummyData; |
185 | } |
186 | |
187 | /*! |
188 | * brief Initializes the LPSPI master. |
189 | * |
190 | * param base LPSPI peripheral address. |
191 | * param masterConfig Pointer to structure lpspi_master_config_t. |
192 | * param srcClock_Hz Module source input clock in Hertz |
193 | */ |
194 | void LPSPI_MasterInit(LPSPI_Type *base, const lpspi_master_config_t *masterConfig, uint32_t srcClock_Hz) |
195 | { |
196 | assert(masterConfig != NULL); |
197 | |
198 | uint32_t tcrPrescaleValue = 0; |
199 | |
200 | #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) |
201 | |
202 | uint32_t instance = LPSPI_GetInstance(base); |
203 | /* Enable LPSPI clock */ |
204 | (void)CLOCK_EnableClock(s_lpspiClocks[instance]); |
205 | |
206 | #if defined(LPSPI_PERIPH_CLOCKS) |
207 | (void)CLOCK_EnableClock(s_LpspiPeriphClocks[instance]); |
208 | #endif |
209 | |
210 | #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ |
211 | |
212 | /* Set LPSPI to master */ |
213 | LPSPI_SetMasterSlaveMode(base, kLPSPI_Master); |
214 | |
215 | /* Set specific PCS to active high or low */ |
216 | LPSPI_SetOnePcsPolarity(base, masterConfig->whichPcs, masterConfig->pcsActiveHighOrLow); |
217 | |
218 | /* Set Configuration Register 1 related setting.*/ |
219 | base->CFGR1 = (base->CFGR1 & ~(LPSPI_CFGR1_OUTCFG_MASK | LPSPI_CFGR1_PINCFG_MASK | LPSPI_CFGR1_NOSTALL_MASK)) | |
220 | LPSPI_CFGR1_OUTCFG(masterConfig->dataOutConfig) | LPSPI_CFGR1_PINCFG(masterConfig->pinCfg) | |
221 | LPSPI_CFGR1_NOSTALL(0); |
222 | |
223 | /* Set baudrate and delay times*/ |
224 | (void)LPSPI_MasterSetBaudRate(base, masterConfig->baudRate, srcClock_Hz, &tcrPrescaleValue); |
225 | |
226 | /* Set default watermarks */ |
227 | LPSPI_SetFifoWatermarks(base, (uint32_t)kLpspiDefaultTxWatermark, (uint32_t)kLpspiDefaultRxWatermark); |
228 | |
229 | /* Set Transmit Command Register*/ |
230 | base->TCR = LPSPI_TCR_CPOL(masterConfig->cpol) | LPSPI_TCR_CPHA(masterConfig->cpha) | |
231 | LPSPI_TCR_LSBF(masterConfig->direction) | LPSPI_TCR_FRAMESZ(masterConfig->bitsPerFrame - 1U) | |
232 | LPSPI_TCR_PRESCALE(tcrPrescaleValue) | LPSPI_TCR_PCS(masterConfig->whichPcs); |
233 | |
234 | LPSPI_Enable(base, true); |
235 | |
236 | (void)LPSPI_MasterSetDelayTimes(base, masterConfig->pcsToSckDelayInNanoSec, kLPSPI_PcsToSck, srcClock_Hz); |
237 | (void)LPSPI_MasterSetDelayTimes(base, masterConfig->lastSckToPcsDelayInNanoSec, kLPSPI_LastSckToPcs, srcClock_Hz); |
238 | (void)LPSPI_MasterSetDelayTimes(base, masterConfig->betweenTransferDelayInNanoSec, kLPSPI_BetweenTransfer, |
239 | srcClock_Hz); |
240 | |
241 | LPSPI_SetDummyData(base, LPSPI_DUMMY_DATA); |
242 | } |
243 | |
244 | /*! |
245 | * brief Sets the lpspi_master_config_t structure to default values. |
246 | * |
247 | * This API initializes the configuration structure for LPSPI_MasterInit(). |
248 | * The initialized structure can remain unchanged in LPSPI_MasterInit(), or can be modified |
249 | * before calling the LPSPI_MasterInit(). |
250 | * Example: |
251 | * code |
252 | * lpspi_master_config_t masterConfig; |
253 | * LPSPI_MasterGetDefaultConfig(&masterConfig); |
254 | * endcode |
255 | * param masterConfig pointer to lpspi_master_config_t structure |
256 | */ |
257 | void LPSPI_MasterGetDefaultConfig(lpspi_master_config_t *masterConfig) |
258 | { |
259 | assert(masterConfig != NULL); |
260 | |
261 | /* Initializes the configure structure to zero. */ |
262 | (void)memset(masterConfig, 0, sizeof(*masterConfig)); |
263 | |
264 | masterConfig->baudRate = 500000; |
265 | masterConfig->bitsPerFrame = 8; |
266 | masterConfig->cpol = kLPSPI_ClockPolarityActiveHigh; |
267 | masterConfig->cpha = kLPSPI_ClockPhaseFirstEdge; |
268 | masterConfig->direction = kLPSPI_MsbFirst; |
269 | |
270 | masterConfig->pcsToSckDelayInNanoSec = 1000000000U / masterConfig->baudRate * 2U; |
271 | masterConfig->lastSckToPcsDelayInNanoSec = 1000000000U / masterConfig->baudRate * 2U; |
272 | masterConfig->betweenTransferDelayInNanoSec = 1000000000U / masterConfig->baudRate * 2U; |
273 | |
274 | masterConfig->whichPcs = kLPSPI_Pcs0; |
275 | masterConfig->pcsActiveHighOrLow = kLPSPI_PcsActiveLow; |
276 | |
277 | masterConfig->pinCfg = kLPSPI_SdiInSdoOut; |
278 | masterConfig->dataOutConfig = kLpspiDataOutRetained; |
279 | } |
280 | |
281 | /*! |
282 | * brief LPSPI slave configuration. |
283 | * |
284 | * param base LPSPI peripheral address. |
285 | * param slaveConfig Pointer to a structure lpspi_slave_config_t. |
286 | */ |
287 | void LPSPI_SlaveInit(LPSPI_Type *base, const lpspi_slave_config_t *slaveConfig) |
288 | { |
289 | assert(slaveConfig != NULL); |
290 | |
291 | #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) |
292 | |
293 | uint32_t instance = LPSPI_GetInstance(base); |
294 | /* Enable LPSPI clock */ |
295 | (void)CLOCK_EnableClock(s_lpspiClocks[instance]); |
296 | |
297 | #if defined(LPSPI_PERIPH_CLOCKS) |
298 | (void)CLOCK_EnableClock(s_LpspiPeriphClocks[instance]); |
299 | #endif |
300 | |
301 | #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ |
302 | |
303 | LPSPI_SetMasterSlaveMode(base, kLPSPI_Slave); |
304 | |
305 | LPSPI_SetOnePcsPolarity(base, slaveConfig->whichPcs, slaveConfig->pcsActiveHighOrLow); |
306 | |
307 | base->CFGR1 = (base->CFGR1 & ~(LPSPI_CFGR1_OUTCFG_MASK | LPSPI_CFGR1_PINCFG_MASK)) | |
308 | LPSPI_CFGR1_OUTCFG(slaveConfig->dataOutConfig) | LPSPI_CFGR1_PINCFG(slaveConfig->pinCfg); |
309 | |
310 | LPSPI_SetFifoWatermarks(base, (uint32_t)kLpspiDefaultTxWatermark, (uint32_t)kLpspiDefaultRxWatermark); |
311 | |
312 | base->TCR = LPSPI_TCR_CPOL(slaveConfig->cpol) | LPSPI_TCR_CPHA(slaveConfig->cpha) | |
313 | LPSPI_TCR_LSBF(slaveConfig->direction) | LPSPI_TCR_FRAMESZ(slaveConfig->bitsPerFrame - 1U); |
314 | |
315 | /* This operation will set the dummy data for edma transfer, no effect in interrupt way. */ |
316 | LPSPI_SetDummyData(base, LPSPI_DUMMY_DATA); |
317 | |
318 | LPSPI_Enable(base, true); |
319 | } |
320 | |
321 | /*! |
322 | * brief Sets the lpspi_slave_config_t structure to default values. |
323 | * |
324 | * This API initializes the configuration structure for LPSPI_SlaveInit(). |
325 | * The initialized structure can remain unchanged in LPSPI_SlaveInit() or can be modified |
326 | * before calling the LPSPI_SlaveInit(). |
327 | * Example: |
328 | * code |
329 | * lpspi_slave_config_t slaveConfig; |
330 | * LPSPI_SlaveGetDefaultConfig(&slaveConfig); |
331 | * endcode |
332 | * param slaveConfig pointer to lpspi_slave_config_t structure. |
333 | */ |
334 | void LPSPI_SlaveGetDefaultConfig(lpspi_slave_config_t *slaveConfig) |
335 | { |
336 | assert(slaveConfig != NULL); |
337 | |
338 | /* Initializes the configure structure to zero. */ |
339 | (void)memset(slaveConfig, 0, sizeof(*slaveConfig)); |
340 | |
341 | slaveConfig->bitsPerFrame = 8; /*!< Bits per frame, minimum 8, maximum 4096.*/ |
342 | slaveConfig->cpol = kLPSPI_ClockPolarityActiveHigh; /*!< Clock polarity. */ |
343 | slaveConfig->cpha = kLPSPI_ClockPhaseFirstEdge; /*!< Clock phase. */ |
344 | slaveConfig->direction = kLPSPI_MsbFirst; /*!< MSB or LSB data shift direction. */ |
345 | |
346 | slaveConfig->whichPcs = kLPSPI_Pcs0; /*!< Desired Peripheral Chip Select (pcs) */ |
347 | slaveConfig->pcsActiveHighOrLow = kLPSPI_PcsActiveLow; /*!< Desired PCS active high or low */ |
348 | |
349 | slaveConfig->pinCfg = kLPSPI_SdiInSdoOut; |
350 | slaveConfig->dataOutConfig = kLpspiDataOutRetained; |
351 | } |
352 | |
353 | /*! |
354 | * brief Restores the LPSPI peripheral to reset state. Note that this function |
355 | * sets all registers to reset state. As a result, the LPSPI module can't work after calling |
356 | * this API. |
357 | * param base LPSPI peripheral address. |
358 | */ |
359 | void LPSPI_Reset(LPSPI_Type *base) |
360 | { |
361 | /* Reset all internal logic and registers, except the Control Register. Remains set until cleared by software.*/ |
362 | base->CR |= LPSPI_CR_RST_MASK; |
363 | |
364 | /* Software reset doesn't reset the CR, so manual reset the FIFOs */ |
365 | base->CR |= LPSPI_CR_RRF_MASK | LPSPI_CR_RTF_MASK; |
366 | |
367 | /* Master logic is not reset and module is disabled.*/ |
368 | base->CR = 0x00U; |
369 | } |
370 | |
371 | /*! |
372 | * brief De-initializes the LPSPI peripheral. Call this API to disable the LPSPI clock. |
373 | * param base LPSPI peripheral address. |
374 | */ |
375 | void LPSPI_Deinit(LPSPI_Type *base) |
376 | { |
377 | /* Reset to default value */ |
378 | LPSPI_Reset(base); |
379 | |
380 | #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) |
381 | |
382 | uint32_t instance = LPSPI_GetInstance(base); |
383 | /* Enable LPSPI clock */ |
384 | (void)CLOCK_DisableClock(s_lpspiClocks[instance]); |
385 | |
386 | #if defined(LPSPI_PERIPH_CLOCKS) |
387 | (void)CLOCK_DisableClock(s_LpspiPeriphClocks[instance]); |
388 | #endif |
389 | |
390 | #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ |
391 | } |
392 | |
393 | static void LPSPI_SetOnePcsPolarity(LPSPI_Type *base, |
394 | lpspi_which_pcs_t pcs, |
395 | lpspi_pcs_polarity_config_t activeLowOrHigh) |
396 | { |
397 | uint32_t cfgr1Value = 0; |
398 | /* Clear the PCS polarity bit */ |
399 | cfgr1Value = base->CFGR1 & ~(1UL << (LPSPI_CFGR1_PCSPOL_SHIFT + (uint32_t)pcs)); |
400 | |
401 | /* Configure the PCS polarity bit according to the activeLowOrHigh setting */ |
402 | base->CFGR1 = cfgr1Value | ((uint32_t)activeLowOrHigh << (LPSPI_CFGR1_PCSPOL_SHIFT + (uint32_t)pcs)); |
403 | } |
404 | |
405 | /*! |
406 | * brief Sets the LPSPI baud rate in bits per second. |
407 | * |
408 | * This function takes in the desired bitsPerSec (baud rate) and calculates the nearest |
409 | * possible baud rate without exceeding the desired baud rate and returns the |
410 | * calculated baud rate in bits-per-second. It requires the caller to provide |
411 | * the frequency of the module source clock (in Hertz). Note that the baud rate |
412 | * does not go into effect until the Transmit Control Register (TCR) is programmed |
413 | * with the prescale value. Hence, this function returns the prescale tcrPrescaleValue |
414 | * parameter for later programming in the TCR. The higher level |
415 | * peripheral driver should alert the user of an out of range baud rate input. |
416 | * |
417 | * Note that the LPSPI module must first be disabled before configuring this. |
418 | * Note that the LPSPI module must be configured for master mode before configuring this. |
419 | * |
420 | * param base LPSPI peripheral address. |
421 | * param baudRate_Bps The desired baud rate in bits per second. |
422 | * param srcClock_Hz Module source input clock in Hertz. |
423 | * param tcrPrescaleValue The TCR prescale value needed to program the TCR. |
424 | * return The actual calculated baud rate. This function may also return a "0" if the |
425 | * LPSPI is not configured for master mode or if the LPSPI module is not disabled. |
426 | */ |
427 | |
428 | uint32_t LPSPI_MasterSetBaudRate(LPSPI_Type *base, |
429 | uint32_t baudRate_Bps, |
430 | uint32_t srcClock_Hz, |
431 | uint32_t *tcrPrescaleValue) |
432 | { |
433 | assert(tcrPrescaleValue != NULL); |
434 | |
435 | /* For master mode configuration only, if slave mode detected, return 0. |
436 | * Also, the LPSPI module needs to be disabled first, if enabled, return 0 |
437 | */ |
438 | if ((!LPSPI_IsMaster(base)) || ((base->CR & LPSPI_CR_MEN_MASK) != 0U)) |
439 | { |
440 | return 0U; |
441 | } |
442 | |
443 | uint32_t prescaler, bestPrescaler; |
444 | uint32_t scaler, bestScaler; |
445 | uint32_t realBaudrate, bestBaudrate; |
446 | uint32_t diff, min_diff; |
447 | uint32_t desiredBaudrate = baudRate_Bps; |
448 | |
449 | /* find combination of prescaler and scaler resulting in baudrate closest to the |
450 | * requested value |
451 | */ |
452 | min_diff = 0xFFFFFFFFU; |
453 | |
454 | /* Set to maximum divisor value bit settings so that if baud rate passed in is less |
455 | * than the minimum possible baud rate, then the SPI will be configured to the lowest |
456 | * possible baud rate |
457 | */ |
458 | bestPrescaler = 7; |
459 | bestScaler = 255; |
460 | |
461 | bestBaudrate = 0; /* required to avoid compilation warning */ |
462 | |
463 | /* In all for loops, if min_diff = 0, the exit for loop*/ |
464 | for (prescaler = 0U; prescaler < 8U; prescaler++) |
465 | { |
466 | if (min_diff == 0U) |
467 | { |
468 | break; |
469 | } |
470 | for (scaler = 0U; scaler < 256U; scaler++) |
471 | { |
472 | if (min_diff == 0U) |
473 | { |
474 | break; |
475 | } |
476 | realBaudrate = (srcClock_Hz / (s_baudratePrescaler[prescaler] * (scaler + 2U))); |
477 | |
478 | /* calculate the baud rate difference based on the conditional statement |
479 | * that states that the calculated baud rate must not exceed the desired baud rate |
480 | */ |
481 | if (desiredBaudrate >= realBaudrate) |
482 | { |
483 | diff = desiredBaudrate - realBaudrate; |
484 | if (min_diff > diff) |
485 | { |
486 | /* a better match found */ |
487 | min_diff = diff; |
488 | bestPrescaler = prescaler; |
489 | bestScaler = scaler; |
490 | bestBaudrate = realBaudrate; |
491 | } |
492 | } |
493 | } |
494 | } |
495 | |
496 | /* Write the best baud rate scalar to the CCR. |
497 | * Note, no need to check for error since we've already checked to make sure the module is |
498 | * disabled and in master mode. Also, there is a limit on the maximum divider so we will not |
499 | * exceed this. |
500 | */ |
501 | #if defined(FSL_FEATURE_LPSPI_HAS_CCR1) && FSL_FEATURE_LPSPI_HAS_CCR1 |
502 | /* When CCR1 is present, the CCR[DBT] and CCR[SCKDIV] is write only, all read will return 0 |
503 | The real DBT and SCKDIV can be obtained in CCR1, CCR[DBT]=CCR1[SCKSCK] and CCR[SCKDIV]=CCR1[SCKHLD]+CCR1[SCKSET] |
504 | So when changing either CCR[DBT] or CCR[SCKDIV] make sure the other value is not overwritten by 0 */ |
505 | base->CCR = base->CCR | LPSPI_CCR_DBT((base->CCR1 & LPSPI_CCR1_SCKSCK_MASK) >> LPSPI_CCR1_SCKSCK_SHIFT) | |
506 | LPSPI_CCR_SCKDIV(bestScaler); |
507 | #else |
508 | base->CCR = (base->CCR & ~LPSPI_CCR_SCKDIV_MASK) | LPSPI_CCR_SCKDIV(bestScaler); |
509 | #endif /* FSL_FEATURE_LPSPI_HAS_CCR1 */ |
510 | |
511 | /* return the best prescaler value for user to use later */ |
512 | *tcrPrescaleValue = bestPrescaler; |
513 | |
514 | /* return the actual calculated baud rate */ |
515 | return bestBaudrate; |
516 | } |
517 | |
518 | /*! |
519 | * brief Manually configures a specific LPSPI delay parameter (module must be disabled to |
520 | * change the delay values). |
521 | * |
522 | * This function configures the following: |
523 | * SCK to PCS delay, or |
524 | * PCS to SCK delay, or |
525 | * The configurations must occur between the transfer delay. |
526 | * |
527 | * The delay names are available in type lpspi_delay_type_t. |
528 | * |
529 | * The user passes the desired delay along with the delay value. |
530 | * This allows the user to directly set the delay values if they have |
531 | * pre-calculated them or if they simply wish to manually increment the value. |
532 | * |
533 | * Note that the LPSPI module must first be disabled before configuring this. |
534 | * Note that the LPSPI module must be configured for master mode before configuring this. |
535 | * |
536 | * param base LPSPI peripheral address. |
537 | * param scaler The 8-bit delay value 0x00 to 0xFF (255). |
538 | * param whichDelay The desired delay to configure, must be of type lpspi_delay_type_t. |
539 | */ |
540 | void LPSPI_MasterSetDelayScaler(LPSPI_Type *base, uint32_t scaler, lpspi_delay_type_t whichDelay) |
541 | { |
542 | /*These settings are only relevant in master mode */ |
543 | #if defined(FSL_FEATURE_LPSPI_HAS_CCR1) && FSL_FEATURE_LPSPI_HAS_CCR1 |
544 | /* When CCR1 is present, the CCR[DBT] and CCR[SCKDIV] is write only, all read will return 0 |
545 | The real DBT and SCKDIV can be obtained in CCR1, CCR[DBT]=CCR1[SCKSCK] and CCR[SCKDIV]=CCR1[SCKHLD]+CCR1[SCKSET] |
546 | So when changing either CCR[DBT] or CCR[SCKDIV] make sure the other value is not overwritten by 0 */ |
547 | uint32_t dbt = (base->CCR1 & LPSPI_CCR1_SCKSCK_MASK) >> LPSPI_CCR1_SCKSCK_SHIFT; |
548 | uint32_t sckdiv = (base->CCR1 & LPSPI_CCR1_SCKHLD_MASK) >> LPSPI_CCR1_SCKHLD_SHIFT; |
549 | sckdiv += (base->CCR1 & LPSPI_CCR1_SCKSET_MASK) >> LPSPI_CCR1_SCKSET_SHIFT; |
550 | switch (whichDelay) |
551 | { |
552 | case kLPSPI_PcsToSck: |
553 | base->CCR = (base->CCR & (~LPSPI_CCR_PCSSCK_MASK)) | LPSPI_CCR_PCSSCK(scaler) | LPSPI_CCR_DBT(dbt) | |
554 | LPSPI_CCR_SCKDIV(sckdiv); |
555 | |
556 | break; |
557 | case kLPSPI_LastSckToPcs: |
558 | base->CCR = (base->CCR & (~LPSPI_CCR_SCKPCS_MASK)) | LPSPI_CCR_SCKPCS(scaler) | LPSPI_CCR_DBT(dbt) | |
559 | LPSPI_CCR_SCKDIV(sckdiv); |
560 | |
561 | break; |
562 | case kLPSPI_BetweenTransfer: |
563 | base->CCR = base->CCR | LPSPI_CCR_DBT(scaler) | LPSPI_CCR_SCKDIV(sckdiv); |
564 | #else |
565 | switch (whichDelay) |
566 | { |
567 | case kLPSPI_PcsToSck: |
568 | base->CCR = (base->CCR & (~LPSPI_CCR_PCSSCK_MASK)) | LPSPI_CCR_PCSSCK(scaler); |
569 | |
570 | break; |
571 | case kLPSPI_LastSckToPcs: |
572 | base->CCR = (base->CCR & (~LPSPI_CCR_SCKPCS_MASK)) | LPSPI_CCR_SCKPCS(scaler); |
573 | |
574 | break; |
575 | case kLPSPI_BetweenTransfer: |
576 | base->CCR = (base->CCR & (~LPSPI_CCR_DBT_MASK)) | LPSPI_CCR_DBT(scaler); |
577 | #endif /* FSL_FEATURE_LPSPI_HAS_CCR1 */ |
578 | break; |
579 | default: |
580 | assert(false); |
581 | break; |
582 | } |
583 | } |
584 | |
585 | /*! |
586 | * brief Calculates the delay based on the desired delay input in nanoseconds (module must be |
587 | * disabled to change the delay values). |
588 | * |
589 | * This function calculates the values for the following: |
590 | * SCK to PCS delay, or |
591 | * PCS to SCK delay, or |
592 | * The configurations must occur between the transfer delay. |
593 | * |
594 | * The delay names are available in type lpspi_delay_type_t. |
595 | * |
596 | * The user passes the desired delay and the desired delay value in |
597 | * nano-seconds. The function calculates the value needed for the desired delay parameter |
598 | * and returns the actual calculated delay because an exact delay match may not be possible. In this |
599 | * case, the closest match is calculated without going below the desired delay value input. |
600 | * It is possible to input a very large delay value that exceeds the capability of the part, in |
601 | * which case the maximum supported delay is returned. It is up to the higher level |
602 | * peripheral driver to alert the user of an out of range delay input. |
603 | * |
604 | * Note that the LPSPI module must be configured for master mode before configuring this. And note that |
605 | * the delayTime = LPSPI_clockSource / (PRESCALE * Delay_scaler). |
606 | * |
607 | * param base LPSPI peripheral address. |
608 | * param delayTimeInNanoSec The desired delay value in nano-seconds. |
609 | * param whichDelay The desired delay to configuration, which must be of type lpspi_delay_type_t. |
610 | * param srcClock_Hz Module source input clock in Hertz. |
611 | * return actual Calculated delay value in nano-seconds. |
612 | */ |
613 | uint32_t LPSPI_MasterSetDelayTimes(LPSPI_Type *base, |
614 | uint32_t delayTimeInNanoSec, |
615 | lpspi_delay_type_t whichDelay, |
616 | uint32_t srcClock_Hz) |
617 | { |
618 | uint64_t realDelay, bestDelay; |
619 | uint32_t scaler, bestScaler; |
620 | uint32_t diff, min_diff; |
621 | uint64_t initialDelayNanoSec; |
622 | uint32_t clockDividedPrescaler; |
623 | |
624 | /* For delay between transfer, an additional scaler value is needed */ |
625 | uint32_t additionalScaler = 0; |
626 | |
627 | /*As the RM note, the LPSPI baud rate clock is itself divided by the PRESCALE setting, which can vary between |
628 | * transfers.*/ |
629 | clockDividedPrescaler = |
630 | srcClock_Hz / s_baudratePrescaler[(base->TCR & LPSPI_TCR_PRESCALE_MASK) >> LPSPI_TCR_PRESCALE_SHIFT]; |
631 | |
632 | /* Find combination of prescaler and scaler resulting in the delay closest to the requested value.*/ |
633 | min_diff = 0xFFFFFFFFU; |
634 | |
635 | /* Initialize scaler to max value to generate the max delay */ |
636 | bestScaler = 0xFFU; |
637 | |
638 | /* Calculate the initial (min) delay and maximum possible delay based on the specific delay as |
639 | * the delay divisors are slightly different based on which delay we are configuring. |
640 | */ |
641 | if (whichDelay == kLPSPI_BetweenTransfer) |
642 | { |
643 | /* First calculate the initial, default delay, note min delay is 2 clock cycles. Due to large size of |
644 | calculated values (uint64_t), we need to break up the calculation into several steps to ensure |
645 | accurate calculated results |
646 | */ |
647 | initialDelayNanoSec = 1000000000U; |
648 | initialDelayNanoSec *= 2U; |
649 | initialDelayNanoSec /= clockDividedPrescaler; |
650 | |
651 | /* Calculate the maximum delay */ |
652 | bestDelay = 1000000000U; |
653 | bestDelay *= 257U; /* based on DBT+2, or 255 + 2 */ |
654 | bestDelay /= clockDividedPrescaler; |
655 | |
656 | additionalScaler = 1U; |
657 | } |
658 | else |
659 | { |
660 | /* First calculate the initial, default delay, min delay is 1 clock cycle. Due to large size of calculated |
661 | values (uint64_t), we need to break up the calculation into several steps to ensure accurate calculated |
662 | results. |
663 | */ |
664 | initialDelayNanoSec = 1000000000U; |
665 | initialDelayNanoSec /= clockDividedPrescaler; |
666 | |
667 | /* Calculate the maximum delay */ |
668 | bestDelay = 1000000000U; |
669 | bestDelay *= 256U; /* based on SCKPCS+1 or PCSSCK+1, or 255 + 1 */ |
670 | bestDelay /= clockDividedPrescaler; |
671 | |
672 | additionalScaler = 0U; |
673 | } |
674 | |
675 | /* If the initial, default delay is already greater than the desired delay, then |
676 | * set the delay to their initial value (0) and return the delay. In other words, |
677 | * there is no way to decrease the delay value further. |
678 | */ |
679 | if (initialDelayNanoSec >= delayTimeInNanoSec) |
680 | { |
681 | LPSPI_MasterSetDelayScaler(base, 0, whichDelay); |
682 | return (uint32_t)initialDelayNanoSec; |
683 | } |
684 | |
685 | /* If min_diff = 0, the exit for loop */ |
686 | for (scaler = 0U; scaler < 256U; scaler++) |
687 | { |
688 | if (min_diff == 0U) |
689 | { |
690 | break; |
691 | } |
692 | /* Calculate the real delay value as we cycle through the scaler values. |
693 | Due to large size of calculated values (uint64_t), we need to break up the |
694 | calculation into several steps to ensure accurate calculated results |
695 | */ |
696 | realDelay = 1000000000U; |
697 | realDelay *= ((uint64_t)scaler + 1UL + (uint64_t)additionalScaler); |
698 | realDelay /= clockDividedPrescaler; |
699 | |
700 | /* calculate the delay difference based on the conditional statement |
701 | * that states that the calculated delay must not be less then the desired delay |
702 | */ |
703 | if (realDelay >= delayTimeInNanoSec) |
704 | { |
705 | diff = (uint32_t)(realDelay - (uint64_t)delayTimeInNanoSec); |
706 | if (min_diff > diff) |
707 | { |
708 | /* a better match found */ |
709 | min_diff = diff; |
710 | bestScaler = scaler; |
711 | bestDelay = realDelay; |
712 | } |
713 | } |
714 | } |
715 | |
716 | /* write the best scaler value for the delay */ |
717 | LPSPI_MasterSetDelayScaler(base, bestScaler, whichDelay); |
718 | |
719 | /* return the actual calculated delay value (in ns) */ |
720 | return (uint32_t)bestDelay; |
721 | } |
722 | |
723 | /*Transactional APIs -- Master*/ |
724 | |
725 | /*! |
726 | * brief Initializes the LPSPI master handle. |
727 | * |
728 | * This function initializes the LPSPI handle, which can be used for other LPSPI transactional APIs. Usually, for a |
729 | * specified LPSPI instance, call this API once to get the initialized handle. |
730 | |
731 | * param base LPSPI peripheral address. |
732 | * param handle LPSPI handle pointer to lpspi_master_handle_t. |
733 | * param callback DSPI callback. |
734 | * param userData callback function parameter. |
735 | */ |
736 | void LPSPI_MasterTransferCreateHandle(LPSPI_Type *base, |
737 | lpspi_master_handle_t *handle, |
738 | lpspi_master_transfer_callback_t callback, |
739 | void *userData) |
740 | { |
741 | assert(handle != NULL); |
742 | |
743 | /* Zero the handle. */ |
744 | (void)memset(handle, 0, sizeof(*handle)); |
745 | |
746 | s_lpspiHandle[LPSPI_GetInstance(base)] = handle; |
747 | |
748 | /* Set irq handler. */ |
749 | s_lpspiMasterIsr = LPSPI_MasterTransferHandleIRQ; |
750 | |
751 | handle->callback = callback; |
752 | handle->userData = userData; |
753 | } |
754 | |
755 | /*! |
756 | * brief Check the argument for transfer . |
757 | * |
758 | * param base LPSPI peripheral address. |
759 | * param transfer the transfer struct to be used. |
760 | * param isEdma True to check for EDMA transfer, false to check interrupt non-blocking transfer |
761 | * return Return true for right and false for wrong. |
762 | */ |
763 | bool LPSPI_CheckTransferArgument(LPSPI_Type *base, lpspi_transfer_t *transfer, bool isEdma) |
764 | { |
765 | assert(transfer != NULL); |
766 | uint32_t bitsPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) + 1U; |
767 | uint32_t bytesPerFrame = (bitsPerFrame + 7U) / 8U; |
768 | uint32_t temp = (base->CFGR1 & LPSPI_CFGR1_PINCFG_MASK); |
769 | /* If the transfer count is zero, then return immediately.*/ |
770 | if (transfer->dataSize == 0U) |
771 | { |
772 | return false; |
773 | } |
774 | |
775 | /* If both send buffer and receive buffer is null */ |
776 | if ((NULL == (transfer->txData)) && (NULL == (transfer->rxData))) |
777 | { |
778 | return false; |
779 | } |
780 | |
781 | /*The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4 . |
782 | *For bytesPerFrame greater than 4 situation: |
783 | *the transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not integer multiples of 4 , |
784 | *otherwise , the transfer data size can be integer multiples of bytesPerFrame. |
785 | */ |
786 | if (bytesPerFrame <= 4U) |
787 | { |
788 | if ((transfer->dataSize % bytesPerFrame) != 0U) |
789 | { |
790 | return false; |
791 | } |
792 | } |
793 | else |
794 | { |
795 | if ((bytesPerFrame % 4U) != 0U) |
796 | { |
797 | if (transfer->dataSize != bytesPerFrame) |
798 | { |
799 | return false; |
800 | } |
801 | } |
802 | else |
803 | { |
804 | if ((transfer->dataSize % bytesPerFrame) != 0U) |
805 | { |
806 | return false; |
807 | } |
808 | } |
809 | } |
810 | |
811 | /* Check if using 3-wire mode and the txData is NULL, set the output pin to tristated. */ |
812 | if ((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut))) |
813 | { |
814 | /* The 3-wire mode can't send and receive data at the same time. */ |
815 | if ((transfer->txData != NULL) && (transfer->rxData != NULL)) |
816 | { |
817 | return false; |
818 | } |
819 | if (NULL == transfer->txData) |
820 | { |
821 | base->CFGR1 |= LPSPI_CFGR1_OUTCFG_MASK; |
822 | } |
823 | } |
824 | |
825 | if (isEdma && ((bytesPerFrame % 4U) == 3U)) |
826 | { |
827 | return false; |
828 | } |
829 | |
830 | return true; |
831 | } |
832 | |
833 | /*! |
834 | * brief LPSPI master transfer data using a polling method. |
835 | * |
836 | * This function transfers data using a polling method. This is a blocking function, which does not return until all |
837 | * transfers have been completed. |
838 | * |
839 | * Note: |
840 | * The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4. |
841 | * For bytesPerFrame greater than 4: |
842 | * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not integer multiples of 4. |
843 | * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame. |
844 | * |
845 | * param base LPSPI peripheral address. |
846 | * param transfer pointer to lpspi_transfer_t structure. |
847 | * return status of status_t. |
848 | */ |
849 | status_t LPSPI_MasterTransferBlocking(LPSPI_Type *base, lpspi_transfer_t *transfer) |
850 | { |
851 | assert(transfer != NULL); |
852 | |
853 | /* Check that LPSPI is not busy.*/ |
854 | if ((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_ModuleBusyFlag) != 0U) |
855 | { |
856 | return kStatus_LPSPI_Busy; |
857 | } |
858 | LPSPI_Enable(base, false); |
859 | /* Check arguements */ |
860 | if (!LPSPI_CheckTransferArgument(base, transfer, false)) |
861 | { |
862 | return kStatus_InvalidArgument; |
863 | } |
864 | |
865 | LPSPI_FlushFifo(base, true, true); |
866 | LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag); |
867 | |
868 | /* Variables */ |
869 | bool isTxMask = false; |
870 | bool isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U); |
871 | uint8_t bytesEachWrite; |
872 | uint8_t bytesEachRead; |
873 | uint8_t *txData = transfer->txData; |
874 | uint8_t *rxData = transfer->rxData; |
875 | uint8_t dummyData = g_lpspiDummyData[LPSPI_GetInstance(base)]; |
876 | uint32_t readData = 0U; |
877 | uint32_t txRemainingByteCount = transfer->dataSize; |
878 | uint32_t rxRemainingByteCount = transfer->dataSize; |
879 | uint32_t wordToSend = |
880 | ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24); |
881 | /*The TX and RX FIFO sizes are always the same*/ |
882 | uint32_t fifoSize = LPSPI_GetRxFifoSize(base); |
883 | uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U; |
884 | /* No need to configure PCS continous if the transfer byte count is smaller than frame size */ |
885 | bool isPcsContinuous = (((transfer->configFlags & (uint32_t)kLPSPI_MasterPcsContinuous) != 0U) && |
886 | (bytesPerFrame < transfer->dataSize)); |
887 | uint32_t rxFifoMaxBytes = MIN(bytesPerFrame, 4U) * fifoSize; |
888 | uint32_t whichPcs = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT; |
889 | uint32_t temp = (base->CFGR1 & LPSPI_CFGR1_PINCFG_MASK); |
890 | |
891 | #if SPI_RETRY_TIMES |
892 | uint32_t waitTimes; |
893 | #endif |
894 | |
895 | /* Mask tx data in half duplex mode */ |
896 | if (((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut))) && |
897 | (txData == NULL)) |
898 | { |
899 | isTxMask = true; |
900 | } |
901 | |
902 | base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK); |
903 | LPSPI_Enable(base, true); |
904 | |
905 | /* Configure transfer control register. */ |
906 | base->TCR = (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK | |
907 | LPSPI_TCR_TXMSK_MASK | LPSPI_TCR_PCS_MASK)) | |
908 | LPSPI_TCR_PCS(whichPcs); |
909 | |
910 | /*TCR is also shared the FIFO, so wait for TCR written.*/ |
911 | if (!LPSPI_TxFifoReady(base)) |
912 | { |
913 | return kStatus_LPSPI_Timeout; |
914 | } |
915 | |
916 | /* PCS should be configured separately from the other bits, otherwise it will not take effect. */ |
917 | base->TCR |= LPSPI_TCR_CONT(isPcsContinuous) | LPSPI_TCR_CONTC(isPcsContinuous) | LPSPI_TCR_RXMSK(NULL == rxData); |
918 | |
919 | /*TCR is also shared the FIFO, so wait for TCR written.*/ |
920 | if (!LPSPI_TxFifoReady(base)) |
921 | { |
922 | return kStatus_LPSPI_Timeout; |
923 | } |
924 | |
925 | if (bytesPerFrame <= 4U) |
926 | { |
927 | bytesEachWrite = (uint8_t)bytesPerFrame; |
928 | bytesEachRead = (uint8_t)bytesPerFrame; |
929 | } |
930 | else |
931 | { |
932 | bytesEachWrite = 4U; |
933 | bytesEachRead = 4U; |
934 | } |
935 | |
936 | /*Write the TX data until txRemainingByteCount is equal to 0 */ |
937 | while (txRemainingByteCount > 0U) |
938 | { |
939 | if (txRemainingByteCount < bytesEachWrite) |
940 | { |
941 | bytesEachWrite = (uint8_t)txRemainingByteCount; |
942 | } |
943 | |
944 | /*Wait until TX FIFO is not full*/ |
945 | #if SPI_RETRY_TIMES |
946 | waitTimes = SPI_RETRY_TIMES; |
947 | while ((LPSPI_GetTxFifoCount(base) == fifoSize) && (--waitTimes != 0U)) |
948 | #else |
949 | while (LPSPI_GetTxFifoCount(base) == fifoSize) |
950 | #endif |
951 | { |
952 | } |
953 | #if SPI_RETRY_TIMES |
954 | if (waitTimes == 0U) |
955 | { |
956 | return kStatus_LPSPI_Timeout; |
957 | } |
958 | #endif |
959 | |
960 | /* To prevent rxfifo overflow, ensure transmitting and receiving are executed in parallel */ |
961 | if (((NULL == rxData) || (rxRemainingByteCount - txRemainingByteCount) < rxFifoMaxBytes)) |
962 | { |
963 | if (isTxMask) |
964 | { |
965 | /* When TCR[TXMSK]=1, transfer is initiate by writting a new command word to TCR. TCR[TXMSK] is cleared |
966 | by hardware every time when TCR[FRAMESZ] bit of data is transfered. |
967 | In this case TCR[TXMSK] should be set to initiate each transfer. */ |
968 | base->TCR |= LPSPI_TCR_TXMSK_MASK; |
969 | if (isPcsContinuous && (txRemainingByteCount == bytesPerFrame)) |
970 | { |
971 | /* For the last piece of frame size of data, if is PCS continous mode(TCR[CONT]), TCR[CONTC] should |
972 | * be cleared to de-assert the PCS. Be sure to clear the TXMSK as well otherwise another FRAMESZ |
973 | * of data will be received. */ |
974 | base->TCR &= ~(LPSPI_TCR_CONTC_MASK | LPSPI_TCR_CONT_MASK | LPSPI_TCR_TXMSK_MASK); |
975 | } |
976 | txRemainingByteCount -= bytesPerFrame; |
977 | } |
978 | else |
979 | { |
980 | if (txData != NULL) |
981 | { |
982 | wordToSend = LPSPI_CombineWriteData(txData, bytesEachWrite, isByteSwap); |
983 | txData += bytesEachWrite; |
984 | } |
985 | /* Otherwise push data to tx FIFO to initiate transfer */ |
986 | LPSPI_WriteData(base, wordToSend); |
987 | txRemainingByteCount -= bytesEachWrite; |
988 | } |
989 | } |
990 | |
991 | /* Check whether there is RX data in RX FIFO . Read out the RX data so that the RX FIFO would not overrun. */ |
992 | if ((rxData != NULL) && (rxRemainingByteCount != 0U)) |
993 | { |
994 | /* To ensure parallel execution in 3-wire mode, after writting 1 to TXMSK to generate clock of |
995 | bytesPerFrame's data wait until bytesPerFrame's data is received. */ |
996 | while (isTxMask && (LPSPI_GetRxFifoCount(base) == 0U)) |
997 | { |
998 | } |
999 | #if SPI_RETRY_TIMES |
1000 | waitTimes = SPI_RETRY_TIMES; |
1001 | while ((LPSPI_GetRxFifoCount(base) != 0U) && (--waitTimes != 0U)) |
1002 | #else |
1003 | while (LPSPI_GetRxFifoCount(base) != 0U) |
1004 | #endif |
1005 | { |
1006 | readData = LPSPI_ReadData(base); |
1007 | if (rxRemainingByteCount < bytesEachRead) |
1008 | { |
1009 | bytesEachRead = (uint8_t)rxRemainingByteCount; |
1010 | } |
1011 | |
1012 | LPSPI_SeparateReadData(rxData, readData, bytesEachRead, isByteSwap); |
1013 | rxData += bytesEachRead; |
1014 | |
1015 | rxRemainingByteCount -= bytesEachRead; |
1016 | } |
1017 | #if SPI_RETRY_TIMES |
1018 | if (waitTimes == 0U) |
1019 | { |
1020 | return kStatus_LPSPI_Timeout; |
1021 | } |
1022 | #endif |
1023 | } |
1024 | } |
1025 | |
1026 | if (isPcsContinuous && !isTxMask) |
1027 | { |
1028 | /* In PCS continous mode(TCR[CONT]), after write all the data in TX FIFO, TCR[CONTC] and TCR[CONT] should be |
1029 | cleared to de-assert the PCS. Note that TCR register also use the TX FIFO. Also CONTC should be cleared when |
1030 | tx is not masked, otherwise written to TCR register with TXMSK bit wet will initiate a new transfer. */ |
1031 | #if SPI_RETRY_TIMES |
1032 | waitTimes = SPI_RETRY_TIMES; |
1033 | while ((LPSPI_GetTxFifoCount(base) == fifoSize) && (--waitTimes != 0U)) |
1034 | #else |
1035 | while (LPSPI_GetTxFifoCount(base) == fifoSize) |
1036 | #endif |
1037 | { |
1038 | } |
1039 | #if SPI_RETRY_TIMES |
1040 | if (waitTimes == 0U) |
1041 | { |
1042 | return kStatus_LPSPI_Timeout; |
1043 | } |
1044 | #endif |
1045 | base->TCR = (base->TCR & ~(LPSPI_TCR_CONTC_MASK | LPSPI_TCR_CONT_MASK)); |
1046 | } |
1047 | |
1048 | /*Read out the RX data in FIFO*/ |
1049 | if (rxData != NULL) |
1050 | { |
1051 | while (rxRemainingByteCount > 0U) |
1052 | { |
1053 | #if SPI_RETRY_TIMES |
1054 | waitTimes = SPI_RETRY_TIMES; |
1055 | while ((LPSPI_GetRxFifoCount(base) != 0U) && (--waitTimes != 0U)) |
1056 | #else |
1057 | while (LPSPI_GetRxFifoCount(base) != 0U) |
1058 | #endif |
1059 | { |
1060 | readData = LPSPI_ReadData(base); |
1061 | |
1062 | if (rxRemainingByteCount < bytesEachRead) |
1063 | { |
1064 | bytesEachRead = (uint8_t)rxRemainingByteCount; |
1065 | } |
1066 | |
1067 | LPSPI_SeparateReadData(rxData, readData, bytesEachRead, isByteSwap); |
1068 | rxData += bytesEachRead; |
1069 | |
1070 | rxRemainingByteCount -= bytesEachRead; |
1071 | } |
1072 | #if SPI_RETRY_TIMES |
1073 | if (waitTimes == 0U) |
1074 | { |
1075 | return kStatus_LPSPI_Timeout; |
1076 | } |
1077 | #endif |
1078 | } |
1079 | } |
1080 | else |
1081 | { |
1082 | /* If no RX buffer, then transfer is not complete until transfer complete flag sets */ |
1083 | #if SPI_RETRY_TIMES |
1084 | waitTimes = SPI_RETRY_TIMES; |
1085 | while (((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_TransferCompleteFlag) == 0U) && (--waitTimes != 0U)) |
1086 | #else |
1087 | while ((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_TransferCompleteFlag) == 0U) |
1088 | #endif |
1089 | { |
1090 | } |
1091 | #if SPI_RETRY_TIMES |
1092 | if (waitTimes == 0U) |
1093 | { |
1094 | return kStatus_LPSPI_Timeout; |
1095 | } |
1096 | #endif |
1097 | } |
1098 | |
1099 | return kStatus_Success; |
1100 | } |
1101 | |
1102 | /*! |
1103 | * brief LPSPI master transfer data using an interrupt method. |
1104 | * |
1105 | * This function transfers data using an interrupt method. This is a non-blocking function, which returns right away. |
1106 | * When all data is transferred, the callback function is called. |
1107 | * |
1108 | * Note: |
1109 | * The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4. |
1110 | * For bytesPerFrame greater than 4: |
1111 | * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not integer multiples of 4. |
1112 | * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame. |
1113 | * |
1114 | * param base LPSPI peripheral address. |
1115 | * param handle pointer to lpspi_master_handle_t structure which stores the transfer state. |
1116 | * param transfer pointer to lpspi_transfer_t structure. |
1117 | * return status of status_t. |
1118 | */ |
1119 | status_t LPSPI_MasterTransferNonBlocking(LPSPI_Type *base, lpspi_master_handle_t *handle, lpspi_transfer_t *transfer) |
1120 | { |
1121 | assert(handle != NULL); |
1122 | assert(transfer != NULL); |
1123 | |
1124 | /* Check that we're not busy.*/ |
1125 | if (handle->state == (uint8_t)kLPSPI_Busy) |
1126 | { |
1127 | return kStatus_LPSPI_Busy; |
1128 | } |
1129 | |
1130 | LPSPI_Enable(base, false); |
1131 | /* Check arguements */ |
1132 | if (!LPSPI_CheckTransferArgument(base, transfer, false)) |
1133 | { |
1134 | return kStatus_InvalidArgument; |
1135 | } |
1136 | |
1137 | /* Flush FIFO, clear status, disable all the interrupts. */ |
1138 | LPSPI_FlushFifo(base, true, true); |
1139 | LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag); |
1140 | LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable); |
1141 | |
1142 | /* Variables */ |
1143 | bool isRxMask = false; |
1144 | uint8_t txWatermark; |
1145 | uint8_t dummyData = g_lpspiDummyData[LPSPI_GetInstance(base)]; |
1146 | uint32_t tmpTimes; |
1147 | uint32_t whichPcs = (transfer->configFlags & LPSPI_MASTER_PCS_MASK) >> LPSPI_MASTER_PCS_SHIFT; |
1148 | uint32_t temp = (base->CFGR1 & LPSPI_CFGR1_PINCFG_MASK); |
1149 | |
1150 | /* Assign the original value for members of transfer handle. */ |
1151 | handle->state = (uint8_t)kLPSPI_Busy; |
1152 | handle->txData = transfer->txData; |
1153 | handle->rxData = transfer->rxData; |
1154 | handle->txRemainingByteCount = transfer->dataSize; |
1155 | handle->rxRemainingByteCount = transfer->dataSize; |
1156 | handle->totalByteCount = transfer->dataSize; |
1157 | handle->writeTcrInIsr = false; |
1158 | handle->bytesPerFrame = (uint16_t)((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U; |
1159 | /* No need to configure PCS continous if the transfer byte count is smaller than frame size */ |
1160 | bool isPcsContinuous = (((transfer->configFlags & (uint32_t)kLPSPI_MasterPcsContinuous) != 0U) && |
1161 | (transfer->dataSize > handle->bytesPerFrame)); |
1162 | handle->writeRegRemainingTimes = |
1163 | (transfer->dataSize / (uint32_t)handle->bytesPerFrame) * (((uint32_t)handle->bytesPerFrame + 3U) / 4U); |
1164 | handle->readRegRemainingTimes = handle->writeRegRemainingTimes; |
1165 | handle->txBuffIfNull = |
1166 | ((uint32_t)dummyData) | ((uint32_t)dummyData << 8) | ((uint32_t)dummyData << 16) | ((uint32_t)dummyData << 24); |
1167 | /*The TX and RX FIFO sizes are always the same*/ |
1168 | handle->fifoSize = LPSPI_GetRxFifoSize(base); |
1169 | handle->isPcsContinuous = isPcsContinuous; |
1170 | handle->isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_MasterByteSwap) != 0U); |
1171 | /*Calculate the bytes for write/read the TX/RX register each time*/ |
1172 | if (handle->bytesPerFrame <= 4U) |
1173 | { |
1174 | handle->bytesEachWrite = (uint8_t)handle->bytesPerFrame; |
1175 | handle->bytesEachRead = (uint8_t)handle->bytesPerFrame; |
1176 | } |
1177 | else |
1178 | { |
1179 | handle->bytesEachWrite = 4U; |
1180 | handle->bytesEachRead = 4U; |
1181 | } |
1182 | |
1183 | /*Set the RX and TX watermarks to reduce the ISR times.*/ |
1184 | if (handle->fifoSize > 1U) |
1185 | { |
1186 | txWatermark = 1U; |
1187 | handle->rxWatermark = handle->fifoSize - 2U; |
1188 | } |
1189 | else |
1190 | { |
1191 | txWatermark = 0U; |
1192 | handle->rxWatermark = 0U; |
1193 | } |
1194 | LPSPI_SetFifoWatermarks(base, txWatermark, handle->rxWatermark); |
1195 | |
1196 | /* If there is no rxData, mask the receive data so that receive data is not stored in receive FIFO. */ |
1197 | if (handle->rxData == NULL) |
1198 | { |
1199 | isRxMask = true; |
1200 | handle->rxRemainingByteCount = 0; |
1201 | } |
1202 | |
1203 | /* Mask tx data in half duplex mode since the tx/rx share the same pin, so that the data received from slave is not |
1204 | * interfered. */ |
1205 | if (((temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdiInSdiOut)) || (temp == LPSPI_CFGR1_PINCFG(kLPSPI_SdoInSdoOut))) && |
1206 | (handle->txData == NULL)) |
1207 | { |
1208 | handle->isTxMask = true; |
1209 | } |
1210 | |
1211 | /*Transfers will stall when transmit FIFO is empty or receive FIFO is full. */ |
1212 | base->CFGR1 &= (~LPSPI_CFGR1_NOSTALL_MASK); |
1213 | |
1214 | /* Enable module for following configuration of TCR to take effect. */ |
1215 | LPSPI_Enable(base, true); |
1216 | |
1217 | /* Configure transfer control register. */ |
1218 | base->TCR = (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK | |
1219 | LPSPI_TCR_TXMSK_MASK | LPSPI_TCR_PCS_MASK)) | |
1220 | LPSPI_TCR_PCS(whichPcs); |
1221 | |
1222 | /*TCR is also shared the FIFO , so wait for TCR written.*/ |
1223 | if (!LPSPI_TxFifoReady(base)) |
1224 | { |
1225 | return kStatus_LPSPI_Timeout; |
1226 | } |
1227 | |
1228 | /* PCS should be configured separately from the other bits, otherwise it will not take effect. */ |
1229 | base->TCR |= LPSPI_TCR_CONT(isPcsContinuous) | LPSPI_TCR_CONTC(isPcsContinuous) | LPSPI_TCR_RXMSK(isRxMask); |
1230 | |
1231 | /* Enable the NVIC for LPSPI peripheral. Note that below code is useless if the LPSPI interrupt is in INTMUX , |
1232 | * and you should also enable the INTMUX interupt in your application. |
1233 | */ |
1234 | (void)EnableIRQ(s_lpspiIRQ[LPSPI_GetInstance(base)]); |
1235 | |
1236 | /*TCR is also shared the FIFO , so wait for TCR written.*/ |
1237 | if (!LPSPI_TxFifoReady(base)) |
1238 | { |
1239 | return kStatus_LPSPI_Timeout; |
1240 | } |
1241 | |
1242 | if (handle->isTxMask) |
1243 | { |
1244 | /* When TCR[TXMSK]=1, transfer is initiate by writting a new command word to TCR. TCR[TXMSK] is cleared by |
1245 | hardware every time when TCR[FRAMESZ] bit of data is transfered. In this case TCR[TXMSK] should be set to |
1246 | initiate each transfer. */ |
1247 | |
1248 | base->TCR |= LPSPI_TCR_TXMSK_MASK; |
1249 | handle->txRemainingByteCount -= (uint32_t)handle->bytesPerFrame; |
1250 | } |
1251 | else |
1252 | { |
1253 | /* Fill up the TX data in FIFO to initiate transfer */ |
1254 | LPSPI_MasterTransferFillUpTxFifo(base, handle); |
1255 | } |
1256 | |
1257 | /* Since SPI is a synchronous interface, we only need to enable the RX interrupt if there is RX data. |
1258 | * The IRQ handler will get the status of RX and TX interrupt flags. |
1259 | */ |
1260 | if (handle->rxData != NULL) |
1261 | { |
1262 | if (handle->isTxMask) |
1263 | { |
1264 | /* if tx data is masked, transfer is initiated by writing 1 to TCR[TXMSK] and TCR[FRMESZ] bits of data is |
1265 | read. If rx water mark is set larger than TCR[FRMESZ], rx interrupt will not be generated. Lower the rx |
1266 | water mark setting */ |
1267 | if ((handle->bytesPerFrame / 4U) < (uint16_t)handle->rxWatermark) |
1268 | { |
1269 | handle->rxWatermark = |
1270 | (uint8_t)(handle->bytesPerFrame / 4U) > 0U ? (uint8_t)(handle->bytesPerFrame / 4U - 1U) : 0U; |
1271 | base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) | LPSPI_FCR_RXWATER(handle->rxWatermark); |
1272 | } |
1273 | } |
1274 | else |
1275 | { |
1276 | /*Set rxWatermark to (readRegRemainingTimes-1) if readRegRemainingTimes less than rxWatermark. Otherwise |
1277 | *there is not RX interrupt for the last datas because the RX count is not greater than rxWatermark. |
1278 | */ |
1279 | tmpTimes = handle->readRegRemainingTimes; |
1280 | if (tmpTimes <= handle->rxWatermark) |
1281 | { |
1282 | base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) | LPSPI_FCR_RXWATER(tmpTimes - 1U); |
1283 | } |
1284 | } |
1285 | |
1286 | LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_RxInterruptEnable); |
1287 | } |
1288 | else |
1289 | { |
1290 | LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable); |
1291 | } |
1292 | |
1293 | return kStatus_Success; |
1294 | } |
1295 | |
1296 | static void LPSPI_MasterTransferFillUpTxFifo(LPSPI_Type *base, lpspi_master_handle_t *handle) |
1297 | { |
1298 | assert(handle != NULL); |
1299 | |
1300 | uint32_t wordToSend = 0; |
1301 | uint8_t fifoSize = handle->fifoSize; |
1302 | uint32_t writeRegRemainingTimes = handle->writeRegRemainingTimes; |
1303 | uint32_t readRegRemainingTimes = handle->readRegRemainingTimes; |
1304 | size_t txRemainingByteCount = handle->txRemainingByteCount; |
1305 | uint8_t bytesEachWrite = handle->bytesEachWrite; |
1306 | bool isByteSwap = handle->isByteSwap; |
1307 | |
1308 | /* Make sure the difference in remaining TX and RX byte counts does not exceed FIFO depth |
1309 | * and that the number of TX FIFO entries does not exceed the FIFO depth. |
1310 | * But no need to make the protection if there is no rxData. |
1311 | */ |
1312 | while ((LPSPI_GetTxFifoCount(base) < fifoSize) && |
1313 | (((readRegRemainingTimes - writeRegRemainingTimes) < (uint32_t)fifoSize) || (handle->rxData == NULL))) |
1314 | { |
1315 | if (txRemainingByteCount < (size_t)bytesEachWrite) |
1316 | { |
1317 | handle->bytesEachWrite = (uint8_t)txRemainingByteCount; |
1318 | bytesEachWrite = handle->bytesEachWrite; |
1319 | } |
1320 | |
1321 | if (handle->txData != NULL) |
1322 | { |
1323 | wordToSend = LPSPI_CombineWriteData(handle->txData, bytesEachWrite, isByteSwap); |
1324 | handle->txData += bytesEachWrite; |
1325 | } |
1326 | else |
1327 | { |
1328 | wordToSend = handle->txBuffIfNull; |
1329 | } |
1330 | |
1331 | /*Write the word to TX register*/ |
1332 | LPSPI_WriteData(base, wordToSend); |
1333 | |
1334 | /*Decrease the write TX register times.*/ |
1335 | --handle->writeRegRemainingTimes; |
1336 | writeRegRemainingTimes = handle->writeRegRemainingTimes; |
1337 | |
1338 | /*Decrease the remaining TX byte count.*/ |
1339 | handle->txRemainingByteCount -= (size_t)bytesEachWrite; |
1340 | txRemainingByteCount = handle->txRemainingByteCount; |
1341 | |
1342 | if (handle->txRemainingByteCount == 0U) |
1343 | { |
1344 | /* If PCS is continuous, update TCR to de-assert PCS */ |
1345 | if (handle->isPcsContinuous) |
1346 | { |
1347 | /* Only write to the TCR if the FIFO has room */ |
1348 | if (LPSPI_GetTxFifoCount(base) < fifoSize) |
1349 | { |
1350 | base->TCR = (base->TCR & ~(LPSPI_TCR_CONTC_MASK)); |
1351 | handle->writeTcrInIsr = false; |
1352 | } |
1353 | /* Else, set a global flag to tell the ISR to do write to the TCR */ |
1354 | else |
1355 | { |
1356 | handle->writeTcrInIsr = true; |
1357 | } |
1358 | } |
1359 | break; |
1360 | } |
1361 | } |
1362 | } |
1363 | |
1364 | static void LPSPI_MasterTransferComplete(LPSPI_Type *base, lpspi_master_handle_t *handle) |
1365 | { |
1366 | assert(handle != NULL); |
1367 | |
1368 | /* Disable interrupt requests*/ |
1369 | LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable); |
1370 | |
1371 | handle->state = (uint8_t)kLPSPI_Idle; |
1372 | |
1373 | if (handle->callback != NULL) |
1374 | { |
1375 | handle->callback(base, handle, kStatus_Success, handle->userData); |
1376 | } |
1377 | } |
1378 | |
1379 | /*! |
1380 | * brief Gets the master transfer remaining bytes. |
1381 | * |
1382 | * This function gets the master transfer remaining bytes. |
1383 | * |
1384 | * param base LPSPI peripheral address. |
1385 | * param handle pointer to lpspi_master_handle_t structure which stores the transfer state. |
1386 | * param count Number of bytes transferred so far by the non-blocking transaction. |
1387 | * return status of status_t. |
1388 | */ |
1389 | status_t LPSPI_MasterTransferGetCount(LPSPI_Type *base, lpspi_master_handle_t *handle, size_t *count) |
1390 | { |
1391 | assert(handle != NULL); |
1392 | |
1393 | if (NULL == count) |
1394 | { |
1395 | return kStatus_InvalidArgument; |
1396 | } |
1397 | |
1398 | /* Catch when there is not an active transfer. */ |
1399 | if (handle->state != (uint8_t)kLPSPI_Busy) |
1400 | { |
1401 | *count = 0; |
1402 | return kStatus_NoTransferInProgress; |
1403 | } |
1404 | |
1405 | size_t remainingByte; |
1406 | |
1407 | if (handle->rxData != NULL) |
1408 | { |
1409 | remainingByte = handle->rxRemainingByteCount; |
1410 | } |
1411 | else |
1412 | { |
1413 | remainingByte = handle->txRemainingByteCount; |
1414 | } |
1415 | |
1416 | *count = handle->totalByteCount - remainingByte; |
1417 | |
1418 | return kStatus_Success; |
1419 | } |
1420 | |
1421 | /*! |
1422 | * brief LPSPI master abort transfer which uses an interrupt method. |
1423 | * |
1424 | * This function aborts a transfer which uses an interrupt method. |
1425 | * |
1426 | * param base LPSPI peripheral address. |
1427 | * param handle pointer to lpspi_master_handle_t structure which stores the transfer state. |
1428 | */ |
1429 | void LPSPI_MasterTransferAbort(LPSPI_Type *base, lpspi_master_handle_t *handle) |
1430 | { |
1431 | assert(handle != NULL); |
1432 | |
1433 | /* Disable interrupt requests*/ |
1434 | LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable); |
1435 | |
1436 | LPSPI_Reset(base); |
1437 | |
1438 | handle->state = (uint8_t)kLPSPI_Idle; |
1439 | handle->txRemainingByteCount = 0; |
1440 | handle->rxRemainingByteCount = 0; |
1441 | } |
1442 | |
1443 | /*! |
1444 | * brief LPSPI Master IRQ handler function. |
1445 | * |
1446 | * This function processes the LPSPI transmit and receive IRQ. |
1447 | * |
1448 | * param base LPSPI peripheral address. |
1449 | * param handle pointer to lpspi_master_handle_t structure which stores the transfer state. |
1450 | */ |
1451 | void LPSPI_MasterTransferHandleIRQ(LPSPI_Type *base, lpspi_master_handle_t *handle) |
1452 | { |
1453 | assert(handle != NULL); |
1454 | |
1455 | uint32_t readData; |
1456 | uint8_t bytesEachRead = handle->bytesEachRead; |
1457 | bool isByteSwap = handle->isByteSwap; |
1458 | uint32_t readRegRemainingTimes = handle->readRegRemainingTimes; |
1459 | |
1460 | if (handle->rxData != NULL) |
1461 | { |
1462 | if (handle->rxRemainingByteCount != 0U) |
1463 | { |
1464 | /* First, disable the interrupts to avoid potentially triggering another interrupt |
1465 | * while reading out the RX FIFO as more data may be coming into the RX FIFO. We'll |
1466 | * re-enable the interrupts based on the LPSPI state after reading out the FIFO. |
1467 | */ |
1468 | LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_RxInterruptEnable); |
1469 | |
1470 | while ((LPSPI_GetRxFifoCount(base) != 0U) && (handle->rxRemainingByteCount != 0U)) |
1471 | { |
1472 | /*Read out the data*/ |
1473 | readData = LPSPI_ReadData(base); |
1474 | |
1475 | /*Decrease the read RX register times.*/ |
1476 | --handle->readRegRemainingTimes; |
1477 | readRegRemainingTimes = handle->readRegRemainingTimes; |
1478 | |
1479 | if (handle->rxRemainingByteCount < (size_t)bytesEachRead) |
1480 | { |
1481 | handle->bytesEachRead = (uint8_t)(handle->rxRemainingByteCount); |
1482 | bytesEachRead = handle->bytesEachRead; |
1483 | } |
1484 | |
1485 | LPSPI_SeparateReadData(handle->rxData, readData, bytesEachRead, isByteSwap); |
1486 | handle->rxData += bytesEachRead; |
1487 | |
1488 | /*Decrease the remaining RX byte count.*/ |
1489 | handle->rxRemainingByteCount -= (size_t)bytesEachRead; |
1490 | } |
1491 | |
1492 | /* Re-enable the interrupts only if rxCount indicates there is more data to receive, |
1493 | * else we may get a spurious interrupt. |
1494 | * */ |
1495 | if (handle->rxRemainingByteCount != 0U) |
1496 | { |
1497 | /* Set the TDF and RDF interrupt enables simultaneously to avoid race conditions */ |
1498 | LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_RxInterruptEnable); |
1499 | } |
1500 | } |
1501 | |
1502 | /*Set rxWatermark to (readRegRemainingTimes-1) if readRegRemainingTimes less than rxWatermark. Otherwise there |
1503 | *is not RX interrupt for the last datas because the RX count is not greater than rxWatermark. |
1504 | */ |
1505 | if (readRegRemainingTimes <= (uint32_t)handle->rxWatermark) |
1506 | { |
1507 | base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) | |
1508 | LPSPI_FCR_RXWATER((readRegRemainingTimes > 1U) ? (readRegRemainingTimes - 1U) : (0U)); |
1509 | } |
1510 | } |
1511 | |
1512 | if (handle->txRemainingByteCount != 0U) |
1513 | { |
1514 | if (handle->isTxMask) |
1515 | { |
1516 | /* When TCR[TXMSK]=1, transfer is initiate by writting a new command word to TCR. TCR[TXMSK] is cleared by |
1517 | hardware every time when TCR[FRAMESZ] bit of data is transfered. |
1518 | In this case TCR[TXMSK] should be set to initiate each transfer. */ |
1519 | base->TCR |= LPSPI_TCR_TXMSK_MASK; |
1520 | if ((handle->txRemainingByteCount == (uint32_t)handle->bytesPerFrame) && (handle->isPcsContinuous)) |
1521 | { |
1522 | /* For the last piece of frame size of data, if is PCS continous mode(TCR[CONT]), TCR[CONTC] should |
1523 | * be cleared to de-assert the PCS. Be sure to clear the TXMSK as well otherwise another FRAMESZ |
1524 | * of data will be received. */ |
1525 | base->TCR &= ~(LPSPI_TCR_CONTC_MASK | LPSPI_TCR_CONT_MASK | LPSPI_TCR_TXMSK_MASK); |
1526 | } |
1527 | handle->txRemainingByteCount -= (uint32_t)handle->bytesPerFrame; |
1528 | } |
1529 | else |
1530 | { |
1531 | LPSPI_MasterTransferFillUpTxFifo(base, handle); |
1532 | } |
1533 | } |
1534 | else |
1535 | { |
1536 | if ((LPSPI_GetTxFifoCount(base) < (handle->fifoSize))) |
1537 | { |
1538 | if ((handle->isPcsContinuous) && (handle->writeTcrInIsr) && (!handle->isTxMask)) |
1539 | { |
1540 | base->TCR = (base->TCR & ~(LPSPI_TCR_CONTC_MASK)); |
1541 | handle->writeTcrInIsr = false; |
1542 | } |
1543 | } |
1544 | } |
1545 | |
1546 | if ((handle->txRemainingByteCount == 0U) && (handle->rxRemainingByteCount == 0U) && (!handle->writeTcrInIsr)) |
1547 | { |
1548 | /* If no RX buffer, then transfer is not complete until transfer complete flag sets */ |
1549 | if (handle->rxData == NULL) |
1550 | { |
1551 | if ((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_TransferCompleteFlag) != 0U) |
1552 | { |
1553 | LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_TransferCompleteFlag); |
1554 | /* Complete the transfer and disable the interrupts */ |
1555 | LPSPI_MasterTransferComplete(base, handle); |
1556 | } |
1557 | else |
1558 | { |
1559 | LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_TransferCompleteInterruptEnable); |
1560 | LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable | (uint32_t)kLPSPI_RxInterruptEnable); |
1561 | } |
1562 | } |
1563 | else |
1564 | { |
1565 | /* Complete the transfer and disable the interrupts */ |
1566 | LPSPI_MasterTransferComplete(base, handle); |
1567 | } |
1568 | } |
1569 | } |
1570 | |
1571 | /*Transactional APIs -- Slave*/ |
1572 | /*! |
1573 | * brief Initializes the LPSPI slave handle. |
1574 | * |
1575 | * This function initializes the LPSPI handle, which can be used for other LPSPI transactional APIs. Usually, for a |
1576 | * specified LPSPI instance, call this API once to get the initialized handle. |
1577 | * |
1578 | * param base LPSPI peripheral address. |
1579 | * param handle LPSPI handle pointer to lpspi_slave_handle_t. |
1580 | * param callback DSPI callback. |
1581 | * param userData callback function parameter. |
1582 | */ |
1583 | void LPSPI_SlaveTransferCreateHandle(LPSPI_Type *base, |
1584 | lpspi_slave_handle_t *handle, |
1585 | lpspi_slave_transfer_callback_t callback, |
1586 | void *userData) |
1587 | { |
1588 | assert(handle != NULL); |
1589 | |
1590 | /* Zero the handle. */ |
1591 | (void)memset(handle, 0, sizeof(*handle)); |
1592 | |
1593 | s_lpspiHandle[LPSPI_GetInstance(base)] = handle; |
1594 | |
1595 | /* Set irq handler. */ |
1596 | s_lpspiSlaveIsr = LPSPI_SlaveTransferHandleIRQ; |
1597 | |
1598 | handle->callback = callback; |
1599 | handle->userData = userData; |
1600 | } |
1601 | |
1602 | /*! |
1603 | * brief LPSPI slave transfer data using an interrupt method. |
1604 | * |
1605 | * This function transfer data using an interrupt method. This is a non-blocking function, which returns right away. |
1606 | * When all data is transferred, the callback function is called. |
1607 | * |
1608 | * Note: |
1609 | * The transfer data size should be integer multiples of bytesPerFrame if bytesPerFrame is less than or equal to 4. |
1610 | * For bytesPerFrame greater than 4: |
1611 | * The transfer data size should be equal to bytesPerFrame if the bytesPerFrame is not an integer multiple of 4. |
1612 | * Otherwise, the transfer data size can be an integer multiple of bytesPerFrame. |
1613 | * |
1614 | * param base LPSPI peripheral address. |
1615 | * param handle pointer to lpspi_slave_handle_t structure which stores the transfer state. |
1616 | * param transfer pointer to lpspi_transfer_t structure. |
1617 | * return status of status_t. |
1618 | */ |
1619 | status_t LPSPI_SlaveTransferNonBlocking(LPSPI_Type *base, lpspi_slave_handle_t *handle, lpspi_transfer_t *transfer) |
1620 | { |
1621 | assert(handle != NULL); |
1622 | assert(transfer != NULL); |
1623 | |
1624 | /* Check that we're not busy.*/ |
1625 | if (handle->state == (uint8_t)kLPSPI_Busy) |
1626 | { |
1627 | return kStatus_LPSPI_Busy; |
1628 | } |
1629 | LPSPI_Enable(base, false); |
1630 | /* Check arguements */ |
1631 | if (!LPSPI_CheckTransferArgument(base, transfer, false)) |
1632 | { |
1633 | return kStatus_InvalidArgument; |
1634 | } |
1635 | |
1636 | /* Flush FIFO, clear status, disable all the inerrupts. */ |
1637 | LPSPI_FlushFifo(base, true, true); |
1638 | LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_AllStatusFlag); |
1639 | LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable); |
1640 | |
1641 | /* Variables */ |
1642 | bool isRxMask = false; |
1643 | bool isTxMask = false; |
1644 | uint8_t txWatermark; |
1645 | uint32_t readRegRemainingTimes; |
1646 | uint32_t whichPcs = (transfer->configFlags & LPSPI_SLAVE_PCS_MASK) >> LPSPI_SLAVE_PCS_SHIFT; |
1647 | uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U; |
1648 | |
1649 | /* Assign the original value for members of transfer handle. */ |
1650 | handle->state = (uint8_t)kLPSPI_Busy; |
1651 | handle->txData = transfer->txData; |
1652 | handle->rxData = transfer->rxData; |
1653 | handle->txRemainingByteCount = transfer->dataSize; |
1654 | handle->rxRemainingByteCount = transfer->dataSize; |
1655 | handle->totalByteCount = transfer->dataSize; |
1656 | handle->writeRegRemainingTimes = (transfer->dataSize / bytesPerFrame) * ((bytesPerFrame + 3U) / 4U); |
1657 | handle->readRegRemainingTimes = handle->writeRegRemainingTimes; |
1658 | /*The TX and RX FIFO sizes are always the same*/ |
1659 | handle->fifoSize = LPSPI_GetRxFifoSize(base); |
1660 | handle->isByteSwap = ((transfer->configFlags & (uint32_t)kLPSPI_SlaveByteSwap) != 0U); |
1661 | /*Calculate the bytes for write/read the TX/RX register each time*/ |
1662 | if (bytesPerFrame <= 4U) |
1663 | { |
1664 | handle->bytesEachWrite = (uint8_t)bytesPerFrame; |
1665 | handle->bytesEachRead = (uint8_t)bytesPerFrame; |
1666 | } |
1667 | else |
1668 | { |
1669 | handle->bytesEachWrite = 4U; |
1670 | handle->bytesEachRead = 4U; |
1671 | } |
1672 | /* Set proper RX and TX watermarks to reduce the ISR response times. */ |
1673 | if (handle->fifoSize > 1U) |
1674 | { |
1675 | txWatermark = 1U; |
1676 | handle->rxWatermark = handle->fifoSize - 2U; |
1677 | } |
1678 | else |
1679 | { |
1680 | txWatermark = 0U; |
1681 | handle->rxWatermark = 0U; |
1682 | } |
1683 | LPSPI_SetFifoWatermarks(base, txWatermark, handle->rxWatermark); |
1684 | |
1685 | /* If there is no rxData, mask the receive data so that receive data is not stored in receive FIFO. */ |
1686 | if (handle->rxData == NULL) |
1687 | { |
1688 | isRxMask = true; |
1689 | handle->rxRemainingByteCount = 0U; |
1690 | } |
1691 | /* If there is no txData, mask the transmit data so that no data is loaded from transmit FIFO and output pin |
1692 | * is tristated. */ |
1693 | if (handle->txData == NULL) |
1694 | { |
1695 | isTxMask = true; |
1696 | handle->txRemainingByteCount = 0U; |
1697 | } |
1698 | |
1699 | /* Enable module for following configuration of TCR to take effect. */ |
1700 | LPSPI_Enable(base, true); |
1701 | |
1702 | base->TCR = (base->TCR & ~(LPSPI_TCR_CONT_MASK | LPSPI_TCR_CONTC_MASK | LPSPI_TCR_RXMSK_MASK | |
1703 | LPSPI_TCR_TXMSK_MASK | LPSPI_TCR_PCS_MASK)) | |
1704 | LPSPI_TCR_RXMSK(isRxMask) | LPSPI_TCR_TXMSK(isTxMask) | LPSPI_TCR_PCS(whichPcs); |
1705 | |
1706 | /* Enable the NVIC for LPSPI peripheral. Note that below code is useless if the LPSPI interrupt is in INTMUX , |
1707 | * and you should also enable the INTMUX interupt in your application. |
1708 | */ |
1709 | (void)EnableIRQ(s_lpspiIRQ[LPSPI_GetInstance(base)]); |
1710 | |
1711 | /*TCR is also shared the FIFO, so wait for TCR written.*/ |
1712 | if (!LPSPI_TxFifoReady(base)) |
1713 | { |
1714 | return kStatus_LPSPI_Timeout; |
1715 | } |
1716 | |
1717 | /* Fill up the TX data in FIFO */ |
1718 | if (handle->txData != NULL) |
1719 | { |
1720 | LPSPI_SlaveTransferFillUpTxFifo(base, handle); |
1721 | } |
1722 | |
1723 | /* Since SPI is a synchronous interface, we only need to enable the RX interrupt if there is RX data. |
1724 | * The IRQ handler will get the status of RX and TX interrupt flags. |
1725 | */ |
1726 | if (handle->rxData != NULL) |
1727 | { |
1728 | /*Set rxWatermark to (readRegRemainingTimes-1) if readRegRemainingTimes less than rxWatermark. Otherwise there |
1729 | *is not RX interrupt for the last datas because the RX count is not greater than rxWatermark. |
1730 | */ |
1731 | readRegRemainingTimes = handle->readRegRemainingTimes; |
1732 | if (readRegRemainingTimes <= (uint32_t)handle->rxWatermark) |
1733 | { |
1734 | base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) | LPSPI_FCR_RXWATER(readRegRemainingTimes - 1U); |
1735 | } |
1736 | |
1737 | /* RX request and FIFO overflow request enable */ |
1738 | LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_RxInterruptEnable | (uint32_t)kLPSPI_ReceiveErrorInterruptEnable); |
1739 | } |
1740 | else |
1741 | { |
1742 | LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable); |
1743 | } |
1744 | |
1745 | if (handle->txData != NULL) |
1746 | { |
1747 | /* TX FIFO underflow request enable */ |
1748 | LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_TransmitErrorInterruptEnable); |
1749 | } |
1750 | |
1751 | return kStatus_Success; |
1752 | } |
1753 | |
1754 | static void LPSPI_SlaveTransferFillUpTxFifo(LPSPI_Type *base, lpspi_slave_handle_t *handle) |
1755 | { |
1756 | assert(handle != NULL); |
1757 | |
1758 | uint32_t wordToSend = 0U; |
1759 | uint8_t bytesEachWrite = handle->bytesEachWrite; |
1760 | bool isByteSwap = handle->isByteSwap; |
1761 | |
1762 | while (LPSPI_GetTxFifoCount(base) < (handle->fifoSize)) |
1763 | { |
1764 | if (handle->txRemainingByteCount < (size_t)bytesEachWrite) |
1765 | { |
1766 | handle->bytesEachWrite = (uint8_t)handle->txRemainingByteCount; |
1767 | bytesEachWrite = handle->bytesEachWrite; |
1768 | } |
1769 | |
1770 | wordToSend = LPSPI_CombineWriteData(handle->txData, bytesEachWrite, isByteSwap); |
1771 | handle->txData += bytesEachWrite; |
1772 | |
1773 | /*Decrease the remaining TX byte count.*/ |
1774 | handle->txRemainingByteCount -= (size_t)bytesEachWrite; |
1775 | |
1776 | /*Write the word to TX register*/ |
1777 | LPSPI_WriteData(base, wordToSend); |
1778 | |
1779 | if (handle->txRemainingByteCount == 0U) |
1780 | { |
1781 | break; |
1782 | } |
1783 | } |
1784 | } |
1785 | |
1786 | static void LPSPI_SlaveTransferComplete(LPSPI_Type *base, lpspi_slave_handle_t *handle) |
1787 | { |
1788 | assert(handle != NULL); |
1789 | |
1790 | status_t status = kStatus_Success; |
1791 | |
1792 | /* Disable interrupt requests*/ |
1793 | LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_AllInterruptEnable); |
1794 | |
1795 | if (handle->state == (uint8_t)kLPSPI_Error) |
1796 | { |
1797 | status = kStatus_LPSPI_Error; |
1798 | } |
1799 | else |
1800 | { |
1801 | status = kStatus_Success; |
1802 | } |
1803 | |
1804 | handle->state = (uint8_t)kLPSPI_Idle; |
1805 | |
1806 | if (handle->callback != NULL) |
1807 | { |
1808 | handle->callback(base, handle, status, handle->userData); |
1809 | } |
1810 | } |
1811 | |
1812 | /*! |
1813 | * brief Gets the slave transfer remaining bytes. |
1814 | * |
1815 | * This function gets the slave transfer remaining bytes. |
1816 | * |
1817 | * param base LPSPI peripheral address. |
1818 | * param handle pointer to lpspi_slave_handle_t structure which stores the transfer state. |
1819 | * param count Number of bytes transferred so far by the non-blocking transaction. |
1820 | * return status of status_t. |
1821 | */ |
1822 | status_t LPSPI_SlaveTransferGetCount(LPSPI_Type *base, lpspi_slave_handle_t *handle, size_t *count) |
1823 | { |
1824 | assert(handle != NULL); |
1825 | |
1826 | if (NULL == count) |
1827 | { |
1828 | return kStatus_InvalidArgument; |
1829 | } |
1830 | |
1831 | /* Catch when there is not an active transfer. */ |
1832 | if (handle->state != (uint8_t)kLPSPI_Busy) |
1833 | { |
1834 | *count = 0; |
1835 | return kStatus_NoTransferInProgress; |
1836 | } |
1837 | |
1838 | size_t remainingByte; |
1839 | |
1840 | if (handle->rxData != NULL) |
1841 | { |
1842 | remainingByte = handle->rxRemainingByteCount; |
1843 | } |
1844 | else |
1845 | { |
1846 | remainingByte = handle->txRemainingByteCount; |
1847 | } |
1848 | |
1849 | *count = handle->totalByteCount - remainingByte; |
1850 | |
1851 | return kStatus_Success; |
1852 | } |
1853 | |
1854 | /*! |
1855 | * brief LPSPI slave aborts a transfer which uses an interrupt method. |
1856 | * |
1857 | * This function aborts a transfer which uses an interrupt method. |
1858 | * |
1859 | * param base LPSPI peripheral address. |
1860 | * param handle pointer to lpspi_slave_handle_t structure which stores the transfer state. |
1861 | */ |
1862 | void LPSPI_SlaveTransferAbort(LPSPI_Type *base, lpspi_slave_handle_t *handle) |
1863 | { |
1864 | assert(handle != NULL); |
1865 | |
1866 | /* Disable interrupt requests*/ |
1867 | LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable | (uint32_t)kLPSPI_RxInterruptEnable); |
1868 | |
1869 | LPSPI_Reset(base); |
1870 | |
1871 | handle->state = (uint8_t)kLPSPI_Idle; |
1872 | handle->txRemainingByteCount = 0U; |
1873 | handle->rxRemainingByteCount = 0U; |
1874 | } |
1875 | |
1876 | /*! |
1877 | * brief LPSPI Slave IRQ handler function. |
1878 | * |
1879 | * This function processes the LPSPI transmit and receives an IRQ. |
1880 | * |
1881 | * param base LPSPI peripheral address. |
1882 | * param handle pointer to lpspi_slave_handle_t structure which stores the transfer state. |
1883 | */ |
1884 | void LPSPI_SlaveTransferHandleIRQ(LPSPI_Type *base, lpspi_slave_handle_t *handle) |
1885 | { |
1886 | assert(handle != NULL); |
1887 | |
1888 | uint32_t readData; /* variable to store word read from RX FIFO */ |
1889 | uint8_t bytesEachRead = handle->bytesEachRead; |
1890 | bool isByteSwap = handle->isByteSwap; |
1891 | uint32_t readRegRemainingTimes; |
1892 | |
1893 | if (handle->rxData != NULL) |
1894 | { |
1895 | if (handle->rxRemainingByteCount > 0U) |
1896 | { |
1897 | while (LPSPI_GetRxFifoCount(base) != 0U) |
1898 | { |
1899 | /*Read out the data*/ |
1900 | readData = LPSPI_ReadData(base); |
1901 | |
1902 | /*Decrease the read RX register times.*/ |
1903 | --handle->readRegRemainingTimes; |
1904 | |
1905 | if (handle->rxRemainingByteCount < (size_t)bytesEachRead) |
1906 | { |
1907 | handle->bytesEachRead = (uint8_t)handle->rxRemainingByteCount; |
1908 | bytesEachRead = handle->bytesEachRead; |
1909 | } |
1910 | |
1911 | LPSPI_SeparateReadData(handle->rxData, readData, bytesEachRead, isByteSwap); |
1912 | handle->rxData += bytesEachRead; |
1913 | |
1914 | /*Decrease the remaining RX byte count.*/ |
1915 | handle->rxRemainingByteCount -= (size_t)bytesEachRead; |
1916 | |
1917 | if ((handle->txRemainingByteCount > 0U) && (handle->txData != NULL)) |
1918 | { |
1919 | LPSPI_SlaveTransferFillUpTxFifo(base, handle); |
1920 | } |
1921 | |
1922 | if (handle->rxRemainingByteCount == 0U) |
1923 | { |
1924 | break; |
1925 | } |
1926 | } |
1927 | } |
1928 | |
1929 | /*Set rxWatermark to (readRegRemainingTimes-1) if readRegRemainingTimes less than rxWatermark. Otherwise there |
1930 | *is not RX interrupt for the last datas because the RX count is not greater than rxWatermark. |
1931 | */ |
1932 | readRegRemainingTimes = handle->readRegRemainingTimes; |
1933 | if (readRegRemainingTimes <= (uint32_t)handle->rxWatermark) |
1934 | { |
1935 | base->FCR = (base->FCR & (~LPSPI_FCR_RXWATER_MASK)) | |
1936 | LPSPI_FCR_RXWATER((readRegRemainingTimes > 1U) ? (readRegRemainingTimes - 1U) : (0U)); |
1937 | } |
1938 | } |
1939 | if ((handle->rxData == NULL) && (handle->txRemainingByteCount != 0U) && (handle->txData != NULL)) |
1940 | { |
1941 | LPSPI_SlaveTransferFillUpTxFifo(base, handle); |
1942 | } |
1943 | |
1944 | if ((handle->txRemainingByteCount == 0U) && (handle->rxRemainingByteCount == 0U)) |
1945 | { |
1946 | /* If no RX buffer, then transfer is not complete until transfer complete flag sets and the TX FIFO empty*/ |
1947 | if (handle->rxData == NULL) |
1948 | { |
1949 | if (((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_FrameCompleteFlag) != 0U) && |
1950 | (LPSPI_GetTxFifoCount(base) == 0U)) |
1951 | { |
1952 | LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_FrameCompleteFlag); |
1953 | /* Complete the transfer and disable the interrupts */ |
1954 | LPSPI_SlaveTransferComplete(base, handle); |
1955 | } |
1956 | else |
1957 | { |
1958 | LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_FrameCompleteFlag); |
1959 | LPSPI_EnableInterrupts(base, (uint32_t)kLPSPI_FrameCompleteInterruptEnable); |
1960 | LPSPI_DisableInterrupts(base, (uint32_t)kLPSPI_TxInterruptEnable | (uint32_t)kLPSPI_RxInterruptEnable); |
1961 | } |
1962 | } |
1963 | else |
1964 | { |
1965 | /* Complete the transfer and disable the interrupts */ |
1966 | LPSPI_SlaveTransferComplete(base, handle); |
1967 | } |
1968 | } |
1969 | |
1970 | /* Catch tx fifo underflow conditions, service only if tx under flow interrupt enabled */ |
1971 | if (((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_TransmitErrorFlag) != 0U) && |
1972 | ((base->IER & LPSPI_IER_TEIE_MASK) != 0U)) |
1973 | { |
1974 | LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_TransmitErrorFlag); |
1975 | /* Change state to error and clear flag */ |
1976 | if (handle->txData != NULL) |
1977 | { |
1978 | handle->state = (uint8_t)kLPSPI_Error; |
1979 | } |
1980 | handle->errorCount++; |
1981 | } |
1982 | /* Catch rx fifo overflow conditions, service only if rx over flow interrupt enabled */ |
1983 | if (((LPSPI_GetStatusFlags(base) & (uint32_t)kLPSPI_ReceiveErrorFlag) != 0U) && |
1984 | ((base->IER & LPSPI_IER_REIE_MASK) != 0U)) |
1985 | { |
1986 | LPSPI_ClearStatusFlags(base, (uint32_t)kLPSPI_ReceiveErrorFlag); |
1987 | /* Change state to error and clear flag */ |
1988 | if (handle->txData != NULL) |
1989 | { |
1990 | handle->state = (uint8_t)kLPSPI_Error; |
1991 | } |
1992 | handle->errorCount++; |
1993 | } |
1994 | } |
1995 | |
1996 | static uint32_t LPSPI_CombineWriteData(uint8_t *txData, uint8_t bytesEachWrite, bool isByteSwap) |
1997 | { |
1998 | assert(txData != NULL); |
1999 | |
2000 | uint32_t wordToSend = 0U; |
2001 | |
2002 | switch (bytesEachWrite) |
2003 | { |
2004 | case 1: |
2005 | wordToSend = *txData; |
2006 | ++txData; |
2007 | break; |
2008 | |
2009 | case 2: |
2010 | if (!isByteSwap) |
2011 | { |
2012 | wordToSend = *txData; |
2013 | ++txData; |
2014 | wordToSend |= (unsigned)(*txData) << 8U; |
2015 | ++txData; |
2016 | } |
2017 | else |
2018 | { |
2019 | wordToSend = (unsigned)(*txData) << 8U; |
2020 | ++txData; |
2021 | wordToSend |= *txData; |
2022 | ++txData; |
2023 | } |
2024 | |
2025 | break; |
2026 | |
2027 | case 3: |
2028 | if (!isByteSwap) |
2029 | { |
2030 | wordToSend = *txData; |
2031 | ++txData; |
2032 | wordToSend |= (unsigned)(*txData) << 8U; |
2033 | ++txData; |
2034 | wordToSend |= (unsigned)(*txData) << 16U; |
2035 | ++txData; |
2036 | } |
2037 | else |
2038 | { |
2039 | wordToSend = (unsigned)(*txData) << 16U; |
2040 | ++txData; |
2041 | wordToSend |= (unsigned)(*txData) << 8U; |
2042 | ++txData; |
2043 | wordToSend |= *txData; |
2044 | ++txData; |
2045 | } |
2046 | break; |
2047 | |
2048 | case 4: |
2049 | if (!isByteSwap) |
2050 | { |
2051 | wordToSend = *txData; |
2052 | ++txData; |
2053 | wordToSend |= (unsigned)(*txData) << 8U; |
2054 | ++txData; |
2055 | wordToSend |= (unsigned)(*txData) << 16U; |
2056 | ++txData; |
2057 | wordToSend |= (unsigned)(*txData) << 24U; |
2058 | ++txData; |
2059 | } |
2060 | else |
2061 | { |
2062 | wordToSend = (unsigned)(*txData) << 24U; |
2063 | ++txData; |
2064 | wordToSend |= (unsigned)(*txData) << 16U; |
2065 | ++txData; |
2066 | wordToSend |= (unsigned)(*txData) << 8U; |
2067 | ++txData; |
2068 | wordToSend |= *txData; |
2069 | ++txData; |
2070 | } |
2071 | break; |
2072 | |
2073 | default: |
2074 | assert(false); |
2075 | break; |
2076 | } |
2077 | return wordToSend; |
2078 | } |
2079 | |
2080 | static void LPSPI_SeparateReadData(uint8_t *rxData, uint32_t readData, uint8_t bytesEachRead, bool isByteSwap) |
2081 | { |
2082 | assert(rxData != NULL); |
2083 | |
2084 | switch (bytesEachRead) |
2085 | { |
2086 | case 1: |
2087 | *rxData = (uint8_t)readData; |
2088 | ++rxData; |
2089 | break; |
2090 | |
2091 | case 2: |
2092 | if (!isByteSwap) |
2093 | { |
2094 | *rxData = (uint8_t)readData; |
2095 | ++rxData; |
2096 | *rxData = (uint8_t)(readData >> 8); |
2097 | ++rxData; |
2098 | } |
2099 | else |
2100 | { |
2101 | *rxData = (uint8_t)(readData >> 8); |
2102 | ++rxData; |
2103 | *rxData = (uint8_t)readData; |
2104 | ++rxData; |
2105 | } |
2106 | break; |
2107 | |
2108 | case 3: |
2109 | if (!isByteSwap) |
2110 | { |
2111 | *rxData = (uint8_t)readData; |
2112 | ++rxData; |
2113 | *rxData = (uint8_t)(readData >> 8); |
2114 | ++rxData; |
2115 | *rxData = (uint8_t)(readData >> 16); |
2116 | ++rxData; |
2117 | } |
2118 | else |
2119 | { |
2120 | *rxData = (uint8_t)(readData >> 16); |
2121 | ++rxData; |
2122 | *rxData = (uint8_t)(readData >> 8); |
2123 | ++rxData; |
2124 | *rxData = (uint8_t)readData; |
2125 | ++rxData; |
2126 | } |
2127 | break; |
2128 | |
2129 | case 4: |
2130 | if (!isByteSwap) |
2131 | { |
2132 | *rxData = (uint8_t)readData; |
2133 | ++rxData; |
2134 | *rxData = (uint8_t)(readData >> 8); |
2135 | ++rxData; |
2136 | *rxData = (uint8_t)(readData >> 16); |
2137 | ++rxData; |
2138 | *rxData = (uint8_t)(readData >> 24); |
2139 | ++rxData; |
2140 | } |
2141 | else |
2142 | { |
2143 | *rxData = (uint8_t)(readData >> 24); |
2144 | ++rxData; |
2145 | *rxData = (uint8_t)(readData >> 16); |
2146 | ++rxData; |
2147 | *rxData = (uint8_t)(readData >> 8); |
2148 | ++rxData; |
2149 | *rxData = (uint8_t)readData; |
2150 | ++rxData; |
2151 | } |
2152 | break; |
2153 | |
2154 | default: |
2155 | assert(false); |
2156 | break; |
2157 | } |
2158 | } |
2159 | |
2160 | static bool LPSPI_TxFifoReady(LPSPI_Type *base) |
2161 | { |
2162 | #if SPI_RETRY_TIMES |
2163 | uint32_t waitTimes = SPI_RETRY_TIMES; |
2164 | while (((uint8_t)LPSPI_GetTxFifoCount(base) != 0U) && (--waitTimes != 0U)) |
2165 | #else |
2166 | while ((uint8_t)LPSPI_GetTxFifoCount(base) != 0U) |
2167 | #endif |
2168 | { |
2169 | } |
2170 | #if SPI_RETRY_TIMES |
2171 | if (waitTimes == 0U) |
2172 | { |
2173 | return false; |
2174 | } |
2175 | #endif |
2176 | return true; |
2177 | } |
2178 | |
2179 | static void LPSPI_CommonIRQHandler(LPSPI_Type *base, void *param) |
2180 | { |
2181 | if (LPSPI_IsMaster(base)) |
2182 | { |
2183 | s_lpspiMasterIsr(base, (lpspi_master_handle_t *)param); |
2184 | } |
2185 | else |
2186 | { |
2187 | s_lpspiSlaveIsr(base, (lpspi_slave_handle_t *)param); |
2188 | } |
2189 | SDK_ISR_EXIT_BARRIER; |
2190 | } |
2191 | |
2192 | #if defined(LPSPI0) |
2193 | void LPSPI0_DriverIRQHandler(void); |
2194 | void LPSPI0_DriverIRQHandler(void) |
2195 | { |
2196 | assert(s_lpspiHandle[0] != NULL); |
2197 | LPSPI_CommonIRQHandler(LPSPI0, s_lpspiHandle[0]); |
2198 | } |
2199 | #endif |
2200 | |
2201 | #if defined(LPSPI1) |
2202 | void LPSPI1_DriverIRQHandler(void); |
2203 | void LPSPI1_DriverIRQHandler(void) |
2204 | { |
2205 | assert(s_lpspiHandle[1] != NULL); |
2206 | LPSPI_CommonIRQHandler(LPSPI1, s_lpspiHandle[1]); |
2207 | } |
2208 | #endif |
2209 | |
2210 | #if defined(LPSPI2) |
2211 | void LPSPI2_DriverIRQHandler(void); |
2212 | void LPSPI2_DriverIRQHandler(void) |
2213 | { |
2214 | assert(s_lpspiHandle[2] != NULL); |
2215 | LPSPI_CommonIRQHandler(LPSPI2, s_lpspiHandle[2]); |
2216 | } |
2217 | #endif |
2218 | |
2219 | #if defined(LPSPI3) |
2220 | void LPSPI3_DriverIRQHandler(void); |
2221 | void LPSPI3_DriverIRQHandler(void) |
2222 | { |
2223 | assert(s_lpspiHandle[3] != NULL); |
2224 | LPSPI_CommonIRQHandler(LPSPI3, s_lpspiHandle[3]); |
2225 | } |
2226 | #endif |
2227 | |
2228 | #if defined(LPSPI4) |
2229 | void LPSPI4_DriverIRQHandler(void); |
2230 | void LPSPI4_DriverIRQHandler(void) |
2231 | { |
2232 | assert(s_lpspiHandle[4] != NULL); |
2233 | LPSPI_CommonIRQHandler(LPSPI4, s_lpspiHandle[4]); |
2234 | } |
2235 | #endif |
2236 | |
2237 | #if defined(LPSPI5) |
2238 | void LPSPI5_DriverIRQHandler(void); |
2239 | void LPSPI5_DriverIRQHandler(void) |
2240 | { |
2241 | assert(s_lpspiHandle[5] != NULL); |
2242 | LPSPI_CommonIRQHandler(LPSPI5, s_lpspiHandle[5]); |
2243 | } |
2244 | #endif |
2245 | |
2246 | #if defined(DMA__LPSPI0) |
2247 | void DMA_SPI0_INT_DriverIRQHandler(void); |
2248 | void DMA_SPI0_INT_DriverIRQHandler(void) |
2249 | { |
2250 | assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI0)] != NULL); |
2251 | LPSPI_CommonIRQHandler(DMA__LPSPI0, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI0)]); |
2252 | } |
2253 | #endif |
2254 | |
2255 | #if defined(DMA__LPSPI1) |
2256 | void DMA_SPI1_INT_DriverIRQHandler(void); |
2257 | void DMA_SPI1_INT_DriverIRQHandler(void) |
2258 | { |
2259 | assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI1)] != NULL); |
2260 | LPSPI_CommonIRQHandler(DMA__LPSPI1, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI1)]); |
2261 | } |
2262 | #endif |
2263 | #if defined(DMA__LPSPI2) |
2264 | void DMA_SPI2_INT_DriverIRQHandler(void); |
2265 | void DMA_SPI2_INT_DriverIRQHandler(void) |
2266 | { |
2267 | assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI2)] != NULL); |
2268 | LPSPI_CommonIRQHandler(DMA__LPSPI2, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI2)]); |
2269 | } |
2270 | #endif |
2271 | |
2272 | #if defined(DMA__LPSPI3) |
2273 | void DMA_SPI3_INT_DriverIRQHandler(void); |
2274 | void DMA_SPI3_INT_DriverIRQHandler(void) |
2275 | { |
2276 | assert(s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI3)] != NULL); |
2277 | LPSPI_CommonIRQHandler(DMA__LPSPI3, s_lpspiHandle[LPSPI_GetInstance(DMA__LPSPI3)]); |
2278 | } |
2279 | #endif |
2280 | |
2281 | #if defined(ADMA__LPSPI0) |
2282 | void ADMA_SPI0_INT_DriverIRQHandler(void); |
2283 | void ADMA_SPI0_INT_DriverIRQHandler(void) |
2284 | { |
2285 | assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI0)] != NULL); |
2286 | LPSPI_CommonIRQHandler(ADMA__LPSPI0, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI0)]); |
2287 | } |
2288 | #endif |
2289 | |
2290 | #if defined(ADMA__LPSPI1) |
2291 | void ADMA_SPI1_INT_DriverIRQHandler(void); |
2292 | void ADMA_SPI1_INT_DriverIRQHandler(void) |
2293 | { |
2294 | assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI1)] != NULL); |
2295 | LPSPI_CommonIRQHandler(ADMA__LPSPI1, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI1)]); |
2296 | } |
2297 | #endif |
2298 | #if defined(ADMA__LPSPI2) |
2299 | void ADMA_SPI2_INT_DriverIRQHandler(void); |
2300 | void ADMA_SPI2_INT_DriverIRQHandler(void) |
2301 | { |
2302 | assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI2)] != NULL); |
2303 | LPSPI_CommonIRQHandler(ADMA__LPSPI2, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI2)]); |
2304 | } |
2305 | #endif |
2306 | |
2307 | #if defined(ADMA__LPSPI3) |
2308 | void ADMA_SPI3_INT_DriverIRQHandler(void); |
2309 | void ADMA_SPI3_INT_DriverIRQHandler(void) |
2310 | { |
2311 | assert(s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI3)] != NULL); |
2312 | LPSPI_CommonIRQHandler(ADMA__LPSPI3, s_lpspiHandle[LPSPI_GetInstance(ADMA__LPSPI3)]); |
2313 | } |
2314 | #endif |
2315 | |