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 #define SPIE_BAD (-1)
\r
167 #define SPIE_JOB_NOT_DONE 1
\r
169 #if defined(CFG_MPC5604B)
\r
175 //#define SPI_IMPLEMENTATION SPI_FIFO
\r
176 #define USE_DIO_CS STD_ON
\r
178 // E2 read = cmd + addr + data = 1 + 2 + 64 ) = 67 ~ 72
\r
179 #define SPI_INTERNAL_MTU 72
\r
181 /* The depth of the HW FIFO */
\r
182 #define FIFO_DEPTH 4
\r
184 /* Define for debug purposes, checks that SPI/DMA is ok */
\r
185 //#define STEP_VALIDATION 1
\r
187 #define MODULE_NAME "/driver/Spi"
\r
189 //#define USE_LDEBUG_PRINTF 1
\r
191 #define DEBUG_LVL DEBUG_NONE
\r
194 //#define USE_LOCAL_RAMLOG
\r
195 #if defined(USE_LOCAL_RAMLOG)
\r
196 #define RAMLOG_STR(_x) ramlog_str(_x)
\r
197 #define RAMLOG_DEC(_x) ramlog_dec(_x)
\r
198 #define RAMLOG_HEX(_x) ramlog_hex(_x)
\r
200 #define RAMLOG_STR(_x)
\r
201 #define RAMLOG_DEC(_x)
\r
202 #define RAMLOG_HEX(_x)
\r
205 #define SPI_ASSERT(_exp) if( !(_exp) ) while(1) {}
\r
207 /* ----------------------------[private macro]-------------------------------*/
\r
210 #define MIN(_x,_y) (((_x) < (_y)) ? (_x) : (_y))
\r
213 #define MAX(_x,_y) (((_x) > (_y)) ? (_x) : (_y))
\r
216 #define GET_SPI_HW_PTR(_unit) \
\r
217 ((volatile struct DSPI_tag *)(0xFFF90000 + 0x4000*(_unit)))
\r
219 #define GET_SPI_UNIT_PTR(_unit) &Spi_Unit[Spi_CtrlToUnit[_unit]]
\r
221 #define ENABLE_EOQ_INTERRUPT(_spi_hw) _spi_hw->RSER.B.EOQF_RE = 1
\r
222 #define DISABLE_EOQ_INTERRUPT(_spi_hw) _spi_hw->RSER.B.EOQF_RE = 0
\r
224 #define GET_HW(_channel) ( volatile struct DSPI_tag *)((uint32)&DSPI_A + 0x4000 * _channel )
\r
226 /* Development error macros. */
\r
227 #if ( SPI_DEV_ERROR_DETECT == STD_ON )
\r
228 #define VALIDATE(_exp,_api,_err ) \
\r
230 Det_ReportError(MODULE_ID_SPI,0,_api,_err); \
\r
234 #define VALIDATE_W_RV(_exp,_api,_err,_rv ) \
\r
236 Det_ReportError(MODULE_ID_SPI,0,_api,_err); \
\r
240 #define VALIDATE(_exp,_api,_err )
\r
241 #define VALIDATE_W_RV(_exp,_api,_err,_rv )
\r
244 /* ----------------------------[private typedef]-----------------------------*/
\r
246 #if (SPI_IMPLEMENTATION == SPI_DMA )
\r
247 typedef struct Spi_DmaConfig {
\r
248 Dma_ChannelType RxDmaChannel;
\r
249 Dma_ChannelType TxDmaChannel;
\r
250 } Spi_DmaConfigType;
\r
262 vuint32_t CTCNT :1;
\r
270 vuint32_t TXDATA :16;
\r
274 typedef SPICommandType Spi_CommandType;
\r
276 const Spi_DataType * src; /* Pointer to source buffer */
\r
277 Spi_DataType * dest; /* Pointer to destination buffer */
\r
278 Spi_NumberOfDataType length; // Number of elements of Spi_DataType in destination buffer
\r
279 _Bool active; // Set if the buffer is configured.
\r
285 } Spi_CallTypeType;
\r
288 uint8 ctarId; // this channel is assigned to this CTAR
\r
289 } Spi_ChannelInfoType;
\r
292 * This structure represents a controller unit
\r
296 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
297 Dma_ChannelType dmaTxChannel; // Tx DMA channel information
\r
298 Dma_TcdType dmaTxTCD;
\r
299 Dma_ChannelType dmaRxChannel; // Rx DMA channel information
\r
300 Dma_TcdType dmaRxTCD;
\r
301 Spi_CommandType txQueue[SPI_INTERNAL_MTU]; // Pointed to by SADDR of DMA
\r
302 uint32 rxQueue[SPI_INTERNAL_MTU]; // Pointed to by DADDR of DMA
\r
304 uint32 txCurrIndex; // current index for data when sending
\r
305 uint32 channelCodes[(CTAR_CNT-1)]; // Helper array to assign CTAR's
\r
306 Spi_StatusType status; // Status for this unit
\r
307 const Spi_JobConfigType * currJob; // The current job
\r
308 const Spi_JobType * currJobIndexPtr; // Points array of jobs current
\r
309 Spi_JobType currJobIndex;
\r
310 const Spi_SequenceConfigType * currSeqPtr; // The Sequence
\r
311 Spi_CallTypeType callType; // 1 - if the current job is sync. 0 - if not
\r
312 volatile struct DSPI_tag * hwPtr;
\r
313 uint8 hwUnit; // 0...
\r
317 Spi_SeqResultType seqResult;
\r
321 volatile struct DSPI_tag * hwPtr; /* The HW device used by this Job */
\r
322 const Spi_ExternalDeviceType * extDeviceCfgPtr; /* The external device used by this job */
\r
323 const Spi_JobConfigType * jobCfgPtr;
\r
324 Spi_UnitType * unitPtr;
\r
325 const Spi_ChannelType * channelsPtr;
\r
326 #if (SPI_IMPLEMENTATION == SPI_FIFO )
\r
327 uint32_t fifoSent; /* Number of bytes in FIFO (before EOQ is set) */
\r
328 uint8_t currTxChIndex; /* the currently transmitting channel index for FIFO */
\r
329 uint32_t txChCnt; /* number of Spi_DataType sent for the current channel */
\r
330 uint32_t rxChCnt; /* number of Spi_DataType received for the current channel */
\r
331 uint32_t currRxChIndex; /* the currently receiving channel index for FIFO */
\r
333 Spi_JobResultType jobResult;
\r
337 boolean initRun; // Initially FALSE set to TRUE if Spi_Init() have been called
\r
338 const Spi_ConfigType * configPtr; // Pointer to the configuration
\r
339 Spi_EbType * extBufPtr; // Pointer to the external buffers
\r
340 Spi_ChannelInfoType * channelInfo;
\r
341 uint32 spiHwConfigured; // Mask if the HW unit is configured or not
\r
342 Spi_AsyncModeType asyncMode;
\r
344 /* This is a bunch of debug counters. */
\r
345 uint32 totalNbrOfTranfers;
\r
346 uint32 totalNbrOfStartedJobs;
\r
347 /* Counters for busy waiting for DSPI and DMA. */
\r
348 uint32 totalNbrOfWaitTXRXS;
\r
349 uint32 totalNbrOfWaitRxDMA;
\r
350 #if defined(STEP_VALIDATION)
\r
356 /* ----------------------------[private function prototypes]-----------------*/
\r
357 /* ----------------------------[private variables]---------------------------*/
\r
359 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
360 /* Templates for Rx/Tx DMA structures */
\r
361 const Dma_TcdType Spi_DmaTx = {
\r
362 .SADDR = 0, .SMOD = 0, .SSIZE = DMA_TRANSFER_SIZE_32BITS, .DMOD = 0,
\r
363 .DSIZE = DMA_TRANSFER_SIZE_32BITS, .SOFF = 4, .NBYTESu.R = 4, .SLAST = 0,
\r
364 .DADDR = 0, .CITERE_LINK = 0, .CITER = 0, .DOFF = 0, .DLAST_SGA = 0,
\r
365 .BITERE_LINK = 0, .BITER = 0, .BWC = 0, .MAJORLINKCH = 0, .DONE = 0,
\r
366 .ACTIVE = 0, .MAJORE_LINK = 0, .E_SG = 0, .D_REQ = 0, .INT_HALF = 0,
\r
367 .INT_MAJ = 0, .START = 0 };
\r
369 const Dma_TcdType Spi_DmaRx = { .SADDR = 0, .SMOD = 0,
\r
370 .SSIZE = DMA_TRANSFER_SIZE_32BITS, .DMOD = 0,
\r
371 .DSIZE = DMA_TRANSFER_SIZE_32BITS, .SOFF = 0, .NBYTESu.R = 4, .SLAST = 0,
\r
372 .DADDR = 0, .CITERE_LINK = 0, .CITER = 1, .DOFF = 4, .DLAST_SGA = 0,
\r
373 .BITERE_LINK = 0, .BITER = 1, .BWC = 0, .MAJORLINKCH = 0, .DONE = 0,
\r
374 .ACTIVE = 0, .MAJORE_LINK = 0, .E_SG = 0, .D_REQ = 0, .INT_HALF = 0,
\r
375 #if defined(__DMA_INT)
\r
383 Spi_GlobalType Spi_Global;
\r
384 Spi_EbType Spi_Eb[SPI_MAX_CHANNEL];
\r
385 Spi_UnitType Spi_Unit[SPI_CONTROLLER_CNT];
\r
386 Spi_SeqUnitType Spi_SeqUnit[SPI_MAX_SEQUENCE];
\r
387 Spi_JobUnitType Spi_JobUnit[SPI_MAX_JOB];
\r
388 Spi_ChannelInfoType Spi_ChannelInfo[SPI_MAX_CHANNEL];
\r
389 uint8 Spi_CtrlToUnit[4];
\r
392 #if (SPI_IMPLEMENTATION == SPI_DMA)
\r
393 /* When using DMA it assumes predefined names */
\r
394 Spi_DmaConfigType Spi_DmaConfig[SPI_CONTROLLER_CNT] = {
\r
395 #if (SPI_USE_HW_UNIT_0 == STD_ON )
\r
397 .RxDmaChannel = DMA_DSPI_A_RESULT_CHANNEL,
\r
398 .TxDmaChannel = DMA_DSPI_A_COMMAND_CHANNEL,
\r
401 #if (SPI_USE_HW_UNIT_1 == STD_ON )
\r
403 .RxDmaChannel = DMA_DSPI_B_RESULT_CHANNEL,
\r
404 .TxDmaChannel = DMA_DSPI_B_COMMAND_CHANNEL,
\r
407 #if (SPI_USE_HW_UNIT_2 == STD_ON )
\r
409 .RxDmaChannel = DMA_DSPI_C_RESULT_CHANNEL,
\r
410 .TxDmaChannel = DMA_DSPI_C_COMMAND_CHANNEL,
\r
413 #if (SPI_USE_HW_UNIT_3 == STD_ON )
\r
415 .RxDmaChannel = DMA_DSPI_D_RESULT_CHANNEL,
\r
416 .TxDmaChannel = DMA_DSPI_D_COMMAND_CHANNEL,
\r
422 /* ----------------------------[private functions]---------------------------*/
\r
424 #if (SPI_IMPLEMENTATION == SPI_FIFO )
\r
425 static void Spi_WriteJob_FIFO( Spi_JobType jobIndex );
\r
428 * Get the buffer for a channel.
\r
434 static Spi_DataType *spiGetRxBuf(Spi_ChannelType ch, Spi_NumberOfDataType *length ) {
\r
436 if( Spi_Global.configPtr->SpiChannelConfig[ch].SpiChannelType == SPI_EB ) {
\r
437 *length = Spi_Global.extBufPtr[ch].length;
\r
438 buf = Spi_Global.extBufPtr[ch].dest;
\r
447 static const Spi_DataType *spiGetTxBuf(Spi_ChannelType ch, Spi_NumberOfDataType *length ) {
\r
448 const Spi_DataType *buf;
\r
449 if( Spi_Global.configPtr->SpiChannelConfig[ch].SpiChannelType == SPI_EB ) {
\r
450 *length = Spi_Global.extBufPtr[ch].length;
\r
451 buf = Spi_Global.extBufPtr[ch].src;
\r
461 static void Spi_Isr(Spi_UnitType *uPtr );
\r
463 static void Spi_Isr_A(void) {
\r
464 Spi_Isr(GET_SPI_UNIT_PTR(DSPI_CTRL_A));
\r
466 static void Spi_Isr_B(void) {
\r
467 Spi_Isr(GET_SPI_UNIT_PTR(DSPI_CTRL_B));
\r
469 static void Spi_Isr_C(void) {
\r
470 Spi_Isr(GET_SPI_UNIT_PTR(DSPI_CTRL_C));
\r
472 static void Spi_Isr_D(void) {
\r
473 Spi_Isr(GET_SPI_UNIT_PTR(DSPI_CTRL_D));
\r
475 /* ----------------------------[public functions]----------------------------*/
\r
477 uint32 Spi_GetJobCnt(void);
\r
478 uint32 Spi_GetChannelCnt(void);
\r
479 uint32 Spi_GetExternalDeviceCnt(void);
\r
482 static void Spi_Isr_DMA( void )
\r
485 Dma_ClearInterrupt(5);
\r
489 static void Spi_JobWrite(Spi_JobType jobIndex);
\r
491 static void Spi_SetJobResult(Spi_JobType Job, Spi_JobResultType result) {
\r
492 Spi_JobUnit[Job].jobResult = result;
\r
496 static void Spi_SetHWUnitStatus( Spi_UnitType *uPtr, Spi_StatusType status) {
\r
497 uPtr->status = status;
\r
500 static void Spi_SetHWUnitStatus(Spi_HWUnitType HWUnit, Spi_StatusType status) {
\r
501 Spi_Unit[Spi_CtrlToUnit[HWUnit]].status = status;
\r
506 * Get external Ptr to device from index
\r
508 * @param deviceType The device index.
\r
509 * @return Ptr to the external device
\r
512 static inline const Spi_ExternalDeviceType *Spi_GetExternalDevicePtrFromIndex(
\r
513 Spi_ExternalDeviceTypeType deviceType) {
\r
514 return (&(Spi_Global.configPtr->SpiExternalDevice[(deviceType)]));
\r
518 * Get configuration job ptr from job index
\r
519 * @param jobIndex the job
\r
520 * @return Ptr to the job configuration
\r
522 static const Spi_JobConfigType *Spi_GetJobPtrFromIndex(Spi_JobType jobIndex) {
\r
523 return &Spi_Global.configPtr->SpiJobConfig[jobIndex];
\r
527 * Get sequence ptr from sequence index
\r
528 * @param seqIndex the sequence
\r
529 * @return Ptr to the sequence configuration
\r
531 static const Spi_SequenceConfigType *Spi_GetSeqPtrFromIndex(
\r
532 Spi_SequenceType SeqIndex) {
\r
533 return &Spi_Global.configPtr->SpiSequenceConfig[SeqIndex];
\r
537 * Get unit ptr from unit index
\r
538 * @param unit the unit
\r
539 * @return Ptr to the SPI unit
\r
541 static Spi_UnitType *Spi_GetUnitPtrFromIndex(uint32 unit) {
\r
542 return &Spi_Unit[Spi_CtrlToUnit[unit]];
\r
546 * Function to see if two sequences share jobs
\r
548 * @param seq - Seqence 1
\r
549 * @param seq - Seqence 2
\r
550 * @return 0 - if the don't share any jobs
\r
551 * !=0 - if they share jobs
\r
554 static boolean Spi_ShareJobs(Spi_SequenceType seq1, Spi_SequenceType seq2) {
\r
555 uint32 seqMask1 = 0;
\r
556 uint32 seqMask2 = 0;
\r
557 const Spi_JobType *jobPtr;
\r
558 const Spi_SequenceConfigType *seqConfig;
\r
560 // Search for jobs in sequence 1
\r
561 seqConfig = Spi_GetSeqPtrFromIndex(seq1);
\r
562 jobPtr = &seqConfig->JobAssignment[0];
\r
564 while (*jobPtr != JOB_NOT_VALID) {
\r
565 assert(*jobPtr<31);
\r
566 seqMask1 |= (1 << *jobPtr);
\r
570 // Search for jobs in sequence 2
\r
571 seqConfig = Spi_GetSeqPtrFromIndex(seq2);
\r
572 jobPtr = &seqConfig->JobAssignment[0];
\r
574 while (*jobPtr != JOB_NOT_VALID) {
\r
575 assert(*jobPtr<31);
\r
576 seqMask2 |= (1 << *jobPtr);
\r
580 return (seqMask1 & seqMask2);
\r
584 //-------------------------------------------------------------------
\r
587 * Sets a result for a sequence
\r
589 * @param Sequence The sequence to set the result for
\r
590 * @param result The result to set.
\r
592 static void Spi_SetSequenceResult(Spi_SequenceType Sequence,
\r
593 Spi_SeqResultType result) {
\r
594 Spi_SeqUnit[Sequence].seqResult = result;
\r
597 //-------------------------------------------------------------------
\r
601 * Gets the next job to do
\r
603 * @param spiUnit The SPI unit
\r
604 * @return The job ID. -1 if no more jobs
\r
606 static Spi_JobType Spi_GetNextJob(Spi_UnitType *spiUnit) {
\r
607 spiUnit->currJobIndexPtr++;
\r
608 return *(spiUnit->currJobIndexPtr);
\r
610 //-------------------------------------------------------------------
\r
613 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
616 * Function to handle things after a transmit on the SPI is finished.
\r
617 * It copies data from it't local buffers to the buffers pointer to
\r
618 * by the external buffers
\r
620 * @param spiUnit Ptr to a SPI unit
\r
623 static int Spi_Rx_DMA(Spi_UnitType *spiUnit) {
\r
624 _Bool printedSomeThing = 0;
\r
626 /* Stop the channels */
\r
627 Dma_StopChannel(spiUnit->dmaTxChannel);
\r
628 Dma_StopChannel(spiUnit->dmaRxChannel);
\r
630 RAMLOG_STR("PostTransmit Job: "); RAMLOG_DEC(spiUnit->currJob->SpiJobId); RAMLOG_STR("\n");
\r
632 /* Copy data from RX queue to the external buffer( if a<uny ) */
\r
637 const Spi_ChannelConfigType *chConfig;
\r
638 Spi_EbType *extChBuff;
\r
642 // Check that we got the number of bytes we sent
\r
643 sentTx = spiUnit->txCurrIndex + 1;
\r
644 gotTx = (Dma_GetTcd(spiUnit->dmaRxChannel)->DADDR
\r
645 - (uint32) &spiUnit->rxQueue[0]) / sizeof(uint32);
\r
647 if (sentTx != gotTx) {
\r
648 // Something failed
\r
649 DEBUG(DEBUG_LOW,"%s: Expected %d bytes. Got %d bytes\n ",MODULE_NAME,sentTx, gotTx );
\r
650 #if defined(STEP_VALIDATION)
\r
655 RAMLOG_STR("Rx "); RAMLOG_DEC(gotTx); RAMLOG_STR(" Bytes\n"); DEBUG(DEBUG_LOW,"%s: Got %d bytes\n",MODULE_NAME,gotTx);
\r
658 // Find the channels for this job
\r
659 while ((channelIndex = spiUnit->currJob->ChannelAssignment[j++])
\r
661 chConfig = &Spi_Global.configPtr->SpiChannelConfig[channelIndex];
\r
663 /* Check configuration error */
\r
664 #if ( SPI_CHANNEL_BUFFERS_ALLOWED == 1 )
\r
665 assert( chConfig->SpiChannelType == SPI_EB );
\r
668 // Send the channels that are setup with external buffers
\r
669 // Get the external buffer for this channel
\r
670 extChBuff = &Spi_Global.extBufPtr[channelIndex];
\r
671 if (extChBuff->dest != NULL) {
\r
672 // Note! No support for >8 "data"
\r
673 for (int k = 0; k < extChBuff->length; k++) {
\r
674 extChBuff->dest[k] = spiUnit->rxQueue[currIndex++];
\r
675 DEBUG(DEBUG_LOW," %02x ",extChBuff->dest[k]);
\r
676 printedSomeThing = 1;
\r
680 if (chConfig->SpiDataWidth > 8) {
\r
681 currIndex += (extChBuff->length / 2);
\r
683 currIndex += extChBuff->length;
\r
687 if (printedSomeThing)
\r
688 DEBUG(DEBUG_LOW,"\n");
\r
694 #elif (SPI_IMPLEMENTATION==SPI_FIFO)
\r
696 static int Spi_Rx_FIFO(Spi_UnitType *spiUnit) {
\r
697 Spi_JobUnitType * jobUnitPtr;
\r
698 Spi_DataType * buf;
\r
701 Spi_ChannelType currChannel;
\r
702 Spi_NumberOfDataType bufLen;
\r
704 int rv = SPIE_JOB_NOT_DONE;
\r
705 const Spi_ChannelConfigType * chConfig;
\r
709 // RAMLOG_STR("PostTransmit Job: "); RAMLOG_DEC(spiUnit->currJob->SpiJobId); RAMLOG_STR("\n");
\r
710 RAMLOG_STR("Spi_Rx_FIFO\n");
\r
712 jobUnitPtr = &Spi_JobUnit[spiUnit->currJobIndex];
\r
714 if( jobUnitPtr->hwPtr->TCR.B.SPI_TCNT != jobUnitPtr->fifoSent ) {
\r
715 #if defined(STEP_VALIDATION)
\r
722 * Fill receive buffers, either EB or IB
\r
723 * Example with 8-bit CMD, 16-bit ADDR and some 8-bit data.
\r
724 * CMD | ADDR | DATA
\r
725 * | 12 | 23 | 34 | 00 | 01 | 02 | 03
\r
726 * 1 2 3 4 5 6 BYTE CNT
\r
727 * 1 2 3 4 (5) (6) FIFO
\r
728 * With a FIFO of 4 we can see that the CMD, ADDR and almost the whole
\r
729 * DATA channel is sent.
\r
731 currChannel = jobUnitPtr->channelsPtr[jobUnitPtr->currRxChIndex];
\r
732 assert( currChannel != CH_NOT_VALID );
\r
734 if( jobUnitPtr->fifoSent != jobUnitPtr->hwPtr->SR.B.RXCTR ) {
\r
735 #if defined(STEP_VALIDATION)
\r
741 while ( jobUnitPtr->fifoSent != 0 ) {
\r
743 chConfig = &Spi_Global.configPtr->SpiChannelConfig[currChannel];
\r
745 RAMLOG_STR("CIR#");RAMLOG_DEC(jobUnitPtr->currRxChIndex);RAMLOG_STR("\n");
\r
747 /* Get this channels destination buffer */
\r
748 buf = spiGetRxBuf(currChannel, &bufLen);
\r
749 assert(bufLen!=0); /* We should always get a valid bufLen */
\r
751 copyCnt = MIN( (bufLen - jobUnitPtr->rxChCnt) >> ((chConfig->SpiDataWidth-1)/8), jobUnitPtr->fifoSent );
\r
753 if( copyCnt == 0 ) {
\r
754 #if defined(STEP_VALIDATION)
\r
760 jobUnitPtr->fifoSent -= copyCnt;
\r
762 bInChar = (chConfig->SpiDataWidth > 8 ) ? 2 : 1;
\r
765 if( buf != NULL ) {
\r
766 for(i=0;i<copyCnt;i++) {
\r
767 popVal = jobUnitPtr->hwPtr->POPR.B.RXDATA;
\r
768 RAMLOG_STR("%");RAMLOG_HEX(popVal);
\r
769 buf[jobUnitPtr->rxChCnt] = (Spi_DataType)popVal;
\r
770 jobUnitPtr->rxChCnt += bInChar;
\r
773 for(i=0;i<copyCnt;i++) {
\r
774 popVal = jobUnitPtr->hwPtr->POPR.B.RXDATA;
\r
775 jobUnitPtr->rxChCnt += bInChar;
\r
779 if( (bufLen - jobUnitPtr->rxChCnt ) == 0 ) {
\r
780 /* advance to the next channel */
\r
781 jobUnitPtr->rxChCnt = 0;
\r
782 jobUnitPtr->currRxChIndex++;
\r
783 currChannel = jobUnitPtr->channelsPtr[jobUnitPtr->currRxChIndex];
\r
784 if( currChannel == CH_NOT_VALID ) {
\r
785 //assert( jobUnitPtr->fifoSent == 0);
\r
786 jobUnitPtr->fifoSent = 0;
\r
787 jobUnitPtr->currRxChIndex = 0;
\r
795 #if defined(STEP_VALIDATION)
\r
796 /* Check if we are done with this job */
\r
797 if( 0 != jobUnitPtr->hwPtr->SR.B.RXCTR ) {
\r
807 //-------------------------------------------------------------------
\r
810 * ISR for End of Queue interrupt
\r
812 * The interrupt handling is quite simple. Since this driver assumes
\r
813 * that we are the master the EOQ interrupt is sufficient to check.
\r
815 * @param unit The HW unit it happend on
\r
817 static void Spi_Isr( Spi_UnitType *uPtr) {
\r
818 volatile struct DSPI_tag *spiHw = uPtr->hwPtr;
\r
821 RAMLOG_STR("Spi_Isr\n");
\r
823 // This may seem pretty stupid to wait for the controller
\r
824 // to shutdown here, but there seems to be no other way to do this.
\r
826 // - Waiting for DMA rx/tx hits earlier than EOQ.
\r
827 // - Other interrupts from SPI all hit earlier than EOQ.
\r
828 // TODO: There is the TCF_RE bit! Use this instead?
\r
830 // TODO: We could implement a timeout here and fail the job
\r
831 // if this never happens.
\r
833 // This is the busy wait when called from a non-interrupt context
\r
834 while (spiHw->SR.B.TXRXS) {
\r
835 Spi_Global.totalNbrOfWaitTXRXS++;
\r
838 #if (SPI_IMPLEMENTATION == SPI_DMA)
\r
839 while (!Dma_ChannelDone(uPtr->dmaRxChannel)) {
\r
840 Spi_Global.totalNbrOfWaitRxDMA++;
\r
844 #if defined(STEP_VALIDATION)
\r
845 /* Since EOQF clears TXRXS */
\r
846 SPI_ASSERT( (spiHw->SR.B.EOQF==1) && (spiHw->SR.B.TXRXS == 0));
\r
849 /* Halt DSPI unit until we are ready for next transfer. */
\r
850 spiHw->MCR.B.HALT = 1;
\r
851 spiHw->SR.B.EOQF = 1;
\r
854 Spi_Global.totalNbrOfTranfers++;
\r
856 // Disable EOQ interrupts
\r
858 // This does NOT clear the interrupt request.
\r
859 // That can only be done by clearing( setting ) the EOQ
\r
860 // bit.. but that also triggers a new transfer.
\r
863 // A possibility could be to use the HALT bit instead of
\r
864 // using this trick, but hey, this works
\r
866 DISABLE_EOQ_INTERRUPT(spiHw);
\r
868 // Update external buffers
\r
869 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
870 rv = Spi_Rx_DMA(uPtr);
\r
872 #if (USE_DIO_CS == STD_ON)
\r
873 void (*cb)(int) = Spi_JobUnit[uPtr->currJobIndex].extDeviceCfgPtr->SpiCsCallback;
\r
878 #elif (SPI_IMPLEMENTATION==SPI_FIFO)
\r
879 rv = Spi_Rx_FIFO(uPtr);
\r
881 if( rv == SPIE_JOB_NOT_DONE ) {
\r
882 /* RX FIFO now empty, but the job is not done -> send more */
\r
883 Spi_WriteJob_FIFO ( uPtr->currJobIndex );
\r
884 RAMLOG_STR("Spi_Isr END\n");
\r
887 #if (USE_DIO_CS == STD_ON)
\r
889 void (*cb)(int) = Spi_JobUnit[uPtr->currJobIndex].extDeviceCfgPtr->SpiCsCallback;
\r
897 // Call notification end
\r
898 if (uPtr->currJob->SpiJobEndNotification != NULL) {
\r
899 uPtr->currJob->SpiJobEndNotification();
\r
902 if (rv == SPIE_BAD) {
\r
903 // Fail both job and sequence
\r
904 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);
\r
905 Spi_SetJobResult(uPtr->currJob->SpiJobId, SPI_JOB_FAILED);
\r
906 Spi_SetSequenceResult(uPtr->currSeqPtr->SpiSequenceId,
\r
908 #if defined(STEP_VALIDATION)
\r
912 Spi_JobType nextJob;
\r
914 // The job is at least done..
\r
915 Spi_SetJobResult(uPtr->currJob->SpiJobId, SPI_JOB_OK);
\r
917 // WriteNextJob should
\r
918 // 1. Update the JobResult to SPI_JOB_OK
\r
919 // 2. Update the HWUnit status to IDLE
\r
922 // - Jobs have the controller
\r
923 // - Sequences can we interruptible between jobs.
\r
925 // According to SPI086 you can't share a job with a sequence that
\r
926 // is in SPI_SEQ_PENDING ( that happens first thing at Spi_AsyncTranmit() )
\r
928 // So, I no clue what to use the priority thing for :(
\r
930 nextJob = Spi_GetNextJob(uPtr);
\r
931 if( nextJob != JOB_NOT_VALID ) {
\r
932 Spi_JobWrite(nextJob);
\r
933 RAMLOG_STR("more_jobs\n");
\r
935 // No more jobs, so set HwUnit and sequence IDLE/OK also.
\r
936 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);
\r
937 Spi_SetSequenceResult(uPtr->currSeqPtr->SpiSequenceId,
\r
940 if (uPtr->currSeqPtr->SpiSeqEndNotification != NULL) {
\r
941 uPtr->currSeqPtr->SpiSeqEndNotification();
\r
944 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);
\r
946 /* We are now ready for next transfer. */
\r
947 spiHw->MCR.B.HALT = 1;
\r
949 RAMLOG_STR("NO_more_jobs\n");
\r
953 RAMLOG_STR("Spi_Isr END\n");
\r
956 //-------------------------------------------------------------------
\r
958 Std_ReturnType Spi_WriteIB(Spi_ChannelType Channel,
\r
959 const Spi_DataType *DataBufferPtr) {
\r
960 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_WRITEIB_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
961 VALIDATE_W_RV( ( Channel<SPI_MAX_CHANNEL ), SPI_WRITEIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
962 VALIDATE_W_RV( ( DataBufferPtr != NULL ), SPI_WRITEIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
963 VALIDATE_W_RV( ( SPI_IB==Spi_Global.configPtr->SpiChannelConfig[Channel].SpiChannelType ),
\r
964 SPI_WRITEIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
966 /* According to SPI051 it seems that we only have to a "depth" of 1 */
\r
969 Std_ReturnType rv = E_NOT_OK;
\r
974 const uint32 clk_table_asc[] = { 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
\r
975 4096, 8192, 16384, 32768, 65536 };
\r
976 const uint32 clk_table_cssck[] = { 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
\r
977 4096, 8192, 16384, 32768, 65536 };
\r
978 const uint16 clk_table_br[] = { 2, 4, 6, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
\r
979 4096, 8192, 16384, 32768 };
\r
980 const uint8 clk_table_pasc[] = { 1, 3, 5, 7 };
\r
981 const uint8 clk_table_pcssck[] = { 1, 3, 5, 7 };
\r
982 const uint8 clk_table_pbr[] = { 2, 3, 5, 7 };
\r
985 * Function to setup CTAR's from configuration
\r
986 * @param spiHw - Pointer to HW SPI device
\r
987 * @param extDev - Pointer to external device configuration
\r
988 * @param ctar_unit - The ctar unit number to setup
\r
989 * @param width - The width in bits of the data to send with the CTAR
\r
991 static void Spi_SetupCTAR( Spi_HWUnitType unit,
\r
992 const Spi_ExternalDeviceType *extDev,
\r
993 Spi_ChannelType ctar_unit,
\r
994 Spi_TransferStartType transferStart,
\r
1002 McuE_PeriperalClock_t perClock;
\r
1004 volatile struct DSPI_tag *spiHw = GET_SPI_HW_PTR(unit);
\r
1005 /* BAUDRATE CALCULATION
\r
1006 * -----------------------------
\r
1007 * Baudrate = Fsys/ PBR * ( 1+ DBR) / BR
\r
1008 * PBR range: 2 to 7
\r
1009 * DBR range: 0 to 1
\r
1012 * To make this easy set DBR = 0 and PBR=2
\r
1013 * --> BR=Fsys/(Baudrate.* 2 )
\r
1016 #if defined(CFG_MPC5516) || defined(CFG_MPC5517) || defined(CFG_MPC560X)
\r
1019 perClock = PERIPHERAL_CLOCK_DSPI_A;
\r
1022 perClock = PERIPHERAL_CLOCK_DSPI_B;
\r
1024 #if defined(CFG_MPC5516) || defined(CFG_MPC5517) || defined(CFG_MPC5604B)
\r
1026 perClock = PERIPHERAL_CLOCK_DSPI_C;
\r
1029 #if defined(CFG_MPC5516) || defined(CFG_MPC5517)
\r
1031 perClock = PERIPHERAL_CLOCK_DSPI_D;
\r
1039 #error CPU not supported
\r
1041 clock = McuE_GetPeripheralClock(perClock);
\r
1043 DEBUG(DEBUG_MEDIUM,"%s: Peripheral clock at %d Mhz\n",MODULE_NAME,clock);
\r
1045 DEBUG(DEBUG_MEDIUM,"%s: Want to run at %d Mhz\n",MODULE_NAME,extDev->SpiBaudrate);
\r
1047 spiHw->CTAR[ctar_unit].B.DBR = 0;
\r
1048 spiHw->CTAR[ctar_unit].B.PBR = 0; // 2
\r
1049 pre_br = clock / (extDev->SpiBaudrate
\r
1050 * clk_table_pbr[spiHw->CTAR[ctar_unit].B.PBR]);
\r
1052 // find closest lesser
\r
1053 for (i = 0; i < sizeof(clk_table_br) / sizeof(clk_table_br[0]); i++) {
\r
1054 if (clk_table_br[i] >= pre_br) {
\r
1061 spiHw->CTAR[ctar_unit].B.BR = i;
\r
1063 DEBUG(DEBUG_LOW,"%s: CLK %d Mhz\n",MODULE_NAME,
\r
1064 clock / clk_table_pbr[spiHw->CTAR[ctar_unit].B.PBR] *
\r
1065 ( 1 + spiHw->CTAR[ctar_unit].B.DBR)/clk_table_br[spiHw->CTAR[ctar_unit].B.BR]);
\r
1067 /* For other timings autosar only specifies SpiTimeClk2Cs == "After SCK delay"
\r
1068 * in Freescale language. The dumb thing is that this should be a relative time
\r
1069 * to the clock. Not fixed.
\r
1070 * Autosar specifies 0.0--100.0 ms(float)
\r
1071 * Our intepretation is 0--1000000 ns (uint32)
\r
1073 * AFTER SCK DELAY:
\r
1074 * -----------------------------
\r
1075 * Tasc = 1/Fsys * PASC * ASC [s]
\r
1077 * Assume the Tasc get's here in ns( typical range is ~10ns )
\r
1080 // Calc the PASC * ASC value...
\r
1081 tmp = extDev->SpiTimeClk2Cs * (clock / 1000000);
\r
1083 // Nothing fancy here...
\r
1087 int b_value = INT_MAX;
\r
1090 // Find the best match of Prescaler and Scaler value
\r
1091 for (i = 0; i < ARRAY_SIZE(clk_table_pasc); i++) {
\r
1092 for (j = 0; j < ARRAY_SIZE(clk_table_asc); j++) {
\r
1093 tt = abs((int) clk_table_pasc[i] * clk_table_asc[j] * 1000
\r
1095 if (tt < b_value) {
\r
1103 /* After SCK delay. */
\r
1104 spiHw->CTAR[ctar_unit].B.PASC = best_i;
\r
1105 spiHw->CTAR[ctar_unit].B.ASC = best_j;
\r
1108 DEBUG(DEBUG_MEDIUM,"%s: Timing: Tasc %d ns\n",MODULE_NAME,
\r
1109 clk_table_pasc[spiHw->CTAR[ctar_unit].B.PASC] *
\r
1110 clk_table_asc[spiHw->CTAR[ctar_unit].B.ASC] * 1000/ (clock/1000000) );
\r
1112 /* The PCS to SCK delay is the delay between the assertion of PCS and
\r
1113 * the first edge the SCK.
\r
1115 * PCS TO SCK DELAY:
\r
1116 * -----------------------------
\r
1117 * Tcsc = 1/Fsys * PCSSCK * CSSCK [s]
\r
1120 // Calc the PCSSCK * CSSCK value...
\r
1121 tmp = extDev->SpiTimeCs2Clk * (clock / 1000000);
\r
1123 // Nothing fancy here...
\r
1127 int b_value = INT_MAX;
\r
1130 // Find the best match of Prescaler and Scaler value
\r
1131 for (i = 0; i < ARRAY_SIZE(clk_table_pcssck); i++) {
\r
1132 for (j = 0; j < ARRAY_SIZE(clk_table_cssck); j++) {
\r
1133 tt = abs((int) clk_table_pcssck[i] * clk_table_cssck[j] * 1000
\r
1135 if (tt < b_value) {
\r
1143 /* PCS to SCK delay */
\r
1144 spiHw->CTAR[ctar_unit].B.PCSSCK = best_i;
\r
1145 spiHw->CTAR[ctar_unit].B.CSSCK = best_j;
\r
1148 DEBUG(DEBUG_MEDIUM,"%s: Timing: Tcsc %d ns\n",MODULE_NAME,
\r
1149 clk_table_pcssck[spiHw->CTAR[ctar_unit].B.PCSSCK] *
\r
1150 clk_table_cssck[spiHw->CTAR[ctar_unit].B.CSSCK]*1000/(clock/1000000));
\r
1152 /* Time that PCS is high between transfers */
\r
1153 spiHw->CTAR[ctar_unit].B.PDT = 2;
\r
1154 spiHw->CTAR[ctar_unit].B.DT = 2;
\r
1156 DEBUG(DEBUG_MEDIUM,"%s: Timing: Tdt %d ns\n",MODULE_NAME,
\r
1157 clk_table_pasc[spiHw->CTAR[ctar_unit].B.PDT] *
\r
1158 clk_table_asc[spiHw->CTAR[ctar_unit].B.DT]*1000/(clock/1000000));
\r
1160 /* Data is transferred MSB first */
\r
1162 spiHw->CTAR[ctar_unit].B.LSBFE = (transferStart == SPI_TRANSFER_START_MSB ) ? 0 : 1;
\r
1165 spiHw->CTAR[ctar_unit].B.FMSZ = width - 1;
\r
1166 spiHw->CTAR[ctar_unit].B.CPHA = (extDev->SpiDataShiftEdge
\r
1167 == SPI_EDGE_LEADING) ? 0 : 1;
\r
1168 spiHw->CTAR[ctar_unit].B.CPOL = (extDev->SpiShiftClockIdleLevel == STD_LOW) ? 0 : 1;
\r
1170 // This the ACTIVE polarity. Freescale have inactive polarity
\r
1171 if (extDev->SpiCsPolarity == STD_HIGH) {
\r
1172 spiHw->MCR.R &= ~(1 << (16 + extDev->SpiCsIdentifier));
\r
1174 spiHw->MCR.R |= (1 << (16 + extDev->SpiCsIdentifier));
\r
1178 //-------------------------------------------------------------------
\r
1180 static void Spi_InitController(Spi_UnitType *uPtr ) {
\r
1182 volatile struct DSPI_tag *spiHw = uPtr->hwPtr;
\r
1184 /* Module configuration register. */
\r
1185 /* Master mode. */
\r
1186 spiHw->MCR.B.MSTR = 1;
\r
1187 /* No freeze. Run SPI when debugger is stopped. */
\r
1188 spiHw->MCR.B.FRZ = 0;
\r
1189 /* PSC5 as regular CS. */
\r
1190 spiHw->MCR.B.PCSSE = 0;
\r
1192 /* Enable FIFO's. */
\r
1193 #if (SPI_IMPLEMENTATION == SPI_DMA)
\r
1194 spiHw->MCR.B.DIS_RXF = 1;
\r
1195 spiHw->MCR.B.DIS_TXF = 1;
\r
1196 #elif (SPI_IMPLEMENTATION == SPI_FIFO)
\r
1197 spiHw->MCR.B.DIS_RXF = 0;
\r
1198 spiHw->MCR.B.DIS_TXF = 0;
\r
1202 /* Set all active low. */
\r
1203 spiHw->MCR.B.PCSIS0 = 1;
\r
1204 spiHw->MCR.B.PCSIS1 = 1;
\r
1205 spiHw->MCR.B.PCSIS2 = 1;
\r
1206 spiHw->MCR.B.PCSIS3 = 1;
\r
1207 spiHw->MCR.B.PCSIS4 = 1;
\r
1208 spiHw->MCR.B.PCSIS5 = 1;
\r
1210 #if (SPI_IMPLEMENTATION == SPI_DMA)
\r
1211 /* DMA TX FIFO fill. */
\r
1212 spiHw->RSER.B.TFFF_RE = 1;
\r
1213 spiHw->RSER.B.TFFF_DIRS = 1;
\r
1215 /* DMA RX FIFO drain. */
\r
1216 spiHw->RSER.B.RFDF_RE = 1;
\r
1217 spiHw->RSER.B.RFDF_DIRS = 1;
\r
1220 // Setup CTAR's channel codes..
\r
1221 for (int i = 0; i < (CTAR_CNT-1); i++) {
\r
1222 uPtr->channelCodes[i] = CH_NOT_VALID;
\r
1225 /* Force to stopped state. */
\r
1226 spiHw->MCR.B.HALT = 1;
\r
1228 spiHw->SR.B.EOQF = 1;
\r
1230 /* Enable clocks. */
\r
1231 spiHw->MCR.B.MDIS = 0;
\r
1233 #if defined(__DMA_INT)
\r
1234 Irq_InstallVector(Spi_Isr_DMA, 16 , 1, CPU_Z1);
\r
1237 // Install EOFQ int..
\r
1238 switch (uPtr->hwUnit) {
\r
1239 #if defined(CFG_MPC560X)
\r
1241 ISR_INSTALL_ISR2("SPI_A",Spi_Isr_A, DSPI_0_ISR_EOQF, 15, 0);
\r
1244 ISR_INSTALL_ISR2("SPI_B",Spi_Isr_B, DSPI_1_ISR_EOQF, 15, 0);
\r
1246 #if defined(CFG_MPC5604B)
\r
1248 ISR_INSTALL_ISR2("SPI_C",Spi_Isr_C, DSPI_2_ISR_EOQF, 15, 0);
\r
1251 #elif defined(CFG_MPC5516) || defined(CFG_MPC5517)
\r
1253 ISR_INSTALL_ISR2("SPI_A",Spi_Isr_A, DSPI_A_ISR_EOQF, 15, 0);
\r
1256 ISR_INSTALL_ISR2("SPI_B",Spi_Isr_B, DSPI_B_ISR_EOQF, 15, 0);
\r
1259 ISR_INSTALL_ISR2("SPI_A",Spi_Isr_C, DSPI_C_ISR_EOQF, 15, 0);
\r
1262 ISR_INSTALL_ISR2("SPI_B",Spi_Isr_D, DSPI_D_ISR_EOQF, 15, 0);
\r
1265 #error ISR NOT installed.
\r
1270 //-------------------------------------------------------------------
\r
1272 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
1273 static void Spi_DmaSetup( Spi_UnitType *uPtr ) {
\r
1277 tcd = &uPtr->dmaTxTCD;
\r
1279 tcd->SADDR = (uint32) uPtr->txQueue;
\r
1280 tcd->DADDR = (uint32) &(uPtr->hwPtr->PUSHR.R);
\r
1282 Dma_StopChannel(uPtr->dmaTxChannel);
\r
1283 Dma_CheckConfig();
\r
1285 // CITER and BITER set when we send
\r
1286 tcd = &uPtr->dmaRxTCD;
\r
1288 tcd->SADDR = (uint32) &(uPtr->hwPtr->POPR.R);
\r
1289 tcd->DADDR = (uint32) uPtr->rxQueue;
\r
1291 Dma_StopChannel(uPtr->dmaRxChannel);
\r
1292 Dma_CheckConfig();
\r
1297 //-------------------------------------------------------------------
\r
1299 void Spi_Init(const Spi_ConfigType *ConfigPtr) {
\r
1300 const Spi_JobConfigType *jobConfig2;
\r
1301 Spi_UnitType *uPtr;
\r
1304 #if (SPI_IMPLEMENTATION == SPI_DMA )
\r
1309 memset(&Spi_Global,0,sizeof(Spi_Global));
\r
1310 Spi_Global.configPtr = ConfigPtr;
\r
1311 Spi_Global.extBufPtr = Spi_Eb;
\r
1313 Spi_Global.asyncMode = SPI_INTERRUPT_MODE;
\r
1315 // Set all sequence results to OK
\r
1316 for (Spi_SequenceType i = (Spi_SequenceType) 0; i < SPI_MAX_SEQUENCE; i++) {
\r
1317 Spi_SetSequenceResult(i, SPI_SEQ_OK);
\r
1319 // Figure out what HW controllers that are used
\r
1320 for (int j = 0; j < Spi_GetJobCnt(); j++) {
\r
1321 jobConfig2 = &Spi_Global.configPtr->SpiJobConfig[j];
\r
1322 Spi_Global.spiHwConfigured |= (1 << jobConfig2->SpiHwUnit);
\r
1325 confMask = Spi_Global.spiHwConfigured;
\r
1327 for (; confMask; confMask &= ~(1 << ctrlNr)) {
\r
1328 ctrlNr = ilog2(confMask);
\r
1329 DEBUG(DEBUG_LOW,"%s:Configured HW controller %d\n",MODULE_NAME,ctrlNr);
\r
1330 uPtr = GET_SPI_UNIT_PTR(ctrlNr);
\r
1331 uPtr->hwPtr = GET_SPI_HW_PTR(ctrlNr);
\r
1332 uPtr->hwUnit = ctrlNr;
\r
1333 Spi_InitController(uPtr);
\r
1334 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);
\r
1335 #if (SPI_IMPLEMENTATION == SPI_DMA )
\r
1336 unitNr = Spi_CtrlToUnit[ctrlNr];
\r
1340 unitNr = Spi_CtrlToUnit[ctrlNr];
\r
1342 /* Make sure that this channel shall be used. */
\r
1343 //assert (ConfigPtr->SpiHwConfig[ctrlNr].Activated);
\r
1344 assert(Spi_DmaConfig[unitNr].TxDmaChannel != (-1));
\r
1345 assert(Spi_DmaConfig[unitNr].RxDmaChannel != (-1));
\r
1347 uPtr->dmaTxChannel = Spi_DmaConfig[unitNr].TxDmaChannel;
\r
1348 uPtr->dmaRxChannel = Spi_DmaConfig[unitNr].RxDmaChannel;
\r
1350 Spi_DmaSetup(uPtr);
\r
1355 /* Setup the relations for Job, for easy access */
\r
1356 for(int j=0; j<SPI_MAX_JOB; j++ ) {
\r
1357 jobConfig2 = &Spi_Global.configPtr->SpiJobConfig[j];
\r
1358 Spi_JobUnit[j].jobCfgPtr = jobConfig2;
\r
1359 Spi_JobUnit[j].extDeviceCfgPtr = &Spi_Global.configPtr->SpiExternalDevice[jobConfig2->DeviceAssignment];
\r
1360 Spi_JobUnit[j].unitPtr = GET_SPI_UNIT_PTR(jobConfig2->SpiHwUnit);
\r
1361 Spi_JobUnit[j].hwPtr= GET_SPI_HW_PTR(jobConfig2->SpiHwUnit);
\r
1362 Spi_JobUnit[j].channelsPtr = &jobConfig2->ChannelAssignment[0];
\r
1365 /* Setup CTARS, configuration */
\r
1367 Spi_UnitType *spiUnit;
\r
1372 uint32 channelCode;
\r
1375 const Spi_JobConfigType *jobConfig;
\r
1376 const Spi_ChannelConfigType *chConfig;
\r
1378 for (j = 0; j < Spi_GetJobCnt(); j++) {
\r
1379 jobConfig = &Spi_Global.configPtr->SpiJobConfig[j];
\r
1380 spiUnit = GET_SPI_UNIT_PTR( jobConfig->SpiHwUnit );
\r
1382 // Also find the controllers used while we are at it
\r
1383 Spi_Global.spiHwConfigured |= (1 << jobConfig->SpiHwUnit);
\r
1385 // ..and set the job status
\r
1386 Spi_SetJobResult((Spi_JobType) j, SPI_JOB_OK);
\r
1389 // Go through all the jobs and it's channels to setup CTAS
\r
1390 // A job have the same physical controller ( SpiHwUnit )
\r
1391 while ((channelIndex = jobConfig->ChannelAssignment[l++])
\r
1392 != CH_NOT_VALID) {
\r
1393 chConfig = &Spi_Global.configPtr->SpiChannelConfig[channelIndex];
\r
1395 // Form a channel code from
\r
1396 // <MSB/LSB><external_device_id><channel width>
\r
1397 channelCode = ( ((uint32_t)chConfig->SpiTransferStart << 16) +
\r
1398 (jobConfig->DeviceAssignment << 8) +
\r
1399 chConfig->SpiDataWidth);
\r
1401 for (k = 0; k < (CTAR_CNT-1); k++) {
\r
1402 if (spiUnit->channelCodes[k] == channelCode) {
\r
1403 Spi_ChannelInfo[channelIndex].ctarId = k;
\r
1404 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
1405 // already in list, break
\r
1409 if (spiUnit->channelCodes[k] == CH_NOT_VALID) {
\r
1411 spiUnit->channelCodes[k] = channelCode;
\r
1412 // Assign the CTAR index to channel info..
\r
1413 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
1416 jobConfig->SpiHwUnit,
\r
1417 Spi_GetExternalDevicePtrFromIndex( jobConfig->DeviceAssignment),
\r
1418 (Spi_ChannelType) k,
\r
1419 chConfig->SpiTransferStart,
\r
1420 chConfig->SpiDataWidth);
\r
1422 Spi_ChannelInfo[channelIndex].ctarId = k;
\r
1426 /* No more CTARS */
\r
1427 assert(k<(CTAR_CNT-1));
\r
1432 Spi_Global.initRun = TRUE;
\r
1435 //-------------------------------------------------------------------
\r
1437 Std_ReturnType Spi_DeInit(void) {
\r
1438 volatile struct DSPI_tag *spiHw;
\r
1441 Spi_UnitType *uPtr;
\r
1444 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_DEINIT_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
1445 if (Spi_GetStatus() == SPI_BUSY)
\r
1448 // Disable the HW modules ( SPI021 )
\r
1449 confMask = Spi_Global.spiHwConfigured;
\r
1451 // Disable the SPI hw
\r
1452 for (; confMask; confMask &= ~(1 << confNr)) {
\r
1453 confNr = ilog2(confMask);
\r
1454 spiHw = GET_SPI_HW_PTR(confNr);
\r
1455 // Disable the hardware..
\r
1456 spiHw->MCR.B.MDIS = 1;
\r
1457 uPtr = GET_SPI_UNIT_PTR(confNr);
\r
1459 Spi_InitController(uPtr);
\r
1460 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);
\r
1464 Spi_Global.configPtr = NULL;
\r
1465 Spi_Global.initRun = FALSE;
\r
1470 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
1474 * @param jobConfig
\r
1477 static void Spi_DoWrite_DMA( Spi_UnitType *spiUnit,Spi_JobType jobIndex,
\r
1478 const Spi_JobConfigType *jobConfig )
\r
1483 const Spi_ChannelConfigType *chConfig;
\r
1484 Spi_EbType *extChBuff;
\r
1485 Spi_CommandType cmd;
\r
1489 // Find the channels for this job
\r
1490 while ((channelIndex = jobConfig->ChannelAssignment[j++]) != CH_NOT_VALID) {
\r
1491 chConfig = &Spi_Global.configPtr->SpiChannelConfig[channelIndex];
\r
1493 /* Check configuration error */
\r
1494 #if ( SPI_CHANNEL_BUFFERS_ALLOWED == 1 )
\r
1495 assert( chConfig->SpiChannelType == SPI_EB );
\r
1498 // Send the channels that are setup with external buffers
\r
1499 // Get the external buffer for this channel
\r
1500 extChBuff = &Spi_Global.extBufPtr[channelIndex];
\r
1502 if (extChBuff->active == 0) {
\r
1503 LDEBUG_PRINTF("Err:External buffer %d@job %d not setup\n",channelIndex,jobIndex);
\r
1508 // Start to fill the SPI queue for the DMA:
\r
1509 for (k = 0; k < extChBuff->length; k++) {
\r
1511 Spi_Global.configPtr->SpiExternalDevice[jobConfig->DeviceAssignment].SpiCsIdentifier;
\r
1513 cmd.B.CONT = 1; // Channels should keep CS active
\r
1514 // ( A job must assert CS continuously)
\r
1515 cmd.R |= (1 << (16 + csId)); // Set PCS
\r
1517 cmd.B.CTAS = Spi_ChannelInfo[channelIndex].ctarId;
\r
1518 if (extChBuff->src != NULL) {
\r
1519 if (chConfig->SpiDataWidth > 8) {
\r
1520 cmd.B.TXDATA = (extChBuff->src[k] << 8) + (extChBuff->src[k + 1] & 0xff);
\r
1523 cmd.B.TXDATA = extChBuff->src[k];
\r
1526 cmd.B.TXDATA = chConfig->SpiDefaultData;
\r
1529 // Just keep on filling the tx queue
\r
1530 spiUnit->txQueue[spiUnit->txCurrIndex++].R = cmd.R;
\r
1532 } /*while( channelIndex == */
\r
1535 cmd.B.CONT = 0; // CS high
\r
1536 cmd.B.EOQ = 1; // last in queue
\r
1537 spiUnit->txQueue[--spiUnit->txCurrIndex].R = cmd.R;
\r
1539 // Set the length of the data to send
\r
1540 spiUnit->dmaTxTCD.CITER = spiUnit->txCurrIndex + 1;
\r
1541 spiUnit->dmaTxTCD.BITER = spiUnit->txCurrIndex + 1;
\r
1543 Spi_Global.totalNbrOfStartedJobs++;
\r
1545 RAMLOG_STR("Job: "); RAMLOG_DEC(jobIndex); RAMLOG_STR(" Cnt: "); RAMLOG_DEC(spiUnit->txCurrIndex+1); RAMLOG_STR("\n");
\r
1547 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
1550 Spi_UnitType *spiUnit = GET_SPI_UNIT_PTR(jobConfig->SpiHwUnit);
\r
1551 volatile struct DSPI_tag *spiHw = GET_SPI_HW_PTR(jobConfig->SpiHwUnit);
\r
1553 Dma_ConfigureChannel((Dma_TcdType *) &spiUnit->dmaTxTCD,
\r
1554 spiUnit->dmaTxChannel);
\r
1555 Dma_ConfigureChannel((Dma_TcdType *) &spiUnit->dmaRxTCD,
\r
1556 spiUnit->dmaRxChannel);
\r
1557 /* Flush TX/Rx FIFO. Ref. man. 23.5.1 step 8 */
\r
1558 spiHw->MCR.B.CLR_RXF = 1;
\r
1559 spiHw->MCR.B.CLR_TXF = 1;
\r
1561 Dma_StartChannel(spiUnit->dmaRxChannel);
\r
1562 Dma_StartChannel(spiUnit->dmaTxChannel);
\r
1564 // Step 9. Clear TCNT
\r
1565 spiHw->TCR.B.SPI_TCNT = 0;
\r
1567 if ( (Spi_Global.asyncMode == SPI_INTERRUPT_MODE) &&
\r
1568 (spiUnit->callType == SPI_ASYNC_CALL)) {
\r
1569 ENABLE_EOQ_INTERRUPT(spiHw);
\r
1571 DISABLE_EOQ_INTERRUPT(spiHw);
\r
1574 /* This will trig a new transfer. Ref. man. 23.5.1 step 11 */
\r
1575 spiHw->SR.B.EOQF = 1;
\r
1576 spiHw->MCR.B.HALT = 0;
\r
1578 // Since it's not obvious on how to tell when a SPI sequence
\r
1579 // is sent, keep things below to what things have been tested.
\r
1580 #if defined(STEP_VALIDATION)
\r
1581 /* Wait for transfer to complete (EOQF bit is set) */
\r
1582 while (spiHw->SR.B.EOQF==1) {
\r
1583 Spi_Global.eoqf_cnt++;
\r
1585 while (spiHw->SR.B.TXRXS) {Spi_Global.txrxs_cnt++;}
\r
1586 while( EDMA.TCD[spiUnit->dmaRxChannel].ACTIVE ) {;}
\r
1593 #if (SPI_IMPLEMENTATION==SPI_FIFO)
\r
1597 * @param jobConfig
\r
1600 static void Spi_WriteJob_FIFO( Spi_JobType jobIndex )
\r
1602 Spi_ChannelType currChannel;
\r
1603 Spi_CommandType cmd;
\r
1604 Spi_CommandType dCmd;
\r
1605 Spi_NumberOfDataType bufLen;
\r
1606 const Spi_ChannelConfigType * chConfig;
\r
1607 Spi_JobUnitType * jobUnitPtr;
\r
1608 const Spi_DataType * buf;
\r
1609 Spi_NumberOfDataType copyCnt;
\r
1610 Spi_NumberOfDataType fifoLeft;
\r
1611 // boolean done = 0;
\r
1612 // boolean lastJob = 0;
\r
1614 jobUnitPtr = &Spi_JobUnit[jobIndex];
\r
1617 fifoLeft = FIFO_DEPTH;
\r
1619 RAMLOG_STR("Spi_WriteJob_FIFO\n");
\r
1621 #if defined(STEP_VALIDATION)
\r
1622 if( jobUnitPtr->hwPtr->SR.B.TXCTR != 0 ) {
\r
1628 dCmd.R = 0xfffffffful;
\r
1630 /* Iterate over the channels for this job */
\r
1631 currChannel = jobUnitPtr->channelsPtr[jobUnitPtr->currTxChIndex];
\r
1632 while ( fifoLeft != 0) {
\r
1634 chConfig = &Spi_Global.configPtr->SpiChannelConfig[currChannel];
\r
1635 buf = spiGetTxBuf( currChannel, &bufLen);
\r
1637 /* Minimum of how much data to copy and the limit of the FIFO */
\r
1638 copyCnt = MIN( (bufLen - jobUnitPtr->txChCnt) >> ((chConfig->SpiDataWidth-1)/8), fifoLeft );
\r
1640 /* Channels should keep CS active ( A job must assert CS continuously) */
\r
1642 /* Set the Chip Select (PCS) */
\r
1643 cmd.R |= (1 << (16 + jobUnitPtr->extDeviceCfgPtr->SpiCsIdentifier));
\r
1645 #if defined(STEP_VALIDATION)
\r
1646 if( cmd.B.EOQ == 1) {
\r
1651 /* Push as much as we can (FIFO or Channel limits) */
\r
1652 for(i=0; i < copyCnt ; i++ ) {
\r
1653 cmd.B.CTAS = Spi_ChannelInfo[currChannel].ctarId;
\r
1654 if (buf != NULL) {
\r
1655 if (chConfig->SpiDataWidth > 8 ) {
\r
1656 cmd.B.TXDATA = (buf[jobUnitPtr->txChCnt] << 8) +
\r
1657 (buf[jobUnitPtr->txChCnt + 1] & 0xff);
\r
1659 cmd.B.TXDATA = buf[jobUnitPtr->txChCnt];
\r
1662 cmd.B.TXDATA = chConfig->SpiDefaultData;
\r
1665 if (chConfig->SpiDataWidth > 8 ) {
\r
1666 jobUnitPtr->txChCnt+=2;
\r
1668 jobUnitPtr->txChCnt++;
\r
1672 if( dCmd.R != 0xfffffffful) {
\r
1673 jobUnitPtr->hwPtr->PUSHR.R = dCmd.R; // Write delayed
\r
1676 dCmd.R = cmd.R; // Save it
\r
1680 RAMLOG_STR("CI#");RAMLOG_DEC(jobUnitPtr->currTxChIndex);RAMLOG_STR("\n");
\r
1683 /* Done with channel? */
\r
1684 if( ((bufLen - jobUnitPtr->txChCnt) == 0) ) {
\r
1685 jobUnitPtr->txChCnt = 0;
\r
1686 /* Done with job? */
\r
1687 jobUnitPtr->currTxChIndex++;
\r
1688 currChannel = jobUnitPtr->channelsPtr[jobUnitPtr->currTxChIndex];
\r
1689 if( currChannel == CH_NOT_VALID ) {
\r
1690 jobUnitPtr->currTxChIndex = 0;
\r
1699 jobUnitPtr->hwPtr->PUSHR.R = cmd.R;
\r
1701 jobUnitPtr->fifoSent = FIFO_DEPTH - fifoLeft;
\r
1703 #if defined(STEP_VALIDATION)
\r
1704 if( jobUnitPtr->fifoSent != jobUnitPtr->hwPtr->SR.B.TXCTR ) {
\r
1709 jobUnitPtr->hwPtr->TCR.B.SPI_TCNT = 0;
\r
1711 if ( (Spi_Global.asyncMode == SPI_INTERRUPT_MODE) &&
\r
1712 (jobUnitPtr->unitPtr->callType == SPI_ASYNC_CALL)) {
\r
1713 ENABLE_EOQ_INTERRUPT(jobUnitPtr->hwPtr);
\r
1715 DISABLE_EOQ_INTERRUPT(jobUnitPtr->hwPtr);
\r
1718 #if defined(STEP_VALIDATION)
\r
1719 /* Verify FIFO before sending */
\r
1721 SPICommandType *base = (SPICommandType *)&jobUnitPtr->hwPtr->TXFR[0];
\r
1722 SPICommandType *curr;
\r
1725 i = jobUnitPtr->hwPtr->SR.B.TXNXTPTR; /* Next entry to send */
\r
1726 lastIndex = ( i + jobUnitPtr->hwPtr->SR.B.TXCTR - 1 ) % FIFO_DEPTH;
\r
1727 while( i != lastIndex ) {
\r
1729 if( curr->B.EOQ == 1) { /* This entry must not have EOQ set */
\r
1733 i = (i + 1) % FIFO_DEPTH;
\r
1736 if( curr->B.EOQ != 1) {
\r
1737 SPI_ASSERT(0); /* Last entry must have EOQ set */
\r
1742 jobUnitPtr->hwPtr->SR.B.EOQF = 1;
\r
1743 jobUnitPtr->hwPtr->MCR.B.HALT = 0;
\r
1745 #if defined(STEP_VALIDATION)
\r
1746 /* Wait for transfer to complete (EOQF bit is set) */
\r
1747 while (jobUnitPtr->hwPtr->SR.B.EOQF==1) {
\r
1748 Spi_Global.eoqf_cnt++;
\r
1750 while (jobUnitPtr->hwPtr->SR.B.TXRXS) {Spi_Global.txrxs_cnt++;}
\r
1753 // TODO: Clear FIFO's? CLR_TXF?
\r
1756 #endif /* (SPI_IMPLEMENTATION==SPI_FIFO) */
\r
1759 //-------------------------------------------------------------------
\r
1765 * Write a job to the SPI bus
\r
1767 * @param jobIndex The job to write to the SPI bus
\r
1769 static void Spi_JobWrite(Spi_JobType jobIndex) {
\r
1770 Spi_UnitType *uPtr = Spi_JobUnit[jobIndex].unitPtr;
\r
1772 uPtr->txCurrIndex = 0;
\r
1773 uPtr->currJob = Spi_JobUnit[jobIndex].jobCfgPtr;
\r
1774 uPtr->currJobIndex = jobIndex;
\r
1775 #if (SPI_IMPLEMENTATION == SPI_FIFO)
\r
1776 Spi_JobUnit[jobIndex].txChCnt = 0;
\r
1777 Spi_JobUnit[jobIndex].rxChCnt = 0;
\r
1780 Spi_SetHWUnitStatus(uPtr, SPI_BUSY);
\r
1781 Spi_SetJobResult(jobIndex, SPI_JOB_PENDING);
\r
1783 #if (USE_DIO_CS == STD_ON)
\r
1784 if( Spi_JobUnit[jobIndex].extDeviceCfgPtr->SpiCsCallback != NULL ) {
\r
1785 Spi_JobUnit[jobIndex].extDeviceCfgPtr->SpiCsCallback(1);
\r
1789 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
1790 Spi_DoWrite_DMA( uPtr, jobIndex, Spi_JobUnit[jobIndex].jobCfgPtr );
\r
1791 #elif (SPI_IMPLEMENTATION==SPI_FIFO)
\r
1792 Spi_JobUnit[jobIndex].currTxChIndex = 0;
\r
1793 Spi_WriteJob_FIFO ( jobIndex );
\r
1798 #if defined(USE_LDEBUG_PRINTF) && ( DEBUG_LVL <= DEBUG_HIGH )
\r
1799 void Spi_PrintSeqInfo(const Spi_SequenceConfigType *seqConfigPtr) {
\r
1802 DEBUG(DEBUG_HIGH,"%s: Seq: %d:",MODULE_NAME,seqConfigPtr->SpiSequenceId);
\r
1804 while ((job = seqConfigPtr->JobAssignment[i]) != JOB_NOT_VALID) {
\r
1805 DEBUG(DEBUG_HIGH,"%d ",job);
\r
1807 } DEBUG(DEBUG_HIGH,"\n");
\r
1813 * Write a sequence to the SPI bus
\r
1815 * @param seqIndex The sequence
\r
1816 * @param sync 1 - make the call sync. 0 - make the call async
\r
1818 static void Spi_SeqWrite(Spi_SequenceType seqIndex, Spi_CallTypeType sync) {
\r
1820 const Spi_SequenceConfigType *seqConfig;
\r
1821 const Spi_JobConfigType *jobConfig;
\r
1822 Spi_UnitType *uPtr;
\r
1823 Spi_JobType jobIndex;
\r
1825 seqConfig = Spi_GetSeqPtrFromIndex(seqIndex);
\r
1826 jobIndex = seqConfig->JobAssignment[0];
\r
1827 jobConfig = Spi_GetJobPtrFromIndex(jobIndex);
\r
1829 uPtr = Spi_GetUnitPtrFromIndex(jobConfig->SpiHwUnit);
\r
1831 /* Fill in the required fields for job and sequence.. */
\r
1832 uPtr->currJobIndexPtr = &seqConfig->JobAssignment[0];
\r
1833 uPtr->callType = sync;
\r
1834 uPtr->currSeqPtr = seqConfig;
\r
1836 Spi_SetSequenceResult(seqIndex, SPI_SEQ_PENDING);
\r
1838 // Setup interrupt for end of queue
\r
1839 if ( (Spi_Global.asyncMode == SPI_INTERRUPT_MODE) &&
\r
1840 (uPtr->callType== SPI_ASYNC_CALL)) {
\r
1841 DEBUG(DEBUG_MEDIUM,"%s: async/interrupt mode\n",MODULE_NAME);
\r
1843 DEBUG(DEBUG_MEDIUM,"%s: sync/polled mode\n",MODULE_NAME);
\r
1846 #if defined(USE_LDEBUG_PRINTF) && ( DEBUG_LVL <= DEBUG_HIGH )
\r
1847 Spi_PrintSeqInfo( seqConfig );
\r
1850 Spi_JobWrite(jobIndex);
\r
1852 if (uPtr->callType == SPI_SYNC_CALL) {
\r
1853 while (Spi_GetSequenceResult(seqIndex) == SPI_SEQ_PENDING) {
\r
1860 //-------------------------------------------------------------------
\r
1861 static _Bool Spi_AnyPendingJobs(Spi_SequenceType Sequence) {
\r
1863 // Check that we don't share any jobs with another sequence that is SPI_SEQ_PENDING
\r
1864 for (int i = 0; i < SPI_MAX_SEQUENCE; i++) {
\r
1865 if (i == Sequence) {
\r
1869 if (Spi_GetSequenceResult(i) == SPI_SEQ_PENDING) {
\r
1870 // We have found a pending sequence... check that we don't share any jobs
\r
1871 // with that sequence, SPI086
\r
1872 if (Spi_ShareJobs(Sequence, i)) {
\r
1881 //-------------------------------------------------------------------
\r
1890 Std_ReturnType Spi_SyncTransmit(Spi_SequenceType Sequence) {
\r
1892 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_SYNCTRANSMIT_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
1893 VALIDATE_W_RV( ( SPI_MAX_SEQUENCE>Sequence ), SPI_SYNCTRANSMIT_SERVICE_ID, SPI_E_PARAM_SEQ, E_NOT_OK );
\r
1894 Std_ReturnType rv = E_OK;
\r
1896 if (Spi_GetSequenceResult(Sequence) == SPI_SEQ_PENDING) {
\r
1897 DEBUG(DEBUG_LOW,"%s: Spi_AsyncTransmit() is PENDING\n",MODULE_NAME);
\r
1898 return E_NOT_OK; // SPI157
\r
1901 assert(Spi_GetSequenceResult(Sequence) == SPI_SEQ_OK);
\r
1903 if (Spi_AnyPendingJobs(Sequence)) {
\r
1907 Spi_SeqWrite(Sequence, SPI_SYNC_CALL);
\r
1912 //-------------------------------------------------------------------
\r
1914 Std_ReturnType Spi_AsyncTransmit(Spi_SequenceType Sequence) {
\r
1915 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_ASYNCTRANSMIT_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
1916 VALIDATE_W_RV( ( SPI_MAX_SEQUENCE>Sequence ), SPI_ASYNCTRANSMIT_SERVICE_ID, SPI_E_PARAM_SEQ, E_NOT_OK );
\r
1918 if (Spi_GetSequenceResult(Sequence) == SPI_SEQ_PENDING) {
\r
1919 DEBUG(DEBUG_LOW,"%s: Spi_AsyncTransmit() is PENDING\n",MODULE_NAME);
\r
1920 return E_NOT_OK; // SPI157
\r
1923 assert(Spi_GetSequenceResult(Sequence) == SPI_SEQ_OK);
\r
1925 if (Spi_AnyPendingJobs(Sequence)) {
\r
1929 DEBUG(DEBUG_LOW,"%s: Starting seq: %d\n",MODULE_NAME,Sequence);
\r
1931 Spi_SeqWrite(Sequence, SPI_ASYNC_CALL);
\r
1936 //-------------------------------------------------------------------
\r
1939 Std_ReturnType Spi_ReadIB( Spi_ChannelType Channel,
\r
1940 Spi_DataType * const DataBufferPtr)
\r
1942 (void)DataBufferPtr;
\r
1944 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_READIB_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
1945 VALIDATE_W_RV( ( Channel<SPI_MAX_CHANNEL ), SPI_READIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
1946 VALIDATE_W_RV( ( SPI_IB<Spi_Global.configPtr->SpiChannelConfig[Channel].SpiChannelType ),
\r
1947 SPI_READIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
1949 /* NOT SUPPORTED */
\r
1951 Std_ReturnType rv = E_NOT_OK;
\r
1955 //-------------------------------------------------------------------
\r
1957 Std_ReturnType Spi_SetupEB( Spi_ChannelType Channel,
\r
1958 const Spi_DataType* SrcDataBufferPtr,
\r
1959 Spi_DataType* DesDataBufferPtr,
\r
1960 Spi_NumberOfDataType Length)
\r
1962 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_SETUPEB_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
1963 VALIDATE_W_RV( ( Channel<SPI_MAX_CHANNEL ), SPI_SETUPEB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
1964 #if ( SPI_CHANNEL_BUFFERS_ALLOWED == 1 )
\r
1965 VALIDATE_W_RV( ( SPI_EB==Spi_Global.configPtr->SpiChannelConfig[Channel].SpiChannelType ),
\r
1966 SPI_SETUPEB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
1969 VALIDATE_W_RV( ( Length<=Spi_Global.configPtr->SpiChannelConfig[Channel].SpiEbMaxLength ),
\r
1970 SPI_SETUPEB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
1972 Spi_EbType *extChBuff = &Spi_Global.extBufPtr[Channel];
\r
1973 const Spi_ChannelConfigType *chConfig =
\r
1974 &Spi_Global.configPtr->SpiChannelConfig[Channel];
\r
1976 if (chConfig->SpiChannelType == SPI_EB) {
\r
1977 extChBuff->src = SrcDataBufferPtr;
\r
1978 extChBuff->dest = DesDataBufferPtr;
\r
1979 extChBuff->length = Length;
\r
1980 extChBuff->active = 1;
\r
1982 /* NOT SUPPORTED */
\r
1991 //-------------------------------------------------------------------
\r
1993 Spi_StatusType Spi_GetStatus(void) {
\r
1994 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_GETSTATUS_SERVICE_ID, SPI_E_UNINIT, SPI_UNINIT );
\r
1996 // Check all sequences if they have any job pending
\r
1997 for (int i = 0; i < SPI_MAX_SEQUENCE; i++) {
\r
1998 if (Spi_GetSequenceResult(i) == SPI_SEQ_PENDING) {
\r
2006 //-------------------------------------------------------------------
\r
2009 Spi_JobResultType Spi_GetJobResult(Spi_JobType Job) {
\r
2010 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_GETJOBRESULT_SERVICE_ID, SPI_E_UNINIT, SPI_JOB_FAILED );
\r
2011 VALIDATE_W_RV( ( SPI_MAX_JOB<Job ), SPI_GETJOBRESULT_SERVICE_ID, SPI_E_PARAM_JOB, SPI_JOB_FAILED );
\r
2013 return Spi_JobUnit[Job].jobResult;
\r
2016 //-------------------------------------------------------------------
\r
2019 Spi_SeqResultType Spi_GetSequenceResult(Spi_SequenceType Sequence) {
\r
2020 Spi_SeqResultType rv;
\r
2022 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_GETSEQUENCERESULT_SERVICE_ID, SPI_E_UNINIT, SPI_SEQ_FAILED );
\r
2023 VALIDATE_W_RV( ( SPI_MAX_SEQUENCE>Sequence ), SPI_GETSEQUENCERESULT_SERVICE_ID, SPI_E_PARAM_SEQ, SPI_SEQ_FAILED );
\r
2025 rv = Spi_SeqUnit[Sequence].seqResult;
\r
2030 //-------------------------------------------------------------------
\r
2032 Spi_StatusType Spi_GetHWUnitStatus(Spi_HWUnitType HWUnit) {
\r
2033 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_GETHWUNITSTATUS_SERVICE_ID, SPI_E_UNINIT, SPI_UNINIT );
\r
2035 return Spi_Unit[Spi_CtrlToUnit[HWUnit]].status;
\r
2038 //-------------------------------------------------------------------
\r
2040 #if (SPI_CANCEL_API == STD_ON )
\r
2041 void Spi_Cancel( Spi_SequenceType Sequence ) {
\r
2042 VALIDATE( ( TRUE == Spi_Global.initRun ), SPI_CANCEL_SERVICE_ID, SPI_E_UNINIT );
\r
2043 VALIDATE( ( SPI_MAX_SEQUENCE<Sequence ), SPI_CANCEL_SERVICE_ID, SPI_E_PARAM_SEQ );
\r
2045 /* NOT SUPPORTED */
\r
2049 //-------------------------------------------------------------------
\r
2052 #if ( SPI_LEVEL_DELIVERED == 2) // SPI154
\r
2053 Std_ReturnType Spi_SetAsyncMode(Spi_AsyncModeType Mode) {
\r
2054 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_SETASYNCMODE_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
2057 // Not really sure by whom this function is supposed to be called by.
\r
2058 // The users of SPI(e2,flash,etc) should probably not use this.
\r
2060 for (int i = 0; i < SPI_MAX_SEQUENCE; i++) {
\r
2061 if (Spi_GetSequenceResult(i) == SPI_SEQ_PENDING) {
\r
2066 Spi_Global.asyncMode = Mode;
\r
2072 //-------------------------------------------------------------------
\r
2074 void Spi_MainFunction_Handling(void) {
\r
2075 /* NOT SUPPORTED */
\r
2078 //-------------------------------------------------------------------
\r
2080 void Spi_MainFunction_Driving(void) {
\r
2081 volatile struct DSPI_tag *spiHw;
\r
2084 Spi_UnitType *uPtr;
\r
2086 // TODO: check that the queue is empty.. if so do the next job.
\r
2087 if (Spi_Global.asyncMode == SPI_POLLING_MODE) {
\r
2088 confMask = Spi_Global.spiHwConfigured;
\r
2090 for (; confMask; confMask &= ~(1 << ctrlNr)) {
\r
2091 ctrlNr = ilog2(confMask);
\r
2092 uPtr = GET_SPI_UNIT_PTR(ctrlNr);
\r
2093 spiHw = uPtr->hwPtr;
\r
2095 if (Spi_GetHWUnitStatus(ctrlNr) == SPI_BUSY) {
\r
2096 if (spiHw->SR.B.TXRXS) {
\r
2097 // Still not done..
\r
2099 uPtr = GET_SPI_UNIT_PTR(ctrlNr);
\r