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