From 3755cad586d07d639b55f0b4c6fca6859b6858d0 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Thu, 13 Jul 2023 16:55:50 +0200 Subject: [PATCH] test-sinclair: Experiments with RC --- test-sinclair/README | 4 +- test-sinclair/main.c | 156 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 158 insertions(+), 2 deletions(-) diff --git a/test-sinclair/README b/test-sinclair/README index cdb49b8..80095ed 100644 --- a/test-sinclair/README +++ b/test-sinclair/README @@ -3,6 +3,8 @@ Assignment of peripherals and pins SPI2 emulated TM1618 LED driver USART1 debugging +TIM3 TM1618 timeout +TIM4 timing of IR remote control Blue Pill pinout @@ -22,7 +24,7 @@ BluePill LED | PC13 GND | | PB0 PA11 | | PB1 PA10 | RXD1 - debugging console | PB10 PA9 | TXD1 - debugging console - | PB11 PA8 | + | PB11 PA8 | IR remote control | RESET PB15 | MOSI2 - LED driver data input | 3.3 V PB14 | MISO2 - unused | GND PB13 | SCK2 - LED driver clock diff --git a/test-sinclair/main.c b/test-sinclair/main.c index 753bcfd..29ddb6a 100644 --- a/test-sinclair/main.c +++ b/test-sinclair/main.c @@ -34,6 +34,7 @@ static void clock_init(void) rcc_periph_clock_enable(RCC_USART1); rcc_periph_clock_enable(RCC_USB); rcc_periph_clock_enable(RCC_TIM3); + rcc_periph_clock_enable(RCC_TIM4); rcc_periph_reset_pulse(RST_GPIOA); rcc_periph_reset_pulse(RST_GPIOB); @@ -42,6 +43,7 @@ static void clock_init(void) rcc_periph_reset_pulse(RST_USART1); rcc_periph_reset_pulse(RST_USB); rcc_periph_reset_pulse(RST_TIM3); + rcc_periph_reset_pulse(RST_TIM4); } static void gpio_init(void) @@ -59,6 +61,10 @@ static void gpio_init(void) // PB15 = MOSI2 gpio_set_mode(GPIOB, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO13); gpio_set_mode(GPIOB, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO15); + + // PA8 = IR remote control + gpio_clear(GPIOA, GPIO8); + gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO8); } static void usart_init(void) @@ -66,7 +72,7 @@ static void usart_init(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); + usart_set_mode(USART1, USART_MODE_TX_RX); usart_set_parity(USART1, USART_PARITY_NONE); usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE); @@ -294,6 +300,148 @@ static void tm_show(void) #endif } +/*** Infra-red remote control simulator ***/ + +enum rc_keys { + RC_POWER_OFF, + RC_POWER_ON, + RC_HIGH, + RC_MED, + RC_LO, + RC_SLEEP, + RC_DRY, + RC_WARM, + RC_COLD, + RC_T17, + RC_T18, + RC_T19, + RC_T20, + RC_T21, + RC_T22, + RC_T23, + RC_T24, + RC_T25, + RC_T26, + RC_T27, + RC_T28, + RC_T29, + RC_T30, + RC_MAX +}; + +static const char * const rc_patterns[RC_MAX] = { + [RC_POWER_OFF] = "*#*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*B*A*B*A*A*B*A*A*#*$", + [RC_POWER_ON] = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*B*A*B*A*A*A*A*B*#*$", + [RC_HIGH] = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*B*A*A*A*B*A*B*A*B*A*A*B*#*$", + [RC_MED] = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*B*A*A*A*B*B*A*B*A*B*B*B*B*#*$", + [RC_LO] = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*B*A*A*A*B*A*B*A*B*A*B*B*A*B*#*$", + [RC_SLEEP] = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*B*A*A*B*A*A*A*B*A*B*A*B*A*A*B*A*B*#*$", + [RC_DRY] = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*B*A*A*B*A*A*B*A*B*A*B*A*B*B*#*$", + [RC_WARM] = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*B*B*B*A*B*A*B*B*B*A*#*$", + [RC_COLD] = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*B*A*B*A*A*A*A*B*#*$", + [RC_T17] = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*A*A*B*A*B*A*A*B*#*$", + [RC_T18] = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*A*A*B*B*B*A*A*A*#*$", + [RC_T19] = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*A*B*A*A*A*B*B*B*#*$", + [RC_T20] = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*A*B*A*B*A*B*B*A*#*$", + [RC_T21] = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*A*B*B*A*A*B*A*B*#*$", + [RC_T22] = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*A*B*B*B*A*B*A*A*#*$", + [RC_T23] = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*B*A*A*A*A*A*B*B*#*$", + [RC_T24] = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*B*A*A*B*A*A*B*A*#*$", + [RC_T25] = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*B*A*B*A*A*A*A*B*#*$", + [RC_T26] = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*B*A*B*B*A*A*A*A*#*$", + [RC_T27] = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*B*B*A*A*B*B*B*B*#*$", + [RC_T28] = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*B*B*A*B*B*B*B*A*#*$", + [RC_T29] = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*B*B*B*A*B*B*A*B*#*$", + [RC_T30] = "*#*A*A*A*A*A*A*B*B*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*A*B*A*A*A*A*A*A*A*A*B*B*B*B*B*B*A*A*#*$", +}; + +static const char rc_keys[] = "Oohmlsdwc7890123456&*()"; + +static void rc_init(void) +{ + // TIM4 runs at 1 MHz and it is used for timing of RC pulses + timer_set_prescaler(TIM4, CPU_CLOCK_MHZ - 1); + timer_set_mode(TIM4, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); + timer_update_on_overflow(TIM4); + timer_disable_preload(TIM4); + timer_one_shot_mode(TIM4); + timer_enable_irq(TIM4, TIM_DIER_UIE); + nvic_enable_irq(NVIC_TIM4_IRQ); +} + +static volatile const char *rc_pattern_pos; +static volatile char rc_pending; + +void tim4_isr(void) +{ + if (TIM_SR(TIM4) & TIM_SR_UIF) { + TIM_SR(TIM4) &= ~TIM_SR_UIF; + + if (!rc_pattern_pos) // Just to be sure + return; + + bool val; // 1=pulse, 0=break + uint duration; // in μs + + switch (*rc_pattern_pos++) { + case '#': + val = 0; + duration = 3600; + break; + case '*': + val = 1; + duration = 565; + break; + case 'A': + val = 0; + duration = 480; + break; + case 'B': + val = 0; + duration = 1471; + break; + case '$': + val = 0; + duration = 10000; + break; + default: + // End of transmission + rc_pattern_pos = NULL; + rc_pending = 0; + return; + } + + if (val) + gpio_set(GPIOA, GPIO8); + else + gpio_clear(GPIOA, GPIO8); + + timer_set_period(TIM4, duration - 1); + timer_generate_event(TIM4, TIM_EGR_UG); + timer_enable_counter(TIM4); + } +} + +static bool rc_send(char key) +{ + if (rc_pending) + return false; + if (!key) + return false; + + const char *s = strchr(rc_keys, key); + if (!s) + return false; + rc_pending = key; + rc_pattern_pos = rc_patterns[s - rc_keys]; + debug_printf("RC sending: %c\n", key); + + timer_set_period(TIM4, 1); + timer_generate_event(TIM4, TIM_EGR_UG); + timer_enable_counter(TIM4); + return true; +} + /*** USB ***/ static usbd_device *usbd_dev; @@ -496,6 +644,7 @@ int main(void) debug_printf("Hello, world!\n"); tm_init(); + rc_init(); usb_init(); u32 last_blink = 0; @@ -507,6 +656,11 @@ int main(void) tm_show(); } + if (usart_get_flag(USART1, USART_SR_RXNE)) { + uint ch = usart_recv(USART1); + debug_putc(ch); + } + if (usb_event_pending) { usbd_poll(usbd_dev); usb_event_pending = 0; -- 2.39.2