FRDM-K28F SPI

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

FRDM-K28F SPI

1,070 Views
ravitej_tanneru
Contributor I

Hi Support Team,

We are using FRDM-K28F for one of our product development. One of our main requirement is to achieve good throughput over SPI.

Could it be taken on priority as we are at a critical stage of completion.

We are using SPI0 on K28 as SPI Master at 33 MHz (I suppose this is the maximum) and using EDMA as well with SPI.

Need help with following,

1. Can we use SPI I/O and SPI_EMDA simultaneously? Some SPI transaction using DMA and some without DMA? If yes, is it possible to get any example for the same?

2. We observed that, for reading each byte, K28 takes 12 clock (SCK) cycles with 33Mhz Clock. 8 Clock cycles + 4 clock cycles gap before providing next clock of 8 cycles. Attaching SPI capture [Each_byte.PNG] How can we reduce this gap?

3. We tried to use Continuous mode, buy we were able to run only till 25MHz. Can we use 'Continuous Mode' at 33MHz?

4. Can we tune EDMA parameters to  increase the SPI throughput? If yes, can you provide related information like what all parameters can be configured. We are using DSPI_MasterTransferEDMA() api.

-> Following code was used for SPI_DMA init.

/*********************************************************************************************************************
dspi_master_config_t spi_init()
{
    uint32_t srcClock_Hz;
    dspi_master_config_t masterConfig;

    /* Master config */
    masterConfig.whichCtar = kDSPI_Ctar0;
    masterConfig.ctarConfig.baudRate = TRANSFER_BAUDRATE;
    masterConfig.ctarConfig.bitsPerFrame = 8U;
    masterConfig.ctarConfig.cpol = kDSPI_ClockPolarityActiveHigh;
    masterConfig.ctarConfig.cpha = kDSPI_ClockPhaseFirstEdge;
    masterConfig.ctarConfig.direction = kDSPI_MsbFirst;
    masterConfig.ctarConfig.pcsToSckDelayInNanoSec = 1000000000U / TRANSFER_BAUDRATE;
    masterConfig.ctarConfig.lastSckToPcsDelayInNanoSec = 1000000000U / TRANSFER_BAUDRATE;
    masterConfig.ctarConfig.betweenTransferDelayInNanoSec = 1000000000U / TRANSFER_BAUDRATE;

    masterConfig.whichPcs = EXAMPLE_DSPI_MASTER_PCS_FOR_INIT;
    masterConfig.pcsActiveHighOrLow = kDSPI_PcsActiveLow;

    masterConfig.enableContinuousSCK = false;
    masterConfig.enableRxFifoOverWrite = false;
    masterConfig.enableModifiedTimingFormat = false;
    masterConfig.samplePoint = kDSPI_SckToSin0Clock;

    srcClock_Hz = DSPI_MASTER_CLK_FREQ;
    DSPI_MasterInit(EXAMPLE_DSPI_MASTER_BASEADDR, &masterConfig, srcClock_Hz);

    return masterConfig;
}
#else
dspi_master_config_t SPI_DMA_INIT()
{
    /* DMA Mux setting and EDMA init */
    uint32_t masterRxChannel, masterTxChannel;
    edma_config_t userConfig;

    masterRxChannel = 0;
    masterTxChannel = 1;

    /* If DSPI instances support Gasket feature, only two channels are needed. */
#if (!(defined(FSL_FEATURE_DSPI_HAS_GASKET) && FSL_FEATURE_DSPI_HAS_GASKET))
    uint32_t masterIntermediaryChannel;
    masterIntermediaryChannel = 2U;
#endif
    /* DMA MUX init */
    DMAMUX_Init(EXAMPLE_DSPI_MASTER_DMA_MUX_BASEADDR);

    DMAMUX_SetSource(EXAMPLE_DSPI_MASTER_DMA_MUX_BASEADDR, masterRxChannel,
            (uint8_t)EXAMPLE_DSPI_MASTER_DMA_RX_REQUEST_SOURCE);
    DMAMUX_EnableChannel(EXAMPLE_DSPI_MASTER_DMA_MUX_BASEADDR, masterRxChannel);

#if (defined EXAMPLE_DSPI_MASTER_DMA_TX_REQUEST_SOURCE)
    DMAMUX_SetSource(EXAMPLE_DSPI_MASTER_DMA_MUX_BASEADDR, masterTxChannel,
            (uint8_t)EXAMPLE_DSPI_MASTER_DMA_TX_REQUEST_SOURCE);
    DMAMUX_EnableChannel(EXAMPLE_DSPI_MASTER_DMA_MUX_BASEADDR, masterTxChannel);
#endif

    /* EDMA init */
    /*
     * userConfig.enableRoundRobinArbitration = false;
     * userConfig.enableHaltOnError = true;
     * userConfig.enableContinuousLinkMode = false;
     * userConfig.enableDebugMode = false;
     */
    EDMA_GetDefaultConfig(&userConfig);

    EDMA_Init(EXAMPLE_DSPI_MASTER_DMA_BASEADDR, &userConfig);

    uint32_t srcClock_Hz;
    dspi_master_config_t masterConfig;

    /* Master config */
    masterConfig.whichCtar = kDSPI_Ctar0;
    masterConfig.ctarConfig.baudRate = TRANSFER_BAUDRATE;
    masterConfig.ctarConfig.bitsPerFrame = 8;
    masterConfig.ctarConfig.cpol = kDSPI_ClockPolarityActiveHigh;
    masterConfig.ctarConfig.cpha = kDSPI_ClockPhaseFirstEdge;
    masterConfig.ctarConfig.direction = kDSPI_MsbFirst;
    masterConfig.ctarConfig.pcsToSckDelayInNanoSec = 1000000000U / TRANSFER_BAUDRATE;
    masterConfig.ctarConfig.lastSckToPcsDelayInNanoSec = 1000000000U / TRANSFER_BAUDRATE;
    masterConfig.ctarConfig.betweenTransferDelayInNanoSec = 1000000000U / TRANSFER_BAUDRATE;

    masterConfig.whichPcs = EXAMPLE_DSPI_MASTER_PCS_FOR_INIT;
    masterConfig.pcsActiveHighOrLow = kDSPI_PcsActiveLow;

    masterConfig.enableContinuousSCK = false;
    masterConfig.enableRxFifoOverWrite = false;
    masterConfig.enableModifiedTimingFormat = false;
    masterConfig.samplePoint = kDSPI_SckToSin0Clock;

    srcClock_Hz = DSPI_MASTER_CLK_FREQ;
    DSPI_MasterInit(EXAMPLE_DSPI_MASTER_BASEADDR, &masterConfig, srcClock_Hz);

    /* Set up dspi master */
    memset(&(dspiEdmaMasterRxRegToRxDataHandle), 0, sizeof(dspiEdmaMasterRxRegToRxDataHandle));

#if (!(defined(FSL_FEATURE_DSPI_HAS_GASKET) && FSL_FEATURE_DSPI_HAS_GASKET))
    memset(&(dspiEdmaMasterTxDataToIntermediaryHandle), 0, sizeof(dspiEdmaMasterTxDataToIntermediaryHandle));
#endif
    memset(&(dspiEdmaMasterIntermediaryToTxRegHandle), 0, sizeof(dspiEdmaMasterIntermediaryToTxRegHandle));

    EDMA_CreateHandle(&(dspiEdmaMasterRxRegToRxDataHandle), EXAMPLE_DSPI_MASTER_DMA_BASEADDR, masterRxChannel);

#if (!(defined(FSL_FEATURE_DSPI_HAS_GASKET) && FSL_FEATURE_DSPI_HAS_GASKET))
    EDMA_CreateHandle(&(dspiEdmaMasterTxDataToIntermediaryHandle), EXAMPLE_DSPI_MASTER_DMA_BASEADDR,
            masterIntermediaryChannel);
#endif
    EDMA_CreateHandle(&(dspiEdmaMasterIntermediaryToTxRegHandle), EXAMPLE_DSPI_MASTER_DMA_BASEADDR, masterTxChannel);
#if (defined(FSL_FEATURE_DSPI_HAS_GASKET) && FSL_FEATURE_DSPI_HAS_GASKET)
    DSPI_MasterTransferCreateHandleEDMA(EXAMPLE_DSPI_MASTER_BASEADDR, &g_dspi_edma_m_handle, DSPI_MasterUserCallback,
            NULL, &dspiEdmaMasterRxRegToRxDataHandle, NULL,
            &dspiEdmaMasterIntermediaryToTxRegHandle);
#else
    DSPI_MasterTransferCreateHandleEDMA(EXAMPLE_DSPI_MASTER_BASEADDR, &g_dspi_edma_m_handle, DSPI_MasterUserCallback,
            NULL, &dspiEdmaMasterRxRegToRxDataHandle,
            &dspiEdmaMasterTxDataToIntermediaryHandle,
            &dspiEdmaMasterIntermediaryToTxRegHandle);
#endif

    return masterConfig;
}

/*********************************************************************************************************************/

ANY QUICK HELP ON THIS WOULD BE HIGHLY APPRECIATED.

Thanks

Ravitej

(E-Mail: ravitej.tanneru@redpinesignals.com)   

Labels (1)
0 Kudos
4 Replies

768 Views
scottm
Senior Contributor II

I'm using the K22F, but I think the SPI module is the same.  I use a mix of polled and DMA access.  I'm not using the SDK code, though - I was on Processor Expert before, but I've rewritten everything myself now.

I'm not sure about the current version, but previous SDK versions have had pretty heavy SPI drivers that imposed a lot of latency for small transfers.  I'm usually interfacing with SPI flash memory, and there's a lot of polling for completion and setting of write enable flags that requires some back-and-forth that can really slow down transactions.

For that stuff, I've got some very minimalist blocking functions for SPI access.  When a FreeRTOS task needs to read or write a block of data, it uses the DMA block read or write functions (after setting up the transaction in polled mode) so that other tasks can keep running while it waits.  I have one place where read/write access is needed in a critical section, and since there's no benefit to using DMA when you're just sitting and waiting anyway, it has a more complicated polling read/write that switches to 16-bit transfers to eliminate a wasted bit between words, so it gains a few percent in transfer speed over an 8-bit DMA transfer.

Screenshot 2017-10-22 12.39.33.png

This is an old capture showing what I've been able to attain.  The big gap at +5 us is the switch between byte-at-a-time access and the 16-bit polled block transfer.  Note that there's still a 1-bit dead time between words, and I haven't found a way to get rid of that.

Scott

0 Kudos

768 Views
jingpan
NXP TechSupport
NXP TechSupport

Hi Ravitej,

1. What does SPI I/O mean? In a SPI block, if DMA is enabled, all data must transfer by DMA. It can't only transfer part of them.
2. In K28 datasheet table 49, it says that the max frequency of operation is 30M. So I thinks it's better to obey the rules.
3. No. Please look at datasheet page 65. When DSPI is configured with continuous CS and SCK, there is a constraint that SPI clock should not be greater than 1/6 of bus clock. So, 150/6=25M.
4. I think it's hard to speed up any more.

Regards,

Jing

0 Kudos

768 Views
ravitej_tanneru
Contributor I

Hi Jing,

Thanks for your response.

Could you please help in clarifying folllowing,

1. SPI I/O means SPI without DMA. We want to use SPI with DMA and without DMA simultaneously. I understood that, once DMA is configured to send/receive some data, the complete transaction is done by DMA. What we would like to check is, if we can 1 packet using DMA and the 2nd packet without DMA?

2. Ok agreed. Thanks.

3. Ok agreed. Thanks.

4. Our application needs to have good throughput numbers. So would need inputs on tuning DMA parameters, if possible.

Like, if we can configure DMA beat size or major/minor loop count etc to make it more efficient.

Thanks

Ravitej

0 Kudos

768 Views
jingpan
NXP TechSupport
NXP TechSupport

Hi Ravitej,

If you want to use SPI with DMA and without DMA simultaneously, you have to turn on and turn off DMA by software.

I think DMA always has higher priority to occupy system bus. The configuration has little influence to transfer speed. And after all, the speed of DMA controller is far more fast than SPI serial port.

Regards,

Jing

0 Kudos