iLLD_TC27xD  1.0
IfxQspi_SpiSlave.c
Go to the documentation of this file.
1 /**
2  * \file IfxQspi_SpiSlave.c
3  * \brief QSPI SPISLAVE details
4  *
5  * \version iLLD_1_0_0_11_0
6  * \copyright Copyright (c) 2013 Infineon Technologies AG. All rights reserved.
7  *
8  *
9  * IMPORTANT NOTICE
10  *
11  *
12  * Infineon Technologies AG (Infineon) is supplying this file for use
13  * exclusively with Infineon's microcontroller products. This file can be freely
14  * distributed within development tools that are supporting such microcontroller
15  * products.
16  *
17  * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
18  * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
20  * INFINEON SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
21  * OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
22  *
23  */
24 
25 /******************************************************************************/
26 /*----------------------------------Includes----------------------------------*/
27 /******************************************************************************/
28 
29 #include "IfxQspi_SpiSlave.h"
30 
31 /** \addtogroup IfxLld_Qspi_SpiSlave_Support
32  * \{ */
33 
34 /******************************************************************************/
35 /*-----------------------Private Function Prototypes--------------------------*/
36 /******************************************************************************/
37 
38 /** \brief Reads data from the Rx FIFO
39  * \param handle Module handle
40  * \return None
41  */
42 static void IfxQspi_SpiSlave_read(IfxQspi_SpiSlave *handle);
43 
44 /** \brief Writes data into the Tx FIFO
45  * \param handle Module handle
46  * \return None
47  */
48 static void IfxQspi_SpiSlave_write(IfxQspi_SpiSlave *handle);
49 
50 /** \} */
51 
52 /** \addtogroup IfxLld_Qspi_SpiSlave_DataStructures
53  * \{ */
54 
55 /******************************************************************************/
56 /*------------------------Private Variables/Constants-------------------------*/
57 /******************************************************************************/
58 
59 /** \brief dummy variable where recived data is placed
60  */
61 static uint32 IfxQspi_SpiSlave_dummyRxValue = 0;
62 
63 /** \brief dummy value to be transmitted
64  */
65 static const uint32 IfxQspi_SpiSlave_dummyTxValue = ~0;
66 
67 /** \} */
68 
69 /******************************************************************************/
70 /*-------------------------Function Implementations---------------------------*/
71 /******************************************************************************/
72 
73 SpiIf_Status IfxQspi_SpiSlave_exchange(IfxQspi_SpiSlave *handle, const void *src, void *dest, Ifx_SizeT count)
74 {
76 
77  /* initiate transfer when resource is free */
78  if (handle->onTransfer == FALSE)
79  {
80  status = SpiIf_Status_ok;
81 
82  handle->onTransfer = TRUE;
83  handle->txJob.data = (void *)src;
84  handle->txJob.remaining = count;
85  handle->rxJob.data = dest;
86  handle->rxJob.remaining = count;
87  IfxQspi_SpiSlave_write(handle);
88  }
89 
90  return status;
91 }
92 
93 
95 {
97 
98  if (handle->onTransfer != 0)
99  {
100  status = SpiIf_Status_busy;
101  }
102 
103  return status;
104 }
105 
106 
108 {
109  Ifx_QSPI *qspiSFR = config->qspi;
110  Ifx_DMA *dmaSFR = &MODULE_DMA;
111 
112  /* handle.base must be at offset 0 to be compatible with the standard interface SscIf */
113  {
115  IfxScuWdt_clearCpuEndinit(password);
118  IfxScuWdt_setCpuEndinit(password);
119  }
120 
121  { /* Configure GLOBAL, Note: at the moment default values for GLOBAL */
122  Ifx_QSPI_GLOBALCON globalcon;
123  globalcon.U = 0;
124  globalcon.B.TQ = IfxQspi_calculateTimeQuantumLength(qspiSFR, config->base.maximumBaudrate);
125  globalcon.B.EXPECT = IfxQspi_ExpectTimeout_2097152; /* 2^(EXPECT+6) : timeout for expect phase in Tqspi */
126  //globalcon.B.LB = 0; /* 0 : disable loop-back w*/
127  //globalcon.B.DEL0 = 0; /* 0 : disable delayed mode for SLSO 0 */
128  //globalcon.B.STROBE = 0; /* (STROBE+1) : strobe delay for SLSO 0 in Tq */
129  //globalcon.B.SRF = 0; /* 0 : disable stop-on-RXFIFO full feature */
130  //globalcon.B.STIP = 0; /* 0 : MRST = 0 when QSPI is deselected in slave mode */
131  //globalcon.B.EN = 0; /* 0 : PAUSE requested, 1 : RUN requested */
132  globalcon.B.MS = IfxQspi_Mode_master; /* select master mode during configuration - we will switch to slave mode at the end of this function */
133  globalcon.B.AREN = (config->pauseOnBaudrateSpikeErrors != FALSE) ? 1U : 0U;
134  globalcon.B.RESETS = 1;
135  qspiSFR->GLOBALCON.U = globalcon.U;
136  }
137 
138  { /* Configure interrupt requests */
139  Ifx_QSPI_GLOBALCON1 globalcon1;
140  globalcon1.U = 0;
141  //TODO: globalcon1.B.ERRORENS;
142  globalcon1.B.TXEN = (config->base.txPriority > 0) || (config->dma.useDma);
143  globalcon1.B.RXEN = (config->base.rxPriority > 0) || (config->dma.useDma);
144  globalcon1.B.TXFIFOINT = config->txFifoThreshold;
145  globalcon1.B.RXFIFOINT = config->rxFifoThreshold;
146  qspiSFR->GLOBALCON1.U = globalcon1.U;
147  }
148 
149  handle->qspi = qspiSFR;
150  handle->base.driver = handle;
151  handle->base.sending = 0U;
152  handle->base.activeChannel = NULL_PTR;
153 
154  /* Protocol Configuration */
155  {
157 
158  SpiIf_ChConfig chConfig;
159  SpiIf_initChannelConfig(&chConfig, NULL_PTR);
160  chConfig.mode.clockPolarity = protocol->clockPolarity;
161  chConfig.mode.shiftClock = protocol->shiftClock;
162  chConfig.mode.dataHeading = protocol->dataHeading;
163  chConfig.mode.dataWidth = protocol->dataWidth;
164  chConfig.mode.parityMode = protocol->parityMode;
165 
166  {
167  Ifx_QSPI_BACON bacon;
168  uint8 cs = 0; // not relevant for slave
169 
170  qspiSFR->ECON[cs].U = IfxQspi_calculateExtendedConfigurationValue(qspiSFR, cs, &chConfig);
171  bacon.U = IfxQspi_calculateBasicConfigurationValue(qspiSFR, IfxQspi_ChannelId_0, &chConfig.mode, config->base.maximumBaudrate);
173  }
174  handle->dataWidth = protocol->dataWidth;
175  }
176 
177  handle->rxJob.data = NULL_PTR;
178  handle->rxJob.remaining = 0;
179  handle->txJob.data = NULL_PTR;
180  handle->txJob.remaining = 0;
181  handle->onTransfer = FALSE;
182 
183  /* Configure I/O pins for slave mode */
184  const IfxQspi_SpiSlave_Pins *pins = config->pins;
185 
186  if (pins != NULL_PTR)
187  {
188  const IfxQspi_Sclk_In *sclkIn = pins->sclk;
189 
190  if (sclkIn != NULL_PTR)
191  {
192  IfxQspi_initSclkInPin(sclkIn, pins->sclkMode);
193  }
194 
195  const IfxQspi_Mtsr_In *mtsrIn = pins->mtsr;
196 
197  if (mtsrIn != NULL_PTR)
198  {
199  IfxQspi_initMtsrInPin(mtsrIn, pins->mtsrMode);
200  }
201 
202  const IfxQspi_Mrst_Out *mrstOut = pins->mrst;
203 
204  if (mrstOut != NULL_PTR)
205  {
206  IfxQspi_initMrstOutPin(mrstOut, pins->mrstMode, pins->pinDriver);
207  }
208 
209  const IfxQspi_Slsi_In *slsiIn = pins->slsi;
210 
211  if (slsiIn != NULL_PTR)
212  {
213  IfxQspi_initSlsi(slsiIn, pins->slsiMode);
214  }
215  }
216 
217  if (config->dma.useDma)
218  {
219  IfxDma_Dma dma;
220  IfxDma_Dma_createModuleHandle(&dma, dmaSFR);
221 
223  IfxDma_Dma_initChannelConfig(&dmaCfg, &dma);
224  handle->dma.useDma = TRUE;
225  {
226  handle->dma.txDmaChannelId = config->dma.txDmaChannelId;
227  dmaCfg.channelId = handle->dma.txDmaChannelId;
228  dmaCfg.hardwareRequestEnabled = FALSE; // will be triggered from qspi service request
229  dmaCfg.channelInterruptEnabled = TRUE; // trigger interrupt after transaction
230 
231  // source address and transfer count will be configured during runtime
232  dmaCfg.sourceAddress = 0;
235  dmaCfg.transferCount = 0;
237 
238  // destination address is fixed; use circular mode to stay at this address for each move
239  dmaCfg.destinationAddress = (uint32)&qspiSFR->DATAENTRY[0].U;
242 
246 
247  IfxDma_Dma_initChannel(&handle->dma.txDmaChannel, &dmaCfg);
248  }
249 
250  {
251  handle->dma.rxDmaChannelId = config->dma.rxDmaChannelId;
252  dmaCfg.channelId = handle->dma.rxDmaChannelId;
253  dmaCfg.hardwareRequestEnabled = FALSE; // will be triggered from qspi service request
254  dmaCfg.channelInterruptEnabled = TRUE; // trigger interrupt after transaction
255 
256  // source address is fixed; use circular mode to stay at this address for each move
257  dmaCfg.sourceAddress = (uint32)&qspiSFR->RXEXIT.U;
260 
261  // destination address and transfer count will be configured during runtime
262  dmaCfg.destinationAddress = 0;
265  dmaCfg.transferCount = 0;
266 
271 
272  IfxDma_Dma_initChannel(&handle->dma.rxDmaChannel, &dmaCfg);
273  }
274  /* Dma channel interrupt configuration */
275  {
276  volatile Ifx_SRC_SRCR *src = IfxDma_getSrcPointer(dmaSFR, (IfxDma_ChannelId)config->dma.txDmaChannelId);
277  IfxSrc_init(src, config->base.isrProvider, config->base.txPriority);
278  IfxSrc_enable(src);
279 
281  IfxSrc_init(src, config->base.isrProvider, config->base.rxPriority);
282  IfxSrc_enable(src);
283  }
284  }
285 
286  /* interrupt configuration */
287  {
289 
290  if (handle->dma.useDma)
291  {
292  volatile Ifx_SRC_SRCR *src = IfxQspi_getTransmitSrc(qspiSFR);
294  IfxSrc_enable(src);
295 
296  src = IfxQspi_getReceiveSrc(qspiSFR);
298  IfxSrc_enable(src);
299  }
300  else
301  {
302  if (config->base.txPriority != 0)
303  {
304  volatile Ifx_SRC_SRCR *src = IfxQspi_getTransmitSrc(qspiSFR);
305  IfxSrc_init(src, config->base.isrProvider, config->base.txPriority);
306  IfxSrc_enable(src);
307  }
308 
309  if (config->base.rxPriority != 0)
310  {
311  volatile Ifx_SRC_SRCR *src = IfxQspi_getReceiveSrc(qspiSFR);
312  IfxSrc_init(src, config->base.isrProvider, config->base.rxPriority);
313  IfxSrc_enable(src);
314  }
315  }
316  }
317  /* finally switch to slave mode */
318  IfxQspi_run(qspiSFR);
319  qspiSFR->GLOBALCON.B.MS = IfxQspi_Mode_slave;
320 }
321 
322 
324 {
325  const IfxQspi_SpiSlave_Protocol defaultProtocol = {
328  .dataHeading = SpiIf_DataHeading_msbFirst,
329  .dataWidth = 8,
330  .parityMode = Ifx_ParityMode_even
331  };
332 
333  SpiIf_initConfig(&config->base);
334 
335  config->qspi = qspi;
336  config->allowSleepMode = FALSE;
341  config->pins = NULL_PTR;
342  config->protocol = defaultProtocol;
343 
346  config->dma.useDma = FALSE;
347 }
348 
349 
351 {
352  Ifx_DMA *dmaSFR = &MODULE_DMA;
353  IfxDma_ChannelId rxDmaChannelId = qspiHandle->dma.rxDmaChannelId;
354 
355  if (IfxDma_getAndClearChannelInterrupt(dmaSFR, rxDmaChannelId))
356  {
357  qspiHandle->onTransfer = FALSE;
358  }
359 
361 }
362 
363 
365 {
366  Ifx_DMA *dmaSFR = &MODULE_DMA;
367  IfxDma_ChannelId txDmaChannelId = qspiHandle->dma.txDmaChannelId;
368  // TODO
370  IfxDma_getAndClearChannelInterrupt(dmaSFR, txDmaChannelId);
371 }
372 
373 
375 {
376  Ifx_QSPI *qspiSFR = handle->qspi;
377  uint16 errorFlags = IfxQspi_getErrorFlags(qspiSFR);
379  Ifx_DMA *dmaSFR = &MODULE_DMA;
380 
381  /* store all the flags in the variable */
382 
383  if ((errorFlags & IfxQspi_Error_parity) == 1)
384  {
385  handle->errorFlags.parityError = 1;
386  }
387 
388  if ((errorFlags & IfxQspi_Error_configuration) == 1)
389  {
390  handle->errorFlags.configurationError = 1;
391  }
392 
393  if ((errorFlags & IfxQspi_Error_baudrate) == 1)
394  {
395  handle->errorFlags.baudrateError = 1;
396  }
397 
398  if ((errorFlags & IfxQspi_Error_expectTimeout) == 1)
399  {
400  handle->errorFlags.expectTimeoutError = 1;
401  }
402 
403  if ((errorFlags & IfxQspi_Error_txfifoOverflow) == 1)
404  {
405  handle->errorFlags.txFifoOverflowError = 1;
406  }
407 
408  if ((errorFlags & IfxQspi_Error_txfifoUnderflow) == 1)
409  {
410  handle->errorFlags.txFifoUnderflowError = 1;
411  }
412 
413  if ((errorFlags & IfxQspi_Error_rxfifoOverflow) == 1)
414  {
415  handle->errorFlags.rxFifoOverflowError = 1;
416  }
417 
418  if ((errorFlags & IfxQspi_Error_rxfifoUnderflow) == 1)
419  {
420  handle->errorFlags.rxFifoUnderflowError = 1;
421  }
422 
423  if ((errorFlags & IfxQspi_Error_slsiMisplacedInactivation) == 1)
424  {
426  }
427 
428  if (errorFlags)
429  {
430  handle->onTransfer = FALSE;
431  }
432 
433  if (handle->dma.useDma)
434  {
437  }
438 }
439 
440 
442 {
443  IfxQspi_SpiSlave_read(handle);
444 }
445 
446 
448 {
449  IfxQspi_SpiSlave_write(handle);
450 }
451 
452 
453 static void IfxQspi_SpiSlave_read(IfxQspi_SpiSlave *handle)
454 {
455  Ifx_QSPI *qspiSFR = handle->qspi;
456  SpiIf_Job *job = &handle->rxJob;
458  count = __min(job->remaining, count);
459 
460  if (job->data == NULL_PTR)
461  {
462  // no data should be buffered: do dummy reads
463  int i;
464 
465  for (i = 0; i < count; ++i)
466  {
467  IfxQspi_readReceiveFifo(qspiSFR);
468  }
469  }
470  else
471  {
472  if (handle->dataWidth <= 8)
473  {
474  IfxQspi_read8(qspiSFR, job->data, count);
475  job->data = &(((uint8 *)job->data)[count]);
476  }
477  else if (handle->dataWidth <= 16)
478  {
479  IfxQspi_read16(qspiSFR, job->data, count);
480  job->data = &(((uint16 *)job->data)[count]);
481  }
482  else
483  {
484  IfxQspi_read32(qspiSFR, job->data, count);
485  job->data = &(((uint32 *)job->data)[count]);
486  }
487  }
488 
489  job->remaining = job->remaining - count;
490 
491  if (job->remaining == 0)
492  {
493  handle->onTransfer = FALSE;
494  }
495 }
496 
497 
498 static void IfxQspi_SpiSlave_write(IfxQspi_SpiSlave *handle)
499 {
500  SpiIf_Job *job = &handle->txJob;
501 
502  if (handle->dma.useDma)
503  {
504  Ifx_DMA *dmaSFR = &MODULE_DMA;
505  SpiIf_Job *jobrx = &handle->rxJob;
506 
507  Ifx_QSPI *qspiSFR = handle->qspi;
508  volatile Ifx_SRC_SRCR *src = IfxQspi_getTransmitSrc(qspiSFR);
509 
510  IfxDma_ChannelId txDmaChannelId = handle->dma.txDmaChannelId;
511  IfxDma_ChannelId rxDmaChannelId = handle->dma.rxDmaChannelId;
512 
513  boolean interruptState = IfxCpu_disableInterrupts();
514  IfxDma_setChannelTransferCount(dmaSFR, txDmaChannelId, job->remaining);
515 
516  if (handle->dataWidth <= 8)
517  {
519  }
520  else if (handle->dataWidth <= 16)
521  {
523  }
524  else
525  {
527  }
528 
529  if (job->data == NULL_PTR)
530  {
531  IfxDma_setChannelSourceAddress(dmaSFR, txDmaChannelId, (void *)IFXCPU_GLB_ADDR_DSPR(IfxCpu_getCoreId(), &IfxQspi_SpiSlave_dummyTxValue));
534  }
535  else
536  {
537  IfxDma_setChannelSourceAddress(dmaSFR, txDmaChannelId, (void *)IFXCPU_GLB_ADDR_DSPR(IfxCpu_getCoreId(), job->data));
540  }
541 
542  IfxDma_clearChannelInterrupt(dmaSFR, txDmaChannelId);
543 
544  /* Receive config */
545  IfxDma_setChannelTransferCount(dmaSFR, rxDmaChannelId, job->remaining);
546 
547  if (handle->dataWidth <= 8)
548  {
550  }
551  else if (handle->dataWidth <= 16)
552  {
554  }
555  else
556  {
558  }
559 
560  if (jobrx->data == NULL_PTR)
561  {
562  IfxDma_setChannelDestinationAddress(dmaSFR, rxDmaChannelId, (void *)IFXCPU_GLB_ADDR_DSPR(IfxCpu_getCoreId(), &IfxQspi_SpiSlave_dummyRxValue));
565  }
566  else
567  {
568  IfxDma_setChannelDestinationAddress(dmaSFR, rxDmaChannelId, (void *)IFXCPU_GLB_ADDR_DSPR(IfxCpu_getCoreId(), jobrx->data));
571  }
572 
573  IfxDma_clearChannelInterrupt(dmaSFR, rxDmaChannelId);
574  IfxQspi_flushTransmitFifo(qspiSFR);
575  IfxQspi_flushReceiveFifo(qspiSFR);
577  src = IfxQspi_getTransmitSrc(qspiSFR);
578  IfxSrc_clearRequest(src);
579  src = IfxQspi_getReceiveSrc(qspiSFR);
580  IfxSrc_clearRequest(src);
581  src = IfxQspi_getErrorSrc(qspiSFR);
582  IfxSrc_clearRequest(src);
583 
584  IfxDma_clearChannelInterrupt(dmaSFR, rxDmaChannelId);
585  IfxDma_clearChannelInterrupt(dmaSFR, txDmaChannelId);
586  IfxDma_setChannelInterruptServiceRequest(dmaSFR, txDmaChannelId);
587  IfxDma_setChannelInterruptServiceRequest(dmaSFR, rxDmaChannelId);
588  IfxDma_enableChannelTransaction(dmaSFR, rxDmaChannelId);
589  IfxDma_enableChannelTransaction(dmaSFR, txDmaChannelId);
590  IfxDma_startChannelTransaction(dmaSFR, txDmaChannelId);
591 
592  IfxCpu_restoreInterrupts(interruptState);
593  }
594  else
595  {
596  uint8 cs = 0;
597 
598  if (job->remaining > 0)
599  {
600  Ifx_QSPI *qspiSFR = handle->qspi;
601 
602  // following operation must be atomic (FIXME actually, we would only have to stall the Tx interrupt)
603  boolean interruptState = IfxCpu_disableInterrupts();
604  Ifx_SizeT count = (Ifx_SizeT)(IFXQSPI_HWFIFO_DEPTH - 1 - IfxQspi_getTransmitFifoLevel(qspiSFR)); // -1, since BACON allocates one FIFO entry
605  count = __min(job->remaining, count);
606 
607  if (count > 0)
608  {
609  job->remaining = job->remaining - count;
610 
611  if (job->data == NULL_PTR)
612  {
613  // no data should be sent (only received): send all
614  int i;
615 
616  for (i = 0; i < count; ++i)
617  {
618  IfxQspi_writeTransmitFifo(qspiSFR, ~0);
619  }
620  }
621  else
622  {
623  if (handle->dataWidth <= 8)
624  {
625  IfxQspi_write8(qspiSFR, cs, job->data, count);
626  job->data = &(((uint8 *)job->data)[count]);
627  }
628  else if (handle->dataWidth <= 16)
629  {
630  IfxQspi_write16(qspiSFR, cs, job->data, count);
631  job->data = &(((uint16 *)job->data)[count]);
632  }
633  else
634  {
635  IfxQspi_write32(qspiSFR, cs, job->data, count);
636  job->data = &(((uint32 *)job->data)[count]);
637  }
638  }
639  }
640 
641  IfxCpu_restoreInterrupts(interruptState);
642  }
643  }
644 }