Dual edge capture with DMA

cancel
Showing results for 
Search instead for 
Did you mean: 

Dual edge capture with DMA

1,014 Views
mauriziolenzini
Contributor I

  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;

}

Labels (1)
0 Kudos
6 Replies

284 Views
tianyunfang
Contributor I

Are you solve it?I have same problem!

0 Kudos

284 Views
Kan_Li
NXP TechSupport
NXP TechSupport

I am sorry , but a little bit confused. Seems just square wave input to FTM0_CH4, no signal input to FTM0_CH5, so what is the purpose for DMA channel 10? in my understanding, if FTM0_CH4 is configured as input capture on rising or falling edge, the DMA should all be triggered by FTM0_CH4. Would you please kindly help to clarify?

Thanks for your patience!


Have a great day,
Kan

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

0 Kudos

284 Views
mauriziolenzini
Contributor I

Thanks Mr Kan_Li

I apologize to you, but my english is bad.

I use the FTM0 in dual edge capture mode ( period measurement ). FTM0_CH4 ( PORTA ) is the input of square wave. If you want measure the period you need the C(n)V register for first edge and C(n+1)V for the second edge ( the difference is the period of the square wave ). I need two DMA because I want to move two data: the C(n)V register and C(n+1)V register. In my application C(n)V is  FTM0_C4V and C(n+1)V is FTM0_C5V.  DMA channel 9 move the FTM0_C4V data into RAM buffer and DMA channel 10 move FTM0_C5V data into a RAM buffer.

Is it correct this reasoning?

best regards

0 Kudos

284 Views
Kan_Li
NXP TechSupport
NXP TechSupport

Thanks for the information! I think I found the cause. Seems you want to use Dual Edge Capture mode, but looks like channel 4 and channel 5 are both configured as rising edge,

/* 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 */

and RM also says "When the CH(n+1)F bit is set, both edges were captured and the captured values are ready for reading in the C(n)V and C(n+1)V registers." so when CH(n)F to trigger DMA, C(n)V is not ready yet. so you just need one DMA channel to mode C(n)V and C(n+1)V, by scatter-gather mode, or use channel link to move C(n)V and C(n+1)V when CH(n+1)F is set.

Hope that helps,


Have a great day,
Kan

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

284 Views
mauriziolenzini
Contributor I

Thanks you have right!

The RM recommends the clearing of flag  CH(n)F and CH(n+1)F ( looks the note of the figure in paragraph period measurement in FlexTimer chapter  ), but with DMA channel link mode or scatter-gather mode only CH(n+1)F is cleared. Is it correct? (  This would mean that you can not use DMA in dual edge capture mode).

Have a nice day

0 Kudos

284 Views
Kan_Li
NXP TechSupport
NXP TechSupport

In Continuous Capture mode of Dual edge capture, it is possible to clear only the CH(n+1)F bit.  Therefore, when the CH(n+1)F bit is set again, the latest captured values are available in C(n)V and C(n+1)V registers. Please kindly refer to 40.4.24.2 Continuous Capture mode for more details.


Have a great day,
Kan

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

0 Kudos