AnsweredAssumed Answered

Dual edge capture with DMA

Question asked by maurizio lenzini on Nov 18, 2014
Latest reply on Oct 19, 2018 by Tian YunFang

  I need to configure the timer in dual edge capture mode with DMA. My application measure the period

  ( with FTM0 CH4 in dual edge capture mode ) of square wave in input ( 1 us ) and transfers the result

  in ram buffer for post analysis. The DMA should transfer, every period, two bytes from FTM0_CnV ( channel 4,5 ) to the RAM buffer

  ( wuwFTM0Cs4_buffer and wuwFTM0Cs5_buffer ). The data moved form FTM0_C4V to the RAM buffer are always zero. The DMA  associated at FTM0_C5V doesn't move.

  DMA seems doesn't move FTM0_CnV value correctly. Anyone have an idea?

 

  The follow code without the DMA its works correctly.

  This is my code:

                                                    |

                      _    _   _                  |

  Square wave |  |_|  |_|  |_  ----------> | FTM0_CH4  K70 (150 MHz)

                                                    |

                                                    |

  period 1 us

 

typedef unsigned short int    UWORD;  /* 16 bits */

typedef unsigned long int   ULONG;  /* 32 bits */

 

#define ELEMENTS_FTM0  ( 16 )

#define DMA_CH9                ( 9 )

#define DMA_CH9_MUX       ( 9 )

#define DMA_CH10            ( 10 )

#define DMA_CH10_MUX   ( 10 )

 

static UWORD wuwFTM0Cs4_buffer[ ELEMENTS_FTM0 ]; /* circular buffer: the DMA fills this array */

static UWORD wuwFTM0Cs5_buffer[ ELEMENTS_FTM0 ];

 

void vDualEdgeCaptureTimerDMA( void )

{

  PORTA_PCR7  =  PORT_PCR_MUX(3); /* FTM0_CH4 input   */

  GPIOA_PDDR  =  0;

            

  //////////////////// DMA CHANNEL 9 get data from FTM0_C4V ( first edge )//////////////////////////////////////////////////

  /* clear flag */

  DMAMUX0_CHCFG(DMA_CH9_MUX) &= ~( DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_TRIG_MASK );

  DMAMUX0_CHCFG(DMA_CH9_MUX) |= DMAMUX_CHCFG_SOURCE( 28 );        /* FTM0_C4V trigger event */

 

  /* enable DMA channel  */

  DMAMUX0_CHCFG(DMA_CH9_MUX) |= DMAMUX_CHCFG_ENBL_MASK;

 

  /* DMA section */ 

  DMA_CERQ                   = DMA_CERQ_CERQ(DMA_CH9);            /* clear enable request  */

 

  DMA_SADDR(DMA_CH9)         = (ULONG) (&FTM0_C4V);               /* Source address, to be advanced by 0 bytes after one word.   */

  DMA_DADDR(DMA_CH9)         = (ULONG) (&wuwFTM0Cs4_buffer[ 0 ]); /* Destination address  */

    

  DMA_SLAST(DMA_CH9)              = (ULONG)( ((ULONG)-1) * 0);

  DMA_DLAST_SGA(DMA_CH9)     = (ULONG)( ((ULONG)-1) * (ELEMENTS_FTM0 * 2));

 

  DMA_ATTR(DMA_CH9)          = DMA_ATTR_SSIZE(1) |                /* sixteen bit moved */

                                                DMA_ATTR_DSIZE(1);                 /* sixteen bit moved */

  DMA_DOFF(DMA_CH9)          = 2;                                 /* source advance TWO byte per write     */

  DMA_SOFF(DMA_CH9)          = 0;                                 /* source advance zero byte per write     */

 

 

  DMA_CITER_ELINKNO(DMA_CH9) = ELEMENTS_FTM0;

  DMA_BITER_ELINKNO(DMA_CH9) = ELEMENTS_FTM0;

 

  DMA_CSR(DMA_CH9)           = 0;

 

  DMA_NBYTES_MLOFFNO(DMA_CH9) = DMA_NBYTES_MLOFFNO_SMLOE_MASK | 2; /* Number of bytes per minor loop:  */

 

  DMA_SERQ                    = DMA_SERQ_SERQ(DMA_CH9);          /* Transmitter and receiver enable */

 

  //////////////////// DMA CHANNEL 10 get data from FTM0_C5V ( second edge )//////////////////////////////////////////////////

 

  /* clear flag */

  DMAMUX0_CHCFG(DMA_CH10_MUX) &= ~( DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_TRIG_MASK );

  DMAMUX0_CHCFG(DMA_CH10_MUX) |= DMAMUX_CHCFG_SOURCE( 29 );        /* FTM0_C5V trigger */

 

  /* enable DMA channel  */

  DMAMUX0_CHCFG(DMA_CH10_MUX) |= DMAMUX_CHCFG_ENBL_MASK;

 

  /* DMA section */ 

  DMA_CERQ                    = DMA_CERQ_CERQ(DMA_CH10);           /* clear enable request  */

 

  DMA_SADDR(DMA_CH10)         = (ULONG) (&FTM0_C5V);               /* Source address */

  DMA_DADDR(DMA_CH10)         = (ULONG) (&wuwFTM0Cs5_buffer[ 0 ]); /* Destination address  */

    

  DMA_SLAST(DMA_CH10)         = (ULONG)( ((ULONG)-1) * 0);

  DMA_DLAST_SGA(DMA_CH10)     = (ULONG)( ((ULONG)-1) * (ELEMENTS_FTM0 * 2));   /* for a one-off transfer, we don't care about the DEST pointer afterwards.  */

  

  DMA_ATTR(DMA_CH10)          = DMA_ATTR_SSIZE(1) |

                                                   DMA_ATTR_DSIZE(1);

  DMA_DOFF(DMA_CH10)          = 2;                                 /* source advance two byte per write     */

  DMA_SOFF(DMA_CH10)          = 0;                                 /* source advance zero byte per write     */

 

  DMA_CITER_ELINKNO(DMA_CH10) = ELEMENTS_FTM0;

  DMA_BITER_ELINKNO(DMA_CH10) = ELEMENTS_FTM0;

 

  DMA_CSR(DMA_CH10)           = 0;

 

  DMA_NBYTES_MLOFFNO(DMA_CH10)  = DMA_NBYTES_MLOFFNO_SMLOE_MASK | 2; /* Number of bytes per minor loop:  */

 

  DMA_SERQ                      = DMA_SERQ_SERQ(DMA_CH10);           /* set enable request */

 

  /* Enable the Clock to the FTM0 Module */

  SIM_SCGC6 |= SIM_SCGC6_FTM0_MASK;

 

  FTM0_FMS |= FTM_FMS_WPEN_MASK;

 

  /* FTM0_MODE[WPDIS] = 1; */

  if (( FTM0_FMS & FTM_FMS_WPEN_MASK ) == FTM_FMS_WPEN_MASK )

  {

    /* Disable Write Protection - enables changes to QUADEN, DECAPEN, etc.   */

    FTM0_MODE |= FTM_MODE_WPDIS_MASK;

  }

  else

  {

    vFatalError( ERR_TIMER_NOT_READY, NO_SECONDARY_CODE );

  }

 

 

  FTM0_CNT = 0x0; /* FTM Counter Value - reset counter to zero */

 

  /**/

  FTM0_MOD  = 0xFFFF;

 

  /* Status and Control bits */

  FTM0_SC =  FTM_SC_CLKS(1); /* Selects Clock source */

 

  /* sets pre-scale value see details below */

  /******begin FTM_SC_PS details ****************************

  * Sets the Prescale value for the Flex Timer Module which divides the

  * Peripheral bus clock -> 48Mhz by the set amount

  * Peripheral bus clock set up in clock.h

  *

  * The value of the prescaler is selected by the PS[2:0] bits.

  * (FTMx_SC field bits 0-2 are Prescale bits -  set above in FTM_SC Setting)

  *

  *  000 - 0 - No divide

  *  001 - 1 - Divide by 2

  *  010 - 2 - Divide by 4

  *  011 - 3 - Divide by 8

  *  100 - 4 - Divide by 16

  *  101 - 5 - Divide by 32

  *  110 - 6 - Divide by 64 -

  *  111 - 7 - Divide by 128

  *  ******end FTM_SC_PS details*****************************/

  FTM0_SC |= FTM_SC_PS(0);

 

  /* FTM1_MOD = (PERIPHERAL_BUS_CLOCK/(1<<FTM0_CLK_PRESCALE))/FTM0_OVERFLOW_FREQUENCY ; */ /* Set the overflow rate */

  FTM0_CNTIN = 0; /* Set the Counter Initial Value to 0*/

 

  /* */

  FTM0_MODE |= FTM_MODE_FTMEN_MASK;

 

  /* FTMx_CnSC*/

  /* input capture seting  */

  FTM0_C4SC    &= ~FTM_CnSC_ELSB_MASK;    /* rising Edge */

  FTM0_C4SC    |= FTM_CnSC_ELSA_MASK;       /* rising Edge */

  FTM0_C4SC    &= ~FTM_CnSC_MSB_MASK;     /* Channel Mode select */

  FTM0_C4SC    |= FTM_CnSC_MSA_MASK;        /* Channel Mode select */

 

  FTM0_C5SC    &= ~FTM_CnSC_ELSB_MASK;   /* rising Edge */

  FTM0_C5SC    |= FTM_CnSC_ELSA_MASK;      /* rising Edge */

  FTM0_C5SC    &= ~FTM_CnSC_MSB_MASK;    /* Channel Mode select */

  FTM0_C5SC    |= FTM_CnSC_MSA_MASK;       /* Channel Mode select */

 

  FTM0_SC      &= ~FTM_SC_CPWMS_MASK;        /* no pwm */

  FTM0_COMBINE |= FTM_COMBINE_DECAPEN2_MASK; /* */

  FTM0_COMBINE |= FTM_COMBINE_DECAP2_MASK;

 

  FTM0_C4SC    |= FTM_CnSC_DMA_MASK;         /* DMA support */

  FTM0_C5SC    |= FTM_CnSC_DMA_MASK;         /* DMA support */

 

  FTM0_C4SC    |= FTM_CnSC_CHIE_MASK;        /* IE enabled for DMA  */

  FTM0_C5SC    |= FTM_CnSC_CHIE_MASK;        /* IE enabled for DMA  */

 

  /*  Interrupts */

  FTM0_FMS     &= ~FTM_FMS_WPEN_MASK;

}

Outcomes