SPI/DMA Kinetis K64

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

SPI/DMA Kinetis K64

1,817 Views
mikaelelharrar
Contributor III

Hi community,

I'm working with an external ADC through SPI with K64.

The ADC samples the analog voltage at 42ksps ( I get an external GPIO interrupt to pull the data each about 25 us).

Unfortunatly the DMA seems to be very slow, and at this frequence, it doesnt have enough time to pull the data (it tooks about 40 us to pull 12 bytes).

So each 2 interrupt, I get "DMA busy".

[You can see my old post here SPI/DMA issue with kinetis K64 (MK64F12) ]

I'm trying to save some cycles by changing the DMA mechanism.

I would like to:

1) Understand why the DMA is too slow ?

2) An idea to make it more faster ?

3) How can I trigger the DMA directly with the GPIO interrupt ? Please if you have a code example (I didnt succedded to do that).

Here below the DMA configuration code.If you have an idea to improve it, please let me know:

static void _init_ads_dma(){

    uint32_t masterRxChannel, masterIntermediaryChannel, masterTxChannel;
    edma_config_t userConfig;

    masterRxChannel = 0U;
    masterIntermediaryChannel = 1U;
    masterTxChannel = 2U;

    /* DMA MUX init */
    DMAMUX_Init(DSPI_MASTER_DMA_MUX_BASEADDR);
    DMAMUX_SetSource(DSPI_MASTER_DMA_MUX_BASEADDR, masterRxChannel, kDmaRequestMux0SPI0Rx);
    DMAMUX_EnableChannel(DSPI_MASTER_DMA_MUX_BASEADDR, masterRxChannel);
    DMAMUX_SetSource(DSPI_MASTER_DMA_MUX_BASEADDR, masterTxChannel, kDmaRequestMux0SPI0Tx);
    DMAMUX_EnableChannel(DSPI_MASTER_DMA_MUX_BASEADDR, masterTxChannel);

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

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

    EDMA_CreateHandle(&(dspiEdmaMasterRxRegToRxDataHandle), DSPI_MASTER_DMA_BASEADDR, masterRxChannel);
    EDMA_CreateHandle(&(dspiEdmaMasterTxDataToIntermediaryHandle), DSPI_MASTER_DMA_BASEADDR, masterIntermediaryChannel);
    EDMA_CreateHandle(&(dspiEdmaMasterIntermediaryToTxRegHandle), DSPI_MASTER_DMA_BASEADDR, masterTxChannel);

    DSPI_MasterTransferCreateHandleEDMA(ADS_SPI_BASEADDR, &g_dspi_edma_m_handle, EDMA_Callback,
                                        NULL, &dspiEdmaMasterRxRegToRxDataHandle,
                                        &dspiEdmaMasterTxDataToIntermediaryHandle,
                                        &dspiEdmaMasterIntermediaryToTxRegHandle);
}


void _extract_data_with_dma(void){

    dspi_transfer_t masterXfer;
    status_t status;

    /* Start master transfer */
    masterXfer.txData = (uint8_t *)w_data_byte;
    masterXfer.rxData = (uint8_t *)r_data_byte;
    masterXfer.dataSize = 12;
    masterXfer.configFlags = kDSPI_MasterCtar0 | ADS_DSPI_PCS_FOR_TRANSFER | kDSPI_MasterPcsContinuous;

    status = DSPI_MasterTransferEDMA(ADS_SPI_BASEADDR, &g_dspi_edma_m_handle, &masterXfer);
    if (kStatus_Success != status){
        extract_counter_error++;
    }
    else {
        extract_counter_ok++;
    }
}

/*
 * GPIO IRQ HANDLER
 *
 */
void ADC_PORT_IRQ_HANDLER(void){

    uint32_t reg = GPIO_GetPinsInterruptFlags(ADC_GPIO);

    if(reg & (1U << N_DRDY_PIN)){
        /* Clear external interrupt flag. */
        GPIO_ClearPinsInterruptFlags(ADC_GPIO, 1U << N_DRDY_PIN);

        if(_in_capture){
            capture_counter_gpio++;
            _extract_data_with_dma();
        }
    }
}

/*
 * DMA Callback
 *
 */
static
void EDMA_Callback(SPI_Type *base, dspi_master_edma_handle_t *handle, status_t status, void *userData)
{
    if (status == kStatus_Success)
    {
        if(_in_capture){
            capture_counter_dma++;
        }
    }
}

Tags (2)
0 Kudos
5 Replies

833 Views
mjbcswitzerland
Specialist V

Mikael

What speed is the SPI bus? With 30MHz I extract 64 bytes from an ADC in 13us without DMA.

At the moment you are not improving speed using DMA since it is still being done in the interrupt routine.

What you need to do is use the GPIO as DMA trigger and not as interrupt - let the trigger start the DMA controller to get the data for you and then generate an interrupt to inform that it is ready.

Regards

Mark

0 Kudos

833 Views
mikaelelharrar
Contributor III

Hi Mark,

My SPI bus speed is 15 Mhz.

I think calling "extract_data" into the interrupt handler is a little improvement because the function is not blocking at all. It only set some registers and finally start the DMA.

If I work in pooling mode, I have have some starvation issues (my main task don't get processor time).

Anyway I tried to use the GPIO trigger on the DMA channel without success. It doesnt work me at all.

If you have an code example to share, I will enjoy ...

As far I understood, the trigger setting need to be done around the DMAMUX and the GPIO PIN configuration but I dont know why it doesnt work me.

Thanks

Mikael

0 Kudos

833 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi Mikael,

The K64 reference manual chapter 3.3.9.1 DMA MUX request sources shows the DMA request source.

The ADC0/1 module also could trigger the DMA transfer.

If customer just want to move one or two ADC conversion results, using DMA modules could not enhance much performance Vs. interrupt. DMA module will show powerful during mass data transfer.

Thank you for the attention.


Have a great day,
Ma Hui

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

833 Views
mikaelelharrar
Contributor III

Hi Hui Ma,

I talked about external ADC, not internal ADC. 

The DMA transfer is between SPI bus and memory.

Thanks

Mikael

0 Kudos

833 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi Mikael,

You could refer below document and using SPI to trigger the DMA transfer:

https://community.nxp.com/docs/DOC-100304 

Wish it helps.


Have a great day,
Ma Hui

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos