Continious DMA with SPI1 TX k22

cancel
Showing results for 
Search instead for 
Did you mean: 

Continious DMA with SPI1 TX k22

289 Views
alexeyusoltsev
Contributor IV

  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);
}

Tags (4)
3 Replies

195 Views
alexeyusoltsev
Contributor IV

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);
}

0 Kudos

195 Views
Alexis_A
NXP TechSupport
NXP TechSupport

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

195 Views
alexeyusoltsev
Contributor IV

  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

0 Kudos