Changeset - db81b1787e6e
[Not reviewed]
cortex-f0
0 8 0
matthewreed - 9 years ago 2015-12-23 22:37:10

Cleaned up pid code and several other todos
8 files changed with 71 insertions and 55 deletions:
0 comments (0 inline, 0 general)
display.c
Show inline comments
 
@@ -332,13 +332,13 @@ void display_process(therm_settings_t* s
 
            // Button handler
 
            if(SW_BTN_PRESSED) {
 
                flash_save(set);
 
                status->state = STATE_IDLE;
 
            }
 
            else {
 
                user_input_signed((int16_t*)(&set->val.temp_offset));
 
                user_input_signed(&set->val.temp_offset);
 
            }
 

	
 
            // Event Handler
 
            // N/A
 
 
 
        } break;
 
@@ -351,13 +351,13 @@ void display_process(therm_settings_t* s
 
            // [ 30 => 120 C             ]
 
            ssd1306_drawstring("Preheating...", 0, 0);
 
            //ssd1306_drawlogo();
 
            draw_setpoint(status);
 

	
 
            status->pid_enabled = 1;
 
	    status->setpoint = set->val.setpoint_brew;
 
            status->setpoint = set->val.setpoint_brew;
 

	
 
            // Button handler
 
            if(SW_BTN_PRESSED) {
 
                status->state = STATE_IDLE;
 
            }
 
            else {
 
@@ -377,13 +377,13 @@ void display_process(therm_settings_t* s
 
            // [ therm : ready to brew ]
 
            // [ 30 => 120 C           ]
 
            ssd1306_drawstring("Preheated!", 0, 0);
 
            //ssd1306_drawlogo();
 
            draw_setpoint(status);
 
            status->pid_enabled = 1;
 
	    status->setpoint = set->val.setpoint_brew;
 
            status->setpoint = set->val.setpoint_brew;
 

	
 
            // Button handler
 
            if(SW_BTN_PRESSED) {
 
                status->state = STATE_IDLE;
 
            }
 
            else {
 
@@ -564,7 +564,13 @@ static void draw_setpoint(therm_status_t
 

	
 
    trigger_drawsetpoint = 0;
 
    setpoint_last = status->setpoint;
 
    temp_last = status->temp;
 
}
 

	
 
void display_startup_screen() {
 
    ssd1306_clearscreen();
 
    ssd1306_drawstring("therm v0.2", 1, 40);
 
    ssd1306_drawstring("protofusion.org/therm", 3, 0);
 
}
 

	
 
// vim:softtabstop=4 shiftwidth=4 expandtab 
display.h
Show inline comments
 
@@ -12,9 +12,10 @@
 
#include "flash.h"
 
#include "gpio.h"
 
#ifdef MAX31865_RTD_SENSOR
 
#include "max31865.h"
 
#endif
 

	
 
void display_startup_screen();
 
void display_process(therm_settings_t* set, therm_status_t* status);
 

	
 
#endif
gpio.c
Show inline comments
 
@@ -18,23 +18,25 @@ void user_input(uint16_t* to_modify)
 
        }
 
    }
 
}
 

	
 

	
 
// Increment/decrement signed variable with up/down buttons
 
void user_input_signed(int16_t* to_modify)
 
void user_input_signed(int32_t* to_modify)
 
{
 
    // TODO: Bounds check on int16_t
 
	//fixme: need to cast to 16/32 bits correctly
 
    if(CHANGE_ELAPSED) {
 
        if(!HAL_GPIO_ReadPin(SW_UP) ) {
 
            CHANGE_RESET;
 
            (*to_modify)++;
 
            if (*to_modify < 32768)
 
            	(*to_modify)++;
 
        }
 
        else if(!HAL_GPIO_ReadPin(SW_DOWN)) {
 
            CHANGE_RESET;
 
            (*to_modify)--;
 
            if (*to_modify >= -32768)
 
            	(*to_modify)--;
 
        }
 
    }
 
}
 

	
 

	
 
// Initialize GPIO
gpio.h
Show inline comments
 
@@ -9,12 +9,12 @@
 
#define CHANGE_PERIOD_MS 100
 
#define CHANGE_ELAPSED (HAL_GetTick() - change_time_reset) > CHANGE_PERIOD_MS
 
#define CHANGE_RESET change_time_reset = HAL_GetTick()
 

	
 

	
 
void user_input(uint16_t* to_modify);
 
void user_input_signed(int16_t* to_modify);
 
void user_input_signed(int32_t* to_modify);
 
void gpio_init(void);
 

	
 
#endif
 

	
 
// vim:softtabstop=4 shiftwidth=4 expandtab 
main.c
Show inline comments
 
@@ -2,29 +2,29 @@
 
 
#include "config.h"
 
#include "syslib.h"
 
#include "pid.h"
 
#include "states.h"
 
#include "ssd1306.h"
 
#ifdef MAX31855_TC_SENSOR
 
#include "max31855.h"
 
#endif
 
#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();
 
 
@@ -50,42 +50,41 @@ int main(void)
 
    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();
 
    ssd1306_clearscreen();
 
 
    // 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; 
 
 
    // Startup screen 
 
    ssd1306_drawstring("therm v0.2", 1, 40);
 
    ssd1306_drawstring("protofusion.org/therm", 3, 0);
 
 
    HAL_Delay(1000);
 
 
    // Restore settings from flash memory
 
    flash_restore(&set);
 
 
    HAL_Delay(1000);
 
    HAL_Delay(2000);
 
    ssd1306_clearscreen();
 
 
    // Soft timers
 
    uint32_t last_ssr_on = 0;
 
    uint32_t last_vcp_tx = 0;
 
    uint32_t last_led = 0;
 
@@ -101,27 +100,33 @@ int main(void)
 
        {
 
            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(spi_get(), &set, &status);
 
            #endif
 
			#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.val.k_p, set.val.k_i, set.val.k_d, status.temp, status.temp_frac, status.setpoint, &set, &status);
 
                int16_t power_percent = pid_update(&set, &status, &pid_state);
 
                //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;
 
            }
 
 
@@ -135,18 +140,16 @@ int main(void)
 
            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);
 
                HAL_GPIO_WritePin(LED_POWER, 1);
 
                last_ssr_on = HAL_GetTick();
 
            }
 
            else {
 
@@ -154,13 +157,13 @@ int main(void)
 
                HAL_GPIO_WritePin(SSR_PIN, 0);
 
                HAL_GPIO_WritePin(LED_POWER, 0);
 
            }
 
            
 
        }
 
        
 
        // Transmit temperature over USB-CDC on a regulat basis
 
        // 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);
max31865.c
Show inline comments
 
@@ -50,20 +50,14 @@ void max31865_clear_errors(SPI_HandleTyp
 
	max31865_config(hspi1);
 
}
 

	
 
// Grab temperature reading from MAX31865
 
void max31865_readtemp(SPI_HandleTypeDef* hspi1, therm_settings_t* set, therm_status_t* status)
 
{
 
    ///////////////////////////////////
 
    // This is duplicated from MAX31855, update for MAX31865 registers/etc
 
    /////////////////////////////////// 
 

	
 
    // TODO: Set configuration register based on params in config.h (2-wire, 4-wire, etc RTD). This is register 0x00.
 
        // 2-wire RTC or 2-wire (duh) NTC thermistor will be the only options
 
        // Need option for resistance of RTD
 
        // These options should be stored in the set structure and should be menu-selectable
 
    // TODO: Set RTD ref resistance in set struct
 

	
 
    // Assert CS
 
    HAL_GPIO_WritePin(MAX_CS, 0);
 
    
 
    uint8_t regh = MAX31865_REG_RTD_MSB;
 
    
pid.c
Show inline comments
 
#include "stm32f0xx_hal.h"
 
#include "states.h"
 
#include "pid.h"
 

	
 
// PID implementation
 
// TODO: Make struct that has the last_temp and i_state in it, pass by ref. Make struct that has other input values maybe.
 
static int16_t last_pid_temp = 0;
 
static uint8_t last_pid_temp_frac = 0;
 
static int32_t i_state = 0;
 

	
 
int16_t pid_update(uint16_t k_p, uint16_t k_i, uint16_t k_d, int16_t temp, uint8_t temp_frac, int16_t setpoint, therm_settings_t* set, therm_status_t* status) 
 
void pid_init(pid_state_t* state)
 
{
 
	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)
 
{
 
  // Calculate instantaneous error
 
  int16_t error = setpoint - temp; // TODO: Use fixed point fraction
 
  int16_t error = status->setpoint - status->temp; // TODO: Use fixed point fraction
 

	
 
  // Proportional component
 
  int32_t p_term = k_p * error;
 
  int32_t p_term = set->val.k_p * error;
 

	
 
  // Error accumulator (integrator)
 
  i_state += error;
 
  state->i_state += error;
 

	
 
  // to prevent the iTerm getting huge from lots of 
 
  //  error, we use a "windup guard" 
 
  // (this happens when the machine is first turned on and
 
  // it cant help be cold despite its best efforts)
 
  // not necessary, but this makes windup guard values 
 
  // relative to the current iGain
 
  int32_t windup_guard_res = set->val.windup_guard / k_i;  
 
  int32_t windup_guard_res = set->val.windup_guard / set->val.k_i;
 

	
 
  // Calculate integral term with windup guard 
 
  if (i_state > windup_guard_res) 
 
    i_state = windup_guard_res;
 
  else if (i_state < -windup_guard_res) 
 
    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 = k_i * i_state;
 
  int32_t i_term = set->val.k_i * state->i_state;
 

	
 
  // Calculate differential term (slope since last iteration)
 
  int32_t d_term = (k_d * (status->temp - last_pid_temp));
 
  int32_t d_term = (set->val.k_d * (status->temp - state->last_pid_temp));
 

	
 
  // Save temperature for next iteration
 
  last_pid_temp = status->temp;
 
  last_pid_temp_frac = status->temp_frac;
 
  state->last_pid_temp = status->temp;
 
  state->last_pid_temp_frac = status->temp_frac;
 

	
 
  int16_t result = p_term + i_term - d_term;
 

	
 
  // Put out tenths of percent, 0-1000. 
 
  if(result > 1000)
 
    result = 1000;
pid.h
Show inline comments
 
#ifndef PIDS_H
 
#define PIDS_H
 

	
 
#include "stm32f0xx_hal.h"
 
#include "states.h"
 

	
 
int16_t pid_update(uint16_t k_p, uint16_t k_i, uint16_t k_d, int16_t temp, uint8_t temp_frac, int16_t setpoint, therm_settings_t* set, therm_status_t* status);
 
typedef struct {
 
	int16_t last_pid_temp;
 
	uint8_t last_pid_temp_frac;
 
	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);
 

	
 
#endif
0 comments (0 inline, 0 general)