Xmega 128A3U - Frequency sensing (input capture)

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

As said in a different topic I wanted to experiment with frequency sensing of a FAN pwm signal comming from a motherboard (input capture) on a Xmega.

At the moment I am doing so and I am running against some problems which I cannot figure out by myself.

 

As a start I used 2 sources of information:

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

and

http://www.dolman-wim.nl/xmega/b... (paragraph 23.18)

 

And of course the information from the specific FAN:

http://media.digikey.com/pdf/Dat...

 

Furthermore I created a PWM LED which I could run at 0,5Hz (to test with variable PW).

My problem is that when I run the PWM led with 0,5Hz and lets say 80% this is detected and shown in my USART output. Same for 24k Hz and 80%.

I then get:

Current Frequency: 24060.1503 Hz                                                
Current PulseWidth: 80 %                                                        
Current Frequency: 24060.1503 Hz                                                
Current PulseWidth: 80 %                                                        
Current Frequency: 24060.1503 Hz

The code to generate the PWM:

#define Freq_Val 24000.0F	// Required frequency
#define PW_Val 80			// Pulse Width (percent)

#define ICPreScale 1		// Input Capture  Pre-scaler 1/2/4/8/64/256/1024
#define OCPreScale 1		// Output Control Pre-scaler 1/2/4/8/64/256/1024

uint32_t period;            // Changed to 32-bits
uint32_t pulseWidth;        // Changed to 32-bits
uint16_t FreqVal;
uint16_t PWVal;

float frequency;
void init_pwm(void)
{
	PORTD.DIRSET  = PIN0_bm;
	TCD0.CTRLB    = TC0_CCAEN_bm | TC_WGMODE_SINGLESLOPE_gc;
	
	switch ( OCPreScale ) {
		
		case  1:
		TCD0.CTRLA    = TC_CLKSEL_DIV1_gc;
		break;

		case  2:
		TCD0.CTRLA     = TC_CLKSEL_DIV2_gc;
		break;

		case 4:
		TCD0.CTRLA     = TC_CLKSEL_DIV4_gc;
		break;
		
		case 8:
		TCD0.CTRLA     = TC_CLKSEL_DIV8_gc;
		break;
		
		case 64:
		TCD0.CTRLA     = TC_CLKSEL_DIV64_gc;
		break;
		
		case 256:
		TCD0.CTRLA     = TC_CLKSEL_DIV256_gc;
		break;
		
		case 1024:
		TCD0.CTRLA     = TC_CLKSEL_DIV1024_gc;
		break;
	}
	
	FreqVal = (F_CPU/(Freq_Val*OCPreScale))-1;					// Page 173 Xmega AU manual
	PWVal = ((PW_Val*(uint32_t)FreqVal)/100);
	TCD0.PER      = FreqVal;
	TCD0.CCA      = PWVal;
}

 

Then my code to init the freq and PW:

void init_inputFREQcapture(void)
{
	PORTD.DIRCLR   = PIN4_bm;
	PORTD.PIN4CTRL = PORT_OPC_PULLDOWN_gc | PORT_ISC_RISING_gc;
	EVSYS.CH0MUX   = EVSYS_CHMUX_PORTD_PIN4_gc;
	EVSYS.CH0CTRL  = EVSYS_DIGFILT_8SAMPLES_gc;
	TCC0.CTRLD     = TC_EVACT_FRQ_gc | TC_EVSEL_CH0_gc;
	TCC0.CTRLB     = TC0_CCAEN_bm | TC_WGMODE_NORMAL_gc;
	
	switch ( ICPreScale ) {
		
		case  1:
			TCC0.CTRLA     = TC_CLKSEL_DIV1_gc;
		break;

		case  2:
			TCC0.CTRLA     = TC_CLKSEL_DIV2_gc;
		break;

		case 4:
			TCC0.CTRLA     = TC_CLKSEL_DIV4_gc;		
			break;
		
		case 8:
			TCC0.CTRLA     = TC_CLKSEL_DIV8_gc;
			break;
			
		case 64:
			TCC0.CTRLA     = TC_CLKSEL_DIV64_gc;
			break;
			
		case 256:
			TCC0.CTRLA     = TC_CLKSEL_DIV256_gc;
			break;
			
		case 1024:
			TCC0.CTRLA     = TC_CLKSEL_DIV1024_gc;
			break;
	}
}

void init_inputPWcapture(void)
{
	PORTD.DIRCLR   = PIN5_bm;
	PORTD.PIN4CTRL = PORT_OPC_PULLDOWN_gc | PORT_ISC_RISING_gc;
	EVSYS.CH1MUX   = EVSYS_CHMUX_PORTD_PIN5_gc;
	EVSYS.CH1CTRL  = EVSYS_DIGFILT_8SAMPLES_gc;
	TCC1.CTRLD     = TC_EVACT_PW_gc | TC_EVSEL_CH1_gc;
	TCC1.CTRLB     = TC1_CCAEN_bm | TC_WGMODE_NORMAL_gc;
	
	switch ( ICPreScale ) {
			
		case  1:
		TCC1.CTRLA     = TC_CLKSEL_DIV1_gc;
		break;

		case  2:
		TCC1.CTRLA     = TC_CLKSEL_DIV2_gc;
		break;

		case 4:
		TCC1.CTRLA     = TC_CLKSEL_DIV4_gc;
		break;
			
		case 8:
		TCC1.CTRLA     = TC_CLKSEL_DIV8_gc;
		break;
			
		case 64:
		TCC1.CTRLA     = TC_CLKSEL_DIV64_gc;
		break;
			
		case 256:
		TCC1.CTRLA     = TC_CLKSEL_DIV256_gc;
		break;
			
		case 1024:
		TCC1.CTRLA     = TC_CLKSEL_DIV1024_gc;
		break;
	}
}

And in my main loop:

while(1)
	{
		// Current period & pulse width
		period = TCC0.CCA;
		pulseWidth = TCC1.CCA;

		// Calculate
		frequency = (F_CPU/((float)period*ICPreScale));

		// Frequency from last capture.
		uint16_t d1 = frequency;            // Get the integer part (678).
		float f2 = frequency - d1;     // Get fractional part (678.0123 - 678 = 0.0123).
		int d2 = trunc(f2 * 10000);   // Turn into integer (123).
		sprintf (str, "%d.%04d", d1, d2);
		//sprintf(str,"%u", frequency);
		dbgPutStr("Current Frequency: ");
		dbgPutStr(str);
		dbgPutStr(" Hz\r\n");
		
		// PulseWidth from last capture.
		sprintf(str,"%lu", (((pulseWidth+1)*100)/period));
		dbgPutStr("Current PulseWidth: ");
		dbgPutStr(str);
		dbgPutStr(" %\r\n");
		
		_delay_ms( BLINK_DELAY_MS ) ; // wait.
	}

The result when I am trying to get the frequency from my FAN PWM:

Current Frequency: 1252.4461 Hz                                                 
Current PulseWidth: 4 %                                                         
Current Frequency: 1204.1845 Hz                                                 
Current PulseWidth: 4 %                                                         
Current Frequency: 1203.1884 Hz                                                 
Current PulseWidth: 4 %                                                         
Current Frequency: 1250.7817 Hz                                                 
Current PulseWidth: 4 %                                                         
Current Frequency: 1244.3614 Hz                                                 
Current PulseWidth: 4 %                                                         
Current Frequency: 1990.7926 Hz 

These are with the same settings as blinking the led...

 

I have read the manual multiple times, but it might be something with the PWM signal type. But at the moment I am shooting blind. Hope someone can give me a tip what to look for.

Thank you all in advance.

Last Edited: Thu. Apr 23, 2015 - 04:22 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think you need to look at it with a scope to check what is actually happening in your input pins.

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

Last couple of days I made some progress on my investigation.

 

What I did was programming my atmega 644 with fast PWM, I then feeded that signal through a led which started to blink again 0.5Hz. Then I changed the frequency to 24kHz and hooked up my XMega to read the frequency and PW. It read both in a correct way. Value was 1kHz off, hard set 24kHz in my atmega. But for functionality of this test not a problem.

Current Frequency: 22972.0019 Hz                                                
Current PulseWidth: 30 % 

Then hooked up to the fan, again NO result. FAN was still an aircraft engine.

Besides testing my code on an other fan (computer 4 wire fan, other than these I have), I have no clue.

This is because:

- ATmega did test with 4,5V output

- XMega did test with 3V output

- Both where able to blink a led

- Both showed up correctly in my Xmega reading program (freq and PW)

 

Furthermore I did connect the test with the atmega direct to the FAN (as it was described on the net), the xmega I tested with a zener to limit to 3,3V.

As per described above I have tested with an open collector set-up (at/Xmega to base of BC548 and collector to the PWM cable of the fan and the emittor to ground)

All grounds are common.

 

At this moment I can only suspect something is wrong with my fan.... Though I have no clue why. Furthermore I find it strange that I can read the signal form my atmega and not fron the mainboard. 

 

The fan is an: Dell CHHRN-A00 - 9G2L (Delta PFC0612DE)

I think it is equal to: http://media.digikey.com/pdf/Dat...

 

Could you guys take a look at what I am doing wrong or what I can test. I do not have a scope so looking at the output form my mainboard is not possible and I do not have a spare soundcard

 

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

I think it is time you bought yourself a scope so you can see what the input actually looks like otherwise you are making a lot of assumptions.

 

David

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

Well you might be right on that one, but that is not done at this moment.

 

Furthermore I had a bright moment and remembered there might be a stock cooler from intel on my Attic. And I was right.

It has also 4 wire and these specs:

 

Model No.: E97378-001
CPU Type Socket: LGA 1155/1156
Fan Dimensions (mm): 92*92*32
Fan Speed (RPM): 1200rpm -2800rpm
Fan Directions: 4
Pin of the fan: 4
PWM function: Y
Acoustical Noise (dBA): 22
Rated Voltage (VDC): : 12
Rated Current (A): : 0.2
Bearing Type: Hydraumatic
Heat Sink Masterial: Aluminum + Copper insert
Heat Sink Dimensions (mm): 87*87*19
Weight of cooler: 280g

So hooked it up and I was able to control the PWM as supposed to. So I build back everything to the XMega and flashed the Atmega with my Tach signal reader.

This is showing the rpm drop or raise when I program a different % in the Xmega. So far this proves that everything should work on a regular PC fan.

Which leaves me the question if the Delta from my server which I am trying to control is a regular PC fan, might it be an industrial edition which is different in control (different control circuit).

Since I am not E engineer could you guys advice:

 

This is the small schematic which is in the PDF concerning PWM control:

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

I would start by creating PWM on one Timer.

And Input Capture with a different Timer.

 

Neither of these 'jobs' take more than a few lines to configure.

Since you are using relatively low frequencies,  you could even poll the PWM pin in software.   i.e. forget about Input Capture.

 

Note that you could do exactly the same with a Mega or even a Tiny.

 

Once you are happy with your measurement and display,   you can try it out with your real FAN hardware.

If you find some anomalies,    you get out the oscilloscope to see how clean your input signal is.     (or you insert a l-p filter before you start)

 

David.

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

Hi David, thanks for your reply, but I think I already did that?

I have indeed code to create a pwm and code to read pwm and code to read tach signal.

 

Where tach signal read on the delta fan works as it supposed to however PWM the delta fan is impossible for me. PWM the intel stock fan with the same pwm works like a charm.

Btw I did start with the led on 0,5Hz.

 

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

Okey, last couple of days I had some time to experiment.

I finished with investigating another type of fan so I was self confident I should be able to solve this one as well... Right...

 

So started with again building the same setup:

 

This is the color coding according a PFC0612DE-F00

Red = +

Black = -

Yellow = PWM

Blue = TACH

 

AND this does NOT work. So I searched the net. Coz I had no clue, then I stumbled on a forum which clearly marked this fan to be having a different color coding indecision

Red = +

Black = -

Yellow = PWM -> TACH

Blue = TACH -> PWM

 

Hooked the fan up in the new config AND bingo, everything works. Downside the fan was even in lowest PWM still too loud. But now I know it is working like the other ones I had.

Just ordered some new ones really quiet which are going to run at a too low speed for the server I am placing them int, so too adjust this I will use the DDS tach generator to pump the RPM Tach up.

 

I will further on continue in that topic, since this investigation is done for now.