FEATIRE COMPLETE?

This commit is contained in:
2026-04-12 23:29:57 +02:00
parent 82e43b67da
commit 4abb1df03c
4 changed files with 63 additions and 43 deletions

View File

@@ -6,12 +6,10 @@
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define CLAMP(min, max, val) MIN(MAX(min, val), max)
volatile uint16_t _fan_driver_delta[12];
volatile uint32_t _delta_idx = 0;
static const uint16_t pwm_timer_period = 2048;
static const uint8_t rpm_buf_size = sizeof(_fan_driver_delta) / sizeof(_fan_driver_delta[0]);
@@ -26,11 +24,6 @@ enum {
MODE_RPM_TARGET = 1
} fan_driver_control_mode;
enum {
FAN_TYPE_PWM = 0,
FAN_TYPE_DC = 1
} fan_driver_fan_type;
// callback for the pin interrupt
void TIM2_IRQHandler(void) __attribute__((interrupt));
@@ -48,10 +41,15 @@ void TIM2_IRQHandler(void) {
void fan_driver_init(void) {
const uint8_t pwm_pin = 2; // also need to change TIM1->CCER
const uint8_t tacho_pin = 3;
const uint8_t power_pin = 6; // also change in set_power func
// enable clock gating to relevant periphs
RCC->APB1PCENR |= RCC_APB1Periph_TIM2;
RCC->APB2PCENR |= RCC_APB2Periph_GPIOD | RCC_APB2Periph_TIM1 | RCC_APB2Periph_AFIO; // enable clock gating for gpio and pwm timer
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_TIM1 | RCC_APB2Periph_AFIO; // enable clock gating for gpio and pwm timer
// power pin init
GPIOC->CFGLR &= ~(0xf << (4 * power_pin));
GPIOC->CFGLR |= (GPIO_Speed_10MHz | GPIO_CNF_OUT_PP) << (4 * power_pin);
// pwm stuff init
// port conf register is 32 bits. each pin is 4 bits
@@ -64,7 +62,7 @@ void fan_driver_init(void) {
TIM1->SWEVGR |= TIM_UG; // reload immediately
TIM1->CCER |= TIM_CC1E | TIM_CC1NP; // enable timer output t1ch1, positive polarity
TIM1->CHCTLR1 |= TIM_OC1M_2 | TIM_OC1M_1; // set compare mode, set output?
TIM1->CH1CVR = 0; // initial duty at 0
TIM1->CH1CVR = TIM1->ATRLR; // initial duty at full speed
TIM1->BDTR |= TIM_MOE; // enable outputs
TIM1->CTLR1 |= TIM_CEN; // enable timer
@@ -103,30 +101,35 @@ static void fan_driver_pwm_set_duty(const uint16_t duty) {
TIM1->CH1CVR = MIN(duty, fan_driver_pwm_get_max_duty());
}
static void fan_driver_set_power(const bool power) {
GPIOC->BSHR = (1 << (6 + 16 * !power));
}
void fan_driver_control_loop(void) {
// static uint16_t counter = 0;
static uint32_t last_delta_idx = 0xffffffff;
if(_delta_idx == last_delta_idx) {
fan_driver_is_stalled = (_delta_idx == last_delta_idx);
if(fan_driver_is_stalled) {
fan_driver_current_rpm = 0;
fan_driver_is_stalled = true;
return;
}
fan_driver_is_stalled = false;
last_delta_idx = _delta_idx;
fan_driver_set_power(!fan_driver_powered_down);
if (fan_driver_powered_down)
return;
uint32_t delta = 0;
for (int i = 0; i < rpm_buf_size; i++)
delta += _fan_driver_delta[i];
delta /= rpm_buf_size;
// each tick is 2us. one minute is 30000000 ticks, each rotation is 2 pulses
fan_driver_current_rpm = delta ? 30000000 / 2 / delta : 0;
// each tick is 2us. one minute is 30000000 ticks, each rotation is 2 pulses
if(fan_driver_control_mode == MODE_RPM_TARGET) {
const int32_t duty_trim = (fan_driver_current_rpm - fan_driver_target_rpm) / 3;
fan_driver_pwm_set_duty(fan_driver_pwm_get_duty() + CLAMP(-100, 100, duty_trim));
if(fan_driver_control_mode == 1) {
const int32_t duty_trim = (fan_driver_target_rpm - fan_driver_current_rpm) / 4;
fan_driver_pwm_set_duty(fan_driver_pwm_get_duty() + duty_trim);
fan_driver_is_steady = (duty_trim == 0);
} else {
fan_driver_is_steady = true;

View File

@@ -31,7 +31,7 @@ static void i2c_registers_reinit(volatile uint8_t* reg) {
static void i2c_registers_set_defaults(volatile uint8_t* reg) {
i2c_set_register_word(reg, I2C_REG_TARGET_RPM, 750);
reg[I2C_REG_MODE] = 0x01; // target rpm mode, power enabled
reg[I2C_REG_MODE] = 0x01; // target rpm mode, pwm control, power enabled
}
#endif //I2C_H

View File

@@ -5,25 +5,31 @@
volatile uint8_t i2c_registers[16] = {0x00};
void update_fan_from_regs(volatile uint8_t* reg) {
fan_driver_target_rpm = i2c_get_register_word(reg, I2C_REG_TARGET_RPM);
fan_driver_pwm_set_duty(i2c_get_register_word(reg, I2C_REG_CURRENT_DUTY));
fan_driver_control_mode = (reg[I2C_REG_MODE] & 0x01);
fan_driver_powered_down = (reg[I2C_REG_MODE] & 0x02) >> 1;
}
void onWrite(const uint8_t reg, const uint8_t length) {
if (length == 0) return;
switch (reg) {
case I2C_REG_TARGET_RPM:
fan_driver_target_rpm = i2c_get_register_word(i2c_registers, I2C_REG_TARGET_RPM);
update_fan_from_regs(i2c_registers);
printf("set tgt fan speed to %d\n", fan_driver_target_rpm);
break;
case I2C_REG_CURRENT_DUTY:
printf("set duty cycle to %d\n", i2c_get_register_word(i2c_registers, I2C_REG_CURRENT_DUTY));
update_fan_from_regs(i2c_registers);
printf("set duty cycle to %d\n", fan_driver_pwm_get_duty());
break;
case I2C_REG_MODE:
fan_driver_control_mode = (i2c_registers[I2C_REG_MODE] & 0x01);
fan_driver_fan_type = (i2c_registers[I2C_REG_MODE] & 0x02) >> 1;
fan_driver_powered_down = (i2c_registers[I2C_REG_MODE] & 0x04) >> 2;
printf("set mode register to %x. control mode is %d, type is %d, powered down is %d\n", i2c_registers[I2C_REG_MODE], fan_driver_control_mode, fan_driver_fan_type, fan_driver_powered_down);
update_fan_from_regs(i2c_registers);
printf("set mode register to %x. control mode is %d, powered down is %d\n", i2c_registers[I2C_REG_MODE], fan_driver_control_mode, fan_driver_powered_down);
break;
default:
@@ -39,7 +45,6 @@ int main() {
printf("System bootup\n");
fan_driver_init();
fan_driver_pwm_set_duty(1000);
// Initialize I2C slave
funGpioInitC();
@@ -47,6 +52,7 @@ int main() {
funPinMode(PC2, GPIO_CFGLR_OUT_10Mhz_AF_OD); // SCL
i2c_registers_reinit(i2c_registers);
i2c_registers_set_defaults(i2c_registers);
update_fan_from_regs(i2c_registers);
fan_driver_target_rpm = i2c_get_register_word(i2c_registers, I2C_REG_TARGET_RPM);
SetupI2CSlave(I2C_DEVICE_ADDR, i2c_registers, sizeof(i2c_registers), onWrite, NULL, false);
@@ -56,9 +62,9 @@ int main() {
i2c_set_register_word(i2c_registers, I2C_REG_CURRENT_RPM, fan_driver_current_rpm);
i2c_set_register_word(i2c_registers, I2C_REG_CURRENT_DUTY, fan_driver_pwm_get_duty());
i2c_registers[I2C_REG_STATE] = (fan_driver_is_steady) | (fan_driver_is_stalled << 1);
i2c_registers[I2C_REG_STATE] = (!fan_driver_is_steady) | (fan_driver_is_stalled << 1);
Delay_Ms(200);
Delay_Ms(250);
}
}