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