KM34Z256: PDB back to back mode trigger ADC0 ch0->ch2 and DMA copy

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

KM34Z256: PDB back to back mode trigger ADC0 ch0->ch2 and DMA copy

1,387 Views
nickng
Contributor II

Hi,

I have tried to go through all the possible related reference manuals and example code project about the usage of triggering the ADC0 [ch 0 ~2]conversion sequentially by PDB and use DMA P2M to copy the conversion result to buffer over back to back mode .

So that the PDB0.ch0pretrig0 pretriggered the ADC0.ch0 to do the ADC conversion and then emit a ADC.COCO complete flag to the DMA0 , DMA0 starts to copy the result from ADC0.R[0].

PDB0.ch0pretrig1 is then automatically pretriggered the ADC0.ch1 conversion and the result goes to ADC0.R[1] -> DMA0 copy it as well..

=>

PDB0.ch0pretrig0 ->  ADC0.ch0 ->ADC0.R[0] -> DMA0->P2M->

PDB0.ch0pretrig1 ->  ADC0.ch1 ->ADC0.R[1] -> DMA0->P2M->

PDB0.ch0pretrig2 ->  ADC0.ch2 ->ADC0.R[2] -> DMA0->P2M-> PDB0.ch0 ->  ...

  But I am  still not really sure the correct  way to configure the PDB in such scene ...

Here is my config :

1. please help to correct.....

2. if I set in this way, is that possible kick it to start?

The manual (KM34P144M75SF0RM.pdf ) says I can control the pretrigger   channel by assigning the CHnC1.BB register.

So I guessI need to configure the enableBackToBackOperationMask w.r.t PDB0 pretrigger channel with certain delay

i.e.:

  PDB0.ch0 : pdbAdcPreTriggerConfigStruct.enableBackToBackOperationMask = 0U;

  PDB0.ch1 : pdbAdcPreTriggerConfigStruct.enableBackToBackOperationMask = 1U;

  PDB0.ch2 : pdbAdcPreTriggerConfigStruct.enableBackToBackOperationMask = 2U;

and XBAR setting:

    XBAR_Init(XBAR);
    /* Configure the XBAR signal connections. */

    /* Configure the XBAR interrupt. */
    xbarConfig.activeEdge = kXBAR_EdgeRising;
    xbarConfig.requestType = kXBAR_RequestDisable;


    XBAR_SetSignalsConnection(XBAR, kXBAR_InputPdb0Ch0Pretrigger0, kXBAR_OutputPdb0PreTrigger2Ack );

    XBAR_SetOutputSignalConfig(XBAR, kXBAR_OutputAdcTrgA, &xbarConfig);


    XBAR_SetSignalsConnection(XBAR, kXBAR_InputPdb0Ch0Pretrigger1, kXBAR_OutputPdb0PreTrigger0Ack );
    XBAR_SetOutputSignalConfig(XBAR, kXBAR_OutputAdcTrgB, &xbarConfig);


    XBAR_SetSignalsConnection(XBAR, kXBAR_InputPdb0Ch0Pretrigger2, kXBAR_OutputPdb0PreTrigger1Ack );
    XBAR_SetOutputSignalConfig(XBAR, kXBAR_OutputAdcTrgC, &xbarConfig);

pastedImage_1.png

Labels (1)
0 Kudos
6 Replies

965 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Nick,

I am sorry for the delay.

Regarding your question, as you know that the KM34 has PDB module, ADC module, you want to use PDB to trigger ADC twice in ONE PDB cycle, as you said:

PDB0.ch0pretrig0 ->  ADC0.ch0 ->ADC0.R[0] -> DMA0->P2M->

PDB0.ch0pretrig1 ->  ADC0.ch1 ->ADC0.R[1] -> DMA0->P2M->

okay, I think you can use the configuration:

1)initialize the PDB, ADC for peripheral module gated clock, PDM modulus for PDB0_MOD,delay1 and delay2 of CH0  by PDB0_CH0DLY0/PDB0_CH0DLY1, note that difference(PDB0_CH0DLY1-PDB0_CH0DLY0) must be greater than one ADC conversion time. But in the case, you have to clear all BB bits in PDB0_CHnC1, because you do not use backTOback triggering mode.

2)configuer the ADC channel and set the ADTRG bit in ADC0_SC2, in this way, you use hardware triggering mode.

3)set the PDBADCTRG bit in SIM_MISC_CTL so that PDB is assigned to trigger ADC instead of crossbar, so It is UNNECESSARY to configure the crossbar module.

I suggest you use interrupt mechanism to read ADC results to memory. If you use DMA, you have to pay attention to the fact that both COCO in ADC0_SC1A and ADC0_SC1B can trigger DMA, the DMA can NOT identify which COCO bit in ADC0_SC1A or ADC0_SC1B trigger DMA, so it is possible that you do not know whether  the data in memory is from ADC0_R[0] or ADC0_R[1].

Hope it can help you

BR

Xiangjun Rong

0 Kudos

965 Views
nickng
Contributor II

Hi Xiangjun,

Thanks a lot for your reply.

I could make it work without using PDB back to back mode.

Thanks to the result register is at successive memory ( ADC0.R[4] ),   I can use DMA with the M2M and cycle steal mode such that it can change the source and destination of each ADCC.OCO request per DMA read/write cycle.  Therefore, no  ADC coco conflict during DMA transfer. I just got it done yesterday. 

By the way, I am trying to make it work with the back to back mode but I did not  succeed. Could you please provide me a complete code example base on the above case?

I have tried to set SIM mode into PDB ADC trigger and     

 

SIM->MISC_CTL = ((SIM->MISC_CTL &    (~(SIM_MISC_CTL_UART2IRSEL_MASK)))                       /* Mask bits to zero which are setting */      | SIM_MISC_CTL_UART2IRSEL(MISC_CTL_UART2IRSEL_NONE)    /* UART2 IrDA Select: Pad RX input PTI[6] or PTE[6] selected for RX input of UART2 and UART2 TX signal is not used for modulation */    );  SIM->MISC_CTL |= SIM_MISC_CTL_PDBADCTRG(1) ;/*pick PDB as the ADC HW trigger source instead of Xbar*/
adc16ChannelConfigStruct.channelNumber = 0;      adc16ChannelConfigStruct.enableInterruptOnConversionCompleted = false; /* Enable the interrupt. */     
ADC16_SetChannelConfig(ADC0, adc16ChannelConfigStruct.channelNumber, &adc16ChannelConfigStruct);    
  adc16ChannelConfigStruct.channelNumber = 1;     
ADC16_SetChannelConfig(ADC0, adc16ChannelConfigStruct.channelNumber, &adc16ChannelConfigStruct);    
  ADC16_EnableHardwareTrigger(ADC0, true);      DMA_Configuration();      /* Enable DMA */     
ADC16_EnableDMA(ADC0, true);
PDB_GetDefaultConfig(&pdbConfigStruct);
pdbConfigStruct.prescalerDivider = kPDB_PrescalerDivider4;
PDB_Init(PDB0, &pdbConfigStruct);    /* Configure the delay interrupt. */
PDB_SetModulusValue(PDB0, 3900U);//3900 = 166us / 24MHz    /* The available delay value is less than or equal to the modulus value. */
PDB_SetCounterDelayValue(PDB0, 3000U);
PDB_DisableInterrupts(PDB0, kPDB_DelayInterruptEnable);
pdbAdcPreTriggerConfigStruct.enableBackToBackOperationMask = (1U << 0 ) | (1U << 1) ;   
pdbAdcPreTriggerConfigStruct.enablePreTriggerMask = (1U << 0 )| (1U << 1) ;   
pdbAdcPreTriggerConfigStruct.enableOutputMask = 0 | (1U << 1) ;‍‍‍‍‍‍‍‍‍‍
PDB_SetADCPreTriggerConfig(PDB0, 0, &pdbAdcPreTriggerConfigStruct);
PDB_SetADCPreTriggerDelayValue(PDB0, 0, 0, 0);
PDB_SetADCPreTriggerDelayValue(PDB0, 0, 1, 1200);
PDB_DoSoftwareTrigger(PDB0);‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

but it seems not working.

Thanks a lot,

Nick

0 Kudos

965 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Nick,

can you post all your project so taht I can review your code?

BR

XiangJun Rong

0 Kudos

965 Views
nickng
Contributor II


/*
 * Copyright (c) 2015, Freescale Semiconductor, Inc.
 * Copyright 2016-2017 NXP
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * o Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * o Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * o Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "fsl_debug_console.h"
#include "board.h"
#include "fsl_pdb.h"
#include "fsl_adc16.h"
#include "fsl_xbar.h"
#include "fsl_dma.h"
#include "fsl_dmamux.h"

#include "pin_mux.h"
#include "fsl_vref.h"
/*******************************************************************************
 * Definitions
 ******************************************************************************/
#define DEMO_AFE_CHANNEL 0U
/* About 23 mV */
#define DEMO_AFE_VREF_TRIM 46U

#define DEMO_AFE_CH0_IRQ_HANDLER_FUNC AFE_CH0_IRQHandler
#define DEMO_AFE_IRQn AFE_CH0_IRQn

/*******************************************************************************
 * Prototypes
 ******************************************************************************/
void APP_VREF_Config(void);

/*******************************************************************************
 * Variables
 ******************************************************************************/
volatile bool g_bAdcConvDone;   /* Conversion done flag */
volatile int32_t g_result0 = 0; /* Conversion result */
volatile int32_t i32a_adc16result[] = {0,0}; /* Conversion result */
dma_handle_t g_DMA_Handle;                                       /* Dma handler */
dma_transfer_config_t g_transferConfig;                          /* Dma transfer config */


#define DEMO_DMA_CHANNEL 0U



/*******************************************************************************
 * Code
 ******************************************************************************/


void BOARD_InitPins(void) {
  CLOCK_EnableClock(kCLOCK_PortI);                           /* PCTLI Clock Gate Control: Clock enabled */
  CLOCK_EnableClock(kCLOCK_PortJ);                           /* PCTLJ Clock Gate Control: Clock enabled */

  PORT_SetPinMux(PORTI, PIN6_IDX, kPORT_MuxAlt2);            /* PORTI6 (pin 6) is configured as UART2_RX */
  PORT_SetPinMux(PORTI, PIN7_IDX, kPORT_MuxAlt2);            /* PORTI7 (pin 7) is configured as UART2_TX */
  PORT_SetPinMux(PORTJ, PIN3_IDX, kPORT_MuxAsGpio);          /* PORTJ3 (pin 62) is configured as PTJ3 */
  SIM->MISC_CTL = ((SIM->MISC_CTL &
    (~(SIM_MISC_CTL_UART2IRSEL_MASK)))                       /* Mask bits to zero which are setting */
      | SIM_MISC_CTL_UART2IRSEL(MISC_CTL_UART2IRSEL_NONE)    /* UART2 IrDA Select: Pad RX input PTI[6] or PTE[6] selected for RX input of UART2 and UART2 TX signal is not used for modulation */
    );

  SIM->MISC_CTL |= SIM_MISC_CTL_PDBADCTRG(1) ;/*pick PDB as the ADC HW trigger source instead of Xbar*/

}

static void DMA_Configuration(void)
{

    /* Configure DMAMUX */
    DMAMUX_Init(DMAMUX0);
    DMAMUX_SetSource(DMAMUX0, DEMO_DMA_CHANNEL, kDmaRequestMux0SarADC); /* Map ADC source to channel 0 */
    DMAMUX_EnableChannel(DMAMUX0, DEMO_DMA_CHANNEL);

    DMA_Init(DMA0);
    DMA_CreateHandle(&g_DMA_Handle, DMA0, DEMO_DMA_CHANNEL);
    DMA_PrepareTransfer(&g_transferConfig, (void *)(&ADC0->R[0]), sizeof(uint32_t),
                        (void *)&i32a_adc16result, sizeof(uint32_t), sizeof(i32a_adc16result),
                              kDMA_MemoryToMemory);/*move both SRC and DES => ADC0->R and result buff*/
    /* Setup transfer */
    DMA_SetTransferConfig(DMA0, DEMO_DMA_CHANNEL, &g_transferConfig);
    /* Enable interrupt when transfer is done. */
    DMA_EnableInterrupts(DMA0, DEMO_DMA_CHANNEL);
    /* Enable async DMA request. */
    DMA_EnableAsyncRequest(DMA0, DEMO_DMA_CHANNEL, true);
    /* Forces a single read/write transfer per request. */
    DMA_EnableCycleSteal(DMA0, DEMO_DMA_CHANNEL, true);
    /* Enable transfer. */
    DMA_StartTransfer(&g_DMA_Handle);

   /* Enable IRQ. */
   NVIC_EnableIRQ(DMA0_IRQn);
}

void DMA0_IRQHandler(void)
{
//     if ((DMA_DSR_BCR_DONE(DMA_GetChannelStatusFlags(DMA0, 0))) )
//     {
          /* Clear transaction done interrupt flag */
          DMA_ClearChannelStatusFlags(DMA0, 0, kDMA_TransactionsDoneFlag);
          DMA_ClearChannelStatusFlags(DMA0, 0,kDMA_ConfigurationErrorFlag);
          DMA_SetTransferConfig(DMA0,0, &g_transferConfig);
           g_bAdcConvDone = true;
//     }

}


void APP_VREF_Config(void)
{
    vref_config_t config;

    /* Get vref default configure */
    /*
     * config.bufferMode = kVREF_ModeHighPowerBuffer;
     * config.bufferMode = kVREF_ModeTightRegulationBuffer;
     * config.enableExternalVoltRef = false;
     * config.enableLowRef = false;
     */
    VREF_GetDefaultConfig(&config);
#if defined(FSL_FEATURE_VREF_HAS_LOW_REFERENCE) && FSL_FEATURE_VREF_HAS_LOW_REFERENCE
    /* Enable low reference volt */
    config.enableLowRef = true;
#endif /* FSL_FEATURE_VREF_HAS_LOW_REFERENCE */
    /* Init vref */
    VREF_Init(VREF, &config);
#if defined(FSL_FEATURE_VREF_HAS_LOW_REFERENCE) && FSL_FEATURE_VREF_HAS_LOW_REFERENCE
    /* Vref set trim reference */
    VREF_SetLowReferenceTrimVal(VREF, 3U);
#endif /* FSL_FEATURE_VREF_HAS_LOW_REFERENCE */
    /* Vref set trim, this value will not be the same with every boards */
    VREF_SetTrimVal(VREF, DEMO_AFE_VREF_TRIM);
}


static void ADC_Init(void)
{
    /* Configure the ADC. */

    adc16_config_t adc16ConfigStruct;
    adc16_channel_config_t adc16ChannelConfigStruct;

    /*
     * adc16ConfigStruct.referenceVoltageSource = kADC16_ReferenceVoltageSourceVref;
     * adc16ConfigStruct.clockSource = kADC16_ClockSourceAsynchronousClock;
     * adc16ConfigStruct.enableAsynchronousClock = true;
     * adc16ConfigStruct.clockDivider = kADC16_ClockDivider8;
     * adc16ConfigStruct.resolution = kADC16_ResolutionSE12Bit;
     * adc16ConfigStruct.longSampleMode = kADC16_LongSampleDisabled;
     * adc16ConfigStruct.enableHighSpeed = false;
     * adc16ConfigStruct.enableLowPower = false;
     * adc16ConfigStruct.enableContinuousConversion = false;
     */

    ADC16_GetDefaultConfig(&adc16ConfigStruct);
    adc16ConfigStruct.enableHighSpeed = true;
    adc16ConfigStruct.longSampleMode = kADC16_LongSampleCycle10;//kADC16_LongSampleDisabled;
    adc16ConfigStruct.resolution = kADC16_ResolutionSE16Bit ;
    ADC16_Init(ADC0, &adc16ConfigStruct);
    ADC16_SetHardwareAverage(ADC0, kADC16_HardwareAverageDisabled);//kADC16_HardwareAverageCount4);//
  #if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION
      ADC16_EnableHardwareTrigger(ADC0, false);
      if (kStatus_Success == ADC16_DoAutoCalibration(ADC0))
      {
  //        PRINTF("ADC16_DoAutoCalibration() Done.\r\n");
      }

  #endif /* FSL_FEATURE_ADC16_HAS_CALIBRATION */

      adc16ChannelConfigStruct.channelNumber = 0;
      adc16ChannelConfigStruct.enableInterruptOnConversionCompleted = false; /* Enable the interrupt. */
      ADC16_SetChannelConfig(ADC0, adc16ChannelConfigStruct.channelNumber, &adc16ChannelConfigStruct);

      adc16ChannelConfigStruct.channelNumber = 1;
      ADC16_SetChannelConfig(ADC0, adc16ChannelConfigStruct.channelNumber, &adc16ChannelConfigStruct);

      ADC16_EnableHardwareTrigger(ADC0, true);
      DMA_Configuration();
      /* Enable DMA */
      ADC16_EnableDMA(ADC0, true);

}


int main(void)
{

    /* Init board hardware. */
    BOARD_InitPins();
    BOARD_BootClockRUN();
    BOARD_InitDebugConsole();


    APP_VREF_Config();

    ADC_Init();


    pdb_config_t pdbConfigStruct;
    pdb_adc_pretrigger_config_t pdbAdcPreTriggerConfigStruct;

    //==============
    /* Configure the PDB counter. */
    /*
     * pdbConfigStruct.loadValueMode = kPDB_LoadValueImmediately;
     * pdbConfigStruct.prescalerDivider = kPDB_PrescalerDivider1;
     * pdbConfigStruct.dividerMultiplicationFactor = kPDB_DividerMultiplicationFactor1;
     * pdbConfigStruct.triggerInputSource = kPDB_TriggerSoftware;
     * pdbConfigStruct.enableContinuousMode = false;
     */
    PDB_GetDefaultConfig(&pdbConfigStruct);
//    pdbConfigStruct.enableContinuousMode = true;
    pdbConfigStruct.prescalerDivider = kPDB_PrescalerDivider4;
    PDB_Init(PDB0, &pdbConfigStruct);

    /* Configure the delay interrupt. */
    PDB_SetModulusValue(PDB0, 3900U);//3900 = 166us / 24MHz


    /* The available delay value is less than or equal to the modulus value. */
    PDB_SetCounterDelayValue(PDB0, 3000U);
    PDB_DisableInterrupts(PDB0, kPDB_DelayInterruptEnable);

    /* Configure the ADC Pre-Trigger. */

    pdbAdcPreTriggerConfigStruct.enableBackToBackOperationMask = 0 | (1U << 1) ;

    pdbAdcPreTriggerConfigStruct.enablePreTriggerMask = (1U << 0 )| (1U << 1);
    pdbAdcPreTriggerConfigStruct.enableOutputMask = 0 | (1U << 1) ;
    PDB_SetADCPreTriggerConfig(PDB0, 0, &pdbAdcPreTriggerConfigStruct);
    PDB_SetADCPreTriggerDelayValue(PDB0, 0, 0, 0);
    PDB_SetADCPreTriggerDelayValue(PDB0, 0, 1, 1200);
    /* The available Pre-Trigger delay value is less than or equal to the modulus value. */

    PDB_DoLoadValues(PDB0);




    while (1)
    {
        /* Wait next triger from user */
        PRINTF("Press any key to trigger ADC conversion\r\n");
        GETCHAR();
        g_bAdcConvDone = false;


        PDB_DoSoftwareTrigger(PDB0);

        while (!g_bAdcConvDone)
        {
        }
        /* Print result */

          PRINTF("ADC 16 value  = %05d   %05d    \r\n",  i32a_adc16result[0], i32a_adc16result[1]);
        /* Software trigger conversion */

    }
}



 

0 Kudos

965 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Nick,

Sorry for the delay.

Based on your solution, the PDB module triggers ADC_SC1A and ADC_SC1B in one PDB cycle, you use DMA to transfer ADC_RA and ADC_RB to memory. As I said the solution is not feasible, because both the COCO event of ADC_SC1A and ADC_SC1B can trigger DMA, but you do not know which sample should be transferred ADC_RA or ADC_RB once DMA is triggered.

In your code:

DMA_PrepareTransfer(&g_transferConfig, (void *)(&ADC0->R[0]), sizeof(uint32_t),
                        (void *)&i32a_adc16result, sizeof(uint32_t), sizeof(i32a_adc16result),
                              kDMA_MemoryToMemory);/*move both SRC and DES => ADC0->R and result buff*

You transfer ADC0->R[0], where is ADC0->R[1]?

I suggest you use interrupt mode to transfer data to memory.

BR

Xiangjun rong

 

0 Kudos

965 Views
nickng
Contributor II

Hi Xiangjun,

It is running at memory to memory mode and in cycle steal , therefore it will increase both addresses (source and destination ) per adc coco. And they are triggered by PDB sequentially. Every adc triggering cycle has only  on adc in active.

you may try to test  the code but 

pdbAdcPreTriggerConfigStruct.enableBackToBackOperationMask = 0;

It should work.

Best regards,

Nick

0 Kudos