iLLD_TC27xC  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_0_1_0_10
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);
278  IfxSrc_enable(src);
279 
282  IfxSrc_enable(src);
283  }
284  }
285 
286  /* interrupt configuration */
287  {
288  /** NOTE: If not DMA, the interrupt service provider is assigned to the CPU ID where
289  * this function is called from */
291 
292  if (handle->dma.useDma)
293  {
294  volatile Ifx_SRC_SRCR *src = IfxQspi_getTransmitSrc(qspiSFR);
296  IfxSrc_enable(src);
297 
298  src = IfxQspi_getReceiveSrc(qspiSFR);
300  IfxSrc_enable(src);
301  }
302  else
303  {
304  if (config->base.txPriority != 0)
305  {
306  volatile Ifx_SRC_SRCR *src = IfxQspi_getTransmitSrc(qspiSFR);
307  IfxSrc_init(src, config->base.isrProvider, config->base.txPriority);
308  IfxSrc_enable(src);
309  }
310 
311  if (config->base.rxPriority != 0)
312  {
313  volatile Ifx_SRC_SRCR *src = IfxQspi_getReceiveSrc(qspiSFR);
314  IfxSrc_init(src, config->base.isrProvider, config->base.rxPriority);
315  IfxSrc_enable(src);
316  }
317  }
318  }
319  /* finally switch to slave mode */
320  IfxQspi_run(qspiSFR);
321  qspiSFR->GLOBALCON.B.MS = IfxQspi_Mode_slave;
322 }
323 
324 
326 {
327  const IfxQspi_SpiSlave_Protocol defaultProtocol = {
330  .dataHeading = SpiIf_DataHeading_msbFirst,
331  .dataWidth = 8,
332  .parityMode = Ifx_ParityMode_even
333  };
334 
335  SpiIf_initConfig(&config->base);
336 
337  config->qspi = qspi;
338  config->allowSleepMode = FALSE;
343  config->pins = NULL_PTR;
344  config->protocol = defaultProtocol;
345 
348  config->dma.useDma = FALSE;
349 }
350 
351 
353 {
354  Ifx_DMA *dmaSFR = &MODULE_DMA;
355  IfxDma_ChannelId rxDmaChannelId = qspiHandle->dma.rxDmaChannelId;
356 
357  if (IfxDma_getAndClearChannelInterrupt(dmaSFR, rxDmaChannelId))
358  {
359  qspiHandle->onTransfer = FALSE;
360  }
361 
363 }
364 
365 
367 {
368  Ifx_DMA *dmaSFR = &MODULE_DMA;
369  IfxDma_ChannelId txDmaChannelId = qspiHandle->dma.txDmaChannelId;
370  // TODO
372  IfxDma_getAndClearChannelInterrupt(dmaSFR, txDmaChannelId);
373 }
374 
375 
377 {
378  // FIXME implement error handler
379 }
380 
381 
383 {
384  IfxQspi_SpiSlave_read(handle);
385 }
386 
387 
389 {
390  IfxQspi_SpiSlave_write(handle);
391 }
392 
393 
394 static void IfxQspi_SpiSlave_read(IfxQspi_SpiSlave *handle)
395 {
396  Ifx_QSPI *qspiSFR = handle->qspi;
397  SpiIf_Job *job = &handle->rxJob;
399  count = __min(job->remaining, count);
400 
401  if (job->data == NULL_PTR)
402  {
403  // no data should be buffered: do dummy reads
404  int i;
405 
406  for (i = 0; i < count; ++i)
407  {
408  IfxQspi_readReceiveFifo(qspiSFR);
409  }
410  }
411  else
412  {
413  if (handle->dataWidth <= 8)
414  {
415  IfxQspi_read8(qspiSFR, job->data, count);
416  job->data = &(((uint8 *)job->data)[count]);
417  }
418  else if (handle->dataWidth <= 16)
419  {
420  IfxQspi_read16(qspiSFR, job->data, count);
421  job->data = &(((uint16 *)job->data)[count]);
422  }
423  else
424  {
425  IfxQspi_read32(qspiSFR, job->data, count);
426  job->data = &(((uint32 *)job->data)[count]);
427  }
428  }
429 
430  job->remaining = job->remaining - count;
431 
432  if (job->remaining == 0)
433  {
434  handle->onTransfer = FALSE;
435  }
436 }
437 
438 
439 static void IfxQspi_SpiSlave_write(IfxQspi_SpiSlave *handle)
440 {
441  SpiIf_Job *job = &handle->txJob;
442 
443  if (handle->dma.useDma)
444  {
445  Ifx_DMA *dmaSFR = &MODULE_DMA;
446  SpiIf_Job *jobrx = &handle->rxJob;
447 
448  Ifx_QSPI *qspiSFR = handle->qspi;
449  volatile Ifx_SRC_SRCR *src = IfxQspi_getTransmitSrc(qspiSFR);
450 
451  IfxDma_ChannelId txDmaChannelId = handle->dma.txDmaChannelId;
452  IfxDma_ChannelId rxDmaChannelId = handle->dma.rxDmaChannelId;
453 
454  boolean interruptState = IfxCpu_disableInterrupts();
455  IfxDma_setChannelTransferCount(dmaSFR, txDmaChannelId, job->remaining);
456 
457  if (handle->dataWidth <= 8)
458  {
460  }
461  else if (handle->dataWidth <= 16)
462  {
464  }
465  else
466  {
468  }
469 
470  if (job->data == NULL_PTR)
471  {
472  IfxDma_setChannelSourceAddress(dmaSFR, txDmaChannelId, (void *)IFXCPU_GLB_ADDR_DSPR(IfxCpu_getCoreId(), &IfxQspi_SpiSlave_dummyTxValue));
475  }
476  else
477  {
478  IfxDma_setChannelSourceAddress(dmaSFR, txDmaChannelId, (void *)IFXCPU_GLB_ADDR_DSPR(IfxCpu_getCoreId(), job->data));
481  }
482 
483  IfxDma_clearChannelInterrupt(dmaSFR, txDmaChannelId);
484 
485  /* Receive config */
486  IfxDma_setChannelTransferCount(dmaSFR, rxDmaChannelId, job->remaining);
487 
488  if (handle->dataWidth <= 8)
489  {
491  }
492  else if (handle->dataWidth <= 16)
493  {
495  }
496  else
497  {
499  }
500 
501  if (jobrx->data == NULL_PTR)
502  {
503  IfxDma_setChannelDestinationAddress(dmaSFR, rxDmaChannelId, (void *)IFXCPU_GLB_ADDR_DSPR(IfxCpu_getCoreId(), &IfxQspi_SpiSlave_dummyRxValue));
506  }
507  else
508  {
509  IfxDma_setChannelDestinationAddress(dmaSFR, rxDmaChannelId, (void *)IFXCPU_GLB_ADDR_DSPR(IfxCpu_getCoreId(), jobrx->data));
512  }
513 
514  IfxDma_clearChannelInterrupt(dmaSFR, rxDmaChannelId);
515 
516  IfxQspi_flushTransmitFifo(qspiSFR);
517  IfxQspi_flushReceiveFifo(qspiSFR);
519  src = IfxQspi_getTransmitSrc(qspiSFR);
520  IfxSrc_clearRequest(src);
521  src = IfxQspi_getReceiveSrc(qspiSFR);
522  IfxSrc_clearRequest(src);
523  src = IfxQspi_getErrorSrc(qspiSFR);
524  IfxSrc_clearRequest(src);
525 
526  IfxDma_clearChannelInterrupt(dmaSFR, rxDmaChannelId);
527  IfxDma_clearChannelInterrupt(dmaSFR, txDmaChannelId);
528  IfxDma_setChannelInterruptServiceRequest(dmaSFR, txDmaChannelId);
529  IfxDma_setChannelInterruptServiceRequest(dmaSFR, rxDmaChannelId);
530  IfxDma_enableChannelTransaction(dmaSFR, rxDmaChannelId);
531  IfxDma_enableChannelTransaction(dmaSFR, txDmaChannelId);
532  IfxDma_startChannelTransaction(dmaSFR, txDmaChannelId);
533 
534  IfxCpu_restoreInterrupts(interruptState);
535  }
536  else
537  {
538  uint8 cs = 0;
539 
540  if (job->remaining > 0)
541  {
542  Ifx_QSPI *qspiSFR = handle->qspi;
543 
544  // following operation must be atomic (FIXME actually, we would only have to stall the Tx interrupt)
545  boolean interruptState = IfxCpu_disableInterrupts();
546  Ifx_SizeT count = (Ifx_SizeT)(IFXQSPI_CFG_HWFIFO_DEPTH - 1 - IfxQspi_getTransmitFifoLevel(qspiSFR)); // -1, since BACON allocates one FIFO entry
547  count = __min(job->remaining, count);
548 
549  if (count > 0)
550  {
551  job->remaining = job->remaining - count;
552 
553  if (job->data == NULL_PTR)
554  {
555  // no data should be sent (only received): send all
556  int i;
557 
558  for (i = 0; i < count; ++i)
559  {
560  IfxQspi_writeTransmitFifo(qspiSFR, cs, ~0);
561  }
562  }
563  else
564  {
565  if (handle->dataWidth <= 8)
566  {
567  IfxQspi_write8(qspiSFR, cs, job->data, count);
568  job->data = &(((uint8 *)job->data)[count]);
569  }
570  else if (handle->dataWidth <= 16)
571  {
572  IfxQspi_write16(qspiSFR, cs, job->data, count);
573  job->data = &(((uint16 *)job->data)[count]);
574  }
575  else
576  {
577  IfxQspi_write32(qspiSFR, cs, job->data, count);
578  job->data = &(((uint32 *)job->data)[count]);
579  }
580  }
581  }
582 
583  IfxCpu_restoreInterrupts(interruptState);
584  }
585  }
586 }