Capture rising/falling edges and send to DMA

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

Capture rising/falling edges and send to DMA

1,388 Views
MikeAdv
Contributor III

I'm trying to capture 4 edge transistions on FTM1 and send those captures to the DMA.  Then after four captures, I'd like to interrupt from the DMA.  It seems like the CHnF nver gets cleared and thus the DMA request just copies the same capture value into all of my buffer spots.

 

The documentation says that the CHF is cleared when the DMA transfer is complete.  However, when I step through and try and debug the following code, CHF stay's high the whole time.

 

Is there any example code to do something along these lines?

 

uint32_t dummy_var[4]; //Enable the Clock to the FTM0 Module SIM_SCGC6 |= SIM_SCGC6_FTM1_MASK; SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK; SIM_SCGC7 |= SIM_SCGC7_DMA_MASK;  PORTA_PCR8 = PORT_PCR_MUX(3);  // PTA8, FTM1_CH0, A34 PORTA_PCR9 = PORT_PCR_MUX(3);  // PTA9, FTM1_CH1, A33  // The input capture mode is selected when (DECAPEN = 0), (COMBINE = 0), (CPWMS // = 0), (MSnB:MSnA = 0:0), and (ELSnB:ELSnA != 0:0). // ELSnB:ELSnA = 11 for capture rising and falling edges  // DMA = 1 and CHnIE = 1 requests DMA FTM1_C0SC |= FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK | FTM_CnSC_DMA_MASK | FTM_CnSC_CHIE_MASK;  // Eventually want to have DMA send capture on both CH0 and CH1, but for now, let's just try and get CH0 working //FTM1_C1SC |= FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK | FTM_CnSC_DMA_MASK | FTM_CnSC_CHIE_MASK; FTM1_C1SC |= FTM_CnSC_ELSA_MASK | FTM_CnSC_ELSB_MASK;  FTM1_CNTIN = 0x0; FTM1_MOD = 0xffff; FTM1_CNT = 0x0;  FTM1_SC = FTM_SC_PS(0) | FTM_SC_CLKS(1);  // system clock div by 1 FTM1_MODE |= FTM_MODE_FTMEN_MASK;  // start DMA configuration  DMAMUX_CHCFG0 = 0x0;  // DMA module is on pg. 433    // Enable minor looping CR[EMLM] = 1 DMA_CR |= DMA_CR_EMLM_MASK | DMA_CR_EDBG_MASK;  // clear TCD before we set it up?  Not sure if necessary but can't hurt. DMA_TCD0_SADDR = 0x0; DMA_TCD0_SOFF = 0x0; DMA_TCD0_ATTR = 0x0; DMA_TCD0_NBYTES_MLNO = 0x0; DMA_TCD0_SLAST = 0x0; DMA_TCD0_DADDR = 0x0; DMA_TCD0_DOFF = 0x0; DMA_TCD0_CITER_ELINKNO = 0x0; DMA_TCD0_DLASTSGA = 0x0; DMA_TCD0_CSR = 0x0; DMA_TCD0_BITER_ELINKNO = 0x0;    DMA_TCD0_SADDR = (uint32_t)&FTM1_C0V;   // FTM1_C0V is only 16 bits but probably comes from a 32 bit register???? DMA_TCD0_SOFF = 0;  // address offset; Sign-extended offset applied to the current source address to form the next-state value as each source      // read is completed. (pg. 475)      // Don't think I need anything since I'm transfering one 32 bit register per minor loop.        // Bit confused here -- not sure if minor loop iterates on each byte or on the entire 32-bit register.  // 0 : 8 bit // 1 : 16 bit // 2 : 32 bit DMA_TCD0_ATTR = DMA_ATTR_SSIZE(2) | DMA_ATTR_DSIZE(2);  // 16 bit source/dest size  // can also set modulo stuff here for circular???  // Enable minor loop offset on destination address (increment by 4), 4 bytes transfered per service request (pg. 478) DMA_TCD0_NBYTES_MLOFFYES = DMA_NBYTES_MLOFFYES_DMLOE_MASK | (4 << DMA_NBYTES_MLOFFYES_MLOFF_SHIFT) | (4 << DMA_NBYTES_MLOFFYES_NBYTES_SHIFT) ;      // Trying to capture 4 different FTM0_C0V capture times DMA_TCD0_CITER_ELINKNO = 4; DMA_TCD0_BITER_ELINKNO = 4;   DMA_TCD0_DADDR = (uint32_t)&dummy_var;  // dummy_var is an array of 4 32 bit registers DMA_TCD0_DOFF = 0; // same applies here as SOFF?  Just one iteration per minor loop? DMA_TCD0_SLAST = -16; // Setup for next major loop by moving destination back to the start of dummy_Var (-4*4)  DMA_ERQ = DMA_ERQ_ERQ0_MASK;  // Enable CH0 of DMA // Set DMAMUX to route FTM1 DMA event to CH0 of DMA. // pg. 170 gives slot assignments;  Slot 57 is FTM1 // pg 425 talks about DMA mux  DMAMUX_CHCFG0 = DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(57); 
0 Kudos
5 Replies

818 Views
FirmEE
Contributor II

I would think that you would like to fully configure the DMA before you enable it to transfer, that is, the DMA MUX config statement should be before you enable the DMA.

 

I am still having problems getting the DMA to transfer from the Timer, If I set the timer to generate interrupts and service it there, everything works fine.  Now if I can only get the DMA to do this instead of an interrupt service.  I also have submitted a service request.  If you should get this working I am very interested in the solution.

MB.

0 Kudos

818 Views
MikeAdv
Contributor III

I tried moving the DMAMUX statement to the begining and didn't see much different behavior.

 

Likewise, if you make progress, I'd be interested.

 

As best I can tell, it seems like the CHnF never gets cleared in the FTM.  Thus, the DMA request just repeats (in my case 4 times) and writes the same C0V value to the four slots in my buffer.

 

The statement in the reference manual is: "CHnF bit is cleared when the channel DMA transfer is done."  Maybe the entire major loop of the DMA has to complete?  This wouldn't make much sense.  It might be possible to test for this by stringing together several DMA -- it looked like that might be how the linking function of the DMA works -- not sure.  

 

(Note: I've found several little bugs in the code I posted initially.  I think I realized I don't need the minor loop since it is just one transfer?  I'm still a little confused on this.  I'm transfering 4 bytes, does that mean for iterations of the minor loop?  Or since the 4 bytes makeup one register is that considered one minor loop iteration?  I'm seeing values greater than 256 in my buffer when I disabled the minor loop, so it must mean that one minor loop iteration is a read/write of the entire 32bit register.  Also, I was using SLAST and should have been using DLAST to reset where the data was going.)

0 Kudos

818 Views
MikeAdv
Contributor III

Think I finally found my problem.

 

I read the DMA slot number from the wrong table in the manual.  When I select the correct DMA source (and my other little bugs I found), I think things seems to be working as expected.

0 Kudos

818 Views
FirmEE
Contributor II

Hello Mike,

Well, I'm still having some issues with the DMA transfer of Captured Timer values.  I have a 250 KHz square wave feeding into my timer input, Timer is configured to capture on both edges. This gives me a pulse width of 2uSec. With a core clock of 100MHz, System clock is set to 50MHz and Timer prescale=1, I should get timer values separated by 100 counts. I am  getting what appears to be random values written to my buffer by the DMA.  I configure the DMA to transfwer 64 request, it does the 64 transfers but the data is not correct.

Ho does the DMA clear the Timer Channel Flag?  It appears as if the timer is wrapping around and an overflow interrupt is signaling the next transfer.  Did you have any such problems? 

If I configure the timer to generate interrupts and service the interups I get the correct values.  I need the DMA to do this since my actual signal will be a lot faster and interrupt service will not be fast enoug.

Please let me know how you got yous to work.

Regards. Mike B.

0 Kudos

818 Views
kenrenjen
Contributor III

I am trying to find a solution for that problem as well.. So let me know if you ever solved it two years ago :smileywink: - Or if there is anyone else who knows a good solution for handling (counting) overflows without interrupt.

thanks..

0 Kudos