S32 SDK
lpspi_master_driver.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2017 NXP
4  * All rights reserved.
5  *
6  * THIS SOFTWARE IS PROVIDED BY NXP "AS IS" AND ANY EXPRESSED OR
7  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
8  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
9  * IN NO EVENT SHALL NXP OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
10  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
11  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
12  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
14  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
15  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
16  * THE POSSIBILITY OF SUCH DAMAGE.
17  */
18 
87 #include <string.h>
88 #include "lpspi_master_driver.h"
89 #include "clock_manager.h"
90 #include "interrupt_manager.h"
91 #include "device_registers.h"
92 #include "lpspi_hw_access.h"
93 
94 
95 /*******************************************************************************
96  * Definitions
97  ******************************************************************************/
98 #define MICROSECONDS 1000000
99 /*******************************************************************************
100  * Variables
101  ******************************************************************************/
102 
103 /*******************************************************************************
104  * Prototypes
105  ******************************************************************************/
106 /* This function initialize a new SPI transfer */
107 static status_t LPSPI_DRV_MasterStartTransfer(uint32_t instance,
108  const uint8_t * sendBuffer,
109  uint8_t * receiveBuffer,
110  uint16_t transferByteCount);
111 
112 /* This function cleans up state structure and hardware after a transfer is complete .*/
113 static void LPSPI_DRV_MasterCompleteTransfer(uint32_t instance);
114 
115 /* Callback for DMA transfer done.*/
116 static void LPSPI_DRV_MasterCompleteDMATransfer(void* parameter, edma_chn_status_t status);
117 
119 static void LPSPI_DRV_MasterClearCountinuous(void* parameter, edma_chn_status_t status);
120 
121 /*******************************************************************************
122  * Code
123  ******************************************************************************/
124 
125 /*FUNCTION**********************************************************************
126  *
127  * Function Name : LPSPI_DRV_MasterInit
128  * Description : Initializes a LPSPI instance for interrupt driven master mode operation.
129  *
130  * This function uses an interrupt-driven method for transferring data.
131  * In this function, the term "spiConfig" is used to indicate the SPI device for which the LPSPI
132  * master is communicating.
133  * This function initializes the run-time state structure to track the ongoing
134  * transfers, un-gates the clock to the LPSPI module, resets the LPSPI module,
135  * configures the IRQ state structure, enables the module-level interrupt to the core, and
136  * enables the LPSPI module.
137  * Implements : LPSPI_DRV_MasterInit_Activity
138  *
139  *END**************************************************************************/
140 status_t LPSPI_DRV_MasterInit(uint32_t instance, lpspi_state_t * lpspiState,
141  const lpspi_master_config_t * spiConfig)
142 {
143  DEV_ASSERT(instance < LPSPI_INSTANCE_COUNT);
144  DEV_ASSERT(lpspiState != NULL);
145  DEV_ASSERT(spiConfig != NULL);
146  LPSPI_Type *base = g_lpspiBase[instance];
147  status_t errorCode = STATUS_SUCCESS;
148 
149  /* Save runtime structure pointers so irq handler can point to the correct state structure */
150  g_lpspiStatePtr[instance] = lpspiState;
151  /* Reset the LPSPI registers to their default state */
152  LPSPI_Init(base);
153  /* Set for master mode */
154  (void)LPSPI_SetMasterSlaveMode(base, LPSPI_MASTER);
155  /* Set Pin configuration such that SDO=out and SDI=in */
156  (void)LPSPI_SetPinConfigMode(base, LPSPI_SDI_IN_SDO_OUT, LPSPI_DATA_OUT_RETAINED, true);
157  /* Calculate the FIFO size for the LPSPI */
158  LPSPI_GetFifoSizes(base, &(lpspiState->fifoSize), NULL);
159 
160  /* Configure bus for this device. If NULL is passed, we assume the caller has
161  * preconfigured the bus and doesn't wish to re-configure it again for this transfer.
162  * Do nothing for calculatedBaudRate. If the user wants to know the calculatedBaudRate
163  * then they can call this function separately.
164  */
165  errorCode = LPSPI_DRV_MasterConfigureBus(instance, spiConfig, NULL);
166  if (errorCode != STATUS_SUCCESS)
167  {
168  return errorCode;
169  }
170  /* Initialize the semaphore */
171  errorCode = OSIF_SemaCreate(&(lpspiState->lpspiSemaphore), 0);
172  DEV_ASSERT(errorCode == STATUS_SUCCESS);
173  /* Enable the interrupt */
174  INT_SYS_EnableIRQ(g_lpspiIrqId[instance]);
175  /* Finally, enable LPSPI */
176  LPSPI_Enable(base);
177  return errorCode;
178 }
179 
180 /*FUNCTION**********************************************************************
181  *
182  * Function Name : LPSPI_DRV_MasterDeinit
183  * Description : Shuts down a LPSPI instance.
184  *
185  * This function resets the LPSPI peripheral, gates its clock, and disables the interrupt to
186  * the core. It first checks to see if a transfer is in progress and if so returns an error
187  * status.
188  * Implements : LPSPI_DRV_MasterDeinit_Activity
189  *
190  *END**************************************************************************/
192 {
193  DEV_ASSERT(instance < LPSPI_INSTANCE_COUNT);
194  /* Instantiate local variable of type lpspi_state_t and point to global state */
195  const lpspi_state_t * lpspiState = g_lpspiStatePtr[instance];
196  LPSPI_Type *base = g_lpspiBase[instance];
197  status_t errorCode = STATUS_SUCCESS;
198 
199  /* Check if a transfer is still in progress */
200  DEV_ASSERT(lpspiState->isTransferInProgress == false);
201 
202  /* Reset the LPSPI registers to their default state, inlcuding disabling the LPSPI */
203  LPSPI_Init(base);
204  /* Disable the interrupt */
205  INT_SYS_DisableIRQ(g_lpspiIrqId[instance]);
206  /* Clear the state pointer. */
207  g_lpspiStatePtr[instance] = NULL;
208 
209  /* Destroy the semaphore */
210  errorCode = OSIF_SemaDestroy(&(lpspiState->lpspiSemaphore));
211  DEV_ASSERT(errorCode == STATUS_SUCCESS);
212  return errorCode;
213 }
214 
215 /*FUNCTION**********************************************************************
216  *
217  * Function Name : LPSPI_DRV_MasterSetDelay
218  * Description : Configures the LPSPI master mode bus timing delay options.
219  *
220  * This function involves the LPSPI module's delay options to
221  * "fine tune" some of the signal timings and match the timing needs of a slower peripheral device.
222  * This is an optional function that can be called after the LPSPI module has been initialized for
223  * master mode. The timings are adjusted in terms of cycles of the baud rate clock.
224  * The bus timing delays that can be adjusted are listed below:
225  *
226  * SCK to PCS Delay: Adjustable delay option between the last edge of SCK to the de-assertion
227  * of the PCS signal.
228  *
229  * PCS to SCK Delay: Adjustable delay option between the assertion of the PCS signal to the
230  * first SCK edge.
231  *
232  * Delay between Transfers: Adjustable delay option between the de-assertion of the PCS signal for
233  * a frame to the assertion of the PCS signal for the next frame.
234  * Implements : LPSPI_DRV_MasterSetDelay_Activity
235  *
236  *END**************************************************************************/
237 status_t LPSPI_DRV_MasterSetDelay(uint32_t instance, uint32_t delayBetwenTransfers,
238  uint32_t delaySCKtoPCS, uint32_t delayPCStoSCK)
239 {
240  DEV_ASSERT(instance < LPSPI_INSTANCE_COUNT);
241  /* Instantiate local variable of type lpspi_state_t and point to global state */
242  const lpspi_state_t * lpspiState = g_lpspiStatePtr[instance];
243  LPSPI_Type *base = g_lpspiBase[instance];
244  status_t errorCode = STATUS_SUCCESS;
245  uint32_t realDelayBetwenTransfers, realDelaySCKtoPCS, realDelayPCStoSCK;
246  lpspi_prescaler_t prescaler;
247  /* Disable module */
248  errorCode = LPSPI_Disable(base);
249  if (errorCode != STATUS_SUCCESS)
250  {
251  return errorCode;
252  }
253  prescaler = LPSPI_GetClockPrescaler(base);
254  realDelayBetwenTransfers = delayBetwenTransfers * lpspiState->lpspiSrcClk / s_baudratePrescaler[prescaler] / (uint32_t)MICROSECONDS;
255  realDelaySCKtoPCS = delaySCKtoPCS * lpspiState->lpspiSrcClk / s_baudratePrescaler[prescaler] / (uint32_t)MICROSECONDS;
256  realDelayPCStoSCK = delayPCStoSCK * lpspiState->lpspiSrcClk/ s_baudratePrescaler[prescaler] / (uint32_t)MICROSECONDS;
257  /* Verify if current prescaler can be used for this configuration of delays
258  * If a delay is out of range, it will be adjusted to min or max value */
259  if (realDelayBetwenTransfers > (uint32_t)257U)
260  {
261  realDelayBetwenTransfers = (uint32_t)257U;
262  }
263  if(realDelaySCKtoPCS > (uint32_t)256U)
264  {
265  realDelaySCKtoPCS = (uint32_t)256U;
266  }
267  if(realDelayPCStoSCK > (uint32_t)256U)
268  {
269  realDelayPCStoSCK = (uint32_t)256U;
270  }
271  if (realDelayBetwenTransfers < (uint32_t)2U)
272  {
273  realDelayBetwenTransfers = (uint32_t)2U;
274  }
275  if(realDelaySCKtoPCS == (uint32_t)0)
276  {
277  realDelaySCKtoPCS = (uint32_t)1U;
278  }
279  if(realDelayPCStoSCK == (uint32_t)0U)
280  {
281  realDelayPCStoSCK = (uint32_t)1U;
282  }
283 
284  (void)LPSPI_SetDelay(base, LPSPI_SCK_TO_PCS, realDelaySCKtoPCS-1U);
285  (void)LPSPI_SetDelay(base, LPSPI_PCS_TO_SCK, realDelayPCStoSCK-1U);
286  (void)LPSPI_SetDelay(base, LPSPI_BETWEEN_TRANSFER, realDelayBetwenTransfers-2U);
287  /* Enable module */
288  LPSPI_Enable(base);
289  return errorCode;
290 }
291 
292 /*FUNCTION**********************************************************************
293  *
294  * Function Name : LPSPI_DRV_MasterConfigureBus
295  * Description : Configures the LPSPI port physical parameters to access a device on the bus when
296  * the LSPI instance is configured for interrupt operation.
297  *
298  * In this function, the term "spiConfig" is used to indicate the SPI device for which the LPSPI
299  * master is communicating. This is an optional function as the spiConfig parameters are
300  * normally configured in the initialization function or the transfer functions, where these various
301  * functions would call the configure bus function.
302  * The user can pass in a different spiConfig structure to the transfer function which contains
303  * the parameters for the SPI bus to allow for communication to a different SPI device
304  * (the transfer function then calls this function). However, the user also has the option to call
305  * this function directly especially to get the calculated baud rate, at which point they may pass
306  * in NULL for the spiConfig structure in the transfer function (assuming they have called this
307  * configure bus function first).
308  * Implements : LPSPI_DRV_MasterConfigureBus_Activity
309  *
310  *END**************************************************************************/
312  const lpspi_master_config_t * spiConfig,
313  uint32_t * calculatedBaudRate)
314 {
315  DEV_ASSERT(instance < LPSPI_INSTANCE_COUNT);
316  DEV_ASSERT(spiConfig != NULL);
317  /* Instantiate local variable of type lpspi_state_t and point to global state */
318  lpspi_state_t * lpspiState = g_lpspiStatePtr[instance];
319  LPSPI_Type *base = g_lpspiBase[instance];
320  uint32_t baudRate;
321 
322  /* The Transmit Command Register (TCR) Prescale value is calculated as part of the baud rate
323  calculation. The value is stored in the run-time state structure for later programming
324  in the TCR. */
325  uint32_t tcrPrescaleValue;
326 
327  /* Check the bitcount to make sure it falls within the boundary conditions */
328  if ((spiConfig->bitcount < 8U) || (spiConfig->bitcount > 4096U))
329  {
330  return STATUS_ERROR;
331  }
332  /* First, per the spec, we need to disable the LPSPI module before setting the delay */
333 
334  if (LPSPI_Disable(base) != STATUS_SUCCESS)
335  {
336  /* If error is returned, the LPSPI is busy */
337  return STATUS_ERROR;
338  }
339  /* Configure internal state structure for LPSPI */
340  lpspiState->bitsPerFrame = spiConfig->bitcount;
341  lpspiState->lpspiSrcClk = spiConfig->lpspiSrcClk;
342  lpspiState->isPcsContinuous = spiConfig->isPcsContinuous;
343  lpspiState->lsb = spiConfig->lsbFirst;
344  /* Save transfer type DMA/Interrupt */
345  lpspiState->transferType = spiConfig->transferType;
346  /* Update transfer status */
347  lpspiState->isTransferInProgress = false;
348  lpspiState->isBlocking = false;
349  /* Calculate the bytes/frame for lpspiState->bytesPerFrame. */
350  lpspiState->bytesPerFrame = (uint16_t)((lpspiState->bitsPerFrame + 7U) / 8U);
351  /* For DMA transfers bytes per frame must be equal to 1, 2 or multiple of 4 */
352  if ((lpspiState->transferType == LPSPI_USING_DMA) && (!(((lpspiState->bytesPerFrame % 4U) == (uint16_t)0) ||
353  (lpspiState->bytesPerFrame<=2U))))
354  {
355  return STATUS_ERROR;
356  }
357  /* Store DMA channel number used in transfer */
358  lpspiState->rxDMAChannel = spiConfig->rxDMAChannel;
359  lpspiState->txDMAChannel = spiConfig->txDMAChannel;
360  /* Store callback */
361  lpspiState->callback = spiConfig->callback;
362  lpspiState->callbackParam = spiConfig->callbackParam;
363  /* Configure the desired PCS polarity */
364  (void)LPSPI_SetPcsPolarityMode(base, spiConfig->whichPcs, spiConfig->pcsPolarity);
365  /* Set up the baud rate */
366  baudRate = LPSPI_SetBaudRate(base, spiConfig->bitsPerSec, spiConfig->lpspiSrcClk,
367  &tcrPrescaleValue);
368  /* Now, re-enable the LPSPI module */
369  LPSPI_Enable(base);
370  /* If the baud rate return is "0", it means there was an error */
371  if (baudRate == (uint32_t)0)
372  {
373  return STATUS_ERROR;
374  }
375  /* If the user wishes to know the calculated baud rate, then pass it back */
376  if (calculatedBaudRate != NULL)
377  {
378  *calculatedBaudRate = baudRate;
379  }
380  /* Write the TCR for this transfer. */
381  lpspi_tx_cmd_config_t txCmdCfg =
382  {
383  .frameSize = lpspiState->bitsPerFrame,
384  .width = LPSPI_SINGLE_BIT_XFER,
385  .txMask = false,
386  .rxMask = false,
387  .contCmd = false,
388  .contTransfer = spiConfig->isPcsContinuous,
389  .byteSwap = false,
390  .lsbFirst = spiConfig->lsbFirst,
391  .whichPcs = spiConfig->whichPcs,
392  .preDiv = tcrPrescaleValue,
393  .clkPhase = spiConfig->clkPhase,
394  .clkPolarity = spiConfig->clkPolarity
395  };
396  LPSPI_SetTxCommandReg(base, &txCmdCfg);
397  return STATUS_SUCCESS;
398 }
399 
400 /*FUNCTION**********************************************************************
401  *
402  * Function Name : LPSPI_DRV_MasterTransferBlocking
403  * Description : Performs an interrupt driven blocking SPI master mode transfer.
404  *
405  * This function simultaneously sends and receives data on the SPI bus, as SPI is naturally
406  * a full-duplex bus. The function does not return until the transfer is complete.
407  * This function allows the user to optionally pass in a SPI configuration structure which
408  * allows the user to change the SPI bus attributes in conjunction with initiating a SPI transfer.
409  * The difference between passing in the SPI configuration structure here as opposed to the
410  * configure bus function is that the configure bus function returns the calculated baud rate where
411  * this function does not. The user can also call the configure bus function prior to the transfer
412  * in which case the user would simply pass in a NULL to the transfer function's device structure
413  * parameter.
414  * Implements : LPSPI_DRV_MasterTransferBlocking_Activity
415  *
416  *END**************************************************************************/
418  const uint8_t * sendBuffer,
419  uint8_t * receiveBuffer,
420  uint16_t transferByteCount,
421  uint32_t timeout)
422 {
423  DEV_ASSERT(instance < LPSPI_INSTANCE_COUNT);
424  /* Instantiate local variable of type lpspi_state_t and point to global state */
425  lpspi_state_t * lpspiState = g_lpspiStatePtr[instance];
426  LPSPI_Type *base = g_lpspiBase[instance];
427  status_t error = STATUS_SUCCESS;
428  status_t osifError;
429  /* If the transfer count is zero, then return immediately.*/
430  if (transferByteCount == (uint16_t)0)
431  {
432  return error;
433  }
434  lpspiState->isBlocking = true;
435  /* start the transfer process, if it returns an error code, return this back to user */
436  error = LPSPI_DRV_MasterStartTransfer(instance, sendBuffer, receiveBuffer,
437  transferByteCount);
438  if (error != STATUS_SUCCESS)
439  {
440  /* The transfer is complete.*/
441  lpspiState->isTransferInProgress = false;
442  /* Disable interrupt requests*/
443  /*LPSPI_CLR_IER(base, LPSPI_IER_TDIE_MASK|LPSPI_IER_RDIE_MASK);*/
444  LPSPI_SetIntMode(base, LPSPI_TX_DATA_FLAG, false);
445  LPSPI_SetIntMode(base, LPSPI_RX_DATA_FLAG, false);
446 
448  LPSPI_SetIntMode(base, LPSPI_TRANSFER_COMPLETE, false);
449  (void)LPSPI_ClearStatusFlag(base, LPSPI_TRANSFER_COMPLETE);
450 
451  return error;
452  }
453 
454  /* As this is a synchronous transfer, wait until the transfer is complete.*/
455  osifError = OSIF_SemaWait(&(lpspiState->lpspiSemaphore), timeout);
456 
457  /* If a timeout occurs, stop the transfer by setting the isTransferInProgress to false and
458  * disabling interrupts, then return the timeout error status.
459  */
460  if (osifError == STATUS_TIMEOUT)
461  {
462  /* Set isBlocking variable to false to avoid dummy semaphore post. */
463  lpspiState->isBlocking = false;
464  /* Complete transfer. */
466  return(STATUS_TIMEOUT);
467  }
468 
470  LPSPI_SetIntMode(base, LPSPI_TRANSFER_COMPLETE, false);
471  (void)LPSPI_ClearStatusFlag(base, LPSPI_TRANSFER_COMPLETE);
472 
473  return error;
474 }
475 
476 /*FUNCTION**********************************************************************
477  *
478  * Function Name : LPSPI_DRV_MasterTransfer
479  * Description : Performs an interrupt driven non-blocking SPI master mode transfer.
480  *
481  * This function simultaneously sends and receives data on the SPI bus, as SPI is naturally
482  * a full-duplex bus. The function returns immediately after initiating the transfer. The user
483  * needs to check whether the transfer is complete using the LPSPI_DRV_MasterGetTransferStatus
484  * function.
485  * This function allows the user to optionally pass in a SPI configuration structure which
486  * allows the user to change the SPI bus attributes in conjunction with initiating a SPI transfer.
487  * The difference between passing in the SPI configuration structure here as opposed to the
488  * configure bus function is that the configure bus function returns the calculated baud rate where
489  * this function does not. The user can also call the configure bus function prior to the transfer
490  * in which case the user would simply pass in a NULL to the transfer function's device structure
491  * parameter.
492  * Implements : LPSPI_DRV_MasterTransfer_Activity
493  *
494  *END**************************************************************************/
496  const uint8_t * sendBuffer,
497  uint8_t * receiveBuffer,
498  uint16_t transferByteCount)
499 {
500  DEV_ASSERT(instance < LPSPI_INSTANCE_COUNT);
501  status_t error = STATUS_SUCCESS;
502  /* If the transfer count is zero, then return immediately.*/
503  if (transferByteCount == (uint16_t)0)
504  {
505  return STATUS_SUCCESS;
506  }
507 
508  /* Start the transfer process, if it returns an error code, return this back to user */
509  error = LPSPI_DRV_MasterStartTransfer(instance, sendBuffer, receiveBuffer,
510  transferByteCount);
511  if (error != STATUS_SUCCESS)
512  {
513  return error;
514  }
515 
516  /* Else, return immediately as this is an async transfer */
517  return STATUS_SUCCESS;
518 }
519 
520 /*FUNCTION**********************************************************************
521  *
522  * Function Name : LPSPI_DRV_MasterGetTransferStatus
523  * Description : Returns whether the previous interrupt driven transfer is completed.
524  *
525  * When performing an a-sync (non-blocking) transfer, the user can call this function to ascertain
526  * the state of the current transfer: in progress (or busy) or complete (success).
527  * In addition, if the transfer is still in progress, the user can get the number of words that
528  * should be receive.
529  * Implements : LPSPI_DRV_MasterGetTransferStatus_Activity
530  *
531  *END**************************************************************************/
532 status_t LPSPI_DRV_MasterGetTransferStatus(uint32_t instance, uint32_t * bytesRemained)
533 {
534  DEV_ASSERT(instance < LPSPI_INSTANCE_COUNT);
535  /* Instantiate local variable of type lpspi_state_t and point to global state */
536  const lpspi_state_t * lpspiState = g_lpspiStatePtr[instance];
537  /* Fill in the bytes transferred.*/
538  if (bytesRemained != NULL)
539  {
540  *bytesRemained = lpspiState->rxCount;
541  }
542  if (lpspiState->status == LPSPI_TRANSFER_OK)
543  {
544  return (status_t)(lpspiState->isTransferInProgress ? STATUS_BUSY : STATUS_SUCCESS);
545  }
546  else
547  {
548  return STATUS_ERROR;
549  }
550 }
551 /*FUNCTION**********************************************************************
552  *
553  * Function Name : LPSPI_DRV_MasterAbortTransfer
554  * Description : Terminates an interrupt driven asynchronous transfer early.
555  *
556  * During an a-sync (non-blocking) transfer, the user has the option to terminate the transfer early
557  * if the transfer is still in progress.
558  * Implements : LPSPI_DRV_MasterAbortTransfer_Activity
559  *END**************************************************************************/
561 {
562  DEV_ASSERT(instance < LPSPI_INSTANCE_COUNT);
563  LPSPI_Type *base = g_lpspiBase[instance];
564  /* Stop the running transfer. */
566  LPSPI_SetFlushFifoCmd(base, true, true);
567  /* The second flush command is used to avoid the case when one word is still in shifter. */
568  LPSPI_SetFlushFifoCmd(base, true, true);
569  return STATUS_SUCCESS;
570 }
571 
572 /*FUNCTION**********************************************************************
573  *
574  * Function Name : LPSPI_DRV_MasterStartTransfer
575  * Description : Configure a non-blocking transfer.
576  *
577  * The number of transferByteCount must be divided by number of bytes/frame.
578  * The sendBuffer must be not NULL, but receiveBuffer can be NULL.
579  *
580  *END**************************************************************************/
581 static status_t LPSPI_DRV_MasterStartTransfer(uint32_t instance,
582  const uint8_t * sendBuffer,
583  uint8_t * receiveBuffer,
584  uint16_t transferByteCount)
585 {
586  DEV_ASSERT(instance < LPSPI_INSTANCE_COUNT);
587  DEV_ASSERT(sendBuffer != NULL);
588  /* Instantiate local variable of type dspi_master_state_t and point to global state */
589  lpspi_state_t * lpspiState = g_lpspiStatePtr[instance];
590  LPSPI_Type *base = g_lpspiBase[instance];
592 
593  /* Check that we're not busy. */
594  if (LPSPI_GetStatusFlag(base, LPSPI_MODULE_BUSY))
595  {
596  return STATUS_BUSY;
597  }
598  #ifdef ERRATA_E10655
599  else
600  {
601  /* Double check to fix errata e10655. */
602  if (LPSPI_GetStatusFlag(base, LPSPI_MODULE_BUSY))
603  {
604  return STATUS_BUSY;
605  }
606  }
607  #endif
608 
609  /* Verify if the number of bytes is divided by number of bytes/frame. */
610  if ((transferByteCount % lpspiState->bytesPerFrame) != (uint16_t)0)
611  {
612  return STATUS_ERROR;
613  }
614  if(lpspiState->isPcsContinuous == true)
615  {
616  LPSPI_SetContCBit(base);
617  }
618 
619  /* Configure watermarks */
620  LPSPI_SetRxWatermarks(base, 0U);
621  LPSPI_SetTxWatermarks(base, 2U);
622 
623  lpspiState->status = LPSPI_TRANSFER_OK;
624  /* Clear all interrupts sources */
625  (void)LPSPI_ClearStatusFlag(base, LPSPI_ALL_STATUS);
626  /* Enable fault interrupts sources */
627  LPSPI_SetIntMode(base,LPSPI_TRANSMIT_ERROR , true);
628  LPSPI_SetIntMode(base,LPSPI_RECEIVE_ERROR , true);
629 
630  if (lpspiState->transferType == LPSPI_USING_INTERRUPTS)
631  {
632  /* Fill out the other members of the run-time state structure. */
633  lpspiState->txBuff = (const uint8_t *)sendBuffer;
634  lpspiState->rxBuff = (uint8_t *)receiveBuffer;
635  lpspiState->txFrameCnt = 0;
636  lpspiState->rxFrameCnt = 0;
637  lpspiState->txCount = transferByteCount;
638  /*For continuous mode an extra word must be written to negate the PCS */
639  if (lpspiState->isPcsContinuous == true)
640  {
641  lpspiState->txCount++;
642  }
643  /* Clean RX and TX buffers */
644  LPSPI_SetFlushFifoCmd(base, true, true);
645  /* The second flush command is used to avoid the case when one word is still in shifter. */
646  LPSPI_SetFlushFifoCmd(base, true, true);
647  /* Update transfer status */
648  lpspiState->isTransferInProgress = true;
649  /* Mask the RX if no buffer is passed in. */
650  if (lpspiState->rxBuff == NULL)
651  {
652  /* Since we're not receiving, set rxCount to 0. */
653  lpspiState->rxCount = 0;
654  }
655  else
656  {
657  /* Enable RDF interrupt if RX buffer is not NULL. */
658  LPSPI_SetIntMode(base, LPSPI_RX_DATA_FLAG, true);
659  lpspiState->rxCount = transferByteCount;
660  }
661  /* Enable the TDF and RDF interrupt. */
662  LPSPI_SetIntMode(base, LPSPI_TX_DATA_FLAG, true);
663  }
664  else
665  {
666  /* Configure rxCount depending on transfer type.*/
667  if (receiveBuffer == NULL)
668  {
669  lpspiState->rxCount = 0;
670  }
671  else
672  {
673  lpspiState->rxCount = transferByteCount;
674  }
675 
676  /* When LPSPI use DMA frames with 3 bytes size are not accepted. */
677  switch(lpspiState->bytesPerFrame)
678  {
679  case 1: dmaTransferSize = EDMA_TRANSFER_SIZE_1B; break;
680  case 2: dmaTransferSize = EDMA_TRANSFER_SIZE_2B; break;
681  case 4: dmaTransferSize = EDMA_TRANSFER_SIZE_4B; break;
682  default : dmaTransferSize = EDMA_TRANSFER_SIZE_1B; break;
683  }
684  /* Configure TX DMA channel */
686  (uint32_t)sendBuffer, (uint32_t)(&(base->TDR)), dmaTransferSize, (uint32_t)1U<<(uint8_t)(dmaTransferSize),
687  (uint32_t)transferByteCount/(uint32_t)((uint32_t)1U <<(uint8_t)(dmaTransferSize)), true);
688 
689  /* Start TX channel */
690  (void)EDMA_DRV_StartChannel(lpspiState->txDMAChannel);
691  /* Configure RX DMA channel if is used in current transfer. */
692  if(receiveBuffer != NULL)
693  {
695  (uint32_t)(&(base->RDR)),(uint32_t)receiveBuffer, dmaTransferSize, (uint32_t)1U<<(uint8_t)(dmaTransferSize),
696  (uint32_t)transferByteCount/(uint32_t)((uint32_t)1U <<(uint8_t)(dmaTransferSize)), true);
697 
698  (void)EDMA_DRV_InstallCallback(lpspiState->rxDMAChannel, (LPSPI_DRV_MasterCompleteDMATransfer),(void*)(instance));
699  if (lpspiState->isPcsContinuous == true)
700  {
701  (void)EDMA_DRV_InstallCallback(lpspiState->txDMAChannel, (LPSPI_DRV_MasterClearCountinuous),(void*)(instance));
702  }
703  /* Start RX channel */
704  (void)EDMA_DRV_StartChannel(lpspiState->rxDMAChannel);
705  }
706  else
707  {
708  /* If RX buffer is null the transfer is done when all bytes were sent. */
709  (void)EDMA_DRV_InstallCallback(lpspiState->txDMAChannel, (LPSPI_DRV_MasterCompleteDMATransfer),(void*)(instance));
710  }
711  /* Update transfer status */
712  lpspiState->isTransferInProgress = true;
713  /* Enable LPSPI DMA request */
714  if (receiveBuffer!=NULL)
715  {
716  LPSPI_SetRxDmaCmd(base, true);
717  }
718  LPSPI_SetTxDmaCmd(base, true);
719  }
720  return STATUS_SUCCESS;
721 }
722 
728 static void LPSPI_DRV_MasterCompleteTransfer(uint32_t instance)
729 {
730  /* instantiate local variable of type dspi_master_state_t and point to global state */
731  lpspi_state_t * lpspiState = g_lpspiStatePtr[instance];
732  LPSPI_Type *base = g_lpspiBase[instance];
733  /* The transfer is complete.*/
734  lpspiState->isTransferInProgress = false;
735  if(lpspiState->transferType == LPSPI_USING_DMA)
736  {
737  /* Disable LPSPI DMA request */
738  LPSPI_SetRxDmaCmd(base, false);
739  LPSPI_SetTxDmaCmd(base, false);
740  }
741  else
742  {
743  /* Disable (clear) interrupt requests */
744  LPSPI_SetIntMode(base, LPSPI_RX_DATA_FLAG, false);
745  LPSPI_SetIntMode(base, LPSPI_TX_DATA_FLAG, false);
746  }
747 
749  LPSPI_SetIntMode(base, LPSPI_TRANSFER_COMPLETE, false);
750  (void)LPSPI_ClearStatusFlag(base, LPSPI_TRANSFER_COMPLETE);
751  if (lpspiState->isBlocking == true)
752  {
753  (void)OSIF_SemaPost(&(lpspiState->lpspiSemaphore));
754  lpspiState->isBlocking = false;
755  }
756  if (lpspiState->callback != NULL)
757  {
758  lpspiState->callback(lpspiState, SPI_EVENT_END_TRANSFER, lpspiState->callbackParam);
759  }
760 
761 }
762 
767 static void LPSPI_DRV_MasterCompleteDMATransfer(void* parameter, edma_chn_status_t status)
768 {
769  uint32_t instance = (uint32_t)parameter;
770 
771  (void)status;
772  /* Disable continuous PCS */
774 }
775 
780 static void LPSPI_DRV_MasterClearCountinuous(void* parameter, edma_chn_status_t status)
781 {
782  uint32_t instance = (uint32_t)parameter;
783  LPSPI_Type *base = g_lpspiBase[instance];
784 
785  (void)status;
786  /* Disable continuous PCS */
787  LPSPI_ClearContCBit(base);
788 }
789 
795 void LPSPI_DRV_MasterIRQHandler(uint32_t instance)
796 {
797  /* Instantiate local variable of type dspi_master_state_t and point to global state */
798  lpspi_state_t * lpspiState = g_lpspiStatePtr[instance];
799  LPSPI_Type *base = g_lpspiBase[instance];
800  uint16_t txCount, rxCount;
801  txCount = lpspiState->txCount;
802  rxCount = lpspiState->rxCount;
803 
804  /* If an error is detected the transfer will be aborted */
805  if ((bool)LPSPI_GetStatusFlag(base, LPSPI_TRANSMIT_ERROR))
806  {
807  lpspiState->status = LPSPI_TRANSMIT_FAIL;
808  (void)LPSPI_DRV_MasterAbortTransfer(instance);
809  (void)LPSPI_ClearStatusFlag(base, LPSPI_TRANSMIT_ERROR);
810  return;
811  }
812  if (LPSPI_GetStatusFlag(base, LPSPI_RECEIVE_ERROR))
813  {
814  lpspiState->status = LPSPI_RECEIVE_FAIL;
815  (void)LPSPI_DRV_MasterAbortTransfer(instance);
816  (void)LPSPI_ClearStatusFlag(base, LPSPI_RECEIVE_ERROR);
817  return;
818  }
819 
820  /* RECEIVE IRQ handler: Check read buffer only if there are remaining bytes to read. */
821  if(LPSPI_GetStatusFlag(base,LPSPI_RX_DATA_FLAG) && (rxCount != (uint16_t)0))
822  {
823  LPSPI_DRV_ReadRXBuffer(instance);
824  }
825  /* Transmit data */
826  if (LPSPI_GetStatusFlag(base,LPSPI_TX_DATA_FLAG) && ((txCount != (uint16_t)0)))
827  {
828  LPSPI_DRV_FillupTxBuffer(instance);
829  }
830  txCount = lpspiState->txCount;
831  rxCount = lpspiState->rxCount;
832  if (txCount == (uint16_t)0)
833  {
834  /* Disable TX flag. Software buffer is empty.*/
835  LPSPI_SetIntMode(base, LPSPI_TX_DATA_FLAG, false);
836  LPSPI_SetIntMode(base, LPSPI_TRANSFER_COMPLETE, true);
837  /* Check if we're done with this transfer.*/
838  if (rxCount == (uint16_t)0)
839  {
840  if (LPSPI_GetStatusFlag(base, LPSPI_TRANSFER_COMPLETE) == true)
841  {
843  }
844  }
845  }
846 }
847 
848 
849 /*******************************************************************************
850  * EOF
851  ******************************************************************************/
volatile uint16_t rxFrameCnt
#define LPSPI_INSTANCE_COUNT
Definition: S32K142.h:6130
volatile uint16_t txFrameCnt
Runtime state structure for the LPSPI master driver.
Data structure containing information about a device on the SPI bus.
void LPSPI_DRV_ReadRXBuffer(uint32_t instance)
The function LPSPI_DRV_ReadRXBuffer reads data from RX hardware buffer and writes this data in RX sof...
status_t OSIF_SemaDestroy(const semaphore_t *const pSem)
Destroys a previously created semaphore.
lpspi_signal_polarity_t pcsPolarity
status_t LPSPI_DRV_MasterDeinit(uint32_t instance)
Shuts down a LPSPI instance.
lpspi_transfer_type transferType
lpspi_transfer_type transferType
lpspi_state_t * g_lpspiStatePtr[LPSPI_INSTANCE_COUNT]
spi_callback_t callback
static void LPSPI_DRV_MasterCompleteTransfer(uint32_t instance)
Finish up a transfer. Cleans up after a transfer is complete. Interrupts are disabled, and the LPSPI module is disabled. This is not a public API as it is called from other driver functions.
status_t LPSPI_DRV_MasterConfigureBus(uint32_t instance, const lpspi_master_config_t *spiConfig, uint32_t *calculatedBaudRate)
Configures the LPSPI port physical parameters to access a device on the bus when the LSPI instance is...
status_t LPSPI_DRV_MasterInit(uint32_t instance, lpspi_state_t *lpspiState, const lpspi_master_config_t *spiConfig)
Initializes a LPSPI instance for interrupt driven master mode operation.
status_t LPSPI_DRV_MasterTransfer(uint32_t instance, const uint8_t *sendBuffer, uint8_t *receiveBuffer, uint16_t transferByteCount)
Performs an interrupt driven non-blocking SPI master mode transfer.
status_t OSIF_SemaCreate(semaphore_t *const pSem, const uint8_t initValue)
Creates a semaphore with a given value.
status_t LPSPI_DRV_MasterGetTransferStatus(uint32_t instance, uint32_t *bytesRemained)
Returns whether the previous interrupt driven transfer is completed.
void LPSPI_DRV_FillupTxBuffer(uint32_t instance)
The function LPSPI_DRV_FillupTxBuffer writes data in TX hardware buffer depending on driver state and...
void INT_SYS_DisableIRQ(IRQn_Type irqNumber)
Disables an interrupt for a given IRQ number.
#define DEV_ASSERT(x)
Definition: devassert.h:77
volatile uint16_t rxCount
void LPSPI_DRV_MasterIRQHandler(uint32_t instance)
Interrupt handler for LPSPI master mode. This handler uses the buffers stored in the lpspi_state_t st...
edma_chn_status_t
Channel status for eDMA channel.
Definition: edma_driver.h:193
edma_transfer_size_t
eDMA transfer configuration Implements : edma_transfer_size_t_Class
Definition: edma_driver.h:160
lpspi_clock_phase_t clkPhase
volatile uint16_t txCount
status_t LPSPI_DRV_MasterTransferBlocking(uint32_t instance, const uint8_t *sendBuffer, uint8_t *receiveBuffer, uint16_t transferByteCount, uint32_t timeout)
Performs an interrupt driven blocking SPI master mode transfer.
status_t LPSPI_DRV_MasterSetDelay(uint32_t instance, uint32_t delayBetwenTransfers, uint32_t delaySCKtoPCS, uint32_t delayPCStoSCK)
Configures the LPSPI master mode bus timing delay options.
status_t
Status return codes. Common error codes will be a unified enumeration (C enum) that will contain all ...
Definition: status.h:44
IRQn_Type g_lpspiIrqId[LPSPI_INSTANCE_COUNT]
Table to save LPSPI IRQ enumeration numbers defined in the CMSIS header file.
void LPSPI_DRV_DisableTEIEInterrupts(uint32_t instance)
Disable the TEIE interrupts at the end of a transfer. Disable the interrupts and clear the status for...
static status_t LPSPI_DRV_MasterStartTransfer(uint32_t instance, const uint8_t *sendBuffer, uint8_t *receiveBuffer, uint16_t transferByteCount)
status_t OSIF_SemaWait(semaphore_t *const pSem, const uint32_t timeout)
Decrement a semaphore with timeout.
status_t EDMA_DRV_StartChannel(uint8_t channel)
Starts an eDMA channel.
Definition: edma_driver.c:813
lpspi_which_pcs_t whichPcs
static void LPSPI_DRV_MasterCompleteDMATransfer(void *parameter, edma_chn_status_t status)
Finish up a transfer DMA. The main purpose of this function is to create a function compatible with D...
volatile bool isTransferInProgress
status_t OSIF_SemaPost(semaphore_t *const pSem)
Increment a semaphore.
void INT_SYS_EnableIRQ(IRQn_Type irqNumber)
Enables an interrupt for a given IRQ number.
__O uint32_t TDR
Definition: S32K142.h:6123
status_t LPSPI_DRV_MasterAbortTransfer(uint32_t instance)
Terminates an interrupt driven asynchronous transfer early.
lpspi_sck_polarity_t clkPolarity
LPSPI_Type * g_lpspiBase[LPSPI_INSTANCE_COUNT]
Table of base pointers for SPI instances.
#define MICROSECONDS
const uint8_t * txBuff
__I uint32_t RDR
Definition: S32K142.h:6126
status_t EDMA_DRV_ConfigMultiBlockTransfer(uint8_t channel, edma_transfer_type_t type, uint32_t srcAddr, uint32_t destAddr, edma_transfer_size_t transferSize, uint32_t blockSize, uint32_t blockCount, bool disableReqOnCompletion)
Configures a multiple block data transfer with DMA.
Definition: edma_driver.c:589
status_t EDMA_DRV_InstallCallback(uint8_t channel, edma_callback_t callback, void *parameter)
Registers the callback function and the parameter for eDMA channel.
Definition: edma_driver.c:293
semaphore_t lpspiSemaphore
static void LPSPI_DRV_MasterClearCountinuous(void *parameter, edma_chn_status_t status)
Clear the continuous mode. The main purpose of this function is to clear continuous mode...
transfer_status_t status