Are there any examples using the CSL to setup and use the EDMA3 to setup a peripheral (like SPI, TWI, or UART) on a keystone multicore device? I currently have tried setting it up for the 6670, but am not quite sure what is wrong.
CSL_Edma3Handle hModule;CSL_Edma3ParamHandle paramHandle0;CSL_Edma3ParamHandle paramHandle1;CSL_Edma3ChannelAttr chParam;CSL_Edma3ChannelObj ChObj0,ChObj1;CSL_Edma3ChannelHandle hChannel0,hChannel1;CSL_Edma3HwDmaChannelSetup chSetup;CSL_Edma3ParamSetup paramSetup;CSL_Edma3Obj moduleObj;CSL_Edma3CmdIntr regionIntr;CSL_Edma3ChannelErr chErrClear;CSL_Status EdmaStat;#define TEST_ACNT 4#define TEST_BCNT 16#define TEST_CCNT 1bool ti_spi_edma_transfer(void *src, void *dest, uint32 transLen) { int i; // Module Initialization CSL_edma3Init(NULL); // Module Open hModule = CSL_edma3Open(&moduleObj,2,NULL,&EdmaStat); // Channel Open chParam.regionNum = CSL_EDMA3_REGION_GLOBAL; chSetup.que = CSL_EDMA3_QUE_0; chParam.chaNum = CSL_TPCC2_SPIXEVT; hChannel0 = CSL_edma3ChannelOpen(&ChObj0, 2, &chParam, &EdmaStat); // Channel Setup chSetup.paramNum = CSL_TPCC2_SPIXEVT; CSL_edma3HwChannelSetupQue(hChannel0,chSetup.que); CSL_edma3HwChannelSetupParam(hChannel0,chSetup.paramNum); chParam.regionNum = CSL_EDMA3_REGION_GLOBAL; chSetup.que = CSL_EDMA3_QUE_0; chParam.chaNum = CSL_TPCC2_SPIREVT; hChannel1 = CSL_edma3ChannelOpen(&ChObj1, 2, &chParam, &EdmaStat); // Channel Setup chSetup.paramNum = CSL_TPCC2_SPIREVT; CSL_edma3HwChannelSetupQue(hChannel1,chSetup.que); CSL_edma3HwChannelSetupParam(hChannel1,chSetup.paramNum); // Parameter Handle Open // Open all the handles and keep them ready paramHandle0 = CSL_edma3GetParamHandle(hChannel0,CSL_TPCC2_SPIXEVT,NULL); paramHandle1 = CSL_edma3GetParamHandle(hChannel1,CSL_TPCC2_SPIREVT,NULL); paramSetup.aCntbCnt = CSL_EDMA3_CNT_MAKE(TEST_ACNT,TEST_BCNT); paramSetup.srcDstBidx = CSL_EDMA3_BIDX_MAKE(TEST_ACNT,0); paramSetup.srcDstCidx = CSL_EDMA3_CIDX_MAKE(0,0); paramSetup.cCnt = TEST_CCNT; paramSetup.option = CSL_EDMA3_OPT_MAKE(FALSE,TRUE,FALSE,TRUE, CSL_TPCC2_SPIXEVT, CSL_EDMA3_TCC_NORMAL, CSL_EDMA3_FIFOWIDTH_NONE, FALSE, CSL_EDMA3_SYNC_A, CSL_EDMA3_ADDRMODE_INCR, CSL_EDMA3_ADDRMODE_INCR); paramSetup.srcAddr = (Uint32)src; paramSetup.dstAddr = (Uint32)&(SPI_REGS->SPIDAT1); paramSetup.linkBcntrld = CSL_EDMA3_LINKBCNTRLD_MAKE(CSL_EDMA3_LINK_NULL,0); CSL_edma3ParamSetup(paramHandle0,¶mSetup); paramSetup.aCntbCnt = CSL_EDMA3_CNT_MAKE(TEST_ACNT,TEST_BCNT); paramSetup.srcDstBidx = CSL_EDMA3_BIDX_MAKE(0,TEST_ACNT ); paramSetup.srcDstCidx = CSL_EDMA3_CIDX_MAKE(0,0); paramSetup.cCnt = TEST_CCNT; paramSetup.option = CSL_EDMA3_OPT_MAKE(FALSE,TRUE,FALSE,TRUE, CSL_TPCC2_SPIREVT, CSL_EDMA3_TCC_NORMAL, CSL_EDMA3_FIFOWIDTH_NONE, FALSE, CSL_EDMA3_SYNC_A, CSL_EDMA3_ADDRMODE_INCR, CSL_EDMA3_ADDRMODE_INCR); paramSetup.srcAddr = (Uint32)&(SPI_REGS->SPIBUF); paramSetup.dstAddr = (Uint32)dest; paramSetup.linkBcntrld = CSL_EDMA3_LINKBCNTRLD_MAKE(CSL_EDMA3_LINK_NULL,0); CSL_edma3ParamSetup(paramHandle1,¶mSetup); /* clear the EDMA error registers */ chErrClear.missed = TRUE; chErrClear.secEvt = TRUE; CSL_edma3HwChannelControl (hChannel0, CSL_EDMA3_CMD_CHANNEL_DISABLE, NULL); CSL_edma3HwChannelControl (hChannel1, CSL_EDMA3_CMD_CHANNEL_DISABLE, NULL); CSL_edma3HwChannelControl (hChannel0, CSL_EDMA3_CMD_CHANNEL_CLEARERR, &chErrClear); CSL_edma3HwChannelControl (hChannel1, CSL_EDMA3_CMD_CHANNEL_CLEARERR, &chErrClear); CSL_edma3HwChannelControl (hChannel0, CSL_EDMA3_CMD_CHANNEL_CLEAR, NULL); CSL_edma3HwChannelControl (hChannel1, CSL_EDMA3_CMD_CHANNEL_CLEAR, NULL); // Trigger channel CSL_edma3HwChannelControl(hChannel0,CSL_EDMA3_CMD_CHANNEL_ENABLE,NULL); // Trigger channel CSL_edma3HwChannelControl(hChannel1,CSL_EDMA3_CMD_CHANNEL_ENABLE,NULL); /* Start I2C */ SPI_REGS->SPIDAT1 |= (1 << 28); // Hold CS Line SPI_REGS->SPIGCR1 |= (1 << 24); // SPI enable bit (should only be set to 1 when ready to enable) // Wait for interrupt regionIntr.region = CSL_EDMA3_REGION_GLOBAL; regionIntr.intr = 0; regionIntr.intrh = 0; do{ CSL_edma3GetHwStatus(hModule,CSL_EDMA3_QUERY_INTRPEND,®ionIntr); for(i=0; i < 1000; i++) asm("nop"); }while (!(regionIntr.intr & 0xC000));// channel 30 & 31 /* Stop the transmission */ SPI_REGS->SPIGCR1 &= ~(1 << 24); // SPI enable bit (should only be set to 1 when ready to enable) SPI_REGS->SPIDAT1 &= ~(1 << 28); // Hold CS Line /* close instance of EDMA */ CSL_edma3ChannelClose(hChannel0); CSL_edma3ChannelClose(hChannel1); CSL_edma3Close(hModule);}
Hello, Aditya ,
Great to know you start looking at this issue. For your knowledge, we have SPI works in loopback mode as well as communicating with a SPI slave with CPU interrupt.
SPI+EDMA doesn't work. Thanks.
Xinwei
Aditya,
I have not done an internal loop back, however we have a custom board and we do have SPI working back and forth w/ a different processor with a protocol that is interrupt driven. However in our final project, we would like to use the EDMA to drive the SPI to take the load off of the Cores on long transfers.
Erick
Xinwei, Erick,
Thanks. I am trying to get a working project ready for you. At the moment am facing some issues with EDMA missed events on transmit side. I will post a working project once I have it ready. Please be assured that we want to get you a working project as soon as possible.
Regards,
Aditya
Hello, Aditya
How is it going for this project? We really need a working version of SPI+DMA right now. Please update us the progress and the version you have right now.
I attached one SPI+EDMA example test case below, which is based on C6670 CSL.
The SPI is configured in internal loopback mode and Channel 2 and Channel 3 of EDMA3_CC1 are being used for SPIXEVT and SPIREVT (Table 7-36 in C6670 data manual).
The source buffer is located in CorePac0 L2 SRAM and being sent to SPI by EDMA. After loopback, the data is received by SPI and being sent to destination buffer located in CorePac1 L2 SRAM by EDMA as well.
Please take a look and let us know if you need any more info about this. Thanks.
4670.edma_spi.zip
Sincerely,
Steven
------------------------------------------------------------------------------------------------------------
Please click the Verify Answer button on this post if it answers your question.
Thank you very much, Steven. I really appreciate it. I have your example build and run well on the C6678 evm board. I have one more question: the src and dst buffer in your example is located in the L2SRAM, can I adapt this example to have my receiving dst buffer in the DDR? I want to have a bigger buffer.
Looking forward your reply!!
Xinwei,
Sure. You can define the src/dst anywhere you prefer.
For example, currently the dst buffer is in ".gem1_data"
#pragma DATA_SECTION(dstBuf, ".gem1_data")#pragma DATA_ALIGN(dstBuf, 8)Uint16 dstBuf[BUF_SIZE];
You can change to DDR SRAM as
#pragma DATA_SECTION(dstBuf, ".ddrData")#pragma DATA_ALIGN(dstBuf, 8)Uint16 dstBuf[BUF_SIZE];
And in the "example.cmd" file, you will see ".ddrData" is pointed to the DDR3_DATA_MEM. In this way, dstBuf is located in DDR SRAM.
Alternately, you can use pointers of src/dst buffers, instead of pre-allocating them.
Then you can give the actually memory location to those buffer pointers in the source code.
But please pay attention to the memory allocation, that the buffers should be overlapped with others.
Hope it helps.
Thank you, Steve. Yes, it definitely helps. I have make the DDR+SPI happened in the loopback mode. I have another two questions:
1) I change the main in the example to a function spidmatest, and I call it in my main before everything start. It works for the first time when I called. The second time, just following the first call, it hangs at Setup_SPI() because the last while loop in this function. Could you please explain why? How to rescue it when I want the DMA happen more than once. (I have it working only once in the SPI working (non-loopback) mode also).
2) I used the Oscilloscope to measure the time for transfering 350bytes data via SPI working at 50MHZ using the DMA, it takes around 97us. Is that reasonable? I expect it to be shorter.
Thank you very much!
1. The following example attached demonstrates how to trigger the SPI-EDMA transfer for multiple times. Basically, we need to setup reload paramSet for EDMA channels for the continuous peripheral support (refer to section 3.4.3 in EDMA user guide).
And we can disable/enable the DMAREQEN bit in the SPIINT0 register to re-trigger the TX/RX DMA request.
2. The throughput calculation is embedded in the attached example as well. If SPI is running at 66MHz the throughput is about 57Mbps. Please take a look at the following document for reference:Throughput Performance Guide for C66x KeyStone Devices (Rev. A)
0410.edma_spi.zip
Thank you, Steve. I will look at the new code shortly. Before I got your new example, I had looked the EDMA registers and figured out one way for continuous firing SPI+DMA:. This is what I did:
1) disable the complete interrupt bit by seting the fourth parameter False in the paramSetup.option call;
2)write to register ' EDMA1_CH2SECR *( volatile Uint32* ) (0x02720000 + 0x1040) ' 0x4 to clear the ECR bit.
Yes, I stop the transfer by seting SPINT0 to 0.
It works well so far. Could you please let me know if this way is proper? Anything I should be cautions of?
Thanks.
If you do not need EDMA generate interrupt at the completion of transfer, you can disable that and clear the secondary event bit as you did.
Or you can still let EDMA generate interrupt and clear the interrupt pending in ICR (Interrupt Clear Register, offset 0x1070), as shown in the second example.
I think either way should be fine, as long as it works for your scenario.
Thank you, Steve. Yes, your code works well.
What I am currently doing is to receive data from SPI and put them in a large DDR buffer. But it seems 20% slower than using a buffer in L2 SRAM.
So I am thinking to use L2SRAM buffer and use an DMA completion interrupt so that the ISR can do another DMA from L2SRAM to DDR. Do you think this will be faster? I really appreciate if you can share the example code of setting up the DMA complete interrupt. Thanks,
Hey Steve,
Thanks for the example, I haven't had a chance to test it out yet, but it looks like it's what I need to get it going
Hi,
I tried the same code on c6657. I appreciate if anyone can advise on this problem.
Hari
0830.main.c
I got first problem where CSL_TPCC_1 is not defined. I see it defines CSL_TPCC_2. I tried replacing with values 1 or 2.
Compilation is fine, But I get struck @
while(!(((CSL_SpiRegsOvly) CSL_SPI_REGS)->SPIFLG & 0x00000100));profileRxStart = CSL_tscRead();
Harikrishna.
Using TPCC_2 instead of TPCC_1 requires using different edma channels as the SPI is setup for specific channels, so when CSL_EDMA3_CHA_2 is used, that is specific for TPCC_1, so you need to use CSL_TPCC2_SPIXEVT instead (lines 74, 77, 97, and 104). Same thing goes for CSL_EDMA3_CHA_3, you should replace those references with CSL_TPCC2_SPIREVT.
Lines 167/168 are also specific to edma channels 2 and 3, you'll have to use the defines for those specific channels. and lines 149 and 147 check to see if the the channel 2 and channel 3 bits are also done.
Hope that helps,