application: replace TEC power board with H-bridge

This commit is contained in:
King Kévin 2020-12-08 23:07:36 +01:00
parent eb55880296
commit b8cc7d7591
1 changed files with 49 additions and 72 deletions

View File

@ -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)