TC or TCC for dynamic frequency input measurement and outputting on another TC or TCC with minimal delay

Go To Last Post
3 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

I'm trying to use the following setup:

Edge Trigger through event system to timer to measure frequency and then output to another timer output to recreate the signal input frequency divided by 4.

EIC->TC or TCC -> Divide Input Frequency by 4 -> Output divided frequency to another TC or TCC

 

I have the first portion somewhat working with a Atmel Start setup. The interrupt for TC4 is below. I can read into an array the values, but they seem to vary somewhat. By 1 or 2 every other read of the CC0 register. I never get a very constant value while inputting a 1kHz square wave into the micro. At some slightly higher frequencies(5kHz) I'll start to get values back that don't make sense like 5-100 from the CC0 register.

 

I am then outputting TC4 period to the TC0 CC0 register with an output pin enabled on the TC0 W0. I have that connected to a scope and can see the "bad" values on the scope that I am reading from the input TC4 Handler(These are the 5-100 counts I mentioned above).

 

So 2 things I'm looking to optimize/understand:

1.) What can I do to optimize the accuracy and precision of the period value that I'm reading from TC4 CC0 register.

2.) What are my limitations on frequency response with a sweep on the input. I'm looking to vary the input frequency every 40 micro seconds and output that exact input frequency divided by 4.

3.) Is there an example project for something similar to this. I have found a few projects that measure frequency, but not something that outputs that measured frequency.

 

void TC4_Handler(void){ //Read frequency
    
    static uint32_t valueOfPeriod[500];
    static uint32_t valueOfPeriodTest;
    static uint32_t previousValueOfPeriod;
    static uint16_t iterate = 0;
    
    if ((TC4->COUNT32.INTFLAG.bit.MC0 == 1) && (TC4->COUNT32.INTFLAG.bit.ERR== 0)  && (TC4->COUNT32.INTFLAG.bit.OVF== 0))
    {
        
        valueOfPeriod[iterate] = hri_tccount32_read_CC_reg(TC4, 0);
        valueOfPeriodTest = valueOfPeriod[iterate];
        if((valueOfPeriodTest<previousValueOfPeriod-1) || (valueOfPeriodTest>previousValueOfPeriod+1))
        {
            gpio_set_pin_level(LED_EN,0);
            
        }

        iterate++;
        if(iterate>500)
        {
            iterate = 0;
            
        }
     
        PWM_1_WritePeriod(valueOfPeriodTest*4); //This sets the CC register for TC0 to valueOfPeriod/2
    }
    
    
    
    TC4->COUNT16.INTFLAG.bit.MC0 |= 0x01;
    TC4->COUNT16.INTFLAG.bit.MC1 |= 0x01;
    TC4->COUNT16.INTFLAG.bit.ERR |= 0x01;
    TC4->COUNT16.INTFLAG.bit.OVF |= 0x01;
    
}

 

Any assistance would be appreciated. I can provide the initialization information of the timers, event system, or edge trigger if needed.

This topic has a solution.

Kyle

Last Edited: Wed. Jun 29, 2022 - 07:39 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Haven't seen any traffic on here about this, but figured I'd put this on as a resource if anyone else is trying to accomplish this as I work towards a solution:

 

I found this example project that looks like what I'm trying to accomplish:

https://microchipsupport.force.c...

 

I'm going to give it a shot on the SAMC18NA micro that I'm using and see how performant it is and if it will work for my application.

Kyle

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok so after some experimentation and reading I think I found a resolution to this. Main takeaways are:

 

1.) I was reloading the output PWM period register while it was in the middle of a output cycle. This caused a glitching with the PWM that I thought was due to the input not reading the frequency input fast enough. That was not the case.

2.) Using a TCC instead of a TC for PWM improved issue#1 as it's double buffered. This eliminated most glitches, but not all.

3.) The real resolution was to use a interrupt for TCC to only allow a reload of the period register on a match when it was at the end of a PWM cycle. This eliminates all glitches.

 

Doing 2 and 3 allows me to input a frequency and output the same frequency while sweeping from 1kHz to 20kHz at a rate of 1uS with very little phase delay from input to output. I didn't quantify this delay yet, but I can't hear and audible delay from input to output. I haven't tried higher frequencies over 20kHz since I'm working in the audible range and don't need to, but image it would work for much higher frequencies.

 

I'm posting a rough demo project that is working on my custom hardware for anyone that needs to do this in the future.

 

Note the project is all generated with Atmel Start. I didn't do any of the initialization code by hand. I have several additional timers that aren't used and didn't delete them, but they aren't needed I manually commented their initialization out in the auto generated Atmel Start init. I recommend deleting them if you regenerate Atmel Start as they some of their init code conflicts with the 2 timers that are use and will cause the example not to work propely.

Attachment(s): 

Kyle