Reading Duty Cycle with an XMEGA384C3

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

I am running the code for Example 3 in AVR App note 1306 for measuring duty cycle on PC0:

 

https://github.com/Synapseware/xmega-intro/blob/master/avr1306-timers-counters/code/TC_example.c

 

I an injecting a 60Hz signal at 50% duty cycle into PC0 of my XMEGA384C3, and the value I am getting is 0 and 1... I am running at 32MHZ. Cannot figure out why it is not working correctly.

 

The only modification of the code is to enable the 32MHz Oscillator:

 


/* Definition of the CPU clock speed and TC prescaler setting. */
#define F_CPU 32000000UL
#define CPU_PRESCALER 1
#include "avr_compiler.h"
#include "TC_driver.h"
/* Prototyping of functions. */

volatile uint16_t currentDutyCycle;

void Example3( void );

int main( void )
{
	CCP = CCP_IOREG_gc;              // disable register security for oscillator update
	OSC.CTRL = OSC_RC32MEN_bm;       // enable 32MHz oscillator
	while(!(OSC.STATUS & OSC_RC32MRDY_bm)); // wait for oscillator to be ready
	CCP = CCP_IOREG_gc;              // disable register security for clock update
	CLK.CTRL = CLK_SCLKSEL_RC32M_gc; // switch to 32MHz clock
	Example3();


}

/*! \brief This example shows how to configure TCC0 for measurement of Frequency
* and Duty cycle of a signal applied to PC0.
*
* This function implements example 3, "Using Input Capture to Calculate
* Frequency and Duty Cycle of a Signal" from the "Getting Started" section of
* application note AVR1306.
*/
void Example3( void )
{
/* Configure PC0 for input, triggered on both edges. */
PORTC.PIN0CTRL = PORT_ISC_BOTHEDGES_gc;
PORTC.DIRCLR = 0x01;
/* Select PC0 as input to event channel 0. */
EVSYS.CH0MUX = EVSYS_CHMUX_PORTC_PIN0_gc;
/* Configure TCC0 for Input Capture using event channel 2. */
TC0_ConfigInputCapture( &TCC0, TC_EVSEL_CH0_gc );
/* Enable Input "Capture or Compare" channel A. */
TC0_EnableCCChannels( &TCC0, TC0_CCAEN_bm );
/* Clear MSB of PER[H:L] to allow for propagation of edge polarity. */
TC_SetPeriod( &TCC0, 0x7FFF );
/* Start timer by selecting a clock source. */
TC0_ConfigClockSource( &TCC0, TC_CLKSEL_DIV1_gc );
/* Enable CCA interrupt. */
TC0_SetCCAIntLevel( &TCC0, TC_CCAINTLVL_LO_gc );
PMIC.CTRL |= PMIC_LOLVLEN_bm;
sei();
do {
/* Wait while interrupt measure Frequency and Duty cycle. */

	if (currentDutyCycle == 50)
		printf("DUTY CYCLE CORRECT");

} while (1);
}
ISR(TCC0_CCA_vect)
{
static uint32_t frequency;
static uint32_t dutyCycle;
static uint16_t totalPeriod;
static uint16_t highPeriod;
uint16_t thisCapture = TC_GetCaptureA( &TCC0 );
/* Save total period based on rising edge and reset counter. */
if ( thisCapture & 0x8000 ) {
totalPeriod = thisCapture & 0x7FFF;
TC_Restart( &TCC0 );
}
/* Calculate duty cycle based on time from reset and falling edge. */
else {
highPeriod = thisCapture;
}
dutyCycle = ( ( ( highPeriod * 100 ) / totalPeriod ) + dutyCycle ) / 2;
frequency = ( ( ( F_CPU / CPU_PRESCALER ) / totalPeriod ) + frequency ) / 2;

currentDutyCycle = dutyCycle;
}

 
Last Edited: Fri. Oct 28, 2016 - 07:43 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Change:

OSC.CTRL = OSC_RC32MEN_bm;       // enable 32MHz oscillator

To:

OSC.CTRL |= OSC_RC32MEN_bm;       // enable 32MHz oscillator

And test again.

Ozhan KD
Knowledge is POWER

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

electronic.designer wrote:

And test again.

 

That probably won't make any difference since:

 

But you are right, OP should be using "|=" instead of "="  to enable the RC32M.

 

Zacharoni16, the OSC.CTRL is not CCP-protected; the CLK.CTRL is.  Most of these old application notes exist as ASF Example Projects, although not necessarily for the specific MCU you are using.  You can create an ASF project for the X384C3, use the ASF Wizard to add the appropriate ASF modules, and then copy the source from an example project for a different MCU.

 

 

Greg Muth

Portland, OR, US

Xplained/Pro/Mini Boards mostly

 

Make Xmega Great Again!

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I changed the OSC.CTRL as you both suggested. It seems like I am getting either a 0 or 1 for the duty cycle. I tried making an ASF project and it did not change anything, I also cannot get it to work with even default 2MHz Clock. I am using the XMEGA384C3 on an XMEGA C3 XPLAINED Dev board. As far as I can tell, Atmel did not connect anything to the PC0 pin that could affect it.

 

I know my signal is getting to the pin, I have a scope on it, and the amplitude of the signal is around 4VDC @ 60Hz (Not fast at all).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just a guess, but with a faster clock, you will need to change the timer pre-scaler so the time period (~16.66mS) your trying to measure fits with in its range. 

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

Well at 2Mhz to overflow the timer it would take around 32mS  2Mhz timer clock, since (1/2000000)*65535=32ms, vs 1/60 Hz=16ms.

 

I'm doing all my testing with the 2Mhz clock right now, and it is really acting weird. I am printing out the duty Cycle, TotalPeriod, and HighPeriod to UART:

This is sweep from 41% Duty Cycle to 49% Duty Cycle (Some duty cycles are read correctly then some are way wrong (Low), seems to go back and forth like every other duty cycle, 40% , 44%, 48% read correctly):

 

19 1355 47460
19 1354 47462
19 1354 47458
19 1350 47462
19 1355 47457
19 1351 47456
19 1346 47455
20 1186 47458
40 1345 47795
44 1350 47800
44 1352 47802
44 1354 47797
44 1356 47801
44 1352 47798
44 1350 47796
44 1349 47799
44 1351 47797
44 1349 47800
44 1355 47800
44 1355 47802
44 1356 47799
44 1350 47799
44 1351 47797
44 1349 47797
44 1347 47797
44 1346 47797
44 1354 47800
44 1351 47798
44 1348 47798
44 1349 47797
44 1350 47799
44 1347 47797
44 1347 47795
44 1346 47798
44 1347 47798
44 1350 47797
44 1347 47796
44 1347 47796
44 1348 47798
44 1346 47797
44 1340 47798
44 1348 47798
44 1344 47797
44 1340 47792
44 1344 47796
44 1344 47795
44 1342 47794
44 1344 47796
44 1342 47794
44 1346 47796
44 1349 47800
44 1351 47795
44 1344 47795
44 1346 47796
44 1350 47799
44 1346 47796
44 1343 47795
44 1346 47796
44 1347 47797
44 1349 47799
44 1351 47799
44 1354 47800
44 1351 47801
44 1354 47799
44 1352 47799
44 1350 47798
44 1348 47797
44 1347 47796
44 1346 47797
44 1347 47797
44 1348 47796
44 1349 47799
44 1353 47800
44 1348 47795
44 1348 47799
44 1350 47795
44 1348 47795
44 1348 47798
44 1351 47800
44 1351 47797
44 1352 47801
44 1355 47802
44 1353 47797
44 1348 47796
44 1347 47797
44 1346 47797
44 1344 47797
44 1350 47797
44 1346 47796
44 1348 47798
44 1343 47795
44 1344 47794
44 1340 47793
44 1342 47795
44 1340 47796
44 1342 47794
44 1340 47794
44 1339 47793
44 1339 47794
44 1343 47797
44 1348 47797
44 1347 47799
44 1351 47799
44 1352 47797
44 1346 47795
44 1347 47799
44 1350 47795
44 1347 47794
27 1326 48116
23 1347 48138
21 1340 48136
21 1342 48136
21 1343 48136
21 1343 48133
21 1346 48136
21 1349 48140
21 1345 48135
21 1344 48138
21 1344 48137
21 1343 48139
21 1344 48137
21 1348 48142
21 1348 48140
21 1347 48141
21 1349 48140
21 1351 48139
21 1351 48139
21 1349 48139
21 1349 48139
21 1351 48143
21 1352 48139
21 1350 48140
21 1349 48141
21 1355 48144
21 1348 48136
21 1345 48138
21 1349 48142
21 1353 48141
21 1353 48140
21 1351 48143
32 1269 48388
43 1260 48480
46 1351 48480
46 1351 48484
46 1356 48483
46 1351 48480
46 1348 48482
46 1350 48479
46 1351 48483
46 1353 48483
46 1353 48479
46 1355 48482
46 1352 48479
46 1351 48483
46 1354 48481
46 1352 48482
46 1349 48480
46 1350 48480
46 1350 48479
46 1350 48481
46 1352 48479
46 1347 48480
46 1351 48480
46 1342 48478
46 1340 48475
46 1340 48480
46 1345 48479
46 1347 48477
46 1352 48481
46 1349 48481
46 1342 48476
46 1342 48478
46 1341 48473
46 1335 48476
46 1342 48478
46 1341 48476
46 1344 48477
46 1343 48478
46 1346 48477
46 1345 48480
46 1345 48478
46 1348 48480
46 1351 48479
46 1347 48479
46 1346 48475
46 1341 48479
46 1348 48482
46 1348 48480
46 1346 48480
46 1348 48478
46 1348 48477
46 1345 48479
46 1349 48480
46 1348 48479
46 1346 48478
46 1345 48478
46 1344 48477
46 1345 48481
46 1344 48477
46 1347 48478
46 1346 48477
46 1345 48478
46 1343 48478
46 1347 48477
46 1352 48483
46 1353 48480
46 1350 48477
46 1344 48480
46 1349 48477
46 1349 48482
Serial port COM6 closed

 

 

 

Last Edited: Mon. Oct 31, 2016 - 09:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I know my signal is getting to the pin, I have a scope on it, and the amplitude of the signal is around 4VDC @ 60Hz

 

Last time I checked 4VDC is greater than (3.3 + 0.5)VDC.  From the 384C3 datasheet:

 

 

Greg Muth

Portland, OR, US

Xplained/Pro/Mini Boards mostly

 

Make Xmega Great Again!

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I lowered the voltage down to 3.1VDC no effect, but I finally got it working, Albeit it is reading Frequency and Duty cycle are off by 1-2. I can't understand where the +1-2 is coming from: My signal is high and goes low for the % Duty Cycle duration: 

The code is now: 

 

uint16_t thisCapture = TC_GetCaptureA( &TCC0 ); 

/* Calculate duty cycle based on time from reset and falling edge. */
if (thisCapture & 0x8000)
{
totalPeriod = thisCapture & 0x8000;
TC_Restart( &TCC0 ); 

}
/* Save total period based on rising edge and reset counter. */ 

else
{ 

highPeriod = thisCapture; 

}
#define CPU_PRESCALER 1
currentDutyCycle = ( ( ( highPeriod * 100UL) / (totalPeriod) ) + currentDutyCycle ) / 2;

 

Reading an 60Hz 80% duty cycle signal:

 

Duty cycle is 2% high, Frequency is +1Hz high. I'm thinking a 0x7FFF PER for TCC0 @ 2Mhz isn't long enough period to measure the signal ?

82% 32768TP: 27167HP: 61 Hz 
82% 32768TP: 27168HP: 61 Hz 
82% 32768TP: 27169HP: 61 Hz 
82% 32768TP: 27177HP: 61 Hz 
82% 32768TP: 27169HP: 61 Hz 
82% 32768TP: 27170HP: 61 Hz 
82% 32768TP: 27167HP: 61 Hz 

Last Edited: Tue. Nov 1, 2016 - 05:44 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
TC_Restart( &TCC0 );

How many clock cycles does this take?  Could this be why your seeing slippage? 

Instead just record the TC count and take the diff from the previous trigger, no need to restart the timer.

 

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the suggestion!

I replaced it with this and get the same results, actually seems to be off by more (2-3):

 

static uint16_t trig1 = 0;

	uint16_t thisCapture = TC_GetCaptureA( &TCC0 );

	/* Calculate duty cycle based on time from reset and falling edge. */
	if (thisCapture & 0x8000)
	{
					trig1 = TCC0.CNT; // Record the count of first edge
					totalPeriod = thisCapture;
					//TC_Restart( &TCC0 );

	}
	/*  Save total period based on rising edge and reset counter. */

	else
	{
		TCC0.CNT -= trig1; // Adjust the count
		highPeriod = thisCapture;

	}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Something seems off, as soon as I change the input frequency to anything else besides 60 Hz it does not measure it correctly