TinyFanControl-Firmware/src/main.c

148 lines
3.0 KiB
C

#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/cm3/systick.h>
#include <libopencmsis/core_cm3.h>
#include "uart.h"
#include "temp_sensor.h"
#include "fan_ctrl_pwm.h"
#include "fan_ctrl_dc.h"
#include "fan_controller.h"
#include "eeprom_config.h"
#include "pinout.h"
#define SYSTICK_FREQ 10 // Hz
static uint64_t timebase_ms = 0;
static bool systick_triggered = false;
static void clock_setup(void)
{
/* We are running on MSI (2.1 MHz) after boot. */
rcc_periph_clock_enable(RCC_GPIOA); // for basically everything
/* Enable clocks for peripherals. */
rcc_periph_clock_enable(RCC_USART2);
rcc_periph_clock_enable(RCC_ADC1);
rcc_periph_clock_enable(RCC_DMA);
rcc_periph_clock_enable(RCC_TIM21);
}
/* Set up systick to fire freq times per second */
static void init_systick(int freq)
{
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB);
/* clear counter so it starts right away */
STK_CVR = 0;
systick_set_reload(rcc_ahb_frequency / freq);
systick_counter_enable();
systick_interrupt_enable();
}
int main(void)
{
// delay startup a bit to allow debugger to connect before debug pins are
// reconfigured to UART.
for(uint32_t i = 0; i < 1000000; i++) {
__asm__("nop");
}
clock_setup();
init_systick(SYSTICK_FREQ);
uart_init();
temp_sensor_init();
bool use_dcdc = EEPROM_CONFIG_FLAGS & EEPROM_CONFIG_FLAG_USE_DCDC_CONTROL;
if(use_dcdc) {
fan_ctrl_dc_init();
} else {
fan_ctrl_pwm_init();
}
fan_controller_init();
uart_enqueue("TinyFanControl v" VERSION " initialized.\n");
uint8_t last_duty = 0;
gpio_clear(LED_PORT, LED_PIN);
gpio_mode_setup(LED_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED_PIN);
while (1) {
if(systick_triggered) {
systick_triggered = false;
timebase_ms += 1000 / SYSTICK_FREQ;
uint32_t timebase_ms_fast = timebase_ms & 0xFFFFFFFF;
if(timebase_ms_fast <= 1000) {
if((timebase_ms_fast % 100) == 0) {
gpio_toggle(LED_PORT, LED_PIN);
}
} else {
// start the measurement in the background.
temp_sensor_trigger_update();
}
}
// check for completion of a measurement
if(temp_sensor_has_new_values()) {
// if a temperature update is available, run the control loop.
fxp_t temperature = temp_sensor_get_ntc_temperature();
uint8_t duty = fan_controller_update(temperature);
// handle fan power-on and power-off
if(last_duty == 0 && duty != 0) {
gpio_set(LED_PORT, LED_PIN);
if(use_dcdc) {
fan_ctrl_dc_enable();
} else {
fan_ctrl_pwm_enable();
}
} else if(last_duty != 0 && duty == 0) {
gpio_clear(LED_PORT, LED_PIN);
if(use_dcdc) {
fan_ctrl_dc_disable();
} else {
fan_ctrl_pwm_disable();
}
}
// set the updated duty cycle
if(use_dcdc) {
fan_ctrl_dc_set_duty(duty);
} else {
fan_ctrl_pwm_set_duty(duty);
}
last_duty = duty;
}
__WFI();
}
return 0;
}
/* Called when systick fires */
void sys_tick_handler(void)
{
systick_triggered = true;
}
void hard_fault_handler(void)
{
while (1);
}