]>
Commit | Line | Data |
---|---|---|
b8dc4070 L |
1 | /*------------------------------------------------------------------------------\r |
2 | * irmp-main.c - demo program to test the IRMP decoder on STM32F1 whith libopencm3\r | |
b1a276a1 | 3 | *\r |
b8dc4070 L |
4 | * Copyright (c) 2017 Leo C. <erbl259-lmu@yahoo.de>\r |
5 | *\r | |
6 | * This demo program is essentially a combination of some libopencm3 examples\r | |
113f999d | 7 | * from https://github.com/libopencm3/libopencm3-examples\r |
b8dc4070 | 8 | * and irmp-main-stm32.c from the IRMP distribution, which is\r |
b1a276a1 L |
9 | * Copyright (c) 2009-2016 Frank Meyer - frank(at)fli4l.de\r |
10 | *\r | |
b8dc4070 L |
11 | * The program demonstrates the integration of IRMP in a libopencm3 environment,\r |
12 | * and how to use the libopencm3 api functions, or alternatively direct\r | |
13 | * register access, using the macros defined by libopencm3.\r | |
b1a276a1 | 14 | *\r |
b8dc4070 | 15 | * This demo runs on the Generic STM32F103C8T6 Development Board, aka bluepill.\r |
b1a276a1 L |
16 | *\r |
17 | * This program is free software; you can redistribute it and/or modify\r | |
18 | * it under the terms of the GNU General Public License as published by\r | |
19 | * the Free Software Foundation; either version 2 of the License, or\r | |
20 | * (at your option) any later version.\r | |
b8dc4070 | 21 | *------------------------------------------------------------------------------\r |
b1a276a1 L |
22 | */\r |
23 | \r | |
24 | #include "config.h"\r | |
25 | #include "timer.h"\r | |
26 | #include "serial.h"\r | |
27 | #include "irmp.h"\r | |
28 | #include <libopencm3/stm32/rcc.h>\r | |
29 | #include <libopencm3/stm32/gpio.h>\r | |
30 | #include <stdio.h>\r | |
31 | \r | |
b8dc4070 L |
32 | /* The folloing macros can also be defined in the Makefile */\r |
33 | /* If 0 or undefined, use direct register access where appropriate,\r | |
34 | * else use the libopencm3 api functions everywhere. */\r | |
b1a276a1 | 35 | #ifndef USE_OPENCM3_API\r |
b8dc4070 | 36 | #define USE_OPENCM3_API 0\r |
b1a276a1 L |
37 | #endif\r |
38 | \r | |
b8dc4070 | 39 | /* Toggle a pin on irmp timer isr entry and exit */\r |
b1a276a1 L |
40 | #ifndef DEBUG_IRMP_TIMER_INT\r |
41 | #define DEBUG_IRMP_TIMER_INT 0\r | |
42 | #endif\r | |
43 | \r | |
b8dc4070 L |
44 | /**\r |
45 | * Do all initialisations, that are not done by a specific module here.\r | |
46 | */\r | |
b1a276a1 L |
47 | static void setup_clock_and_gpios(void)\r |
48 | {\r | |
49 | /* Clock setup */\r | |
50 | /* Default clock is 8MHz HSI */\r | |
51 | //rcc_clock_setup_in_hse_8mhz_out_24mhz();\r | |
b8dc4070 | 52 | //rcc_clock_setup_in_hse_8mhz_out_72mhz();\r |
b1a276a1 L |
53 | \r |
54 | /* GPIO setup */\r | |
55 | /* Only the on board led is configured here */\r | |
56 | \r | |
57 | rcc_periph_clock_enable(RCC_LED_PORT);\r | |
58 | \r | |
59 | /* Set GPIO13 (in GPIO port C) to 'output push-pull'. */\r | |
60 | /* Manually: */\r | |
61 | // GPIOC_CRH = (GPIO_CNF_OUTPUT_PUSHPULL << (((12 - 8) * 4) + 2));\r | |
62 | // GPIOC_CRH |= (GPIO_MODE_OUTPUT_2_MHZ << ((12 - 8) * 4));\r | |
63 | /* Using API functions: */\r | |
64 | gpio_set(LED_PORT, LED_PIN); /* set output register high (led off) */\r | |
65 | gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_2_MHZ,\r | |
66 | GPIO_CNF_OUTPUT_PUSHPULL, LED_PIN);\r | |
67 | }\r | |
68 | \r | |
69 | /*--------------------------------------------------------------------------*/\r | |
70 | /* IRMP */\r | |
71 | /*--------------------------------------------------------------------------*/\r | |
72 | \r | |
dbc48aa1 L |
73 | #define IRMP_TIMER_NUMBER 3\r |
74 | #define IRMP_TIMER CONCAT(TIM, IRMP_TIMER_NUMBER)\r | |
75 | \r | |
e380aa53 L |
76 | #define IRMP_TIMER_CR1 TIM_CR1(IRMP_TIMER)\r |
77 | #define IRMP_TIMER_DIER TIM_DIER(IRMP_TIMER)\r | |
78 | #define IRMP_TIMER_SR TIM_SR(IRMP_TIMER)\r | |
79 | #define IRMP_TIMER_ARR TIM_ARR(IRMP_TIMER)\r | |
dbc48aa1 | 80 | #define IRMP_TIMER_RCC CONCAT(RCC_TIM, IRMP_TIMER_NUMBER)\r |
e380aa53 | 81 | #define NVIC_IRMP_TIMER_IRQ CONCAT(CONCAT(NVIC_TIM, IRMP_TIMER_NUMBER), _IRQ)\r |
dbc48aa1 | 82 | #define IRMP_TIMER_ISR CONCAT(CONCAT(tim, IRMP_TIMER_NUMBER), _isr)\r |
b1a276a1 L |
83 | \r |
84 | \r | |
b8dc4070 L |
85 | /** Retrieve the actual input clock of a timer\r |
86 | \r | |
87 | @param[in] timer_peripheral Unsigned int32. Timer register address base\r | |
88 | @returns Unsigned int32. frequency value.\r | |
89 | */\r | |
b1a276a1 L |
90 | uint32_t timer_internal_clock_get(uint32_t timer_peripheral)\r |
91 | {\r | |
92 | uint32_t timer_frequency;\r | |
b1a276a1 L |
93 | \r |
94 | /* Get preripheral bus frequency and prescaler mask */\r | |
e380aa53 L |
95 | if ((timer_peripheral >= TIM2 && timer_peripheral <= TIM5)\r |
96 | || (timer_peripheral >= TIM12 && timer_peripheral <= TIM14))\r | |
97 | {\r | |
b1a276a1 | 98 | timer_frequency = rcc_apb1_frequency;\r |
e380aa53 L |
99 | } else {\r |
100 | timer_frequency = rcc_apb2_frequency;\r | |
b1a276a1 L |
101 | }\r |
102 | /* Timer clock is doubled, if the APB prescaler is greater than 1 */\r | |
e380aa53 | 103 | if (timer_frequency != rcc_ahb_frequency)\r |
b1a276a1 L |
104 | timer_frequency *= 2;\r |
105 | \r | |
106 | return timer_frequency;\r | |
107 | }\r | |
108 | \r | |
b8dc4070 L |
109 | /**\r |
110 | * Intialize the irmp interrupt timer\r | |
111 | */\r | |
b1a276a1 L |
112 | void irmp_timer_init (void)\r |
113 | {\r | |
114 | #if DEBUG_IRMP_TIMER_INT\r | |
115 | /* Output pin for debugging */\r | |
116 | rcc_periph_clock_enable(RCC_GPIOA);\r | |
117 | gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,\r | |
118 | GPIO_CNF_OUTPUT_PUSHPULL, GPIO2);\r | |
119 | #endif\r | |
120 | /* Enable timer clock. */\r | |
dbc48aa1 | 121 | rcc_periph_clock_enable(IRMP_TIMER_RCC);\r |
e380aa53 L |
122 | nvic_set_priority(NVIC_IRMP_TIMER_IRQ, 4*16);\r |
123 | nvic_enable_irq(NVIC_IRMP_TIMER_IRQ);\r | |
b1a276a1 L |
124 | \r |
125 | #if USE_OPENCM3_API /* Using API functions: */\r | |
126 | \r | |
127 | /* Timer global mode:\r | |
128 | * - No divider\r | |
129 | * - Alignment edge\r | |
130 | * - Direction up\r | |
131 | * (These are actually default values after reset, so this call\r | |
132 | * is strictly unnecessary, but demos the api for alternative settings)\r | |
133 | */\r | |
e380aa53 | 134 | timer_set_mode(IRMP_TIMER, TIM_CR1_CKD_CK_INT,\r |
b1a276a1 | 135 | TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);\r |
e380aa53 | 136 | timer_set_period(IRMP_TIMER, timer_internal_clock_get(IRMP_TIMER) / F_INTERRUPTS - 1);\r |
b1a276a1 | 137 | /* Enable Channel 1 compare interrupt to recalculate compare values */\r |
e380aa53 | 138 | timer_enable_irq(IRMP_TIMER, TIM_DIER_UIE);\r |
b1a276a1 | 139 | /* Counter enable. */\r |
e380aa53 | 140 | timer_enable_counter(IRMP_TIMER);\r |
b1a276a1 L |
141 | \r |
142 | #else /* Manually */\r | |
143 | \r | |
e380aa53 L |
144 | IRMP_TIMER_CR1 = TIM_CR1_CKD_CK_INT | TIM_CR1_CMS_EDGE | TIM_CR1_DIR_UP;\r |
145 | IRMP_TIMER_ARR = timer_internal_clock_get(IRMP_TIMER) / F_INTERRUPTS - 1;\r | |
b1a276a1 L |
146 | \r |
147 | /* Enable Timer interrupt and timer */\r | |
e380aa53 L |
148 | IRMP_TIMER_DIER = TIM_DIER_UIE;\r |
149 | IRMP_TIMER_CR1 |= TIM_CR1_CEN;\r | |
b1a276a1 L |
150 | \r |
151 | #endif\r | |
152 | }\r | |
153 | \r | |
154 | void IRMP_TIMER_ISR(void)\r | |
155 | {\r | |
156 | #if DEBUG_IRMP_TIMER_INT\r | |
157 | # if USE_OPENCM3_API /* Using API functions: */\r | |
158 | \r | |
159 | gpio_clear(GPIOA, GPIO2);\r | |
160 | /* Clear update interrupt flag. */\r | |
e380aa53 | 161 | timer_clear_flag(IRMP_TIMER, TIM_SR_UIF);\r |
b1a276a1 L |
162 | # else /* Manually */\r |
163 | GPIO_BRR(GPIOA) = GPIO2;\r | |
164 | # endif\r | |
165 | #endif\r | |
166 | /* Clear update interrupt flag. */\r | |
e380aa53 | 167 | IRMP_TIMER_SR = ~TIM_SR_UIF;\r |
b1a276a1 L |
168 | \r |
169 | (void) irmp_ISR(); // call irmp ISR\r | |
170 | \r | |
171 | // call other timer interrupt routines...\r | |
172 | \r | |
173 | #if DEBUG_IRMP_TIMER_INT\r | |
174 | # if USE_OPENCM3_API /* Using API functions: */\r | |
175 | gpio_set(GPIOA, GPIO2);\r | |
176 | # else /* Manually */\r | |
177 | GPIO_BSRR(GPIOA) = GPIO2;\r | |
178 | # endif\r | |
179 | #endif\r | |
180 | }\r | |
181 | \r | |
182 | /*--------------------------------------------------------------------------*/\r | |
183 | \r | |
b8dc4070 L |
184 | /** Test if a IR protocol is supported\r |
185 | *\r | |
186 | * Return true, if proto is valid protocol number and the protocol\r | |
187 | * is enabled in irmpconfig.h\r | |
188 | */\r | |
b1a276a1 L |
189 | int irmp_protocol_is_supported(int proto)\r |
190 | {\r | |
191 | #if IRMP_SUPPORT_SIRCS_PROTOCOL\r | |
192 | if (proto == IRMP_SIRCS_PROTOCOL) return 1;\r | |
193 | #endif\r | |
194 | #if IRMP_SUPPORT_NEC_PROTOCOL\r | |
195 | if (proto == IRMP_NEC_PROTOCOL) return 1;\r | |
196 | #endif\r | |
197 | #if IRMP_SUPPORT_SAMSUNG_PROTOCOL\r | |
198 | if (proto == IRMP_SAMSUNG_PROTOCOL) return 1;\r | |
199 | #endif\r | |
200 | #if IRMP_SUPPORT_KASEIKYO_PROTOCOL\r | |
201 | if (proto == IRMP_KASEIKYO_PROTOCOL) return 1;\r | |
202 | #endif\r | |
203 | #if IRMP_SUPPORT_JVC_PROTOCOL\r | |
204 | if (proto == IRMP_JVC_PROTOCOL) return 1;\r | |
205 | #endif\r | |
206 | #if IRMP_SUPPORT_NEC16_PROTOCOL\r | |
207 | if (proto == IRMP_NEC16_PROTOCOL) return 1;\r | |
208 | #endif\r | |
209 | #if IRMP_SUPPORT_NEC42_PROTOCOL\r | |
210 | if (proto == IRMP_NEC42_PROTOCOL) return 1;\r | |
211 | #endif\r | |
212 | #if IRMP_SUPPORT_MATSUSHITA_PROTOCOL\r | |
213 | if (proto == IRMP_MATSUSHITA_PROTOCOL) return 1;\r | |
214 | #endif\r | |
215 | #if IRMP_SUPPORT_DENON_PROTOCOL\r | |
216 | if (proto == IRMP_DENON_PROTOCOL) return 1;\r | |
217 | #endif\r | |
218 | #if IRMP_SUPPORT_RC5_PROTOCOL\r | |
219 | if (proto == IRMP_RC5_PROTOCOL) return 1;\r | |
220 | #endif\r | |
221 | #if IRMP_SUPPORT_RC6_PROTOCOL\r | |
222 | if (proto == IRMP_RC6_PROTOCOL) return 1;\r | |
223 | #endif\r | |
224 | #if IRMP_SUPPORT_IR60_PROTOCOL\r | |
225 | if (proto == IRMP_IR60_PROTOCOL) return 1;\r | |
226 | #endif\r | |
227 | #if IRMP_SUPPORT_GRUNDIG_PROTOCOL\r | |
228 | if (proto == IRMP_GRUNDIG_PROTOCOL) return 1;\r | |
229 | #endif\r | |
230 | #if IRMP_SUPPORT_SIEMENS_PROTOCOL\r | |
231 | if (proto == IRMP_SIEMENS_PROTOCOL) return 1;\r | |
232 | #endif\r | |
233 | #if IRMP_SUPPORT_NOKIA_PROTOCOL\r | |
234 | if (proto == IRMP_NOKIA_PROTOCOL) return 1;\r | |
235 | #endif\r | |
236 | #if IRMP_SUPPORT_BOSE_PROTOCOL\r | |
237 | if (proto == IRMP_BOSE_PROTOCOL) return 1;\r | |
238 | #endif\r | |
239 | #if IRMP_SUPPORT_KATHREIN_PROTOCOL\r | |
240 | if (proto == IRMP_KATHREIN_PROTOCOL) return 1;\r | |
241 | #endif\r | |
242 | #if IRMP_SUPPORT_NUBERT_PROTOCOL\r | |
243 | if (proto == IRMP_NUBERT_PROTOCOL) return 1;\r | |
244 | #endif\r | |
245 | #if IRMP_SUPPORT_FAN_PROTOCOL\r | |
246 | if (proto == IRMP_FAN_PROTOCOL) return 1;\r | |
247 | #endif\r | |
248 | #if IRMP_SUPPORT_SPEAKER_PROTOCOL\r | |
249 | if (proto == IRMP_SPEAKER_PROTOCOL) return 1;\r | |
250 | #endif\r | |
251 | #if IRMP_SUPPORT_BANG_OLUFSEN_PROTOCOL\r | |
252 | if (proto == IRMP_BANG_OLUFSEN_PROTOCOL) return 1;\r | |
253 | #endif\r | |
254 | #if IRMP_SUPPORT_RECS80_PROTOCOL\r | |
255 | if (proto == IRMP_RECS80_PROTOCOL) return 1;\r | |
256 | #endif\r | |
257 | #if IRMP_SUPPORT_RECS80EXT_PROTOCOL\r | |
258 | if (proto == IRMP_RECS80EXT_PROTOCOL) return 1;\r | |
259 | #endif\r | |
260 | #if IRMP_SUPPORT_THOMSON_PROTOCOL\r | |
261 | if (proto == IRMP_THOMSON_PROTOCOL) return 1;\r | |
262 | #endif\r | |
263 | #if IRMP_SUPPORT_NIKON_PROTOCOL\r | |
264 | if (proto == IRMP_NIKON_PROTOCOL) return 1;\r | |
265 | #endif\r | |
266 | #if IRMP_SUPPORT_NETBOX_PROTOCOL\r | |
267 | if (proto == IRMP_NETBOX_PROTOCOL) return 1;\r | |
268 | #endif\r | |
269 | #if IRMP_SUPPORT_ORTEK_PROTOCOL\r | |
270 | if (proto == IRMP_ORTEK_PROTOCOL) return 1;\r | |
271 | #endif\r | |
272 | #if IRMP_SUPPORT_TELEFUNKEN_PROTOCOL\r | |
273 | if (proto == IRMP_TELEFUNKEN_PROTOCOL) return 1;\r | |
274 | #endif\r | |
275 | #if IRMP_SUPPORT_FDC_PROTOCOL\r | |
276 | if (proto == IRMP_FDC_PROTOCOL) return 1;\r | |
277 | #endif\r | |
278 | #if IRMP_SUPPORT_RCCAR_PROTOCOL\r | |
279 | if (proto == IRMP_RCCAR_PROTOCOL) return 1;\r | |
280 | #endif\r | |
281 | #if IRMP_SUPPORT_ROOMBA_PROTOCOL\r | |
282 | if (proto == IRMP_ROOMBA_PROTOCOL) return 1;\r | |
283 | #endif\r | |
284 | #if IRMP_SUPPORT_RUWIDO_PROTOCOL\r | |
285 | if (proto == IRMP_RUWIDO_PROTOCOL) return 1;\r | |
286 | #endif\r | |
287 | #if IRMP_SUPPORT_A1TVBOX_PROTOCOL\r | |
288 | if (proto == IRMP_A1TVBOX_PROTOCOL) return 1;\r | |
289 | #endif\r | |
290 | #if IRMP_SUPPORT_LEGO_PROTOCOL\r | |
291 | if (proto == IRMP_LEGO_PROTOCOL) return 1;\r | |
292 | #endif\r | |
293 | #if IRMP_SUPPORT_RCMM_PROTOCOL\r | |
294 | if (proto == IRMP_RCMM_PROTOCOL) return 1;\r | |
295 | #endif\r | |
296 | #if IRMP_SUPPORT_LGAIR_PROTOCOL\r | |
297 | if (proto == IRMP_LGAIR_PROTOCOL) return 1;\r | |
298 | #endif\r | |
299 | #if IRMP_SUPPORT_SAMSUNG48_PROTOCOL\r | |
300 | if (proto == IRMP_SAMSUNG48_PROTOCOL) return 1;\r | |
301 | #endif\r | |
302 | #if IRMP_SUPPORT_MERLIN_PROTOCOL\r | |
303 | if (proto == IRMP_MERLIN_PROTOCOL) return 1;\r | |
304 | #endif\r | |
305 | #if IRMP_SUPPORT_PENTAX_PROTOCOL\r | |
306 | if (proto == IRMP_PENTAX_PROTOCOL) return 1;\r | |
307 | #endif\r | |
308 | #if IRMP_SUPPORT_S100_PROTOCOL\r | |
309 | if (proto == IRMP_S100_PROTOCOL) return 1;\r | |
310 | #endif\r | |
311 | #if IRMP_SUPPORT_ACP24_PROTOCOL\r | |
312 | if (proto == IRMP_ACP24_PROTOCOL) return 1;\r | |
313 | #endif\r | |
314 | #if IRMP_SUPPORT_TECHNICS_PROTOCOL\r | |
315 | if (proto == IRMP_TECHNICS_PROTOCOL) return 1;\r | |
316 | #endif\r | |
317 | #if IRMP_SUPPORT_PANASONIC_PROTOCOL\r | |
318 | if (proto == IRMP_PANASONIC_PROTOCOL) return 1;\r | |
319 | #endif\r | |
320 | #if IRMP_SUPPORT_MITSU_HEAVY_PROTOCOL\r | |
321 | if (proto == IRMP_MITSU_HEAVY_PROTOCOL) return 1;\r | |
322 | #endif\r | |
323 | #if IRMP_SUPPORT_VINCENT_PROTOCOL\r | |
324 | if (proto == IRMP_VINCENT_PROTOCOL) return 1;\r | |
325 | #endif\r | |
326 | #if IRMP_SUPPORT_SAMSUNGAH_PROTOCOL\r | |
327 | if (proto == IRMP_SAMSUNGAH_PROTOCOL) return 1;\r | |
328 | #endif\r | |
329 | #if IRMP_SUPPORT_RADIO1_PROTOCOL\r | |
330 | if (proto == IRMP_RADIO1_PROTOCOL) return 1;\r | |
331 | #endif\r | |
332 | \r | |
333 | return 0;\r | |
334 | }\r | |
335 | \r | |
b8dc4070 L |
336 | /**\r |
337 | * Print the names of all supported protocols, or the supported protocol\r | |
338 | * numbers, if names are not enabled.\r | |
339 | */\r | |
b1a276a1 L |
340 | void print_supported_protocols(void)\r |
341 | {\r | |
342 | printf("Supported IR protocols:");\r | |
343 | for (int i = 0; i <= IRMP_N_PROTOCOLS; i++) {\r | |
344 | if (irmp_protocol_is_supported(i)) {\r | |
345 | #if IRMP_PROTOCOL_NAMES == 1\r | |
346 | printf(" %s", irmp_protocol_names[i]);\r | |
347 | #else\r | |
348 | printf(" %d", i);\r | |
349 | #endif\r | |
350 | }\r | |
351 | }\r | |
352 | printf("\n");\r | |
353 | }\r | |
354 | \r | |
355 | /*--------------------------------------------------------------------------*/\r | |
356 | \r | |
b8dc4070 L |
357 | /** Let the board led do something\r |
358 | *\r | |
359 | * The led should blink with 1 Hz\r | |
360 | */\r | |
b1a276a1 L |
361 | void led_blink(void)\r |
362 | {\r | |
363 | static uint32_t ts;\r | |
364 | \r | |
365 | if (get_timer(ts) >= 500) {\r | |
366 | ts = get_timer(0);\r | |
367 | gpio_toggle(LED_PORT, LED_PIN);\r | |
368 | }\r | |
369 | }\r | |
370 | \r | |
371 | int main (void)\r | |
372 | {\r | |
373 | IRMP_DATA irmp_data;\r | |
374 | \r | |
375 | setup_clock_and_gpios();\r | |
376 | setvbuf(stdout, NULL, _IONBF, 0);\r | |
377 | serial_setup(CON_BAUDRATE);\r | |
378 | \r | |
379 | printf("\nIRMP on STM32F103 with libopencm3 demo\n"\r | |
380 | " System frequency: %luHz\n"\r | |
381 | "IRMP timer input frequency (CK_INT): %luHz\n"\r | |
382 | " IRMP interrupt frequency: %uHz\n",\r | |
e380aa53 | 383 | rcc_ahb_frequency, timer_internal_clock_get(IRMP_TIMER), F_INTERRUPTS);\r |
b1a276a1 L |
384 | \r |
385 | systick_setup();\r | |
386 | irmp_timer_init(); // initialize timer for irmp\r | |
387 | irmp_init(); // initialize irmp\r | |
388 | \r | |
389 | print_supported_protocols();\r | |
390 | for (;;)\r | |
391 | {\r | |
392 | led_blink();\r | |
393 | if (irmp_get_data (&irmp_data))\r | |
394 | {\r | |
395 | printf("protocol: 0x%.2x", irmp_data.protocol);\r | |
396 | #if IRMP_PROTOCOL_NAMES == 1\r | |
397 | printf(" %-11s", irmp_protocol_names[irmp_data.protocol]);\r | |
398 | #endif\r | |
399 | printf(" adress: 0x%.4x command: 0x%.4x flags: 0x%.2x\n",\r | |
400 | irmp_data.address, irmp_data.command, irmp_data.flags);\r | |
401 | }\r | |
402 | }\r | |
403 | }\r |