Artain
Posts: 3
Joined: Wed Jul 31, 2019 7:41 pm

Re: 5V 4-pin Noctua A4X10 on Raspberry Pi

Wed Jul 31, 2019 8:33 pm

First of all I'm a Software engineer not a electrical one but this stuff is my hobby so here it goes.

I had the same problem. I bought a Noctua NF-A4X10 5V-PWM the one with the 4 pins. I then checked a few forums and watched a bunch of YT videos but nothing really did what I wanted to do.
Of course I could let the fan run at 100% because its really silent or i could buy a control unit. But I love automation so it has to be run by the pi itself. I run also in a few problems with my pi because I'm usually building stuff with ESPs. After 2 Days of failure I decided I need a oscilloscope. The day it arrived everything went clear.
First of all it is really hard to get a nice rectangle curve even with Mosfets. But after re-reading the Noctua spec doc I noticed:
There are no special requirements for the circuits that generate the PWM signal. However, Noctua recommends to use a CMOS-inverter type circuit as shown below. This is the very circuit that is used for GPIO pins inside most micro-controllers.
So i checked what the PWM signal is the raspi can generate itself and its better then anything I could create with transistors and I don't need generate a duty signal for the mosfets.
I just don't have a PC output on my oscilloscope or I could show you what I mean.
Anyway long story short I created a python script which does exactly what I and I think you also want it to do. But first here is how I connected the fan to my Pi
Image

Note two things, first you need to connect it to a PWM capable pin and second you need to use the resistor as its mentioned in the spec pdf.
As you can see you don't need any transistor for you PWM signal or curve. You could add a diode between raspi and fan but I don't think its necessary at with a noctua nor at these currents,...
And here is my code. If you have any questions about it feel free to ask. (But also note I'm not a python programmer. I just need it as a python for some reasons :roll:)

Code: Select all

import os
import threading
from threading import Thread
import time
from time import sleep
import signal
import sys
import RPi.GPIO as GPIO
from Queue import Queue

# following are the setting
pwmPin = 13 #Pin with PWM capability please reference https://pinout.xyz/pinout/pin33_gpio13
tachoPin = 6 #Pin where the tacho is plugged in
desiredTemp = 45 
maxTemp = 65 #At this temperature the fan will run at 100%
threshold = 15 #Percentage threshold how low the fan can run. 15 works for Noctua A4x10. Other fans need to be checked
rpmReadCycle = 100 #How often should the frequency from the tachometer be checked. The higher the more accurate but the longer it takes.
rpmFilePath = "rpm" #Path to where a file with the rpm number should be saved. So other apps can access it.
repeatInSec = 2 #How often should the measurement takes place. Every X seconds.

# Don't change, only if needed
pTemp = (maxTemp - desiredTemp) / 100.0 
dutyAverage = 0
pwmDuty = 100
pwmctr = None
rpmThread = None
tQueue = None

# second thread for Tachometer
class FreqThread(threading.Thread):
	def __init__(self, queue, tempPin, rpmReadCycle, filepath, args=(), kwargs=None):
		global tpin
		threading.Thread.__init__(self, args=(), kwargs=None)
		self.queue = queue
		self.tpin = tempPin
		self.cycle = rpmReadCycle
		GPIO.setup(self.tpin, GPIO.IN)
		self.fpath = filepath
		

	def run(self):
		while self.queue.empty():
			self.getRPM()
			sleep(1)
	
	def getRPM(self):
		startedAt = time.time()
		pinread = None
		for c in range(self.cycle):
			pinread = GPIO.wait_for_edge(self.tpin, GPIO.FALLING, timeout=1000)
			if pinread is None:
				break
		self.rpmFile = open(self.fpath, "w")
		if pinread is None:
			print("Frequenzy~: 0Hz | RPM~: 0")
			self.rpmFile.write("0")
			self.rpmFile.close()
			return
		duration = time.time() - startedAt
		frequency = self.cycle / duration
		rpm = int(frequency / 2 * 60)
		self.rpmFile.write(str(rpm))
		self.rpmFile.close()
		print("Frequenzy~: {:3.2f} | RPM~: {:4d}".format(frequency, rpm))
		

#sets some initial data
def setup():
	global pwmctr, tQueue
	tQueue = Queue();
	GPIO.setwarnings(False)
	GPIO.setmode(GPIO.BCM)
	GPIO.setup(pwmPin, GPIO.OUT)
	
	pwmctr=GPIO.PWM(pwmPin,100)
	pwmctr.start(100)
	rpmThread = FreqThread(tQueue, tachoPin, rpmReadCycle, rpmFilePath, None)
	rpmThread.start()
	return();
def getCPUtemp(): #reads the cpu temperature from the temp file
	f = open('/sys/class/thermal/thermal_zone0/temp', 'r')
	res = f.readline()
	f.close()
	temp = float(res) / 1000
	return temp
def changeDuty(): #calculates the needed PWM duty and changes it
	global sum, pwmDuty, pwmctr, dutyAverage, mWaited
	temp = getCPUtemp()
	diff = temp-desiredTemp
	pDiff = 0
	if diff > 0:
		pDiff = diff / pTemp
	pwmDuty = int(pDiff)
	dutyAverage = (dutyAverage + pwmDuty) / 2 #Average for getting the fan faster then needed so the desired temperature can be reached even under load
	pwmDuty = pwmDuty + dutyAverage
	if pwmDuty > 100:
		pwmDuty = 100
	if pwmDuty < threshold and pwmDuty > 8:
		pwmDuty = threshold;
	elif pwmDuty < threshold and pwmDuty <= 8:
		pwmDuty = 0
	pwmctr.ChangeDutyCycle(pwmDuty)
	print("actualTemp {:4.2f} TempDiff {:4.2f} pDiff {:4.2f} pwmDuty {:5.0f}".format(temp, diff, pDiff, pwmDuty))
	return()
def fanOFF():
	global pwmctr
	pwmctr.ChangeDutyCycle(0)
	return

try:
	setup()
	fanOFF()
	
	while True:
		changeDuty()
		sleep(repeatInSec)
except KeyboardInterrupt: # trap a CTRL+C keyboard interrupt 
	print("Wait for thread to be stopped")
	tQueue.put(None)
	fanOFF()
	GPIO.cleanup()

sar100
Posts: 4
Joined: Fri Aug 02, 2019 4:58 pm

Re: 5V 4-pin Noctua A4X10 on Raspberry Pi

Fri Aug 02, 2019 5:14 pm

hi all,

I have bought a noctua fan 5V pwm and i am studying how connect it to raspberry. I have read the differents schemes and I think that there are a problem in some of them if we connect the fan to 5V and the GPIO to control the pwm directly to pwm signal of the fan.

I think there are a pull-up resistor in fan unit in this pin and thus a reverse current in the GPIO pin that it can damage it. I think if you can use the fan at 5V you must use a “driver” or a transistor. My first try it will be with a 3,3 as suply level and I think that it don’t damage the pin.

I will tell you how the tests are going.

Regards

pcmanbob
Posts: 8387
Joined: Fri May 31, 2013 9:28 pm
Location: Mansfield UK

Re: 5V 4-pin Noctua A4X10 on Raspberry Pi

Fri Aug 02, 2019 8:27 pm

It clearly states the pwm input needs to be at 5V Which is why the circuit is required, you can use software pwm on any gpio pin, and software pwm will be fine for the fan control.
We want information… information… information........................no information no help
The use of crystal balls & mind reading are not supported

drgeoff
Posts: 10363
Joined: Wed Jan 25, 2012 6:39 pm

Re: 5V 4-pin Noctua A4X10 on Raspberry Pi

Fri Aug 02, 2019 11:00 pm

jcyr wrote:
Fri Aug 02, 2019 10:31 pm
pcmanbob wrote:
Tue Jul 02, 2019 1:06 pm
Because the fan being used in this tread has an internal pull up that may be 3.3v or 5v , you never want to connect 5v to the pi gpio or you will damage your pi.

So a transistor is used as a interface between the gpio and fan, also the fan used in the tread requires a current limiting resistor on the PWM to limit the max current to 5mA.

your fan may not have the same specifications you would need to find the specifications document for your fan and see what it says.
Ok, since the Noctua has an internal pull-up on the PWM input, I'd use this:

Image

At power up GPIO18 will be in Hi-Z state, so R1 keeps the fan at full power till the PWM signal on GPIO18 overrides it. R2 turns off the motor if there is no power on the 3.3V rail and GPIO18 is at Hi-Z (system halted).
Fan will run when there is no power on 3.3 volt rail. Fan's internal pullup to +5.

Artain
Posts: 3
Joined: Wed Jul 31, 2019 7:41 pm

Re: 5V 4-pin Noctua A4X10 on Raspberry Pi

Fri Aug 02, 2019 11:04 pm

pcmanbob wrote:
Tue Jul 02, 2019 1:06 pm
Because the fan being used in this tread has an internal pull up that may be 3.3v or 5v , you never want to connect 5v to the pi gpio or you will damage your pi.

So a transistor is used as a interface between the gpio and fan, also the fan used in the tread requires a current limiting resistor on the PWM to limit the max current to 5mA.

your fan may not have the same specifications you would need to find the specifications document for your fan and see what it says.
I tested the pwm signal from the pi to the fan. I don't see a 5V pullup just the 3V
This is what I got:
Image

Artain
Posts: 3
Joined: Wed Jul 31, 2019 7:41 pm

Re: 5V 4-pin Noctua A4X10 on Raspberry Pi

Fri Aug 02, 2019 11:29 pm

jcyr wrote:
Fri Aug 02, 2019 11:16 pm
Artain wrote:
Fri Aug 02, 2019 11:04 pm
I tested the pwm signal from the pi to the fan. I don't see a 5V pullup just the 3V
You wouldn't see the 5V with the PWM active, you'd only see it with the PWM pin in high impedance mode. Disconnect the PWM signal, then measure the voltage on the motor's PWM input side. You should then see whatever voltage the internal resistor is pulling up to. The documentation says it should be 3,30/5V... whatever that means? Is it 3.3 or 5?
Clearly I don't know what I'm talking about. But I try to learn. Well i measured it with the pwm signal disconnected and it bounces between 3,5 and 4V but occasionally peaks at 4,5V.

User avatar
davidcoton
Posts: 4675
Joined: Mon Sep 01, 2014 2:37 pm
Location: Cambridge, UK

Re: 5V 4-pin Noctua A4X10 on Raspberry Pi

Sat Aug 03, 2019 9:25 am

jcyr wrote:
Fri Aug 02, 2019 11:46 pm
I must be missing something... you should have fried your PWM pin.
I don't know which driver @Artain is using, but there are two circuits given above, one by you! The measurements are taken on the fan side of the driver.
Signature retired

sar100
Posts: 4
Joined: Fri Aug 02, 2019 4:58 pm

Re: 5V 4-pin Noctua A4X10 on Raspberry Pi

Sat Aug 03, 2019 8:58 pm

jcyr wrote:
Fri Aug 02, 2019 11:46 pm
Artain wrote:
Fri Aug 02, 2019 11:29 pm
jcyr wrote:
Fri Aug 02, 2019 11:16 pm


You wouldn't see the 5V with the PWM active, you'd only see it with the PWM pin in high impedance mode. Disconnect the PWM signal, then measure the voltage on the motor's PWM input side. You should then see whatever voltage the internal resistor is pulling up to. The documentation says it should be ... whatever that means? Is it 3.3 or 5?
Clearly I don't know what I'm talking about. But I try to learn. Well i measured it with the pwm signal disconnected and it bounces between 3,5 and 4V but occasionally peaks at 4,5V.
Weird! I guess that's what they mean by '3,30/5V'.

I must be missing something... you should have fried your PWM pin. 4.5V is above the permitted voltage for a 3.3V pin. The pin should have been subjected to that voltage at power up when the PWM pin high impedance mode prior to PWM initialization.
I think “3,3/5V” means there are a Vcc pull up resistor, if you connect Vcc to 5V there are 5V pull up.

https://jeancyr.com/noctua.png

@jeancyr what Mosfet are you using? i think this circuit would work fine and and it won't damage the pin.

Thanks

sar100
Posts: 4
Joined: Fri Aug 02, 2019 4:58 pm

Re: 5V 4-pin Noctua A4X10 on Raspberry Pi

Sun Aug 04, 2019 8:56 am

Hi,

are r1 and r2 to do fastest edges of pwm signals? has it other functions?

Thanks

sar100
Posts: 4
Joined: Fri Aug 02, 2019 4:58 pm

Re: 5V 4-pin Noctua A4X10 on Raspberry Pi

Tue Aug 06, 2019 11:04 am

hi,

now I can't buy transistors but I want do some test.

could I connect the fan to 3,3V as supply voltage and the pwm pin directly to raspberry?

Thanks

nachomagic
Posts: 1
Joined: Wed Aug 07, 2019 11:03 am

Re: 5V 4-pin Noctua A4X10 on Raspberry Pi

Wed Aug 07, 2019 11:05 am

Thanks for the code, it's working like a charm :)
Artain wrote:
Wed Jul 31, 2019 8:33 pm
First of all I'm a Software engineer not a electrical one but this stuff is my hobby so here it goes.

I had the same problem. I bought a Noctua NF-A4X10 5V-PWM the one with the 4 pins. I then checked a few forums and watched a bunch of YT videos but nothing really did what I wanted to do.
Of course I could let the fan run at 100% because its really silent or i could buy a control unit. But I love automation so it has to be run by the pi itself. I run also in a few problems with my pi because I'm usually building stuff with ESPs. After 2 Days of failure I decided I need a oscilloscope. The day it arrived everything went clear.
First of all it is really hard to get a nice rectangle curve even with Mosfets. But after re-reading the Noctua spec doc I noticed:
There are no special requirements for the circuits that generate the PWM signal. However, Noctua recommends to use a CMOS-inverter type circuit as shown below. This is the very circuit that is used for GPIO pins inside most micro-controllers.
So i checked what the PWM signal is the raspi can generate itself and its better then anything I could create with transistors and I don't need generate a duty signal for the mosfets.
I just don't have a PC output on my oscilloscope or I could show you what I mean.
Anyway long story short I created a python script which does exactly what I and I think you also want it to do. But first here is how I connected the fan to my Pi
Image

Note two things, first you need to connect it to a PWM capable pin and second you need to use the resistor as its mentioned in the spec pdf.
As you can see you don't need any transistor for you PWM signal or curve. You could add a diode between raspi and fan but I don't think its necessary at with a noctua nor at these currents,...
And here is my code. If you have any questions about it feel free to ask. (But also note I'm not a python programmer. I just need it as a python for some reasons :roll:)

Code: Select all

import os
import threading
from threading import Thread
import time
from time import sleep
import signal
import sys
import RPi.GPIO as GPIO
from Queue import Queue

# following are the setting
pwmPin = 13 #Pin with PWM capability please reference https://pinout.xyz/pinout/pin33_gpio13
tachoPin = 6 #Pin where the tacho is plugged in
desiredTemp = 45 
maxTemp = 65 #At this temperature the fan will run at 100%
threshold = 15 #Percentage threshold how low the fan can run. 15 works for Noctua A4x10. Other fans need to be checked
rpmReadCycle = 100 #How often should the frequency from the tachometer be checked. The higher the more accurate but the longer it takes.
rpmFilePath = "rpm" #Path to where a file with the rpm number should be saved. So other apps can access it.
repeatInSec = 2 #How often should the measurement takes place. Every X seconds.

# Don't change, only if needed
pTemp = (maxTemp - desiredTemp) / 100.0 
dutyAverage = 0
pwmDuty = 100
pwmctr = None
rpmThread = None
tQueue = None

# second thread for Tachometer
class FreqThread(threading.Thread):
	def __init__(self, queue, tempPin, rpmReadCycle, filepath, args=(), kwargs=None):
		global tpin
		threading.Thread.__init__(self, args=(), kwargs=None)
		self.queue = queue
		self.tpin = tempPin
		self.cycle = rpmReadCycle
		GPIO.setup(self.tpin, GPIO.IN)
		self.fpath = filepath
		

	def run(self):
		while self.queue.empty():
			self.getRPM()
			sleep(1)
	
	def getRPM(self):
		startedAt = time.time()
		pinread = None
		for c in range(self.cycle):
			pinread = GPIO.wait_for_edge(self.tpin, GPIO.FALLING, timeout=1000)
			if pinread is None:
				break
		self.rpmFile = open(self.fpath, "w")
		if pinread is None:
			print("Frequenzy~: 0Hz | RPM~: 0")
			self.rpmFile.write("0")
			self.rpmFile.close()
			return
		duration = time.time() - startedAt
		frequency = self.cycle / duration
		rpm = int(frequency / 2 * 60)
		self.rpmFile.write(str(rpm))
		self.rpmFile.close()
		print("Frequenzy~: {:3.2f} | RPM~: {:4d}".format(frequency, rpm))
		

#sets some initial data
def setup():
	global pwmctr, tQueue
	tQueue = Queue();
	GPIO.setwarnings(False)
	GPIO.setmode(GPIO.BCM)
	GPIO.setup(pwmPin, GPIO.OUT)
	
	pwmctr=GPIO.PWM(pwmPin,100)
	pwmctr.start(100)
	rpmThread = FreqThread(tQueue, tachoPin, rpmReadCycle, rpmFilePath, None)
	rpmThread.start()
	return();
def getCPUtemp(): #reads the cpu temperature from the temp file
	f = open('/sys/class/thermal/thermal_zone0/temp', 'r')
	res = f.readline()
	f.close()
	temp = float(res) / 1000
	return temp
def changeDuty(): #calculates the needed PWM duty and changes it
	global sum, pwmDuty, pwmctr, dutyAverage, mWaited
	temp = getCPUtemp()
	diff = temp-desiredTemp
	pDiff = 0
	if diff > 0:
		pDiff = diff / pTemp
	pwmDuty = int(pDiff)
	dutyAverage = (dutyAverage + pwmDuty) / 2 #Average for getting the fan faster then needed so the desired temperature can be reached even under load
	pwmDuty = pwmDuty + dutyAverage
	if pwmDuty > 100:
		pwmDuty = 100
	if pwmDuty < threshold and pwmDuty > 8:
		pwmDuty = threshold;
	elif pwmDuty < threshold and pwmDuty <= 8:
		pwmDuty = 0
	pwmctr.ChangeDutyCycle(pwmDuty)
	print("actualTemp {:4.2f} TempDiff {:4.2f} pDiff {:4.2f} pwmDuty {:5.0f}".format(temp, diff, pDiff, pwmDuty))
	return()
def fanOFF():
	global pwmctr
	pwmctr.ChangeDutyCycle(0)
	return

try:
	setup()
	fanOFF()
	
	while True:
		changeDuty()
		sleep(repeatInSec)
except KeyboardInterrupt: # trap a CTRL+C keyboard interrupt 
	print("Wait for thread to be stopped")
	tQueue.put(None)
	fanOFF()
	GPIO.cleanup()

Tomxtal
Posts: 5
Joined: Fri Jun 26, 2015 11:09 pm

Re: 5V 4-pin Noctua A4X10 on Raspberry Pi

Wed Aug 28, 2019 1:51 pm

Hi jcyr
Do you have a copy of the python code you used with your two mosfet setup. I'm ask has I have not got in to any programming as yet.

TomXtal

Tomxtal
Posts: 5
Joined: Fri Jun 26, 2015 11:09 pm

Re: 5V 4-pin Noctua A4X10 on Raspberry Pi

Wed Aug 28, 2019 7:49 pm

jcyr thanks for the quick reply.
I have setup my PI4 with a heatsink from china I have mill out some of the fins so as to mount a 50mm fan pwm type and works OK but I need to some out method of controlling the pwm output from the PI. I have check the pwm wire from the fan and I see its 5 volt so not a good idea to connect this direct to the PI. I do have some IRF520 mosfet which I may give a try, as any one try this kind of mosfet? I'm also look for some code to run this kind of settup.

Image

Image

Image

DarkoSan
Posts: 7
Joined: Fri Mar 03, 2017 1:25 pm

Re: 5V 4-pin Noctua A4X10 on Raspberry Pi

Mon Oct 07, 2019 11:42 am

Hi Artain,
Thank you for sharing the schematic and the code. I would like to use your implementation with slightly bigger fan (120mm).
I have two questions:
1. What is the purpose of the connection from 3V3 rail to the GPIO6 and then to Tacho? Can’t it be connected directly GPIO6 to Tacho?
2. Would you please share specific for the resistor, at what Wattage is it? 1W / 2.2kΩ?

Artain wrote:
Wed Jul 31, 2019 8:33 pm
First of all I'm a Software engineer not a electrical one but this stuff is my hobby so here it goes.

I had the same problem. I bought a Noctua NF-A4X10 5V-PWM the one with the 4 pins. I then checked a few forums and watched a bunch of YT videos but nothing really did what I wanted to do.
Of course I could let the fan run at 100% because its really silent or i could buy a control unit. But I love automation so it has to be run by the pi itself. I run also in a few problems with my pi because I'm usually building stuff with ESPs. After 2 Days of failure I decided I need a oscilloscope. The day it arrived everything went clear.
First of all it is really hard to get a nice rectangle curve even with Mosfets. But after re-reading the Noctua spec doc I noticed:
There are no special requirements for the circuits that generate the PWM signal. However, Noctua recommends to use a CMOS-inverter type circuit as shown below. This is the very circuit that is used for GPIO pins inside most micro-controllers.
So i checked what the PWM signal is the raspi can generate itself and its better then anything I could create with transistors and I don't need generate a duty signal for the mosfets.
I just don't have a PC output on my oscilloscope or I could show you what I mean.
Anyway long story short I created a python script which does exactly what I and I think you also want it to do. But first here is how I connected the fan to my Pi
Image

Note two things, first you need to connect it to a PWM capable pin and second you need to use the resistor as its mentioned in the spec pdf.
As you can see you don't need any transistor for you PWM signal or curve. You could add a diode between raspi and fan but I don't think its necessary at with a noctua nor at these currents,...
And here is my code. If you have any questions about it feel free to ask. (But also note I'm not a python programmer. I just need it as a python for some reasons :roll:)

Code: Select all

import os
import threading
from threading import Thread
import time
from time import sleep
import signal
import sys
import RPi.GPIO as GPIO
from Queue import Queue

# following are the setting
pwmPin = 13 #Pin with PWM capability please reference https://pinout.xyz/pinout/pin33_gpio13
tachoPin = 6 #Pin where the tacho is plugged in
desiredTemp = 45 
maxTemp = 65 #At this temperature the fan will run at 100%
threshold = 15 #Percentage threshold how low the fan can run. 15 works for Noctua A4x10. Other fans need to be checked
rpmReadCycle = 100 #How often should the frequency from the tachometer be checked. The higher the more accurate but the longer it takes.
rpmFilePath = "rpm" #Path to where a file with the rpm number should be saved. So other apps can access it.
repeatInSec = 2 #How often should the measurement takes place. Every X seconds.

# Don't change, only if needed
pTemp = (maxTemp - desiredTemp) / 100.0 
dutyAverage = 0
pwmDuty = 100
pwmctr = None
rpmThread = None
tQueue = None

# second thread for Tachometer
class FreqThread(threading.Thread):
	def __init__(self, queue, tempPin, rpmReadCycle, filepath, args=(), kwargs=None):
		global tpin
		threading.Thread.__init__(self, args=(), kwargs=None)
		self.queue = queue
		self.tpin = tempPin
		self.cycle = rpmReadCycle
		GPIO.setup(self.tpin, GPIO.IN)
		self.fpath = filepath
		

	def run(self):
		while self.queue.empty():
			self.getRPM()
			sleep(1)
	
	def getRPM(self):
		startedAt = time.time()
		pinread = None
		for c in range(self.cycle):
			pinread = GPIO.wait_for_edge(self.tpin, GPIO.FALLING, timeout=1000)
			if pinread is None:
				break
		self.rpmFile = open(self.fpath, "w")
		if pinread is None:
			print("Frequenzy~: 0Hz | RPM~: 0")
			self.rpmFile.write("0")
			self.rpmFile.close()
			return
		duration = time.time() - startedAt
		frequency = self.cycle / duration
		rpm = int(frequency / 2 * 60)
		self.rpmFile.write(str(rpm))
		self.rpmFile.close()
		print("Frequenzy~: {:3.2f} | RPM~: {:4d}".format(frequency, rpm))
		

#sets some initial data
def setup():
	global pwmctr, tQueue
	tQueue = Queue();
	GPIO.setwarnings(False)
	GPIO.setmode(GPIO.BCM)
	GPIO.setup(pwmPin, GPIO.OUT)
	
	pwmctr=GPIO.PWM(pwmPin,100)
	pwmctr.start(100)
	rpmThread = FreqThread(tQueue, tachoPin, rpmReadCycle, rpmFilePath, None)
	rpmThread.start()
	return();
def getCPUtemp(): #reads the cpu temperature from the temp file
	f = open('/sys/class/thermal/thermal_zone0/temp', 'r')
	res = f.readline()
	f.close()
	temp = float(res) / 1000
	return temp
def changeDuty(): #calculates the needed PWM duty and changes it
	global sum, pwmDuty, pwmctr, dutyAverage, mWaited
	temp = getCPUtemp()
	diff = temp-desiredTemp
	pDiff = 0
	if diff > 0:
		pDiff = diff / pTemp
	pwmDuty = int(pDiff)
	dutyAverage = (dutyAverage + pwmDuty) / 2 #Average for getting the fan faster then needed so the desired temperature can be reached even under load
	pwmDuty = pwmDuty + dutyAverage
	if pwmDuty > 100:
		pwmDuty = 100
	if pwmDuty < threshold and pwmDuty > 8:
		pwmDuty = threshold;
	elif pwmDuty < threshold and pwmDuty <= 8:
		pwmDuty = 0
	pwmctr.ChangeDutyCycle(pwmDuty)
	print("actualTemp {:4.2f} TempDiff {:4.2f} pDiff {:4.2f} pwmDuty {:5.0f}".format(temp, diff, pDiff, pwmDuty))
	return()
def fanOFF():
	global pwmctr
	pwmctr.ChangeDutyCycle(0)
	return

try:
	setup()
	fanOFF()
	
	while True:
		changeDuty()
		sleep(repeatInSec)
except KeyboardInterrupt: # trap a CTRL+C keyboard interrupt 
	print("Wait for thread to be stopped")
	tQueue.put(None)
	fanOFF()
	GPIO.cleanup()

User avatar
davidcoton
Posts: 4675
Joined: Mon Sep 01, 2014 2:37 pm
Location: Cambridge, UK

Re: 5V 4-pin Noctua A4X10 on Raspberry Pi

Tue Oct 08, 2019 3:30 pm

DarkoSan wrote:
Mon Oct 07, 2019 11:42 am
1. What is the purpose of the connection from 3V3 rail to the GPIO6 and then to Tacho? Can’t it be connected directly GPIO6 to Tacho?
The tacho is an open collector (volt free) output. In fact with a Pi you can use the internal pull-up resistor by using the correct GPIO configuration, so it is not strictly necessary.
DarkoSan wrote:
Mon Oct 07, 2019 11:42 am
2. Would you please share specific for the resistor, at what Wattage is it? 1W / 2.2kΩ?
You can calculate that yourself. You know the maximum voltage is 3.3V, and that P=V x I and V=I x R. So:
P=V x V / R
=3.3 x 3.3 / 2200
=5mW
You do not need a 1W resistor!
Signature retired

Jaybe
Posts: 1
Joined: Tue Oct 22, 2019 9:18 pm

Re: 5V 4-pin Noctua A4X10 on Raspberry Pi

Tue Oct 22, 2019 9:27 pm

This thread has been very insightful. I have the same Noctua 5v fan which I use with my Pi 3B+ that hosts OctoPrint. Having the fan go off at certain temp thresholds is something I've wanted to accomplish too (which is how I stumbled here).

I've followed Artain's schematic and it works great except for when the Pi is shutdown. When shutdown, the fan then just runs at 100% because it is still powered. Is there a way to prevent this?

(It's not massively important because A: the Pi shouldn't really have downtime and B: I can just unplug it. I figure it'd be a good learning experience, though!)

schnoog
Posts: 12
Joined: Tue Dec 27, 2011 3:55 pm
Contact: Website

Re: 5V 4-pin Noctua A4X10 on Raspberry Pi

Sun Nov 03, 2019 12:30 pm

Thanks @Artain.

The resistant R1 isn't required if you use the internal pull up.

I'm using a NF-A6x25 5V PWM which is directly connected to the pin header (but added a 47µF cap between 5V+ and Ground).

Yellow -> Pin 2
Black -> Pin 6
Green-> Pin 31
Blue -> Pin 33

Code: Select all

import os
import threading
from threading import Thread
import time
from time import sleep
import signal
import sys
import RPi.GPIO as GPIO
from Queue import Queue

# following are the setting
pwmPin = 13 #Pin with PWM capability please reference https://pinout.xyz/pinout/pin33_gpio13
tachoPin = 6 #Pin where the tacho is plugged in
desiredTemp = 45 
maxTemp = 65 #At this temperature the fan will run at 100%
threshold = 15 #Percentage threshold how low the fan can run. 15 works for Noctua A4x10. Other fans need to be checked
rpmReadCycle = 100 #How often should the frequency from the tachometer be checked. The higher the more accurate but the longer it takes.
rpmFilePath = "rpm" #Path to where a file with the rpm number should be saved. So other apps can access it.
repeatInSec = 2 #How often should the measurement takes place. Every X seconds.

# Don't change, only if needed
pTemp = (maxTemp - desiredTemp) / 100.0 
dutyAverage = 0
pwmDuty = 100
pwmctr = None
rpmThread = None
tQueue = None

# second thread for Tachometer
class FreqThread(threading.Thread):
	def __init__(self, queue, tempPin, rpmReadCycle, filepath, args=(), kwargs=None):
		global tpin
		threading.Thread.__init__(self, args=(), kwargs=None)
		self.queue = queue
		self.tpin = tempPin
		self.cycle = rpmReadCycle
		#GPIO.setup(self.tpin, GPIO.IN) # External Pull Up required
		GPIO.setup(self.tpin, GPIO.IN, pull_up_down=GPIO.PUD_UP)  #Internal Pull Up
		self.fpath = filepath
		

	def run(self):
		while self.queue.empty():
			self.getRPM()
			sleep(1)
	
	def getRPM(self):
		startedAt = time.time()
		pinread = None
		for c in range(self.cycle):
			pinread = GPIO.wait_for_edge(self.tpin, GPIO.FALLING, timeout=1000)
			if pinread is None:
				break
		self.rpmFile = open(self.fpath, "w")
		if pinread is None:
			print("Frequenzy~: 0Hz | RPM~: 0")
			self.rpmFile.write("0")
			self.rpmFile.close()
			return
		duration = time.time() - startedAt
		frequency = self.cycle / duration
		rpm = int(frequency / 2 * 60)
		self.rpmFile.write(str(rpm))
		self.rpmFile.close()
		print("Frequenzy~: {:3.2f} | RPM~: {:4d}".format(frequency, rpm))
		

#sets some initial data
def setup():
	global pwmctr, tQueue
	tQueue = Queue();
	GPIO.setwarnings(False)
	GPIO.setmode(GPIO.BCM)
	GPIO.setup(pwmPin, GPIO.OUT)
	
	pwmctr=GPIO.PWM(pwmPin,100)
	pwmctr.start(100)
	rpmThread = FreqThread(tQueue, tachoPin, rpmReadCycle, rpmFilePath, None)
	rpmThread.start()
	return();
def getCPUtemp(): #reads the cpu temperature from the temp file
	f = open('/sys/class/thermal/thermal_zone0/temp', 'r')
	res = f.readline()
	f.close()
	temp = float(res) / 1000
	return temp
def changeDuty(): #calculates the needed PWM duty and changes it
	global sum, pwmDuty, pwmctr, dutyAverage, mWaited
	temp = getCPUtemp()
	diff = temp-desiredTemp
	pDiff = 0
	if diff > 0:
		pDiff = diff / pTemp
	pwmDuty = int(pDiff)
	dutyAverage = (dutyAverage + pwmDuty) / 2 #Average for getting the fan faster then needed so the desired temperature can be reached even under load
	pwmDuty = pwmDuty + dutyAverage
	if pwmDuty > 100:
		pwmDuty = 100
	if pwmDuty < threshold and pwmDuty > 8:
		pwmDuty = threshold;
	elif pwmDuty < threshold and pwmDuty <= 8:
		pwmDuty = 0
	pwmctr.ChangeDutyCycle(pwmDuty)
	print("actualTemp {:4.2f} TempDiff {:4.2f} pDiff {:4.2f} pwmDuty {:5.0f}".format(temp, diff, pDiff, pwmDuty))
	return()
def fanOFF():
	global pwmctr
	pwmctr.ChangeDutyCycle(0)
	return

try:
	setup()
	fanOFF()
	
	while True:
		changeDuty()
		sleep(repeatInSec)
except KeyboardInterrupt: # trap a CTRL+C keyboard interrupt 
	print("Wait for thread to be stopped")
	tQueue.put(None)
	fanOFF()
	GPIO.cleanup()

pams
Posts: 15
Joined: Mon Jul 23, 2018 4:30 pm

Re: 5V 4-pin PWM Noctua A4X10 on Raspberry Pi

Mon Nov 04, 2019 8:48 am

I've seen that the python code provided by some people is using RPI.GPIO, which, to my knowledge, only offers software PWM. Be careful with that!

Acc. to Noctua, these fans target PWM frequency is 25kHz (acceptable range: 21kHz to 28kHz). Software PWM is never going to achieve that.

Hardware PWM is what is needed. And for that use Joan's pigpio, not RPI.GPIO.

robov
Posts: 1
Joined: Sat Nov 16, 2019 3:22 pm

Re: 5V 4-pin PWM Noctua A4X10 on Raspberry Pi

Sat Nov 16, 2019 3:24 pm

pams wrote:
Mon Nov 04, 2019 8:48 am
I've seen that the python code provided by some people is using RPI.GPIO, which, to my knowledge, only offers software PWM. Be careful with that!

Acc. to Noctua, these fans target PWM frequency is 25kHz (acceptable range: 21kHz to 28kHz). Software PWM is never going to achieve that.

Hardware PWM is what is needed. And for that use Joan's pigpio, not RPI.GPIO.
That's good point, how can I change the code above using hardware PWM. Does anyone tried it ?

bk4nt
Posts: 7
Joined: Fri Dec 06, 2019 6:00 pm

Re: 5V 4-pin Noctua A4X10 on Raspberry Pi

Mon Dec 09, 2019 2:06 am

sar100 wrote:
Sat Aug 03, 2019 8:58 pm
jcyr wrote:
Fri Aug 02, 2019 11:46 pm
Artain wrote:
Fri Aug 02, 2019 11:29 pm


Clearly I don't know what I'm talking about. But I try to learn. Well i measured it with the pwm signal disconnected and it bounces between 3,5 and 4V but occasionally peaks at 4,5V.
Weird! I guess that's what they mean by '3,30/5V'.

I must be missing something... you should have fried your PWM pin. 4.5V is above the permitted voltage for a 3.3V pin. The pin should have been subjected to that voltage at power up when the PWM pin high impedance mode prior to PWM initialization.
I think “3,3/5V” means there are a Vcc pull up resistor, if you connect Vcc to 5V there are 5V pull up.
I wired also directly PWM pin to the GPIO: no issue, my Pi 4 didn't fry...

I see the same using my scope, an almost nice 3.3V square signal. But with a spike following the raising edge, going very shortly above 3.3V, maybe 3.4V, then back to flat 3.3V.

I think the CPU/GPIO has a diode on its input (but sure a really weak one, for basic ESD protection) which seems to be sufficient to protect the input. The fan pull up resistor shouldn't drain that much current to the Pi gpio when it is at high level? Some micro amps only? I now added an 1N4148 between +3.3V(K) and the FAN PWM input(A), but that makes no difference, the very short spike above +3.3V is similar.

On the unconnected fan PWM pin, using a voltmeter, I see some 3.7V (when I connect it, more, up to 4.5V, then it shifts in seconds to 3.7V...). So, connected to the Pi, this seems to be limited to 3.3 (3.4V max) by the internal diode on the gpio input.

I think I'll keep it simple, with the 1N4148 diode I now added.

PS: according to the Noctua specs, you shall not drive the PWM pin with an open collector.
pams wrote:
Mon Nov 04, 2019 8:48 am
I've seen that the python code provided by some people is using RPI.GPIO, which, to my knowledge, only offers software PWM. Be careful with that!

Acc. to Noctua, these fans target PWM frequency is 25kHz (acceptable range: 21kHz to 28kHz). Software PWM is never going to achieve that.

Hardware PWM is what is needed. And for that use Joan's pigpio, not RPI.GPIO.
I noticed RPi.GPIO currently doesn't support hardware PWM. At 25kHz, this eats up a lot of CPU time, some 20% of a core.

I'm using this fan with 100Hz only now, works also, for less than 1% of a core.

What I'm running is that: https://github.com/bk4nt/pi-fan-pwm/blo ... fan-pwm.py

Feson
Posts: 1
Joined: Mon Dec 09, 2019 3:55 am

Re: 5V 4-pin PWM Noctua A4X10 on Raspberry Pi

Mon Dec 09, 2019 4:14 am

I am using this on rpi3B+

gforce2010
Posts: 6
Joined: Fri Feb 08, 2019 7:09 pm

Re: 5V 4-pin PWM Noctua A4X10 on Raspberry Pi

Fri Jan 24, 2020 3:18 pm

I am shortly goint to be connecting a Noctura 4020 PWM fan to my Pi but this post has confused my a bit.

Can I connect the PWM pin directlly to my Pi? The Pi outputs 3.3V but the Noctura spec says the PWM requires a 5V signal?

Return to “General discussion”