<p><a href=/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/noctua-pwm-pi-ezgif.com-optimize.e400dfe08b35d68aee56e4e16fae8785.gif class=fancybox><picture><img class=img-fluid src=/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/noctua-pwm-pi-ezgif.com-optimize.e400dfe08b35d68aee56e4e16fae8785.gif alt="Noctua NF-A20 PWM fan" loading=lazy height=895 width=1711></picture></a></p><p>I am making
<a href=/posts/minipc-rack-part-1/>my homelab</a>
and I need to control the
<a href=https://noctua.at/en/nf-a20-pwm-chromax-black-swap target=_blank rel=noopener>Noctua NF-A20 PWM chromax.black.swap 200x200mm</a>
fan from Raspberry Pi, and this is how I’ve done it.</p><h2 id=parts-you-need>Parts you need:</h2><ul><li>Some Raspberry Pi</li><li>The Noctua NF-A20 PWM fan (should work with other 12V noctua fans as well)</li><li>A multimeter</li><li><a href=https://www.amazon.com/Adjustable-Converter-Transformer-Regulator-3-5V-35V/dp/B092CJBL92 target=_blank rel=noopener>LM2577 DC-DC Step Up Booster Converter</a></li><li><a href=https://www.amazon.com/ALLECIN-2N2222-Amplifier-Transistors-Transistor/dp/B0CBK1T5FQ target=_blank rel=noopener>NPN Transistor</a></li><li>1K Ohm Resistor</li></ul><h2 id=diagram>Diagram:</h2><p><a href=/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/diagram.6b98eb62e389136c2a1f5c245243f014.png class=fancybox><picture><source srcset=/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/diagram_hu240544990833317495.webp type=image/webp><img class=img-fluid src=/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/diagram.6b98eb62e389136c2a1f5c245243f014.png alt="diagram image" loading=lazy height=1824 width=1883></picture></a></p><h2 id=lets-start-from-the-pi>Let’s start from the Pi:</h2><p>1- Connect a wire from GPIO pin 16, or any simple gpio pin, to the 1k resistor, and then the other end of the transistor to the middle pin of the transistor.</p><p>2- A wire from the right pin of the transistor to any ground pin of the Pi. The face of the transistor is the flat one.</p><p>3- A wire from the left pin of the transistor to the “IN-” 5V negative input of the power convertor.</p><p>4- A wire from one of the 5V Pi pins (top right) to the “IN+” 5V positive input of the power convertor.</p><p>5- <strong>Important</strong>: adjust the converter to 12V or lower.<br>Do NOT connect the fan right now because you can permanently damage it because of high voltage.<br> A- Turn on the converter by connecting a ground pin from the Pi directly to the Power Converter’s “IN-” connector OR by runing the code from the next section and just calling <code>speed(fan, 100) / time.sleep(180)</code>.<br> B- Connect a multimeter to the converter’s “OUT+” and “OUT-” and select voltage measurement on the multimeter (usually marked as “2V”).<br> C- On the converter turn the small yellow screw until the multimeter shows 12V or a bit smaller to be safe. I have mine at 11.5V.</p><p><a href=/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/power-converter-nob.09666e2f6a0cb904a3d9dbb80a0fa25b.png class=fancybox><picture><source srcset=/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/power-converter-nob_hu2864229298055400022.webp type=image/webp><img class=img-fluid src=/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/power-converter-nob.09666e2f6a0cb904a3d9dbb80a0fa25b.png alt="power converter adjustment nob" loading=lazy height=255 width=999></picture></a></p><p> D- When you are done disconnect the multimeter and the ground wire, or turn off the script.</p><p>The pinout from the noctua fan I found here:
<a href=https://faqs.noctua.at/en/support/solutions/articles/101000081757-what-pin-configuration-do-noctua-fans-use- target=_blank rel=noopener>https://faqs.noctua.at/en/support/solutions/articles/101000081757-what-pin-configuration-do-noctua-fans-use-</a>
<a href=/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/noctua-pinout.db5471cf55cd488e3de87f4205f2f44e.png class=fancybox><picture><source srcset=/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/noctua-pinout_hu15230658805204666452.webp type=image/webp><img class=img-fluid src=/posts/how-to-control-a-noctua-nf-a20-pwm-fan-from-raspberry-pi/noctua-pinout.db5471cf55cd488e3de87f4205f2f44e.png alt="noctua pinout image" loading=lazy height=160 width=1037></picture></a></p><p>5- Wire from power convertor “OUT-” (12V negative) to noctua pin 1.</p><p>6- Wire from power convertor “OUT+” (12V positive) to noctua pin 2.</p><p>5- Wire from noctua pin 4 to Pi GPIO pin 12.
<a href=https://pinout.xyz/pinout/pin32_gpio12/ target=_blank rel=noopener>This pin has PWM capability</a>
.</p><h2 id=the-code>The code:</h2><p>I used the code from this
<a href=https://www.the-diy-life.com/connecting-a-pwm-fan-to-a-raspberry-pi/ target=_blank rel=noopener>tutorial published on the-diy-life.com by Michael Klements</a>
(
<a href=https://github.com/mklements/PWMFanControl/blob/main/FanProportional.py target=_blank rel=noopener>original code</a>
), and I modified it to use the transistor to turn off the fan, because the fan PWM does not scale down to 0 RPM. The
<a href=https://noctua.at/en/nf-a20-pwm-chromax-black-swap/specification target=_blank rel=noopener>minimum rotational speed is 20%</a>
(350RPM).</p><div class=highlight><pre tabindex=0 style=color:#d0d0d0;background-color:#202020;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-python data-lang=python><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868"> 1</span><span><span style=color:#999;font-style:italic>#!/usr/bin/env python3</span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868"> 2</span><span><span style=color:#6ab825;font-weight:700>import</span> <span style=color:#447fcf;text-decoration:underline>RPi.GPIO</span> <span style=color:#6ab825;font-weight:700>as</span> <span style=color:#447fcf;text-decoration:underline>GPIO</span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868"> 3</span><span><span style=color:#6ab825;font-weight:700>import</span> <span style=color:#447fcf;text-decoration:underline>time</span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868"> 4</span><span><span style=color:#6ab825;font-weight:700>import</span> <span style=color:#447fcf;text-decoration:underline>signal</span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868"> 5</span><span><span style=color:#6ab825;font-weight:700>import</span> <span style=color:#447fcf;text-decoration:underline>sys</span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868"> 6</span><span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868"> 7</span><span><span style=color:#999;font-style:italic># The Noctua PWM control actually wants 25 kHz (kilo!), see page 6 on:</span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868"> 8</span><span><span style=color:#999;font-style:italic># https://noctua.at/pub/media/wysiwyg/Noctua_PWM_specifications_white_paper.pdf</span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868"> 9</span><span>PWM_FREQ = <span style=color:#3677a9>25</span> <span style=color:#999;font-style:italic># [Hz] PWM frequency</span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">10</span><span>FAN_PIN = <span style=color:#3677a9>12</span> <span style=color:#999;font-style:italic># BCM pin used to drive PWM fan</span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">11</span><span>TRAN_PIN = <span style=color:#3677a9>16</span> <span style=color:#999;font-style:italic># NPN Transistor</span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">12</span><span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">13</span><span><span style=color:#6ab825;font-weight:700>def</span> <span style=color:#447fcf>speed</span>(fan, percent):
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">14</span><span> <span style=color:#24909d>print</span>(<span style=color:#ed9d13>"set fan to"</span>, percent)
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">15</span><span> <span style=color:#6ab825;font-weight:700>if</span> (percent < <span style=color:#3677a9>20</span>):
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">16</span><span> GPIO.output(TRAN_PIN, <span style=color:#6ab825;font-weight:700>False</span>)
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">17</span><span> fan.ChangeDutyCycle(<span style=color:#3677a9>20</span>)
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">18</span><span> <span style=color:#6ab825;font-weight:700>else</span>:
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">19</span><span> GPIO.output(TRAN_PIN, <span style=color:#6ab825;font-weight:700>True</span>)
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">20</span><span> fan.ChangeDutyCycle(percent)
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">21</span><span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">22</span><span><span style=color:#6ab825;font-weight:700>try</span>:
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">23</span><span> signal.signal(signal.SIGTERM, <span style=color:#6ab825;font-weight:700>lambda</span> *args: sys.exit(<span style=color:#3677a9>0</span>))
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">24</span><span> GPIO.setwarnings(<span style=color:#6ab825;font-weight:700>True</span>)
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">25</span><span> GPIO.setmode(GPIO.BCM)
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">26</span><span> GPIO.setup(TRAN_PIN, GPIO.OUT)
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">27</span><span> GPIO.setup(FAN_PIN, GPIO.OUT, initial=GPIO.LOW)
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">28</span><span> fan = GPIO.PWM(FAN_PIN, PWM_FREQ)
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">29</span><span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">30</span><span> <span style=color:#999;font-style:italic># do a few cycles just for testing</span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">31</span><span> speed(fan, <span style=color:#3677a9>100</span>)
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">32</span><span> time.sleep(<span style=color:#3677a9>30</span>)
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">33</span><span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">34</span><span> speed(fan, <span style=color:#3677a9>50</span>)
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">35</span><span> time.sleep(<span style=color:#3677a9>30</span>)
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">36</span><span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">37</span><span> speed(fan, <span style=color:#3677a9>0</span>)
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">38</span><span> time.sleep(<span style=color:#3677a9>30</span>)
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">39</span><span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">40</span><span> speed(fan, <span style=color:#3677a9>20</span>)
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">41</span><span> time.sleep(<span style=color:#3677a9>30</span>)
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">42</span><span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">43</span><span> speed(fan, <span style=color:#3677a9>70</span>)
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">44</span><span> time.sleep(<span style=color:#3677a9>30</span>)
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">45</span><span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">46</span><span> speed(fan, <span style=color:#3677a9>100</span>)
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">47</span><span> time.sleep(<span style=color:#3677a9>30</span>)
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">48</span><span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">49</span><span><span style=color:#6ab825;font-weight:700>except</span> <span style=color:#bbb>KeyboardInterrupt</span>:
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">50</span><span> <span style=color:#6ab825;font-weight:700>pass</span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">51</span><span>
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">52</span><span><span style=color:#6ab825;font-weight:700>finally</span>:
</span></span><span style=display:flex><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#686868">53</span><span> GPIO.cleanup()
</span></span></code></pre></div><p>Done. Happy tinkering !</p><hr width=100% id=EOF><p style=color:#777>Last modified on 2024-11-18</p>