The Ultra96 board needs a fan in order to stay cool, with the standard BSP this fan is run at full speed.
This project shows you how to alter the standard BSP so that the fan speed can be controlled from Linux, or can be controlled by a simple linear algorithm based on processor temperature and fully running in the programmable logic.
First of all a word of warning, we are messing around with the cooling system for the processor here. Leaving the fan totally off for a long period will harm your Ultra96, the default BSP doesn't have over temperature shutdown enabled so if you mess something up here you may melt your Ultra96.
So please only attempt this if you are sure of you abilities, keep an eye on the temperature of the Ultra96 at all times until you are sure the changes you have made are working. You can use the "sensors" command in linux to check the temperature.
Step 1 - Building and Deploying PetaLinux from the BSPYou need to know how to build and deploy PetaLinux from the BSP, the rather wonderful Adam Taylor shows you how to do this here. Make sure you understand everything in his post before continuing.
Step 2 - Add Fan Control Component to Your IP Repository in VivadoFirst you need to clone the component from github:
git clone https://github.com/AndrewCapon/Ultra96FanControl.git
Then either copy the Ultra96_fan_control1.0 older to your IP Repository or add it directly in Vivado: Settings->IP->Repository
Step 3 - Block Diagram ChangesThe following image shows the final block diagram:
You need to add the following IP Components and connect them up as shown in the diagram.
System Management WizardDocumentation can be found here and here.
The System Management Wizard allows us to read the temperature of the processor along with the other sensors.
Set the basic settings as shown on the following image. We are only interested in the temperature sensor so we set it up to use a single channel and to use the DRP interface:
For the On-Chip Sensor settings we only want to enable the "Over Temperature Alarm" and the "User Temperature Alarm".
The "Over Temperature Alarm" will shutdown the processor while running the fan at full speed, this is not a graceful shutdown of linux. I set this at 85C as this is the maximum operational temperature for this grade of chip. This is our "catch all" in case things go really wrong!
The "User Temperature Alarm" will trigger the "Alarm Out" port at 75C, we will use this to force the fan to run at full speed irrespective of any user settings to the fan algorithm:
We need two more components in order to get the System Management component to function, so you also need to add the following:
NotThe reset port "reset_in" resets on high where all the AXI components are resetting on low so we need to invert the reset. In the folder you cloned earlier is a file not.v copy this into your Design Sources and drag it from there onto the block diagram.
ConstantThe Temperate is read from the System Management by setting the status register (DADDR) to 0. As we are only interested in this one reading we can just attach a constant to the daddr_in port, set up the constant as follows:
Now we can add the fan control component, this takes the temperature and user alarm from the System Management component and generates a 12 bit PWM signs to control the voltage sent to the fan.
You need to make sure you have the following constraint in your constraint file:
set_property PACKAGE_PIN F4 [get_ports FAN_PWM]
Also for the over temperature shutdown to work you need to add the following line:
set_property BITSTREAM.CONFIG.OVERTEMPSHUTDOWN ENABLE [current_design]
Now connect everything up as shown in the block diagram at the top, generate the bitstream and follow the instruction from Adam Taylor to build PetaLinux with you new hardware.
2018.3 Vivado ChangesIf you are running 2018.3 you need to make a change to the Zynq component, set GPIO EMIO to 6:
Also the Designer Assistant will try to make the Vp_Vn on the System Management component external, delete anything it attaches to this pin.
Step 4 - TestingWhen you boot the Ultra96 the fan should start on full power and then gradually ramp down over a few seconds. If this doesn't happen something is wrong somewhere, power off the Ultra96 and go back and check everything.
First we will test if we can set the fan speed manually, this is done via register 3. Bit 12 of register 3 toggles manual control on while bits 11 to 0 set the 12 bit PWM value.
You can set this register from linux using "devmem", first check the base address of the fan control component on the address tab in Vivido, on mine it is 0x00_8000_1000.
The address we want is: base address + (4 * register number), so for register 3 we have 0x00_8000_1000 + (4*3) = 0x00_800_100C.
So to put the fan on full we use:
devmem 0x8000100c 32 0x1fff
You should hear the fan ramp up to full speed over a few seconds.
To go back to the automatic control set the register to 0:
devmem 0x8000100c 32 0
The fan should now ramp down to the speed determined by the fan algorithm.
So register 3 can be used to manually control the fan speed when bit 12 is 1. When bit 12 is 0 the fan algorithm takes over.
The fan algorithm works on a linear scale between a low and high temperature, it is not a particularly good fan control algorithm as the voltage control of the fan speed is nonlinear, the PCM voltage output is nonlinear and the cooling from the fan is nonlinear. It works well enough for me though and means the fan is not blasting at full speed all the time.
The algorithm never quite gets to where it should be and oscillates a bit, but I wanted it to run fully on the PL so I kept it simple stupid as my Verilog skills are at the low end of the scale!
To control the fan algorithm register 0 and register 1 are used. Register 0 sets the lower temperature and register 1 sets the higher temperature.
By default these values are 50C to 85C which works well for me here keeping the Ultra96 at about 52C under no load and 54.5C at full load.
If you wanted to keep yours a bit cooler you could set the range to 40C to 75C for example, the values for the registers should be the temperature * 100:
devmem 0x80001000 32 4000
devmem 0x80001004 32 7500
There is one more register 2 which controls the smoothing of the temperature reading and the PWM changes, by default this is 2000. If you would like the changes to be quicker lower this value.
Input Registers- 0 - Temp low setting. C * 100
- 1 - Temp high setting. C * 100
- 2 - Smooth Divisor.
- 3 - PWM Override value. Bit 12 enables. Bits 11-0 PWM value.
- 0 - Temp low setting. C * 100
- 1 - Temp high setting. C * 100
- 2 - Smooth Divisor.
- 3 - PWM Overide value.
- 4 - Unfiltered temperature reading. C * 100
- 5 - Temperature alarm 1=Over Temp
- 6 - State machine state. FAN_OFF=0, FAN_PROCESS=1, FAN_ON=2, FAN_FORCED=3
- 7 - PWM calculated. Fixed 24.8
- 8 - PWM Used. Fixed 24.8
- 9 - Last PWM used. Fixed 24.8
- 10 - Unfiltered temperature reading. C * 100
- 11 - Temperature used. Fixed 24.8
- 12 - Last Temperature used. Fixed 24.8
- 13 - Error between low and actual temperature. Fixed 24.8
- 14 - Linear position between low and high temperature. Fixed 24.8
- 15 - Maximum PWM value.
In the github repository is also a C source file, FanControl.c
If you copy this to your Ultra96 and build it as follows:
gcc FanInfo.c -o FanInfo
Then run it:
./FanInfo
You will see all the register values being updated, this is useful for testing things out:
Fan Control Registers
Temp Low = 5000
Temp High = 8500
Smooth Divisor = 2000
PWM Override = 0 - 0
Temp = 5236
Alarm = 0
Dbg0 (state) = FAN_PROCESS
Dbg1 (PWM) = 287.929688
Dbg2 (usePWM) = 280.121094
Dbg3 (lastPWM) = 280.121094
Dbg4 (Real Temp) = 5236.000000
Dbg5 (Use Temp) = 5253.300781
Dbg6 (last Temp) = 5253.339844
Dbg7 (Error) = 253.339844
Dbg8 (Linear) = 0.070312
Dbg9 (Max PWM) = 4095.000000
Good luck...
Comments