#include <libopencm3/stm32/usart.h>
#include <libopencm3/stm32/timer.h>
+#include <string.h>
+
static void clock_setup(void)
{
rcc_clock_setup_in_hse_8mhz_out_72mhz();
rcc_periph_clock_enable(RCC_GPIOB);
rcc_periph_clock_enable(RCC_GPIOC);
rcc_periph_clock_enable(RCC_USART1);
- rcc_periph_clock_enable(RCC_TIM2);
+ rcc_periph_clock_enable(RCC_TIM1);
+ rcc_periph_clock_enable(RCC_TIM4);
rcc_periph_clock_enable(RCC_AFIO);
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_TIM2);
+ rcc_periph_reset_pulse(RST_TIM1);
+ rcc_periph_reset_pulse(RST_TIM4);
}
static void gpio_setup(void)
gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
gpio_clear(GPIOC, GPIO13);
- // Remap TIM2
+ // Switch JTAG off to free up pins
+ gpio_primary_remap(AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON, 0);
// gpio_primary_remap(AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON, AFIO_MAPR_TIM2_REMAP_FULL_REMAP);
- AFIO_MAPR = 0x04000300;
+
+ // TIM2_CH3 on GPIOB3 (remapped)
+ // gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO10);
+
+ // TIM4_CH1 on GPIOB6: PWM for fan control
+ gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO6);
+
+ // TIM4_CH2 on GPIOB7: PWM for IR LED
+ gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO7);
}
static volatile u32 ms_ticks;
systick_interrupt_enable();
}
-static void delay_ms(uint ms)
+static void UNUSED delay_ms(uint ms)
{
u32 start_ticks = ms_ticks;
while (ms_ticks - start_ticks < ms)
static void usart_setup(void)
{
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART1_TX);
+ gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_USART1_RX);
usart_set_baudrate(USART1, 115200);
usart_set_databits(USART1, 8);
usart_enable(USART1);
}
+enum rc_keys {
+ RC_AUTO,
+ RC_TEMP_UP,
+ RC_FUNC,
+ RC_HI,
+ RC_TIMER,
+ RC_MID,
+ RC_TEMP_DOWN,
+ RC_SLEEP,
+ RC_LOW,
+ RC_POWER,
+ RC_MAX
+};
+
+static const char * const rc_patterns[RC_MAX] = {
+ [RC_AUTO] = "^#*A*A*A*A*A*A*A*B*B*B*B*B*B*B*B*A*A*B*B*A*B*A*A*B*B*A*A*B*A*B*B*A*",
+ [RC_TEMP_UP] = "^#*A*A*A*A*A*A*A*B*B*B*B*B*B*B*B*A*A*A*B*A*B*A*A*B*B*B*A*B*A*B*B*A*",
+ [RC_FUNC] = "^#*A*A*A*A*A*A*A*B*B*B*B*B*B*B*B*A*B*A*B*B*B*A*A*B*A*B*A*A*A*B*B*A*",
+ [RC_HI] = "^#*A*A*A*A*A*A*A*B*B*B*B*B*B*B*B*A*B*A*A*B*B*A*A*B*A*B*B*A*A*B*B*A*",
+ [RC_TIMER] = "^#*A*A*A*A*A*A*A*B*B*B*B*B*B*B*B*A*A*B*B*B*B*A*A*B*B*A*A*A*A*B*B*A*",
+ [RC_MID] = "^#*A*A*A*A*A*A*A*B*B*B*B*B*B*B*B*A*B*B*A*B*B*A*A*B*A*A*B*A*A*B*B*A*",
+ [RC_TEMP_DOWN] = "^#*A*A*A*A*A*A*A*B*B*B*B*B*B*B*B*A*B*A*B*A*B*A*A*B*A*B*A*B*A*B*B*A*",
+ [RC_SLEEP] = "^#*A*A*A*A*A*A*A*B*B*B*B*B*B*B*B*A*B*B*B*B*B*A*A*B*A*A*A*A*A*B*B*A*",
+ [RC_LOW] = "^#*A*A*A*A*A*A*A*B*B*B*B*B*B*B*B*A*A*B*A*B*B*A*A*B*B*A*B*A*A*B*B*A*",
+ [RC_POWER] = "^#*A*A*A*A*A*A*A*B*B*B*B*B*B*B*B*A*A*A*B*B*B*A*A*B*B*B*A*A*A*B*B*A*",
+};
+
+// FIXME
+static const char rc_keys[] = "aufhtmdslp";
+
+// TIM4 will run on CPU clock, it will overflow with frequency 38 kHz (IR modulation frequency)
+#define T4_CYCLE ((CPU_CLOCK_MHZ * 1000000 + 37999) / 38000)
+
+static void rc_setup(void)
+{
+ timer_set_prescaler(TIM4, 0);
+ 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, T4_CYCLE - 1);
+
+ // 50% PWM for the IR LED
+ timer_set_oc_mode(TIM4, TIM_OC2, TIM_OCM_PWM1);
+ timer_set_oc_value(TIM4, TIM_OC2, T4_CYCLE / 2);
+ timer_set_oc_polarity_high(TIM4, TIM_OC2);
+ timer_enable_oc_output(TIM4, TIM_OC2);
+
+ // PWM for controlling fan
+ timer_set_oc_mode(TIM4, TIM_OC1, TIM_OCM_PWM1);
+ timer_set_oc_value(TIM4, TIM_OC1, T4_CYCLE / 4);
+ timer_set_oc_polarity_high(TIM4, TIM_OC1);
+ timer_enable_oc_output(TIM4, TIM_OC1);
+
+ timer_enable_counter(TIM4);
+
+ // TIM1 runs at 1 MHz and it is used for timing of RC pulses
+ timer_set_prescaler(TIM1, CPU_CLOCK_MHZ - 1);
+ timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
+ timer_update_on_overflow(TIM1);
+ timer_disable_preload(TIM1);
+ timer_one_shot_mode(TIM1);
+ timer_enable_irq(TIM1, TIM_DIER_UIE);
+ nvic_enable_irq(NVIC_TIM1_UP_IRQ);
+}
+
+static const char *rc_pattern_pos;
+
+void tim1_up_isr(void)
+{
+ if (TIM_SR(TIM1) & TIM_SR_UIF) {
+ TIM_SR(TIM1) &= ~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 = 1;
+ duration = 9032;
+ break;
+ case '#':
+ val = 0;
+ duration = 4457;
+ break;
+ case '*':
+ val = 1;
+ duration = 619;
+ break;
+ case 'A':
+ val = 0;
+ duration = 514;
+ break;
+ case 'B':
+ val = 0;
+ duration = 1617;
+ break;
+ default:
+ // End of transmission
+ gpio_set(GPIOC, GPIO13); // FIXME
+ rc_pattern_pos = NULL;
+ val = 0;
+ duration = 10000;
+ }
+
+ if (val)
+ timer_set_oc_mode(TIM4, TIM_OC2, TIM_OCM_PWM1);
+ else
+ timer_set_oc_mode(TIM4, TIM_OC2, TIM_OCM_FORCE_HIGH);
+
+ timer_set_period(TIM1, duration - 1);
+ timer_generate_event(TIM1, TIM_EGR_UG);
+ timer_enable_counter(TIM1);
+ }
+}
+
+static void rc_send(uint key)
+{
+ rc_pattern_pos = rc_patterns[key];
+
+ gpio_clear(GPIOC, GPIO13);
+
+ timer_set_period(TIM1, 1);
+ timer_generate_event(TIM1, TIM_EGR_UG);
+ timer_enable_counter(TIM1);
+}
+
int main(void)
{
clock_setup();
gpio_setup();
tick_setup();
usart_setup();
+ rc_setup();
- // cm_enable_interrupts();
- debug_puts("Hello!\n");
-
-#if 1
- timer_set_prescaler(TIM2, 3);
- timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
- timer_disable_preload(TIM2);
- timer_set_period(TIM2, 65535);
- timer_set_oc_mode(TIM2, TIM_OC3, TIM_OCM_PWM1);
- timer_set_oc_value(TIM2, TIM_OC3, 32768);
- timer_set_oc_polarity_high(TIM2, TIM_OC3);
- timer_enable_counter(TIM2);
- timer_enable_oc_output(TIM2, TIM_OC3);
-#endif
-
- gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO10);
- // gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO10);
- gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO15);
+ debug_puts("Hello world!\n");
+ gpio_set(GPIOC, GPIO13);
for (;;) {
+#if 0
gpio_toggle(GPIOC, GPIO13);
- delay_ms(20);
- gpio_toggle(GPIOA, GPIO15);
- debug_putc('.');
- timer_set_oc_mode(TIM2, TIM_OC3, TIM_OCM_FORCE_LOW);
- delay_ms(20);
- timer_set_oc_mode(TIM2, TIM_OC3, TIM_OCM_FORCE_HIGH);
+ delay_ms(1);
+ timer_set_oc_mode(TIM4, TIM_OC2, TIM_OCM_FORCE_HIGH);
+ gpio_toggle(GPIOC, GPIO13);
+ delay_ms(1);
+ timer_set_oc_mode(TIM4, TIM_OC2, TIM_OCM_PWM1);
+#else
+ if (usart_get_flag(USART1, USART_SR_RXNE)) {
+ uint ch = usart_recv(USART1);
+ const char *key = strchr(rc_keys, ch);
+ if (key) {
+ debug_putc(ch);
+ rc_send(key - rc_keys);
+ }
+ }
+#endif
}
return 0;