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 static void Spi_Isr_E(void) {
\r
499 Spi_Isr(GET_SPI_UNIT_PTR(DSPI_CTRL_E));
\r
501 static void Spi_Isr_F(void) {
\r
502 Spi_Isr(GET_SPI_UNIT_PTR(DSPI_CTRL_F));
\r
504 /* ----------------------------[public functions]----------------------------*/
\r
506 uint32 Spi_GetJobCnt(void);
\r
507 uint32 Spi_GetChannelCnt(void);
\r
508 uint32 Spi_GetExternalDeviceCnt(void);
\r
511 static void Spi_Isr_DMA( void )
\r
514 Dma_ClearInterrupt(5);
\r
518 static void Spi_JobWrite(Spi_JobType jobIndex);
\r
520 static void Spi_SetJobResult(Spi_JobType Job, Spi_JobResultType result) {
\r
521 Spi_JobUnit[Job].jobResult = result;
\r
524 static void Spi_SetHWUnitStatus( Spi_UnitType *uPtr, Spi_StatusType status) {
\r
525 uPtr->status = status;
\r
529 * Get external Ptr to device from index
\r
531 * @param deviceType The device index.
\r
532 * @return Ptr to the external device
\r
535 static inline const Spi_ExternalDeviceType *Spi_GetExternalDevicePtrFromIndex(
\r
536 Spi_ExternalDeviceTypeType deviceType) {
\r
537 return (&(Spi_Global.configPtr->SpiExternalDevice[(deviceType)]));
\r
541 * Get configuration job ptr from job index
\r
542 * @param jobIndex the job
\r
543 * @return Ptr to the job configuration
\r
545 static const Spi_JobConfigType *Spi_GetJobPtrFromIndex(Spi_JobType jobIndex) {
\r
546 return &Spi_Global.configPtr->SpiJobConfig[jobIndex];
\r
550 * Get sequence ptr from sequence index
\r
551 * @param seqIndex the sequence
\r
552 * @return Ptr to the sequence configuration
\r
554 static const Spi_SequenceConfigType *Spi_GetSeqPtrFromIndex(
\r
555 Spi_SequenceType SeqIndex) {
\r
556 return &Spi_Global.configPtr->SpiSequenceConfig[SeqIndex];
\r
561 * Function to see if two sequences share jobs
\r
563 * @param seq - Seqence 1
\r
564 * @param seq - Seqence 2
\r
565 * @return 0 - if the don't share any jobs
\r
566 * !=0 - if they share jobs
\r
569 static boolean Spi_ShareJobs(Spi_SequenceType seq1, Spi_SequenceType seq2) {
\r
570 uint32 seqMask1 = 0;
\r
571 uint32 seqMask2 = 0;
\r
572 const Spi_JobType *jobPtr;
\r
573 const Spi_SequenceConfigType *seqConfig;
\r
575 // Search for jobs in sequence 1
\r
576 seqConfig = Spi_GetSeqPtrFromIndex(seq1);
\r
577 jobPtr = &seqConfig->JobAssignment[0];
\r
579 while (*jobPtr != JOB_NOT_VALID) {
\r
580 assert(*jobPtr<31);
\r
581 seqMask1 |= (1 << *jobPtr);
\r
585 // Search for jobs in sequence 2
\r
586 seqConfig = Spi_GetSeqPtrFromIndex(seq2);
\r
587 jobPtr = &seqConfig->JobAssignment[0];
\r
589 while (*jobPtr != JOB_NOT_VALID) {
\r
590 assert(*jobPtr<31);
\r
591 seqMask2 |= (1 << *jobPtr);
\r
595 return (seqMask1 & seqMask2);
\r
599 //-------------------------------------------------------------------
\r
602 * Sets a result for a sequence
\r
604 * @param Sequence The sequence to set the result for
\r
605 * @param result The result to set.
\r
607 static void Spi_SetSequenceResult(Spi_SequenceType Sequence,
\r
608 Spi_SeqResultType result) {
\r
609 Spi_SeqUnit[Sequence].seqResult = result;
\r
612 //-------------------------------------------------------------------
\r
616 * Gets the next job to do
\r
618 * @param spiUnit The SPI unit
\r
619 * @return The job ID. -1 if no more jobs
\r
621 static Spi_JobType Spi_GetNextJob(Spi_UnitType *spiUnit) {
\r
622 spiUnit->currJobIndexPtr++;
\r
623 return *(spiUnit->currJobIndexPtr);
\r
625 //-------------------------------------------------------------------
\r
628 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
631 * Function to handle things after a transmit on the SPI is finished.
\r
632 * It copies data from it't local buffers to the buffers pointer to
\r
633 * by the external buffers
\r
635 * @param spiUnit Ptr to a SPI unit
\r
638 static int Spi_Rx_DMA(Spi_UnitType *spiUnit) {
\r
639 _Bool printedSomeThing = 0;
\r
641 /* Stop the channels */
\r
642 Dma_StopChannel(spiUnit->dmaTxChannel);
\r
643 Dma_StopChannel(spiUnit->dmaRxChannel);
\r
645 RAMLOG_STR("PostTransmit Job: "); RAMLOG_DEC(spiUnit->currJob->SpiJobId); RAMLOG_STR("\n");
\r
647 /* Copy data from RX queue to the external buffer( if a<uny ) */
\r
652 const Spi_ChannelConfigType *chConfig;
\r
653 Spi_EbType *extChBuff;
\r
657 // Check that we got the number of bytes we sent
\r
658 sentTx = spiUnit->txCurrIndex + 1;
\r
659 gotTx = (Dma_GetTcd(spiUnit->dmaRxChannel)->DADDR
\r
660 - (uint32) &spiUnit->rxQueue[0]) / sizeof(uint32);
\r
662 if (sentTx != gotTx) {
\r
663 // Something failed
\r
664 DEBUG(DEBUG_LOW,"%s: Expected %d bytes. Got %d bytes\n ",MODULE_NAME,sentTx, gotTx );
\r
665 #if defined(STEP_VALIDATION)
\r
670 RAMLOG_STR("Rx "); RAMLOG_DEC(gotTx); RAMLOG_STR(" Bytes\n"); DEBUG(DEBUG_LOW,"%s: Got %d bytes\n",MODULE_NAME,gotTx);
\r
673 // Find the channels for this job
\r
674 while ((channelIndex = spiUnit->currJob->ChannelAssignment[j++])
\r
676 chConfig = &Spi_Global.configPtr->SpiChannelConfig[channelIndex];
\r
678 /* Check configuration error */
\r
679 #if ( SPI_CHANNEL_BUFFERS_ALLOWED == 1 )
\r
680 assert( chConfig->SpiChannelType == SPI_EB );
\r
683 // Send the channels that are setup with external buffers
\r
684 // Get the external buffer for this channel
\r
685 extChBuff = &Spi_Global.extBufPtr[channelIndex];
\r
686 if (extChBuff->dest != NULL) {
\r
687 // Note! No support for >8 "data"
\r
688 for (int k = 0; k < extChBuff->length; k++) {
\r
689 extChBuff->dest[k] = spiUnit->rxQueue[currIndex++];
\r
690 DEBUG(DEBUG_LOW," %02x ",extChBuff->dest[k]);
\r
691 printedSomeThing = 1;
\r
695 if (chConfig->SpiDataWidth > 8) {
\r
696 currIndex += (extChBuff->length / 2);
\r
698 currIndex += extChBuff->length;
\r
702 if (printedSomeThing)
\r
703 DEBUG(DEBUG_LOW,"\n");
\r
709 #elif (SPI_IMPLEMENTATION==SPI_FIFO)
\r
711 static int Spi_Rx_FIFO(Spi_UnitType *spiUnit) {
\r
712 Spi_JobUnitType * jobUnitPtr;
\r
713 Spi_DataType * buf;
\r
716 Spi_ChannelType currChannel;
\r
717 Spi_NumberOfDataType bufLen;
\r
719 int rv = SPIE_JOB_NOT_DONE;
\r
720 const Spi_ChannelConfigType * chConfig;
\r
724 // RAMLOG_STR("PostTransmit Job: "); RAMLOG_DEC(spiUnit->currJob->SpiJobId); RAMLOG_STR("\n");
\r
725 RAMLOG_STR("Spi_Rx_FIFO\n");
\r
727 jobUnitPtr = &Spi_JobUnit[spiUnit->currJobIndex];
\r
729 if( jobUnitPtr->hwPtr->TCR.B.SPI_TCNT != jobUnitPtr->fifoSent ) {
\r
730 #if defined(STEP_VALIDATION)
\r
737 * Fill receive buffers, either EB or IB
\r
738 * Example with 8-bit CMD, 16-bit ADDR and some 8-bit data.
\r
739 * CMD | ADDR | DATA
\r
740 * | 12 | 23 | 34 | 00 | 01 | 02 | 03
\r
741 * 1 2 3 4 5 6 BYTE CNT
\r
742 * 1 2 3 4 (5) (6) FIFO
\r
743 * With a FIFO of 4 we can see that the CMD, ADDR and almost the whole
\r
744 * DATA channel is sent.
\r
746 currChannel = jobUnitPtr->channelsPtr[jobUnitPtr->currRxChIndex];
\r
747 assert( currChannel != CH_NOT_VALID );
\r
749 if( jobUnitPtr->fifoSent != jobUnitPtr->hwPtr->SR.B.RXCTR ) {
\r
750 #if defined(STEP_VALIDATION)
\r
756 while ( jobUnitPtr->fifoSent != 0 ) {
\r
758 chConfig = &Spi_Global.configPtr->SpiChannelConfig[currChannel];
\r
760 RAMLOG_STR("CIR#");RAMLOG_DEC(jobUnitPtr->currRxChIndex);RAMLOG_STR("\n");
\r
762 /* Get this channels destination buffer */
\r
763 buf = spiGetRxBuf(currChannel, &bufLen);
\r
764 assert(bufLen!=0); /* We should always get a valid bufLen */
\r
766 copyCnt = MIN( (bufLen - jobUnitPtr->rxChCnt) >> ((chConfig->SpiDataWidth-1)/8), jobUnitPtr->fifoSent );
\r
768 if( copyCnt == 0 ) {
\r
769 #if defined(STEP_VALIDATION)
\r
775 jobUnitPtr->fifoSent -= copyCnt;
\r
777 bInChar = (chConfig->SpiDataWidth > 8 ) ? 2 : 1;
\r
780 if( buf != NULL ) {
\r
781 for(i=0;i<copyCnt;i++) {
\r
782 popVal = jobUnitPtr->hwPtr->POPR.B.RXDATA;
\r
783 RAMLOG_STR("%");RAMLOG_HEX(popVal);
\r
784 buf[jobUnitPtr->rxChCnt] = (Spi_DataType)popVal;
\r
785 jobUnitPtr->rxChCnt += bInChar;
\r
788 for(i=0;i<copyCnt;i++) {
\r
789 popVal = jobUnitPtr->hwPtr->POPR.B.RXDATA;
\r
790 jobUnitPtr->rxChCnt += bInChar;
\r
794 if( (bufLen - jobUnitPtr->rxChCnt ) == 0 ) {
\r
795 /* advance to the next channel */
\r
796 jobUnitPtr->rxChCnt = 0;
\r
797 jobUnitPtr->currRxChIndex++;
\r
798 currChannel = jobUnitPtr->channelsPtr[jobUnitPtr->currRxChIndex];
\r
799 if( currChannel == CH_NOT_VALID ) {
\r
800 //assert( jobUnitPtr->fifoSent == 0);
\r
801 jobUnitPtr->fifoSent = 0;
\r
802 jobUnitPtr->currRxChIndex = 0;
\r
810 #if defined(STEP_VALIDATION)
\r
811 /* Check if we are done with this job */
\r
812 if( 0 != jobUnitPtr->hwPtr->SR.B.RXCTR ) {
\r
822 //-------------------------------------------------------------------
\r
825 * ISR for End of Queue interrupt
\r
827 * The interrupt handling is quite simple. Since this driver assumes
\r
828 * that we are the master the EOQ interrupt is sufficient to check.
\r
830 * @param unit The HW unit it happend on
\r
832 static void Spi_Isr( Spi_UnitType *uPtr) {
\r
833 volatile struct DSPI_tag *spiHw = uPtr->hwPtr;
\r
836 RAMLOG_STR("Spi_Isr\n");
\r
838 // This may seem pretty stupid to wait for the controller
\r
839 // to shutdown here, but there seems to be no other way to do this.
\r
841 // - Waiting for DMA rx/tx hits earlier than EOQ.
\r
842 // - Other interrupts from SPI all hit earlier than EOQ.
\r
843 // TODO: There is the TCF_RE bit! Use this instead?
\r
845 // TODO: We could implement a timeout here and fail the job
\r
846 // if this never happens.
\r
848 // This is the busy wait when called from a non-interrupt context
\r
849 while (spiHw->SR.B.TXRXS) {
\r
850 Spi_Global.totalNbrOfWaitTXRXS++;
\r
853 #if (SPI_IMPLEMENTATION == SPI_DMA)
\r
854 while (!Dma_ChannelDone(uPtr->dmaRxChannel)) {
\r
855 Spi_Global.totalNbrOfWaitRxDMA++;
\r
859 #if defined(STEP_VALIDATION)
\r
860 /* Since EOQF clears TXRXS */
\r
861 SPI_ASSERT( (spiHw->SR.B.EOQF==1) && (spiHw->SR.B.TXRXS == 0));
\r
864 /* Halt DSPI unit until we are ready for next transfer. */
\r
865 spiHw->MCR.B.HALT = 1;
\r
866 spiHw->SR.B.EOQF = 1;
\r
869 Spi_Global.totalNbrOfTranfers++;
\r
871 // Disable EOQ interrupts
\r
873 // This does NOT clear the interrupt request.
\r
874 // That can only be done by clearing( setting ) the EOQ
\r
875 // bit.. but that also triggers a new transfer.
\r
878 // A possibility could be to use the HALT bit instead of
\r
879 // using this trick, but hey, this works
\r
881 DISABLE_EOQ_INTERRUPT(spiHw);
\r
883 // Update external buffers
\r
884 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
885 rv = Spi_Rx_DMA(uPtr);
\r
887 #if (USE_DIO_CS == STD_ON)
\r
888 void (*cb)(int) = Spi_JobUnit[uPtr->currJobIndex].extDeviceCfgPtr->SpiCsCallback;
\r
893 #elif (SPI_IMPLEMENTATION==SPI_FIFO)
\r
894 rv = Spi_Rx_FIFO(uPtr);
\r
896 if( rv == SPIE_JOB_NOT_DONE ) {
\r
897 /* RX FIFO now empty, but the job is not done -> send more */
\r
898 Spi_WriteJob_FIFO ( uPtr->currJobIndex );
\r
899 RAMLOG_STR("Spi_Isr END\n");
\r
902 #if (USE_DIO_CS == STD_ON)
\r
904 void (*cb)(int) = Spi_JobUnit[uPtr->currJobIndex].extDeviceCfgPtr->SpiCsCallback;
\r
912 // Call notification end
\r
913 if (uPtr->currJob->SpiJobEndNotification != NULL) {
\r
914 uPtr->currJob->SpiJobEndNotification();
\r
917 if (rv == SPIE_BAD) {
\r
918 // Fail both job and sequence
\r
919 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);
\r
920 Spi_SetJobResult(uPtr->currJob->SpiJobId, SPI_JOB_FAILED);
\r
921 Spi_SetSequenceResult(uPtr->currSeqPtr->SpiSequenceId,
\r
923 #if defined(STEP_VALIDATION)
\r
927 Spi_JobType nextJob;
\r
929 // The job is at least done..
\r
930 Spi_SetJobResult(uPtr->currJob->SpiJobId, SPI_JOB_OK);
\r
932 // WriteNextJob should
\r
933 // 1. Update the JobResult to SPI_JOB_OK
\r
934 // 2. Update the HWUnit status to IDLE
\r
937 // - Jobs have the controller
\r
938 // - Sequences can we interruptible between jobs.
\r
940 // According to SPI086 you can't share a job with a sequence that
\r
941 // is in SPI_SEQ_PENDING ( that happens first thing at Spi_AsyncTranmit() )
\r
943 // So, I no clue what to use the priority thing for :(
\r
945 nextJob = Spi_GetNextJob(uPtr);
\r
946 if( nextJob != JOB_NOT_VALID ) {
\r
947 Spi_JobWrite(nextJob);
\r
948 RAMLOG_STR("more_jobs\n");
\r
950 // No more jobs, so set HwUnit and sequence IDLE/OK also.
\r
951 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);
\r
952 Spi_SetSequenceResult(uPtr->currSeqPtr->SpiSequenceId,
\r
955 if (uPtr->currSeqPtr->SpiSeqEndNotification != NULL) {
\r
956 uPtr->currSeqPtr->SpiSeqEndNotification();
\r
959 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);
\r
961 /* We are now ready for next transfer. */
\r
962 spiHw->MCR.B.HALT = 1;
\r
964 RAMLOG_STR("NO_more_jobs\n");
\r
968 RAMLOG_STR("Spi_Isr END\n");
\r
971 //-------------------------------------------------------------------
\r
973 Std_ReturnType Spi_WriteIB(Spi_ChannelType Channel,
\r
974 const Spi_DataType *DataBufferPtr) {
\r
975 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_WRITEIB_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
976 VALIDATE_W_RV( ( Channel<SPI_MAX_CHANNEL ), SPI_WRITEIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
977 VALIDATE_W_RV( ( DataBufferPtr != NULL ), SPI_WRITEIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
978 VALIDATE_W_RV( ( SPI_IB==Spi_Global.configPtr->SpiChannelConfig[Channel].SpiChannelType ),
\r
979 SPI_WRITEIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
981 /* According to SPI051 it seems that we only have to a "depth" of 1 */
\r
984 Std_ReturnType rv = E_NOT_OK;
\r
989 const uint32 clk_table_asc[] = { 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
\r
990 4096, 8192, 16384, 32768, 65536 };
\r
991 const uint32 clk_table_cssck[] = { 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
\r
992 4096, 8192, 16384, 32768, 65536 };
\r
993 const uint16 clk_table_br[] = { 2, 4, 6, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
\r
994 4096, 8192, 16384, 32768 };
\r
995 const uint8 clk_table_pasc[] = { 1, 3, 5, 7 };
\r
996 const uint8 clk_table_pcssck[] = { 1, 3, 5, 7 };
\r
997 const uint8 clk_table_pbr[] = { 2, 3, 5, 7 };
\r
1000 * Function to setup CTAR's from configuration
\r
1001 * @param spiHw - Pointer to HW SPI device
\r
1002 * @param extDev - Pointer to external device configuration
\r
1003 * @param ctar_unit - The ctar unit number to setup
\r
1004 * @param width - The width in bits of the data to send with the CTAR
\r
1006 static void Spi_SetupCTAR( Spi_HWUnitType unit,
\r
1007 const Spi_ExternalDeviceType *extDev,
\r
1008 Spi_ChannelType ctar_unit,
\r
1009 Spi_TransferStartType transferStart,
\r
1017 McuE_PeriperalClock_t perClock;
\r
1019 volatile struct DSPI_tag *spiHw = GET_SPI_HW_PTR(unit);
\r
1020 /* BAUDRATE CALCULATION
\r
1021 * -----------------------------
\r
1022 * Baudrate = Fsys/ PBR * ( 1+ DBR) / BR
\r
1023 * PBR range: 2 to 7
\r
1024 * DBR range: 0 to 1
\r
1027 * To make this easy set DBR = 0 and PBR=2
\r
1028 * --> BR=Fsys/(Baudrate.* 2 )
\r
1034 perClock = PERIPHERAL_CLOCK_DSPI_A;
\r
1037 perClock = PERIPHERAL_CLOCK_DSPI_B;
\r
1039 #if (SPI_CONTROLLER_TOTAL_CNT>2)
\r
1041 perClock = PERIPHERAL_CLOCK_DSPI_C;
\r
1044 #if (SPI_CONTROLLER_TOTAL_CNT>3)
\r
1046 perClock = PERIPHERAL_CLOCK_DSPI_D;
\r
1049 #if (SPI_CONTROLLER_TOTAL_CNT>4)
\r
1051 perClock = PERIPHERAL_CLOCK_DSPI_E;
\r
1054 #if (SPI_CONTROLLER_TOTAL_CNT>5)
\r
1056 perClock = PERIPHERAL_CLOCK_DSPI_F;
\r
1064 clock = McuE_GetPeripheralClock(perClock);
\r
1066 DEBUG(DEBUG_MEDIUM,"%s: Peripheral clock at %d Mhz\n",MODULE_NAME,clock);
\r
1068 DEBUG(DEBUG_MEDIUM,"%s: Want to run at %d Mhz\n",MODULE_NAME,extDev->SpiBaudrate);
\r
1070 spiHw->CTAR[ctar_unit].B.DBR = 0;
\r
1071 spiHw->CTAR[ctar_unit].B.PBR = 0; // 2
\r
1072 pre_br = clock / (extDev->SpiBaudrate
\r
1073 * clk_table_pbr[spiHw->CTAR[ctar_unit].B.PBR]);
\r
1075 // find closest lesser
\r
1076 for (i = 0; i < sizeof(clk_table_br) / sizeof(clk_table_br[0]); i++) {
\r
1077 if (clk_table_br[i] >= pre_br) {
\r
1084 spiHw->CTAR[ctar_unit].B.BR = i;
\r
1086 DEBUG(DEBUG_LOW,"%s: CLK %d Mhz\n",MODULE_NAME,
\r
1087 clock / clk_table_pbr[spiHw->CTAR[ctar_unit].B.PBR] *
\r
1088 ( 1 + spiHw->CTAR[ctar_unit].B.DBR)/clk_table_br[spiHw->CTAR[ctar_unit].B.BR]);
\r
1090 /* For other timings autosar only specifies SpiTimeClk2Cs == "After SCK delay"
\r
1091 * in Freescale language. The dumb thing is that this should be a relative time
\r
1092 * to the clock. Not fixed.
\r
1093 * Autosar specifies 0.0--100.0 ms(float)
\r
1094 * Our intepretation is 0--1000000 ns (uint32)
\r
1096 * AFTER SCK DELAY:
\r
1097 * -----------------------------
\r
1098 * Tasc = 1/Fsys * PASC * ASC [s]
\r
1100 * Assume the Tasc get's here in ns( typical range is ~10ns )
\r
1103 // Calc the PASC * ASC value...
\r
1104 tmp = extDev->SpiTimeClk2Cs * (clock / 1000000);
\r
1106 // Nothing fancy here...
\r
1110 int b_value = INT_MAX;
\r
1113 // Find the best match of Prescaler and Scaler value
\r
1114 for (i = 0; i < ARRAY_SIZE(clk_table_pasc); i++) {
\r
1115 for (j = 0; j < ARRAY_SIZE(clk_table_asc); j++) {
\r
1116 tt = abs((int) clk_table_pasc[i] * clk_table_asc[j] * 1000
\r
1118 if (tt < b_value) {
\r
1126 /* After SCK delay. */
\r
1127 spiHw->CTAR[ctar_unit].B.PASC = best_i;
\r
1128 spiHw->CTAR[ctar_unit].B.ASC = best_j;
\r
1131 DEBUG(DEBUG_MEDIUM,"%s: Timing: Tasc %d ns\n",MODULE_NAME,
\r
1132 clk_table_pasc[spiHw->CTAR[ctar_unit].B.PASC] *
\r
1133 clk_table_asc[spiHw->CTAR[ctar_unit].B.ASC] * 1000/ (clock/1000000) );
\r
1135 /* The PCS to SCK delay is the delay between the assertion of PCS and
\r
1136 * the first edge the SCK.
\r
1138 * PCS TO SCK DELAY:
\r
1139 * -----------------------------
\r
1140 * Tcsc = 1/Fsys * PCSSCK * CSSCK [s]
\r
1143 // Calc the PCSSCK * CSSCK value...
\r
1144 tmp = extDev->SpiTimeCs2Clk * (clock / 1000000);
\r
1146 // Nothing fancy here...
\r
1150 int b_value = INT_MAX;
\r
1153 // Find the best match of Prescaler and Scaler value
\r
1154 for (i = 0; i < ARRAY_SIZE(clk_table_pcssck); i++) {
\r
1155 for (j = 0; j < ARRAY_SIZE(clk_table_cssck); j++) {
\r
1156 tt = abs((int) clk_table_pcssck[i] * clk_table_cssck[j] * 1000
\r
1158 if (tt < b_value) {
\r
1166 /* PCS to SCK delay */
\r
1167 spiHw->CTAR[ctar_unit].B.PCSSCK = best_i;
\r
1168 spiHw->CTAR[ctar_unit].B.CSSCK = best_j;
\r
1171 DEBUG(DEBUG_MEDIUM,"%s: Timing: Tcsc %d ns\n",MODULE_NAME,
\r
1172 clk_table_pcssck[spiHw->CTAR[ctar_unit].B.PCSSCK] *
\r
1173 clk_table_cssck[spiHw->CTAR[ctar_unit].B.CSSCK]*1000/(clock/1000000));
\r
1175 /* Time that PCS is high between transfers */
\r
1176 spiHw->CTAR[ctar_unit].B.PDT = 2;
\r
1177 spiHw->CTAR[ctar_unit].B.DT = 2;
\r
1179 DEBUG(DEBUG_MEDIUM,"%s: Timing: Tdt %d ns\n",MODULE_NAME,
\r
1180 clk_table_pasc[spiHw->CTAR[ctar_unit].B.PDT] *
\r
1181 clk_table_asc[spiHw->CTAR[ctar_unit].B.DT]*1000/(clock/1000000));
\r
1183 /* Data is transferred MSB first */
\r
1185 spiHw->CTAR[ctar_unit].B.LSBFE = (transferStart == SPI_TRANSFER_START_MSB ) ? 0 : 1;
\r
1188 spiHw->CTAR[ctar_unit].B.FMSZ = width - 1;
\r
1189 spiHw->CTAR[ctar_unit].B.CPHA = (extDev->SpiDataShiftEdge
\r
1190 == SPI_EDGE_LEADING) ? 0 : 1;
\r
1191 spiHw->CTAR[ctar_unit].B.CPOL = (extDev->SpiShiftClockIdleLevel == STD_LOW) ? 0 : 1;
\r
1193 // This the ACTIVE polarity. Freescale have inactive polarity
\r
1194 if (extDev->SpiCsPolarity == STD_HIGH) {
\r
1195 spiHw->MCR.R &= ~(1 << (16 + extDev->SpiCsIdentifier));
\r
1197 spiHw->MCR.R |= (1 << (16 + extDev->SpiCsIdentifier));
\r
1201 //-------------------------------------------------------------------
\r
1203 static void Spi_InitController(Spi_UnitType *uPtr ) {
\r
1205 volatile struct DSPI_tag *spiHw = uPtr->hwPtr;
\r
1207 /* Module configuration register. */
\r
1208 /* Master mode. */
\r
1209 spiHw->MCR.B.MSTR = 1;
\r
1210 /* No freeze. Run SPI when debugger is stopped. */
\r
1211 spiHw->MCR.B.FRZ = 0;
\r
1212 /* PSC5 as regular CS. */
\r
1213 spiHw->MCR.B.PCSSE = 0;
\r
1215 /* Enable FIFO's. */
\r
1216 #if (SPI_IMPLEMENTATION == SPI_DMA)
\r
1217 spiHw->MCR.B.DIS_RXF = 1;
\r
1218 spiHw->MCR.B.DIS_TXF = 1;
\r
1219 #elif (SPI_IMPLEMENTATION == SPI_FIFO)
\r
1220 spiHw->MCR.B.DIS_RXF = 0;
\r
1221 spiHw->MCR.B.DIS_TXF = 0;
\r
1225 /* Set all active low. */
\r
1226 spiHw->MCR.B.PCSIS0 = 1;
\r
1227 spiHw->MCR.B.PCSIS1 = 1;
\r
1228 spiHw->MCR.B.PCSIS2 = 1;
\r
1229 spiHw->MCR.B.PCSIS3 = 1;
\r
1230 spiHw->MCR.B.PCSIS4 = 1;
\r
1231 spiHw->MCR.B.PCSIS5 = 1;
\r
1233 #if (SPI_IMPLEMENTATION == SPI_DMA)
\r
1234 /* DMA TX FIFO fill. */
\r
1235 spiHw->RSER.B.TFFF_RE = 1;
\r
1236 spiHw->RSER.B.TFFF_DIRS = 1;
\r
1238 /* DMA RX FIFO drain. */
\r
1239 spiHw->RSER.B.RFDF_RE = 1;
\r
1240 spiHw->RSER.B.RFDF_DIRS = 1;
\r
1243 // Setup CTAR's channel codes..
\r
1244 for (int i = 0; i < (CTAR_CNT-1); i++) {
\r
1245 uPtr->channelCodes[i] = CH_NOT_VALID;
\r
1248 /* Force to stopped state. */
\r
1249 spiHw->MCR.B.HALT = 1;
\r
1251 spiHw->SR.B.EOQF = 1;
\r
1253 /* Enable clocks. */
\r
1254 spiHw->MCR.B.MDIS = 0;
\r
1256 #if defined(__DMA_INT)
\r
1257 Irq_InstallVector(Spi_Isr_DMA, 16 , 1, CPU_Z1);
\r
1260 // Install EOFQ int..
\r
1261 switch (uPtr->hwUnit) {
\r
1263 ISR_INSTALL_ISR2("SPI_A",Spi_Isr_A, DSPI_A_ISR_EOQF, 15, 0);
\r
1266 ISR_INSTALL_ISR2("SPI_B",Spi_Isr_B, DSPI_B_ISR_EOQF, 15, 0);
\r
1268 #if (SPI_CONTROLLER_TOTAL_CNT > 2)
\r
1270 ISR_INSTALL_ISR2("SPI_C",Spi_Isr_C, DSPI_C_ISR_EOQF, 15, 0);
\r
1273 #if (SPI_CONTROLLER_TOTAL_CNT > 3)
\r
1275 ISR_INSTALL_ISR2("SPI_D",Spi_Isr_D, DSPI_D_ISR_EOQF, 15, 0);
\r
1278 #if (SPI_CONTROLLER_TOTAL_CNT > 4)
\r
1280 ISR_INSTALL_ISR2("SPI_E",Spi_Isr_E, DSPI_E_ISR_EOQF, 15, 0);
\r
1283 #if (SPI_CONTROLLER_TOTAL_CNT > 5)
\r
1285 ISR_INSTALL_ISR2("SPI_F",Spi_Isr_F, DSPI_F_ISR_EOQF, 15, 0);
\r
1291 //-------------------------------------------------------------------
\r
1293 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
1294 static void Spi_DmaSetup( Spi_UnitType *uPtr ) {
\r
1298 tcd = &uPtr->dmaTxTCD;
\r
1300 tcd->SADDR = (uint32) uPtr->txQueue;
\r
1301 tcd->DADDR = (uint32) &(uPtr->hwPtr->PUSHR.R);
\r
1303 Dma_StopChannel(uPtr->dmaTxChannel);
\r
1304 Dma_CheckConfig();
\r
1306 // CITER and BITER set when we send
\r
1307 tcd = &uPtr->dmaRxTCD;
\r
1309 tcd->SADDR = (uint32) &(uPtr->hwPtr->POPR.R);
\r
1310 tcd->DADDR = (uint32) uPtr->rxQueue;
\r
1312 Dma_StopChannel(uPtr->dmaRxChannel);
\r
1313 Dma_CheckConfig();
\r
1318 //-------------------------------------------------------------------
\r
1320 void Spi_Init(const Spi_ConfigType *ConfigPtr) {
\r
1321 const Spi_JobConfigType *jobConfig2;
\r
1322 Spi_UnitType *uPtr;
\r
1325 #if (SPI_IMPLEMENTATION == SPI_DMA )
\r
1330 memset(&Spi_Global,0,sizeof(Spi_Global));
\r
1331 Spi_Global.configPtr = ConfigPtr;
\r
1332 Spi_Global.extBufPtr = Spi_Eb;
\r
1334 Spi_Global.asyncMode = SPI_INTERRUPT_MODE;
\r
1336 // Set all sequence results to OK
\r
1337 for (Spi_SequenceType i = (Spi_SequenceType) 0; i < SPI_MAX_SEQUENCE; i++) {
\r
1338 Spi_SetSequenceResult(i, SPI_SEQ_OK);
\r
1340 // Figure out what HW controllers that are used
\r
1341 for (int j = 0; j < Spi_GetJobCnt(); j++) {
\r
1342 jobConfig2 = &Spi_Global.configPtr->SpiJobConfig[j];
\r
1343 Spi_Global.spiHwConfigured |= (1 << jobConfig2->SpiHwUnit);
\r
1346 confMask = Spi_Global.spiHwConfigured;
\r
1348 for (int i=0; confMask; confMask &= ~(1 << ctrlNr),i++) {
\r
1349 ctrlNr = ilog2(confMask);
\r
1350 Spi_CtrlToUnit[ctrlNr] = i;
\r
1352 DEBUG(DEBUG_LOW,"%s:Configured HW controller %d\n",MODULE_NAME,ctrlNr);
\r
1353 uPtr = GET_SPI_UNIT_PTR(ctrlNr);
\r
1354 uPtr->hwPtr = GET_SPI_HW_PTR(ctrlNr);
\r
1355 uPtr->hwUnit = ctrlNr;
\r
1356 Spi_InitController(uPtr);
\r
1357 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);
\r
1358 #if (SPI_IMPLEMENTATION == SPI_DMA )
\r
1361 unitNr = Spi_CtrlToUnit[ctrlNr];
\r
1363 /* Make sure that this channel shall be used. */
\r
1364 //assert (ConfigPtr->SpiHwConfig[ctrlNr].Activated);
\r
1365 assert(Spi_DmaConfig[unitNr].TxDmaChannel != (-1));
\r
1366 assert(Spi_DmaConfig[unitNr].RxDmaChannel != (-1));
\r
1368 uPtr->dmaTxChannel = Spi_DmaConfig[unitNr].TxDmaChannel;
\r
1369 uPtr->dmaRxChannel = Spi_DmaConfig[unitNr].RxDmaChannel;
\r
1371 Spi_DmaSetup(uPtr);
\r
1376 /* Setup the relations for Job, for easy access */
\r
1377 for(int j=0; j<SPI_MAX_JOB; j++ ) {
\r
1378 jobConfig2 = &Spi_Global.configPtr->SpiJobConfig[j];
\r
1379 Spi_JobUnit[j].jobCfgPtr = jobConfig2;
\r
1380 Spi_JobUnit[j].extDeviceCfgPtr = &Spi_Global.configPtr->SpiExternalDevice[jobConfig2->DeviceAssignment];
\r
1381 Spi_JobUnit[j].unitPtr = GET_SPI_UNIT_PTR(jobConfig2->SpiHwUnit);
\r
1382 Spi_JobUnit[j].hwPtr= GET_SPI_HW_PTR(jobConfig2->SpiHwUnit);
\r
1383 Spi_JobUnit[j].channelsPtr = &jobConfig2->ChannelAssignment[0];
\r
1386 /* Setup CTARS, configuration */
\r
1388 Spi_UnitType *spiUnit;
\r
1393 uint32 channelCode;
\r
1396 const Spi_JobConfigType *jobConfig;
\r
1397 const Spi_ChannelConfigType *chConfig;
\r
1399 for (j = 0; j < Spi_GetJobCnt(); j++) {
\r
1400 jobConfig = &Spi_Global.configPtr->SpiJobConfig[j];
\r
1401 spiUnit = GET_SPI_UNIT_PTR( jobConfig->SpiHwUnit );
\r
1403 // Also find the controllers used while we are at it
\r
1404 Spi_Global.spiHwConfigured |= (1 << jobConfig->SpiHwUnit);
\r
1406 // ..and set the job status
\r
1407 Spi_SetJobResult((Spi_JobType) j, SPI_JOB_OK);
\r
1410 // Go through all the jobs and it's channels to setup CTAS
\r
1411 // A job have the same physical controller ( SpiHwUnit )
\r
1412 while ((channelIndex = jobConfig->ChannelAssignment[l++])
\r
1413 != CH_NOT_VALID) {
\r
1414 chConfig = &Spi_Global.configPtr->SpiChannelConfig[channelIndex];
\r
1416 // Form a channel code from
\r
1417 // <MSB/LSB><external_device_id><channel width>
\r
1418 channelCode = ( ((uint32_t)chConfig->SpiTransferStart << 16) +
\r
1419 (jobConfig->DeviceAssignment << 8) +
\r
1420 chConfig->SpiDataWidth);
\r
1422 for (k = 0; k < (CTAR_CNT-1); k++) {
\r
1423 if (spiUnit->channelCodes[k] == channelCode) {
\r
1424 Spi_ChannelInfo[channelIndex].ctarId = k;
\r
1425 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
1426 // already in list, break
\r
1430 if (spiUnit->channelCodes[k] == CH_NOT_VALID) {
\r
1432 spiUnit->channelCodes[k] = channelCode;
\r
1433 // Assign the CTAR index to channel info..
\r
1434 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
1437 jobConfig->SpiHwUnit,
\r
1438 Spi_GetExternalDevicePtrFromIndex( jobConfig->DeviceAssignment),
\r
1439 (Spi_ChannelType) k,
\r
1440 chConfig->SpiTransferStart,
\r
1441 chConfig->SpiDataWidth);
\r
1443 Spi_ChannelInfo[channelIndex].ctarId = k;
\r
1447 /* No more CTARS */
\r
1448 assert(k<(CTAR_CNT-1));
\r
1453 Spi_Global.initRun = TRUE;
\r
1456 //-------------------------------------------------------------------
\r
1458 Std_ReturnType Spi_DeInit(void) {
\r
1459 volatile struct DSPI_tag *spiHw;
\r
1462 Spi_UnitType *uPtr;
\r
1465 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_DEINIT_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
1466 if (Spi_GetStatus() == SPI_BUSY)
\r
1469 // Disable the HW modules ( SPI021 )
\r
1470 confMask = Spi_Global.spiHwConfigured;
\r
1472 // Disable the SPI hw
\r
1473 for (; confMask; confMask &= ~(1 << confNr)) {
\r
1474 confNr = ilog2(confMask);
\r
1475 spiHw = GET_SPI_HW_PTR(confNr);
\r
1476 // Disable the hardware..
\r
1477 spiHw->MCR.B.MDIS = 1;
\r
1478 uPtr = GET_SPI_UNIT_PTR(confNr);
\r
1480 Spi_InitController(uPtr);
\r
1481 Spi_SetHWUnitStatus(uPtr, SPI_IDLE);
\r
1485 Spi_Global.configPtr = NULL;
\r
1486 Spi_Global.initRun = FALSE;
\r
1491 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
1495 * @param jobConfig
\r
1498 static void Spi_DoWrite_DMA( Spi_UnitType *spiUnit,Spi_JobType jobIndex,
\r
1499 const Spi_JobConfigType *jobConfig )
\r
1504 const Spi_ChannelConfigType *chConfig;
\r
1505 Spi_EbType *extChBuff;
\r
1506 Spi_CommandType cmd;
\r
1510 // Find the channels for this job
\r
1511 while ((channelIndex = jobConfig->ChannelAssignment[j++]) != CH_NOT_VALID) {
\r
1512 chConfig = &Spi_Global.configPtr->SpiChannelConfig[channelIndex];
\r
1514 /* Check configuration error */
\r
1515 #if ( SPI_CHANNEL_BUFFERS_ALLOWED == 1 )
\r
1516 assert( chConfig->SpiChannelType == SPI_EB );
\r
1519 // Send the channels that are setup with external buffers
\r
1520 // Get the external buffer for this channel
\r
1521 extChBuff = &Spi_Global.extBufPtr[channelIndex];
\r
1523 if (extChBuff->active == 0) {
\r
1524 LDEBUG_PRINTF("Err:External buffer %d@job %d not setup\n",channelIndex,jobIndex);
\r
1529 // Start to fill the SPI queue for the DMA:
\r
1530 for (k = 0; k < extChBuff->length; k++) {
\r
1532 Spi_Global.configPtr->SpiExternalDevice[jobConfig->DeviceAssignment].SpiCsIdentifier;
\r
1534 cmd.B.CONT = 1; // Channels should keep CS active
\r
1535 // ( A job must assert CS continuously)
\r
1536 cmd.R |= (1 << (16 + csId)); // Set PCS
\r
1538 cmd.B.CTAS = Spi_ChannelInfo[channelIndex].ctarId;
\r
1539 if (extChBuff->src != NULL) {
\r
1540 if (chConfig->SpiDataWidth > 8) {
\r
1541 cmd.B.TXDATA = (extChBuff->src[k] << 8) + (extChBuff->src[k + 1] & 0xff);
\r
1544 cmd.B.TXDATA = extChBuff->src[k];
\r
1547 cmd.B.TXDATA = chConfig->SpiDefaultData;
\r
1550 // Just keep on filling the tx queue
\r
1551 spiUnit->txQueue[spiUnit->txCurrIndex++].R = cmd.R;
\r
1553 } /*while( channelIndex == */
\r
1556 cmd.B.CONT = 0; // CS high
\r
1557 cmd.B.EOQ = 1; // last in queue
\r
1558 spiUnit->txQueue[--spiUnit->txCurrIndex].R = cmd.R;
\r
1560 // Set the length of the data to send
\r
1561 spiUnit->dmaTxTCD.CITER = spiUnit->txCurrIndex + 1;
\r
1562 spiUnit->dmaTxTCD.BITER = spiUnit->txCurrIndex + 1;
\r
1564 Spi_Global.totalNbrOfStartedJobs++;
\r
1566 RAMLOG_STR("Job: "); RAMLOG_DEC(jobIndex); RAMLOG_STR(" Cnt: "); RAMLOG_DEC(spiUnit->txCurrIndex+1); RAMLOG_STR("\n");
\r
1568 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
1571 Spi_UnitType *spiUnit = GET_SPI_UNIT_PTR(jobConfig->SpiHwUnit);
\r
1572 volatile struct DSPI_tag *spiHw = GET_SPI_HW_PTR(jobConfig->SpiHwUnit);
\r
1574 Dma_ConfigureChannel((Dma_TcdType *) &spiUnit->dmaTxTCD,
\r
1575 spiUnit->dmaTxChannel);
\r
1576 Dma_ConfigureChannel((Dma_TcdType *) &spiUnit->dmaRxTCD,
\r
1577 spiUnit->dmaRxChannel);
\r
1578 /* Flush TX/Rx FIFO. Ref. man. 23.5.1 step 8 */
\r
1579 spiHw->MCR.B.CLR_RXF = 1;
\r
1580 spiHw->MCR.B.CLR_TXF = 1;
\r
1582 Dma_StartChannel(spiUnit->dmaRxChannel);
\r
1583 Dma_StartChannel(spiUnit->dmaTxChannel);
\r
1585 // Step 9. Clear TCNT
\r
1586 spiHw->TCR.B.SPI_TCNT = 0;
\r
1588 if ( (Spi_Global.asyncMode == SPI_INTERRUPT_MODE) &&
\r
1589 (spiUnit->callType == SPI_ASYNC_CALL)) {
\r
1590 ENABLE_EOQ_INTERRUPT(spiHw);
\r
1592 DISABLE_EOQ_INTERRUPT(spiHw);
\r
1595 /* This will trig a new transfer. Ref. man. 23.5.1 step 11 */
\r
1596 spiHw->SR.B.EOQF = 1;
\r
1597 spiHw->MCR.B.HALT = 0;
\r
1599 // Since it's not obvious on how to tell when a SPI sequence
\r
1600 // is sent, keep things below to what things have been tested.
\r
1601 #if defined(STEP_VALIDATION)
\r
1602 /* Wait for transfer to complete (EOQF bit is set) */
\r
1603 while (spiHw->SR.B.EOQF==1) {
\r
1604 Spi_Global.eoqf_cnt++;
\r
1606 while (spiHw->SR.B.TXRXS) {Spi_Global.txrxs_cnt++;}
\r
1607 while( EDMA.TCD[spiUnit->dmaRxChannel].ACTIVE ) {;}
\r
1614 #if (SPI_IMPLEMENTATION==SPI_FIFO)
\r
1618 * @param jobConfig
\r
1621 static void Spi_WriteJob_FIFO( Spi_JobType jobIndex )
\r
1623 Spi_ChannelType currChannel;
\r
1624 Spi_CommandType cmd;
\r
1625 Spi_CommandType dCmd;
\r
1626 Spi_NumberOfDataType bufLen;
\r
1627 const Spi_ChannelConfigType * chConfig;
\r
1628 Spi_JobUnitType * jobUnitPtr;
\r
1629 const Spi_DataType * buf;
\r
1630 Spi_NumberOfDataType copyCnt;
\r
1631 Spi_NumberOfDataType fifoLeft;
\r
1632 // boolean done = 0;
\r
1633 // boolean lastJob = 0;
\r
1635 jobUnitPtr = &Spi_JobUnit[jobIndex];
\r
1638 fifoLeft = FIFO_DEPTH;
\r
1640 RAMLOG_STR("Spi_WriteJob_FIFO\n");
\r
1642 #if defined(STEP_VALIDATION)
\r
1643 if( jobUnitPtr->hwPtr->SR.B.TXCTR != 0 ) {
\r
1649 dCmd.R = 0xfffffffful;
\r
1651 /* Iterate over the channels for this job */
\r
1652 currChannel = jobUnitPtr->channelsPtr[jobUnitPtr->currTxChIndex];
\r
1653 while ( fifoLeft != 0) {
\r
1655 chConfig = &Spi_Global.configPtr->SpiChannelConfig[currChannel];
\r
1656 buf = spiGetTxBuf( currChannel, &bufLen);
\r
1658 /* Minimum of how much data to copy and the limit of the FIFO */
\r
1659 copyCnt = MIN( (bufLen - jobUnitPtr->txChCnt) >> ((chConfig->SpiDataWidth-1)/8), fifoLeft );
\r
1661 /* Channels should keep CS active ( A job must assert CS continuously) */
\r
1663 /* Set the Chip Select (PCS) */
\r
1664 cmd.R |= (1 << (16 + jobUnitPtr->extDeviceCfgPtr->SpiCsIdentifier));
\r
1666 #if defined(STEP_VALIDATION)
\r
1667 if( cmd.B.EOQ == 1) {
\r
1672 /* Push as much as we can (FIFO or Channel limits) */
\r
1673 for(i=0; i < copyCnt ; i++ ) {
\r
1674 cmd.B.CTAS = Spi_ChannelInfo[currChannel].ctarId;
\r
1675 if (buf != NULL) {
\r
1676 if (chConfig->SpiDataWidth > 8 ) {
\r
1677 cmd.B.TXDATA = (buf[jobUnitPtr->txChCnt] << 8) +
\r
1678 (buf[jobUnitPtr->txChCnt + 1] & 0xff);
\r
1680 cmd.B.TXDATA = buf[jobUnitPtr->txChCnt];
\r
1683 cmd.B.TXDATA = chConfig->SpiDefaultData;
\r
1686 if (chConfig->SpiDataWidth > 8 ) {
\r
1687 jobUnitPtr->txChCnt+=2;
\r
1689 jobUnitPtr->txChCnt++;
\r
1693 if( dCmd.R != 0xfffffffful) {
\r
1694 jobUnitPtr->hwPtr->PUSHR.R = dCmd.R; // Write delayed
\r
1697 dCmd.R = cmd.R; // Save it
\r
1701 RAMLOG_STR("CI#");RAMLOG_DEC(jobUnitPtr->currTxChIndex);RAMLOG_STR("\n");
\r
1704 /* Done with channel? */
\r
1705 if( ((bufLen - jobUnitPtr->txChCnt) == 0) ) {
\r
1706 jobUnitPtr->txChCnt = 0;
\r
1707 /* Done with job? */
\r
1708 jobUnitPtr->currTxChIndex++;
\r
1709 currChannel = jobUnitPtr->channelsPtr[jobUnitPtr->currTxChIndex];
\r
1710 if( currChannel == CH_NOT_VALID ) {
\r
1711 jobUnitPtr->currTxChIndex = 0;
\r
1720 jobUnitPtr->hwPtr->PUSHR.R = cmd.R;
\r
1722 jobUnitPtr->fifoSent = FIFO_DEPTH - fifoLeft;
\r
1724 #if defined(STEP_VALIDATION)
\r
1725 if( jobUnitPtr->fifoSent != jobUnitPtr->hwPtr->SR.B.TXCTR ) {
\r
1730 jobUnitPtr->hwPtr->TCR.B.SPI_TCNT = 0;
\r
1732 if ( (Spi_Global.asyncMode == SPI_INTERRUPT_MODE) &&
\r
1733 (jobUnitPtr->unitPtr->callType == SPI_ASYNC_CALL)) {
\r
1734 ENABLE_EOQ_INTERRUPT(jobUnitPtr->hwPtr);
\r
1736 DISABLE_EOQ_INTERRUPT(jobUnitPtr->hwPtr);
\r
1739 #if defined(STEP_VALIDATION)
\r
1740 /* Verify FIFO before sending */
\r
1742 SPICommandType *base = (SPICommandType *)&jobUnitPtr->hwPtr->TXFR[0];
\r
1743 SPICommandType *curr;
\r
1746 i = jobUnitPtr->hwPtr->SR.B.TXNXTPTR; /* Next entry to send */
\r
1747 lastIndex = ( i + jobUnitPtr->hwPtr->SR.B.TXCTR - 1 ) % FIFO_DEPTH;
\r
1748 while( i != lastIndex ) {
\r
1750 if( curr->B.EOQ == 1) { /* This entry must not have EOQ set */
\r
1754 i = (i + 1) % FIFO_DEPTH;
\r
1757 if( curr->B.EOQ != 1) {
\r
1758 SPI_ASSERT(0); /* Last entry must have EOQ set */
\r
1763 jobUnitPtr->hwPtr->SR.B.EOQF = 1;
\r
1764 jobUnitPtr->hwPtr->MCR.B.HALT = 0;
\r
1766 #if defined(STEP_VALIDATION)
\r
1767 /* Wait for transfer to complete (EOQF bit is set) */
\r
1768 while (jobUnitPtr->hwPtr->SR.B.EOQF==1) {
\r
1769 Spi_Global.eoqf_cnt++;
\r
1771 while (jobUnitPtr->hwPtr->SR.B.TXRXS) {Spi_Global.txrxs_cnt++;}
\r
1774 // TODO: Clear FIFO's? CLR_TXF?
\r
1777 #endif /* (SPI_IMPLEMENTATION==SPI_FIFO) */
\r
1780 //-------------------------------------------------------------------
\r
1786 * Write a job to the SPI bus
\r
1788 * @param jobIndex The job to write to the SPI bus
\r
1790 static void Spi_JobWrite(Spi_JobType jobIndex) {
\r
1791 Spi_UnitType *uPtr = Spi_JobUnit[jobIndex].unitPtr;
\r
1793 uPtr->txCurrIndex = 0;
\r
1794 uPtr->currJob = Spi_JobUnit[jobIndex].jobCfgPtr;
\r
1795 uPtr->currJobIndex = jobIndex;
\r
1796 #if (SPI_IMPLEMENTATION == SPI_FIFO)
\r
1797 Spi_JobUnit[jobIndex].txChCnt = 0;
\r
1798 Spi_JobUnit[jobIndex].rxChCnt = 0;
\r
1801 Spi_SetHWUnitStatus(uPtr, SPI_BUSY);
\r
1802 Spi_SetJobResult(jobIndex, SPI_JOB_PENDING);
\r
1804 #if (USE_DIO_CS == STD_ON)
\r
1805 if( Spi_JobUnit[jobIndex].extDeviceCfgPtr->SpiCsCallback != NULL ) {
\r
1806 Spi_JobUnit[jobIndex].extDeviceCfgPtr->SpiCsCallback(1);
\r
1810 #if (SPI_IMPLEMENTATION==SPI_DMA)
\r
1811 Spi_DoWrite_DMA( uPtr, jobIndex, Spi_JobUnit[jobIndex].jobCfgPtr );
\r
1812 #elif (SPI_IMPLEMENTATION==SPI_FIFO)
\r
1813 Spi_JobUnit[jobIndex].currTxChIndex = 0;
\r
1814 Spi_WriteJob_FIFO ( jobIndex );
\r
1819 #if defined(USE_LDEBUG_PRINTF) && ( DEBUG_LVL <= DEBUG_HIGH )
\r
1820 void Spi_PrintSeqInfo(const Spi_SequenceConfigType *seqConfigPtr) {
\r
1823 DEBUG(DEBUG_HIGH,"%s: Seq: %d:",MODULE_NAME,seqConfigPtr->SpiSequenceId);
\r
1825 while ((job = seqConfigPtr->JobAssignment[i]) != JOB_NOT_VALID) {
\r
1826 DEBUG(DEBUG_HIGH,"%d ",job);
\r
1828 } DEBUG(DEBUG_HIGH,"\n");
\r
1834 * Write a sequence to the SPI bus
\r
1836 * @param seqIndex The sequence
\r
1837 * @param sync 1 - make the call sync. 0 - make the call async
\r
1839 static void Spi_SeqWrite(Spi_SequenceType seqIndex, Spi_CallTypeType sync) {
\r
1841 const Spi_SequenceConfigType *seqConfig;
\r
1842 const Spi_JobConfigType *jobConfig;
\r
1843 Spi_UnitType *uPtr;
\r
1844 Spi_JobType jobIndex;
\r
1846 seqConfig = Spi_GetSeqPtrFromIndex(seqIndex);
\r
1847 jobIndex = seqConfig->JobAssignment[0];
\r
1848 jobConfig = Spi_GetJobPtrFromIndex(jobIndex);
\r
1850 uPtr = GET_SPI_UNIT_PTR(jobConfig->SpiHwUnit);
\r
1852 /* Fill in the required fields for job and sequence.. */
\r
1853 uPtr->currJobIndexPtr = &seqConfig->JobAssignment[0];
\r
1854 uPtr->callType = sync;
\r
1855 uPtr->currSeqPtr = seqConfig;
\r
1857 Spi_SetSequenceResult(seqIndex, SPI_SEQ_PENDING);
\r
1859 // Setup interrupt for end of queue
\r
1860 if ( (Spi_Global.asyncMode == SPI_INTERRUPT_MODE) &&
\r
1861 (uPtr->callType== SPI_ASYNC_CALL)) {
\r
1862 DEBUG(DEBUG_MEDIUM,"%s: async/interrupt mode\n",MODULE_NAME);
\r
1864 DEBUG(DEBUG_MEDIUM,"%s: sync/polled mode\n",MODULE_NAME);
\r
1867 #if defined(USE_LDEBUG_PRINTF) && ( DEBUG_LVL <= DEBUG_HIGH )
\r
1868 Spi_PrintSeqInfo( seqConfig );
\r
1871 Spi_JobWrite(jobIndex);
\r
1873 if (uPtr->callType == SPI_SYNC_CALL) {
\r
1874 while (Spi_GetSequenceResult(seqIndex) == SPI_SEQ_PENDING) {
\r
1881 //-------------------------------------------------------------------
\r
1882 static _Bool Spi_AnyPendingJobs(Spi_SequenceType Sequence) {
\r
1884 // Check that we don't share any jobs with another sequence that is SPI_SEQ_PENDING
\r
1885 for (int i = 0; i < SPI_MAX_SEQUENCE; i++) {
\r
1886 if (i == Sequence) {
\r
1890 if (Spi_GetSequenceResult(i) == SPI_SEQ_PENDING) {
\r
1891 // We have found a pending sequence... check that we don't share any jobs
\r
1892 // with that sequence, SPI086
\r
1893 if (Spi_ShareJobs(Sequence, i)) {
\r
1902 //-------------------------------------------------------------------
\r
1911 Std_ReturnType Spi_SyncTransmit(Spi_SequenceType Sequence) {
\r
1913 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_SYNCTRANSMIT_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
1914 VALIDATE_W_RV( ( SPI_MAX_SEQUENCE>Sequence ), SPI_SYNCTRANSMIT_SERVICE_ID, SPI_E_PARAM_SEQ, E_NOT_OK );
\r
1915 Std_ReturnType rv = E_OK;
\r
1917 if (Spi_GetSequenceResult(Sequence) == SPI_SEQ_PENDING) {
\r
1918 DEBUG(DEBUG_LOW,"%s: Spi_AsyncTransmit() is PENDING\n",MODULE_NAME);
\r
1919 return E_NOT_OK; // SPI157
\r
1922 assert(Spi_GetSequenceResult(Sequence) == SPI_SEQ_OK);
\r
1924 if (Spi_AnyPendingJobs(Sequence)) {
\r
1928 Spi_SeqWrite(Sequence, SPI_SYNC_CALL);
\r
1933 //-------------------------------------------------------------------
\r
1935 Std_ReturnType Spi_AsyncTransmit(Spi_SequenceType Sequence) {
\r
1936 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_ASYNCTRANSMIT_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
1937 VALIDATE_W_RV( ( SPI_MAX_SEQUENCE>Sequence ), SPI_ASYNCTRANSMIT_SERVICE_ID, SPI_E_PARAM_SEQ, E_NOT_OK );
\r
1939 if (Spi_GetSequenceResult(Sequence) == SPI_SEQ_PENDING) {
\r
1940 DEBUG(DEBUG_LOW,"%s: Spi_AsyncTransmit() is PENDING\n",MODULE_NAME);
\r
1941 return E_NOT_OK; // SPI157
\r
1944 assert(Spi_GetSequenceResult(Sequence) == SPI_SEQ_OK);
\r
1946 if (Spi_AnyPendingJobs(Sequence)) {
\r
1950 DEBUG(DEBUG_LOW,"%s: Starting seq: %d\n",MODULE_NAME,Sequence);
\r
1952 Spi_SeqWrite(Sequence, SPI_ASYNC_CALL);
\r
1957 //-------------------------------------------------------------------
\r
1960 Std_ReturnType Spi_ReadIB( Spi_ChannelType Channel,
\r
1961 Spi_DataType * const DataBufferPtr)
\r
1963 (void)DataBufferPtr;
\r
1965 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_READIB_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
1966 VALIDATE_W_RV( ( Channel<SPI_MAX_CHANNEL ), SPI_READIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
1967 VALIDATE_W_RV( ( SPI_IB<Spi_Global.configPtr->SpiChannelConfig[Channel].SpiChannelType ),
\r
1968 SPI_READIB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
1970 /* NOT SUPPORTED */
\r
1972 Std_ReturnType rv = E_NOT_OK;
\r
1976 //-------------------------------------------------------------------
\r
1978 Std_ReturnType Spi_SetupEB( Spi_ChannelType Channel,
\r
1979 const Spi_DataType* SrcDataBufferPtr,
\r
1980 Spi_DataType* DesDataBufferPtr,
\r
1981 Spi_NumberOfDataType Length)
\r
1983 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_SETUPEB_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
1984 VALIDATE_W_RV( ( Channel<SPI_MAX_CHANNEL ), SPI_SETUPEB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
1985 #if ( SPI_CHANNEL_BUFFERS_ALLOWED == 1 )
\r
1986 VALIDATE_W_RV( ( SPI_EB==Spi_Global.configPtr->SpiChannelConfig[Channel].SpiChannelType ),
\r
1987 SPI_SETUPEB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
1990 VALIDATE_W_RV( ( Length<=Spi_Global.configPtr->SpiChannelConfig[Channel].SpiEbMaxLength ),
\r
1991 SPI_SETUPEB_SERVICE_ID, SPI_E_PARAM_CHANNEL, E_NOT_OK );
\r
1993 Spi_EbType *extChBuff = &Spi_Global.extBufPtr[Channel];
\r
1994 const Spi_ChannelConfigType *chConfig =
\r
1995 &Spi_Global.configPtr->SpiChannelConfig[Channel];
\r
1997 if (chConfig->SpiChannelType == SPI_EB) {
\r
1998 extChBuff->src = SrcDataBufferPtr;
\r
1999 extChBuff->dest = DesDataBufferPtr;
\r
2000 extChBuff->length = Length;
\r
2001 extChBuff->active = 1;
\r
2003 /* NOT SUPPORTED */
\r
2012 //-------------------------------------------------------------------
\r
2014 Spi_StatusType Spi_GetStatus(void) {
\r
2015 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_GETSTATUS_SERVICE_ID, SPI_E_UNINIT, SPI_UNINIT );
\r
2017 // Check all sequences if they have any job pending
\r
2018 for (int i = 0; i < SPI_MAX_SEQUENCE; i++) {
\r
2019 if (Spi_GetSequenceResult(i) == SPI_SEQ_PENDING) {
\r
2027 //-------------------------------------------------------------------
\r
2030 Spi_JobResultType Spi_GetJobResult(Spi_JobType Job) {
\r
2031 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_GETJOBRESULT_SERVICE_ID, SPI_E_UNINIT, SPI_JOB_FAILED );
\r
2032 VALIDATE_W_RV( ( SPI_MAX_JOB<Job ), SPI_GETJOBRESULT_SERVICE_ID, SPI_E_PARAM_JOB, SPI_JOB_FAILED );
\r
2034 return Spi_JobUnit[Job].jobResult;
\r
2037 //-------------------------------------------------------------------
\r
2040 Spi_SeqResultType Spi_GetSequenceResult(Spi_SequenceType Sequence) {
\r
2041 Spi_SeqResultType rv;
\r
2043 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_GETSEQUENCERESULT_SERVICE_ID, SPI_E_UNINIT, SPI_SEQ_FAILED );
\r
2044 VALIDATE_W_RV( ( SPI_MAX_SEQUENCE>Sequence ), SPI_GETSEQUENCERESULT_SERVICE_ID, SPI_E_PARAM_SEQ, SPI_SEQ_FAILED );
\r
2046 rv = Spi_SeqUnit[Sequence].seqResult;
\r
2051 //-------------------------------------------------------------------
\r
2053 Spi_StatusType Spi_GetHWUnitStatus(Spi_HWUnitType HWUnit) {
\r
2054 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_GETHWUNITSTATUS_SERVICE_ID, SPI_E_UNINIT, SPI_UNINIT );
\r
2056 return (GET_SPI_UNIT_PTR(HWUnit))->status;
\r
2059 //-------------------------------------------------------------------
\r
2061 #if (SPI_CANCEL_API == STD_ON )
\r
2062 void Spi_Cancel( Spi_SequenceType Sequence ) {
\r
2063 VALIDATE( ( TRUE == Spi_Global.initRun ), SPI_CANCEL_SERVICE_ID, SPI_E_UNINIT );
\r
2064 VALIDATE( ( SPI_MAX_SEQUENCE<Sequence ), SPI_CANCEL_SERVICE_ID, SPI_E_PARAM_SEQ );
\r
2066 /* NOT SUPPORTED */
\r
2070 //-------------------------------------------------------------------
\r
2073 #if ( SPI_LEVEL_DELIVERED == 2) // SPI154
\r
2074 Std_ReturnType Spi_SetAsyncMode(Spi_AsyncModeType Mode) {
\r
2075 VALIDATE_W_RV( ( TRUE == Spi_Global.initRun ), SPI_SETASYNCMODE_SERVICE_ID, SPI_E_UNINIT, E_NOT_OK );
\r
2078 // Not really sure by whom this function is supposed to be called by.
\r
2079 // The users of SPI(e2,flash,etc) should probably not use this.
\r
2081 for (int i = 0; i < SPI_MAX_SEQUENCE; i++) {
\r
2082 if (Spi_GetSequenceResult(i) == SPI_SEQ_PENDING) {
\r
2087 Spi_Global.asyncMode = Mode;
\r
2093 //-------------------------------------------------------------------
\r
2095 void Spi_MainFunction_Handling(void) {
\r
2096 /* NOT SUPPORTED */
\r
2099 //-------------------------------------------------------------------
\r
2101 void Spi_MainFunction_Driving(void) {
\r
2102 volatile struct DSPI_tag *spiHw;
\r
2105 Spi_UnitType *uPtr;
\r
2107 // TODO: check that the queue is empty.. if so do the next job.
\r
2108 if (Spi_Global.asyncMode == SPI_POLLING_MODE) {
\r
2109 confMask = Spi_Global.spiHwConfigured;
\r
2111 for (; confMask; confMask &= ~(1 << ctrlNr)) {
\r
2112 ctrlNr = ilog2(confMask);
\r
2113 uPtr = GET_SPI_UNIT_PTR(ctrlNr);
\r
2114 spiHw = uPtr->hwPtr;
\r
2116 if (Spi_GetHWUnitStatus(ctrlNr) == SPI_BUSY) {
\r
2117 if (spiHw->SR.B.TXRXS) {
\r
2118 // Still not done..
\r
2120 uPtr = GET_SPI_UNIT_PTR(ctrlNr);
\r