iLLD_TC27xC  1.0
IfxAsclin_Spi.c
Go to the documentation of this file.
1 /**
2  * \file IfxAsclin_Spi.c
3  * \brief ASCLIN SPI 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 "IfxAsclin_Spi.h"
30 #include "Scu/Std/IfxScuWdt.h"
31 
32 /******************************************************************************/
33 /*-----------------------Private Function Prototypes--------------------------*/
34 /******************************************************************************/
35 
36 /**
37  * \param asclin module handle
38  * \return status of the on going job
39  */
40 static IfxAsclin_Spi_Status IfxAsclin_Spi_lock(IfxAsclin_Spi *asclin);
41 
42 /**
43  * \param asclin module handle
44  * \return None
45  */
46 static void IfxAsclin_Spi_unlock(IfxAsclin_Spi *asclin);
47 
48 /******************************************************************************/
49 /*-------------------------Function Implementations---------------------------*/
50 /******************************************************************************/
51 
53 {
54  Ifx_ASCLIN *asclinSFR = asclin->asclin; /* getting the pointer to ASCLIN registers from module handler */
56  IfxScuWdt_clearCpuEndinit(psw); /* clearing the endinit protection*/
57  IfxAsclin_setDisableModuleRequest(asclinSFR); /* disabling the module */
58  IfxScuWdt_setCpuEndinit(psw); /* setting the endinit protection back on */
59 }
60 
61 
62 IfxAsclin_Spi_Status IfxAsclin_Spi_exchange(IfxAsclin_Spi *asclin, void *src, void *dest, uint32 count)
63 {
64  IfxAsclin_Spi_Status status = IfxAsclin_Spi_lock(asclin); /* lock the driver until the communication is done */
65 
66  if (status == IfxAsclin_Spi_Status_ok)
67  {
68  asclin->transferInProgress = 1; /* setting transfer in progress status */
69  asclin->txJob.data = src; /* data to be transmitted */
70  asclin->txJob.pending = count; /* count of Tx data */
71  asclin->rxJob.data = dest; /* empty buffer to receive data */
72  asclin->rxJob.pending = count; /* count of Rx data */
73 
74  IfxAsclin_Spi_write(asclin); /* write data into Tx fifo */
75  }
76 
77  return status;
78 }
79 
80 
82 {
84 
85  if ((asclin->transferInProgress != 0) || (asclin->sending != 0))
86  {
88  }
89 
90  return status;
91 }
92 
93 
95 {
96  Ifx_ASCLIN *asclinSFR = config->asclin; /* pointer to ASCLIN registers */
98 
99  asclin->asclin = asclinSFR; /* adding register pointer to module handler*/
100  IfxAsclin_enableModule(asclinSFR); /* enabling the module */
101 
102  /* mode initialisation */
103  IfxAsclin_setClockSource(asclinSFR, IfxAsclin_ClockSource_noClock); /* disabling the clock */
104  IfxAsclin_setFrameMode(asclinSFR, IfxAsclin_FrameMode_initialise); /* setting the module in Initialise mode */
105  IfxAsclin_setClockSource(asclinSFR, config->clockSource); /* setting the clock source */
106 
107  /* spi mode initialisation */
108  IfxAsclin_setClockSource(asclinSFR, IfxAsclin_ClockSource_noClock); /* disabling the clock */
109  IfxAsclin_setFrameMode(asclinSFR, config->frameMode); /* setting the module in Spi mode */
110  IfxAsclin_setPrescaler(asclinSFR, config->baudrate.prescaler); /* setting the prescaler*/
111  IfxAsclin_setClockSource(asclinSFR, config->clockSource); /* setting the clock source */
112 
113  IfxAsclin_SamplePointPosition samplePointPosition = (config->baudrate.oversampling + 1) / 2; /* sample point position at half of oversampling factor */
114 
115  /* baudrate generation */
116  status = (IfxAsclin_Status)IfxAsclin_setBitTiming(asclinSFR, config->baudrate.baudrate,
117  config->baudrate.oversampling,
118  samplePointPosition,
119  config->bitSampling.medianFilter); /* setting the baudrate bit fields to generate the required baudrate */
120 
121  IfxAsclin_setClockSource(asclinSFR, IfxAsclin_ClockSource_noClock); /* disabling the clock again */
122 
123  /* input output control initialisation */
124  IfxAsclin_setRxInput(asclinSFR, config->inputOutput.alti); /* selecting the Rx(alternate) input pin */
125  IfxAsclin_setClockPolarity(asclinSFR, config->inputOutput.cpol); /* setting the clock polarity */
126  IfxAsclin_setSlavePolarity(asclinSFR, config->inputOutput.spol); /* setting the slave polarity */
127  IfxAsclin_enableLoopBackMode(asclinSFR, config->inputOutput.loopBack); /* selecting loopbak (enable/disable) */
128 
129  /* frame control initialisation */
130  IfxAsclin_setIdleDelay(asclinSFR, config->frame.idleDelay); /* setting idle delay */
131  IfxAsclin_setLeadDelay(asclinSFR, config->frame.leadDelay); /* setting lead delay */
132  IfxAsclin_setStopBit(asclinSFR, config->frame.stopBit); /* setting the stop bit (trail delay) */
133  IfxAsclin_setShiftDirection(asclinSFR, config->frame.shiftDir); /* setting the shift direction */
134 
135  /* data control initialisation */
136  IfxAsclin_setDataLength(asclinSFR, config->dataLength); /* setting the number of bytes to be transfered */
137 
138  /* fifo control initialisation */
139  /* set the FIFO widths based on the supplied datalength */
140  if (config->dataLength <= 8)
141  {
142  IfxAsclin_setTxFifoInletWidth(asclinSFR, IfxAsclin_TxFifoInletWidth_1); /* setting Tx FIFO inlet width to 1 byte */
143  IfxAsclin_setRxFifoOutletWidth(asclinSFR, IfxAsclin_RxFifoOutletWidth_1); /* setting Rx FIFO outlet width to 1 byte */
144  asclin->dataWidth = 1; /* echo the data width to module handle*/
145  }
146 
147  else
148  {
149  IfxAsclin_setTxFifoInletWidth(asclinSFR, IfxAsclin_TxFifoInletWidth_2); /* setting Tx FIFO inlet width to 2 bytes */
150  IfxAsclin_setRxFifoOutletWidth(asclinSFR, IfxAsclin_RxFifoOutletWidth_2); /* setting Rx FIFO outlet width to 2 bytes */
151  asclin->dataWidth = 2; /* echo the data width to module handle*/
152  }
153 
154  IfxAsclin_setRxBufferMode(asclinSFR, config->fifo.buffMode); /* setting Rx FIFO mode */
155  IfxAsclin_setTxFifoInterruptLevel(asclinSFR, config->fifo.txFifoInterruptLevel); /* setting Tx FIFO level at which a Tx interrupt will be triggered */
156  IfxAsclin_setRxFifoInterruptLevel(asclinSFR, config->fifo.rxFifoInterruptLevel); /* setting Rx FIFO interrupt level at which a Rx interrupt will be triggered */
157  IfxAsclin_flushRxFifo(asclinSFR); /* flushing Rx FIFO */
158  IfxAsclin_flushTxFifo(asclinSFR); /* flushing Tx FIFO */
159 
160  IfxAsclin_disableAllFlags(asclinSFR); /* disable all flags */
161  IfxAsclin_clearAllFlags(asclinSFR); /* clear all flags */
162 
163  /* initialising the interrupts */
164  if (config->interrupt.rxPriority > 0)
165  {
166  volatile Ifx_SRC_SRCR *src;
167  src = IfxAsclin_getSrcPointerRx(asclinSFR);
168  IfxSrc_init(src, config->interrupt.typeOfService, config->interrupt.rxPriority);
170  IfxSrc_enable(src);
171  }
172 
173  if (config->interrupt.txPriority > 0)
174  {
175  volatile Ifx_SRC_SRCR *src;
176  src = IfxAsclin_getSrcPointerTx(asclinSFR);
177  IfxSrc_init(src, config->interrupt.typeOfService, config->interrupt.txPriority);
179  IfxSrc_enable(src);
180  }
181 
182  if (config->interrupt.erPriority > 0)
183  {
184  volatile Ifx_SRC_SRCR *src;
185  src = IfxAsclin_getSrcPointerEr(asclinSFR);
186  IfxSrc_init(src, config->interrupt.typeOfService, config->interrupt.erPriority);
188  IfxSrc_enable(src);
189  }
190 
191  /* Pin mapping */
192  const IfxAsclin_Spi_Pins *pins = config->pins;
193 
194  if (pins != NULL_PTR)
195  {
196  IfxAsclin_Sclk_Out *sclk = pins->sclk;
197 
198  if (sclk != NULL_PTR)
199  {
200  IfxAsclin_initSclkPin(sclk, pins->sclkMode, pins->pinDriver);
201  }
202 
203  IfxAsclin_Rx_In *rx = pins->rx;
204 
205  if (rx != NULL_PTR)
206  {
207  IfxAsclin_initRxPin(rx, pins->rxMode);
208  }
209 
210  IfxAsclin_Tx_Out *tx = pins->tx;
211 
212  if (tx != NULL_PTR)
213  {
214  IfxAsclin_initTxPin(tx, pins->txMode, pins->pinDriver);
215  }
216 
217  IfxAsclin_Slso_Out *slso = pins->slso;
218 
219  if (slso != NULL_PTR)
220  {
221  IfxAsclin_initSlsoPin(slso, pins->slsoMode, pins->pinDriver);
222  }
223  }
224 
225  IfxAsclin_enableParity(asclinSFR, FALSE); /* no parity */
226 
227  IfxAsclin_setClockSource(asclinSFR, config->clockSource); /* setting the clock source*/
228 
229  asclin->sending = 0;
230  IfxAsclin_enableTxFifoOutlet(asclinSFR, TRUE); /* disabling Rx FIFO for recieving */
231  IfxAsclin_enableRxFifoInlet(asclinSFR, TRUE); /* disabling Tx FIFO for transmitting */
232 
233  return status;
234 }
235 
236 
237 void IfxAsclin_Spi_initModuleConfig(IfxAsclin_Spi_Config *config, Ifx_ASCLIN *asclin)
238 {
239  const IfxAsclin_Spi_Config defaultConfig = {
240  .asclin = NULL_PTR, /* will be initialized below */
241 
242  .frameMode = IfxAsclin_FrameMode_spi, /* SPI mode */
243  .clockSource = IfxAsclin_ClockSource_kernelClock, /* kernel clock, fclc */
244 
245  /* Default values for input output control */
246  .inputOutput = {
247  .alti = IfxAsclin_RxInputSelect_0, /* alternate input 0; */
248  .cpol = IfxAsclin_ClockPolarity_idleLow, /* CPOL active low */
249  .spol = IfxAsclin_SlavePolarity_idlehigh, /* SPOL active high */
250  .loopBack = FALSE, /* no loop back */
251  },
252 
253  /* Default values for baudrate */
254  .baudrate = {
255  .baudrate = 100000.0, /* default baudrate (the fractional dividier setup will be calculated in initModule) */
256  .prescaler = 2, /* default prescaler */
257  .oversampling = IfxAsclin_OversamplingFactor_8, /* default oversampling factor */
258  },
259 
260  /* Default Values for Bit sampling */
261  .bitSampling = {
262  .medianFilter = IfxAsclin_SamplesPerBit_one, /* one sample per bit */
263  },
264 
265  /* Default Values for Frame Control */
266  .frame = {
267  .idleDelay = IfxAsclin_IdleDelay_0, /* no idle delay */
268  .leadDelay = IfxAsclin_LeadDelay_1, /* one lead bit */
269  .stopBit = IfxAsclin_StopBit_1, /* one stop bit (trail delay) */
270  .shiftDir = IfxAsclin_ShiftDirection_lsbFirst, /* shift direction LSB first */
271  },
272 
273  /* Default Values for Data Control*/
274  .dataLength = IfxAsclin_DataLength_8, /* number of bits per transfer 8*/
275 
276  /* Default Values for fifo Control */
277  .fifo = {
278  .outWidth = IfxAsclin_RxFifoOutletWidth_1, /* 8-bit wide read */
279  .inWidth = IfxAsclin_TxFifoInletWidth_1, /*8-bit wide write */
280  .buffMode = IfxAsclin_ReceiveBufferMode_rxFifo, /* RxFIFO */
281  .txFifoInterruptLevel = IfxAsclin_TxFifoInterruptLevel_15, /* Tx FIFO interrupt level */
282  .rxFifoInterruptLevel = IfxAsclin_RxFifoInterruptLevel_1, /* Rx FIFO interrupt level */
283  },
284 
285  /* Default Values for Interrupt Config */
286  .interrupt = {
287  .rxPriority = 0, /* receive interrupt priority 0 */
288  .txPriority = 0, /* transmit interrupt priority 0 */
289  .erPriority = 0, /* error interrupt priority 0 */
290  .typeOfService = IfxSrc_Tos_cpu0, /* type of service CPU0 */
291  },
292 
293  .pins = NULL_PTR, /* pins to null pointer */
294  };
295 
296  /* Default Configuration */
297  *config = defaultConfig;
298  /* take over module pointer */
299  config->asclin = asclin;
300 }
301 
302 
304 {
305  Ifx_ASCLIN *asclinSFR = asclin->asclin; /* getting the pointer to ASCLIN registers from module handler */
306 
307  /* store all the flags in the variable */
308  if (IfxAsclin_getFrameErrorFlagStatus(asclinSFR))
309  {
311  asclin->errorFlags.frameError = 1;
312  }
313 
315  {
317  asclin->errorFlags.rxFifoOverflow = 1;
318  }
319 
321  {
323  asclin->errorFlags.rxFifoUnderflow = 1;
324  }
325 
327  {
329  asclin->errorFlags.txFifoOverflow = 1;
330  }
331 }
332 
333 
335 {
336  Ifx_ASCLIN *asclinSFR = asclin->asclin; /* getting the pointer to ASCLIN registers from module handler*/
337  IfxAsclin_clearRxFifoFillLevelFlag(asclinSFR); /* clear the interrupt flag */
338  IfxAsclin_Spi_read(asclin); /* read the remaining data */
339 }
340 
341 
343 {
344  Ifx_ASCLIN *asclinSFR = asclin->asclin; /* getting the pointer to ASCLIN registers from module handler */
345  IfxAsclin_clearTxFifoFillLevelFlag(asclinSFR); /* clear the interrupt flag */
346  IfxAsclin_Spi_write(asclin); /* write the remaining data */
347 }
348 
349 
350 static IfxAsclin_Spi_Status IfxAsclin_Spi_lock(IfxAsclin_Spi *asclin)
351 {
352  sint32 sending = __swap(&asclin->sending, 1UL);
353  return (sending == 0) ? IfxAsclin_Spi_Status_ok : IfxAsclin_Spi_Status_busy;
354 }
355 
356 
358 {
359  Ifx_ASCLIN *asclinSFR = asclin->asclin; /* getting the pointer to ASCLIN registers from module handler */
360  IfxAsclin_Spi_Job *job = &asclin->rxJob; /* getting the rxJob structure from module handler */
361 
362  uint32 count = (uint32)IfxAsclin_getRxFifoFillLevel(asclinSFR); /* get the readable count of Rx fifo */
363  count = __min(job->pending, count); /* check for the end of the data */
364 
365  if (job->data == NULL_PTR) /* incase of no data to be received (only transmit case) */
366  {
367  int i;
368  job->pending = job->pending - count; /* discount the current reading count from job pending */
369 
370  for (i = 0; i < count; i++)
371  {
372  IfxAsclin_readRxData(asclinSFR); /* do dummy reads */
373  }
374  }
375  else if (job->pending > 0)
376  {
377  job->pending = job->pending - count; /* discount the current reading count from job pending */
378 
379  /* read data up to the count based on the out width */
380  switch (asclin->dataWidth)
381  {
382  case 1: /* in case of 8 bit wide */
383  IfxAsclin_read8(asclinSFR, job->data, count); /* reading from Rx FIFO */
384  job->data = &(((uint8 *)job->data)[count]); /* pointing to the remaining data */
385  break;
386 
387  case 2: /* in case of 16 bit wide*/
388  IfxAsclin_read16(asclinSFR, job->data, count); /* reading from Rx FIFO */
389  job->data = &(((uint16 *)job->data)[count]); /* pointing to the remaining data */
390  break;
391  }
392  }
393 
394  if (job->pending == 0)
395  {
396  asclin->transferInProgress = 0; /* clearing the transfer in progress status */
397  IfxAsclin_Spi_unlock(asclin); /* unlock the driver */
398  }
399 }
400 
401 
402 static void IfxAsclin_Spi_unlock(IfxAsclin_Spi *asclin)
403 {
404  asclin->sending = 0UL;
405 }
406 
407 
409 {
410  Ifx_ASCLIN *asclinSFR = asclin->asclin; /* getting the pointer to ASCLIN registers from module handler */
411  IfxAsclin_Spi_Job *job = &asclin->txJob; /* getting the txJob structure from module handler */
412 
413  if (job->pending)
414  {
415  /* following operation must be atomic (FIXME actually, we would only have to stall the Tx interrupt) */
416  boolean interruptState = IfxCpu_disableInterrupts();
417 
418  uint32 count = (uint32)(16 - IfxAsclin_getTxFifoFillLevel(asclinSFR)); /* getting the fillable count of the Tx Fifo */
419  count = __min(job->pending, count); /* checking for the end of the data */
420 
421  if (job->data == NULL_PTR) /* incase of no data to be transmitted (only receive case) */
422  {
423  int i;
424  job->pending = job->pending - count; /* discount the current filling count from job pending */
425 
426  for (i = 0; i < count; i++)
427  {
428  IfxAsclin_writeTxData(asclinSFR, ~0); /* write all 1's */
429  }
430  }
431  else
432  {
433  job->pending = job->pending - count; /* discount the current filling count from job pending */
434 
435  /* write data up to the count based on the in width */
436  switch (asclin->dataWidth)
437  {
438  case 1: /* in case of 8 bit wide */
439  IfxAsclin_write8(asclinSFR, job->data, count); /* writing to Tx FIFO */
440  job->data = &(((uint8 *)job->data)[count]); /* pointing to the remaining data */
441  break;
442 
443  case 2: /* in case of 16 bit wide*/
444  IfxAsclin_write16(asclinSFR, job->data, count); /* writing to Tx FIFO */
445  job->data = &(((uint16 *)job->data)[count]); /* pointing to the remaining data */
446  break;
447  }
448  }
449 
450  IfxCpu_restoreInterrupts(interruptState);
451  }
452 }