/*
* Workshop Clock
*
- * (c) 2020 Martin Mareš <mj@ucw.cz>
+ * (c) 2020-2023 Martin Mareš <mj@ucw.cz>
*/
#include "util.h"
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/usart.h>
#include <libopencm3/stm32/i2c.h>
+#include <libopencm3/stm32/timer.h>
#include <libopencm3/usb/dfu.h>
#include <libopencm3/usb/usbd.h>
static void clock_init(void)
{
- rcc_clock_setup_in_hse_8mhz_out_72mhz();
+ rcc_clock_setup_pll(&rcc_hse_configs[RCC_CLOCK_HSE8_72MHZ]);
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_GPIOB);
rcc_periph_clock_enable(RCC_I2C1);
rcc_periph_clock_enable(RCC_USART1);
rcc_periph_clock_enable(RCC_USB);
+ rcc_periph_clock_enable(RCC_TIM1);
rcc_periph_reset_pulse(RST_GPIOA);
rcc_periph_reset_pulse(RST_GPIOB);
rcc_periph_reset_pulse(RST_I2C1);
rcc_periph_reset_pulse(RST_USART1);
rcc_periph_reset_pulse(RST_USB);
+ rcc_periph_reset_pulse(RST_TIM1);
}
static void gpio_init(void)
// PB6 = SCL for display controller
gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO6 | GPIO7);
- // PB8 = SFH5110 output (5V tolerant)
+ // PA8 = SFH5110 output (5V tolerant) connected to TIM1_CH1
gpio_set_mode(GPIOC, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO8);
}
static void display_update(void)
{
- debug_puts("Display update\n");
+ // debug_puts("Display update\n");
byte cmds[4];
cmds[0] = 0;
cmds[1] = ctrl;
cmds[3] = disp[2];
i2c_transfer7(I2C1, 0x70/2, (byte *) cmds, sizeof(cmds), NULL, 0);
- debug_puts("Update done\n");
+ // debug_puts("Update done\n");
}
static void display_init(void)
[15] = 0x78,
};
+/*** Infrared Remote Control ***/
+
+static void ir_init(void)
+{
+ debug_puts("IR init\n");
+
+ timer_set_prescaler(TIM1, 71); // 72 MHz / 72 = 1 MHz
+ timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
+ timer_set_period(TIM1, 65535);
+ timer_update_on_overflow(TIM1);
+
+ // IC1 will trigger on TI1 (TIM1_CH1) falling edge
+ timer_ic_set_input(TIM1, TIM_IC1, TIM_IC_IN_TI1);
+ // timer_ic_set_filter(TIM1, TIM_IC1, TIM_IC_OFF);
+ timer_set_oc_polarity_low(TIM1, TIM_OC1); // OC functions affect IC, too
+
+ // IC2 will trigger on TI1 (TIM1_CH1) rising edge
+ timer_ic_set_input(TIM1, TIM_IC2, TIM_IC_IN_TI1);
+ timer_set_oc_polarity_high(TIM1, TIM_OC2);
+
+ // CH3 will trigger on a break longer than 50 ms
+ timer_set_oc_mode(TIM1, TIM_OC3, TIM_OCM_ACTIVE);
+ timer_set_oc_value(TIM1, TIM_OC3, 30000);
+
+ // Program slave controller to reset the timer on IC1
+ timer_slave_set_trigger(TIM1, TIM_SMCR_TS_TI1FP1);
+ timer_slave_set_mode(TIM1, TIM_SMCR_SMS_RM);
+
+ // Request interrupts
+ timer_enable_irq(TIM1, TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE);
+ nvic_enable_irq(NVIC_TIM1_CC_IRQ);
+
+ // Enable ICs and OCs
+ timer_enable_oc_output(TIM1, TIM_OC1);
+ timer_enable_oc_output(TIM1, TIM_OC2);
+ timer_enable_oc_output(TIM1, TIM_OC3);
+
+ timer_enable_counter(TIM1);
+}
+
+#define IR_MAX_PULSES 64
+static u16 ir_pulses[IR_MAX_PULSES];
+static uint ir_num_pulses;
+static u16 ir_last_pulse;
+
+void tim1_cc_isr(void)
+{
+ if (TIM_SR(TIM1) & TIM_SR_CC1IF) {
+ TIM_SR(TIM1) &= ~TIM_SR_CC1IF;
+ u16 now = TIM_CCR1(TIM1);
+ if (ir_last_pulse) {
+ ir_pulses[ir_num_pulses++] = ir_last_pulse;
+ ir_pulses[ir_num_pulses++] = now - ir_last_pulse;
+ ir_last_pulse = 0;
+ }
+ }
+ if (TIM_SR(TIM1) & TIM_SR_CC2IF) {
+ TIM_SR(TIM1) &= ~TIM_SR_CC2IF;
+ ir_last_pulse = TIM_CCR2(TIM1);
+ }
+ if (TIM_SR(TIM1) & TIM_SR_CC3IF) {
+ TIM_SR(TIM1) &= ~TIM_SR_CC3IF;
+ if (ir_last_pulse) {
+ ir_pulses[ir_num_pulses++] = ir_last_pulse;
+ ir_pulses[ir_num_pulses++] = 0xffff;
+ }
+ ir_last_pulse = 0;
+ }
+}
+
/*** USB ***/
static usbd_device *usbd_dev;
usb_event_pending = 1;
}
-/*** Testing of IR receiver ***/
-
-#ifdef IR_TEST
-
-static u16 get_bit(void)
-{
-#if 1
- return !gpio_get(GPIOB, GPIO8);
-#else
- int x = 0;
- x += !gpio_get(GPIOB, GPIO8);
- x += !gpio_get(GPIOB, GPIO8);
- x += !gpio_get(GPIOB, GPIO8);
- x += !gpio_get(GPIOB, GPIO8);
- return x >= 2;
-#endif
-}
-
-#define MAX_SAMPLES 1024
-u32 samples[MAX_SAMPLES];
-
-static void ir_test_loop(void)
-{
- debug_puts("\n\n### Infrared Remote Control receiver ###\n\n");
-
- systick_set_reload(0xffffff);
- systick_counter_enable();
- systick_interrupt_disable();
- systick_clear();
-
- for (;;) {
- gpio_set(GPIOC, GPIO13);
-
- if (get_bit()) {
- debug_puts("Waiting for silence\n");
- while (get_bit())
- ;
- }
- debug_puts("Ready...");
-
- u16 last = 0;
- uint nsamp = 0;
- u32 start;
-
- do {
- start = systick_get_value();
- last = get_bit();
- } while (!last);
-
- gpio_clear(GPIOC, GPIO13);
-
- for (;;) {
- u32 now;
- u16 curr;
- uint len;
- do {
- now = systick_get_value();
- len = (start - now) & 0xffffff;
- if (len > 5000000) {
- samples[nsamp++] = len;
- goto timeout;
- }
- curr = get_bit();
- } while (curr == last);
- samples[nsamp++] = len;
- if (nsamp >= MAX_SAMPLES)
- break;
- start = now;
- last = curr;
- }
-
- timeout:
- for (uint i=0; i<nsamp; i++) {
- debug_putc(i ? ' ' : '\n');
- debug_printf("%u", (unsigned int)((samples[i] + CPU_CLOCK_MHZ - 1) / CPU_CLOCK_MHZ)); // in μs
- }
- debug_putc('\n');
- }
-}
-
-#endif
-
/*** Main ***/
int main(void)
gpio_init();
usart_init();
-#ifdef IR_TEST
- ir_test_loop();
-#endif
-
tick_init();
desig_get_unique_id_as_dfu(usb_serial_number);
usb_init();
display_init();
+ ir_init();
u32 last_blink = 0;
nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ);
}
+ static u16 pulses[IR_MAX_PULSES];
+ uint np;
+
+ cm_disable_interrupts();
+ np = ir_num_pulses;
+ memcpy(pulses, ir_pulses, 2*np);
+ ir_num_pulses = 0;
+ cm_enable_interrupts();
+
+ if (np) {
+ debug_printf("IR:");
+ for (uint i=0; i < np; i++)
+ debug_printf(" %u", pulses[i]);
+ debug_putc('\n');
+ }
+
wait_for_interrupt();
}