You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
toaster-oven-bluepill/Core/Src/app.c

272 lines
7.3 KiB

/**
* Main task
*/
#include <stdio.h>
#include <string.h>
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "app.h"
#include "ufb/framebuffer.h"
#include "iwdg.h"
#include "tim.h"
#include "adc.h"
#include "oled.h"
#include "ufb/fb_text.h"
/* DMA dest */
static volatile uint16_t adc_values[4];
const float V_REFINT = 1.23f;
#define AVERAGEBUF_DEPTH 32
static struct App {
float oven_temp;
float soc_temp;
float v_sensor;
// float v_current_reference;
// float sensor_current;
// float r_sensor;
uint16_t wheel;
bool push;
uint16_t adc_averagebuf[AVERAGEBUF_DEPTH * 4];
uint8_t averagebuf_ptr;
float adc_averages[4];
} s_app = {};
#define TSENSE_LOOKUP_LEN 101
#define TSENSE_T_STEP 5.0f
#define TSENSE_T_MIN 0.0f
#define TSENSE_T_MAX 500.0f
static const float TSENSE_LOOKUP[TSENSE_LOOKUP_LEN] = {
0.092678405931418f,
0.0943174479327356f,
0.095948157844312f,
0.0975706768542549f,
0.0991848957506647f,
0.100791037522732f,
0.102388993070241f,
0.103978983136042f,
0.105560980458654f,
0.107135039851509f,
0.108701215616829f,
0.110259642413441f,
0.111810211533421f,
0.113353137226489f,
0.114888310929339f,
0.11641594480226f,
0.117936009906507f,
0.119448557132363f,
0.120953636903929f,
0.122451377845456f,
0.12394167187544f,
0.125424725109556f,
0.126900429638119f,
0.128368989630084f,
0.129830374697352f,
0.131284632150064f,
0.132731808872517f,
0.134172027901771f,
0.135605181883591f,
0.13703146935069f,
0.138450783142958f,
0.139863319976468f,
0.14126904821384f,
0.142668011892657f,
0.144060254660872f,
0.145445894373796f,
0.146824824486877f,
0.14819723645253f,
0.149563023938454f,
0.150922376699229f,
0.15227526202401f,
0.153621720954182f,
0.15496179417407f,
0.156295594725426f,
0.157623016940038f,
0.158944245649448f,
0.160259175412251f,
0.16156798947087f,
0.162870654195634f,
0.164167207880495f,
0.165457688491696f,
0.166742204592451f,
0.168020651444079f,
0.169293207677971f,
0.170559768793747f,
0.171820511933356f,
0.173075402684405f,
0.174324476817747f,
0.175567769803026f,
0.176805386030345f,
0.178037221732226f,
0.179263449725904f,
0.180483966491086f,
0.181698943447122f,
0.182908345518766f,
0.184112206156428f,
0.185310558533273f,
0.186503503145257f,
0.187690937227925f,
0.188873028139146f,
0.190049673368296f,
0.191221038959601f,
0.192387089280576f,
0.193547855644572f,
0.194703369109397f,
0.195853726532112f,
0.196998826174689f,
0.19813883026229f,
0.199273637315452f,
0.200403408323351f,
0.201528107189346f,
0.20264776325594f,
0.203762405629782f,
0.204872127762998f,
0.205976828960191f,
0.207076666615101f,
0.208171540293999f,
0.209261606226334f,
0.210346827933364f,
0.211427232937629f,
0.212502848543705f,
0.213573765013592f,
0.214639882704581f,
0.215701354457324f,
0.216758080892489f,
0.217810213752734f,
0.218857716249547f,
0.219900614222686f,
0.220938933310224f,
0.221972760781578f,
0.223001998051553f,
};
static float val_to_c(float val){
// TODO use binary search.. lol
for (int i = 1; i < TSENSE_LOOKUP_LEN; i++) {
float cur = TSENSE_LOOKUP[i];
if (cur >= val) {
float prev = TSENSE_LOOKUP[i-1];
float ratio = (val - prev) / (cur - prev);
return TSENSE_T_MIN + ((float) i + ratio) * TSENSE_T_STEP;
}
}
return TSENSE_T_MAX;
}
void calculate_analog_values() {
uint32_t sums[4] = {};
for (int i = 0; i < AVERAGEBUF_DEPTH * 4; i += 4) {
sums[0] += s_app.adc_averagebuf[i];
sums[1] += s_app.adc_averagebuf[i + 1];
sums[2] += s_app.adc_averagebuf[i + 2];
sums[3] += s_app.adc_averagebuf[i + 3];
}
s_app.adc_averages[0] = (float)sums[0] / AVERAGEBUF_DEPTH;
s_app.adc_averages[1] = (float)sums[1] / AVERAGEBUF_DEPTH;
s_app.adc_averages[2] = (float)sums[2] / AVERAGEBUF_DEPTH;
s_app.adc_averages[3] = (float)sums[3] / AVERAGEBUF_DEPTH;
/* r_pt100, r_ref, internal_temp, v_ref_int */
float refint = s_app.adc_averages[3];
float scale = V_REFINT / refint;
const float avg_slope = 4.3f * scale;
const float v25 = 1.43f;
const float v_tsen = s_app.adc_averages[2] * scale;
s_app.soc_temp = (v25 - v_tsen) / avg_slope + 25.f;
s_app.v_sensor = s_app.adc_averages[0] * scale; // good for debug/tuning
// using a voltage divider, so assuming the reference resistor is measured well,
// we can just use the ratio and the exact voltage value is not important.
s_app.oven_temp = val_to_c(s_app.adc_averages[0] / s_app.adc_averages[1]);
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
// notify
memcpy((void*) &s_app.adc_averagebuf[s_app.averagebuf_ptr * 4], (const void*) adc_values, 8);
s_app.averagebuf_ptr = (s_app.averagebuf_ptr + 1) % AVERAGEBUF_DEPTH;
}
static void hw_init()
{
HAL_ADCEx_Calibration_Start(&hadc1);
/* Start periodic reading of the ADC channels */
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)(void*)adc_values, 4);
/* Enable the rotary encoder */
HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_ALL);
/* Enable buzzer PWM */
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
/* Prepare the framebuffer and OLED interface */
oled_init();
fb_clear();
}
void app_main_task(void *argument)
{
hw_init();
/* Infinite loop */
bool invert = 0;
for(;;)
{
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
s_app.wheel = htim4.Instance->CNT;
s_app.push = 0 == HAL_GPIO_ReadPin(KNOB_PUSH_GPIO_Port, KNOB_PUSH_Pin);
calculate_analog_values();
// printf("Knob %d (P=%d), ADC %.2f %.2f %.2f %.2f, oven %.2f°C, soc %.2f°C, divider %.3f V \r\n",
// (int) s_app.wheel, s_app.push,
// s_app.adc_averages[0], s_app.adc_averages[1], s_app.adc_averages[2], s_app.adc_averages[3],
//
// s_app.oven_temp,
// s_app.soc_temp,
// s_app.v_sensor
// );
invert = !invert;
fb_clear();
if (s_app.push) {
fb_rect(s_app.wheel % FBW, 0, 15, 15, 1);
} else {
if (invert) {
fb_frame(s_app.wheel % FBW, 0, 15, 15, 2, 1);
} else {
fb_frame(s_app.wheel % FBW, 0, 15, 15, 1, 1);
}
}
char tmp[100];
sprintf(tmp, "%d°C", (int) s_app.oven_temp);
fb_text(0, 20, tmp, 0, 1);
fb_blit();
vTaskDelay(100);
// beep
htim2.Instance->ARR = 12000 + (int16_t)s_app.wheel * 100;
htim2.Instance->CCR1 = htim2.Instance->ARR/2;
vTaskDelay(50);
htim2.Instance->ARR = 0;
// feed dogs
HAL_IWDG_Refresh(&hiwdg);
}
}