FEATIRE COMPLETE?
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
24
src/main.c
24
src/main.c
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user