Hello TI engineers,
I'm using EDMA3 to hold the SPI data transfer base on th C6748 starter-ware. SPI DMA event is enabled in Timer ISR function every 125us and disabled in DMA ISR after 4 16-bit words were transferred. But it does not work as I expected.
For example, when the SPI_CLK was 2MHz, I monitored the SPI bus with logic analyzer, I found that 5 16-bit words were transferred in the first turn and 4 16-bit words were transferred in other turns.
For another example, when the SPI_CLK was 6MHz, I monitored the SPI bus with logic analyzer, I found that 9 16-bit words were transferred in the first turn and 8 16-bit words were transferred in other turns.
I only want to transfer 4 16-bit words every 125us, but it doesn't work as expected. Please give me some suggestions. Thanks!
Below is my code.
1. This function is executed every 125us in Timer ISR to enable the SPI DMA event.
void SPI0Transfer(void)
{
EDMA3EnableTransfer(SOC_EDMA30CC_0_REGS, EDMA3_CHA_SPI0_TX, EDMA3_TRIG_MODE_EVENT);
EDMA3EnableTransfer(SOC_EDMA30CC_0_REGS, EDMA3_CHA_SPI0_RX, EDMA3_TRIG_MODE_EVENT);
CSHoldAssert();
SPIIntEnable(SOC_SPI_0_REGS, SPI_DMA_REQUEST_ENA_INT);
}
2.This part is SPI configuration.
#define CHAR_LENGTH (16)
static void SPI0Config(void)
{
unsigned int val = SIMO_SOMI_CLK_CS;
SPIReset(SOC_SPI_0_REGS);
SPIOutOfReset(SOC_SPI_0_REGS);
SPIModeConfigure(SOC_SPI_0_REGS, SPI_MASTER_MODE);
SPIClkConfigure(SOC_SPI_0_REGS, 228000000, 2000000, SPI_DATA_FORMAT0);
SPIDelayConfigure(SOC_SPI_0_REGS,0,0,20,20);
SPIPinControl(SOC_SPI_0_REGS, 0, 0, &val);
SPIDefaultCSSet(SOC_SPI_0_REGS, (CS_ADC0 | CS_ADC1));
/* Configures the polarity and phase of SPI clock */
SPIConfigClkFormat(SOC_SPI_0_REGS, (SPI_CLK_POL_HIGH | SPI_CLK_INPHASE), SPI_DATA_FORMAT0);
/* Configures SPI to transmit MSB bit First during data transfer */
SPIShiftMsbFirst(SOC_SPI_0_REGS, SPI_DATA_FORMAT0);
/* Sets the Charcter length */
SPICharLengthSet(SOC_SPI_0_REGS, CHAR_LENGTH, SPI_DATA_FORMAT0);
/* Enable SPI communication */
SPIEnable(SOC_SPI_0_REGS);
}
3. This function is executed in callback function in DMA ISR to disable SPI DMA event.
void Spi0Pause(void)
{
SPIIntDisable(SOC_SPI_0_REGS, SPI_DMA_REQUEST_ENA_INT);
CSHoldDeassert();
}
static void callback(unsigned int tccNum, unsigned int status)
{
if(tccNum == EDMA3_CHA_SPI0_RX)
{
}
else if(tccNum == EDMA3_CHA_SPI0_TX)
{
Spi0Pause();
}
}
4. This part is DMA configuration.
void EDMA3Initial(void)
{
/* Power up EDMA3CC_0 and EDMA3TC_0 */
PSCModuleControl(SOC_PSC_0_REGS, HW_PSC_CC0, PSC_POWERDOMAIN_ALWAYS_ON, PSC_MDCTL_NEXT_ENABLE);
PSCModuleControl(SOC_PSC_0_REGS, HW_PSC_TC0, PSC_POWERDOMAIN_ALWAYS_ON, PSC_MDCTL_NEXT_ENABLE);
EDMA3Init(SOC_EDMA30CC_0_REGS, 0);
EDMA3IntSetup();
EDMA3Configure();
}
static void EDMA3Configure(void)
{
EDMA3RequestChannel(SOC_EDMA30CC_0_REGS, EDMA3_CHANNEL_TYPE_DMA, EDMA3_CHA_SPI0_TX, EDMA3_CHA_SPI0_TX, 0);
EDMA3RequestChannel(SOC_EDMA30CC_0_REGS, EDMA3_CHANNEL_TYPE_DMA, EDMA3_CHA_SPI0_RX, EDMA3_CHA_SPI0_RX, 0);
DMAParamInit();
cb_Fxn[EDMA3_CHA_SPI0_TX] = &callback;
cb_Fxn[EDMA3_CHA_SPI0_RX] = &callback;
}
void DMAParamInit(void)
{
EDMA3CCPaRAMEntry paramSet;
/* Initialize the paRAM set for receive */
memcpy(¶mSet, &spi0rxDefaultPar, SIZE_PARAMSET - 2);
EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, EDMA3_CHA_SPI0_RX, ¶mSet);//PaRAM 14
EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, 41, ¶mSet);//PaRAM 41
paramSet.destAddr = (unsigned int)spi0RxBuf1;
paramSet.linkAddr = (unsigned short)(41u * 32u);
EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, 40, ¶mSet);//PaRAM 40
/* Initialize the paRAM set for transmit */
memcpy(¶mSet, &spi0txDefaultPar, SIZE_PARAMSET - 2);
EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, EDMA3_CHA_SPI0_TX, ¶mSet);//PaRAM 15
paramSet.linkAddr = 42*32u;
EDMA3SetPaRAM(SOC_EDMA30CC_0_REGS, 42, ¶mSet);//PaRAM 42
}
/*
** Sets up the interrupts for EDMA in AINTC
*/
static void EDMA3IntSetup(void)
{
IntRegister(C674X_MASK_INT5, EDMA3CCComplIsr);
IntEventMap(C674X_MASK_INT5, SYS_INT_EDMA3_0_CC0_INT1);
IntEnable(C674X_MASK_INT5);
}
/*
** EDMA transfer completion ISR
*/
static void EDMA3CCComplIsr(void)
{
volatile unsigned int pendingIrqs;
volatile unsigned int isIPR = 0;
volatile unsigned int indexl;
volatile unsigned int Cnt = 0;
indexl = 1;
IntEventClear(SYS_INT_EDMA3_0_CC0_INT1);
isIPR = EDMA3GetIntrStatus(SOC_EDMA30CC_0_REGS);
if(isIPR)
{
while ((Cnt < EDMA3CC_COMPL_HANDLER_RETRY_COUNT)&& (indexl != 0))
{
indexl = 0;
pendingIrqs = EDMA3GetIntrStatus(SOC_EDMA30CC_0_REGS);
while (pendingIrqs)
{
if((pendingIrqs & 1) == TRUE)
{
/**
* If the user has not given any callback function
* while requesting the TCC, its TCC specific bit
* in the IPR register will NOT be cleared.
*/
/* Here write to ICR to clear the corresponding IPR bits. */
EDMA3ClrIntr(SOC_EDMA30CC_0_REGS, indexl);
(*cb_Fxn[indexl])(indexl, EDMA3_XFER_COMPLETE);
}
++indexl;
pendingIrqs >>= 1;
}
Cnt++;
}
}
}
5. This part is the ParamSet for SPI transfer and receive.
#define SPI0TX_DMA_INT_ENABLE (EDMA3CC_OPT_TCC_SET(EDMA3_CHA_SPI0_TX) | (1 << EDMA3CC_OPT_TCINTEN_SHIFT))
#define SPI0RX_DMA_INT_ENABLE (EDMA3CC_OPT_TCC_SET(EDMA3_CHA_SPI0_RX) | (1 << EDMA3CC_OPT_TCINTEN_SHIFT))
/*
** Default paRAM for Receive section.
*/
static struct EDMA3CCPaRAMEntry const spi0rxDefaultPar =
{
(unsigned int)(SPI0RX_DMA_INT_ENABLE), /* Opt field */
(unsigned int)(SOC_SPI_0_REGS + SPI_SPIBUF), /* source address */
(unsigned short)(2), /* aCnt */
(unsigned short)(4), /* bCnt */
(unsigned int)spi0RxBuf0, /* dest address */
(short) (0), /* source bIdx */
(short)(2), /* dest bIdx */
(unsigned short)(40u * 32u), /* link address */
(unsigned short)(0), /* bCnt reload value */
(short)(0), /* source cIdx */
(short)(0), /* dest cIdx */
(unsigned short)1 /* cCnt */
};
/*
* Default paRAM for Transmit section.
*/
static struct EDMA3CCPaRAMEntry const spi0txDefaultPar =
{
(unsigned int)(SPI0TX_DMA_INT_ENABLE), /* Opt field */
(unsigned int)spi0TxBuf0, /* source address */
(unsigned short)(2), /* aCnt */
(unsigned short)(4), /* bCnt */
(unsigned int)(SOC_SPI_0_REGS + SPI_SPIDAT1), /* dest address */
(short) (2), /* source bIdx */
(short)(0), /* dest bIdx */
(unsigned short)(42u * 32u), /* link address */
(unsigned short)(0), /* bCnt reload value */
(short)(0), /* source cIdx */
(short)(0), /* dest cIdx */
(unsigned short)1 /* cCnt */
};

