#include "stm32f0xx_hal.h"
#include "ssd1306.h"
#include "stm32f0xx_hal_flash.h"
#include "flash.h"
__attribute__((__section__(".eeprom"))) uint16_t eeprom[512];
static void __flash_write(therm_settings_t* tosave);
#define EEPROM_MAGIC_INDEX 16
#define EEPROM_MAGIC_VALUE 0xbeef
void flash_save(therm_settings_t* tosave)
{
ssd1306_clearscreen();
ssd1306_DrawString("Erase...", 0, 0);
HAL_Delay(1500);
HAL_Delay(100);
ssd1306_DrawString("Save...", 1, 0);
__flash_write(tosave);
ssd1306_DrawString("Done!", 2, 0);
HAL_Delay(500);
}
void flash_restore(therm_settings_t *torestore)
ssd1306_DrawString("READING SAVE", 1, 0);
if(eeprom[EEPROM_MAGIC_INDEX] != EEPROM_MAGIC_VALUE)
ssd1306_DrawString("No data to read!", 2, 0);
return;
uint16_t i;
for(i=0;i<128;i++)
torestore->data[i] = *(eeprom+i);
ssd1306_DrawString("READ COMPLETE", 3, 0);
static void __flash_write(therm_settings_t* tosave)
// Erase mem
HAL_FLASH_Unlock();
// Erase the FLASH pages
FLASH_EraseInitTypeDef erase;
erase.TypeErase = TYPEERASE_PAGES;
erase.PageAddress = eeprom;
erase.NbPages = 1;
uint32_t SectorError = 0;
HAL_FLASHEx_Erase(&erase, &SectorError);
CLEAR_BIT(FLASH->CR, FLASH_CR_PER);
// for(i=1;i<20;i++)
// {
// HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, eeprom+i, tosave->data[i]);
// }
HAL_FLASH_Program(TYPEPROGRAM_HALFWORD, eeprom + EEPROM_MAGIC_INDEX, EEPROM_MAGIC_VALUE);
HAL_FLASH_Lock();
// vim:softtabstop=4 shiftwidth=4 expandtab
#include "config.h"
#include "syslib.h"
#include "pid.h"
#include "states.h"
#include "max31855.h"
#include "gpio.h"
#include "spi.h"
#include "stringhelpers.h"
#include "display.h"
#include "storage.h"
#include "usb_device.h"
#include "usbd_cdc_if.h"
therm_settings_t set;
therm_status_t status;
int main(void)
// Initialize HAL
hal_init();
// Configure the system clock
systemclock_init();
// Unset bootloader option bytes (if set)
// FIXME this was never getting called. Try again sometime.
//bootloader_unset();
// Init GPIO
gpio_init();
// Init USB (TODO: Handle plugged/unplugged with external power)
MX_USB_DEVICE_Init();
// set.val.usb_plugged =
// USB startup delay
HAL_GPIO_WritePin(LED_POWER, 1);
// Enter into bootloader if up button pressed on boot
if(!HAL_GPIO_ReadPin(SW_UP))
bootloader_enter();
// Init SPI busses
spi_init();
// Init OLED over SPI
ssd1306_Init();
// Default settings
set.val.boottobrew = 0;
set.val.temp_units = TEMP_UNITS_CELSIUS;
set.val.windup_guard = 1;
set.val.k_p = 1;
set.val.k_i = 1;
set.val.temp_units = TEMP_UNITS_FAHRENHEIT;
set.val.windup_guard = 200;
set.val.k_p = 10;
set.val.k_i = 10;
set.val.k_d = 1;
set.val.ignore_tc_error = 0;
set.val.setpoint_brew = 0;
set.val.setpoint_steam = 0;
set.val.setpoint_brew = 70;
set.val.setpoint_steam = 70;
// Default status
status.temp = 0;
status.temp_frac = 0;
status.state_resume = 0;
status.state = STATE_IDLE;
status.setpoint = 0;
status.setpoint = 70;
status.pid_enabled = 0;
// Load settings (if any) from EEPROM
restore_settings(&set);
// Go to brew instead of idle if configured thusly
if(set.val.boottobrew)
status.state = STATE_PREHEAT_BREW;
// Startup screen
ssd1306_DrawString("therm v0.2", 1, 40);
ssd1306_DrawString("protofusion.org/therm", 3, 0);
HAL_Delay(1000);
flash_restore(&set);
// Soft timers
uint32_t last_ssr_on = 0;
uint32_t last_vcp_tx = 0;
uint32_t last_led = 0;
uint32_t last_pid = 0;
int16_t ssr_output = 0; // Duty cycle of ssr, 0 to SSR_PERIOD
// Main loop
while(1)
// Process sensor inputs
if(HAL_GetTick() - last_led > 400)
last_led = HAL_GetTick();
if((HAL_GetTick() - last_pid > PID_PERIOD))
#ifdef MAX31855_TC_SENSOR
max31855_readtemp(spi_get(), &set, &status); // Read MAX31855
#endif
#ifdef MAX31865_RTD_SENSOR
max31865_readtemp(&set, &status);
HAL_GPIO_TogglePin(LED_POWER);
if(status.pid_enabled)
// Get ssr output for next time
int16_t power_percent = pid_update(set.val.k_p, set.val.k_i, set.val.k_d, status.temp, status.temp_frac, status.setpoint, &set, &status);
//power-percent is 0-1000
//power-percent is 0-1000?
ssr_output = power_percent; //(((uint32_t)SSR_PERIOD * (uint32_t)10 * (uint32_t)100) * power_percent) / (uint32_t)1000000;
else
ssr_output = 0;
last_pid = HAL_GetTick();
// Kill SSR once the desired on-time has elapsed
if(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(HAL_GetTick() - last_ssr_on > SSR_PERIOD)
// Only support heating (ssr_output > 0) right now
if(ssr_output > 0) {
char tempstr[6];
itoa(ssr_output, tempstr, 10);
ssd1306_DrawString(tempstr, 0, 90);
HAL_GPIO_WritePin(SSR_PIN, 1);
last_ssr_on = HAL_GetTick();
else {
// Make sure everything is off
// Kill SSR after elapsed period less than SSR_PERIOD
if(HAL_GetTick() - last_ssr_on > ssr_output || ssr_output == 0)
if(HAL_GetTick() - last_vcp_tx > VCP_TX_FREQ)
// Print temp to cdc
char tempstr[16];
itoa_fp(status.temp, status.temp_frac, tempstr);
uint8_t numlen = strlen(tempstr);
tempstr[numlen] = '\r';
tempstr[numlen+1] = '\n';
// if(set.val.usb_plugged)
// CDC_Transmit_FS(tempstr, numlen+2);
// while(CDC_Transmit_FS("\r\n", 2) == USBD_BUSY);
last_vcp_tx = HAL_GetTick();
// Run state machine
display_process(&set, &status);
Status change: