UC3C Timer/Counter Issues

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

Hi everyone, I'm quite new to AVR32 development, having mostly worked with the Megas. But now I find myself having to support a product range based on the AVR32, with an existing codebase. I've done a lot of searching and reading through the datasheet, but haven't been able to come up with a solution to an issue I'm having, so here goes:

 

Specifically, I'm working on the UC3C1512, in the TQFP-100 package. I'm developing in Atmel Studio 6.2.1563 SP2 on Windows 10 and using the Atmel-ICE JTAG debugger.

 

I have a project now where I need two frequency/pulse counter inputs - lets call them FREQ_IN1 and FREQ_IN2:

  • Existing hardware has these inputs connected to pin 99 and pin 55 respectively.
  • The existing codebase appears to have support for both, but I can only get FREQ_IN1 working.
  • FREQ_IN1 works beautifully on TC1 i/o line A1, setup to give interrupts when RB is loaded (on every falling-edge of the input).
  • Although the code for FREQ_IN2 is almost identical, I can't get it to do anything more than give me timer overflow interrupts. I never get an RB load interrupt for FREQ_IN2.
  • I have verified with a scope that there is a nice square-wave reaching the input on pin 55.

 

Unfortunately, the existing code structure is fairly layered and complex, but below is all the code that I can find related to the TC module.

 

After initial startup, there is a FreqInputOpen() function callled to initialise the frequency inputs:

 

#include "gpio.h"
#include "intc.h"
#include "uc3c.h"

uint4 *CaptureInterruptDisable[MAX_FREQ_INPUTS] =
{
	(uint4*) &AVR32_TC1.channel[1].idr,
	(uint4*) &AVR32_TC0.channel[1].idr,
};

uint4 *CaptureControl[MAX_FREQ_INPUTS] =
{
	(uint4*) &AVR32_TC1.channel[1].ccr,
	(uint4*) &AVR32_TC0.channel[1].ccr,
};

#define FRQ_INP_CHAN_CLOCK_DIS 0x00000002   // Disable the input capture clock (CLKDIS = 1)
#define FRQ_INPUT_NO_INTERRUPT 0x000000FF // Disable all interrupts in the channel


void FreqInputOpen(void)
{
        //Disable everything on startup. Will be enabled later on by FreqInputEnable().        

	*CaptureInterruptDisable[FREQ_IN1] = FRQ_INPUT_NO_INTERRUPT;
	*CaptureInterruptDisable[FREQ_IN2] = FRQ_INPUT_NO_INTERRUPT;
	*CaptureControl[FREQ_IN1] = FRQ_INP_CHAN_CLOCK_DIS;
	*CaptureControl[FREQ_IN2] = FRQ_INP_CHAN_CLOCK_DIS;
	
	//Local variables for each input are also initalised here (eg. frequency in Hz, total number of pulses captured, etc)
}

Then, I call FreqInputEnable(E_FreqInput in_freq_input) to enable one or both inputs. Note my comments regarding the PIN and FUNCTION macros from the uc3c1512c.h header... I can't help feeling there may be an issue here, but I don't know what it could be. I can't find any documentation explaining why these macros are defined the way they are.

const gpio_map_t FreqInpMap =
{
	{AVR32_TC1_A1_1_PIN,	AVR32_TC1_A1_1_FUNCTION	},	// TC1 - A1, IN_FREQ1. This PIN macro evaluates to 34, but somehow works even though FREQ_IN1 is on pin 99.
	{AVR32_TC0_B1_2_PIN,	AVR32_TC0_B1_2_FUNCTION	},	// TC0 - B1, IN_FREQ2. This PIN macro evaluates to 68, which doesn't work. (FREQ_IN2 is on pin 55)
	
        //Also tried using AVR32_TC0_B1_PIN for FREQ_IN2 because this macro evaluates to 55 (FREQ_IN2 is on pin 55), but this didn't work any better (or any worse).
        /* The FUNCTION macros seem to be the GPIO MUX values required for the corresponding PIN macro. So why does AVR32_TC0_B1_FUNCTION evaluate to 0, when the datasheet 
              shows the GPIO MUX value should be 3 in order to route TC0-B1 to pin 55? */
};

uint4 *CaptureStatusRegister[MAX_FREQ_INPUTS] =
{
	(uint4*) &AVR32_TC1.channel[1].sr,
	(uint4*) &AVR32_TC0.channel[1].sr,
};

uint4 *CaptureMode[MAX_FREQ_INPUTS] = 
{
	(uint4*) &AVR32_TC1.channel[1].cmr,
	(uint4*) &AVR32_TC0.channel[1].cmr,
};

uint4 *CaptureInterruptEnable[MAX_FREQ_INPUTS] =
{
	(uint4*) &AVR32_TC1.channel[1].ier,
	(uint4*) &AVR32_TC0.channel[1].ier,
};

bool1 FreqInputEnable(E_FreqInput in_freq_input)
{
	uint4 temp;
	bool1 enable_success_b1 = FALSE;
	uint4 capture_config_u4 = 0;
	
	if (in_freq_input >= MAX_FREQ_INPUTS)
	{
		return enable_success_b1; //Invalid input number, so return input enable failed
	}
	
	/* Assign and enable GPIO pins to the input capture function */
	if(gpio_enable_module(&FreqInpMap[in_freq_input], 1 ) != GPIO_SUCCESS)
	{
		return enable_success_b1; //Failed to enable GPIO pin in the mode required, so return input enable failed
	}
	
	cpu_irq_disable_level(0);
	temp = *CaptureStatusRegister[in_freq_input];	// Acknowledge (but ignore) any pending interrupts
	// External trigger Freq input 1 with input A, freq input 2 with input B
	if (in_freq_input == FREQ_IN1)
	{
		capture_config_u4 = FRQ_INPUT_CAPT_PRESET;
		// Input Capture 1, xtal/128, external trigger with input A, external trigger on both edges
		capture_config_u4 |= (FRQ_INPUT_CLK_SOURCE | FRQ_INPUT_EXT_TRIG_A);
		// Register A loads with the rising edge of the input and Register B with the falling edge
		capture_config_u4 |= (FRQ_INPUT_RA_CAPT_RISE | FRQ_INPUT_RB_CAPT_FALL);
		*CaptureMode[in_freq_input] = capture_config_u4;
		*CaptureInterruptEnable[in_freq_input] = FRQ_INPUT_OVFLW_INTERPT | FRQ_INPUT_LOAD_RB_INT;	//Interrupt when Register B is loaded or counter overflow
		// Register the frequency interrupt handler with the interrupt controller
		INTC_register_interrupt(&FreqInputInterrupt1, FREQ_INP1_IRQ_GRP, FREQ_INP1_IRQ_LN);
	}
	else
	{
		capture_config_u4 = FRQ_INPUT_CAPT_PRESET;
		// Input Capture 1, xtal/128, external trigger with input B, external trigger on both edges
		capture_config_u4 |= (FRQ_INPUT_CLK_SOURCE | FRQ_INPUT_EXT_TRIG_B);
		// Register A loads with the rising edge of the input and Register B with the falling edge
		capture_config_u4 |= (FRQ_INPUT_RA_CAPT_RISE | FRQ_INPUT_RB_CAPT_FALL);
		*CaptureMode[in_freq_input] = capture_config_u4;
		*CaptureInterruptEnable[in_freq_input] = FRQ_INPUT_OVFLW_INTERPT | FRQ_INPUT_LOAD_RB_INT;	//Interrupt when Register B is loaded or counter overflow
		// Register the frequency interrupt handler in the interrupt controller
		INTC_register_interrupt(&FreqInputInterrupt2, FREQ_INP2_IRQ_GRP, FREQ_INP2_IRQ_LN);
	}
	*CaptureControl[in_freq_input] = FRQ_INP_RESET_CHANNEL + FRQ_INP_CHAN_CLOCK_ENBL;
	cpu_irq_enable_level(0);
	
	//Local variables are also re-zeroed here (Hz, total number of pulses etc)
	
	enable_success_b1 = TRUE; //If we got this far, then input enable succeeded

	return (enable_success_b1); //Return success
}

And then everything should be done by the respective interrupt handler - FreqInputInterrupt1() or FreqInputInterrupt2(). Both interrupt handlers are identical except for where indicated by the comments:

#define FRQ_INPUT_OVFLW_INTERPT	0x00000001	// Enable the counter overflow interrupt
#define FRQ_INPUT_LOAD_RB_INT	0x00000040	// Enable the interrupt when RB is loaded


__attribute__((__interrupt__))
void FreqInputInterrupt2(void)
{
	volatile uint4 status_register_u4;
	volatile sint4 counter_s4;
	
	status_register_u4 = AVR32_TC0.channel[1].sr; //FREQ_IN1 uses AVR32_TC1.channel[1].sr here instead, because FREQ_IN1 is on pin 99 (TC1-A1)

	// Counter overflow interrupt?
	if (status_register_u4 & FRQ_INPUT_OVFLW_INTERPT)
	{
		//Update local overflow count variable. This works great.
	}
	
	// RB load interrupt?
	if (status_register_u4 & FRQ_INPUT_LOAD_RB_INT)
	{
	    //When using FREQ_IN1, we get RB_INT events as expected (not in this interrupt handler, but in the corresponding FreqInputInterrupt1() ).
	    //When using FREQ_IN2, we never get an RB_INT event, so this code never runs.
	    
	    //No idea why only the lower byte is used here... what if there's valid data in the high byte?
		counter_s4 = (AVR32_TC0.channel[1].rb & 0x0000FFFF); //Get the lower byte of the counter value that was stored in RB when the trigger occurred. 
        
        //Update local variables (Hz, total number of edges, etc)
        //Zero local overflow count variable
	}
}

To recap - after all that, FREQ_IN1 works great. FREQ_IN2 gives me plenty of TC overflow interrupts, and with the debugger I can see the CV changing - but I never get any RB load interrupts for FREQ_IN2.

 

Sorry for such a long first post... hopefully someone can help me out or point in the right direction :)

 

This topic has a solution.
Last Edited: Thu. Jan 25, 2018 - 02:59 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hmm... 50 views with no reply :(

 

Maybe you all thought simply TL;DR? My first post was definitely quite a wall of text! Or maybe UC3 just isn't used by many?

 

Anyway, for anyone interested, it seems that my distrust of the macros in "uc3c1512c.h" was unfounded. The PIN definitions trace back to line number 1758, where each "PAD" or GPIO pin is mapped to an index value between 0 (PA0) and 126 (PD30).

 

Back to my main problem (not getting any RB interrupts on TC0), this is my current thinking:

  • I'm getting TC0 CV overflow interrupts and I can see that the CV registers are the only ones changing. So that leads me to think that the problem is related to either pin setup (GPIO multiplexing, pin direction setting, etc) or peripheral setup (TC0, triggering, capture mode, etc). Or maybe both.
  • TC1 is working fine and the code for TC0 is almost identical... maybe too close. i.e. maybe the original authors did a copy and paste from TC1 and forgot to make the changes necessary for TC0. I will check the datasheet again and see I've missed anything in my previous searches.
  • As I'm unfamiliar with AVR32, I'm not 100% sure that the gpio_enable_module function does everything required to setup the pin and the GPIO function. This would fit with what I'm seeing (CV going up and overflowing, but no capture events or register changes). Maybe TC1 is working because it has some extra setup code somewhere that I haven't found yet?

 

I'll update if I find anything....

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

ConnectSaucer wrote:
50 views with no reply

Sadly, that's the way it is with AVR32 - VERY few people use them, and they (appear to) have no future.

See: https://www.avrfreaks.net/comment...

 

ConnectSaucer wrote:
a product range based on the AVR32, with an existing codebase

Probably worth starting to think about the long-term support for that product range ...

 

EDIT

 

See also: https://www.avrfreaks.net/comment...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Tue. Jan 23, 2018 - 08:47 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The 'no reply' scenario can also be caused by people not finding/seeing the problem, or people only checking-in to the forum occasionally, or .....


The ASF gpio_enable_module() routine calls gpio_enable_module_pin() which connects a line from an internal-module to a physical-pin and disconnects the internal GPIO from that pin.
(if the internal GPIO module is in control you will need to configure it to define direction/pullup/etc., otherwise the multiplexed module will determine what happens to the pin.
(see the block-diagram in the GPIO section)

Your comment

Quote:
So why does AVR32_TC0_B1_FUNCTION evaluate to 0, when the datasheet shows the GPIO MUX value should be 3 in order to route TC0-B1 to pin 55?
is correct about the GPIO mux value., ie the correct value is 3 to connect TC0-B1 to physical-pin 55.
I have never fully understood the naming-convention used by the ASF for the multiplexing function-values., I find it very confusing and it is much simpler and more understandable to just use the actual multiplexing value (0,1,2,...).
TC0 B1 can be connected to one of 2 pins and the ASF has 2 definitions for the pin-multplexing ;
AVR32_TC0_B1_FUNCTION (which is 0 and is applicable to GPIO-pin 55 which is physical-pin 46)
AVR32_TC0_B1_2_FUNCTION (which is 3 and is applicable to GPIO-pin 68 which is physical-pin 55)

Last Edited: Wed. Jan 24, 2018 - 12:06 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes awneil, a cold shiver goes down my spine whenever I think of the effort that will be required to move 20 or so products over to a new processor/architecture. And I'm the only engineer here :(

 

Mikech - thanks for confirming my thoughts with regards to gpio_enable_module() and the pin multiplexing macros. I now see that the "GPIO pin" numbering is not the same as the physical pin number. Still, I agree with you that the multiplexing function values in those macros make no sense! I'm sure it's been said before, but the ASF just seems weird in some places!

 

I actually managed to solve my TC issue last night... I'll post the solution seperately below.

 

 

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

So for anyone following along, or in the future; here's the solution.

 

On my 3rd or 4th read of the TC section in the datasheet, I spotted the following:

"Registers A and B (RA and RB) are used as capture registers. This means that they can be loaded with the counter value when a programmable event occurs on the signal TIOA." [emphasis added]

And sure enough, the "Capture Mode" block diagram shows connections from TIOA to RA and RB and no connection from TIOB.

 

But hang-on, the pulse/frequency input on our product's PCB is connected to TC0-B1 (TIOB on TC0, channel 1)! So of course I'm never going to get an RB load interrupt, because the input is on the wrong TIO and RB will never get loaded! It looks like the engineers who did the original design and laid out the PCB also missed that one line in the datasheet, because they clearly intended to use TIOB as a pulsed input.

 

So:

  • I soldered a jumper wire over to TC0-A2 (TIOA on TC0, channel 2). On my PCB this was the only pin that I could multiplex a TIOA signal to, which didn't already have some other important function connected to it. Physical pin 56 on the TQFP-100 package.
  • Speaking of multiplexing, I changed over my GPIO mux macros to AVR32_TC0_A2_3_PIN and AVR32_TC0_A2_3_FUNCTION to connect TIOA to this pin.
  • Then I updated all the code to use the correct register offsets for the channel 2 registers (CMR, CCR, SR, IER, IDR, RA and RB) .
  • Lastly, the interrupt group needed to be updated from TC0 channel 1 to channel 2 (AVR32_TC0_IRQ1 to AVR32_TC0_IRQ2).
  • Recompile and run... Lo and behold, I start getting RB load interrupts.

 

Happy days :)

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

ConnectSaucer wrote:
the effort that will be required to move 20 or so products over to a new processor/architecture

Hopefully, it would get easier as you go along ... ?

 

 And I'm the only engineer here 

On the positive side, does that mean Job security ... ?

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

Hopefully, it would get easier as you go along ... ?

 

awneil wrote:

On the positive side, does that mean Job security ... ?

 

Haha, yes and yes :)

 

It would definitely keep me interested and be a great learning opportunity for me too!

Last Edited: Mon. Jan 29, 2018 - 02:32 AM