From b8cc7d759130a7062b99e3075e6eea8710ff3b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?King=20K=C3=A9vin?= Date: Tue, 8 Dec 2020 23:07:36 +0100 Subject: [PATCH] application: replace TEC power board with H-bridge --- application.c | 121 ++++++++++++++++++++------------------------------ 1 file changed, 49 insertions(+), 72 deletions(-) diff --git a/application.c b/application.c index f859262..12637fc 100644 --- a/application.c +++ b/application.c @@ -95,18 +95,17 @@ static volatile bool rtc_internal_second_flag = false; /**< set when a second pa #define CONTROL_POWER_RED_LED_PIN PA7 /**< to control red LED of power indicator (active high) */ #define led_power_on() gpio_set(GPIO_PORT(CONTROL_POWER_RED_LED_PIN), GPIO_PIN(CONTROL_POWER_RED_LED_PIN)) /**< switch power LED on */ #define led_power_off() gpio_clear(GPIO_PORT(CONTROL_POWER_RED_LED_PIN), GPIO_PIN(CONTROL_POWER_RED_LED_PIN)) /**< switch power LED off */ -// the button on the panel is configured as board button -//#define CONTROL_PLAY_BUTTON_LED_PIN PB0 /**< to read play/pause button (connected to ground when pressed) */ +#define CONTROL_PLAY_BUTTON_LED_PIN PB0 /**< to read play/pause button (connected to ground when pressed) */ -#define TEC_POWER_YELLOW PB11 /**< pin to choose which power rail to connect to yellow TEC power input (high = ground, low = 12V), must be 5V tolerant */ -#define tec_power_yellow_on() gpio_clear(GPIO_PORT(TEC_POWER_YELLOW), GPIO_PIN(TEC_POWER_YELLOW)) // sink current, connecting wire to 12V -#define tec_power_yellow_off() gpio_set(GPIO_PORT(TEC_POWER_YELLOW), GPIO_PIN(TEC_POWER_YELLOW)) // don't sink current, disconnecting wire from 12V -#define TEC_POWER_ORANGE PB10 /**< pin to choose which power rail to connect to orange TEC power input (high = ground, low = 12V), must be 5V tolerant */ -#define tec_power_orange_on() gpio_clear(GPIO_PORT(TEC_POWER_ORANGE), GPIO_PIN(TEC_POWER_ORANGE)) // sink current, connecting wire to 12V -#define tec_power_orange_off() gpio_set(GPIO_PORT(TEC_POWER_ORANGE), GPIO_PIN(TEC_POWER_ORANGE)) // don't sink current, disconnecting wire from 12V -#define TEC_POWER_PWM PB9 /**< pin to actually let power go through TECs, where PWM can be used (active low) */ -#define tec_power_pwm_on() gpio_clear(GPIO_PORT(TEC_POWER_PWM), GPIO_PIN(TEC_POWER_PWM)) /**< allow power to go through TECs by sinking current, powering optocoupler, switching on MOSFET, connecting ground */ -#define tec_power_pwm_off() gpio_set(GPIO_PORT(TEC_POWER_PWM), GPIO_PIN(TEC_POWER_PWM)) /**< prevent power to go through TECs by not sinking current, not powering optocoupler, not switching on MOSFET, disconnecting ground */ +#define TEC_POWER_YELLOW PB11 /**< pin to choose which power rail to connect to yellow TEC power input (high = VCC, low = GND) */ +#define tec_power_yellow_on() gpio_set(GPIO_PORT(TEC_POWER_YELLOW), GPIO_PIN(TEC_POWER_YELLOW)) // allow connecting yellow to VCC +#define tec_power_yellow_off() gpio_clear(GPIO_PORT(TEC_POWER_YELLOW), GPIO_PIN(TEC_POWER_YELLOW)) // allow connect yellow to GND +#define TEC_POWER_ORANGE PB10 /**< pin to choose which power rail to connect to orange TEC power input (high = VCC, low = GND) */ +#define tec_power_orange_on() gpio_set(GPIO_PORT(TEC_POWER_ORANGE), GPIO_PIN(TEC_POWER_ORANGE)) // allow connect orange to VCC +#define tec_power_orange_off() gpio_clear(GPIO_PORT(TEC_POWER_ORANGE), GPIO_PIN(TEC_POWER_ORANGE)) // allow connect orange to GND +#define TEC_POWER_PWM PB9 /**< pin to actually let power go through TECs, where PWM can be used (active high) */ +#define tec_power_pwm_on() gpio_set(GPIO_PORT(TEC_POWER_PWM), GPIO_PIN(TEC_POWER_PWM)) /**< connect yellow/orange wire as set */ +#define tec_power_pwm_off() gpio_clear(GPIO_PORT(TEC_POWER_PWM), GPIO_PIN(TEC_POWER_PWM)) /**< disconnect yellow/orange wire */ #define TEC_POWER_TIMER 4 /**< timer connected to pin */ #define TEC_POWER_CHANNEL 4 /**< timer channel connected to pin */ #define TEC_POWER_OC TIM_OC4 /**< timer output compare connected to pin */ @@ -166,15 +165,12 @@ static void safe_state(void) gpio_set(GPIO_PORT(MBLK019_CH14_PIN), GPIO_PIN(MBLK019_CH14_PIN)); // don't sink current (e.g. not powering the opto-coupler/transistor) gpio_set(GPIO_PORT(MBLK019_CH35_PIN), GPIO_PIN(MBLK019_CH35_PIN)); // don't sink current (e.g. not powering the opto-coupler/transistor) - // take control over the power MOSFET and switch it off + // take control over the H-bridge and switch it off rcc_periph_clock_enable(GPIO_RCC(TEC_POWER_PWM)); // enable clock for GPIO port peripheral - gpio_set_mode(GPIO_PORT(TEC_POWER_PWM), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN(TEC_POWER_PWM)); // set pin as output open-drain + gpio_set_mode(GPIO_PORT(TEC_POWER_PWM), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(TEC_POWER_PWM)); // set pin as output tec_power_pwm_off(); // switch off power - - sleep_ms(2); // wait a be before switch relay to prevent arcing - tec_power_yellow_off(); // disconnect 12V from yellow TEC line - tec_power_orange_off(); // disconnect 12V from orange TEC line - sleep_ms(10); // wait for relay to operate + tec_power_yellow_off(); // connect wire to ground + tec_power_orange_off(); // onnect wire to ground // disable heater lid rcc_periph_clock_enable(GPIO_RCC(LID_HEATER_PIN)); // enable clock for GPIO port peripheral @@ -296,9 +292,8 @@ static void tec_heat(void) { tec_power(0); // ensure power is off while switching sleep_ms(2); // wait for the PWM to take effect - tec_power_orange_off(); // disconnect 12V from orange TEC line - tec_power_yellow_on(); // connect 12V to yellow TEC line - sleep_ms(10); // wait for relay to operate + tec_power_orange_off(); // connect GND from orange TEC line + tec_power_yellow_on(); // connect VCC to yellow TEC line // set TEC configuration to heat the top half at max // the following heating configurations exist (when orange is connected to minus and yellow to plus) @@ -321,9 +316,8 @@ static void tec_cool(void) { tec_power(0); // ensure power is off while switching sleep_ms(2); // wait for the PWM to take effect - tec_power_yellow_off(); // disconnect 12V from yellow TEC line - tec_power_orange_on(); // connect 12V to orange TEC line - sleep_ms(10); // wait for relay to operate + tec_power_yellow_off(); // connect GND from yellow TEC line + tec_power_orange_on(); // connect VCC to orange TEC line // set TEC configuration to cool the top half at max // the following heating configurations exist (when orange is connected to minus and yellow to plus) @@ -463,7 +457,6 @@ static void command_bed_power(void* argument) tec_power_yellow_off(); // disconnect 12V from yellow TEC line tec_power_orange_off(); // disconnect 12V from orange TEC line heatsink_fan_off(); // we can switch the fan off now - sleep_ms(10); // wait for relay to operate bed_target = 0; // remember we have no target state = STATE_IDLE; // set new state } else if (target > 0) { // heat @@ -482,13 +475,17 @@ static void command_bed_power(void* argument) } // print segment status - if (gpio_get(GPIO_PORT(TEC_POWER_ORANGE), GPIO_PIN(TEC_POWER_ORANGE)) && gpio_get(GPIO_PORT(TEC_POWER_YELLOW), GPIO_PIN(TEC_POWER_YELLOW)) && gpio_get(GPIO_PORT(TEC_POWER_PWM), GPIO_PIN(TEC_POWER_PWM))) { - puts("TEC power disconnected\n"); - } else if (0 == gpio_get(GPIO_PORT(TEC_POWER_ORANGE), GPIO_PIN(TEC_POWER_ORANGE))) { + const bool yellow = gpio_get(GPIO_PORT(TEC_POWER_YELLOW), GPIO_PIN(TEC_POWER_YELLOW)); + const bool orange = gpio_get(GPIO_PORT(TEC_POWER_ORANGE), GPIO_PIN(TEC_POWER_ORANGE)); + if (!yellow && !orange) { + puts("TEC power off\n"); + } else if (orange && !yellow) { puts("TEC set to cooling\n"); - } else if (0 == gpio_get(GPIO_PORT(TEC_POWER_YELLOW), GPIO_PIN(TEC_POWER_YELLOW))) { + } else if (yellow && !orange) { puts("TEC set to heating\n"); + } else { + puts("unknown TEC power setting\n"); } } @@ -894,51 +891,31 @@ void main(void) puts("OK\n"); } - puts("setup TEC power supply relays: "); - // set as input to check if we are connected + puts("setup TEC power supply: "); rcc_periph_clock_enable(GPIO_RCC(TEC_POWER_YELLOW)); // enable clock for GPIO port peripheral - gpio_clear(GPIO_PORT(TEC_POWER_YELLOW), GPIO_PIN(TEC_POWER_YELLOW)); // pull down - gpio_set_mode(GPIO_PORT(TEC_POWER_YELLOW), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, GPIO_PIN(TEC_POWER_YELLOW)); // set pin as input + gpio_clear(GPIO_PORT(TEC_POWER_YELLOW), GPIO_PIN(TEC_POWER_YELLOW)); // don't connect wire to VCC + gpio_set_mode(GPIO_PORT(TEC_POWER_YELLOW), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(TEC_POWER_YELLOW)); // set pin as output rcc_periph_clock_enable(GPIO_RCC(TEC_POWER_ORANGE)); // enable clock for GPIO port peripheral - gpio_clear(GPIO_PORT(TEC_POWER_ORANGE), GPIO_PIN(TEC_POWER_ORANGE)); // pull down - gpio_set_mode(GPIO_PORT(TEC_POWER_ORANGE), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, GPIO_PIN(TEC_POWER_ORANGE)); // set pin as input - rcc_periph_clock_enable(GPIO_RCC(TEC_POWER_PWM)); // enable clock for GPIO port peripheral - gpio_clear(GPIO_PORT(TEC_POWER_PWM), GPIO_PIN(TEC_POWER_PWM)); // pull down - gpio_set_mode(GPIO_PORT(TEC_POWER_PWM), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, GPIO_PIN(TEC_POWER_PWM)); // set pin as input - sleep_us(100); // let pin settle - if (0 == gpio_get(GPIO_PORT(TEC_POWER_YELLOW), GPIO_PIN(TEC_POWER_YELLOW)) && 0 == gpio_get(GPIO_PORT(TEC_POWER_ORANGE), GPIO_PIN(TEC_POWER_ORANGE)) && 0 == gpio_get(GPIO_PORT(TEC_POWER_PWM), GPIO_PIN(TEC_POWER_PWM))) { - error = "TEC power controller not connected"; - puts("KO\n"); - } else if (gpio_get(GPIO_PORT(TEC_POWER_YELLOW), GPIO_PIN(TEC_POWER_YELLOW)) && gpio_get(GPIO_PORT(TEC_POWER_ORANGE), GPIO_PIN(TEC_POWER_ORANGE)) && gpio_get(GPIO_PORT(TEC_POWER_PWM), GPIO_PIN(TEC_POWER_PWM))) { // board is connected - // configure as output to control to relays - rcc_periph_clock_enable(GPIO_RCC(TEC_POWER_YELLOW)); // enable clock for GPIO port peripheral - gpio_set(GPIO_PORT(TEC_POWER_YELLOW), GPIO_PIN(TEC_POWER_YELLOW)); // don't sink current (e.g. not power relay to connect to 12V) - gpio_set_mode(GPIO_PORT(TEC_POWER_YELLOW), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN(TEC_POWER_YELLOW)); // set pin as output open-drain - rcc_periph_clock_enable(GPIO_RCC(TEC_POWER_ORANGE)); // enable clock for GPIO port peripheral - gpio_set(GPIO_PORT(TEC_POWER_ORANGE), GPIO_PIN(TEC_POWER_ORANGE)); // don't sink current (e.g. not power relay to connect to 12V) - gpio_set_mode(GPIO_PORT(TEC_POWER_ORANGE), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN(TEC_POWER_ORANGE)); // set pin as output open-drain - // set up PWM output - rcc_periph_clock_enable(RCC_TIM_CH(TEC_POWER_TIMER, TEC_POWER_CHANNEL)); // enable clock for GPIO peripheral - gpio_set(TIM_CH_PORT(TEC_POWER_TIMER, TEC_POWER_CHANNEL), TIM_CH_PIN(TEC_POWER_TIMER, TEC_POWER_CHANNEL)); // don't sink current (e.g. not powering the optocoupler/transistor) - gpio_set_mode(TIM_CH_PORT(TEC_POWER_TIMER, TEC_POWER_CHANNEL), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, TIM_CH_PIN(TEC_POWER_TIMER, TEC_POWER_CHANNEL)); // set pin as output - rcc_periph_clock_enable(RCC_AFIO); // enable clock for alternate function (PWM) - rcc_periph_clock_enable(RCC_TIM(TEC_POWER_TIMER)); // enable clock for timer peripheral - rcc_periph_reset_pulse(RST_TIM(TEC_POWER_TIMER)); // reset timer state - timer_set_mode(TIM(TEC_POWER_TIMER), TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // set timer mode, use undivided timer clock, edge alignment (simple count), and count up - // peltier elements can safely be PWMed at 300 Hz to 3000 Hz, we will keep it under 2 kHz to avoid the audible range - timer_set_prescaler(TIM(TEC_POWER_TIMER), rcc_ahb_frequency / 1500000 - 1); // set the clock frequency to 1.5 kHz - timer_set_period(TIM(TEC_POWER_TIMER), UINT16_MAX); // use the whole range as period, even if we can only control up to 100 Hz - timer_set_oc_value(TIM(TEC_POWER_TIMER), TEC_POWER_OC, 0); // duty cycle to 0%, to switch off heater - timer_set_oc_mode(TIM(TEC_POWER_TIMER), TEC_POWER_OC, TIM_OCM_PWM2); // set timer to generate PWM (heater switched of as long as CNT < CCR) - timer_enable_oc_output(TIM(TEC_POWER_TIMER), TEC_POWER_OC); // enable output to generate the PWM signal - timer_enable_break_main_output(TIM(TEC_POWER_TIMER)); // required to enable timer, even when no dead time is used - timer_set_counter(TIM(TEC_POWER_TIMER), 0); // reset counter - timer_enable_counter(TIM(TEC_POWER_TIMER)); // enable timer - puts("OK\n"); - } else { - error = "TEC power controller wrongly connected"; - puts("KO\n"); - } + gpio_clear(GPIO_PORT(TEC_POWER_ORANGE), GPIO_PIN(TEC_POWER_ORANGE)); // don't connect wire to VCC + gpio_set_mode(GPIO_PORT(TEC_POWER_ORANGE), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_PIN(TEC_POWER_ORANGE)); // set pin as output + // set up PWM output + rcc_periph_clock_enable(RCC_TIM_CH(TEC_POWER_TIMER, TEC_POWER_CHANNEL)); // enable clock for GPIO peripheral + gpio_clear(TIM_CH_PORT(TEC_POWER_TIMER, TEC_POWER_CHANNEL), TIM_CH_PIN(TEC_POWER_TIMER, TEC_POWER_CHANNEL)); // don't let power trough + gpio_set_mode(TIM_CH_PORT(TEC_POWER_TIMER, TEC_POWER_CHANNEL), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, TIM_CH_PIN(TEC_POWER_TIMER, TEC_POWER_CHANNEL)); // set pin as output + rcc_periph_clock_enable(RCC_AFIO); // enable clock for alternate function (PWM) + rcc_periph_clock_enable(RCC_TIM(TEC_POWER_TIMER)); // enable clock for timer peripheral + rcc_periph_reset_pulse(RST_TIM(TEC_POWER_TIMER)); // reset timer state + timer_set_mode(TIM(TEC_POWER_TIMER), TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // set timer mode, use undivided timer clock, edge alignment (simple count), and count up + // peltier elements can safely be PWMed at 300 Hz to 3000 Hz, we will keep it under 2 kHz to avoid the audible range + timer_set_prescaler(TIM(TEC_POWER_TIMER), rcc_ahb_frequency / 1500000 - 1); // set the clock frequency to 1.5 kHz + timer_set_period(TIM(TEC_POWER_TIMER), UINT16_MAX); // use the whole range as period, even if we can only control up to 100 Hz + timer_set_oc_value(TIM(TEC_POWER_TIMER), TEC_POWER_OC, 0); // duty cycle to 0%, to switch off heater + timer_set_oc_mode(TIM(TEC_POWER_TIMER), TEC_POWER_OC, TIM_OCM_PWM1); // set timer to generate PWM (heater switched of as long as CNT < CCR) + timer_enable_oc_output(TIM(TEC_POWER_TIMER), TEC_POWER_OC); // enable output to generate the PWM signal + timer_enable_break_main_output(TIM(TEC_POWER_TIMER)); // required to enable timer, even when no dead time is used + timer_set_counter(TIM(TEC_POWER_TIMER), 0); // reset counter + timer_enable_counter(TIM(TEC_POWER_TIMER)); // enable timer + puts("OK\n"); puts("setup heat sink fan: "); // we can't test if it is connected (we only control the MOSFET directly powering the fan)