From 399334cb60092af42574f206ed932ae25bc723e3 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Sun, 14 Jul 2019 16:51:06 +0200 Subject: [PATCH] Aircon: basics --- aircon/Makefile | 6 ++ aircon/README | 12 ++- aircon/config.h | 30 ++++++ aircon/kerm | 5 + aircon/main.c | 238 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 287 insertions(+), 4 deletions(-) create mode 100644 aircon/Makefile create mode 100644 aircon/config.h create mode 100644 aircon/kerm create mode 100644 aircon/main.c diff --git a/aircon/Makefile b/aircon/Makefile new file mode 100644 index 0000000..e7d6e38 --- /dev/null +++ b/aircon/Makefile @@ -0,0 +1,6 @@ +ROOT=.. +BINARY=main +OBJS=main.o # ds18b20.o +LIB_OBJS=util-debug.o + +include $(ROOT)/mk/bluepill.mk diff --git a/aircon/README b/aircon/README index 1c5a496..80f672b 100644 --- a/aircon/README +++ b/aircon/README @@ -1,9 +1,10 @@ - +Assignment of peripherals and pins +================================== TIM1 timing of IR remote control TIM2 MODBUS timing TIM3 DS18B20 one-wire bus timing: CH1 drives DMA1, CH2 drives the line -TIM5 PWM: CH1 for fan control, CH2 for IR RC carrier +TIM4 PWM: CH1 for fan control, CH2 for IR RC carrier USART1 debugging USART3 MODBUS @@ -36,14 +37,17 @@ RXD3 - RS485 | PB11 PA8 | +--------------------+ Interface connector +=================== + + (this side to PCB edge) heat exchanger +24V heat exchanger GND heat exchanger bypass servo heat exchanger fan control (IN1) - - - - - temperature sensors VCC temperature sensors GND temperature sensors data bus + + (this side to BluePill) diff --git a/aircon/config.h b/aircon/config.h new file mode 100644 index 0000000..5e7ab4b --- /dev/null +++ b/aircon/config.h @@ -0,0 +1,30 @@ +/* + * Air Conditioning Controller -- Configuration + * + * (c) 2019 Martin Mareš + */ + +// Processor clock + +#define CPU_CLOCK_MHZ 72 + +// Debugging port + +#define DEBUG_USART USART1 + +// MODBUS library parameters + +#define MODBUS_USART USART3 +#define MODBUS_NVIC_USART_IRQ NVIC_USART3_IRQ +#define MODBUS_USART_ISR usart3_isr + +#define MODBUS_TXEN_GPIO_PORT GPIOA +#define MODBUS_TXEN_GPIO_PIN GPIO1 + +#define MODBUS_TIMER TIM2 +#define MODBUS_NVIC_TIMER_IRQ NVIC_TIM2_IRQ +#define MODBUS_TIMER_ISR tim2_isr + +#define MODBUS_OUR_ADDRESS 42 + +#define MODBUS_BAUD_RATE 19200 diff --git a/aircon/kerm b/aircon/kerm new file mode 100644 index 0000000..988f567 --- /dev/null +++ b/aircon/kerm @@ -0,0 +1,5 @@ +set port /dev/ttyUSB0 +set speed 115200 +set flow-control none +set carrier-watch off +connect diff --git a/aircon/main.c b/aircon/main.c new file mode 100644 index 0000000..75afedf --- /dev/null +++ b/aircon/main.c @@ -0,0 +1,238 @@ +/* + * Air Conditioning Controller + * + * (c) 2019 Martin Mareš + */ + +#include "util.h" +#include "ds18b20.h" + +#include +#include +#include +#include +#include +#include + +static void clock_setup(void) +{ + rcc_clock_setup_in_hse_8mhz_out_72mhz(); + + rcc_periph_clock_enable(RCC_GPIOA); + rcc_periph_clock_enable(RCC_GPIOB); + rcc_periph_clock_enable(RCC_GPIOC); + rcc_periph_clock_enable(RCC_USART1); + rcc_periph_clock_enable(RCC_USART3); + rcc_periph_clock_enable(RCC_TIM1); + rcc_periph_clock_enable(RCC_TIM2); + rcc_periph_clock_enable(RCC_TIM3); + rcc_periph_clock_enable(RCC_TIM4); + rcc_periph_clock_enable(RCC_DMA1); + + rcc_periph_reset_pulse(RST_GPIOA); + rcc_periph_reset_pulse(RST_GPIOB); + rcc_periph_reset_pulse(RST_GPIOC); + rcc_periph_reset_pulse(RST_USART1); + rcc_periph_reset_pulse(RST_USART3); + rcc_periph_reset_pulse(RST_TIM1); + rcc_periph_reset_pulse(RST_TIM2); + rcc_periph_reset_pulse(RST_TIM3); + rcc_periph_reset_pulse(RST_TIM4); +} + +static void gpio_setup(void) +{ + // PA6 = RS485 TX enable + gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO6); + gpio_clear(GPIOA, GPIO6); + + // PA7 = TIM3_CH2 for DS18B20 bus -- configured by ds18b20 library + + // PA9 = TXD1 for debugging console + gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO9); + + // PA10 = RXD1 for debugging console + gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO10); + + // PB0 = bypass LED* + gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO0); + gpio_set(GPIOB, GPIO0); + + // PB1 = IR RC active LED* + gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO1); + gpio_set(GPIOB, GPIO1); + + // PB6 = TIM3_CH1 fan control opto-coupler + gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO7); + + // PB7 = TIM3_CH2 IR LED + gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO7); + + // PB10 = TXD3 for RS485 + gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO10); + + // PB11 = RXD3 for RS485 + gpio_set_mode(GPIOB, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO11); + + // PC13 = BluePill LED + gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13); + gpio_clear(GPIOC, GPIO13); + + // PC15 = bypass opto-coupler + gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO15); + gpio_clear(GPIOC, GPIO15); +} + +static volatile u32 ms_ticks; + +void sys_tick_handler(void) +{ + ms_ticks++; +} + +static void tick_setup(void) +{ + systick_set_frequency(1000, 72000000); + systick_counter_enable(); + systick_interrupt_enable(); +} + +static void delay_ms(uint ms) +{ + u32 start_ticks = ms_ticks; + while (ms_ticks - start_ticks < ms) + ; +} + +static void usart_setup(void) +{ + usart_set_baudrate(USART1, 115200); + usart_set_databits(USART1, 8); + usart_set_stopbits(USART1, USART_STOPBITS_1); + usart_set_mode(USART1, USART_MODE_TX_RX); + usart_set_parity(USART1, USART_PARITY_NONE); + usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE); + + usart_enable(USART1); +} + +#if 0 + +static bool bypass_active; +static byte pwm; + +static void show_temperature(void) +{ + debug_putc('#'); + for (uint i=0; ds_sensors[i].address[0]; i++) { + debug_putc(' '); + int t = ds_sensors[i].current_temp; + if (t == DS_TEMP_UNKNOWN) + debug_puts("---.---"); + else + debug_printf("%3d.%03d", t / 1000, t % 1000); + } + debug_printf(" %d", bypass_active); + debug_printf(" %d", pwm); + debug_puts("\r\n"); +} + +static void pwm_init(void) +{ + timer_set_prescaler(TIM4, 3); // clock = 72 MHz / 2 = 36 MHz + timer_set_mode(TIM4, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); + timer_disable_preload(TIM4); + timer_set_period(TIM4, 255); // PWM frequency = 18 MHz / 256 = 70.3125 kHz FIXME + timer_set_oc_mode(TIM4, TIM_OC1, TIM_OCM_PWM1); + timer_set_oc_value(TIM4, TIM_OC1, 1); + pwm = 1; + /* + * 1 0.03 + * 4 0.48 + * 8 1.54 + * 12 2.71 + * 16 3.99 + * 24 6.34 + * 32 7.85 + * 64 7.95 + * 128 8.02 + * 255 + */ + timer_set_oc_polarity_high(TIM4, TIM_OC1); + timer_enable_counter(TIM4); + timer_enable_oc_output(TIM4, TIM_OC1); + + gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO6); +} + +#endif + +int main(void) +{ + clock_setup(); + gpio_setup(); + tick_setup(); + usart_setup(); + // pwm_init(); + + // ds_init(); + + debug_puts("Hello, world!\n"); + + for (;;) { + gpio_toggle(GPIOC, GPIO13); + + gpio_clear(GPIOB, GPIO1); + delay_ms(100); + gpio_set(GPIOB, GPIO1); + + gpio_clear(GPIOB, GPIO0); + delay_ms(100); + gpio_set(GPIOB, GPIO0); + } + +#if 0 + byte cycles = 0; + for (;;) { + gpio_toggle(GPIOC, GPIO13); + delay_ms(100); + ds_step(); + if (usart_get_flag(USART1, USART_SR_RXNE)) { + uint ch = usart_recv(USART1); + if (ch == 'B') { + bypass_active = 1; + gpio_set(GPIOC, GPIO15); // opto-coupler + gpio_clear(GPIOC, GPIO14); // LED + } else if (ch == 'b') { + bypass_active = 0; + gpio_clear(GPIOC, GPIO15); // opto-coupler + gpio_set(GPIOC, GPIO14); // LED + } else if (ch >= '0' && ch <= '9') { + pwm = 3*(ch - '0') + 1; + /* + * ch pwm % + * 0 1 0 + * 1 4 0 + * 2 7 18 + * 3 10 31 + * 4 13 44 + * 5 16 57 + * 6 19 71 + * 7 22 84 + * 8 25 97 + * 9 28 100 + * + * % = pwm*4.389 - 12.723 + */ + timer_set_oc_value(TIM4, TIM_OC1, pwm); + } + } + if (cycles++ >= 50) { + cycles = 0; + show_temperature(); + } + } +#endif + + return 0; +} -- 2.39.2