Files @ 9294a623e8e5
Branch filter:

Location: therm/main.c

Ethan Zonca
Added support for both heaters and coolers as well as thermostatic control
#include "stm32f0xx_hal.h"

#include "config.h"
#include "syslib.h"
#include "pid.h"
#include "states.h"
#include "ssd1306.h"
#ifdef MAX31865_RTD_SENSOR
#include "max31865.h"
#else
#include "max31855.h"
#endif
#include "gpio.h"
#include "spi.h"
#include "flash.h"
#include "stringhelpers.h"
#include "display.h"

#include "usb_device.h"
#include "usbd_cdc_if.h"

therm_settings_t set;
therm_status_t status;
pid_state_t pid_state;

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_Delay(500);
    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 RTD chip
    #ifdef MAX31865_RTD_SENSOR
    max31865_config(spi_get());
    #endif

    // Init OLED over SPI
    ssd1306_init();

    // Startup screen
    display_startup_screen();

    // 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);

    // Go to brew instead of idle if configured thusly
    if(set.val.boottobrew)
      status.state = STATE_PREHEAT; 

    // Restore settings from flash memory
    flash_restore(&set);

    HAL_Delay(2000);
    ssd1306_clearscreen();

    // 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 

    // Main loop
    while(1)
    {
        // Process sensor inputs

        if(HAL_GetTick() - last_led > 400) 
        {
            last_led = HAL_GetTick();
        }

        if(set.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(&set, &status, &pid_state);

                if(set.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;
            }

            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(set.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;

            uint8_t plant_on = 0;

            // EMZ FIXME: This could be way simpler
            if(set.val.plant_type == PLANT_HEATER && status.setpoint * 10 < temp)
                plant_on = 1;
            else if(set.val.plant_type == PLANT_COOLER && status.setpoint * 10 > temp)
                plant_on = 1;

            // EMZ: TODO: Refactor to output_enabled or something
            if(status.pid_enabled && 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_POWER, 1);
            }
            else
            {
                HAL_GPIO_WritePin(SSR_PIN, 0);
                HAL_GPIO_WritePin(LED_POWER, 0);
            }
            
            last_thermostat = HAL_GetTick();
        }


        // Transmit temperature over USB-CDC on a regular basis
        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); 
    }
}
// vim:softtabstop=4 shiftwidth=4 expandtab