1 /* -------------------------------- Arctic Core ------------------------------
\r
2 * Arctic Core - the open source AUTOSAR platform http://arccore.com
\r
4 * Copyright (C) 2009 ArcCore AB <contact@arccore.com>
\r
6 * This source code is free software; you can redistribute it and/or modify it
\r
7 * under the terms of the GNU General Public License version 2 as published by the
\r
8 * Free Software Foundation; See <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>.
\r
10 * This program is distributed in the hope that it will be useful, but
\r
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
\r
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
\r
14 * -------------------------------- Arctic Core ------------------------------*/
\r
16 /** @reqSettings DEFAULT_SPECIFICATION_REVISION=3.1.5 */
\r
18 /* ----------------------------[information]----------------------------------*/
\r
26 * Implements the SPI driver module
\r
29 * General Have Support
\r
30 * -------------------------------------------
\r
32 * SPI_CHANNEL_BUFFERS_ALLOWED Y/N, Supports only level 1 (0:IB,1:EB,2:IB+EB)
\r
33 * SPI_DEV_ERROR_DETECT Y
\r
34 * SPI_HW_STATUS_API N
\r
35 * SPI_INTERRUPTIBLE_SEQ_ALLOWED N
\r
36 * SPI_LEVEL_DELIVERED Y/N, supports only level 2 (0:sync,1:sync,2:both)
\r
37 * SPI_VERSION_INFO_API Y
\r
40 * - DMA and FIFO is implementations
\r
41 * - Soft CS by callback
\r
47 * Implementation Notes:
\r
48 * - This driver implements SPI_LEVEL_DELIVERED = 2 but with a number
\r
49 * of restrictions. See REQ. below for more information.
\r
51 * - A sequence may use different CS's if the controller is the same.
\r
52 * ( All jobs that belongs to a sequence MUST share the same controller )
\r
54 * - The driver uses Spi_DataType as uint8. This means that an 16-bit address have
\r
55 * a length of 2 when setting upASetting async/sync mode is not supported
\r
56 * ( Spi_SetAsyncMode(), SPI188, etc )
\r
57 * - Cancel API is NOT supported
\r
58 * ( SPI_CANCEL_API must be STD_OFF )
\r
60 * - It's not obvious how to use different modes. My interpretation:
\r
63 * Always blocking in Spi_SyncTransmit()
\r
67 * - The AsyncModeType (SPI_POLLING_MODE,SPI_INTERRUPT_MODE) is used to handle only the
\r
68 * async API, ie Spi_AsyncTransmit(). The synchrone API just calls Spi_SyncTransmit()->Spi_Isr()....
\r
71 * Async and INTERRUPT
\r
74 * Not supported since ??
\r
76 * - Some sequence charts
\r
80 * WriteSeq ISR WriteJob MainFunction_Driving
\r
81 * -------------------------------------------------
\r
86 * ( for each job we will now get an interrupt that write's the next job)
\r
92 * == Async and INTERRUPT ==
\r
98 * ( for each job we will now get an interrupt that write's the next job)
\r
104 * == Async and POLLING ==
\r
105 * ( Not supported yet )
\r
108 * ---------------->
\r
111 * ( for each job in the sequence the sequence must be repeated )
\r
112 * ---------------------------------->
\r
113 * <-----------------
\r
116 * ------------------>
\r
117 * <----------------------------------
\r
124 * -----------------------------------------------
\r
125 * 4 DSPI modules, A,B,C and D
\r
126 * 7 CTAR's for each module.( data-width, baudrate )
\r
130 /* NOTIFICATION INFORMATION
\r
131 * -----------------------------------------------
\r
133 * There's a LOT of status and notification in this module....
\r
136 * |---------------|---------------|
\r
138 * Status IDLE BUSY BUSY IDLE
\r
139 * HwStatus IDLE BUSY BUSY IDLE
\r
140 * JobResult JOB_OK JOB_PENDING JOB_PENDING JOB_OK,SPI_JOB_FAILED
\r
141 * SeqResult SEQ_OK SEQ_PENDING SEQ_PENDING SEQ_OK,SEQ_FAILED,SEQ_CANCELLED
\r
143 * JN - JOb Notification
\r
144 * SN - Sequence NOtificaiton
\r
147 /* ----------------------------[includes]------------------------------------*/
\r
149 #include <stdlib.h>
\r
150 #include <assert.h>
\r
151 #include <limits.h>
\r
152 #include <string.h>
\r
154 #include "mpc55xx.h"
\r
155 //#include <stdio.h>
\r
158 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
163 /* ----------------------------[private define]------------------------------*/
\r
165 #if defined(CFG_MPC5516) || defined(CFG_MPC5517) || defined(CFG_MPC5668) || defined(CFG_MPC5567)
\r
166 #define SPI_CONTROLLER_TOTAL_CNT 4
\r
167 #elif defined(CFG_MPC5604B)
\r
168 #define SPI_CONTROLLER_TOTAL_CNT 3
\r
169 #elif defined(CFG_MPC560X)
\r
170 #define SPI_CONTROLLER_TOTAL_CNT 2
\r
173 #if defined(CFG_MPC560X)
\r
174 #define DSPI_A_ISR_EOQF DSPI_0_ISR_EOQF
\r
175 #define DSPI_B_ISR_EOQF DSPI_1_ISR_EOQF
\r
176 #if defined(CFG_MPC5604B)
\r
177 #define DSPI_C_ISR_EOQF DSPI_2_ISR_EOQF
\r
181 #define SPIE_BAD (-1)
\r
183 #define SPIE_JOB_NOT_DONE 1
\r
185 #if defined(CFG_MPC5604B)
\r
191 //#define SPI_IMPLEMENTATION SPI_FIFO
\r
192 #define USE_DIO_CS STD_ON
\r
194 // E2 read = cmd + addr + data = 1 + 2 + 64 ) = 67 ~ 72
\r
195 #define SPI_INTERNAL_MTU 72
\r
197 /* The depth of the HW FIFO */
\r
198 #define FIFO_DEPTH 4
\r
200 /* Define for debug purposes, checks that SPI/DMA is ok */
\r
201 //#define STEP_VALIDATION 1
\r
203 #define MODULE_NAME "/driver/Spi"
\r
205 //#define USE_LDEBUG_PRINTF 1
\r
207 #define DEBUG_LVL DEBUG_NONE
\r
210 //#define USE_LOCAL_RAMLOG
\r
211 #if defined(USE_LOCAL_RAMLOG)
\r
212 #define RAMLOG_STR(_x) ramlog_str(_x)
\r
213 #define RAMLOG_DEC(_x) ramlog_dec(_x)
\r
214 #define RAMLOG_HEX(_x) ramlog_hex(_x)
\r
216 #define RAMLOG_STR(_x)
\r
217 #define RAMLOG_DEC(_x)
\r
218 #define RAMLOG_HEX(_x)
\r
221 #define SPI_ASSERT(_exp) if( !(_exp) ) while(1) {}
\r
223 /* ----------------------------[private macro]-------------------------------*/
\r
226 #define MIN(_x,_y) (((_x) < (_y)) ? (_x) : (_y))
\r
229 #define MAX(_x,_y) (((_x) > (_y)) ? (_x) : (_y))
\r
232 #define GET_SPI_HW_PTR(_unit) \
\r
233 ((volatile struct DSPI_tag *)(0xFFF90000 + 0x4000*(_unit)))
\r
235 #define GET_SPI_UNIT_PTR(_unit) &Spi_Unit[Spi_CtrlToUnit[_unit]]
\r
237 #define ENABLE_EOQ_INTERRUPT(_spi_hw) _spi_hw->RSER.B.EOQF_RE = 1
\r
238 #define DISABLE_EOQ_INTERRUPT(_spi_hw) _spi_hw->RSER.B.EOQF_RE = 0
\r
240 #define GET_HW(_channel) ( volatile struct DSPI_tag *)((uint32)&DSPI_A + 0x4000 * _channel )
\r
242 /* Development error macros. */
\r
243 #if ( SPI_DEV_ERROR_DETECT == STD_ON )
\r
244 #define VALIDATE(_exp,_api,_err ) \
\r
246 Det_ReportError(MODULE_ID_SPI,0,_api,_err); \
\r
250 #define VALIDATE_W_RV(_exp,_api,_err,_rv ) \
\r
252 Det_ReportError(MODULE_ID_SPI,0,_api,_err); \
\r
256 #define VALIDATE(_exp,_api,_err )
\r
257 #define VALIDATE_W_RV(_exp,_api,_err,_rv )
\r
260 /* ----------------------------[private typedef]-----------------------------*/
\r
262 #if (SPI_IMPLEMENTATION == SPI_DMA )
\r
263 typedef struct Spi_DmaConfig {
\r
264 Dma_ChannelType RxDmaChannel;
\r
265 Dma_ChannelType TxDmaChannel;
\r
266 } Spi_DmaConfigType;
\r
278 vuint32_t CTCNT :1;
\r
286 vuint32_t TXDATA :16;
\r
290 typedef SPICommandType Spi_CommandType;
\r
292 const Spi_DataType * src; /* Pointer to source buffer */
\r
293 Spi_DataType * dest; /* Pointer to destination buffer */
\r
294 Spi_NumberOfDataType length; // Number of elements of Spi_DataType in destination buffer
\r
295 _Bool active; // Set if the buffer is configured.
\r
301 } Spi_CallTypeType;
\r
304 uint8 ctarId; // this channel is assigned to this CTAR
\r
305 } Spi_ChannelInfoType;
\r
308 * This structure represents a controller unit
\r
312 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
313 Dma_ChannelType dmaTxChannel; // Tx DMA channel information
\r
314 Dma_TcdType dmaTxTCD;
\r
315 Dma_ChannelType dmaRxChannel; // Rx DMA channel information
\r
316 Dma_TcdType dmaRxTCD;
\r
317 Spi_CommandType txQueue[SPI_INTERNAL_MTU]; // Pointed to by SADDR of DMA
\r
318 uint32 rxQueue[SPI_INTERNAL_MTU]; // Pointed to by DADDR of DMA
\r
320 uint32 txCurrIndex; // current index for data when sending
\r
321 uint32 channelCodes[(CTAR_CNT-1)]; // Helper array to assign CTAR's
\r
322 Spi_StatusType status; // Status for this unit
\r
323 const Spi_JobConfigType * currJob; // The current job
\r
324 const Spi_JobType * currJobIndexPtr; // Points array of jobs current
\r
325 Spi_JobType currJobIndex;
\r
326 const Spi_SequenceConfigType * currSeqPtr; // The Sequence
\r
327 Spi_CallTypeType callType; // 1 - if the current job is sync. 0 - if not
\r
328 volatile struct DSPI_tag * hwPtr;
\r
329 uint8 hwUnit; // 0...
\r
333 Spi_SeqResultType seqResult;
\r
337 volatile struct DSPI_tag * hwPtr; /* The HW device used by this Job */
\r
338 const Spi_ExternalDeviceType * extDeviceCfgPtr; /* The external device used by this job */
\r
339 const Spi_JobConfigType * jobCfgPtr;
\r
340 Spi_UnitType * unitPtr;
\r
341 const Spi_ChannelType * channelsPtr;
\r
342 #if (SPI_IMPLEMENTATION == SPI_FIFO )
\r
343 uint32_t fifoSent; /* Number of bytes in FIFO (before EOQ is set) */
\r
344 uint8_t currTxChIndex; /* the currently transmitting channel index for FIFO */
\r
345 uint32_t txChCnt; /* number of Spi_DataType sent for the current channel */
\r
346 uint32_t rxChCnt; /* number of Spi_DataType received for the current channel */
\r
347 uint32_t currRxChIndex; /* the currently receiving channel index for FIFO */
\r
349 Spi_JobResultType jobResult;
\r
353 boolean initRun; // Initially FALSE set to TRUE if Spi_Init() have been called
\r
354 const Spi_ConfigType * configPtr; // Pointer to the configuration
\r
355 Spi_EbType * extBufPtr; // Pointer to the external buffers
\r
356 Spi_ChannelInfoType * channelInfo;
\r
357 uint32 spiHwConfigured; // Mask if the HW unit is configured or not
\r
358 Spi_AsyncModeType asyncMode;
\r
360 /* This is a bunch of debug counters. */
\r
361 uint32 totalNbrOfTranfers;
\r
362 uint32 totalNbrOfStartedJobs;
\r
363 /* Counters for busy waiting for DSPI and DMA. */
\r
364 uint32 totalNbrOfWaitTXRXS;
\r
365 uint32 totalNbrOfWaitRxDMA;
\r
366 #if defined(STEP_VALIDATION)
\r
372 /* ----------------------------[private function prototypes]-----------------*/
\r
373 /* ----------------------------[private variables]---------------------------*/
\r
375 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
376 /* Templates for Rx/Tx DMA structures */
\r
377 const Dma_TcdType Spi_DmaTx = {
\r
378 .SADDR = 0, .SMOD = 0, .SSIZE = DMA_TRANSFER_SIZE_32BITS, .DMOD = 0,
\r
379 .DSIZE = DMA_TRANSFER_SIZE_32BITS, .SOFF = 4, .NBYTESu.R = 4, .SLAST = 0,
\r
380 .DADDR = 0, .CITERE_LINK = 0, .CITER = 0, .DOFF = 0, .DLAST_SGA = 0,
\r
381 .BITERE_LINK = 0, .BITER = 0, .BWC = 0, .MAJORLINKCH = 0, .DONE = 0,
\r
382 .ACTIVE = 0, .MAJORE_LINK = 0, .E_SG = 0, .D_REQ = 0, .INT_HALF = 0,
\r
383 .INT_MAJ = 0, .START = 0 };
\r
385 const Dma_TcdType Spi_DmaRx = { .SADDR = 0, .SMOD = 0,
\r
386 .SSIZE = DMA_TRANSFER_SIZE_32BITS, .DMOD = 0,
\r
387 .DSIZE = DMA_TRANSFER_SIZE_32BITS, .SOFF = 0, .NBYTESu.R = 4, .SLAST = 0,
\r
388 .DADDR = 0, .CITERE_LINK = 0, .CITER = 1, .DOFF = 4, .DLAST_SGA = 0,
\r
389 .BITERE_LINK = 0, .BITER = 1, .BWC = 0, .MAJORLINKCH = 0, .DONE = 0,
\r
390 .ACTIVE = 0, .MAJORE_LINK = 0, .E_SG = 0, .D_REQ = 0, .INT_HALF = 0,
\r
391 #if defined(__DMA_INT)
\r
399 Spi_GlobalType Spi_Global;
\r
400 Spi_EbType Spi_Eb[SPI_MAX_CHANNEL];
\r
401 Spi_UnitType Spi_Unit[SPI_CONTROLLER_CNT];
\r
402 Spi_SeqUnitType Spi_SeqUnit[SPI_MAX_SEQUENCE];
\r
403 Spi_JobUnitType Spi_JobUnit[SPI_MAX_JOB];
\r
404 Spi_ChannelInfoType Spi_ChannelInfo[SPI_MAX_CHANNEL];
\r
405 uint8 Spi_CtrlToUnit[4];
\r
408 #if (SPI_IMPLEMENTATION == SPI_DMA)
\r
409 /* When using DMA it assumes predefined names */
\r
410 Spi_DmaConfigType Spi_DmaConfig[SPI_CONTROLLER_CNT] = {
\r
411 #if (SPI_USE_HW_UNIT_0 == STD_ON )
\r
413 .RxDmaChannel = DMA_DSPI_A_RESULT_CHANNEL,
\r
414 .TxDmaChannel = DMA_DSPI_A_COMMAND_CHANNEL,
\r
417 #if (SPI_USE_HW_UNIT_1 == STD_ON )
\r
419 .RxDmaChannel = DMA_DSPI_B_RESULT_CHANNEL,
\r
420 .TxDmaChannel = DMA_DSPI_B_COMMAND_CHANNEL,
\r
423 #if (SPI_USE_HW_UNIT_2 == STD_ON )
\r
425 .RxDmaChannel = DMA_DSPI_C_RESULT_CHANNEL,
\r
426 .TxDmaChannel = DMA_DSPI_C_COMMAND_CHANNEL,
\r
429 #if (SPI_USE_HW_UNIT_3 == STD_ON )
\r
431 .RxDmaChannel = DMA_DSPI_D_RESULT_CHANNEL,
\r
432 .TxDmaChannel = DMA_DSPI_D_COMMAND_CHANNEL,
\r
438 /* ----------------------------[private functions]---------------------------*/
\r
440 #if (SPI_IMPLEMENTATION == SPI_FIFO )
\r
441 static void Spi_WriteJob_FIFO( Spi_JobType jobIndex );
\r
444 * Get the buffer for a channel.
\r
450 static Spi_DataType *spiGetRxBuf(Spi_ChannelType ch, Spi_NumberOfDataType *length ) {
\r
452 if( Spi_Global.configPtr->SpiChannelConfig[ch].SpiChannelType == SPI_EB ) {
\r
453 *length = Spi_Global.extBufPtr[ch].length;
\r
454 buf = Spi_Global.extBufPtr[ch].dest;
\r
463 static const Spi_DataType *spiGetTxBuf(Spi_ChannelType ch, Spi_NumberOfDataType *length ) {
\r
464 const Spi_DataType *buf;
\r
465 if( Spi_Global.configPtr->SpiChannelConfig[ch].SpiChannelType == SPI_EB ) {
\r
466 *length = Spi_Global.extBufPtr[ch].length;
\r
467 buf = Spi_Global.extBufPtr[ch].src;
\r
477 static void Spi_Isr(Spi_UnitType *uPtr );
\r
479 static void Spi_Isr_A(void) {
\r
480 Spi_Isr(GET_SPI_UNIT_PTR(DSPI_CTRL_A));
\r
482 static void Spi_Isr_B(void) {
\r
483 Spi_Isr(GET_SPI_UNIT_PTR(DSPI_CTRL_B));
\r
485 static void Spi_Isr_C(void) {
\r
486 Spi_Isr(GET_SPI_UNIT_PTR(DSPI_CTRL_C));
\r
488 static void Spi_Isr_D(void) {
\r
489 Spi_Isr(GET_SPI_UNIT_PTR(DSPI_CTRL_D));
\r
491 /* ----------------------------[public functions]----------------------------*/
\r
493 uint32 Spi_GetJobCnt(void);
\r
494 uint32 Spi_GetChannelCnt(void);
\r
495 uint32 Spi_GetExternalDeviceCnt(void);
\r
498 static void Spi_Isr_DMA( void )
\r
501 Dma_ClearInterrupt(5);
\r
505 static void Spi_JobWrite(Spi_JobType jobIndex);
\r
507 static void Spi_SetJobResult(Spi_JobType Job, Spi_JobResultType result) {
\r
508 Spi_JobUnit[Job].jobResult = result;
\r
511 static void Spi_SetHWUnitStatus( Spi_UnitType *uPtr, Spi_StatusType status) {
\r
512 uPtr->status = status;
\r
516 * Get external Ptr to device from index
\r
518 * @param deviceType The device index.
\r
519 * @return Ptr to the external device
\r
522 static inline const Spi_ExternalDeviceType *Spi_GetExternalDevicePtrFromIndex(
\r
523 Spi_ExternalDeviceTypeType deviceType) {
\r
524 return (&(Spi_Global.configPtr->SpiExternalDevice[(deviceType)]));
\r
528 * Get configuration job ptr from job index
\r
529 * @param jobIndex the job
\r
530 * @return Ptr to the job configuration
\r
532 static const Spi_JobConfigType *Spi_GetJobPtrFromIndex(Spi_JobType jobIndex) {
\r
533 return &Spi_Global.configPtr->SpiJobConfig[jobIndex];
\r
537 * Get sequence ptr from sequence index
\r
538 * @param seqIndex the sequence
\r
539 * @return Ptr to the sequence configuration
\r
541 static const Spi_SequenceConfigType *Spi_GetSeqPtrFromIndex(
\r
542 Spi_SequenceType SeqIndex) {
\r
543 return &Spi_Global.configPtr->SpiSequenceConfig[SeqIndex];
\r
548 * Function to see if two sequences share jobs
\r
550 * @param seq - Seqence 1
\r
551 * @param seq - Seqence 2
\r
552 * @return 0 - if the don't share any jobs
\r
553 * !=0 - if they share jobs
\r
556 static boolean Spi_ShareJobs(Spi_SequenceType seq1, Spi_SequenceType seq2) {
\r
557 uint32 seqMask1 = 0;
\r
558 uint32 seqMask2 = 0;
\r
559 const Spi_JobType *jobPtr;
\r
560 const Spi_SequenceConfigType *seqConfig;
\r
562 // Search for jobs in sequence 1
\r
563 seqConfig = Spi_GetSeqPtrFromIndex(seq1);
\r
564 jobPtr = &seqConfig->JobAssignment[0];
\r
566 while (*jobPtr != JOB_NOT_VALID) {
\r
567 assert(*jobPtr<31);
\r
568 seqMask1 |= (1 << *jobPtr);
\r
572 // Search for jobs in sequence 2
\r
573 seqConfig = Spi_GetSeqPtrFromIndex(seq2);
\r
574 jobPtr = &seqConfig->JobAssignment[0];
\r
576 while (*jobPtr != JOB_NOT_VALID) {
\r
577 assert(*jobPtr<31);
\r
578 seqMask2 |= (1 << *jobPtr);
\r
582 return (seqMask1 & seqMask2);
\r
586 //-------------------------------------------------------------------
\r
589 * Sets a result for a sequence
\r
591 * @param Sequence The sequence to set the result for
\r
592 * @param result The result to set.
\r
594 static void Spi_SetSequenceResult(Spi_SequenceType Sequence,
\r
595 Spi_SeqResultType result) {
\r
596 Spi_SeqUnit[Sequence].seqResult = result;
\r
599 //-------------------------------------------------------------------
\r
603 * Gets the next job to do
\r
605 * @param spiUnit The SPI unit
\r
606 * @return The job ID. -1 if no more jobs
\r
608 static Spi_JobType Spi_GetNextJob(Spi_UnitType *spiUnit) {
\r
609 spiUnit->currJobIndexPtr++;
\r
610 return *(spiUnit->currJobIndexPtr);
\r
612 //-------------------------------------------------------------------
\r
615 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
618 * Function to handle things after a transmit on the SPI is finished.
\r
619 * It copies data from it't local buffers to the buffers pointer to
\r
620 * by the external buffers
\r
622 * @param spiUnit Ptr to a SPI unit
\r
625 static int Spi_Rx_DMA(Spi_UnitType *spiUnit) {
\r
626 _Bool printedSomeThing = 0;
\r
628 /* Stop the channels */
\r
629 Dma_StopChannel(spiUnit->dmaTxChannel);
\r
630 Dma_StopChannel(spiUnit->dmaRxChannel);
\r
632 RAMLOG_STR("PostTransmit Job: "); RAMLOG_DEC(spiUnit->currJob->SpiJobId); RAMLOG_STR("\n");
\r
634 /* Copy data from RX queue to the external buffer( if a<uny ) */
\r
639 const Spi_ChannelConfigType *chConfig;
\r
640 Spi_EbType *extChBuff;
\r
644 // Check that we got the number of bytes we sent
\r
645 sentTx = spiUnit->txCurrIndex + 1;
\r
646 gotTx = (Dma_GetTcd(spiUnit->dmaRxChannel)->DADDR
\r
647 - (uint32) &spiUnit->rxQueue[0]) / sizeof(uint32);
\r
649 if (sentTx != gotTx) {
\r
650 // Something failed
\r
651 DEBUG(DEBUG_LOW,"%s: Expected %d bytes. Got %d bytes\n ",MODULE_NAME,sentTx, gotTx );
\r
652 #if defined(STEP_VALIDATION)
\r
657 RAMLOG_STR("Rx "); RAMLOG_DEC(gotTx); RAMLOG_STR(" Bytes\n"); DEBUG(DEBUG_LOW,"%s: Got %d bytes\n",MODULE_NAME,gotTx);
\r
660 // Find the channels for this job
\r
661 while ((channelIndex = spiUnit->currJob->ChannelAssignment[j++])
\r
663 chConfig = &Spi_Global.configPtr->SpiChannelConfig[channelIndex];
\r
665 /* Check configuration error */
\r
666 #if ( SPI_CHANNEL_BUFFERS_ALLOWED == 1 )
\r
667 assert( chConfig->SpiChannelType == SPI_EB );
\r
670 // Send the channels that are setup with external buffers
\r
671 // Get the external buffer for this channel
\r
672 extChBuff = &Spi_Global.extBufPtr[channelIndex];
\r
673 if (extChBuff->dest != NULL) {
\r
674 // Note! No support for >8 "data"
\r
675 for (int k = 0; k < extChBuff->length; k++) {
\r
676 extChBuff->dest[k] = spiUnit->rxQueue[currIndex++];
\r
677 DEBUG(DEBUG_LOW," %02x ",extChBuff->dest[k]);
\r
678 printedSomeThing = 1;
\r
682 if (chConfig->SpiDataWidth > 8) {
\r
683 currIndex += (extChBuff->length / 2);
\r
685 currIndex += extChBuff->length;
\r
689 if (printedSomeThing)
\r
690 DEBUG(DEBUG_LOW,"\n");
\r
696 #elif (SPI_IMPLEMENTATION==SPI_FIFO)
\r
698 static int Spi_Rx_FIFO(Spi_UnitType *spiUnit) {
\r
699 Spi_JobUnitType * jobUnitPtr;
\r
700 Spi_DataType * buf;
\r
703 Spi_ChannelType currChannel;
\r
704 Spi_NumberOfDataType bufLen;
\r
706 int rv = SPIE_JOB_NOT_DONE;
\r
707 const Spi_ChannelConfigType * chConfig;
\r
711 // RAMLOG_STR("PostTransmit Job: "); RAMLOG_DEC(spiUnit->currJob->SpiJobId); RAMLOG_STR("\n");
\r
712 RAMLOG_STR("Spi_Rx_FIFO\n");
\r
714 jobUnitPtr = &Spi_JobUnit[spiUnit->currJobIndex];
\r
716 if( jobUnitPtr->hwPtr->TCR.B.SPI_TCNT != jobUnitPtr->fifoSent ) {
\r
717 #if defined(STEP_VALIDATION)
\r
724 * Fill receive buffers, either EB or IB
\r
725 * Example with 8-bit CMD, 16-bit ADDR and some 8-bit data.
\r
726 * CMD | ADDR | DATA
\r
727 * | 12 | 23 | 34 | 00 | 01 | 02 | 03
\r
728 * 1 2 3 4 5 6 BYTE CNT
\r
729 * 1 2 3 4 (5) (6) FIFO
\r
730 * With a FIFO of 4 we can see that the CMD, ADDR and almost the whole
\r
731 * DATA channel is sent.
\r
733 currChannel = jobUnitPtr->channelsPtr[jobUnitPtr->currRxChIndex];
\r
734 assert( currChannel != CH_NOT_VALID );
\r
736 if( jobUnitPtr->fifoSent != jobUnitPtr->hwPtr->SR.B.RXCTR ) {
\r
737 #if defined(STEP_VALIDATION)
\r
743 while ( jobUnitPtr->fifoSent != 0 ) {
\r
745 chConfig = &Spi_Global.configPtr->SpiChannelConfig[currChannel];
\r
747 RAMLOG_STR("CIR#");RAMLOG_DEC(jobUnitPtr->currRxChIndex);RAMLOG_STR("\n");
\r
749 /* Get this channels destination buffer */
\r
750 buf = spiGetRxBuf(currChannel, &bufLen);
\r
751 assert(bufLen!=0); /* We should always get a valid bufLen */
\r
753 copyCnt = MIN( (bufLen - jobUnitPtr->rxChCnt) >> ((chConfig->SpiDataWidth-1)/8), jobUnitPtr->fifoSent );
\r
755 if( copyCnt == 0 ) {
\r
756 #if defined(STEP_VALIDATION)
\r
762 jobUnitPtr->fifoSent -= copyCnt;
\r
764 bInChar = (chConfig->SpiDataWidth > 8 ) ? 2 : 1;
\r
767 if( buf != NULL ) {
\r
768 for(i=0;i<copyCnt;i++) {
\r
769 popVal = jobUnitPtr->hwPtr->POPR.B.RXDATA;
\r
770 RAMLOG_STR("%");RAMLOG_HEX(popVal);
\r
771 buf[jobUnitPtr->rxChCnt] = (Spi_DataType)popVal;
\r
772 jobUnitPtr->rxChCnt += bInChar;
\r
775 for(i=0;i<copyCnt;i++) {
\r
776 popVal = jobUnitPtr->hwPtr->POPR.B.RXDATA;
\r
777 jobUnitPtr->rxChCnt += bInChar;
\r
781 if( (bufLen - jobUnitPtr->rxChCnt ) == 0 ) {
\r
782 /* advance to the next channel */
\r
783 jobUnitPtr->rxChCnt = 0;
\r
784 jobUnitPtr->currRxChIndex++;
\r
785 currChannel = jobUnitPtr->channelsPtr[jobUnitPtr->currRxChIndex];
\r
786 if( currChannel == CH_NOT_VALID ) {
\r
787 //assert( jobUnitPtr->fifoSent == 0);
\r
788 jobUnitPtr->fifoSent = 0;
\r
789 jobUnitPtr->currRxChIndex = 0;
\r
797 #if defined(STEP_VALIDATION)
\r
798 /* Check if we are done with this job */
\r
799 if( 0 != jobUnitPtr->hwPtr->SR.B.RXCTR ) {
\r
809 //-------------------------------------------------------------------
\r
812 * ISR for End of Queue interrupt
\r
814 * The interrupt handling is quite simple. Since this driver assumes
\r
815 * that we are the master the EOQ interrupt is sufficient to check.
\r
817 * @param unit The HW unit it happend on
\r
819 static void Spi_Isr( Spi_UnitType *uPtr) {
\r
820 volatile struct DSPI_tag *spiHw = uPtr->hwPtr;
\r
823 RAMLOG_STR("Spi_Isr\n");
\r
825 // This may seem pretty stupid to wait for the controller
\r
826 // to shutdown here, but there seems to be no other way to do this.
\r
828 // - Waiting for DMA rx/tx hits earlier than EOQ.
\r
829 // - Other interrupts from SPI all hit earlier than EOQ.
\r
830 // TODO: There is the TCF_RE bit! Use this instead?
\r
832 // TODO: We could implement a timeout here and fail the job
\r
833 // if this never happens.
\r
835 // This is the busy wait when called from a non-interrupt context
\r
836 while (spiHw->SR.B.TXRXS) {
\r
837 Spi_Global.totalNbrOfWaitTXRXS++;
\r
840 #if (SPI_IMPLEMENTATION == SPI_DMA)
\r
841 while (!Dma_ChannelDone(uPtr->dmaRxChannel)) {
\r
842 Spi_Global.totalNbrOfWaitRxDMA++;
\r
846 #if defined(STEP_VALIDATION)
\r
847 /* Since EOQF clears TXRXS */
\r
848 SPI_ASSERT( (spiHw->SR.B.EOQF==1) && (spiHw->SR.B.TXRXS == 0));
\r
851 /* Halt DSPI unit until we are ready for next transfer. */
\r
852 spiHw->MCR.B.HALT = 1;
\r
853 spiHw->SR.B.EOQF = 1;
\r
856 Spi_Global.totalNbrOfTranfers++;
\r
858 // Disable EOQ interrupts
\r
860 // This does NOT clear the interrupt request.
\r
861 // That can only be done by clearing( setting ) the EOQ
\r
862 // bit.. but that also triggers a new transfer.
\r
865 // A possibility could be to use the HALT bit instead of
\r
866 // using this trick, but hey, this works
\r
868 DISABLE_EOQ_INTERRUPT(spiHw);
\r
870 // Update external buffers
\r
871 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
872 rv = Spi_Rx_DMA(uPtr);
\r
874 #if (USE_DIO_CS == STD_ON)
\r
875 void (*cb)(int) = Spi_JobUnit[uPtr->currJobIndex].extDeviceCfgPtr->SpiCsCallback;
\r
880 #elif (SPI_IMPLEMENTATION==SPI_FIFO)
\r
881 rv = Spi_Rx_FIFO(uPtr);
\r
883 if( rv == SPIE_JOB_NOT_DONE ) {
\r
884 /* RX FIFO now empty, but the job is not done -> send more */
\r
885 Spi_WriteJob_FIFO ( uPtr->currJobIndex );
\r
886 RAMLOG_STR("Spi_Isr END\n");
\r
889 #if (USE_DIO_CS == STD_ON)
\r
891 void (*cb)(int) = Spi_JobUnit[uPtr->currJobIndex].extDeviceCfgPtr->SpiCsCallback;
\r
899 // Call notification end
\r
900 if (uPtr->currJob->SpiJobEndNotification != NULL) {
\r
901 uPtr->currJob->SpiJobEndNotification();
\r
904 if (rv == SPIE_BAD) {
\r
905 // Fail both job and sequence
\r
906 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);
\r
907 Spi_SetJobResult(uPtr->currJob->SpiJobId, SPI_JOB_FAILED);
\r
908 Spi_SetSequenceResult(uPtr->currSeqPtr->SpiSequenceId,
\r
910 #if defined(STEP_VALIDATION)
\r
914 Spi_JobType nextJob;
\r
916 // The job is at least done..
\r
917 Spi_SetJobResult(uPtr->currJob->SpiJobId, SPI_JOB_OK);
\r
919 // WriteNextJob should
\r
920 // 1. Update the JobResult to SPI_JOB_OK
\r
921 // 2. Update the HWUnit status to IDLE
\r
924 // - Jobs have the controller
\r
925 // - Sequences can we interruptible between jobs.
\r
927 // According to SPI086 you can't share a job with a sequence that
\r
928 // is in SPI_SEQ_PENDING ( that happens first thing at Spi_AsyncTranmit() )
\r
930 // So, I no clue what to use the priority thing for :(
\r
932 nextJob = Spi_GetNextJob(uPtr);
\r
933 if( nextJob != JOB_NOT_VALID ) {
\r
934 Spi_JobWrite(nextJob);
\r
935 RAMLOG_STR("more_jobs\n");
\r
937 // No more jobs, so set HwUnit and sequence IDLE/OK also.
\r
938 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);
\r
939 Spi_SetSequenceResult(uPtr->currSeqPtr->SpiSequenceId,
\r
942 if (uPtr->currSeqPtr->SpiSeqEndNotification != NULL) {
\r
943 uPtr->currSeqPtr->SpiSeqEndNotification();
\r
946 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);
\r
948 /* We are now ready for next transfer. */
\r
949 spiHw->MCR.B.HALT = 1;
\r
951 RAMLOG_STR("NO_more_jobs\n");
\r
955 RAMLOG_STR("Spi_Isr END\n");
\r
958 //-------------------------------------------------------------------
\r
960 Std_ReturnType Spi_WriteIB(Spi_ChannelType Channel,
\r
961 const Spi_DataType *DataBufferPtr) {
\r
962 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_WRITEIB_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
963 VALIDATE_W_RV( ( Channel<SPI_MAX_CHANNEL ), SPI_WRITEIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
964 VALIDATE_W_RV( ( DataBufferPtr != NULL ), SPI_WRITEIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
965 VALIDATE_W_RV( ( SPI_IB==Spi_Global.configPtr->SpiChannelConfig[Channel].SpiChannelType ),
\r
966 SPI_WRITEIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
968 /* According to SPI051 it seems that we only have to a "depth" of 1 */
\r
971 Std_ReturnType rv = E_NOT_OK;
\r
976 const uint32 clk_table_asc[] = { 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
\r
977 4096, 8192, 16384, 32768, 65536 };
\r
978 const uint32 clk_table_cssck[] = { 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
\r
979 4096, 8192, 16384, 32768, 65536 };
\r
980 const uint16 clk_table_br[] = { 2, 4, 6, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
\r
981 4096, 8192, 16384, 32768 };
\r
982 const uint8 clk_table_pasc[] = { 1, 3, 5, 7 };
\r
983 const uint8 clk_table_pcssck[] = { 1, 3, 5, 7 };
\r
984 const uint8 clk_table_pbr[] = { 2, 3, 5, 7 };
\r
987 * Function to setup CTAR's from configuration
\r
988 * @param spiHw - Pointer to HW SPI device
\r
989 * @param extDev - Pointer to external device configuration
\r
990 * @param ctar_unit - The ctar unit number to setup
\r
991 * @param width - The width in bits of the data to send with the CTAR
\r
993 static void Spi_SetupCTAR( Spi_HWUnitType unit,
\r
994 const Spi_ExternalDeviceType *extDev,
\r
995 Spi_ChannelType ctar_unit,
\r
996 Spi_TransferStartType transferStart,
\r
1004 McuE_PeriperalClock_t perClock;
\r
1006 volatile struct DSPI_tag *spiHw = GET_SPI_HW_PTR(unit);
\r
1007 /* BAUDRATE CALCULATION
\r
1008 * -----------------------------
\r
1009 * Baudrate = Fsys/ PBR * ( 1+ DBR) / BR
\r
1010 * PBR range: 2 to 7
\r
1011 * DBR range: 0 to 1
\r
1014 * To make this easy set DBR = 0 and PBR=2
\r
1015 * --> BR=Fsys/(Baudrate.* 2 )
\r
1021 perClock = PERIPHERAL_CLOCK_DSPI_A;
\r
1024 perClock = PERIPHERAL_CLOCK_DSPI_B;
\r
1026 #if (SPI_CONTROLLER_TOTAL_CNT>2)
\r
1028 perClock = PERIPHERAL_CLOCK_DSPI_C;
\r
1031 #if (SPI_CONTROLLER_TOTAL_CNT>3)
\r
1033 perClock = PERIPHERAL_CLOCK_DSPI_D;
\r
1040 clock = McuE_GetPeripheralClock(perClock);
\r
1042 DEBUG(DEBUG_MEDIUM,"%s: Peripheral clock at %d Mhz\n",MODULE_NAME,clock);
\r
1044 DEBUG(DEBUG_MEDIUM,"%s: Want to run at %d Mhz\n",MODULE_NAME,extDev->SpiBaudrate);
\r
1046 spiHw->CTAR[ctar_unit].B.DBR = 0;
\r
1047 spiHw->CTAR[ctar_unit].B.PBR = 0; // 2
\r
1048 pre_br = clock / (extDev->SpiBaudrate
\r
1049 * clk_table_pbr[spiHw->CTAR[ctar_unit].B.PBR]);
\r
1051 // find closest lesser
\r
1052 for (i = 0; i < sizeof(clk_table_br) / sizeof(clk_table_br[0]); i++) {
\r
1053 if (clk_table_br[i] >= pre_br) {
\r
1060 spiHw->CTAR[ctar_unit].B.BR = i;
\r
1062 DEBUG(DEBUG_LOW,"%s: CLK %d Mhz\n",MODULE_NAME,
\r
1063 clock / clk_table_pbr[spiHw->CTAR[ctar_unit].B.PBR] *
\r
1064 ( 1 + spiHw->CTAR[ctar_unit].B.DBR)/clk_table_br[spiHw->CTAR[ctar_unit].B.BR]);
\r
1066 /* For other timings autosar only specifies SpiTimeClk2Cs == "After SCK delay"
\r
1067 * in Freescale language. The dumb thing is that this should be a relative time
\r
1068 * to the clock. Not fixed.
\r
1069 * Autosar specifies 0.0--100.0 ms(float)
\r
1070 * Our intepretation is 0--1000000 ns (uint32)
\r
1072 * AFTER SCK DELAY:
\r
1073 * -----------------------------
\r
1074 * Tasc = 1/Fsys * PASC * ASC [s]
\r
1076 * Assume the Tasc get's here in ns( typical range is ~10ns )
\r
1079 // Calc the PASC * ASC value...
\r
1080 tmp = extDev->SpiTimeClk2Cs * (clock / 1000000);
\r
1082 // Nothing fancy here...
\r
1086 int b_value = INT_MAX;
\r
1089 // Find the best match of Prescaler and Scaler value
\r
1090 for (i = 0; i < ARRAY_SIZE(clk_table_pasc); i++) {
\r
1091 for (j = 0; j < ARRAY_SIZE(clk_table_asc); j++) {
\r
1092 tt = abs((int) clk_table_pasc[i] * clk_table_asc[j] * 1000
\r
1094 if (tt < b_value) {
\r
1102 /* After SCK delay. */
\r
1103 spiHw->CTAR[ctar_unit].B.PASC = best_i;
\r
1104 spiHw->CTAR[ctar_unit].B.ASC = best_j;
\r
1107 DEBUG(DEBUG_MEDIUM,"%s: Timing: Tasc %d ns\n",MODULE_NAME,
\r
1108 clk_table_pasc[spiHw->CTAR[ctar_unit].B.PASC] *
\r
1109 clk_table_asc[spiHw->CTAR[ctar_unit].B.ASC] * 1000/ (clock/1000000) );
\r
1111 /* The PCS to SCK delay is the delay between the assertion of PCS and
\r
1112 * the first edge the SCK.
\r
1114 * PCS TO SCK DELAY:
\r
1115 * -----------------------------
\r
1116 * Tcsc = 1/Fsys * PCSSCK * CSSCK [s]
\r
1119 // Calc the PCSSCK * CSSCK value...
\r
1120 tmp = extDev->SpiTimeCs2Clk * (clock / 1000000);
\r
1122 // Nothing fancy here...
\r
1126 int b_value = INT_MAX;
\r
1129 // Find the best match of Prescaler and Scaler value
\r
1130 for (i = 0; i < ARRAY_SIZE(clk_table_pcssck); i++) {
\r
1131 for (j = 0; j < ARRAY_SIZE(clk_table_cssck); j++) {
\r
1132 tt = abs((int) clk_table_pcssck[i] * clk_table_cssck[j] * 1000
\r
1134 if (tt < b_value) {
\r
1142 /* PCS to SCK delay */
\r
1143 spiHw->CTAR[ctar_unit].B.PCSSCK = best_i;
\r
1144 spiHw->CTAR[ctar_unit].B.CSSCK = best_j;
\r
1147 DEBUG(DEBUG_MEDIUM,"%s: Timing: Tcsc %d ns\n",MODULE_NAME,
\r
1148 clk_table_pcssck[spiHw->CTAR[ctar_unit].B.PCSSCK] *
\r
1149 clk_table_cssck[spiHw->CTAR[ctar_unit].B.CSSCK]*1000/(clock/1000000));
\r
1151 /* Time that PCS is high between transfers */
\r
1152 spiHw->CTAR[ctar_unit].B.PDT = 2;
\r
1153 spiHw->CTAR[ctar_unit].B.DT = 2;
\r
1155 DEBUG(DEBUG_MEDIUM,"%s: Timing: Tdt %d ns\n",MODULE_NAME,
\r
1156 clk_table_pasc[spiHw->CTAR[ctar_unit].B.PDT] *
\r
1157 clk_table_asc[spiHw->CTAR[ctar_unit].B.DT]*1000/(clock/1000000));
\r
1159 /* Data is transferred MSB first */
\r
1161 spiHw->CTAR[ctar_unit].B.LSBFE = (transferStart == SPI_TRANSFER_START_MSB ) ? 0 : 1;
\r
1164 spiHw->CTAR[ctar_unit].B.FMSZ = width - 1;
\r
1165 spiHw->CTAR[ctar_unit].B.CPHA = (extDev->SpiDataShiftEdge
\r
1166 == SPI_EDGE_LEADING) ? 0 : 1;
\r
1167 spiHw->CTAR[ctar_unit].B.CPOL = (extDev->SpiShiftClockIdleLevel == STD_LOW) ? 0 : 1;
\r
1169 // This the ACTIVE polarity. Freescale have inactive polarity
\r
1170 if (extDev->SpiCsPolarity == STD_HIGH) {
\r
1171 spiHw->MCR.R &= ~(1 << (16 + extDev->SpiCsIdentifier));
\r
1173 spiHw->MCR.R |= (1 << (16 + extDev->SpiCsIdentifier));
\r
1177 //-------------------------------------------------------------------
\r
1179 static void Spi_InitController(Spi_UnitType *uPtr ) {
\r
1181 volatile struct DSPI_tag *spiHw = uPtr->hwPtr;
\r
1183 /* Module configuration register. */
\r
1184 /* Master mode. */
\r
1185 spiHw->MCR.B.MSTR = 1;
\r
1186 /* No freeze. Run SPI when debugger is stopped. */
\r
1187 spiHw->MCR.B.FRZ = 0;
\r
1188 /* PSC5 as regular CS. */
\r
1189 spiHw->MCR.B.PCSSE = 0;
\r
1191 /* Enable FIFO's. */
\r
1192 #if (SPI_IMPLEMENTATION == SPI_DMA)
\r
1193 spiHw->MCR.B.DIS_RXF = 1;
\r
1194 spiHw->MCR.B.DIS_TXF = 1;
\r
1195 #elif (SPI_IMPLEMENTATION == SPI_FIFO)
\r
1196 spiHw->MCR.B.DIS_RXF = 0;
\r
1197 spiHw->MCR.B.DIS_TXF = 0;
\r
1201 /* Set all active low. */
\r
1202 spiHw->MCR.B.PCSIS0 = 1;
\r
1203 spiHw->MCR.B.PCSIS1 = 1;
\r
1204 spiHw->MCR.B.PCSIS2 = 1;
\r
1205 spiHw->MCR.B.PCSIS3 = 1;
\r
1206 spiHw->MCR.B.PCSIS4 = 1;
\r
1207 spiHw->MCR.B.PCSIS5 = 1;
\r
1209 #if (SPI_IMPLEMENTATION == SPI_DMA)
\r
1210 /* DMA TX FIFO fill. */
\r
1211 spiHw->RSER.B.TFFF_RE = 1;
\r
1212 spiHw->RSER.B.TFFF_DIRS = 1;
\r
1214 /* DMA RX FIFO drain. */
\r
1215 spiHw->RSER.B.RFDF_RE = 1;
\r
1216 spiHw->RSER.B.RFDF_DIRS = 1;
\r
1219 // Setup CTAR's channel codes..
\r
1220 for (int i = 0; i < (CTAR_CNT-1); i++) {
\r
1221 uPtr->channelCodes[i] = CH_NOT_VALID;
\r
1224 /* Force to stopped state. */
\r
1225 spiHw->MCR.B.HALT = 1;
\r
1227 spiHw->SR.B.EOQF = 1;
\r
1229 /* Enable clocks. */
\r
1230 spiHw->MCR.B.MDIS = 0;
\r
1232 #if defined(__DMA_INT)
\r
1233 Irq_InstallVector(Spi_Isr_DMA, 16 , 1, CPU_Z1);
\r
1236 // Install EOFQ int..
\r
1237 switch (uPtr->hwUnit) {
\r
1239 ISR_INSTALL_ISR2("SPI_A",Spi_Isr_A, DSPI_A_ISR_EOQF, 15, 0);
\r
1242 ISR_INSTALL_ISR2("SPI_B",Spi_Isr_B, DSPI_B_ISR_EOQF, 15, 0);
\r
1244 #if (SPI_CONTROLLER_TOTAL_CNT > 2)
\r
1246 ISR_INSTALL_ISR2("SPI_C",Spi_Isr_C, DSPI_C_ISR_EOQF, 15, 0);
\r
1249 #if (SPI_CONTROLLER_TOTAL_CNT > 3)
\r
1251 ISR_INSTALL_ISR2("SPI_D",Spi_Isr_D, DSPI_D_ISR_EOQF, 15, 0);
\r
1257 //-------------------------------------------------------------------
\r
1259 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
1260 static void Spi_DmaSetup( Spi_UnitType *uPtr ) {
\r
1264 tcd = &uPtr->dmaTxTCD;
\r
1266 tcd->SADDR = (uint32) uPtr->txQueue;
\r
1267 tcd->DADDR = (uint32) &(uPtr->hwPtr->PUSHR.R);
\r
1269 Dma_StopChannel(uPtr->dmaTxChannel);
\r
1270 Dma_CheckConfig();
\r
1272 // CITER and BITER set when we send
\r
1273 tcd = &uPtr->dmaRxTCD;
\r
1275 tcd->SADDR = (uint32) &(uPtr->hwPtr->POPR.R);
\r
1276 tcd->DADDR = (uint32) uPtr->rxQueue;
\r
1278 Dma_StopChannel(uPtr->dmaRxChannel);
\r
1279 Dma_CheckConfig();
\r
1284 //-------------------------------------------------------------------
\r
1286 void Spi_Init(const Spi_ConfigType *ConfigPtr) {
\r
1287 const Spi_JobConfigType *jobConfig2;
\r
1288 Spi_UnitType *uPtr;
\r
1291 #if (SPI_IMPLEMENTATION == SPI_DMA )
\r
1296 memset(&Spi_Global,0,sizeof(Spi_Global));
\r
1297 Spi_Global.configPtr = ConfigPtr;
\r
1298 Spi_Global.extBufPtr = Spi_Eb;
\r
1300 Spi_Global.asyncMode = SPI_INTERRUPT_MODE;
\r
1302 // Set all sequence results to OK
\r
1303 for (Spi_SequenceType i = (Spi_SequenceType) 0; i < SPI_MAX_SEQUENCE; i++) {
\r
1304 Spi_SetSequenceResult(i, SPI_SEQ_OK);
\r
1306 // Figure out what HW controllers that are used
\r
1307 for (int j = 0; j < Spi_GetJobCnt(); j++) {
\r
1308 jobConfig2 = &Spi_Global.configPtr->SpiJobConfig[j];
\r
1309 Spi_Global.spiHwConfigured |= (1 << jobConfig2->SpiHwUnit);
\r
1312 confMask = Spi_Global.spiHwConfigured;
\r
1314 for (int i=0; confMask; confMask &= ~(1 << ctrlNr),i++) {
\r
1315 ctrlNr = ilog2(confMask);
\r
1316 Spi_CtrlToUnit[ctrlNr] = i;
\r
1318 DEBUG(DEBUG_LOW,"%s:Configured HW controller %d\n",MODULE_NAME,ctrlNr);
\r
1319 uPtr = GET_SPI_UNIT_PTR(ctrlNr);
\r
1320 uPtr->hwPtr = GET_SPI_HW_PTR(ctrlNr);
\r
1321 uPtr->hwUnit = ctrlNr;
\r
1322 Spi_InitController(uPtr);
\r
1323 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);
\r
1324 #if (SPI_IMPLEMENTATION == SPI_DMA )
\r
1327 unitNr = Spi_CtrlToUnit[ctrlNr];
\r
1329 /* Make sure that this channel shall be used. */
\r
1330 //assert (ConfigPtr->SpiHwConfig[ctrlNr].Activated);
\r
1331 assert(Spi_DmaConfig[unitNr].TxDmaChannel != (-1));
\r
1332 assert(Spi_DmaConfig[unitNr].RxDmaChannel != (-1));
\r
1334 uPtr->dmaTxChannel = Spi_DmaConfig[unitNr].TxDmaChannel;
\r
1335 uPtr->dmaRxChannel = Spi_DmaConfig[unitNr].RxDmaChannel;
\r
1337 Spi_DmaSetup(uPtr);
\r
1342 /* Setup the relations for Job, for easy access */
\r
1343 for(int j=0; j<SPI_MAX_JOB; j++ ) {
\r
1344 jobConfig2 = &Spi_Global.configPtr->SpiJobConfig[j];
\r
1345 Spi_JobUnit[j].jobCfgPtr = jobConfig2;
\r
1346 Spi_JobUnit[j].extDeviceCfgPtr = &Spi_Global.configPtr->SpiExternalDevice[jobConfig2->DeviceAssignment];
\r
1347 Spi_JobUnit[j].unitPtr = GET_SPI_UNIT_PTR(jobConfig2->SpiHwUnit);
\r
1348 Spi_JobUnit[j].hwPtr= GET_SPI_HW_PTR(jobConfig2->SpiHwUnit);
\r
1349 Spi_JobUnit[j].channelsPtr = &jobConfig2->ChannelAssignment[0];
\r
1352 /* Setup CTARS, configuration */
\r
1354 Spi_UnitType *spiUnit;
\r
1359 uint32 channelCode;
\r
1362 const Spi_JobConfigType *jobConfig;
\r
1363 const Spi_ChannelConfigType *chConfig;
\r
1365 for (j = 0; j < Spi_GetJobCnt(); j++) {
\r
1366 jobConfig = &Spi_Global.configPtr->SpiJobConfig[j];
\r
1367 spiUnit = GET_SPI_UNIT_PTR( jobConfig->SpiHwUnit );
\r
1369 // Also find the controllers used while we are at it
\r
1370 Spi_Global.spiHwConfigured |= (1 << jobConfig->SpiHwUnit);
\r
1372 // ..and set the job status
\r
1373 Spi_SetJobResult((Spi_JobType) j, SPI_JOB_OK);
\r
1376 // Go through all the jobs and it's channels to setup CTAS
\r
1377 // A job have the same physical controller ( SpiHwUnit )
\r
1378 while ((channelIndex = jobConfig->ChannelAssignment[l++])
\r
1379 != CH_NOT_VALID) {
\r
1380 chConfig = &Spi_Global.configPtr->SpiChannelConfig[channelIndex];
\r
1382 // Form a channel code from
\r
1383 // <MSB/LSB><external_device_id><channel width>
\r
1384 channelCode = ( ((uint32_t)chConfig->SpiTransferStart << 16) +
\r
1385 (jobConfig->DeviceAssignment << 8) +
\r
1386 chConfig->SpiDataWidth);
\r
1388 for (k = 0; k < (CTAR_CNT-1); k++) {
\r
1389 if (spiUnit->channelCodes[k] == channelCode) {
\r
1390 Spi_ChannelInfo[channelIndex].ctarId = k;
\r
1391 DEBUG(DEBUG_LOW,"%s: Channel %d re-uses CTAR %d@%d . device=%d,width=%d\n",MODULE_NAME,channelIndex,k,jobConfig->SpiHwUnit,jobConfig->DeviceAssignment,chConfig->SpiDataWidth);
\r
1392 // already in list, break
\r
1396 if (spiUnit->channelCodes[k] == CH_NOT_VALID) {
\r
1398 spiUnit->channelCodes[k] = channelCode;
\r
1399 // Assign the CTAR index to channel info..
\r
1400 DEBUG(DEBUG_LOW,"%s: Channel %d uses CTAR %d@%d . device=%d,width=%d\n",MODULE_NAME,channelIndex,k,jobConfig->SpiHwUnit,jobConfig->DeviceAssignment,chConfig->SpiDataWidth);
\r
1403 jobConfig->SpiHwUnit,
\r
1404 Spi_GetExternalDevicePtrFromIndex( jobConfig->DeviceAssignment),
\r
1405 (Spi_ChannelType) k,
\r
1406 chConfig->SpiTransferStart,
\r
1407 chConfig->SpiDataWidth);
\r
1409 Spi_ChannelInfo[channelIndex].ctarId = k;
\r
1413 /* No more CTARS */
\r
1414 assert(k<(CTAR_CNT-1));
\r
1419 Spi_Global.initRun = TRUE;
\r
1422 //-------------------------------------------------------------------
\r
1424 Std_ReturnType Spi_DeInit(void) {
\r
1425 volatile struct DSPI_tag *spiHw;
\r
1428 Spi_UnitType *uPtr;
\r
1431 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_DEINIT_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
1432 if (Spi_GetStatus() == SPI_BUSY)
\r
1435 // Disable the HW modules ( SPI021 )
\r
1436 confMask = Spi_Global.spiHwConfigured;
\r
1438 // Disable the SPI hw
\r
1439 for (; confMask; confMask &= ~(1 << confNr)) {
\r
1440 confNr = ilog2(confMask);
\r
1441 spiHw = GET_SPI_HW_PTR(confNr);
\r
1442 // Disable the hardware..
\r
1443 spiHw->MCR.B.MDIS = 1;
\r
1444 uPtr = GET_SPI_UNIT_PTR(confNr);
\r
1446 Spi_InitController(uPtr);
\r
1447 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);
\r
1451 Spi_Global.configPtr = NULL;
\r
1452 Spi_Global.initRun = FALSE;
\r
1457 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
1461 * @param jobConfig
\r
1464 static void Spi_DoWrite_DMA( Spi_UnitType *spiUnit,Spi_JobType jobIndex,
\r
1465 const Spi_JobConfigType *jobConfig )
\r
1470 const Spi_ChannelConfigType *chConfig;
\r
1471 Spi_EbType *extChBuff;
\r
1472 Spi_CommandType cmd;
\r
1476 // Find the channels for this job
\r
1477 while ((channelIndex = jobConfig->ChannelAssignment[j++]) != CH_NOT_VALID) {
\r
1478 chConfig = &Spi_Global.configPtr->SpiChannelConfig[channelIndex];
\r
1480 /* Check configuration error */
\r
1481 #if ( SPI_CHANNEL_BUFFERS_ALLOWED == 1 )
\r
1482 assert( chConfig->SpiChannelType == SPI_EB );
\r
1485 // Send the channels that are setup with external buffers
\r
1486 // Get the external buffer for this channel
\r
1487 extChBuff = &Spi_Global.extBufPtr[channelIndex];
\r
1489 if (extChBuff->active == 0) {
\r
1490 LDEBUG_PRINTF("Err:External buffer %d@job %d not setup\n",channelIndex,jobIndex);
\r
1495 // Start to fill the SPI queue for the DMA:
\r
1496 for (k = 0; k < extChBuff->length; k++) {
\r
1498 Spi_Global.configPtr->SpiExternalDevice[jobConfig->DeviceAssignment].SpiCsIdentifier;
\r
1500 cmd.B.CONT = 1; // Channels should keep CS active
\r
1501 // ( A job must assert CS continuously)
\r
1502 cmd.R |= (1 << (16 + csId)); // Set PCS
\r
1504 cmd.B.CTAS = Spi_ChannelInfo[channelIndex].ctarId;
\r
1505 if (extChBuff->src != NULL) {
\r
1506 if (chConfig->SpiDataWidth > 8) {
\r
1507 cmd.B.TXDATA = (extChBuff->src[k] << 8) + (extChBuff->src[k + 1] & 0xff);
\r
1510 cmd.B.TXDATA = extChBuff->src[k];
\r
1513 cmd.B.TXDATA = chConfig->SpiDefaultData;
\r
1516 // Just keep on filling the tx queue
\r
1517 spiUnit->txQueue[spiUnit->txCurrIndex++].R = cmd.R;
\r
1519 } /*while( channelIndex == */
\r
1522 cmd.B.CONT = 0; // CS high
\r
1523 cmd.B.EOQ = 1; // last in queue
\r
1524 spiUnit->txQueue[--spiUnit->txCurrIndex].R = cmd.R;
\r
1526 // Set the length of the data to send
\r
1527 spiUnit->dmaTxTCD.CITER = spiUnit->txCurrIndex + 1;
\r
1528 spiUnit->dmaTxTCD.BITER = spiUnit->txCurrIndex + 1;
\r
1530 Spi_Global.totalNbrOfStartedJobs++;
\r
1532 RAMLOG_STR("Job: "); RAMLOG_DEC(jobIndex); RAMLOG_STR(" Cnt: "); RAMLOG_DEC(spiUnit->txCurrIndex+1); RAMLOG_STR("\n");
\r
1534 DEBUG(DEBUG_LOW,"%s:Tx Job:%d cnt:%d first data:%04x\n",MODULE_NAME,jobIndex,spiUnit->txCurrIndex+1,spiUnit->txQueue[0].B.TXDATA);
\r
1537 Spi_UnitType *spiUnit = GET_SPI_UNIT_PTR(jobConfig->SpiHwUnit);
\r
1538 volatile struct DSPI_tag *spiHw = GET_SPI_HW_PTR(jobConfig->SpiHwUnit);
\r
1540 Dma_ConfigureChannel((Dma_TcdType *) &spiUnit->dmaTxTCD,
\r
1541 spiUnit->dmaTxChannel);
\r
1542 Dma_ConfigureChannel((Dma_TcdType *) &spiUnit->dmaRxTCD,
\r
1543 spiUnit->dmaRxChannel);
\r
1544 /* Flush TX/Rx FIFO. Ref. man. 23.5.1 step 8 */
\r
1545 spiHw->MCR.B.CLR_RXF = 1;
\r
1546 spiHw->MCR.B.CLR_TXF = 1;
\r
1548 Dma_StartChannel(spiUnit->dmaRxChannel);
\r
1549 Dma_StartChannel(spiUnit->dmaTxChannel);
\r
1551 // Step 9. Clear TCNT
\r
1552 spiHw->TCR.B.SPI_TCNT = 0;
\r
1554 if ( (Spi_Global.asyncMode == SPI_INTERRUPT_MODE) &&
\r
1555 (spiUnit->callType == SPI_ASYNC_CALL)) {
\r
1556 ENABLE_EOQ_INTERRUPT(spiHw);
\r
1558 DISABLE_EOQ_INTERRUPT(spiHw);
\r
1561 /* This will trig a new transfer. Ref. man. 23.5.1 step 11 */
\r
1562 spiHw->SR.B.EOQF = 1;
\r
1563 spiHw->MCR.B.HALT = 0;
\r
1565 // Since it's not obvious on how to tell when a SPI sequence
\r
1566 // is sent, keep things below to what things have been tested.
\r
1567 #if defined(STEP_VALIDATION)
\r
1568 /* Wait for transfer to complete (EOQF bit is set) */
\r
1569 while (spiHw->SR.B.EOQF==1) {
\r
1570 Spi_Global.eoqf_cnt++;
\r
1572 while (spiHw->SR.B.TXRXS) {Spi_Global.txrxs_cnt++;}
\r
1573 while( EDMA.TCD[spiUnit->dmaRxChannel].ACTIVE ) {;}
\r
1580 #if (SPI_IMPLEMENTATION==SPI_FIFO)
\r
1584 * @param jobConfig
\r
1587 static void Spi_WriteJob_FIFO( Spi_JobType jobIndex )
\r
1589 Spi_ChannelType currChannel;
\r
1590 Spi_CommandType cmd;
\r
1591 Spi_CommandType dCmd;
\r
1592 Spi_NumberOfDataType bufLen;
\r
1593 const Spi_ChannelConfigType * chConfig;
\r
1594 Spi_JobUnitType * jobUnitPtr;
\r
1595 const Spi_DataType * buf;
\r
1596 Spi_NumberOfDataType copyCnt;
\r
1597 Spi_NumberOfDataType fifoLeft;
\r
1598 // boolean done = 0;
\r
1599 // boolean lastJob = 0;
\r
1601 jobUnitPtr = &Spi_JobUnit[jobIndex];
\r
1604 fifoLeft = FIFO_DEPTH;
\r
1606 RAMLOG_STR("Spi_WriteJob_FIFO\n");
\r
1608 #if defined(STEP_VALIDATION)
\r
1609 if( jobUnitPtr->hwPtr->SR.B.TXCTR != 0 ) {
\r
1615 dCmd.R = 0xfffffffful;
\r
1617 /* Iterate over the channels for this job */
\r
1618 currChannel = jobUnitPtr->channelsPtr[jobUnitPtr->currTxChIndex];
\r
1619 while ( fifoLeft != 0) {
\r
1621 chConfig = &Spi_Global.configPtr->SpiChannelConfig[currChannel];
\r
1622 buf = spiGetTxBuf( currChannel, &bufLen);
\r
1624 /* Minimum of how much data to copy and the limit of the FIFO */
\r
1625 copyCnt = MIN( (bufLen - jobUnitPtr->txChCnt) >> ((chConfig->SpiDataWidth-1)/8), fifoLeft );
\r
1627 /* Channels should keep CS active ( A job must assert CS continuously) */
\r
1629 /* Set the Chip Select (PCS) */
\r
1630 cmd.R |= (1 << (16 + jobUnitPtr->extDeviceCfgPtr->SpiCsIdentifier));
\r
1632 #if defined(STEP_VALIDATION)
\r
1633 if( cmd.B.EOQ == 1) {
\r
1638 /* Push as much as we can (FIFO or Channel limits) */
\r
1639 for(i=0; i < copyCnt ; i++ ) {
\r
1640 cmd.B.CTAS = Spi_ChannelInfo[currChannel].ctarId;
\r
1641 if (buf != NULL) {
\r
1642 if (chConfig->SpiDataWidth > 8 ) {
\r
1643 cmd.B.TXDATA = (buf[jobUnitPtr->txChCnt] << 8) +
\r
1644 (buf[jobUnitPtr->txChCnt + 1] & 0xff);
\r
1646 cmd.B.TXDATA = buf[jobUnitPtr->txChCnt];
\r
1649 cmd.B.TXDATA = chConfig->SpiDefaultData;
\r
1652 if (chConfig->SpiDataWidth > 8 ) {
\r
1653 jobUnitPtr->txChCnt+=2;
\r
1655 jobUnitPtr->txChCnt++;
\r
1659 if( dCmd.R != 0xfffffffful) {
\r
1660 jobUnitPtr->hwPtr->PUSHR.R = dCmd.R; // Write delayed
\r
1663 dCmd.R = cmd.R; // Save it
\r
1667 RAMLOG_STR("CI#");RAMLOG_DEC(jobUnitPtr->currTxChIndex);RAMLOG_STR("\n");
\r
1670 /* Done with channel? */
\r
1671 if( ((bufLen - jobUnitPtr->txChCnt) == 0) ) {
\r
1672 jobUnitPtr->txChCnt = 0;
\r
1673 /* Done with job? */
\r
1674 jobUnitPtr->currTxChIndex++;
\r
1675 currChannel = jobUnitPtr->channelsPtr[jobUnitPtr->currTxChIndex];
\r
1676 if( currChannel == CH_NOT_VALID ) {
\r
1677 jobUnitPtr->currTxChIndex = 0;
\r
1686 jobUnitPtr->hwPtr->PUSHR.R = cmd.R;
\r
1688 jobUnitPtr->fifoSent = FIFO_DEPTH - fifoLeft;
\r
1690 #if defined(STEP_VALIDATION)
\r
1691 if( jobUnitPtr->fifoSent != jobUnitPtr->hwPtr->SR.B.TXCTR ) {
\r
1696 jobUnitPtr->hwPtr->TCR.B.SPI_TCNT = 0;
\r
1698 if ( (Spi_Global.asyncMode == SPI_INTERRUPT_MODE) &&
\r
1699 (jobUnitPtr->unitPtr->callType == SPI_ASYNC_CALL)) {
\r
1700 ENABLE_EOQ_INTERRUPT(jobUnitPtr->hwPtr);
\r
1702 DISABLE_EOQ_INTERRUPT(jobUnitPtr->hwPtr);
\r
1705 #if defined(STEP_VALIDATION)
\r
1706 /* Verify FIFO before sending */
\r
1708 SPICommandType *base = (SPICommandType *)&jobUnitPtr->hwPtr->TXFR[0];
\r
1709 SPICommandType *curr;
\r
1712 i = jobUnitPtr->hwPtr->SR.B.TXNXTPTR; /* Next entry to send */
\r
1713 lastIndex = ( i + jobUnitPtr->hwPtr->SR.B.TXCTR - 1 ) % FIFO_DEPTH;
\r
1714 while( i != lastIndex ) {
\r
1716 if( curr->B.EOQ == 1) { /* This entry must not have EOQ set */
\r
1720 i = (i + 1) % FIFO_DEPTH;
\r
1723 if( curr->B.EOQ != 1) {
\r
1724 SPI_ASSERT(0); /* Last entry must have EOQ set */
\r
1729 jobUnitPtr->hwPtr->SR.B.EOQF = 1;
\r
1730 jobUnitPtr->hwPtr->MCR.B.HALT = 0;
\r
1732 #if defined(STEP_VALIDATION)
\r
1733 /* Wait for transfer to complete (EOQF bit is set) */
\r
1734 while (jobUnitPtr->hwPtr->SR.B.EOQF==1) {
\r
1735 Spi_Global.eoqf_cnt++;
\r
1737 while (jobUnitPtr->hwPtr->SR.B.TXRXS) {Spi_Global.txrxs_cnt++;}
\r
1740 // TODO: Clear FIFO's? CLR_TXF?
\r
1743 #endif /* (SPI_IMPLEMENTATION==SPI_FIFO) */
\r
1746 //-------------------------------------------------------------------
\r
1752 * Write a job to the SPI bus
\r
1754 * @param jobIndex The job to write to the SPI bus
\r
1756 static void Spi_JobWrite(Spi_JobType jobIndex) {
\r
1757 Spi_UnitType *uPtr = Spi_JobUnit[jobIndex].unitPtr;
\r
1759 uPtr->txCurrIndex = 0;
\r
1760 uPtr->currJob = Spi_JobUnit[jobIndex].jobCfgPtr;
\r
1761 uPtr->currJobIndex = jobIndex;
\r
1762 #if (SPI_IMPLEMENTATION == SPI_FIFO)
\r
1763 Spi_JobUnit[jobIndex].txChCnt = 0;
\r
1764 Spi_JobUnit[jobIndex].rxChCnt = 0;
\r
1767 Spi_SetHWUnitStatus(uPtr, SPI_BUSY);
\r
1768 Spi_SetJobResult(jobIndex, SPI_JOB_PENDING);
\r
1770 #if (USE_DIO_CS == STD_ON)
\r
1771 if( Spi_JobUnit[jobIndex].extDeviceCfgPtr->SpiCsCallback != NULL ) {
\r
1772 Spi_JobUnit[jobIndex].extDeviceCfgPtr->SpiCsCallback(1);
\r
1776 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
1777 Spi_DoWrite_DMA( uPtr, jobIndex, Spi_JobUnit[jobIndex].jobCfgPtr );
\r
1778 #elif (SPI_IMPLEMENTATION==SPI_FIFO)
\r
1779 Spi_JobUnit[jobIndex].currTxChIndex = 0;
\r
1780 Spi_WriteJob_FIFO ( jobIndex );
\r
1785 #if defined(USE_LDEBUG_PRINTF) && ( DEBUG_LVL <= DEBUG_HIGH )
\r
1786 void Spi_PrintSeqInfo(const Spi_SequenceConfigType *seqConfigPtr) {
\r
1789 DEBUG(DEBUG_HIGH,"%s: Seq: %d:",MODULE_NAME,seqConfigPtr->SpiSequenceId);
\r
1791 while ((job = seqConfigPtr->JobAssignment[i]) != JOB_NOT_VALID) {
\r
1792 DEBUG(DEBUG_HIGH,"%d ",job);
\r
1794 } DEBUG(DEBUG_HIGH,"\n");
\r
1800 * Write a sequence to the SPI bus
\r
1802 * @param seqIndex The sequence
\r
1803 * @param sync 1 - make the call sync. 0 - make the call async
\r
1805 static void Spi_SeqWrite(Spi_SequenceType seqIndex, Spi_CallTypeType sync) {
\r
1807 const Spi_SequenceConfigType *seqConfig;
\r
1808 const Spi_JobConfigType *jobConfig;
\r
1809 Spi_UnitType *uPtr;
\r
1810 Spi_JobType jobIndex;
\r
1812 seqConfig = Spi_GetSeqPtrFromIndex(seqIndex);
\r
1813 jobIndex = seqConfig->JobAssignment[0];
\r
1814 jobConfig = Spi_GetJobPtrFromIndex(jobIndex);
\r
1816 uPtr = GET_SPI_UNIT_PTR(jobConfig->SpiHwUnit);
\r
1818 /* Fill in the required fields for job and sequence.. */
\r
1819 uPtr->currJobIndexPtr = &seqConfig->JobAssignment[0];
\r
1820 uPtr->callType = sync;
\r
1821 uPtr->currSeqPtr = seqConfig;
\r
1823 Spi_SetSequenceResult(seqIndex, SPI_SEQ_PENDING);
\r
1825 // Setup interrupt for end of queue
\r
1826 if ( (Spi_Global.asyncMode == SPI_INTERRUPT_MODE) &&
\r
1827 (uPtr->callType== SPI_ASYNC_CALL)) {
\r
1828 DEBUG(DEBUG_MEDIUM,"%s: async/interrupt mode\n",MODULE_NAME);
\r
1830 DEBUG(DEBUG_MEDIUM,"%s: sync/polled mode\n",MODULE_NAME);
\r
1833 #if defined(USE_LDEBUG_PRINTF) && ( DEBUG_LVL <= DEBUG_HIGH )
\r
1834 Spi_PrintSeqInfo( seqConfig );
\r
1837 Spi_JobWrite(jobIndex);
\r
1839 if (uPtr->callType == SPI_SYNC_CALL) {
\r
1840 while (Spi_GetSequenceResult(seqIndex) == SPI_SEQ_PENDING) {
\r
1847 //-------------------------------------------------------------------
\r
1848 static _Bool Spi_AnyPendingJobs(Spi_SequenceType Sequence) {
\r
1850 // Check that we don't share any jobs with another sequence that is SPI_SEQ_PENDING
\r
1851 for (int i = 0; i < SPI_MAX_SEQUENCE; i++) {
\r
1852 if (i == Sequence) {
\r
1856 if (Spi_GetSequenceResult(i) == SPI_SEQ_PENDING) {
\r
1857 // We have found a pending sequence... check that we don't share any jobs
\r
1858 // with that sequence, SPI086
\r
1859 if (Spi_ShareJobs(Sequence, i)) {
\r
1868 //-------------------------------------------------------------------
\r
1877 Std_ReturnType Spi_SyncTransmit(Spi_SequenceType Sequence) {
\r
1879 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_SYNCTRANSMIT_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
1880 VALIDATE_W_RV( ( SPI_MAX_SEQUENCE>Sequence ), SPI_SYNCTRANSMIT_SERVICE_ID, SPI_E_PARAM_SEQ, E_NOT_OK );
\r
1881 Std_ReturnType rv = E_OK;
\r
1883 if (Spi_GetSequenceResult(Sequence) == SPI_SEQ_PENDING) {
\r
1884 DEBUG(DEBUG_LOW,"%s: Spi_AsyncTransmit() is PENDING\n",MODULE_NAME);
\r
1885 return E_NOT_OK; // SPI157
\r
1888 assert(Spi_GetSequenceResult(Sequence) == SPI_SEQ_OK);
\r
1890 if (Spi_AnyPendingJobs(Sequence)) {
\r
1894 Spi_SeqWrite(Sequence, SPI_SYNC_CALL);
\r
1899 //-------------------------------------------------------------------
\r
1901 Std_ReturnType Spi_AsyncTransmit(Spi_SequenceType Sequence) {
\r
1902 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_ASYNCTRANSMIT_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
1903 VALIDATE_W_RV( ( SPI_MAX_SEQUENCE>Sequence ), SPI_ASYNCTRANSMIT_SERVICE_ID, SPI_E_PARAM_SEQ, E_NOT_OK );
\r
1905 if (Spi_GetSequenceResult(Sequence) == SPI_SEQ_PENDING) {
\r
1906 DEBUG(DEBUG_LOW,"%s: Spi_AsyncTransmit() is PENDING\n",MODULE_NAME);
\r
1907 return E_NOT_OK; // SPI157
\r
1910 assert(Spi_GetSequenceResult(Sequence) == SPI_SEQ_OK);
\r
1912 if (Spi_AnyPendingJobs(Sequence)) {
\r
1916 DEBUG(DEBUG_LOW,"%s: Starting seq: %d\n",MODULE_NAME,Sequence);
\r
1918 Spi_SeqWrite(Sequence, SPI_ASYNC_CALL);
\r
1923 //-------------------------------------------------------------------
\r
1926 Std_ReturnType Spi_ReadIB( Spi_ChannelType Channel,
\r
1927 Spi_DataType * const DataBufferPtr)
\r
1929 (void)DataBufferPtr;
\r
1931 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_READIB_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
1932 VALIDATE_W_RV( ( Channel<SPI_MAX_CHANNEL ), SPI_READIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
1933 VALIDATE_W_RV( ( SPI_IB<Spi_Global.configPtr->SpiChannelConfig[Channel].SpiChannelType ),
\r
1934 SPI_READIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
1936 /* NOT SUPPORTED */
\r
1938 Std_ReturnType rv = E_NOT_OK;
\r
1942 //-------------------------------------------------------------------
\r
1944 Std_ReturnType Spi_SetupEB( Spi_ChannelType Channel,
\r
1945 const Spi_DataType* SrcDataBufferPtr,
\r
1946 Spi_DataType* DesDataBufferPtr,
\r
1947 Spi_NumberOfDataType Length)
\r
1949 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_SETUPEB_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
1950 VALIDATE_W_RV( ( Channel<SPI_MAX_CHANNEL ), SPI_SETUPEB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
1951 #if ( SPI_CHANNEL_BUFFERS_ALLOWED == 1 )
\r
1952 VALIDATE_W_RV( ( SPI_EB==Spi_Global.configPtr->SpiChannelConfig[Channel].SpiChannelType ),
\r
1953 SPI_SETUPEB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
1956 VALIDATE_W_RV( ( Length<=Spi_Global.configPtr->SpiChannelConfig[Channel].SpiEbMaxLength ),
\r
1957 SPI_SETUPEB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
1959 Spi_EbType *extChBuff = &Spi_Global.extBufPtr[Channel];
\r
1960 const Spi_ChannelConfigType *chConfig =
\r
1961 &Spi_Global.configPtr->SpiChannelConfig[Channel];
\r
1963 if (chConfig->SpiChannelType == SPI_EB) {
\r
1964 extChBuff->src = SrcDataBufferPtr;
\r
1965 extChBuff->dest = DesDataBufferPtr;
\r
1966 extChBuff->length = Length;
\r
1967 extChBuff->active = 1;
\r
1969 /* NOT SUPPORTED */
\r
1978 //-------------------------------------------------------------------
\r
1980 Spi_StatusType Spi_GetStatus(void) {
\r
1981 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_GETSTATUS_SERVICE_ID, SPI_E_UNINIT, SPI_UNINIT );
\r
1983 // Check all sequences if they have any job pending
\r
1984 for (int i = 0; i < SPI_MAX_SEQUENCE; i++) {
\r
1985 if (Spi_GetSequenceResult(i) == SPI_SEQ_PENDING) {
\r
1993 //-------------------------------------------------------------------
\r
1996 Spi_JobResultType Spi_GetJobResult(Spi_JobType Job) {
\r
1997 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_GETJOBRESULT_SERVICE_ID, SPI_E_UNINIT, SPI_JOB_FAILED );
\r
1998 VALIDATE_W_RV( ( SPI_MAX_JOB<Job ), SPI_GETJOBRESULT_SERVICE_ID, SPI_E_PARAM_JOB, SPI_JOB_FAILED );
\r
2000 return Spi_JobUnit[Job].jobResult;
\r
2003 //-------------------------------------------------------------------
\r
2006 Spi_SeqResultType Spi_GetSequenceResult(Spi_SequenceType Sequence) {
\r
2007 Spi_SeqResultType rv;
\r
2009 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_GETSEQUENCERESULT_SERVICE_ID, SPI_E_UNINIT, SPI_SEQ_FAILED );
\r
2010 VALIDATE_W_RV( ( SPI_MAX_SEQUENCE>Sequence ), SPI_GETSEQUENCERESULT_SERVICE_ID, SPI_E_PARAM_SEQ, SPI_SEQ_FAILED );
\r
2012 rv = Spi_SeqUnit[Sequence].seqResult;
\r
2017 //-------------------------------------------------------------------
\r
2019 Spi_StatusType Spi_GetHWUnitStatus(Spi_HWUnitType HWUnit) {
\r
2020 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_GETHWUNITSTATUS_SERVICE_ID, SPI_E_UNINIT, SPI_UNINIT );
\r
2022 return (GET_SPI_UNIT_PTR(HWUnit))->status;
\r
2025 //-------------------------------------------------------------------
\r
2027 #if (SPI_CANCEL_API == STD_ON )
\r
2028 void Spi_Cancel( Spi_SequenceType Sequence ) {
\r
2029 VALIDATE( ( TRUE == Spi_Global.initRun ), SPI_CANCEL_SERVICE_ID, SPI_E_UNINIT );
\r
2030 VALIDATE( ( SPI_MAX_SEQUENCE<Sequence ), SPI_CANCEL_SERVICE_ID, SPI_E_PARAM_SEQ );
\r
2032 /* NOT SUPPORTED */
\r
2036 //-------------------------------------------------------------------
\r
2039 #if ( SPI_LEVEL_DELIVERED == 2) // SPI154
\r
2040 Std_ReturnType Spi_SetAsyncMode(Spi_AsyncModeType Mode) {
\r
2041 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_SETASYNCMODE_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
2044 // Not really sure by whom this function is supposed to be called by.
\r
2045 // The users of SPI(e2,flash,etc) should probably not use this.
\r
2047 for (int i = 0; i < SPI_MAX_SEQUENCE; i++) {
\r
2048 if (Spi_GetSequenceResult(i) == SPI_SEQ_PENDING) {
\r
2053 Spi_Global.asyncMode = Mode;
\r
2059 //-------------------------------------------------------------------
\r
2061 void Spi_MainFunction_Handling(void) {
\r
2062 /* NOT SUPPORTED */
\r
2065 //-------------------------------------------------------------------
\r
2067 void Spi_MainFunction_Driving(void) {
\r
2068 volatile struct DSPI_tag *spiHw;
\r
2071 Spi_UnitType *uPtr;
\r
2073 // TODO: check that the queue is empty.. if so do the next job.
\r
2074 if (Spi_Global.asyncMode == SPI_POLLING_MODE) {
\r
2075 confMask = Spi_Global.spiHwConfigured;
\r
2077 for (; confMask; confMask &= ~(1 << ctrlNr)) {
\r
2078 ctrlNr = ilog2(confMask);
\r
2079 uPtr = GET_SPI_UNIT_PTR(ctrlNr);
\r
2080 spiHw = uPtr->hwPtr;
\r
2082 if (Spi_GetHWUnitStatus(ctrlNr) == SPI_BUSY) {
\r
2083 if (spiHw->SR.B.TXRXS) {
\r
2084 // Still not done..
\r
2086 uPtr = GET_SPI_UNIT_PTR(ctrlNr);
\r