Thermal Subsystem - And a Change in Direction


#1

Minor Trajectory Change

Originally, I intended to develop the OpenGlow’s drivers and control software independently, and add a compatibility layer for the GFUI later. This approach was largely driven by the expectation that GF’s release of code was not likely to happen soon. With the release of Glowforge’s kernel modules, I’ve opted to change course a bit.

The sooner I can get a functioning system into the wild, the sooner there will be opportunity for others to join the development effort. With that in mind, I am going to focus on making the board work with the existing GFUI first, leveraging the drivers that GF has released.

Thermal Subsystem

I began with the thermal module. This component provides the kernel modules that interface with the intake and exhaust fans, coolant pump, thermoelectric cooler, and a water heater used to detect coolant flow. The full source commit can be viewed here.

I packaged the module in the kernel-module-openglow Yocto recipe located in the meta-openglow\openglow-recipes layer. This produces the openglow.ko module which automatically loads at boot:

openglow: loading out-of-tree module taints kernel.
openglow_init: started
openglow_thermal openglow-thermal: thermal_probe: started
openglow_thermal openglow-thermal: thermal_probe: done
openglow_init: done

As other components are added to the module (i.e. pic, cnc, etc…), they will load here as part of the module’s init process.

Once loaded, the module creates the following sysfs entries to expose the api to user space:

root@openglow_std:/sys/openglow# ls
thermal
root@openglow_std:/sys/openglow# ls thermal
driver           heater_pwm       of_node          tach_exhaust     tec_on
driver_override  intake_pwm       power            tach_intake_1    uevent
exhaust_pwm      modalias         subsystem        tach_intake_2    water_pump_on
root@openglow_std:/sys/openglow# 

User API

There are three PWM output controls, three tachometer inputs, and two GPIO outputs.

PWM Outputs

Hardware PWM’s
The cooling fans are controlled with standard 25 kHz (fixed frequency) PWM outputs, with the two intake fans sharing a common output. These outputs are generated by two of the hardware PWM modules in the SOC. The duty cycle is set by writing a value from 0 - 65535 corresponding to a range of 0 - 100%.
The Glowforge code is based on the legacy PWM interface. To work with the newer kernel, I had to do a little modification, and I will be updating it to the use the modern methods in the near future. This will include changing the control values to be simple percentages instead of the 16 bit integer.

The following sets the exhaust fan to 100% (EFrd: 0xFFFF), and the intake fans to 66% (IFrd: 0xA90E), which is the standard configuration for a program run:

root@openglow_std:/sys/openglow/thermal# echo 65535 >> exhaust_pwm
root@openglow_std:/sys/openglow/thermal# echo 43278 >> intake_pwm
root@openglow_std:/sys/openglow# 

Software PWM
To detect coolant flow, the Glowforge uses two temperature sensors and a heater. One sensor is positioned upstream of the heater, and the other downstream. Theory: By slightly heating the coolant, there will be a detectable difference in the upstream and downstream coolant temperatures - when the coolant is flowing.
I haven’t fully explored this yet. It is also possible that the heater is only used for a short time with the pump off. It would be powered until a temperature rise is detected, at which time powering the pump would quickly drop that temperature indicating that coolant is flowing. This seems more reasonable to me.

The Freescale iMX6 SOC has 4 hardware PWMs. On the Glowforge factory control board, two are used for the cooling fans, one is used for the laser power, and one is used for the speaker. They needed a fifth to control the heater, so they created a software PWM that switches a standard GPIO on and off. This is controlled by writing the desired duty cycle (same values as the cooling fans) to the heater_pwm node.

During the design of the OpenGlow hardware, I was unaware that the heater output was being used as a software PWM, so I assigned it a standard GPIO. However, I chose not to implement the speaker (it seemed silly), leaving the fourth hardware PWM free. It is likely that I will asssign this to the heater in the next hardware revision, freeing up the interrupt/CPU overhead that is currently chewed up by the software PWM.

Fan Tachometer Inputs

Each fan has a tachometer output that is connected to a standard GPIO input, which receives 2 pulses for each fan revolution. The kernel module sets an interrupt to occur on the rising edge of each of these pulses. The interrupt handler records the time between each pulse, and this is available to the user by reading the value tach_exhaust, tach_intake_1, and tach_intake_2. With the PWM values as set in the previous examples, we get readings similiar to these:

root@openglow_std:/sys/devices/soc0/openglow-thermal# cat tach_exhaust 
2434666
root@openglow_std:/sys/devices/soc0/openglow-thermal# cat tach_intake_1
7143334
root@openglow_std:/sys/devices/soc0/openglow-thermal# cat tach_intake_2
7193334

The values are in nanoseconds, and with a little math ( RPM = 60 / ((tach_ns * 2) / 1,000,000,000) ) we can get the RPM values:

EXHAUST: 12,322 RPM
INTAKE 1: 4,200 RPM
INTAKE 2: 4,170 RPM

The interrupt handler has a feature whereby it is smart enough to know when the fans have stopped, so the timer will not keep incrementing forever (and rolling over back to zero).
A future hardware change I am considering is to add a dedicated fan controller that will unload the tachometer duties from the CPU.

General Purpose Outputs

We are also given control over two outputs: the coolant pump, and the thermoelectric cooler (TEC). By writing a 0 (OFF) or a 1(ON) to either of the nodes, we control their state. We can also read the values to determine what their current state is.

For instance, shutting off the coolant pump:

root@openglow_std:/sys/devices/soc0/openglow-thermal# cat water_pump_on 
1
root@openglow_std:/sys/devices/soc0/openglow-thermal# echo 0 > water_pump_on 
root@openglow_std:/sys/devices/soc0/openglow-thermal# cat water_pump_on 
0

In normal operation, the Glowforge factory default state upon power up has the fans and TEC off and the coolant pump on. These are actually set by the bootloader (U-Boot) to ensure it happens even if the system fails to boot its operating system or the kernel module fails to load. I’ll be following this convention with the OpenGlow.

Next Steps

I’m currently porting over the PIC module code to work with the OpenGlow. Both the factory and OpenGlow boards utilize a PIC microcontroller as an analog IO controller - providing 4 PWM outpus, 2 DAC outputs, and numerous ADC inputs. The factory Glowforge uses the SPI bus to communicate with the PIC, while the OpenGlow uses I2C. Once this component is complete, the user space API to the LED’s, HV voltage/current, and numerous temperature sensors will be in place. After that, I’ll move on to the CNC module which controls all motion and laser functions.


Analog I/O Subsystem
#2

Out of curiosity and complete ignorance, would it be possible for your firmware to effectively be a target for LightBurn?


#3

I don’t see any reason why not.

Two possibilities come immediately to mind (not limited to these, just the first couple that popped into my head):

  1. LightBurn adds support to their software for whatever formats/interfaces OpenGlow winds up with.
  2. Support is added to OpenGlow for formats/interfaces that LightBurn already supports.

LightBurn says on their website that if the controller supports G-Code, then it will likely be supported by LightBurn. Since G-Code support is high on the priority list of features, I think the answer is a ‘yes’. :slight_smile:

And, since the OpenGlow is Open Source, any other capabilities it needed for it to be fully supported by LightBurn could be added by anyone.


#4

That would be quite cool, I would think.

In particular (and, again, from a point of ignorance), it seems LIghtBurn is a kind of repeatable, document based, approach to driving a laser cutter whereas the Glowforge seems more focused on “shove identified material in, get decent result out automatically”.

Different goals. I’d bet a lot of people would find the LightBurn approach to be very attractive.