FTM input capture

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

FTM input capture

2,616 Views
errorek123
Contributor III

Hi,

Recently i created code to generate and measure PWM signal using FTM module but i got one problem with it. I'm not sure what OSR i need to setup to measure signal precisely. The faster FTM clock the better i guess but timer might overflow faster than the PWM signal state changes and i would have to save how many times timer did overflow?

Let's say i got 100Hz PWM and running from 60Mhz clock, the timer will overflow in about 1 ms, when period of my signal is 10ms.

Now i'm "blindly" setting prescaler to 128 to slow down the clock and i can measure my PWM period just fine for the application but i'm wondering if there is any magic formula to calculate best PS or everyone is just using maximum.

Thanks

6 Replies

2,052 Views
kerryzhou
NXP TechSupport
NXP TechSupport

Hi Brian Smith ,

  Please tell me the kinetis chip part number which you are using?

  Now, take the MK64 FTM as an example. K64 core clock is 120Mhz, the bus clock is 60Mhz.

  Then configure the FTM like this:

pastedImage_1.png

FTM clock source is sytem clock, it is 60Mhz.

Then prescaler is divide by 128, you will get the counter frequency as 468.75KHZ.

 Configure the modulo counter = 46874, you will the FTM period as 100ms, it is 100Khz.

 Now, you just need to configure the PWM duty and output is OK.

Wish it helps you!

If you still have question about it, please kindly let me know.

Have a great day,
Kerry

 

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

 

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

0 Kudos

2,052 Views
mjbcswitzerland
Specialist V

Hi Brian

When using the FTM in capture mode it is the lowest frequency to be measured that defines the pre-scaler setting required. The higher the pre-scaler, the lower the frequency can be measured but this also impacts the resolution and restricts the highest frequency that can be measured or its resolution. Since the FTM is based on a 16 bit counter its range is quite restricted, although you can also activate an overflow interrupt to extend the counter in SW, which has to be very carefully handled due to race states when the capture occurs at the same time as an overflow takes place.

In the uTasker project it is preferred to use a wider timer, such as a PIT instead when possible in order to achieve high resolution PWM measurements across a bandwidth of mHz to MHz as explained in chapter 7 of
http://www.utasker.com/docs/uTasker/uTaskerHWTimers.PDF
This uses a port DMA trigger instead of a capture event and can average PWM measurements over multiple cycles and avoids the need to handle capture event interrupt (in addition to greatly improved frequency range).

Regards

Mark

Complete Kinetis solutions for professional needs, training and support:  http://www.utasker.com/kinetis.html

2,052 Views
errorek123
Contributor III

So i'm i'm understanding it correctly. If using PIT to measure PWM frequency i need to setup PIT as free running counter and setup input pin to trigger dma transfer on both edges and transfer current PIT count to user buffer and then i can calculate frequency and also duty cycle right?

Do i set UINT32_MAX in LDVAL register in PIT?  and for how much transfers i setup DMA for? I would assume atleast 3 transfers which would give me time stamp of 3 edges which are enough to calculate everything. Also when do you actually calculate the frequency and duty cycle and check if it was rising or falling edge? on DMA major interrupt, main loop or somewhere else?

0 Kudos

2,052 Views
mjbcswitzerland
Specialist V

Brian

You can set the PIT up to free-run by programming its load value to be 0xffffffff.

The check of input polarity takes place when the measurement starts.

The number of cycles measured over is up to you but you need at least three time-stamps to be able to calculate the period and duty.
The calculation can be performed any time after the DMA transfer compete interrupt has taken place. It could be done in the interrupt itself but usually it is done by posting an event to a task to inform that the buffer results are ready [if you work with a forever loop you can set a flag in the interrupt routine and do it in main()] - after the result has been calculated the next measurement can be started or the next measurement can be started when next needed.

What I in fact do is not set the PIT up to free run but instead reset it and set a measurement timeout interrupt. This way you get a PIT interrupt before the DMA interrupt in case there is no PWM signal present or when the signal is slower than that of minimum frequency - otherwise the DMA samples may take a long time to complete or never complete at all.

Regards

Mark

0 Kudos

2,052 Views
errorek123
Contributor III

Alright i found out my problem, DMA TCD values are undefinied after restart which caused some trouble.

2,052 Views
errorek123
Contributor III

So i did write a simple code to check if it works reliably and it does but only if i use abs when calculating difference othwise i got correct reading every 2 interrupts as attached on the picture below.

volatile uint32_t timestamp_buffer[4];
volatile uint8_t init_state;

volatile float period_ns;
volatile float dutycycle_ns;
volatile float dutycycle_percent;
volatile float difference;

void DMA0_IRQHandler(void)
{
         if(DMA0->INT && (1<<0))
         {
               DMA0 -> INT |= (1<<0);//clear flag

               difference=abs(timestamp_buffer[0]-timestamp_buffer[2]);
               period_ns=difference * (100/6.0f);

               

               if(init_state == 0)
               {
                     difference=timestamp_buffer[0]-timestamp_buffer[1];
                     dutycycle_ns=difference * (100/6.0f);
                     dutycycle_percent=(dutycycle_ns*100)/period_ns;
               }
               else
               {
                     difference=timestamp_buffer[0]-timestamp_buffer[1];
                     dutycycle_ns=difference * (100/6.0f);
                     dutycycle_percent=100-((dutycycle_ns*100)/period_ns);
               }

         }

}

void dma_init(void)
{

         DMA0->TCD[0].DADDR = (uint32_t) timestamp_buffer;
         DMA0->TCD[0].DOFF = 4;
         DMA0->TCD[0].DLAST_SGA = -16;

         DMA0->TCD[0].SADDR = (uint32_t) & PIT->CHANNEL[0].CVAL;
         DMA0->TCD[0].SOFF = 0;//offset per transfer
         DMA0->TCD[0].SLAST = 0;

         DMA0->TCD[0].ATTR = DMA_ATTR_SSIZE(2) | DMA_ATTR_DSIZE(2);
         DMA0->TCD[0].NBYTES_MLNO = 4;

         DMA0->TCD[0].CSR &= ~DMA_CSR_DREQ_MASK;
         DMA0->TCD[0].CSR |= DMA_CSR_INTMAJOR_MASK;

         DMA0->TCD[0].CITER_ELINKNO = DMA_CITER_ELINKNO_CITER(4);
         DMA0->TCD[0].BITER_ELINKNO = DMA_BITER_ELINKNO_BITER(4);

         DMAMUX->CHCFG[0] = (DMAMUX_CHCFG_ENBL_MASK | DMAMUX_CHCFG_SOURCE(52));
}


int main(void)

{

         BOARD_InitBootClocks();
         BOARD_InitDebugConsole();

         SIM -> SCGC6 |= SIM_SCGC6_DMAMUX_MASK;
         SIM -> SCGC7 |= SIM_SCGC7_DMA_MASK;

         PORTD-> PCR[4] = (PORT_PCR_MUX(0x01) | PORT_PCR_IRQC(3) | PORT_PCR_PE_MASK |          PORT_PCR_PS_MASK);

         SIM->SCGC6 |= SIM_SCGC6_PIT_MASK;
         PIT ->MCR =0;
         PIT ->CHANNEL[0].LDVAL = 0xFFFFFFFF;
         PIT ->CHANNEL[0].TCTRL |= PIT_TCTRL_TEN_MASK;

         init_state = ((GPIOD->PDIR >> 4) & 0x01);

         dma_init();

         __NVIC_EnableIRQ(DMA0_IRQn);

         DMA0->ERQ |= 1<<0;

         while(1)
         {


         }

         return 0 ;
}

I checked some things and it seems like every second dma interrupt data is corrupted or somehow not in the correct order? Sometimes position 2 in my array is highter than position 0 which shouldn't be possible. I know there is one scenario i should take care of which is timer overflow  but it's not the problem here because it happens even before first timer overflow.

ABS function solves all the problems but how is it even possible? So it means that the data is just in the wrong order? Maybe i setup my dma wrong? I did setup my DMA for 4 transfers so the buffer always starts on the same edge.

 

With abs:

1.png

Without abs:

2.png

0 Kudos