AnsweredAssumed Answered

SPI/DMA Kinetis K64

Question asked by Mikael Elharrar on Jun 14, 2017
Latest reply on Jun 20, 2017 by Hui_Ma

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

Outcomes