Contribute
Register

Fan speed control on High Sierra

Status
Not open for further replies.
black.dragon74, you are right, it doesn't make a lot of difference. But correctly configured work tools increase the quality and work experience overall.

My CPU is 32°C, SSD is 9°C, and fan still keeps working. And Asus K501 fan is just super annoying.

I use Notebook Fan Control in Windows to set 0 RPM if CPU temperature is less then 60 and it rarely gets so hot. I have most of my files on SSD. And believe me, working on a quiet laptop is a miracle!

I've been reading a lot of information on fan control and I see that is a very tough job, compared to RPM display( I will keep trying. Any sort of help is appreciated!
 
I use Notebook Fan Control in Windows to set 0 RPM if CPU temperature is less then 60 and it rarely gets so hot. I have most of my files on SSD. And believe me, working on a quiet laptop is a miracle!

I've been reading a lot of information on fan control and I see that is a very tough job, compared to RPM display( I will keep trying. Any sort of help is appreciated!

It should be possible to use the data you find in Notebook Fan Control to determine how you can control the fan from ACPI.
Then you can use ACPIPoller.kext to set fan speed in ACPI depending on temperatures... ACPIPoller.kext provides the ability to call an ACPI method (FCPU) once per second.

Just like I did for the ProBook...
 
Thank you RehabMan. After investigating your method of fan control I concluded that is a 'barbaric' method lol. You are manipulating CPU temperature info values! I don't know how Notebook fan control works yet, maybe the same way, or maybe it somehow controls fan power directly, which is probably a better solution.

Using RWEverything I've found out that my CPU Fan is on '93' address.

My DSDT automatically generated:
Offset (0x93),
TH00, 8,
TH01, 8,
TH10, 8,
TH11, 8,
TSTP, 8

...

Method (TACH, 1, Serialized)
{
Name (_T_0, Zero) // _T_x: Emitted by ASL Compiler
If (ECAV ())
{
While (One)
{
Store (Arg0, _T_0)
If (LEqual (_T_0, Zero))
{
Store (B1B2 (TH00, TH01), Local0)
Break
}
ElseIf (LEqual (_T_0, One))
{
Store (B1B2 (TH10, TH11), Local0)
Break
}
Else
{
Return (Ones)
}

Break
}

Multiply (Local0, 0x02, Local0)
If (LNotEqual (Local0, Zero))
{
Divide (0x0041CDB4, Local0, Local1, Local0)
Return (Local0)
}
Else
{
Return (Ones)
}
}
Else
{
Return (Ones)
}
}

TH00 and TH01 are the CPU fan parameters. B1B2 combines them and then they are stored at Local0.
black.dragon74's SSDT-FAN.aml does it better:
...
Method (FAN0, 0, Serialized)
{
Store (B1B2 (\_SB.PCI0.LPCB.EC0.TH00, \_SB.PCI0.LPCB.EC0.TH01), Local0)
If (LEqual (Local0, 0xFF))
{
Store (Zero, Local0)
}

If (Local0)
{
Multiply (Local0, 0x02, Local0)
Divide (0x0041CDB4, Local0, Local1, Local0)
}

Return (Local0)
}
...
Multiply (Local0, 0x02, Local0): as I understood, the 0x02 here is the multiplier. Changing it changes the display FAN RPM. I can say that 02 is the wrong param for my laptop. The display RPM is way too high. I'm still experimenting with Windows to find out the most accurate multiplier.

Now Notebook Fan Control has an xml for my laptop: https://github.com/hirschmann/nbfc/blob/master/Configs/Asus K501LX.xml
It uses '151' Read Register for CPU Fan. But I don't see any clues on how to use that to set new rpm values.

Well, that was just thinking out loud...
It still would be far better to have a working graphic RPM manipulator in Hackintosh.. (
 
Also, tried an app called Macs Fan Control. It displayed an error: "min/max fan values are equal (0)."
 

Attachments

  • Screen Shot 2017-11-28 at 02.55.09.png
    Screen Shot 2017-11-28 at 02.55.09.png
    79.2 KB · Views: 396
Thank you RehabMan. After investigating your method of fan control I concluded that is a 'barbaric' method lol. You are manipulating CPU temperature info values!

Yes.
It is how we trick the BIOS into releasing control over the fan.
NFC (notebook fan control) is doing the same thing.

I don't know how Notebook fan control works yet,

It is open source...

Using RWEverything I've found out that my CPU Fan is on '93' address.

This is CPU fan RPM reading EC register, or something else.
Refer to NBC code/data.

black.dragon74's SSDT-FAN.aml does it better:

The FAN0 method provides fan RPM readings.
It is a good place to start before you move on to fan control.

Now Notebook Fan Control has an xml for my laptop: https://github.com/hirschmann/nbfc/blob/master/Configs/Asus K501LX.xml
It uses '151' Read Register for CPU Fan. But I don't see any clues on how to use that to set new rpm values.

Keep in mind 151 decimal is 0x97 hex.
 
SSDT-FAN has:
Code:
Store ("CPU Fan SSDT by black.dragon74", Debug)
Where does this debug information go? I've searched /var/log and Console app, but couldn't find any occurrence of "CPU Fan SSDT by black.dragon74".

Is this a correct way to debug? Can I debug values with it? Like:
Code:
Store (Local0, debug)
 
Multiply (Local0, 0x02, Local0): as I understood, the 0x02 here is the multiplier. Changing it changes the display FAN RPM. I can say that 02 is the wrong param for my laptop. The display RPM is way too high. I'm still experimenting with Windows to find out the most accurate multiplier.
Wrong. Have a look and your DSDT and you will know.

Let me explain the below code for you from my SSDT (Also, You can't use other machine's ssdt as the formula to convert 16bit value into RPM is different on different systems, unless they are same models, of course)

Code:
Method (FAN0, 0, Serialized)
{
    Store (B1B2 (\_SB.PCI0.LPCB.EC0.TH00, \_SB.PCI0.LPCB.EC0.TH01), Local0)
    If (LEqual (Local0, 0xFF))
    {
        Store (Zero, Local0)
    }

    If (Local0)
    {
        Multiply (Local0, 0x02, Local0)
        Divide (0x0041CDB4, Local0, Local1, Local0)
    }

    Return (Local0)
}
I have created a method Fan0 as required by FakeSMC_ACPISensor.

As you have split 16 bit registers into 8 bits, Method B1B2 combines them together.

So, in the first line we are combining two 8 bits registers AH00 and AH01 and storing it's value into a variable called Local0.

In the line below it, we are using a conditional statement to check, If Local0's value is 255 (i.e. Fan is off) it stores Zero(0) in Local0 (i.e. RPM is zero)

Next, we are checking if Local0 has some value (i.e. not zero)

Then, we multiply the value of Local0 by 2 and then store it int Local0 (i.e. Local0's new value is Local0 x 2)
Then, we divide the value of Local0 by 0x0041CDB4 (4312500) and then store it's value in Local0.

Finally, we return the value of Local0 (i.e. 16bits converted to RPM units). The text above in bold is the formula your dsdt uses to convert bits to RPM.

Attaching a code snippet from your own DSDT for method TACH0:
Code:
Method (TACH, 1, Serialized)
{
    Name (_T_0, Zero)  // _T_x: Emitted by ASL Compiler
    If (ECAV ())
    {
        While (One)
        {
            Store (Arg0, _T_0)
            If (LEqual (_T_0, Zero))
            {
                Store (B1B2 (TH00, TH01), Local0)
                Break
            }
            ElseIf (LEqual (_T_0, One))
            {
                Store (B1B2 (TH10, TH11), Local0)
                Break
            }
            Else
            {
                Return (Ones)
            }

            Break
        }

        Multiply (Local0, 0x02, Local0)
        If (LNotEqual (Local0, Zero))
        {
            Divide (0x0041CDB4, Local0, Local1, Local0)
            Return (Local0)
        }
        Else
        {
            Return (Ones)
        }
    }
    Else
    {
        Return (Ones)
    }
}
Furthermore, you can verify CPU Temp to Fan RPM ratio on Windows and Mac by using HWMonitor. For my 3 ASUS machines, it is same (more precise on macOS). And, my fan does turn off when temp is lower than 32˚C

Regards
 
Where does this debug information go? I've searched /var/log and Console app, but couldn't find any occurrence of "CPU Fan SSDT by black.dragon74".
Set these in your boot-args: debug=0x12a, acpi_layer=0x08, acpi_level=0x02
Then you can use my OSX-Debug script to see kernel log. ACPI logs start with [ACPI Debug]
Can I debug values with it?
Yes. But only values. Don't combine string and variables together. You can use separate entries for both.
Like,
Code:
Store ("Value of local0 is: ", Debug)
Store (Local0, Debug)
Instead of,
Code:
Store ("Value of Local0 is: " + Local 0, Debug) // This will cause kernel panics.
Is this a correct way to debug?
This is the preferred way. You can find such occurrences in your OEM ACPI tables.

Regards
 
black.dragon74, I couldn't see your debug text line anywhere. It turned out that
Code:
Store("Text", Debug)
must be placed inside Method().

I'll continue to experiment and report back...
 
Last edited:
must be placed inside Method()
Yes, as this is a module level code. I am still learning ACPI. 3 days into it, to be precise and I've come a long way. I have something I'd like to show:-
This:
new.png

And This:
old.png


Just in case you didn't know, the scaling that ASUS provided was from 2200 RPM to 2900 RPM. I managed to get it this low and that high!

There's a good reason I love ASUS machines, their ACPI code is very well written.

Earlier, my fan idled at 2200RPM. It now idles between 800 - 1100 RPM.

I have set it to turn off at 32˚C as I don't like turning it off. Fan noise is rarely annoying if it runs below 2400 RPM.

It wouldn't have been possible without @RehabMan answering my silly questions related to ACPI in CLOVER hot patch thread!

It was a nice experience playing around with ACPI code for a whole day (learned a lot TBH).

P.S: @RehabMan what is the use of ShiftRight function in ACPI? Also, can I find explanations of these methods in ACPI spec?

Regards
 
Status
Not open for further replies.
Back
Top