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_MPC5606B)
\r
168 #define SPI_CONTROLLER_TOTAL_CNT 6
\r
169 #elif defined(CFG_MPC5604B)
\r
170 #define SPI_CONTROLLER_TOTAL_CNT 3
\r
171 #elif defined(CFG_MPC560X)
\r
172 #define SPI_CONTROLLER_TOTAL_CNT 2
\r
175 #if defined(CFG_MPC560X)
\r
176 #define DSPI_A_ISR_EOQF DSPI_0_ISR_EOQF
\r
177 #define DSPI_B_ISR_EOQF DSPI_1_ISR_EOQF
\r
178 #if defined(CFG_MPC560XB)
\r
179 #define DSPI_C_ISR_EOQF DSPI_2_ISR_EOQF
\r
181 #if defined(CFG_MPC5606B)
\r
182 #define DSPI_D_ISR_EOQF DSPI_3_ISR_EOQF
\r
183 #define DSPI_E_ISR_EOQF DSPI_4_ISR_EOQF
\r
184 #define DSPI_F_ISR_EOQF DSPI_5_ISR_EOQF
\r
188 #define SPIE_BAD (-1)
\r
190 #define SPIE_JOB_NOT_DONE 1
\r
192 #if defined(CFG_MPC560XB)
\r
198 //#define SPI_IMPLEMENTATION SPI_FIFO
\r
199 #define USE_DIO_CS STD_ON
\r
201 // E2 read = cmd + addr + data = 1 + 2 + 64 ) = 67 ~ 72
\r
202 #define SPI_INTERNAL_MTU 72
\r
204 /* The depth of the HW FIFO */
\r
205 #define FIFO_DEPTH 4
\r
207 /* Define for debug purposes, checks that SPI/DMA is ok */
\r
208 //#define STEP_VALIDATION 1
\r
210 #define MODULE_NAME "/driver/Spi"
\r
212 //#define USE_LDEBUG_PRINTF 1
\r
214 #define DEBUG_LVL DEBUG_NONE
\r
217 //#define USE_LOCAL_RAMLOG
\r
218 #if defined(USE_LOCAL_RAMLOG)
\r
219 #define RAMLOG_STR(_x) ramlog_str(_x)
\r
220 #define RAMLOG_DEC(_x) ramlog_dec(_x)
\r
221 #define RAMLOG_HEX(_x) ramlog_hex(_x)
\r
223 #define RAMLOG_STR(_x)
\r
224 #define RAMLOG_DEC(_x)
\r
225 #define RAMLOG_HEX(_x)
\r
228 #define SPI_ASSERT(_exp) if( !(_exp) ) while(1) {}
\r
230 /* ----------------------------[private macro]-------------------------------*/
\r
233 #define MIN(_x,_y) (((_x) < (_y)) ? (_x) : (_y))
\r
236 #define MAX(_x,_y) (((_x) > (_y)) ? (_x) : (_y))
\r
239 #define GET_SPI_HW_PTR(_unit) \
\r
240 ((volatile struct DSPI_tag *)(0xFFF90000 + 0x4000*(_unit)))
\r
242 #define GET_SPI_UNIT_PTR(_unit) &Spi_Unit[Spi_CtrlToUnit[_unit]]
\r
244 #define ENABLE_EOQ_INTERRUPT(_spi_hw) _spi_hw->RSER.B.EOQF_RE = 1
\r
245 #define DISABLE_EOQ_INTERRUPT(_spi_hw) _spi_hw->RSER.B.EOQF_RE = 0
\r
247 #define GET_HW(_channel) ( volatile struct DSPI_tag *)((uint32)&DSPI_A + 0x4000 * _channel )
\r
249 /* Development error macros. */
\r
250 #if ( SPI_DEV_ERROR_DETECT == STD_ON )
\r
251 #define VALIDATE(_exp,_api,_err ) \
\r
253 Det_ReportError(MODULE_ID_SPI,0,_api,_err); \
\r
257 #define VALIDATE_W_RV(_exp,_api,_err,_rv ) \
\r
259 Det_ReportError(MODULE_ID_SPI,0,_api,_err); \
\r
263 #define VALIDATE(_exp,_api,_err )
\r
264 #define VALIDATE_W_RV(_exp,_api,_err,_rv )
\r
267 /* ----------------------------[private typedef]-----------------------------*/
\r
269 #if (SPI_IMPLEMENTATION == SPI_DMA )
\r
270 typedef struct Spi_DmaConfig {
\r
271 Dma_ChannelType RxDmaChannel;
\r
272 Dma_ChannelType TxDmaChannel;
\r
273 } Spi_DmaConfigType;
\r
285 vuint32_t CTCNT :1;
\r
293 vuint32_t TXDATA :16;
\r
297 typedef SPICommandType Spi_CommandType;
\r
299 const Spi_DataType * src; /* Pointer to source buffer */
\r
300 Spi_DataType * dest; /* Pointer to destination buffer */
\r
301 Spi_NumberOfDataType length; // Number of elements of Spi_DataType in destination buffer
\r
302 _Bool active; // Set if the buffer is configured.
\r
308 } Spi_CallTypeType;
\r
311 uint8 ctarId; // this channel is assigned to this CTAR
\r
312 } Spi_ChannelInfoType;
\r
315 * This structure represents a controller unit
\r
319 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
320 Dma_ChannelType dmaTxChannel; // Tx DMA channel information
\r
321 Dma_TcdType dmaTxTCD;
\r
322 Dma_ChannelType dmaRxChannel; // Rx DMA channel information
\r
323 Dma_TcdType dmaRxTCD;
\r
324 Spi_CommandType txQueue[SPI_INTERNAL_MTU]; // Pointed to by SADDR of DMA
\r
325 uint32 rxQueue[SPI_INTERNAL_MTU]; // Pointed to by DADDR of DMA
\r
327 uint32 txCurrIndex; // current index for data when sending
\r
328 uint32 channelCodes[(CTAR_CNT-1)]; // Helper array to assign CTAR's
\r
329 Spi_StatusType status; // Status for this unit
\r
330 const Spi_JobConfigType * currJob; // The current job
\r
331 const Spi_JobType * currJobIndexPtr; // Points array of jobs current
\r
332 Spi_JobType currJobIndex;
\r
333 const Spi_SequenceConfigType * currSeqPtr; // The Sequence
\r
334 Spi_CallTypeType callType; // 1 - if the current job is sync. 0 - if not
\r
335 volatile struct DSPI_tag * hwPtr;
\r
336 uint8 hwUnit; // 0...
\r
340 Spi_SeqResultType seqResult;
\r
344 volatile struct DSPI_tag * hwPtr; /* The HW device used by this Job */
\r
345 const Spi_ExternalDeviceType * extDeviceCfgPtr; /* The external device used by this job */
\r
346 const Spi_JobConfigType * jobCfgPtr;
\r
347 Spi_UnitType * unitPtr;
\r
348 const Spi_ChannelType * channelsPtr;
\r
349 #if (SPI_IMPLEMENTATION == SPI_FIFO )
\r
350 uint32_t fifoSent; /* Number of bytes in FIFO (before EOQ is set) */
\r
351 uint8_t currTxChIndex; /* the currently transmitting channel index for FIFO */
\r
352 uint32_t txChCnt; /* number of Spi_DataType sent for the current channel */
\r
353 uint32_t rxChCnt; /* number of Spi_DataType received for the current channel */
\r
354 uint32_t currRxChIndex; /* the currently receiving channel index for FIFO */
\r
356 Spi_JobResultType jobResult;
\r
360 boolean initRun; // Initially FALSE set to TRUE if Spi_Init() have been called
\r
361 const Spi_ConfigType * configPtr; // Pointer to the configuration
\r
362 Spi_EbType * extBufPtr; // Pointer to the external buffers
\r
363 Spi_ChannelInfoType * channelInfo;
\r
364 uint32 spiHwConfigured; // Mask if the HW unit is configured or not
\r
365 Spi_AsyncModeType asyncMode;
\r
367 /* This is a bunch of debug counters. */
\r
368 uint32 totalNbrOfTranfers;
\r
369 uint32 totalNbrOfStartedJobs;
\r
370 /* Counters for busy waiting for DSPI and DMA. */
\r
371 uint32 totalNbrOfWaitTXRXS;
\r
372 uint32 totalNbrOfWaitRxDMA;
\r
373 #if defined(STEP_VALIDATION)
\r
379 /* ----------------------------[private function prototypes]-----------------*/
\r
380 /* ----------------------------[private variables]---------------------------*/
\r
382 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
383 /* Templates for Rx/Tx DMA structures */
\r
384 const Dma_TcdType Spi_DmaTx = {
\r
385 .SADDR = 0, .SMOD = 0, .SSIZE = DMA_TRANSFER_SIZE_32BITS, .DMOD = 0,
\r
386 .DSIZE = DMA_TRANSFER_SIZE_32BITS, .SOFF = 4, .NBYTESu.R = 4, .SLAST = 0,
\r
387 .DADDR = 0, .CITERE_LINK = 0, .CITER = 0, .DOFF = 0, .DLAST_SGA = 0,
\r
388 .BITERE_LINK = 0, .BITER = 0, .BWC = 0, .MAJORLINKCH = 0, .DONE = 0,
\r
389 .ACTIVE = 0, .MAJORE_LINK = 0, .E_SG = 0, .D_REQ = 0, .INT_HALF = 0,
\r
390 .INT_MAJ = 0, .START = 0 };
\r
392 const Dma_TcdType Spi_DmaRx = { .SADDR = 0, .SMOD = 0,
\r
393 .SSIZE = DMA_TRANSFER_SIZE_32BITS, .DMOD = 0,
\r
394 .DSIZE = DMA_TRANSFER_SIZE_32BITS, .SOFF = 0, .NBYTESu.R = 4, .SLAST = 0,
\r
395 .DADDR = 0, .CITERE_LINK = 0, .CITER = 1, .DOFF = 4, .DLAST_SGA = 0,
\r
396 .BITERE_LINK = 0, .BITER = 1, .BWC = 0, .MAJORLINKCH = 0, .DONE = 0,
\r
397 .ACTIVE = 0, .MAJORE_LINK = 0, .E_SG = 0, .D_REQ = 0, .INT_HALF = 0,
\r
398 #if defined(__DMA_INT)
\r
406 Spi_GlobalType Spi_Global;
\r
407 Spi_EbType Spi_Eb[SPI_MAX_CHANNEL];
\r
408 Spi_UnitType Spi_Unit[SPI_CONTROLLER_CNT];
\r
409 Spi_SeqUnitType Spi_SeqUnit[SPI_MAX_SEQUENCE];
\r
410 Spi_JobUnitType Spi_JobUnit[SPI_MAX_JOB];
\r
411 Spi_ChannelInfoType Spi_ChannelInfo[SPI_MAX_CHANNEL];
\r
412 uint8 Spi_CtrlToUnit[4];
\r
415 #if (SPI_IMPLEMENTATION == SPI_DMA)
\r
416 /* When using DMA it assumes predefined names */
\r
417 Spi_DmaConfigType Spi_DmaConfig[SPI_CONTROLLER_CNT] = {
\r
418 #if (SPI_USE_HW_UNIT_0 == STD_ON )
\r
420 .RxDmaChannel = DMA_DSPI_A_RESULT_CHANNEL,
\r
421 .TxDmaChannel = DMA_DSPI_A_COMMAND_CHANNEL,
\r
424 #if (SPI_USE_HW_UNIT_1 == STD_ON )
\r
426 .RxDmaChannel = DMA_DSPI_B_RESULT_CHANNEL,
\r
427 .TxDmaChannel = DMA_DSPI_B_COMMAND_CHANNEL,
\r
430 #if (SPI_USE_HW_UNIT_2 == STD_ON )
\r
432 .RxDmaChannel = DMA_DSPI_C_RESULT_CHANNEL,
\r
433 .TxDmaChannel = DMA_DSPI_C_COMMAND_CHANNEL,
\r
436 #if (SPI_USE_HW_UNIT_3 == STD_ON )
\r
438 .RxDmaChannel = DMA_DSPI_D_RESULT_CHANNEL,
\r
439 .TxDmaChannel = DMA_DSPI_D_COMMAND_CHANNEL,
\r
445 /* ----------------------------[private functions]---------------------------*/
\r
447 #if (SPI_IMPLEMENTATION == SPI_FIFO )
\r
448 static void Spi_WriteJob_FIFO( Spi_JobType jobIndex );
\r
451 * Get the buffer for a channel.
\r
457 static Spi_DataType *spiGetRxBuf(Spi_ChannelType ch, Spi_NumberOfDataType *length ) {
\r
459 if( Spi_Global.configPtr->SpiChannelConfig[ch].SpiChannelType == SPI_EB ) {
\r
460 *length = Spi_Global.extBufPtr[ch].length;
\r
461 buf = Spi_Global.extBufPtr[ch].dest;
\r
470 static const Spi_DataType *spiGetTxBuf(Spi_ChannelType ch, Spi_NumberOfDataType *length ) {
\r
471 const Spi_DataType *buf;
\r
472 if( Spi_Global.configPtr->SpiChannelConfig[ch].SpiChannelType == SPI_EB ) {
\r
473 *length = Spi_Global.extBufPtr[ch].length;
\r
474 buf = Spi_Global.extBufPtr[ch].src;
\r
484 static void Spi_Isr(Spi_UnitType *uPtr );
\r
486 static void Spi_Isr_A(void) {
\r
487 Spi_Isr(GET_SPI_UNIT_PTR(DSPI_CTRL_A));
\r
489 static void Spi_Isr_B(void) {
\r
490 Spi_Isr(GET_SPI_UNIT_PTR(DSPI_CTRL_B));
\r
492 static void Spi_Isr_C(void) {
\r
493 Spi_Isr(GET_SPI_UNIT_PTR(DSPI_CTRL_C));
\r
495 static void Spi_Isr_D(void) {
\r
496 Spi_Isr(GET_SPI_UNIT_PTR(DSPI_CTRL_D));
\r
498 /* ----------------------------[public functions]----------------------------*/
\r
500 uint32 Spi_GetJobCnt(void);
\r
501 uint32 Spi_GetChannelCnt(void);
\r
502 uint32 Spi_GetExternalDeviceCnt(void);
\r
505 static void Spi_Isr_DMA( void )
\r
508 Dma_ClearInterrupt(5);
\r
512 static void Spi_JobWrite(Spi_JobType jobIndex);
\r
514 static void Spi_SetJobResult(Spi_JobType Job, Spi_JobResultType result) {
\r
515 Spi_JobUnit[Job].jobResult = result;
\r
518 static void Spi_SetHWUnitStatus( Spi_UnitType *uPtr, Spi_StatusType status) {
\r
519 uPtr->status = status;
\r
523 * Get external Ptr to device from index
\r
525 * @param deviceType The device index.
\r
526 * @return Ptr to the external device
\r
529 static inline const Spi_ExternalDeviceType *Spi_GetExternalDevicePtrFromIndex(
\r
530 Spi_ExternalDeviceTypeType deviceType) {
\r
531 return (&(Spi_Global.configPtr->SpiExternalDevice[(deviceType)]));
\r
535 * Get configuration job ptr from job index
\r
536 * @param jobIndex the job
\r
537 * @return Ptr to the job configuration
\r
539 static const Spi_JobConfigType *Spi_GetJobPtrFromIndex(Spi_JobType jobIndex) {
\r
540 return &Spi_Global.configPtr->SpiJobConfig[jobIndex];
\r
544 * Get sequence ptr from sequence index
\r
545 * @param seqIndex the sequence
\r
546 * @return Ptr to the sequence configuration
\r
548 static const Spi_SequenceConfigType *Spi_GetSeqPtrFromIndex(
\r
549 Spi_SequenceType SeqIndex) {
\r
550 return &Spi_Global.configPtr->SpiSequenceConfig[SeqIndex];
\r
555 * Function to see if two sequences share jobs
\r
557 * @param seq - Seqence 1
\r
558 * @param seq - Seqence 2
\r
559 * @return 0 - if the don't share any jobs
\r
560 * !=0 - if they share jobs
\r
563 static boolean Spi_ShareJobs(Spi_SequenceType seq1, Spi_SequenceType seq2) {
\r
564 uint32 seqMask1 = 0;
\r
565 uint32 seqMask2 = 0;
\r
566 const Spi_JobType *jobPtr;
\r
567 const Spi_SequenceConfigType *seqConfig;
\r
569 // Search for jobs in sequence 1
\r
570 seqConfig = Spi_GetSeqPtrFromIndex(seq1);
\r
571 jobPtr = &seqConfig->JobAssignment[0];
\r
573 while (*jobPtr != JOB_NOT_VALID) {
\r
574 assert(*jobPtr<31);
\r
575 seqMask1 |= (1 << *jobPtr);
\r
579 // Search for jobs in sequence 2
\r
580 seqConfig = Spi_GetSeqPtrFromIndex(seq2);
\r
581 jobPtr = &seqConfig->JobAssignment[0];
\r
583 while (*jobPtr != JOB_NOT_VALID) {
\r
584 assert(*jobPtr<31);
\r
585 seqMask2 |= (1 << *jobPtr);
\r
589 return (seqMask1 & seqMask2);
\r
593 //-------------------------------------------------------------------
\r
596 * Sets a result for a sequence
\r
598 * @param Sequence The sequence to set the result for
\r
599 * @param result The result to set.
\r
601 static void Spi_SetSequenceResult(Spi_SequenceType Sequence,
\r
602 Spi_SeqResultType result) {
\r
603 Spi_SeqUnit[Sequence].seqResult = result;
\r
606 //-------------------------------------------------------------------
\r
610 * Gets the next job to do
\r
612 * @param spiUnit The SPI unit
\r
613 * @return The job ID. -1 if no more jobs
\r
615 static Spi_JobType Spi_GetNextJob(Spi_UnitType *spiUnit) {
\r
616 spiUnit->currJobIndexPtr++;
\r
617 return *(spiUnit->currJobIndexPtr);
\r
619 //-------------------------------------------------------------------
\r
622 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
625 * Function to handle things after a transmit on the SPI is finished.
\r
626 * It copies data from it't local buffers to the buffers pointer to
\r
627 * by the external buffers
\r
629 * @param spiUnit Ptr to a SPI unit
\r
632 static int Spi_Rx_DMA(Spi_UnitType *spiUnit) {
\r
633 _Bool printedSomeThing = 0;
\r
635 /* Stop the channels */
\r
636 Dma_StopChannel(spiUnit->dmaTxChannel);
\r
637 Dma_StopChannel(spiUnit->dmaRxChannel);
\r
639 RAMLOG_STR("PostTransmit Job: "); RAMLOG_DEC(spiUnit->currJob->SpiJobId); RAMLOG_STR("\n");
\r
641 /* Copy data from RX queue to the external buffer( if a<uny ) */
\r
646 const Spi_ChannelConfigType *chConfig;
\r
647 Spi_EbType *extChBuff;
\r
651 // Check that we got the number of bytes we sent
\r
652 sentTx = spiUnit->txCurrIndex + 1;
\r
653 gotTx = (Dma_GetTcd(spiUnit->dmaRxChannel)->DADDR
\r
654 - (uint32) &spiUnit->rxQueue[0]) / sizeof(uint32);
\r
656 if (sentTx != gotTx) {
\r
657 // Something failed
\r
658 DEBUG(DEBUG_LOW,"%s: Expected %d bytes. Got %d bytes\n ",MODULE_NAME,sentTx, gotTx );
\r
659 #if defined(STEP_VALIDATION)
\r
664 RAMLOG_STR("Rx "); RAMLOG_DEC(gotTx); RAMLOG_STR(" Bytes\n"); DEBUG(DEBUG_LOW,"%s: Got %d bytes\n",MODULE_NAME,gotTx);
\r
667 // Find the channels for this job
\r
668 while ((channelIndex = spiUnit->currJob->ChannelAssignment[j++])
\r
670 chConfig = &Spi_Global.configPtr->SpiChannelConfig[channelIndex];
\r
672 /* Check configuration error */
\r
673 #if ( SPI_CHANNEL_BUFFERS_ALLOWED == 1 )
\r
674 assert( chConfig->SpiChannelType == SPI_EB );
\r
677 // Send the channels that are setup with external buffers
\r
678 // Get the external buffer for this channel
\r
679 extChBuff = &Spi_Global.extBufPtr[channelIndex];
\r
680 if (extChBuff->dest != NULL) {
\r
681 // Note! No support for >8 "data"
\r
682 for (int k = 0; k < extChBuff->length; k++) {
\r
683 extChBuff->dest[k] = spiUnit->rxQueue[currIndex++];
\r
684 DEBUG(DEBUG_LOW," %02x ",extChBuff->dest[k]);
\r
685 printedSomeThing = 1;
\r
689 if (chConfig->SpiDataWidth > 8) {
\r
690 currIndex += (extChBuff->length / 2);
\r
692 currIndex += extChBuff->length;
\r
696 if (printedSomeThing)
\r
697 DEBUG(DEBUG_LOW,"\n");
\r
703 #elif (SPI_IMPLEMENTATION==SPI_FIFO)
\r
705 static int Spi_Rx_FIFO(Spi_UnitType *spiUnit) {
\r
706 Spi_JobUnitType * jobUnitPtr;
\r
707 Spi_DataType * buf;
\r
710 Spi_ChannelType currChannel;
\r
711 Spi_NumberOfDataType bufLen;
\r
713 int rv = SPIE_JOB_NOT_DONE;
\r
714 const Spi_ChannelConfigType * chConfig;
\r
718 // RAMLOG_STR("PostTransmit Job: "); RAMLOG_DEC(spiUnit->currJob->SpiJobId); RAMLOG_STR("\n");
\r
719 RAMLOG_STR("Spi_Rx_FIFO\n");
\r
721 jobUnitPtr = &Spi_JobUnit[spiUnit->currJobIndex];
\r
723 if( jobUnitPtr->hwPtr->TCR.B.SPI_TCNT != jobUnitPtr->fifoSent ) {
\r
724 #if defined(STEP_VALIDATION)
\r
731 * Fill receive buffers, either EB or IB
\r
732 * Example with 8-bit CMD, 16-bit ADDR and some 8-bit data.
\r
733 * CMD | ADDR | DATA
\r
734 * | 12 | 23 | 34 | 00 | 01 | 02 | 03
\r
735 * 1 2 3 4 5 6 BYTE CNT
\r
736 * 1 2 3 4 (5) (6) FIFO
\r
737 * With a FIFO of 4 we can see that the CMD, ADDR and almost the whole
\r
738 * DATA channel is sent.
\r
740 currChannel = jobUnitPtr->channelsPtr[jobUnitPtr->currRxChIndex];
\r
741 assert( currChannel != CH_NOT_VALID );
\r
743 if( jobUnitPtr->fifoSent != jobUnitPtr->hwPtr->SR.B.RXCTR ) {
\r
744 #if defined(STEP_VALIDATION)
\r
750 while ( jobUnitPtr->fifoSent != 0 ) {
\r
752 chConfig = &Spi_Global.configPtr->SpiChannelConfig[currChannel];
\r
754 RAMLOG_STR("CIR#");RAMLOG_DEC(jobUnitPtr->currRxChIndex);RAMLOG_STR("\n");
\r
756 /* Get this channels destination buffer */
\r
757 buf = spiGetRxBuf(currChannel, &bufLen);
\r
758 assert(bufLen!=0); /* We should always get a valid bufLen */
\r
760 copyCnt = MIN( (bufLen - jobUnitPtr->rxChCnt) >> ((chConfig->SpiDataWidth-1)/8), jobUnitPtr->fifoSent );
\r
762 if( copyCnt == 0 ) {
\r
763 #if defined(STEP_VALIDATION)
\r
769 jobUnitPtr->fifoSent -= copyCnt;
\r
771 bInChar = (chConfig->SpiDataWidth > 8 ) ? 2 : 1;
\r
774 if( buf != NULL ) {
\r
775 for(i=0;i<copyCnt;i++) {
\r
776 popVal = jobUnitPtr->hwPtr->POPR.B.RXDATA;
\r
777 RAMLOG_STR("%");RAMLOG_HEX(popVal);
\r
778 buf[jobUnitPtr->rxChCnt] = (Spi_DataType)popVal;
\r
779 jobUnitPtr->rxChCnt += bInChar;
\r
782 for(i=0;i<copyCnt;i++) {
\r
783 popVal = jobUnitPtr->hwPtr->POPR.B.RXDATA;
\r
784 jobUnitPtr->rxChCnt += bInChar;
\r
788 if( (bufLen - jobUnitPtr->rxChCnt ) == 0 ) {
\r
789 /* advance to the next channel */
\r
790 jobUnitPtr->rxChCnt = 0;
\r
791 jobUnitPtr->currRxChIndex++;
\r
792 currChannel = jobUnitPtr->channelsPtr[jobUnitPtr->currRxChIndex];
\r
793 if( currChannel == CH_NOT_VALID ) {
\r
794 //assert( jobUnitPtr->fifoSent == 0);
\r
795 jobUnitPtr->fifoSent = 0;
\r
796 jobUnitPtr->currRxChIndex = 0;
\r
804 #if defined(STEP_VALIDATION)
\r
805 /* Check if we are done with this job */
\r
806 if( 0 != jobUnitPtr->hwPtr->SR.B.RXCTR ) {
\r
816 //-------------------------------------------------------------------
\r
819 * ISR for End of Queue interrupt
\r
821 * The interrupt handling is quite simple. Since this driver assumes
\r
822 * that we are the master the EOQ interrupt is sufficient to check.
\r
824 * @param unit The HW unit it happend on
\r
826 static void Spi_Isr( Spi_UnitType *uPtr) {
\r
827 volatile struct DSPI_tag *spiHw = uPtr->hwPtr;
\r
830 RAMLOG_STR("Spi_Isr\n");
\r
832 // This may seem pretty stupid to wait for the controller
\r
833 // to shutdown here, but there seems to be no other way to do this.
\r
835 // - Waiting for DMA rx/tx hits earlier than EOQ.
\r
836 // - Other interrupts from SPI all hit earlier than EOQ.
\r
837 // TODO: There is the TCF_RE bit! Use this instead?
\r
839 // TODO: We could implement a timeout here and fail the job
\r
840 // if this never happens.
\r
842 // This is the busy wait when called from a non-interrupt context
\r
843 while (spiHw->SR.B.TXRXS) {
\r
844 Spi_Global.totalNbrOfWaitTXRXS++;
\r
847 #if (SPI_IMPLEMENTATION == SPI_DMA)
\r
848 while (!Dma_ChannelDone(uPtr->dmaRxChannel)) {
\r
849 Spi_Global.totalNbrOfWaitRxDMA++;
\r
853 #if defined(STEP_VALIDATION)
\r
854 /* Since EOQF clears TXRXS */
\r
855 SPI_ASSERT( (spiHw->SR.B.EOQF==1) && (spiHw->SR.B.TXRXS == 0));
\r
858 /* Halt DSPI unit until we are ready for next transfer. */
\r
859 spiHw->MCR.B.HALT = 1;
\r
860 spiHw->SR.B.EOQF = 1;
\r
863 Spi_Global.totalNbrOfTranfers++;
\r
865 // Disable EOQ interrupts
\r
867 // This does NOT clear the interrupt request.
\r
868 // That can only be done by clearing( setting ) the EOQ
\r
869 // bit.. but that also triggers a new transfer.
\r
872 // A possibility could be to use the HALT bit instead of
\r
873 // using this trick, but hey, this works
\r
875 DISABLE_EOQ_INTERRUPT(spiHw);
\r
877 // Update external buffers
\r
878 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
879 rv = Spi_Rx_DMA(uPtr);
\r
881 #if (USE_DIO_CS == STD_ON)
\r
882 void (*cb)(int) = Spi_JobUnit[uPtr->currJobIndex].extDeviceCfgPtr->SpiCsCallback;
\r
887 #elif (SPI_IMPLEMENTATION==SPI_FIFO)
\r
888 rv = Spi_Rx_FIFO(uPtr);
\r
890 if( rv == SPIE_JOB_NOT_DONE ) {
\r
891 /* RX FIFO now empty, but the job is not done -> send more */
\r
892 Spi_WriteJob_FIFO ( uPtr->currJobIndex );
\r
893 RAMLOG_STR("Spi_Isr END\n");
\r
896 #if (USE_DIO_CS == STD_ON)
\r
898 void (*cb)(int) = Spi_JobUnit[uPtr->currJobIndex].extDeviceCfgPtr->SpiCsCallback;
\r
906 // Call notification end
\r
907 if (uPtr->currJob->SpiJobEndNotification != NULL) {
\r
908 uPtr->currJob->SpiJobEndNotification();
\r
911 if (rv == SPIE_BAD) {
\r
912 // Fail both job and sequence
\r
913 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);
\r
914 Spi_SetJobResult(uPtr->currJob->SpiJobId, SPI_JOB_FAILED);
\r
915 Spi_SetSequenceResult(uPtr->currSeqPtr->SpiSequenceId,
\r
917 #if defined(STEP_VALIDATION)
\r
921 Spi_JobType nextJob;
\r
923 // The job is at least done..
\r
924 Spi_SetJobResult(uPtr->currJob->SpiJobId, SPI_JOB_OK);
\r
926 // WriteNextJob should
\r
927 // 1. Update the JobResult to SPI_JOB_OK
\r
928 // 2. Update the HWUnit status to IDLE
\r
931 // - Jobs have the controller
\r
932 // - Sequences can we interruptible between jobs.
\r
934 // According to SPI086 you can't share a job with a sequence that
\r
935 // is in SPI_SEQ_PENDING ( that happens first thing at Spi_AsyncTranmit() )
\r
937 // So, I no clue what to use the priority thing for :(
\r
939 nextJob = Spi_GetNextJob(uPtr);
\r
940 if( nextJob != JOB_NOT_VALID ) {
\r
941 Spi_JobWrite(nextJob);
\r
942 RAMLOG_STR("more_jobs\n");
\r
944 // No more jobs, so set HwUnit and sequence IDLE/OK also.
\r
945 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);
\r
946 Spi_SetSequenceResult(uPtr->currSeqPtr->SpiSequenceId,
\r
949 if (uPtr->currSeqPtr->SpiSeqEndNotification != NULL) {
\r
950 uPtr->currSeqPtr->SpiSeqEndNotification();
\r
953 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);
\r
955 /* We are now ready for next transfer. */
\r
956 spiHw->MCR.B.HALT = 1;
\r
958 RAMLOG_STR("NO_more_jobs\n");
\r
962 RAMLOG_STR("Spi_Isr END\n");
\r
965 //-------------------------------------------------------------------
\r
967 Std_ReturnType Spi_WriteIB(Spi_ChannelType Channel,
\r
968 const Spi_DataType *DataBufferPtr) {
\r
969 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_WRITEIB_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
970 VALIDATE_W_RV( ( Channel<SPI_MAX_CHANNEL ), SPI_WRITEIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
971 VALIDATE_W_RV( ( DataBufferPtr != NULL ), SPI_WRITEIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
972 VALIDATE_W_RV( ( SPI_IB==Spi_Global.configPtr->SpiChannelConfig[Channel].SpiChannelType ),
\r
973 SPI_WRITEIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
975 /* According to SPI051 it seems that we only have to a "depth" of 1 */
\r
978 Std_ReturnType rv = E_NOT_OK;
\r
983 const uint32 clk_table_asc[] = { 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
\r
984 4096, 8192, 16384, 32768, 65536 };
\r
985 const uint32 clk_table_cssck[] = { 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
\r
986 4096, 8192, 16384, 32768, 65536 };
\r
987 const uint16 clk_table_br[] = { 2, 4, 6, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
\r
988 4096, 8192, 16384, 32768 };
\r
989 const uint8 clk_table_pasc[] = { 1, 3, 5, 7 };
\r
990 const uint8 clk_table_pcssck[] = { 1, 3, 5, 7 };
\r
991 const uint8 clk_table_pbr[] = { 2, 3, 5, 7 };
\r
994 * Function to setup CTAR's from configuration
\r
995 * @param spiHw - Pointer to HW SPI device
\r
996 * @param extDev - Pointer to external device configuration
\r
997 * @param ctar_unit - The ctar unit number to setup
\r
998 * @param width - The width in bits of the data to send with the CTAR
\r
1000 static void Spi_SetupCTAR( Spi_HWUnitType unit,
\r
1001 const Spi_ExternalDeviceType *extDev,
\r
1002 Spi_ChannelType ctar_unit,
\r
1003 Spi_TransferStartType transferStart,
\r
1011 McuE_PeriperalClock_t perClock;
\r
1013 volatile struct DSPI_tag *spiHw = GET_SPI_HW_PTR(unit);
\r
1014 /* BAUDRATE CALCULATION
\r
1015 * -----------------------------
\r
1016 * Baudrate = Fsys/ PBR * ( 1+ DBR) / BR
\r
1017 * PBR range: 2 to 7
\r
1018 * DBR range: 0 to 1
\r
1021 * To make this easy set DBR = 0 and PBR=2
\r
1022 * --> BR=Fsys/(Baudrate.* 2 )
\r
1028 perClock = PERIPHERAL_CLOCK_DSPI_A;
\r
1031 perClock = PERIPHERAL_CLOCK_DSPI_B;
\r
1033 #if (SPI_CONTROLLER_TOTAL_CNT>2)
\r
1035 perClock = PERIPHERAL_CLOCK_DSPI_C;
\r
1038 #if (SPI_CONTROLLER_TOTAL_CNT>3)
\r
1040 perClock = PERIPHERAL_CLOCK_DSPI_D;
\r
1043 #if (SPI_CONTROLLER_TOTAL_CNT>4)
\r
1045 perClock = PERIPHERAL_CLOCK_DSPI_E;
\r
1048 #if (SPI_CONTROLLER_TOTAL_CNT>5)
\r
1050 perClock = PERIPHERAL_CLOCK_DSPI_F;
\r
1058 clock = McuE_GetPeripheralClock(perClock);
\r
1060 DEBUG(DEBUG_MEDIUM,"%s: Peripheral clock at %d Mhz\n",MODULE_NAME,clock);
\r
1062 DEBUG(DEBUG_MEDIUM,"%s: Want to run at %d Mhz\n",MODULE_NAME,extDev->SpiBaudrate);
\r
1064 spiHw->CTAR[ctar_unit].B.DBR = 0;
\r
1065 spiHw->CTAR[ctar_unit].B.PBR = 0; // 2
\r
1066 pre_br = clock / (extDev->SpiBaudrate
\r
1067 * clk_table_pbr[spiHw->CTAR[ctar_unit].B.PBR]);
\r
1069 // find closest lesser
\r
1070 for (i = 0; i < sizeof(clk_table_br) / sizeof(clk_table_br[0]); i++) {
\r
1071 if (clk_table_br[i] >= pre_br) {
\r
1078 spiHw->CTAR[ctar_unit].B.BR = i;
\r
1080 DEBUG(DEBUG_LOW,"%s: CLK %d Mhz\n",MODULE_NAME,
\r
1081 clock / clk_table_pbr[spiHw->CTAR[ctar_unit].B.PBR] *
\r
1082 ( 1 + spiHw->CTAR[ctar_unit].B.DBR)/clk_table_br[spiHw->CTAR[ctar_unit].B.BR]);
\r
1084 /* For other timings autosar only specifies SpiTimeClk2Cs == "After SCK delay"
\r
1085 * in Freescale language. The dumb thing is that this should be a relative time
\r
1086 * to the clock. Not fixed.
\r
1087 * Autosar specifies 0.0--100.0 ms(float)
\r
1088 * Our intepretation is 0--1000000 ns (uint32)
\r
1090 * AFTER SCK DELAY:
\r
1091 * -----------------------------
\r
1092 * Tasc = 1/Fsys * PASC * ASC [s]
\r
1094 * Assume the Tasc get's here in ns( typical range is ~10ns )
\r
1097 // Calc the PASC * ASC value...
\r
1098 tmp = extDev->SpiTimeClk2Cs * (clock / 1000000);
\r
1100 // Nothing fancy here...
\r
1104 int b_value = INT_MAX;
\r
1107 // Find the best match of Prescaler and Scaler value
\r
1108 for (i = 0; i < ARRAY_SIZE(clk_table_pasc); i++) {
\r
1109 for (j = 0; j < ARRAY_SIZE(clk_table_asc); j++) {
\r
1110 tt = abs((int) clk_table_pasc[i] * clk_table_asc[j] * 1000
\r
1112 if (tt < b_value) {
\r
1120 /* After SCK delay. */
\r
1121 spiHw->CTAR[ctar_unit].B.PASC = best_i;
\r
1122 spiHw->CTAR[ctar_unit].B.ASC = best_j;
\r
1125 DEBUG(DEBUG_MEDIUM,"%s: Timing: Tasc %d ns\n",MODULE_NAME,
\r
1126 clk_table_pasc[spiHw->CTAR[ctar_unit].B.PASC] *
\r
1127 clk_table_asc[spiHw->CTAR[ctar_unit].B.ASC] * 1000/ (clock/1000000) );
\r
1129 /* The PCS to SCK delay is the delay between the assertion of PCS and
\r
1130 * the first edge the SCK.
\r
1132 * PCS TO SCK DELAY:
\r
1133 * -----------------------------
\r
1134 * Tcsc = 1/Fsys * PCSSCK * CSSCK [s]
\r
1137 // Calc the PCSSCK * CSSCK value...
\r
1138 tmp = extDev->SpiTimeCs2Clk * (clock / 1000000);
\r
1140 // Nothing fancy here...
\r
1144 int b_value = INT_MAX;
\r
1147 // Find the best match of Prescaler and Scaler value
\r
1148 for (i = 0; i < ARRAY_SIZE(clk_table_pcssck); i++) {
\r
1149 for (j = 0; j < ARRAY_SIZE(clk_table_cssck); j++) {
\r
1150 tt = abs((int) clk_table_pcssck[i] * clk_table_cssck[j] * 1000
\r
1152 if (tt < b_value) {
\r
1160 /* PCS to SCK delay */
\r
1161 spiHw->CTAR[ctar_unit].B.PCSSCK = best_i;
\r
1162 spiHw->CTAR[ctar_unit].B.CSSCK = best_j;
\r
1165 DEBUG(DEBUG_MEDIUM,"%s: Timing: Tcsc %d ns\n",MODULE_NAME,
\r
1166 clk_table_pcssck[spiHw->CTAR[ctar_unit].B.PCSSCK] *
\r
1167 clk_table_cssck[spiHw->CTAR[ctar_unit].B.CSSCK]*1000/(clock/1000000));
\r
1169 /* Time that PCS is high between transfers */
\r
1170 spiHw->CTAR[ctar_unit].B.PDT = 2;
\r
1171 spiHw->CTAR[ctar_unit].B.DT = 2;
\r
1173 DEBUG(DEBUG_MEDIUM,"%s: Timing: Tdt %d ns\n",MODULE_NAME,
\r
1174 clk_table_pasc[spiHw->CTAR[ctar_unit].B.PDT] *
\r
1175 clk_table_asc[spiHw->CTAR[ctar_unit].B.DT]*1000/(clock/1000000));
\r
1177 /* Data is transferred MSB first */
\r
1179 spiHw->CTAR[ctar_unit].B.LSBFE = (transferStart == SPI_TRANSFER_START_MSB ) ? 0 : 1;
\r
1182 spiHw->CTAR[ctar_unit].B.FMSZ = width - 1;
\r
1183 spiHw->CTAR[ctar_unit].B.CPHA = (extDev->SpiDataShiftEdge
\r
1184 == SPI_EDGE_LEADING) ? 0 : 1;
\r
1185 spiHw->CTAR[ctar_unit].B.CPOL = (extDev->SpiShiftClockIdleLevel == STD_LOW) ? 0 : 1;
\r
1187 // This the ACTIVE polarity. Freescale have inactive polarity
\r
1188 if (extDev->SpiCsPolarity == STD_HIGH) {
\r
1189 spiHw->MCR.R &= ~(1 << (16 + extDev->SpiCsIdentifier));
\r
1191 spiHw->MCR.R |= (1 << (16 + extDev->SpiCsIdentifier));
\r
1195 //-------------------------------------------------------------------
\r
1197 static void Spi_InitController(Spi_UnitType *uPtr ) {
\r
1199 volatile struct DSPI_tag *spiHw = uPtr->hwPtr;
\r
1201 /* Module configuration register. */
\r
1202 /* Master mode. */
\r
1203 spiHw->MCR.B.MSTR = 1;
\r
1204 /* No freeze. Run SPI when debugger is stopped. */
\r
1205 spiHw->MCR.B.FRZ = 0;
\r
1206 /* PSC5 as regular CS. */
\r
1207 spiHw->MCR.B.PCSSE = 0;
\r
1209 /* Enable FIFO's. */
\r
1210 #if (SPI_IMPLEMENTATION == SPI_DMA)
\r
1211 spiHw->MCR.B.DIS_RXF = 1;
\r
1212 spiHw->MCR.B.DIS_TXF = 1;
\r
1213 #elif (SPI_IMPLEMENTATION == SPI_FIFO)
\r
1214 spiHw->MCR.B.DIS_RXF = 0;
\r
1215 spiHw->MCR.B.DIS_TXF = 0;
\r
1219 /* Set all active low. */
\r
1220 spiHw->MCR.B.PCSIS0 = 1;
\r
1221 spiHw->MCR.B.PCSIS1 = 1;
\r
1222 spiHw->MCR.B.PCSIS2 = 1;
\r
1223 spiHw->MCR.B.PCSIS3 = 1;
\r
1224 spiHw->MCR.B.PCSIS4 = 1;
\r
1225 spiHw->MCR.B.PCSIS5 = 1;
\r
1227 #if (SPI_IMPLEMENTATION == SPI_DMA)
\r
1228 /* DMA TX FIFO fill. */
\r
1229 spiHw->RSER.B.TFFF_RE = 1;
\r
1230 spiHw->RSER.B.TFFF_DIRS = 1;
\r
1232 /* DMA RX FIFO drain. */
\r
1233 spiHw->RSER.B.RFDF_RE = 1;
\r
1234 spiHw->RSER.B.RFDF_DIRS = 1;
\r
1237 // Setup CTAR's channel codes..
\r
1238 for (int i = 0; i < (CTAR_CNT-1); i++) {
\r
1239 uPtr->channelCodes[i] = CH_NOT_VALID;
\r
1242 /* Force to stopped state. */
\r
1243 spiHw->MCR.B.HALT = 1;
\r
1245 spiHw->SR.B.EOQF = 1;
\r
1247 /* Enable clocks. */
\r
1248 spiHw->MCR.B.MDIS = 0;
\r
1250 #if defined(__DMA_INT)
\r
1251 Irq_InstallVector(Spi_Isr_DMA, 16 , 1, CPU_Z1);
\r
1254 // Install EOFQ int..
\r
1255 switch (uPtr->hwUnit) {
\r
1257 ISR_INSTALL_ISR2("SPI_A",Spi_Isr_A, DSPI_A_ISR_EOQF, 15, 0);
\r
1260 ISR_INSTALL_ISR2("SPI_B",Spi_Isr_B, DSPI_B_ISR_EOQF, 15, 0);
\r
1262 #if (SPI_CONTROLLER_TOTAL_CNT > 2)
\r
1264 ISR_INSTALL_ISR2("SPI_C",Spi_Isr_C, DSPI_C_ISR_EOQF, 15, 0);
\r
1267 #if (SPI_CONTROLLER_TOTAL_CNT > 3)
\r
1269 ISR_INSTALL_ISR2("SPI_D",Spi_Isr_D, DSPI_D_ISR_EOQF, 15, 0);
\r
1272 #if (SPI_CONTROLLER_TOTAL_CNT > 4)
\r
1274 ISR_INSTALL_ISR2("SPI_E",Spi_Isr_E, DSPI_E_ISR_EOQF, 15, 0);
\r
1277 #if (SPI_CONTROLLER_TOTAL_CNT > 5)
\r
1279 ISR_INSTALL_ISR2("SPI_F",Spi_Isr_F, DSPI_F_ISR_EOQF, 15, 0);
\r
1285 //-------------------------------------------------------------------
\r
1287 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
1288 static void Spi_DmaSetup( Spi_UnitType *uPtr ) {
\r
1292 tcd = &uPtr->dmaTxTCD;
\r
1294 tcd->SADDR = (uint32) uPtr->txQueue;
\r
1295 tcd->DADDR = (uint32) &(uPtr->hwPtr->PUSHR.R);
\r
1297 Dma_StopChannel(uPtr->dmaTxChannel);
\r
1298 Dma_CheckConfig();
\r
1300 // CITER and BITER set when we send
\r
1301 tcd = &uPtr->dmaRxTCD;
\r
1303 tcd->SADDR = (uint32) &(uPtr->hwPtr->POPR.R);
\r
1304 tcd->DADDR = (uint32) uPtr->rxQueue;
\r
1306 Dma_StopChannel(uPtr->dmaRxChannel);
\r
1307 Dma_CheckConfig();
\r
1312 //-------------------------------------------------------------------
\r
1314 void Spi_Init(const Spi_ConfigType *ConfigPtr) {
\r
1315 const Spi_JobConfigType *jobConfig2;
\r
1316 Spi_UnitType *uPtr;
\r
1319 #if (SPI_IMPLEMENTATION == SPI_DMA )
\r
1324 memset(&Spi_Global,0,sizeof(Spi_Global));
\r
1325 Spi_Global.configPtr = ConfigPtr;
\r
1326 Spi_Global.extBufPtr = Spi_Eb;
\r
1328 Spi_Global.asyncMode = SPI_INTERRUPT_MODE;
\r
1330 // Set all sequence results to OK
\r
1331 for (Spi_SequenceType i = (Spi_SequenceType) 0; i < SPI_MAX_SEQUENCE; i++) {
\r
1332 Spi_SetSequenceResult(i, SPI_SEQ_OK);
\r
1334 // Figure out what HW controllers that are used
\r
1335 for (int j = 0; j < Spi_GetJobCnt(); j++) {
\r
1336 jobConfig2 = &Spi_Global.configPtr->SpiJobConfig[j];
\r
1337 Spi_Global.spiHwConfigured |= (1 << jobConfig2->SpiHwUnit);
\r
1340 confMask = Spi_Global.spiHwConfigured;
\r
1342 for (int i=0; confMask; confMask &= ~(1 << ctrlNr),i++) {
\r
1343 ctrlNr = ilog2(confMask);
\r
1344 Spi_CtrlToUnit[ctrlNr] = i;
\r
1346 DEBUG(DEBUG_LOW,"%s:Configured HW controller %d\n",MODULE_NAME,ctrlNr);
\r
1347 uPtr = GET_SPI_UNIT_PTR(ctrlNr);
\r
1348 uPtr->hwPtr = GET_SPI_HW_PTR(ctrlNr);
\r
1349 uPtr->hwUnit = ctrlNr;
\r
1350 Spi_InitController(uPtr);
\r
1351 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);
\r
1352 #if (SPI_IMPLEMENTATION == SPI_DMA )
\r
1355 unitNr = Spi_CtrlToUnit[ctrlNr];
\r
1357 /* Make sure that this channel shall be used. */
\r
1358 //assert (ConfigPtr->SpiHwConfig[ctrlNr].Activated);
\r
1359 assert(Spi_DmaConfig[unitNr].TxDmaChannel != (-1));
\r
1360 assert(Spi_DmaConfig[unitNr].RxDmaChannel != (-1));
\r
1362 uPtr->dmaTxChannel = Spi_DmaConfig[unitNr].TxDmaChannel;
\r
1363 uPtr->dmaRxChannel = Spi_DmaConfig[unitNr].RxDmaChannel;
\r
1365 Spi_DmaSetup(uPtr);
\r
1370 /* Setup the relations for Job, for easy access */
\r
1371 for(int j=0; j<SPI_MAX_JOB; j++ ) {
\r
1372 jobConfig2 = &Spi_Global.configPtr->SpiJobConfig[j];
\r
1373 Spi_JobUnit[j].jobCfgPtr = jobConfig2;
\r
1374 Spi_JobUnit[j].extDeviceCfgPtr = &Spi_Global.configPtr->SpiExternalDevice[jobConfig2->DeviceAssignment];
\r
1375 Spi_JobUnit[j].unitPtr = GET_SPI_UNIT_PTR(jobConfig2->SpiHwUnit);
\r
1376 Spi_JobUnit[j].hwPtr= GET_SPI_HW_PTR(jobConfig2->SpiHwUnit);
\r
1377 Spi_JobUnit[j].channelsPtr = &jobConfig2->ChannelAssignment[0];
\r
1380 /* Setup CTARS, configuration */
\r
1382 Spi_UnitType *spiUnit;
\r
1387 uint32 channelCode;
\r
1390 const Spi_JobConfigType *jobConfig;
\r
1391 const Spi_ChannelConfigType *chConfig;
\r
1393 for (j = 0; j < Spi_GetJobCnt(); j++) {
\r
1394 jobConfig = &Spi_Global.configPtr->SpiJobConfig[j];
\r
1395 spiUnit = GET_SPI_UNIT_PTR( jobConfig->SpiHwUnit );
\r
1397 // Also find the controllers used while we are at it
\r
1398 Spi_Global.spiHwConfigured |= (1 << jobConfig->SpiHwUnit);
\r
1400 // ..and set the job status
\r
1401 Spi_SetJobResult((Spi_JobType) j, SPI_JOB_OK);
\r
1404 // Go through all the jobs and it's channels to setup CTAS
\r
1405 // A job have the same physical controller ( SpiHwUnit )
\r
1406 while ((channelIndex = jobConfig->ChannelAssignment[l++])
\r
1407 != CH_NOT_VALID) {
\r
1408 chConfig = &Spi_Global.configPtr->SpiChannelConfig[channelIndex];
\r
1410 // Form a channel code from
\r
1411 // <MSB/LSB><external_device_id><channel width>
\r
1412 channelCode = ( ((uint32_t)chConfig->SpiTransferStart << 16) +
\r
1413 (jobConfig->DeviceAssignment << 8) +
\r
1414 chConfig->SpiDataWidth);
\r
1416 for (k = 0; k < (CTAR_CNT-1); k++) {
\r
1417 if (spiUnit->channelCodes[k] == channelCode) {
\r
1418 Spi_ChannelInfo[channelIndex].ctarId = k;
\r
1419 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
1420 // already in list, break
\r
1424 if (spiUnit->channelCodes[k] == CH_NOT_VALID) {
\r
1426 spiUnit->channelCodes[k] = channelCode;
\r
1427 // Assign the CTAR index to channel info..
\r
1428 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
1431 jobConfig->SpiHwUnit,
\r
1432 Spi_GetExternalDevicePtrFromIndex( jobConfig->DeviceAssignment),
\r
1433 (Spi_ChannelType) k,
\r
1434 chConfig->SpiTransferStart,
\r
1435 chConfig->SpiDataWidth);
\r
1437 Spi_ChannelInfo[channelIndex].ctarId = k;
\r
1441 /* No more CTARS */
\r
1442 assert(k<(CTAR_CNT-1));
\r
1447 Spi_Global.initRun = TRUE;
\r
1450 //-------------------------------------------------------------------
\r
1452 Std_ReturnType Spi_DeInit(void) {
\r
1453 volatile struct DSPI_tag *spiHw;
\r
1456 Spi_UnitType *uPtr;
\r
1459 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_DEINIT_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
1460 if (Spi_GetStatus() == SPI_BUSY)
\r
1463 // Disable the HW modules ( SPI021 )
\r
1464 confMask = Spi_Global.spiHwConfigured;
\r
1466 // Disable the SPI hw
\r
1467 for (; confMask; confMask &= ~(1 << confNr)) {
\r
1468 confNr = ilog2(confMask);
\r
1469 spiHw = GET_SPI_HW_PTR(confNr);
\r
1470 // Disable the hardware..
\r
1471 spiHw->MCR.B.MDIS = 1;
\r
1472 uPtr = GET_SPI_UNIT_PTR(confNr);
\r
1474 Spi_InitController(uPtr);
\r
1475 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);
\r
1479 Spi_Global.configPtr = NULL;
\r
1480 Spi_Global.initRun = FALSE;
\r
1485 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
1489 * @param jobConfig
\r
1492 static void Spi_DoWrite_DMA( Spi_UnitType *spiUnit,Spi_JobType jobIndex,
\r
1493 const Spi_JobConfigType *jobConfig )
\r
1498 const Spi_ChannelConfigType *chConfig;
\r
1499 Spi_EbType *extChBuff;
\r
1500 Spi_CommandType cmd;
\r
1504 // Find the channels for this job
\r
1505 while ((channelIndex = jobConfig->ChannelAssignment[j++]) != CH_NOT_VALID) {
\r
1506 chConfig = &Spi_Global.configPtr->SpiChannelConfig[channelIndex];
\r
1508 /* Check configuration error */
\r
1509 #if ( SPI_CHANNEL_BUFFERS_ALLOWED == 1 )
\r
1510 assert( chConfig->SpiChannelType == SPI_EB );
\r
1513 // Send the channels that are setup with external buffers
\r
1514 // Get the external buffer for this channel
\r
1515 extChBuff = &Spi_Global.extBufPtr[channelIndex];
\r
1517 if (extChBuff->active == 0) {
\r
1518 LDEBUG_PRINTF("Err:External buffer %d@job %d not setup\n",channelIndex,jobIndex);
\r
1523 // Start to fill the SPI queue for the DMA:
\r
1524 for (k = 0; k < extChBuff->length; k++) {
\r
1526 Spi_Global.configPtr->SpiExternalDevice[jobConfig->DeviceAssignment].SpiCsIdentifier;
\r
1528 cmd.B.CONT = 1; // Channels should keep CS active
\r
1529 // ( A job must assert CS continuously)
\r
1530 cmd.R |= (1 << (16 + csId)); // Set PCS
\r
1532 cmd.B.CTAS = Spi_ChannelInfo[channelIndex].ctarId;
\r
1533 if (extChBuff->src != NULL) {
\r
1534 if (chConfig->SpiDataWidth > 8) {
\r
1535 cmd.B.TXDATA = (extChBuff->src[k] << 8) + (extChBuff->src[k + 1] & 0xff);
\r
1538 cmd.B.TXDATA = extChBuff->src[k];
\r
1541 cmd.B.TXDATA = chConfig->SpiDefaultData;
\r
1544 // Just keep on filling the tx queue
\r
1545 spiUnit->txQueue[spiUnit->txCurrIndex++].R = cmd.R;
\r
1547 } /*while( channelIndex == */
\r
1550 cmd.B.CONT = 0; // CS high
\r
1551 cmd.B.EOQ = 1; // last in queue
\r
1552 spiUnit->txQueue[--spiUnit->txCurrIndex].R = cmd.R;
\r
1554 // Set the length of the data to send
\r
1555 spiUnit->dmaTxTCD.CITER = spiUnit->txCurrIndex + 1;
\r
1556 spiUnit->dmaTxTCD.BITER = spiUnit->txCurrIndex + 1;
\r
1558 Spi_Global.totalNbrOfStartedJobs++;
\r
1560 RAMLOG_STR("Job: "); RAMLOG_DEC(jobIndex); RAMLOG_STR(" Cnt: "); RAMLOG_DEC(spiUnit->txCurrIndex+1); RAMLOG_STR("\n");
\r
1562 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
1565 Spi_UnitType *spiUnit = GET_SPI_UNIT_PTR(jobConfig->SpiHwUnit);
\r
1566 volatile struct DSPI_tag *spiHw = GET_SPI_HW_PTR(jobConfig->SpiHwUnit);
\r
1568 Dma_ConfigureChannel((Dma_TcdType *) &spiUnit->dmaTxTCD,
\r
1569 spiUnit->dmaTxChannel);
\r
1570 Dma_ConfigureChannel((Dma_TcdType *) &spiUnit->dmaRxTCD,
\r
1571 spiUnit->dmaRxChannel);
\r
1572 /* Flush TX/Rx FIFO. Ref. man. 23.5.1 step 8 */
\r
1573 spiHw->MCR.B.CLR_RXF = 1;
\r
1574 spiHw->MCR.B.CLR_TXF = 1;
\r
1576 Dma_StartChannel(spiUnit->dmaRxChannel);
\r
1577 Dma_StartChannel(spiUnit->dmaTxChannel);
\r
1579 // Step 9. Clear TCNT
\r
1580 spiHw->TCR.B.SPI_TCNT = 0;
\r
1582 if ( (Spi_Global.asyncMode == SPI_INTERRUPT_MODE) &&
\r
1583 (spiUnit->callType == SPI_ASYNC_CALL)) {
\r
1584 ENABLE_EOQ_INTERRUPT(spiHw);
\r
1586 DISABLE_EOQ_INTERRUPT(spiHw);
\r
1589 /* This will trig a new transfer. Ref. man. 23.5.1 step 11 */
\r
1590 spiHw->SR.B.EOQF = 1;
\r
1591 spiHw->MCR.B.HALT = 0;
\r
1593 // Since it's not obvious on how to tell when a SPI sequence
\r
1594 // is sent, keep things below to what things have been tested.
\r
1595 #if defined(STEP_VALIDATION)
\r
1596 /* Wait for transfer to complete (EOQF bit is set) */
\r
1597 while (spiHw->SR.B.EOQF==1) {
\r
1598 Spi_Global.eoqf_cnt++;
\r
1600 while (spiHw->SR.B.TXRXS) {Spi_Global.txrxs_cnt++;}
\r
1601 while( EDMA.TCD[spiUnit->dmaRxChannel].ACTIVE ) {;}
\r
1608 #if (SPI_IMPLEMENTATION==SPI_FIFO)
\r
1612 * @param jobConfig
\r
1615 static void Spi_WriteJob_FIFO( Spi_JobType jobIndex )
\r
1617 Spi_ChannelType currChannel;
\r
1618 Spi_CommandType cmd;
\r
1619 Spi_CommandType dCmd;
\r
1620 Spi_NumberOfDataType bufLen;
\r
1621 const Spi_ChannelConfigType * chConfig;
\r
1622 Spi_JobUnitType * jobUnitPtr;
\r
1623 const Spi_DataType * buf;
\r
1624 Spi_NumberOfDataType copyCnt;
\r
1625 Spi_NumberOfDataType fifoLeft;
\r
1626 // boolean done = 0;
\r
1627 // boolean lastJob = 0;
\r
1629 jobUnitPtr = &Spi_JobUnit[jobIndex];
\r
1632 fifoLeft = FIFO_DEPTH;
\r
1634 RAMLOG_STR("Spi_WriteJob_FIFO\n");
\r
1636 #if defined(STEP_VALIDATION)
\r
1637 if( jobUnitPtr->hwPtr->SR.B.TXCTR != 0 ) {
\r
1643 dCmd.R = 0xfffffffful;
\r
1645 /* Iterate over the channels for this job */
\r
1646 currChannel = jobUnitPtr->channelsPtr[jobUnitPtr->currTxChIndex];
\r
1647 while ( fifoLeft != 0) {
\r
1649 chConfig = &Spi_Global.configPtr->SpiChannelConfig[currChannel];
\r
1650 buf = spiGetTxBuf( currChannel, &bufLen);
\r
1652 /* Minimum of how much data to copy and the limit of the FIFO */
\r
1653 copyCnt = MIN( (bufLen - jobUnitPtr->txChCnt) >> ((chConfig->SpiDataWidth-1)/8), fifoLeft );
\r
1655 /* Channels should keep CS active ( A job must assert CS continuously) */
\r
1657 /* Set the Chip Select (PCS) */
\r
1658 cmd.R |= (1 << (16 + jobUnitPtr->extDeviceCfgPtr->SpiCsIdentifier));
\r
1660 #if defined(STEP_VALIDATION)
\r
1661 if( cmd.B.EOQ == 1) {
\r
1666 /* Push as much as we can (FIFO or Channel limits) */
\r
1667 for(i=0; i < copyCnt ; i++ ) {
\r
1668 cmd.B.CTAS = Spi_ChannelInfo[currChannel].ctarId;
\r
1669 if (buf != NULL) {
\r
1670 if (chConfig->SpiDataWidth > 8 ) {
\r
1671 cmd.B.TXDATA = (buf[jobUnitPtr->txChCnt] << 8) +
\r
1672 (buf[jobUnitPtr->txChCnt + 1] & 0xff);
\r
1674 cmd.B.TXDATA = buf[jobUnitPtr->txChCnt];
\r
1677 cmd.B.TXDATA = chConfig->SpiDefaultData;
\r
1680 if (chConfig->SpiDataWidth > 8 ) {
\r
1681 jobUnitPtr->txChCnt+=2;
\r
1683 jobUnitPtr->txChCnt++;
\r
1687 if( dCmd.R != 0xfffffffful) {
\r
1688 jobUnitPtr->hwPtr->PUSHR.R = dCmd.R; // Write delayed
\r
1691 dCmd.R = cmd.R; // Save it
\r
1695 RAMLOG_STR("CI#");RAMLOG_DEC(jobUnitPtr->currTxChIndex);RAMLOG_STR("\n");
\r
1698 /* Done with channel? */
\r
1699 if( ((bufLen - jobUnitPtr->txChCnt) == 0) ) {
\r
1700 jobUnitPtr->txChCnt = 0;
\r
1701 /* Done with job? */
\r
1702 jobUnitPtr->currTxChIndex++;
\r
1703 currChannel = jobUnitPtr->channelsPtr[jobUnitPtr->currTxChIndex];
\r
1704 if( currChannel == CH_NOT_VALID ) {
\r
1705 jobUnitPtr->currTxChIndex = 0;
\r
1714 jobUnitPtr->hwPtr->PUSHR.R = cmd.R;
\r
1716 jobUnitPtr->fifoSent = FIFO_DEPTH - fifoLeft;
\r
1718 #if defined(STEP_VALIDATION)
\r
1719 if( jobUnitPtr->fifoSent != jobUnitPtr->hwPtr->SR.B.TXCTR ) {
\r
1724 jobUnitPtr->hwPtr->TCR.B.SPI_TCNT = 0;
\r
1726 if ( (Spi_Global.asyncMode == SPI_INTERRUPT_MODE) &&
\r
1727 (jobUnitPtr->unitPtr->callType == SPI_ASYNC_CALL)) {
\r
1728 ENABLE_EOQ_INTERRUPT(jobUnitPtr->hwPtr);
\r
1730 DISABLE_EOQ_INTERRUPT(jobUnitPtr->hwPtr);
\r
1733 #if defined(STEP_VALIDATION)
\r
1734 /* Verify FIFO before sending */
\r
1736 SPICommandType *base = (SPICommandType *)&jobUnitPtr->hwPtr->TXFR[0];
\r
1737 SPICommandType *curr;
\r
1740 i = jobUnitPtr->hwPtr->SR.B.TXNXTPTR; /* Next entry to send */
\r
1741 lastIndex = ( i + jobUnitPtr->hwPtr->SR.B.TXCTR - 1 ) % FIFO_DEPTH;
\r
1742 while( i != lastIndex ) {
\r
1744 if( curr->B.EOQ == 1) { /* This entry must not have EOQ set */
\r
1748 i = (i + 1) % FIFO_DEPTH;
\r
1751 if( curr->B.EOQ != 1) {
\r
1752 SPI_ASSERT(0); /* Last entry must have EOQ set */
\r
1757 jobUnitPtr->hwPtr->SR.B.EOQF = 1;
\r
1758 jobUnitPtr->hwPtr->MCR.B.HALT = 0;
\r
1760 #if defined(STEP_VALIDATION)
\r
1761 /* Wait for transfer to complete (EOQF bit is set) */
\r
1762 while (jobUnitPtr->hwPtr->SR.B.EOQF==1) {
\r
1763 Spi_Global.eoqf_cnt++;
\r
1765 while (jobUnitPtr->hwPtr->SR.B.TXRXS) {Spi_Global.txrxs_cnt++;}
\r
1768 // TODO: Clear FIFO's? CLR_TXF?
\r
1771 #endif /* (SPI_IMPLEMENTATION==SPI_FIFO) */
\r
1774 //-------------------------------------------------------------------
\r
1780 * Write a job to the SPI bus
\r
1782 * @param jobIndex The job to write to the SPI bus
\r
1784 static void Spi_JobWrite(Spi_JobType jobIndex) {
\r
1785 Spi_UnitType *uPtr = Spi_JobUnit[jobIndex].unitPtr;
\r
1787 uPtr->txCurrIndex = 0;
\r
1788 uPtr->currJob = Spi_JobUnit[jobIndex].jobCfgPtr;
\r
1789 uPtr->currJobIndex = jobIndex;
\r
1790 #if (SPI_IMPLEMENTATION == SPI_FIFO)
\r
1791 Spi_JobUnit[jobIndex].txChCnt = 0;
\r
1792 Spi_JobUnit[jobIndex].rxChCnt = 0;
\r
1795 Spi_SetHWUnitStatus(uPtr, SPI_BUSY);
\r
1796 Spi_SetJobResult(jobIndex, SPI_JOB_PENDING);
\r
1798 #if (USE_DIO_CS == STD_ON)
\r
1799 if( Spi_JobUnit[jobIndex].extDeviceCfgPtr->SpiCsCallback != NULL ) {
\r
1800 Spi_JobUnit[jobIndex].extDeviceCfgPtr->SpiCsCallback(1);
\r
1804 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
1805 Spi_DoWrite_DMA( uPtr, jobIndex, Spi_JobUnit[jobIndex].jobCfgPtr );
\r
1806 #elif (SPI_IMPLEMENTATION==SPI_FIFO)
\r
1807 Spi_JobUnit[jobIndex].currTxChIndex = 0;
\r
1808 Spi_WriteJob_FIFO ( jobIndex );
\r
1813 #if defined(USE_LDEBUG_PRINTF) && ( DEBUG_LVL <= DEBUG_HIGH )
\r
1814 void Spi_PrintSeqInfo(const Spi_SequenceConfigType *seqConfigPtr) {
\r
1817 DEBUG(DEBUG_HIGH,"%s: Seq: %d:",MODULE_NAME,seqConfigPtr->SpiSequenceId);
\r
1819 while ((job = seqConfigPtr->JobAssignment[i]) != JOB_NOT_VALID) {
\r
1820 DEBUG(DEBUG_HIGH,"%d ",job);
\r
1822 } DEBUG(DEBUG_HIGH,"\n");
\r
1828 * Write a sequence to the SPI bus
\r
1830 * @param seqIndex The sequence
\r
1831 * @param sync 1 - make the call sync. 0 - make the call async
\r
1833 static void Spi_SeqWrite(Spi_SequenceType seqIndex, Spi_CallTypeType sync) {
\r
1835 const Spi_SequenceConfigType *seqConfig;
\r
1836 const Spi_JobConfigType *jobConfig;
\r
1837 Spi_UnitType *uPtr;
\r
1838 Spi_JobType jobIndex;
\r
1840 seqConfig = Spi_GetSeqPtrFromIndex(seqIndex);
\r
1841 jobIndex = seqConfig->JobAssignment[0];
\r
1842 jobConfig = Spi_GetJobPtrFromIndex(jobIndex);
\r
1844 uPtr = GET_SPI_UNIT_PTR(jobConfig->SpiHwUnit);
\r
1846 /* Fill in the required fields for job and sequence.. */
\r
1847 uPtr->currJobIndexPtr = &seqConfig->JobAssignment[0];
\r
1848 uPtr->callType = sync;
\r
1849 uPtr->currSeqPtr = seqConfig;
\r
1851 Spi_SetSequenceResult(seqIndex, SPI_SEQ_PENDING);
\r
1853 // Setup interrupt for end of queue
\r
1854 if ( (Spi_Global.asyncMode == SPI_INTERRUPT_MODE) &&
\r
1855 (uPtr->callType== SPI_ASYNC_CALL)) {
\r
1856 DEBUG(DEBUG_MEDIUM,"%s: async/interrupt mode\n",MODULE_NAME);
\r
1858 DEBUG(DEBUG_MEDIUM,"%s: sync/polled mode\n",MODULE_NAME);
\r
1861 #if defined(USE_LDEBUG_PRINTF) && ( DEBUG_LVL <= DEBUG_HIGH )
\r
1862 Spi_PrintSeqInfo( seqConfig );
\r
1865 Spi_JobWrite(jobIndex);
\r
1867 if (uPtr->callType == SPI_SYNC_CALL) {
\r
1868 while (Spi_GetSequenceResult(seqIndex) == SPI_SEQ_PENDING) {
\r
1875 //-------------------------------------------------------------------
\r
1876 static _Bool Spi_AnyPendingJobs(Spi_SequenceType Sequence) {
\r
1878 // Check that we don't share any jobs with another sequence that is SPI_SEQ_PENDING
\r
1879 for (int i = 0; i < SPI_MAX_SEQUENCE; i++) {
\r
1880 if (i == Sequence) {
\r
1884 if (Spi_GetSequenceResult(i) == SPI_SEQ_PENDING) {
\r
1885 // We have found a pending sequence... check that we don't share any jobs
\r
1886 // with that sequence, SPI086
\r
1887 if (Spi_ShareJobs(Sequence, i)) {
\r
1896 //-------------------------------------------------------------------
\r
1905 Std_ReturnType Spi_SyncTransmit(Spi_SequenceType Sequence) {
\r
1907 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_SYNCTRANSMIT_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
1908 VALIDATE_W_RV( ( SPI_MAX_SEQUENCE>Sequence ), SPI_SYNCTRANSMIT_SERVICE_ID, SPI_E_PARAM_SEQ, E_NOT_OK );
\r
1909 Std_ReturnType rv = E_OK;
\r
1911 if (Spi_GetSequenceResult(Sequence) == SPI_SEQ_PENDING) {
\r
1912 DEBUG(DEBUG_LOW,"%s: Spi_AsyncTransmit() is PENDING\n",MODULE_NAME);
\r
1913 return E_NOT_OK; // SPI157
\r
1916 assert(Spi_GetSequenceResult(Sequence) == SPI_SEQ_OK);
\r
1918 if (Spi_AnyPendingJobs(Sequence)) {
\r
1922 Spi_SeqWrite(Sequence, SPI_SYNC_CALL);
\r
1927 //-------------------------------------------------------------------
\r
1929 Std_ReturnType Spi_AsyncTransmit(Spi_SequenceType Sequence) {
\r
1930 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_ASYNCTRANSMIT_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
1931 VALIDATE_W_RV( ( SPI_MAX_SEQUENCE>Sequence ), SPI_ASYNCTRANSMIT_SERVICE_ID, SPI_E_PARAM_SEQ, E_NOT_OK );
\r
1933 if (Spi_GetSequenceResult(Sequence) == SPI_SEQ_PENDING) {
\r
1934 DEBUG(DEBUG_LOW,"%s: Spi_AsyncTransmit() is PENDING\n",MODULE_NAME);
\r
1935 return E_NOT_OK; // SPI157
\r
1938 assert(Spi_GetSequenceResult(Sequence) == SPI_SEQ_OK);
\r
1940 if (Spi_AnyPendingJobs(Sequence)) {
\r
1944 DEBUG(DEBUG_LOW,"%s: Starting seq: %d\n",MODULE_NAME,Sequence);
\r
1946 Spi_SeqWrite(Sequence, SPI_ASYNC_CALL);
\r
1951 //-------------------------------------------------------------------
\r
1954 Std_ReturnType Spi_ReadIB( Spi_ChannelType Channel,
\r
1955 Spi_DataType * const DataBufferPtr)
\r
1957 (void)DataBufferPtr;
\r
1959 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_READIB_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
1960 VALIDATE_W_RV( ( Channel<SPI_MAX_CHANNEL ), SPI_READIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
1961 VALIDATE_W_RV( ( SPI_IB<Spi_Global.configPtr->SpiChannelConfig[Channel].SpiChannelType ),
\r
1962 SPI_READIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
1964 /* NOT SUPPORTED */
\r
1966 Std_ReturnType rv = E_NOT_OK;
\r
1970 //-------------------------------------------------------------------
\r
1972 Std_ReturnType Spi_SetupEB( Spi_ChannelType Channel,
\r
1973 const Spi_DataType* SrcDataBufferPtr,
\r
1974 Spi_DataType* DesDataBufferPtr,
\r
1975 Spi_NumberOfDataType Length)
\r
1977 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_SETUPEB_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
1978 VALIDATE_W_RV( ( Channel<SPI_MAX_CHANNEL ), SPI_SETUPEB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
1979 #if ( SPI_CHANNEL_BUFFERS_ALLOWED == 1 )
\r
1980 VALIDATE_W_RV( ( SPI_EB==Spi_Global.configPtr->SpiChannelConfig[Channel].SpiChannelType ),
\r
1981 SPI_SETUPEB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
1984 VALIDATE_W_RV( ( Length<=Spi_Global.configPtr->SpiChannelConfig[Channel].SpiEbMaxLength ),
\r
1985 SPI_SETUPEB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
1987 Spi_EbType *extChBuff = &Spi_Global.extBufPtr[Channel];
\r
1988 const Spi_ChannelConfigType *chConfig =
\r
1989 &Spi_Global.configPtr->SpiChannelConfig[Channel];
\r
1991 if (chConfig->SpiChannelType == SPI_EB) {
\r
1992 extChBuff->src = SrcDataBufferPtr;
\r
1993 extChBuff->dest = DesDataBufferPtr;
\r
1994 extChBuff->length = Length;
\r
1995 extChBuff->active = 1;
\r
1997 /* NOT SUPPORTED */
\r
2006 //-------------------------------------------------------------------
\r
2008 Spi_StatusType Spi_GetStatus(void) {
\r
2009 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_GETSTATUS_SERVICE_ID, SPI_E_UNINIT, SPI_UNINIT );
\r
2011 // Check all sequences if they have any job pending
\r
2012 for (int i = 0; i < SPI_MAX_SEQUENCE; i++) {
\r
2013 if (Spi_GetSequenceResult(i) == SPI_SEQ_PENDING) {
\r
2021 //-------------------------------------------------------------------
\r
2024 Spi_JobResultType Spi_GetJobResult(Spi_JobType Job) {
\r
2025 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_GETJOBRESULT_SERVICE_ID, SPI_E_UNINIT, SPI_JOB_FAILED );
\r
2026 VALIDATE_W_RV( ( SPI_MAX_JOB<Job ), SPI_GETJOBRESULT_SERVICE_ID, SPI_E_PARAM_JOB, SPI_JOB_FAILED );
\r
2028 return Spi_JobUnit[Job].jobResult;
\r
2031 //-------------------------------------------------------------------
\r
2034 Spi_SeqResultType Spi_GetSequenceResult(Spi_SequenceType Sequence) {
\r
2035 Spi_SeqResultType rv;
\r
2037 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_GETSEQUENCERESULT_SERVICE_ID, SPI_E_UNINIT, SPI_SEQ_FAILED );
\r
2038 VALIDATE_W_RV( ( SPI_MAX_SEQUENCE>Sequence ), SPI_GETSEQUENCERESULT_SERVICE_ID, SPI_E_PARAM_SEQ, SPI_SEQ_FAILED );
\r
2040 rv = Spi_SeqUnit[Sequence].seqResult;
\r
2045 //-------------------------------------------------------------------
\r
2047 Spi_StatusType Spi_GetHWUnitStatus(Spi_HWUnitType HWUnit) {
\r
2048 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_GETHWUNITSTATUS_SERVICE_ID, SPI_E_UNINIT, SPI_UNINIT );
\r
2050 return (GET_SPI_UNIT_PTR(HWUnit))->status;
\r
2053 //-------------------------------------------------------------------
\r
2055 #if (SPI_CANCEL_API == STD_ON )
\r
2056 void Spi_Cancel( Spi_SequenceType Sequence ) {
\r
2057 VALIDATE( ( TRUE == Spi_Global.initRun ), SPI_CANCEL_SERVICE_ID, SPI_E_UNINIT );
\r
2058 VALIDATE( ( SPI_MAX_SEQUENCE<Sequence ), SPI_CANCEL_SERVICE_ID, SPI_E_PARAM_SEQ );
\r
2060 /* NOT SUPPORTED */
\r
2064 //-------------------------------------------------------------------
\r
2067 #if ( SPI_LEVEL_DELIVERED == 2) // SPI154
\r
2068 Std_ReturnType Spi_SetAsyncMode(Spi_AsyncModeType Mode) {
\r
2069 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_SETASYNCMODE_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
2072 // Not really sure by whom this function is supposed to be called by.
\r
2073 // The users of SPI(e2,flash,etc) should probably not use this.
\r
2075 for (int i = 0; i < SPI_MAX_SEQUENCE; i++) {
\r
2076 if (Spi_GetSequenceResult(i) == SPI_SEQ_PENDING) {
\r
2081 Spi_Global.asyncMode = Mode;
\r
2087 //-------------------------------------------------------------------
\r
2089 void Spi_MainFunction_Handling(void) {
\r
2090 /* NOT SUPPORTED */
\r
2093 //-------------------------------------------------------------------
\r
2095 void Spi_MainFunction_Driving(void) {
\r
2096 volatile struct DSPI_tag *spiHw;
\r
2099 Spi_UnitType *uPtr;
\r
2101 // TODO: check that the queue is empty.. if so do the next job.
\r
2102 if (Spi_Global.asyncMode == SPI_POLLING_MODE) {
\r
2103 confMask = Spi_Global.spiHwConfigured;
\r
2105 for (; confMask; confMask &= ~(1 << ctrlNr)) {
\r
2106 ctrlNr = ilog2(confMask);
\r
2107 uPtr = GET_SPI_UNIT_PTR(ctrlNr);
\r
2108 spiHw = uPtr->hwPtr;
\r
2110 if (Spi_GetHWUnitStatus(ctrlNr) == SPI_BUSY) {
\r
2111 if (spiHw->SR.B.TXRXS) {
\r
2112 // Still not done..
\r
2114 uPtr = GET_SPI_UNIT_PTR(ctrlNr);
\r