S32 SDK
lpspi_slave_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 
82 #include <string.h>
83 #include "lpspi_slave_driver.h"
84 #include "clock_manager.h"
85 #include "interrupt_manager.h"
86 #include "lpspi_hw_access.h"
87 #include "device_registers.h"
88 
89 
90 /*******************************************************************************
91  * Definitions
92  ******************************************************************************/
93 
94 /* Callback for DMA transfer done.*/
95 static void LPSPI_DRV_SlaveCompleteDMATransfer(void* parameter, edma_chn_status_t status);
96 
97 /*******************************************************************************
98  * Code
99  ******************************************************************************/
100  /*
101  * Implements : LPSPI_DRV_SlaveInit_Activity
102  */
103 status_t LPSPI_DRV_SlaveInit(uint32_t instance,
104  lpspi_state_t * lpspiState,
105  const lpspi_slave_config_t * slaveConfig)
106 {
107  DEV_ASSERT(lpspiState != NULL);
108  DEV_ASSERT(slaveConfig != NULL);
109  DEV_ASSERT(instance < LPSPI_INSTANCE_COUNT);
110  LPSPI_Type * base = g_lpspiBase[instance];
111  status_t errorCode = STATUS_SUCCESS;
112 
113  lpspiState->lsb = slaveConfig->lsbFirst;
114  lpspiState->bitsPerFrame = slaveConfig->bitcount;
115  lpspiState->transferType = slaveConfig->transferType;
116  lpspiState->isBlocking = false;
117  /* Store DMA channels numbers used for DMA transfer */
118  lpspiState->rxDMAChannel = slaveConfig->rxDMAChannel;
119  lpspiState->txDMAChannel = slaveConfig->txDMAChannel;
120  /* Store callback */
121  lpspiState->callback = slaveConfig->callback;
122  lpspiState->callbackParam = slaveConfig->callbackParam;
123  /* Calculate the bytes/frame for lpspiState->bytesPerFrame. */
124  lpspiState->bytesPerFrame = (uint16_t)((lpspiState->bitsPerFrame + 7U) / 8U);
125  /* For DMA transfers bytes per frame must be equal to 1, 2 or multiple of 4. */
126  if ((lpspiState->transferType == LPSPI_USING_DMA) && (!(((lpspiState->bytesPerFrame % 4U) == 0U) ||
127  (lpspiState->bytesPerFrame <= 2U))))
128  {
129  return STATUS_ERROR;
130  }
131  lpspiState->isTransferInProgress = false;
132  /* Initialize the semaphore */
133  errorCode = OSIF_SemaCreate(&(lpspiState->lpspiSemaphore), 0);
134  DEV_ASSERT(errorCode == STATUS_SUCCESS);
135  g_lpspiStatePtr[instance] = lpspiState;
136 
137  /* Configure registers */
138  LPSPI_Init(base);
139 
140  /* Configure lpspi to slave mode */
141  (void)LPSPI_SetMasterSlaveMode(base, LPSPI_SLAVE);
142  /* Set Pin settings */
143  (void)LPSPI_SetPinConfigMode(base, LPSPI_SDI_IN_SDO_OUT, LPSPI_DATA_OUT_RETAINED, true);
144  /* Calculate the FIFO size for the LPSPI */
145  LPSPI_GetFifoSizes(base, &(lpspiState->fifoSize), NULL);
146 
147  /* Set polarity */
148  (void)LPSPI_SetPcsPolarityMode(base, slaveConfig->whichPcs, slaveConfig->pcsPolarity);
149 
150  /* Write the TCR for this transfer */
151  lpspi_tx_cmd_config_t txCmdCfg = {
152  .frameSize = lpspiState->bitsPerFrame,
153  .width = LPSPI_SINGLE_BIT_XFER,
154  .txMask = false,
155  .rxMask = false,
156  .byteSwap = false,
157  .lsbFirst = slaveConfig->lsbFirst,
158  .clkPhase = slaveConfig->clkPhase,
159  .clkPolarity = slaveConfig->clkPolarity,
160  .whichPcs = slaveConfig->whichPcs
161  };
162 
163  /* Write to the TX CMD register */
164  LPSPI_SetTxCommandReg(base, &txCmdCfg);
165  LPSPI_Enable(base);
166  /* Enable the interrupt source */
167  INT_SYS_EnableIRQ(g_lpspiIrqId[instance]);
168 
169  return errorCode;
170 }
171 
172  /*
173  * Implements : LPSPI_DRV_SlaveDeinit_Activity
174  */
175 status_t LPSPI_DRV_SlaveDeinit(uint32_t instance)
176 {
177  DEV_ASSERT(instance < LPSPI_INSTANCE_COUNT);
178  /* Instantiate local variable of type lpspi_master_state_t and point to global state */
179  const lpspi_state_t * lpspiState = (lpspi_state_t *)g_lpspiStatePtr[instance];
180  LPSPI_Type *base = g_lpspiBase[instance];
181  status_t errorCode = STATUS_SUCCESS;
182 
183  /* Check if a transfer is still in progress */
184  DEV_ASSERT(lpspiState->isTransferInProgress == false);
185  /* Destroy the semaphore */
186  errorCode = OSIF_SemaDestroy(&(lpspiState->lpspiSemaphore));
187  DEV_ASSERT(errorCode == STATUS_SUCCESS);
188  /* Reset the LPSPI registers to their default state, including disabling the LPSPI */
189  LPSPI_Init(base);
190 
191  /* Disable the interrupt*/
192  INT_SYS_DisableIRQ(g_lpspiIrqId[instance]);
193 
194  /* Clear the state pointer. */
195  g_lpspiStatePtr[instance] = NULL;
196 
197  return errorCode;
198 }
199 
200  /*
201  * Implements : LPSPI_DRV_SlaveTransferBlocking_Activity
202  */
204  const uint8_t *sendBuffer,
205  uint8_t *receiveBuffer,
206  uint16_t transferByteCount,
207  uint32_t timeout)
208 {
209  DEV_ASSERT(instance < LPSPI_INSTANCE_COUNT);
210  lpspi_state_t * state = (lpspi_state_t *)g_lpspiStatePtr[instance];
211  status_t error;
212  status_t osifError;
213  state->isBlocking = true;
214  error = LPSPI_DRV_SlaveTransfer(instance, sendBuffer, receiveBuffer, transferByteCount);
215  if(error != STATUS_SUCCESS)
216  {
218  return error;
219  }
220 
221  /* As this is a synchronous transfer, wait until the transfer is complete.*/
222  osifError = OSIF_SemaWait(&(state->lpspiSemaphore), timeout);
223 
224  if (osifError == STATUS_TIMEOUT)
225  {
226  /* Set isBlocking variable to false to avoid dummy semaphore post. */
227  state->isBlocking = false;
228  /* Complete transfer. */
229  (void)LPSPI_DRV_SlaveAbortTransfer(instance);
230  return(STATUS_TIMEOUT);
231  }
232 
234 
235  return STATUS_SUCCESS;
236 }
237 
238  /*
239  * Implements : LPSPI_DRV_SlaveTransfer_Activity
240  */
242  const uint8_t *sendBuffer,
243  uint8_t *receiveBuffer,
244  uint16_t transferByteCount)
245 {
246  DEV_ASSERT(instance < LPSPI_INSTANCE_COUNT);
247  DEV_ASSERT(!((sendBuffer == NULL) && (receiveBuffer == NULL)));
248  LPSPI_Type * base = g_lpspiBase[instance];
249  lpspi_state_t * state = (lpspi_state_t *)g_lpspiStatePtr[instance];
251  /* The number of transferred bytes should be divisible by frame size */
252  if ((uint16_t)(transferByteCount % state->bytesPerFrame) != (uint16_t)0)
253  {
254  return STATUS_ERROR;
255  }
256  /* Check if LPSPI module isn't busy */
257  if (state->isTransferInProgress == true)
258  {
259  return STATUS_BUSY;
260  }
261  /* Initialize the status of the current transfer */
262  state->status = LPSPI_TRANSFER_OK;
263  /* Clear all interrupts sources */
264  (void)LPSPI_ClearStatusFlag(base, LPSPI_ALL_STATUS);
265  /* Enable fault interrupts sources */
266  LPSPI_SetIntMode(base,LPSPI_TRANSMIT_ERROR , true);
267  LPSPI_SetIntMode(base,LPSPI_RECEIVE_ERROR , true);
268  if (state->transferType == LPSPI_USING_INTERRUPTS)
269  {
270  state->rxBuff = receiveBuffer;
271  state->txBuff = sendBuffer;
272  state->txCount = transferByteCount;
273  state->rxCount = transferByteCount;
274  state->txFrameCnt = 0;
275  state->rxFrameCnt = 0;
276  state->isPcsContinuous = false;
277  /* Configure watermarks */
278  LPSPI_SetRxWatermarks(base, 0U);
279  LPSPI_SetTxWatermarks(base, 2U);
280 
281  /* Clean RX and TX buffers */
282  LPSPI_SetFlushFifoCmd(base, true, true);
283  /* The second flush command is used to avoid the case when one word is still in shifter. */
284  LPSPI_SetFlushFifoCmd(base, true, true);
285  state->isTransferInProgress = true;
286  /* Enable interrupts for RX and TX only if it's necessary */
287  if(state->txBuff != NULL)
288  {
289  LPSPI_SetIntMode(base,LPSPI_TX_DATA_FLAG , true);
290  }
291  else
292  {
293  state->txCount = 0;
294  }
295  if(state->rxBuff != NULL)
296  {
297  LPSPI_SetIntMode(base, LPSPI_RX_DATA_FLAG, true);
298  }
299  else
300  {
301  state->rxCount = 0;
302  }
303  }
304  else
305  {
306  /* Configure watermarks */
307  LPSPI_SetRxWatermarks(base, 0U);
308  LPSPI_SetTxWatermarks(base, 3U);
309  /* When LPSPI use DMA frames with 3 bytes size are not accepted. */
310  switch(state->bytesPerFrame)
311  {
312  case 1: dmaTransferSize = EDMA_TRANSFER_SIZE_1B; break;
313  case 2: dmaTransferSize = EDMA_TRANSFER_SIZE_2B; break;
314  case 4: dmaTransferSize = EDMA_TRANSFER_SIZE_4B; break;
315  default: dmaTransferSize = EDMA_TRANSFER_SIZE_1B; break;
316  }
317  if(receiveBuffer != NULL)
318  {
320  (uint32_t)(&(base->RDR)),(uint32_t)receiveBuffer, dmaTransferSize, (uint32_t)1U<<(uint8_t)(dmaTransferSize),
321  (uint32_t)transferByteCount/(uint32_t)((uint32_t)1U <<(uint8_t)(dmaTransferSize)), true);
322 
323  state->rxCount = transferByteCount;
324  /* Start RX channel */
325  (void)EDMA_DRV_StartChannel(state->rxDMAChannel);
326  }
327  else
328  {
329  state->rxCount = 0;
330  }
331  if(sendBuffer != NULL)
332  {
334  (uint32_t)sendBuffer, (uint32_t)(&(base->TDR)), dmaTransferSize, (uint32_t)1U<<(uint8_t)(dmaTransferSize),
335  (uint32_t)transferByteCount/(uint32_t)((uint32_t)1U <<(uint8_t)(dmaTransferSize)), true);
336 
337  state->txCount = transferByteCount;
338  /* Start TX channel */
339  (void)EDMA_DRV_StartChannel(state->txDMAChannel);
340  }
341  else
342  {
343  state->txCount = 0;
344  }
345  /* Configure which channel will generate transfer complete */
346  /* If current transfer uses both buffers (RX and TX) RX transfer done will generate transfer complete
347  * interrupt. Otherwise transfer complete will be generate by available channel(RX or TX).
348  */
349  if(receiveBuffer != NULL)
350  {
352  }
353  else
354  {
356  }
357  state->isTransferInProgress = true;
358  /* Enable LPSPI DMA request */
359  if (receiveBuffer != NULL)
360  {
361  LPSPI_SetRxDmaCmd(base, true);
362  }
363  if (sendBuffer != NULL)
364  {
365  LPSPI_SetTxDmaCmd(base, true);
366  }
367  }
368  return STATUS_SUCCESS;
369 }
370 
371 void LPSPI_DRV_SlaveIRQHandler(uint32_t instance)
372 {
373  LPSPI_Type * base = g_lpspiBase[instance];
374  lpspi_state_t * lpspiState = (lpspi_state_t *)g_lpspiStatePtr[instance];
375  uint16_t txCount, rxCount;
376 
377  /* If an error is detected the transfer will be aborted */
378  if ((bool)LPSPI_GetStatusFlag(base, LPSPI_TRANSMIT_ERROR))
379  {
380  lpspiState->status = LPSPI_TRANSMIT_FAIL;
381  (void)LPSPI_DRV_SlaveAbortTransfer(instance);
382  return;
383  }
384  if (LPSPI_GetStatusFlag(base, LPSPI_RECEIVE_ERROR))
385  {
386  lpspiState->status = LPSPI_RECEIVE_FAIL;
387  (void)LPSPI_DRV_SlaveAbortTransfer(instance);
388  return;
389  }
390 
391  /* Receive data */
392  if(LPSPI_GetStatusFlag(base,LPSPI_RX_DATA_FLAG))
393  {
394  LPSPI_DRV_ReadRXBuffer(instance);
395  }
396  /* Transmit data */
397  txCount = lpspiState->txCount;
398  if (LPSPI_GetStatusFlag(base,LPSPI_TX_DATA_FLAG) && ((txCount != (uint8_t)0)))
399  {
400  LPSPI_DRV_FillupTxBuffer(instance);
401  }
402  txCount = lpspiState->txCount;
403  rxCount = lpspiState->rxCount;
404  /* If all bytes are sent disable interrupt TDF */
405  if (txCount == (uint8_t)0)
406  {
407  LPSPI_SetIntMode(base, LPSPI_TX_DATA_FLAG, false);
408  }
409  /* If all bytes are received disable interrupt RDF */
410  if (rxCount == (uint8_t)0)
411  {
412  LPSPI_SetIntMode(base, LPSPI_RX_DATA_FLAG, false);
413  }
414  if ((rxCount == (uint8_t)0) && (txCount == (uint8_t)0))
415  {
416  lpspiState->isTransferInProgress = false;
417  if(lpspiState->isBlocking == true)
418  {
419  (void)OSIF_SemaPost(&(lpspiState->lpspiSemaphore));
420  lpspiState->isBlocking = false;
421  }
422  if (lpspiState->callback != NULL)
423  {
424  lpspiState->callback(lpspiState, SPI_EVENT_END_TRANSFER, lpspiState->callbackParam);
425  }
426  }
427 }
428 
429  /*
430  * Implements : LPSPI_DRV_SlaveAbortTransfer_Activity
431  */
433 {
434  LPSPI_Type * base = g_lpspiBase[instance];
435  lpspi_state_t * state = (lpspi_state_t *)g_lpspiStatePtr[instance];
436 
437  if (state->transferType == LPSPI_USING_INTERRUPTS)
438  {
439  /* Disable interrupts */
440  LPSPI_SetIntMode(base, LPSPI_TX_DATA_FLAG, false);
441  LPSPI_SetIntMode(base, LPSPI_RX_DATA_FLAG, false);
442  }
443  else
444  {
445  /* Disable LPSPI DMA request */
446  LPSPI_SetRxDmaCmd(base, false);
447  LPSPI_SetTxDmaCmd(base, false);
448  }
449 
451 
452  state->isTransferInProgress = false;
453  /* Clean RX and TX buffers */
454  LPSPI_SetFlushFifoCmd(base, true, true);
455  /* The second flush command is used to avoid the case when one word is still in shifter. */
456  LPSPI_SetFlushFifoCmd(base, true, true);
457  if(state->isBlocking == true)
458  {
459  (void)OSIF_SemaPost(&(state->lpspiSemaphore));
460  state->isBlocking = false;
461  }
462  return STATUS_SUCCESS;
463 }
464 
465  /*
466  * Implements : LPSPI_DRV_SlaveGetTransferStatus_Activity
467  */
468 status_t LPSPI_DRV_SlaveGetTransferStatus(uint32_t instance,uint32_t * bytesRemained)
469 {
470  const lpspi_state_t * lpspiState = (lpspi_state_t *)g_lpspiStatePtr[instance];
471 
472  /* Fill in the bytes transferred.*/
473  if (bytesRemained != NULL)
474  {
475  *bytesRemained = lpspiState->txCount;
476  }
477  if (lpspiState->status == LPSPI_TRANSFER_OK)
478  {
479  return (status_t)(lpspiState->isTransferInProgress ? STATUS_BUSY : STATUS_SUCCESS);
480  }
481  else
482  {
483  return STATUS_ERROR;
484  }
485 }
486 
491 static void LPSPI_DRV_SlaveCompleteDMATransfer(void* parameter, edma_chn_status_t status)
492 {
493  uint32_t instance = (uint32_t)parameter;
494  lpspi_state_t * lpspiState = (lpspi_state_t *)g_lpspiStatePtr[instance];
495 
496  (void)status;
497  (void)LPSPI_DRV_SlaveAbortTransfer(instance);
498  if (lpspiState->callback != NULL)
499  {
500  lpspiState->callback(lpspiState, SPI_EVENT_END_TRANSFER, lpspiState->callbackParam);
501  }
502 }
volatile uint16_t rxFrameCnt
#define LPSPI_INSTANCE_COUNT
Definition: S32K142.h:6130
volatile uint16_t txFrameCnt
Runtime state structure for the LPSPI master driver.
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_transfer_type transferType
lpspi_signal_polarity_t pcsPolarity
lpspi_state_t * g_lpspiStatePtr[LPSPI_INSTANCE_COUNT]
spi_callback_t callback
lpspi_which_pcs_t whichPcs
status_t OSIF_SemaCreate(semaphore_t *const pSem, const uint8_t initValue)
Creates a semaphore with a given value.
void LPSPI_DRV_FillupTxBuffer(uint32_t instance)
The function LPSPI_DRV_FillupTxBuffer writes data in TX hardware buffer depending on driver state and...
status_t LPSPI_DRV_SlaveTransfer(uint32_t instance, const uint8_t *sendBuffer, uint8_t *receiveBuffer, uint16_t transferByteCount)
Starts the transfer data on LPSPI bus using an interrupt and a non-blocking call. ...
void INT_SYS_DisableIRQ(IRQn_Type irqNumber)
Disables an interrupt for a given IRQ number.
lpspi_clock_phase_t clkPhase
#define DEV_ASSERT(x)
Definition: devassert.h:77
volatile uint16_t rxCount
edma_chn_status_t
Channel status for eDMA channel.
Definition: edma_driver.h:193
status_t LPSPI_DRV_SlaveTransferBlocking(uint32_t instance, const uint8_t *sendBuffer, uint8_t *receiveBuffer, uint16_t transferByteCount, uint32_t timeout)
Transfers data on LPSPI bus using interrupt and a blocking call.
edma_transfer_size_t
eDMA transfer configuration Implements : edma_transfer_size_t_Class
Definition: edma_driver.h:160
volatile uint16_t txCount
lpspi_sck_polarity_t clkPolarity
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.
status_t LPSPI_DRV_SlaveInit(uint32_t instance, lpspi_state_t *lpspiState, const lpspi_slave_config_t *slaveConfig)
Initializes a LPSPI instance for a slave mode operation, using interrupt mechanism.
User configuration structure for the SPI slave driver. Implements : lpspi_slave_config_t_Class.
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 void LPSPI_DRV_SlaveCompleteDMATransfer(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...
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
volatile bool isTransferInProgress
status_t LPSPI_DRV_SlaveAbortTransfer(uint32_t instance)
Aborts the transfer that started by a non-blocking call transfer function.
status_t OSIF_SemaPost(semaphore_t *const pSem)
Increment a semaphore.
lpspi_transfer_type transferType
status_t LPSPI_DRV_SlaveGetTransferStatus(uint32_t instance, uint32_t *bytesRemained)
Returns whether the previous transfer is finished.
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_SlaveDeinit(uint32_t instance)
Shuts down an LPSPI instance interrupt mechanism.
LPSPI_Type * g_lpspiBase[LPSPI_INSTANCE_COUNT]
Table of base pointers for SPI instances.
const uint8_t * txBuff
void LPSPI_DRV_SlaveIRQHandler(uint32_t instance)
Interrupt handler for LPSPI slave mode. This handler uses the buffers stored in the lpspi_master_stat...
__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
transfer_status_t status