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