Hello ,
In my project I send data to DAC through SPI. Also in the project i am using USB. Max samplrate of DAC is 1MHz, so if i use interrupt to load PUSHR of SPI i got stacked with USB.
But there is a good news for me - i need only linear scan, so I can use timer that scans 16bit and DMA to load it to PUSHR. So i set up DMA_CH0 to load PIT_1 value to pushr and triggers on PIT0 each 1us. But the problem is that DMA works only 1 time even if i set up self-linking of the channel.
I can see if i start PUSHR load in the code, after the transmission ends DMA worked once to load PIT1_CVAL. And stops untill i call PUSHR write once again.
My basic pices of code is below:
void ini_dma()
{
const edma_config_t dma_conf={
// .enableContinuousLinkMode=1,
.enableDebugMode=1,
};
//DMAMUX SET_Up
CLOCK_EnableClock(kCLOCK_Dmamux0);
DMAMUX_SetSource(DMAMUX0,dma_ch_0,kDmaRequestMux0SPI1);
DMAMUX_EnableChannel(DMAMUX0,dma_ch_0); //dmamux =1 (PIT_CH0)
DMAMUX_EnablePeriodTrigger(DMAMUX0,dma_ch_0);
CLOCK_EnableClock(kCLOCK_Dma0);
EDMA_Init(DMA0, &dma_conf);
uint16_t abc=32000;
DMA0->CR&=~DMA_CR_EMLM(1);
DMA0->TCD[0].SADDR = (int)&(PIT->CHANNEL[1].CVAL);
// DMA0->TCD[0].SADDR = (int)&(abc);
DMA0->TCD[0].SOFF= 0; /* no address shift after each transfer */
DMA0->TCD[0].SLAST = 0;
DMA0->TCD[0].DADDR = (int)&(SPI1->PUSHR);
DMA0->TCD[0].DOFF= 0;
DMA0->TCD[0].DLAST_SGA= 0;
DMA0->TCD[0].NBYTES_MLNO=2; //2bytes for 16bit PUSHR load
DMA0->TCD[0].CITER_ELINKYES=DMA_CITER_ELINKYES_ELINK(1)|DMA_CITER_ELINKYES_LINKCH(0)|DMA_CITER_ELINKYES_CITER(1);
// DMA0->TCD[0].CITER_ELINKNO=1; //single request
// DMA0->TCD[0].BITER_ELINKNO=1; //single request
DMA0->TCD[0].BITER_ELINKYES=DMA_BITER_ELINKYES_ELINK(1)|DMA_BITER_ELINKYES_LINKCH(0)|DMA_BITER_ELINKYES_BITER(1);
DMA0->TCD[0].CSR|=DMA_CSR_ESG(0);
DMA0->TCD[0].ATTR = DMA_ATTR_SSIZE(1)|DMA_ATTR_DSIZE(1)|DMA_ATTR_DMOD(0)|DMA_ATTR_SMOD(0);
DMA0->ERQ=DMA_ERQ_ERQ0(1); //enable hardware request
/* disable auto close request */
DMA0->TCD[0].CSR &=~DMA_CSR_DREQ(1);
DMA0->EEI=DMA_EEI_EEI0(1);//enable interrupt
DMA0->TCD[0].CSR|=DMA_CSR_START(1)|DMA_CSR_INTMAJOR(1);
}
void ini_pit(){
pit_config_t pit_conf;
uint32_t freq = CLOCK_GetBusClkFreq();
pit_conf.enableRunInDebug=0;
CLOCK_EnableClock(kCLOCK_Pit0);
PIT_SetTimerPeriod(PIT, kPIT_Chnl_0,freq/1000000 ); //1M freq
PIT_Init(PIT, &pit_conf);
PIT_StartTimer(PIT, kPIT_Chnl_0);
PIT->CHANNEL[1].LDVAL=PIT_LDVAL_TSV(0xffff);
PIT->CHANNEL[1].TCTRL|=PIT_TCTRL_CHN(1);
PIT->CHANNEL[1].TCTRL|=PIT_TCTRL_TEN(1)|PIT_TCTRL_TIE(1);
}
I've figured out what causes the problem - TFFF flag after DMA transfers not set up again or wrong time.
So if I set it through debug session - immediately I see next value in the PUSHR(and DAC respectively). But after single transaction TFFF flag goes zero.
My SPI inicialization code is the following:
void spi1_ini(){
dspi_master_config_t config;
dspi_master_config_t* spi1_config = &config;
dspi_master_ctar_config_t ctar;
ctar.baudRate=24000000;
ctar.bitsPerFrame=16;
ctar.cpha=kDSPI_ClockPhaseFirstEdge;
ctar.cpol=kDSPI_ClockPolarityActiveHigh;
ctar.direction=kDSPI_MsbFirst;
ctar.lastSckToPcsDelayInNanoSec=30;
ctar.pcsToSckDelayInNanoSec=10;
spi1_config->whichCtar=kDSPI_Ctar0;
spi1_config->ctarConfig=ctar;
spi1_config->whichPcs=kDSPI_Pcs0;
spi1_config->enableContinuousSCK=0;
spi1_config->pcsActiveHighOrLow=kDSPI_PcsActiveLow;
// GPIO_PinWrite(GPIOE, DAC_EN, 0); //disables DAC
GPIO_PinWrite(GPIOE, DAC_EN, 1); //enables DAC
CLOCK_EnableClock(kCLOCK_Spi1);
SIM->SCGC6|= SIM_SCGC6_SPI1(1);
DSPI_MasterInit(SPI1_BASE, spi1_config, 48000000);
SPI1->MCR|= SPI_MCR_FRZ(1);
SPI1->RSER|=SPI_RSER_TFFF_DIRS(1)|SPI_RSER_TFFF_RE(1);//dma request enable
DSPI_Enable(SPI1, true);
DSPI_MasterWriteData(SPI1, &transfer_cmd, DSPI_DUMMY_DATA);
}
Hello alexeyusoltsev,
Looking at your code I think this is due to you're only setting for 1 cycle so after each transmission you need to start again the transmission. I will suggest checking the example dspi_half_duplex_edma_master and the edma_scatter_gather from the SDK (check the link here).
Let me know if this helps you.
Best Regards,
Alexis Andalon
Hi Alexis Andalon,
thanks a lot for your response. I have no processor time to make a 1Mhz interrupt in scatter-gather mode. So I involved channel linking in a way of self-linking.
But the problem for now is(OMG) that SPI _SR TFFF(FIFO is ready to accept data) flag only sets while TCF flag is cleared, so to start transaction i have to write to TCF of SPI 1 after each transaction to clear TCF manually. If SPI _SR TFFF is not setten up there is no DMA hardware request. I have tried to solve that problem by another channel linking(2DMA channel to send data to 1 SPI) but SPI_SR has fields that protected from writing so I got a bus error. If you know how to solve that i will appreciate it a lot.
From my point of view SPI in kinetis is not made to work with DMA gluelessly.
Regards,
Alexey