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.
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.
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#
There are three PWM output controls, three tachometer inputs, and two GPIO outputs.
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#
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
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_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.
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.