]> mj.ucw.cz Git - home-hw.git/blob - ir-send/test.c
defdd22d9427271da1cd3360c4ace61ef318601d
[home-hw.git] / ir-send / test.c
1 #include "util.h"
2
3 #include <libopencm3/cm3/cortex.h>
4 #include <libopencm3/cm3/nvic.h>
5 #include <libopencm3/cm3/systick.h>
6 #include <libopencm3/stm32/rcc.h>
7 #include <libopencm3/stm32/gpio.h>
8 #include <libopencm3/stm32/usart.h>
9 #include <libopencm3/stm32/timer.h>
10
11 #include <string.h>
12
13 static void clock_setup(void)
14 {
15         rcc_clock_setup_in_hse_8mhz_out_72mhz();
16
17         rcc_periph_clock_enable(RCC_GPIOA);
18         rcc_periph_clock_enable(RCC_GPIOB);
19         rcc_periph_clock_enable(RCC_GPIOC);
20         rcc_periph_clock_enable(RCC_USART1);
21         rcc_periph_clock_enable(RCC_TIM1);
22         rcc_periph_clock_enable(RCC_TIM4);
23         rcc_periph_clock_enable(RCC_AFIO);
24
25         rcc_periph_reset_pulse(RST_GPIOA);
26         rcc_periph_reset_pulse(RST_GPIOB);
27         rcc_periph_reset_pulse(RST_GPIOC);
28         rcc_periph_reset_pulse(RST_USART1);
29         rcc_periph_reset_pulse(RST_TIM1);
30         rcc_periph_reset_pulse(RST_TIM4);
31 }
32
33 static void gpio_setup(void)
34 {
35         // PC13 = BluePill LED
36         gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
37         gpio_clear(GPIOC, GPIO13);
38
39         // Switch JTAG off to free up pins
40         gpio_primary_remap(AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON, 0);
41         // gpio_primary_remap(AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON, AFIO_MAPR_TIM2_REMAP_FULL_REMAP);
42
43         // TIM2_CH3 on PB3 (remapped)
44         // gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO10);
45
46         // TIM4_CH1 on PB6: PWM for fan control
47         gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO6);
48
49         // TIM4_CH2 on PB7: PWM for IR LED
50         gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO7);
51 }
52
53 static volatile u32 ms_ticks;
54
55 void sys_tick_handler(void)
56 {
57         ms_ticks++;
58 }
59
60 static void tick_setup(void)
61 {
62         systick_set_frequency(1000, 72000000);
63         systick_counter_enable();
64         systick_interrupt_enable();
65 }
66
67 static void UNUSED delay_ms(uint ms)
68 {
69         u32 start_ticks = ms_ticks;
70         while (ms_ticks - start_ticks < ms)
71                 ;
72 }
73
74 static void usart_setup(void)
75 {
76         gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART1_TX);
77         gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_USART1_RX);
78
79         usart_set_baudrate(USART1, 115200);
80         usart_set_databits(USART1, 8);
81         usart_set_stopbits(USART1, USART_STOPBITS_1);
82         usart_set_mode(USART1, USART_MODE_TX_RX);
83         usart_set_parity(USART1, USART_PARITY_NONE);
84         usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
85
86         usart_enable(USART1);
87 }
88
89 enum rc_keys {
90         RC_AUTO,
91         RC_TEMP_UP,
92         RC_FUNC,
93         RC_HI,
94         RC_TIMER,
95         RC_MID,
96         RC_TEMP_DOWN,
97         RC_SLEEP,
98         RC_LOW,
99         RC_POWER,
100         RC_XXX_A,
101         RC_XXX_B,
102         RC_MAX
103 };
104
105 static const char * const rc_patterns[RC_MAX] = {
106         [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*",
107         [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*",
108         [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*",
109         [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*",
110         [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*",
111         [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*",
112         [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*",
113         [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*",
114         [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*",
115         [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*",
116         [RC_XXX_A]      = "^#*A*B*A*A*B*A*B*B*A*A*B*A*A*A*A*A*A*B*B*B*B*A*A*A*B*A*A*A*A*B*B*B*",
117         [RC_XXX_B]      = "^#*A*B*A*A*B*A*B*B*A*A*B*A*A*A*A*A*B*B*B*B*B*A*A*A*A*A*A*A*A*B*B*B*",
118 };
119
120 // FIXME
121 static const char rc_keys[] = "aufhtmdslp12";
122
123 // TIM4 will run on CPU clock, it will overflow with frequency 38 kHz (IR modulation frequency)
124 #define T4_CYCLE ((CPU_CLOCK_MHZ * 1000000 + 37999) / 38000)
125
126 static void rc_setup(void)
127 {
128         timer_set_prescaler(TIM4, 0);
129         timer_set_mode(TIM4, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
130         timer_disable_preload(TIM4);
131         timer_set_period(TIM4, T4_CYCLE - 1);
132
133         // 50% PWM for the IR LED
134         timer_set_oc_mode(TIM4, TIM_OC2, TIM_OCM_PWM1);
135         timer_set_oc_value(TIM4, TIM_OC2, T4_CYCLE / 2);
136         timer_set_oc_polarity_high(TIM4, TIM_OC2);
137         timer_enable_oc_output(TIM4, TIM_OC2);
138
139         // PWM for controlling fan
140         timer_set_oc_mode(TIM4, TIM_OC1, TIM_OCM_PWM1);
141         timer_set_oc_value(TIM4, TIM_OC1, T4_CYCLE / 4);
142         timer_set_oc_polarity_high(TIM4, TIM_OC1);
143         timer_enable_oc_output(TIM4, TIM_OC1);
144
145         timer_enable_counter(TIM4);
146
147         // TIM1 runs at 1 MHz and it is used for timing of RC pulses
148         timer_set_prescaler(TIM1, CPU_CLOCK_MHZ - 1);
149         timer_set_mode(TIM1, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
150         timer_update_on_overflow(TIM1);
151         timer_disable_preload(TIM1);
152         timer_one_shot_mode(TIM1);
153         timer_enable_irq(TIM1, TIM_DIER_UIE);
154         nvic_enable_irq(NVIC_TIM1_UP_IRQ);
155 }
156
157 static const char *rc_pattern_pos;
158
159 void tim1_up_isr(void)
160 {
161         if (TIM_SR(TIM1) & TIM_SR_UIF) {
162                 TIM_SR(TIM1) &= ~TIM_SR_UIF;
163
164                 if (!rc_pattern_pos)    // Just to be sure
165                         return;
166
167                 bool val;       // 1=pulse, 0=break
168                 uint duration;  // in μs
169
170                 switch (*rc_pattern_pos++) {
171                         case '^':
172                                 val = 1;
173                                 duration = 9032;
174                                 break;
175                         case '#':
176                                 val = 0;
177                                 duration = 4457;
178                                 break;
179                         case '*':
180                                 val = 1;
181                                 duration = 619;
182                                 break;
183                         case 'A':
184                                 val = 0;
185                                 duration = 514;
186                                 break;
187                         case 'B':
188                                 val = 0;
189                                 duration = 1617;
190                                 break;
191                         default:
192                                 // End of transmission
193                                 gpio_set(GPIOC, GPIO13);        // FIXME
194                                 rc_pattern_pos = NULL;
195                                 val = 0;
196                                 duration = 10000;
197                 }
198
199                 if (val)
200                         timer_set_oc_mode(TIM4, TIM_OC2, TIM_OCM_PWM1);
201                 else
202                         timer_set_oc_mode(TIM4, TIM_OC2, TIM_OCM_FORCE_HIGH);
203
204                 timer_set_period(TIM1, duration - 1);
205                 timer_generate_event(TIM1, TIM_EGR_UG);
206                 timer_enable_counter(TIM1);
207         }
208 }
209
210 static void rc_send(uint key)
211 {
212         rc_pattern_pos = rc_patterns[key];
213
214         gpio_clear(GPIOC, GPIO13);
215
216         timer_set_period(TIM1, 1);
217         timer_generate_event(TIM1, TIM_EGR_UG);
218         timer_enable_counter(TIM1);
219 }
220
221 int main(void)
222 {
223         clock_setup();
224         gpio_setup();
225         tick_setup();
226         usart_setup();
227         rc_setup();
228
229         debug_puts("Hello world!\n");
230         gpio_set(GPIOC, GPIO13);
231
232         for (;;) {
233 #if 0
234                 gpio_toggle(GPIOC, GPIO13);
235                 delay_ms(1);
236                 timer_set_oc_mode(TIM4, TIM_OC2, TIM_OCM_FORCE_HIGH);
237                 gpio_toggle(GPIOC, GPIO13);
238                 delay_ms(1);
239                 timer_set_oc_mode(TIM4, TIM_OC2, TIM_OCM_PWM1);
240 #else
241                 if (usart_get_flag(USART1, USART_SR_RXNE)) {
242                         uint ch = usart_recv(USART1);
243                         const char *key = strchr(rc_keys, ch);
244                         if (key) {
245                                 debug_putc(ch);
246                                 rc_send(key - rc_keys);
247                         }
248                 }
249 #endif
250         }
251
252         return 0;
253 }