2020-04-09 13:16:30 +08:00
# Firmware for the Sinara 8451 Thermostat
2020-03-24 06:03:58 +08:00
2022-01-19 11:37:01 +08:00
- [x] [Continuous Integration ](https://nixbld.m-labs.hk/job/mcu/thermostat/thermostat )
- [x] Download latest firmware build: [ELF ](https://nixbld.m-labs.hk/job/mcu/thermostat/thermostat/latest/download/1 ) [BIN ](https://nixbld.m-labs.hk/job/mcu/thermostat/thermostat/latest/download/2 )
2020-03-24 06:42:22 +08:00
2020-03-24 06:03:58 +08:00
## Building
2020-12-09 10:16:40 +08:00
### Reproducible build with Nix
2022-01-19 11:13:47 +08:00
Thermostat firmware is packaged using the [Nix ](https://nixos.org ) Flakes system. Install Nix 2.4+ and enable flakes by adding ``experimental-features = nix-command flakes`` to ``nix.conf`` (e.g. ``~/.config/nix/nix.conf``).
Once you have Flakes enabled, you can use ``nix build`` to build the firmware.
2020-12-09 10:16:40 +08:00
2022-01-05 08:04:25 +08:00
### Development environment
2020-03-24 06:03:58 +08:00
2022-01-19 11:13:47 +08:00
Clone this repository and with Nix Flakes enabled, use the following commands:
2020-03-24 06:03:58 +08:00
```shell
2022-01-19 11:13:47 +08:00
nix develop
2020-03-24 06:03:58 +08:00
cargo build --release
```
2022-01-19 11:13:47 +08:00
The resulting ELF file will be located under `target/thumbv7em-none-eabihf/release/thermostat` .
2020-03-24 06:03:58 +08:00
2022-01-19 11:13:47 +08:00
Alternatively, you can install the Rust toolchain without Nix using rustup; see the Rust manifest file pulled in `flake.nix` to determine which Rust version to use.
2022-01-05 08:04:25 +08:00
2020-12-07 07:21:09 +08:00
## Debugging
Connect SWDIO/SWCLK/RST/GND to a programmer such as ST-Link v2.1. Run OpenOCD:
```shell
2024-01-04 11:59:41 +08:00
openocd -f interface/stlink.cfg -f target/stm32f4x.cfg
2020-12-07 07:21:09 +08:00
```
You may need to power up the programmer before powering the device.
Leave OpenOCD running. Run the GNU debugger:
```shell
gdb target/thumbv7em-none-eabihf/release/thermostat
(gdb) source openocd.gdb
```
## Flashing
2020-12-09 10:16:40 +08:00
There are several options for flashing Thermostat. DFU requires only a micro-USB connector, whereas OpenOCD needs a JTAG/SWD adapter.
2020-12-09 00:07:48 +08:00
2020-12-09 10:16:40 +08:00
### dfu-util on Linux
2020-12-09 00:07:48 +08:00
* Install the DFU USB tool (dfu-util).
2024-08-07 18:22:48 +08:00
* Convert firmware from ELF to BIN: `llvm-objcopy -O binary target/thumbv7em-none-eabihf/release/thermostat thermostat.bin` (you can skip this step if using the BIN from Hydra)
2020-12-09 00:07:48 +08:00
* Connect to the Micro USB connector to Thermostat below the RJ45.
* Add jumper to Thermostat v2.0 across 2-pin jumper adjacent to JTAG connector.
* Cycle board power to put it in DFU update mode
2020-12-09 10:16:40 +08:00
* Push firmware to flash: `dfu-util -a 0 -s 0x08000000:leave -D thermostat.bin`
2020-12-09 00:07:48 +08:00
* Remove jumper
* Cycle power to leave DFU update mode
2020-12-09 10:16:40 +08:00
### st.com DfuSe tool on Windows
On a Windows machine install [st.com ](https://st.com ) DfuSe USB device firmware upgrade (DFU) software. [link ](https://www.st.com/en/development-tools/stsw-stm32080.html ).
2020-12-09 00:07:48 +08:00
- add jumper to Thermostat v2.0 across 2-pin jumper adjacent to JTAG connector
- cycle board power to put it in DFU update mode
- connect micro-USB to PC
- use st.com software to upload firmware
- remove jumper
- cycle power to leave DFU update mode
2020-12-09 10:16:40 +08:00
### OpenOCD
2020-12-07 07:21:09 +08:00
```shell
2024-01-04 11:59:41 +08:00
openocd -f interface/stlink.cfg -f target/stm32f4x.cfg -c "program target/thumbv7em-none-eabihf/release/thermostat verify reset;exit"
2020-12-07 07:21:09 +08:00
```
2020-03-24 06:03:58 +08:00
## Network
2020-03-24 06:42:22 +08:00
### Connecting
2020-03-24 06:03:58 +08:00
Ethernet, IP: 192.168.1.26/24
Use netcat to connect to port 23/tcp (telnet)
2020-03-24 06:42:22 +08:00
```sh
2020-12-19 04:27:09 +08:00
rlwrap nc -vv 192.168.1.26 23
2020-03-24 06:42:22 +08:00
```
2020-03-24 06:03:58 +08:00
telnet clients send binary data after connect. Enter \n once to
invalidate the first line of input.
### Reading ADC input
2024-09-16 11:52:15 +08:00
ADC input data is provided in reports. Query for the latest report with the command `report` . See the *Reports* section below.
2020-03-24 06:03:58 +08:00
2020-12-17 05:14:21 +08:00
### TCP commands
Send commands as simple text string terminated by `\n` . Responses are
formatted as line-delimited JSON.
2020-03-24 06:03:58 +08:00
2024-08-20 17:42:44 +08:00
| Syntax | Function |
|------------------------------------------- |-------------------------------------------------------------------------------|
| `report` | Show current input |
| `pwm` | Show current PWM settings |
2024-08-16 12:39:10 +08:00
| `pwm <0/1> max_i_pos <amp>` | Set maximum positive output current, clamped to [0, 2] |
| `pwm <0/1> max_i_neg <amp>` | Set maximum negative output current, clamped to [0, 2] |
| `pwm <0/1> max_v <volt>` | Set maximum output voltage, clamped to [0, 4] |
| `pwm <0/1> i_set <amp>` | Disengage PID, set fixed output current, clamped to [-2, 2] |
2024-08-20 17:42:44 +08:00
| `pwm <0/1> polarity <normal/reversed>` | Set output current polarity, with 'normal' being the front panel polarity |
| `pwm <0/1> pid` | Let output current to be controlled by the PID |
| `center <0/1> <volt>` | Set the MAX1968 0A-centerpoint to the specified fixed voltage |
| `center <0/1> vref` | Set the MAX1968 0A-centerpoint to measure from VREF |
| `pid` | Show PID configuration |
| `pid <0/1> target <deg_celsius>` | Set the PID controller target temperature |
| `pid <0/1> kp <value>` | Set proportional gain |
| `pid <0/1> ki <value>` | Set integral gain |
| `pid <0/1> kd <value>` | Set differential gain |
| `pid <0/1> output_min <amp>` | Set mininum output |
| `pid <0/1> output_max <amp>` | Set maximum output |
| `s-h` | Show Steinhart-Hart equation parameters |
| `s-h <0/1> <t0/b/r0> <value>` | Set Steinhart-Hart parameter for a channel |
| `postfilter` | Show postfilter settings |
| `postfilter <0/1> off` | Disable postfilter |
| `postfilter <0/1> rate <rate>` | Set postfilter output data rate |
| `load [0/1]` | Restore configuration for channel all/0/1 from flash |
| `save [0/1]` | Save configuration for channel all/0/1 to flash |
| `reset` | Reset the device |
| `dfu` | Reset device and enters USB device firmware update (DFU) mode |
| `ipv4 <X.X.X.X/L> [Y.Y.Y.Y]` | Configure IPv4 address, netmask length, and optional default gateway |
| `fan` | Show current fan settings and sensors' measurements |
| `fan <value>` | Set fan power with values from 1 to 100 |
| `fan auto` | Enable automatic fan speed control |
| `fcurve <a> <b> <c>` | Set fan controller curve coefficients (see *Fan control* section) |
| `fcurve default` | Set fan controller curve coefficients to defaults (see *Fan control* section) |
| `hwrev` | Show hardware revision, and settings related to it |
2020-10-11 02:50:57 +08:00
## USB
The firmware includes experimental support for acting as a USB-Serial
peripheral. Debug logging will be sent there by default (unless build
with logging via semihosting.)
**Caveat:** This logging does not flush its output. Doing so would
hang indefinitely if the output is not read by the USB host. Therefore
2020-12-07 07:21:09 +08:00
output will be truncated when USB buffers are full.
2020-10-12 03:08:02 +08:00
## Temperature measurement
Connect the thermistor with the SENS pins of the
device. Temperature-depending resistance is measured by the AD7172
ADC. To prepare conversion to a temperature, set the Beta parameters
for the Steinhart-Hart equation.
Set the base temperature in degrees celsius for the channel 0 thermistor:
```
s-h 0 t0 20
```
Set the resistance in Ohms measured at the base temperature t0:
```
s-h 0 r0 10000
```
Set the Beta parameter:
```
s-h 0 b 3800
```
2020-12-19 04:27:09 +08:00
### 50/60 Hz filtering
2020-12-17 03:47:18 +08:00
The AD7172-2 ADC on the SENS inputs supports simultaneous rejection of
50 Hz ± 1 Hz and 60 Hz ± 1 Hz (dB). Affecting sampling rate, the
postfilter rate can be tuned with the `postfilter` command.
| Postfilter rate | Rejection | Effective sampling rate |
| --- | :---: | --- |
| 16.67 Hz | 92 dB | 8.4 Hz |
| 20 Hz | 86 dB | 9.1 Hz |
| 21.25 Hz | 62 dB | 10 Hz |
| 27 Hz | 47 dB | 10.41 Hz |
2020-10-12 03:08:02 +08:00
## Thermo-Electric Cooling (TEC)
2021-01-25 13:11:55 +08:00
- Connect TEC module device 0 to TEC0- and TEC0+.
- Connect TEC module device 1 to TEC1- and TEC1+.
- The GND pin is for shielding not for sinking TEC module currents.
2022-06-06 21:28:30 +08:00
When using a TEC module with the Thermostat, the Thermostat expects the thermal load (where the thermistor is located) to cool down with a positive software current set point, and heat up with a negative current set point.
2021-01-25 13:11:55 +08:00
2024-08-20 17:42:44 +08:00
If the Thermostat is used for temperature control with the Sinara 5432 DAC "Zotino", and is connected via an IDC cable, the TEC polarity may need to be reversed with the `pwm <ch> polarity reversed` TCP command.
2021-01-25 13:11:55 +08:00
Testing heat flow direction with a low set current is recommended before installation of the TEC module.
2020-10-12 03:50:36 +08:00
2024-10-14 11:33:41 +08:00
## Resistive Heater
When using resistive heaters with the Thermostat, ensure that the thermal load has sufficient cooling, and connect the heater to TEC0- and TEC0+ or TEC1- and TEC1+.
Then, set `max_i_neg` and `output_min` to 0 A with `pwm <ch> max_i_neg 0` and `pid <ch> output_min 0` , and make sure that `output_max` is non-negative.
2020-10-12 03:08:02 +08:00
### Limits
Each of the MAX1968 TEC driver has analog/PWM inputs for setting
output limits.
Use the `pwm` command to see current settings and maximum values.
2020-12-09 08:07:08 +08:00
| Limit | Unit | Description |
| --- | :---: | --- |
| `max_v` | Volts | Maximum voltage |
| `max_i_pos` | Amperes | Maximum positive current |
| `max_i_neg` | Amperes | Maximum negative current |
| `i_set` | Amperes | (Not a limit; Open-loop mode) |
2020-10-12 03:08:02 +08:00
Example: set the maximum voltage of channel 0 to 1.5 V.
```
pwm 0 max_v 1.5
```
2021-01-25 13:11:55 +08:00
Example: set the maximum negative current of channel 0 to -3 A.
```
pwm 0 max_i_neg 3
```
Example: set the maximum positive current of channel 1 to 3 A.
```
pwm 0 max_i_pos 3
```
2020-10-12 03:08:02 +08:00
### Open-loop mode
To manually control TEC output current, omit the limit parameter of
the `pwm` command. Doing so will disengage the PID control for that
channel.
Example: set output current of channel 0 to 0 A.
```
2020-12-09 08:07:08 +08:00
pwm 0 i_set 0
2020-10-12 03:08:02 +08:00
```
## PID-stabilized temperature control
Set the target temperature of channel 0 to 20 degrees celsius:
```
pid 0 target 20
```
Enter closed-loop mode by switching control of the TEC output current
of channel 0 to the PID algorithm:
```
pwm 0 pid
```
2020-10-12 03:50:36 +08:00
## LED indicators
| Name | Color | Meaning |
| --- | :---: | --- |
2020-10-12 06:26:49 +08:00
| L1 | Red | Firmware initializing |
| L3 | Green | Closed-loop mode (PID engaged) |
| L4 | Green | Firmware busy |
2020-10-12 03:50:36 +08:00
2020-10-12 03:08:02 +08:00
## Reports
2024-09-16 11:52:15 +08:00
Use the bare `report` command to obtain a single report. Reports are JSON objects
2020-10-12 03:08:02 +08:00
with the following keys.
2020-10-12 03:09:15 +08:00
2020-10-12 03:08:02 +08:00
| Key | Unit | Description |
| --- | :---: | --- |
| `channel` | Integer | Channel `0` , or `1` |
2023-07-20 17:33:29 +08:00
| `time` | Seconds | Temperature measurement time |
2020-10-12 03:08:02 +08:00
| `adc` | Volts | AD7172 input |
| `sens` | Ohms | Thermistor resistance derived from `adc` |
| `temperature` | Degrees Celsius | Steinhart-Hart conversion result derived from `sens` |
| `pid_engaged` | Boolean | `true` if in closed-loop mode |
| `i_set` | Amperes | TEC output current |
| `dac_value` | Volts | AD5680 output derived from `i_set` |
| `dac_feedback` | Volts | ADC measurement of the AD5680 output |
| `i_tec` | Volts | MAX1968 TEC current monitor |
| `tec_i` | Amperes | TEC output current feedback derived from `i_tec` |
| `tec_u_meas` | Volts | Measurement of the voltage across the TEC |
| `pid_output` | Amperes | PID control output |
2021-01-07 14:48:39 +08:00
2024-05-02 17:48:47 +08:00
Note: With Thermostat v2 and below, the voltage and current readouts `i_tec` and `tec_i` are noisy without the hardware fix shown in [this PR][https://git.m-labs.hk/M-Labs/thermostat/pulls/105].
2021-01-07 14:48:39 +08:00
## PID Tuning
The thermostat implements a PID control loop for each of the TEC channels, more details on setting up the PID control loop can be found [here ](./doc/PID%20tuning.md ).
2023-03-22 17:15:49 +08:00
## Fan control
2023-08-24 12:30:46 +08:00
Fan control commands are available for thermostat revisions with an integrated fan system:
2023-03-22 17:15:49 +08:00
1. `fan` - show fan stats: `fan_pwm` , `abs_max_tec_i` , `auto_mode` , `k_a` , `k_b` , `k_c` .
2023-08-24 12:30:46 +08:00
2. `fan auto` - enable auto speed controller mode, where fan speed is controlled by the fan curve `fcurve` .
3. `fan <value>` - set the fan power with the value from `1` to `100` and disable auto mode. There is no way to completely disable the fan.
2023-03-22 17:15:49 +08:00
Please note that power doesn't correlate with the actual speed linearly.
2023-08-24 12:30:46 +08:00
4. `fcurve <a> <b> <c>` - set coefficients of the controlling curve `a*x^2 + b*x + c` , where `x` is `abs_max_tec_i/MAX_TEC_I` , a normalized value in range [0,1],
i.e. the (linear) proportion of current output capacity used, on the channel with the largest current flow. The controlling curve is also clamped to [0,1].
5. `fcurve default` - restore fan curve coefficients to defaults: `a = 1.0, b = 0.0, c = 0.0` .