diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml
--- a/.settings/language.settings.xml
+++ b/.settings/language.settings.xml
@@ -5,7 +5,7 @@
-
+
@@ -16,7 +16,7 @@
-
+
diff --git a/inc/display.h b/inc/display.h
--- a/inc/display.h
+++ b/inc/display.h
@@ -7,7 +7,7 @@
#include "max31865.h"
#endif
-void display_startup_screen();
-void display_process(therm_status_t* status);
+void display_startup_screen(void);
+void display_process(void);
#endif
diff --git a/inc/pid.h b/inc/pid.h
--- a/inc/pid.h
+++ b/inc/pid.h
@@ -10,7 +10,8 @@ typedef struct {
int32_t i_state;
} pid_state_t;
-void pid_init(pid_state_t* state);
-int16_t pid_update(therm_settings_t* set, therm_status_t* status, pid_state_t* state);
+void pid_init(void);
+float pid_process(void);
+int16_t pid_update(void);
#endif
diff --git a/inc/pwmout.h b/inc/pwmout.h
new file mode 100644
--- /dev/null
+++ b/inc/pwmout.h
@@ -0,0 +1,9 @@
+#ifndef PWMOUT_H
+#define PWMOUT_H
+
+
+void pwmout_init(void);
+void pwmout_process(float duty);
+
+
+#endif
diff --git a/inc/states.h b/inc/states.h
--- a/inc/states.h
+++ b/inc/states.h
@@ -5,11 +5,10 @@
#include "config.h"
typedef struct {
- int32_t temp;
- uint8_t temp_frac;
+ float temp;
uint8_t state_resume;
uint8_t state;
- int32_t setpoint;
+ float setpoint;
uint8_t pid_enabled;
uint8_t error_code;
} therm_status_t;
diff --git a/inc/system/flash.h b/inc/system/flash.h
--- a/inc/system/flash.h
+++ b/inc/system/flash.h
@@ -13,4 +13,7 @@ void flash_savesettings(void);
void flash_restoresettings(void);
therm_settings_t* flash_getsettings(void);
+therm_status_t* runtime_status(void);
+
+
#endif // flash_h
diff --git a/inc/tempsense.h b/inc/tempsense.h
new file mode 100644
--- /dev/null
+++ b/inc/tempsense.h
@@ -0,0 +1,8 @@
+#ifndef TEMPSENSE_H
+#define TEMPSENSE_H
+
+
+void tempsense_init(void);
+float tempsense_readtemp(void);
+
+#endif
diff --git a/inc/thermostat.h b/inc/thermostat.h
new file mode 100644
--- /dev/null
+++ b/inc/thermostat.h
@@ -0,0 +1,10 @@
+#ifndef THERMOSTAT_H
+#define THERMOSTAT_H
+
+#include "stm32f3xx_hal.h"
+
+
+float thermostat_process(void);
+
+
+#endif
diff --git a/src/display.c b/src/display.c
--- a/src/display.c
+++ b/src/display.c
@@ -39,15 +39,17 @@ static uint8_t reset_mode = RESET_REBOOT
// Display state machine
-void display_process(therm_status_t* status)
+void display_process(void)
{
+ therm_status_t* status = runtime_status();
therm_settings_t* set = flash_getsettings();
+
+
uint8_t state_changed = status->state != last_state;
last_state = status->state;
- uint8_t temp_changed = status->temp != last_temp || status->temp_frac != last_temp_frac;
+ uint8_t temp_changed = status->temp != last_temp;
last_temp = status->temp;
- last_temp_frac = status->temp_frac;
uint8_t sw_btn = !HAL_GPIO_ReadPin(SW_BTN);
uint8_t sw_up = !HAL_GPIO_ReadPin(SW_UP);
@@ -67,7 +69,7 @@ void display_process(therm_status_t* sta
if(temp_changed || state_changed) {
char tempstr[6];
- itoa_fp(status->temp, status->temp_frac, tempstr);
+// itoa_fp(status->temp, status->temp_frac, tempstr);
ssd1306_drawstring("Temp: ", 3, 40);
ssd1306_drawstring(" ", 3, 72);
ssd1306_drawstring(tempstr, 3, 72);
@@ -656,19 +658,18 @@ void display_process(therm_status_t* sta
}
-static int32_t temp_last = 43002;
-static int32_t temp_frac_last = 43002;
-static int32_t setpoint_last = 10023;
+static float temp_last = 43002.0;
+static float setpoint_last = 10023.0;
// Draw current setpoint on display
static void draw_setpoint(therm_status_t* status) {
// FIXME: need to do this when switching modes too
- if(status->temp != temp_last || status->temp_frac != temp_frac_last || trigger_drawsetpoint) {
- char tempstr[3];
- itoa_fp(status->temp, status->temp_frac, tempstr);
- ssd1306_drawstringbig(" ", 3, 0);
- ssd1306_drawstringbig(tempstr, 3, 0);
- }
+// if(status->temp != temp_last || trigger_drawsetpoint) {
+// char tempstr[3];
+// itoa_fp(status->temp, status->temp_frac, tempstr);
+// ssd1306_drawstringbig(" ", 3, 0);
+// ssd1306_drawstringbig(tempstr, 3, 0);
+// }
if(trigger_drawsetpoint)
ssd1306_drawstringbig(">", 3, 74);
@@ -683,7 +684,6 @@ static void draw_setpoint(therm_status_t
trigger_drawsetpoint = 0;
setpoint_last = status->setpoint;
temp_last = status->temp;
- temp_frac_last = status->temp_frac;
}
void display_startup_screen() {
diff --git a/src/main.c b/src/main.c
--- a/src/main.c
+++ b/src/main.c
@@ -6,20 +6,17 @@
#include "stm32f3xx_hal.h"
#include "config.h"
-
#include "watchdog.h"
#include "system.h"
#include "display.h"
+#include "thermostat.h"
#include "gpio.h"
+#include "tempsense.h"
#include "pid.h"
#include "error.h"
#include "flash.h"
#include "ssd1306/ssd1306.h"
-#include "interrupts.h"
-
-
-therm_status_t status;
-pid_state_t pid_state;
+#include "pwmout.h"
int main(void)
@@ -28,7 +25,6 @@ int main(void)
hal_init();
gpio_init();
-
ssd1306_init();
// Startup screen
@@ -37,149 +33,46 @@ int main(void)
ssd1306_drawlogo();
-
+ // Default status
+ runtime_status()->temp = 0.0;
+ runtime_status()->state_resume = 0;
+ runtime_status()->state = STATE_IDLE;
+ runtime_status()->setpoint = 70;
+ runtime_status()->pid_enabled = 0;
- // Default status
- status.temp = 0;
- status.temp_frac = 0;
- status.state_resume = 0;
- status.state = STATE_IDLE;
- status.setpoint = 70;
- status.pid_enabled = 0;
-
- pid_init(&pid_state);
-
+ pid_init();
+ pwmout_init();
flash_init();
watchdog_init();
-
+ tempsense_init();
// Soft timers
- uint32_t last_ssr_on = 0;
- uint32_t last_vcp_tx = 0;
- uint32_t last_led = 0;
uint32_t last_pid = 0;
uint32_t last_thermostat = 0;
- int16_t ssr_output = 0; // Duty cycle of ssr, 0 to SSR_PERIOD
- uint8_t thermostat_plant_on = 0;
-
while (1)
{
+ float duty = 0.0;
if(flash_getsettings()->val.control_mode == MODE_PID && (HAL_GetTick() - last_pid > PID_PERIOD))
{
-
-// #ifdef MAX31865_RTD_SENSOR
-// max31865_readtemp(spi_get(), &set, &status);
-// #else
-// max31855_readtemp(spi_get(), &set, &status); // Read MAX31855
-// #endif
-
-
- if(status.pid_enabled)
- {
- // Get ssr output for next time
- int16_t power_percent = pid_update(flash_getsettings(), &status, &pid_state);
-
- if(flash_getsettings()->val.plant_type == PLANT_HEATER)
- power_percent *= -1;
-
- //power-percent is 0-1000?
- ssr_output = power_percent; //(((uint32_t)SSR_PERIOD * (uint32_t)10 * (uint32_t)100) * power_percent) / (uint32_t)1000000;
-
-
- // put ssr output on display
- ssd1306_drawstring(" ", 0, 90); //fixme: this is bad, but I can't get the old digits to clear otherwise
- char tempstr[6];
- itoa(ssr_output, tempstr, 10);
- ssd1306_drawstring(tempstr, 0, 90);
- }
- else
- {
- ssr_output = 0;
- }
-
+ runtime_status()->temp = tempsense_readtemp();
+ duty = pid_process();
last_pid = HAL_GetTick();
}
-// // Kill SSR once the desired on-time has elapsed
-// if(set.val.control_mode == MODE_PID && (HAL_GetTick() - last_ssr_on > ssr_output || ssr_output <= 0))
-// {
-// HAL_GPIO_WritePin(SSR_PIN, 0);
-// HAL_GPIO_WritePin(LED_POWER, 0);
-// }
-//
-//
-// // Every 200ms, set the SSR on unless output is 0
-// if(set.val.control_mode == MODE_PID && HAL_GetTick() - last_ssr_on > SSR_PERIOD)
-// {
-// // Heat or cool, if we need to
-// if(ssr_output > 0)
-// {
-// HAL_GPIO_WritePin(SSR_PIN, 1);
-// HAL_GPIO_WritePin(LED_POWER, 1);
-// last_ssr_on = HAL_GetTick();
-// }
-// else {
-// // Make sure everything is off
-// HAL_GPIO_WritePin(SSR_PIN, 0);
-// HAL_GPIO_WritePin(LED_POWER, 0);
-// }
-//
-// }
-
-
// Thermostatic control
if(flash_getsettings()->val.control_mode == MODE_THERMOSTAT && HAL_GetTick() - last_thermostat > SSR_PERIOD)
{
-
-// #ifdef MAX31865_RTD_SENSOR
-// max31865_readtemp(spi_get(), &set, &status);
-// #else
-// max31855_readtemp(spi_get(), &set, &status); // Read MAX31855
-// #endif
-
- // TODO: Migrate this FxP conversion to the readtemp code or similar
- int8_t temp_frac = status.temp_frac > 9 ? status.temp_frac / 10 : status.temp_frac;
- temp_frac = status.temp > 0 ? temp_frac : temp_frac * -1;
- int32_t temp = (status.temp * 10) + temp_frac;
-
-
- // EMZ FIXME: This could be way simpler
- if(flash_getsettings()->val.plant_type == PLANT_HEATER && status.setpoint * 10 < temp - flash_getsettings()->val.hysteresis * 10)
- thermostat_plant_on = 1;
- else if(flash_getsettings()->val.plant_type == PLANT_HEATER && status.setpoint * 10 > temp + flash_getsettings()->val.hysteresis * 10)
- thermostat_plant_on = 0;
-
- if(flash_getsettings()->val.plant_type == PLANT_COOLER && status.setpoint * 10 > temp + flash_getsettings()->val.hysteresis * 10)
- thermostat_plant_on = 1;
- else if(flash_getsettings()->val.plant_type == PLANT_COOLER && status.setpoint * 10 < temp - flash_getsettings()->val.hysteresis * 10)
- thermostat_plant_on = 0;
-
- // EMZ: TODO: Refactor to output_enabled or something
- if(status.pid_enabled && thermostat_plant_on)
- {
- // EMZ TODO: functionalize this
- // put ssr output on display
- ssd1306_drawstring(" ", 0, 90); //fixme: this is bad, but I can't get the old digits to clear otherwise
- char tempstr[6];
- itoa(ssr_output, tempstr, 10);
- ssd1306_drawstring(tempstr, 0, 90);
-
-
-
-// HAL_GPIO_WritePin(SSR_PIN, 1);
- HAL_GPIO_WritePin(LED, 1);
- }
- else
- {
-// HAL_GPIO_WritePin(SSR_PIN, 0);
- HAL_GPIO_WritePin(LED, 0);
- }
-
+ runtime_status()->temp = tempsense_readtemp();
+ duty = thermostat_process();
last_thermostat = HAL_GetTick();
}
+ pwmout_process(duty);
+ display_process();
+ watchdog_feed();
+
// // Transmit temperature over USB-CDC on a regular basis
// if(HAL_GetTick() - last_vcp_tx > VCP_TX_FREQ)
@@ -198,10 +91,6 @@ int main(void)
// last_vcp_tx = HAL_GetTick();
// }
- // Run state machine
- display_process(&status);
-
- watchdog_feed();
}
}
diff --git a/src/pid.c b/src/pid.c
--- a/src/pid.c
+++ b/src/pid.c
@@ -3,23 +3,64 @@
//
#include "pid.h"
+#include "flash.h"
// PID implementation
-void pid_init(pid_state_t* state)
+static pid_state_t state;
+
+
+void pid_init()
{
- state->i_state = 0;
- state->last_pid_temp = 0;
- state->last_pid_temp_frac = 0;
+ state.i_state = 0;
+ state.last_pid_temp = 0;
+ state.last_pid_temp_frac = 0;
}
-int16_t pid_update(therm_settings_t* set, therm_status_t* status, pid_state_t *state)
+float pid_process(void)
{
+// #ifdef MAX31865_RTD_SENSOR
+// max31865_readtemp(spi_get(), &set, &status);
+// #else
+// max31855_readtemp(spi_get(), &set, &status); // Read MAX31855
+// #endif
+
+ float ssr_output = 0;
+
+
+ if(runtime_status()->pid_enabled)
+ {
+ // Get ssr output for next time
+ int16_t power_percent = pid_update();
+
+ if(flash_getsettings()->val.plant_type == PLANT_HEATER)
+ power_percent *= -1;
+
+ //power-percent is 0-1000?
+ ssr_output = power_percent; //(((uint32_t)SSR_PERIOD * (uint32_t)10 * (uint32_t)100) * power_percent) / (uint32_t)1000000;
+
+ // put ssr output on display
+ ssd1306_drawstring(" ", 0, 90); //fixme: this is bad, but I can't get the old digits to clear otherwise
+ char tempstr[6];
+ itoa(ssr_output, tempstr, 10);
+ ssd1306_drawstring(tempstr, 0, 90);
+ }
+ else
+ {
+ ssr_output = 0.0;
+ }
+
+ return ssr_output;
+}
+
+int16_t pid_update(void)
+{
+ therm_status_t* status = runtime_status();
+ therm_settings_t* set = flash_getsettings();
+
// Convert temperature to fixed point number with 1/10th resolution
- int8_t temp_frac = status->temp_frac > 9 ? status->temp_frac / 10 : status->temp_frac;
- temp_frac = status->temp > 0 ? temp_frac : temp_frac * -1;
- int32_t temp = (status->temp * 10) + temp_frac;
+ float temp = status->temp;
// Calculate instantaneous error
int16_t error = status->setpoint * 10 - temp; // TODO: Use fixed point fraction
@@ -28,7 +69,7 @@ int16_t pid_update(therm_settings_t* set
int32_t p_term = set->val.k_p * error;
// Error accumulator (integrator)
- state->i_state += error;
+ state.i_state += error;
// to prevent the iTerm getting huge from lots of
// error, we use a "windup guard"
@@ -39,18 +80,18 @@ int16_t pid_update(therm_settings_t* set
int32_t windup_guard_res = (set->val.windup_guard * 10) / set->val.k_i;
// Calculate integral term with windup guard
- if (state->i_state > windup_guard_res)
- state->i_state = windup_guard_res;
- else if (state->i_state < -windup_guard_res)
- state->i_state = -windup_guard_res;
+ if (state.i_state > windup_guard_res)
+ state.i_state = windup_guard_res;
+ else if (state.i_state < -windup_guard_res)
+ state.i_state = -windup_guard_res;
- int32_t i_term = set->val.k_i * state->i_state;
+ int32_t i_term = set->val.k_i * state.i_state;
// Calculate differential term (slope since last iteration)
- int32_t d_term = (set->val.k_d * (temp - state->last_pid_temp));
+ int32_t d_term = (set->val.k_d * (temp - state.last_pid_temp));
// Save temperature for next iteration
- state->last_pid_temp = temp;
+ state.last_pid_temp = temp;
int16_t result = (p_term + i_term - d_term) / 10;
diff --git a/src/pwmout.c b/src/pwmout.c
new file mode 100644
--- /dev/null
+++ b/src/pwmout.c
@@ -0,0 +1,49 @@
+//
+// PWM Out: generate PWM waveform to control factory
+//
+
+#include "pwmout.h"
+#include "flash.h"
+
+
+static uint32_t last_ssr_on = 0;
+static uint32_t last_vcp_tx = 0;
+static uint32_t last_led = 0;
+
+
+void pwmout_init(void)
+{
+
+}
+
+void pwmout_process(float duty)
+{
+
+ // // Kill SSR once the desired on-time has elapsed
+ // if(set.val.control_mode == MODE_PID && (HAL_GetTick() - last_ssr_on > ssr_output || ssr_output <= 0))
+ // {
+ // HAL_GPIO_WritePin(SSR_PIN, 0);
+ // HAL_GPIO_WritePin(LED_POWER, 0);
+ // }
+ //
+ //
+ // // Every 200ms, set the SSR on unless output is 0
+ // if(set.val.control_mode == MODE_PID && HAL_GetTick() - last_ssr_on > SSR_PERIOD)
+ // {
+ // // Heat or cool, if we need to
+ // if(ssr_output > 0)
+ // {
+ // HAL_GPIO_WritePin(SSR_PIN, 1);
+ // HAL_GPIO_WritePin(LED_POWER, 1);
+ // last_ssr_on = HAL_GetTick();
+ // }
+ // else {
+ // // Make sure everything is off
+ // HAL_GPIO_WritePin(SSR_PIN, 0);
+ // HAL_GPIO_WritePin(LED_POWER, 0);
+ // }
+ //
+ // }
+}
+
+
diff --git a/src/system/flash.c b/src/system/flash.c
--- a/src/system/flash.c
+++ b/src/system/flash.c
@@ -10,6 +10,7 @@
static __attribute__((__section__(".eeprom"))) uint16_t eeprom_emulation[512];
therm_settings_t settings;
+therm_status_t status;
// Initialize flash and restore settings
void flash_init(void)
@@ -78,3 +79,9 @@ inline therm_settings_t* flash_getsettin
{
return &settings;
}
+
+inline therm_status_t* runtime_status(void)
+{
+ return &status;
+}
+
diff --git a/src/tempsense.c b/src/tempsense.c
new file mode 100644
--- /dev/null
+++ b/src/tempsense.c
@@ -0,0 +1,24 @@
+//
+// TempSense: read temperature from TC, RTD, or NTC
+//
+
+#include "tempsense.h"
+#include "flash.h"
+
+
+void tempsense_init(void)
+{
+
+}
+
+float tempsense_readtemp(void)
+{
+ // TODO: Support multiple temperature sensors
+
+
+ // either return latest reading from DMA loop (NTC, etc)
+ // or initiate a blocking read and return it.
+ // Need to gracefully handle the timeout...
+}
+
+
diff --git a/src/thermostat.c b/src/thermostat.c
new file mode 100644
--- /dev/null
+++ b/src/thermostat.c
@@ -0,0 +1,62 @@
+//
+// Thermostat: Thermostatic controller
+//
+
+#include "thermostat.h"
+#include "flash.h"
+#include "gpio.h"
+
+// PID implementation
+
+float thermostat_process(void)
+{
+
+// #ifdef MAX31865_RTD_SENSOR
+// max31865_readtemp(spi_get(), &set, &status);
+// #else
+// max31855_readtemp(spi_get(), &set, &status); // Read MAX31855
+// #endif
+
+ float ssr_output = 0.0;
+ uint8_t thermostat_plant_on = 0;
+
+ // TODO: Migrate this FxP conversion to the readtemp code or similar
+ float temp = runtime_status()->temp;
+
+
+ // EMZ FIXME: This could be way simpler
+ if(flash_getsettings()->val.plant_type == PLANT_HEATER && runtime_status()->setpoint * 10 < temp - flash_getsettings()->val.hysteresis * 10)
+ thermostat_plant_on = 1;
+ else if(flash_getsettings()->val.plant_type == PLANT_HEATER && runtime_status()->setpoint * 10 > temp + flash_getsettings()->val.hysteresis * 10)
+ thermostat_plant_on = 0;
+
+ if(flash_getsettings()->val.plant_type == PLANT_COOLER && runtime_status()->setpoint * 10 > temp + flash_getsettings()->val.hysteresis * 10)
+ thermostat_plant_on = 1;
+ else if(flash_getsettings()->val.plant_type == PLANT_COOLER && runtime_status()->setpoint * 10 < temp - flash_getsettings()->val.hysteresis * 10)
+ thermostat_plant_on = 0;
+
+ // EMZ: TODO: Refactor to output_enabled or something
+ if(runtime_status()->pid_enabled && thermostat_plant_on)
+ {
+ // EMZ TODO: functionalize this
+ // put ssr output on display
+ ssd1306_drawstring(" ", 0, 90); //fixme: this is bad, but I can't get the old digits to clear otherwise
+ char tempstr[6];
+ itoa(ssr_output, tempstr, 10);
+ ssd1306_drawstring(tempstr, 0, 90);
+
+
+
+// HAL_GPIO_WritePin(SSR_PIN, 1);
+ HAL_GPIO_WritePin(LED, 1);
+ }
+ else
+ {
+// HAL_GPIO_WritePin(SSR_PIN, 0);
+ HAL_GPIO_WritePin(LED, 0);
+ }
+
+ return ssr_output;
+}
+
+