1 /*------------------------------------------------------------------------------
2 * irmp-main.c - demo program to test the IRMP decoder on STM32F1 whith libopencm3
4 * Copyright (c) 2017 Leo C. <erbl259-lmu@yahoo.de>
6 * This demo program is essentially a combination of some libopencm3 examples
7 * from https://github.com/libopencm3/libopencm3-examples
8 * and irmp-main-stm32.c from the IRMP distribution, which is
9 * Copyright (c) 2009-2016 Frank Meyer - frank(at)fli4l.de
11 * The program demonstrates the integration of IRMP in a libopencm3 environment,
12 * and how to use the libopencm3 api functions, or alternatively direct
13 * register access, using the macros defined by libopencm3.
15 * This demo runs on the Generic STM32F103C8T6 Development Board, aka bluepill.
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
21 *------------------------------------------------------------------------------
28 #include <libopencm3/stm32/rcc.h>
29 #include <libopencm3/stm32/gpio.h>
32 /* The folloing macros can also be defined in the Makefile */
33 /* If 0 or undefined, use direct register access where appropriate,
34 * else use the libopencm3 api functions everywhere. */
35 #ifndef USE_OPENCM3_API
36 #define USE_OPENCM3_API 0
39 /* Toggle a pin on irmp timer isr entry and exit */
40 #ifndef DEBUG_IRMP_TIMER_INT
41 #define DEBUG_IRMP_TIMER_INT 0
45 * Do all initialisations, that are not done by a specific module here.
47 static void setup_clock_and_gpios(void)
50 /* Default clock is 8MHz HSI */
51 //rcc_clock_setup_in_hse_8mhz_out_24mhz();
52 //rcc_clock_setup_in_hse_8mhz_out_72mhz();
55 /* Only the on board led is configured here */
57 rcc_periph_clock_enable(RCC_LED_PORT
);
59 /* Set GPIO13 (in GPIO port C) to 'output push-pull'. */
61 // GPIOC_CRH = (GPIO_CNF_OUTPUT_PUSHPULL << (((12 - 8) * 4) + 2));
62 // GPIOC_CRH |= (GPIO_MODE_OUTPUT_2_MHZ << ((12 - 8) * 4));
63 /* Using API functions: */
64 gpio_set(LED_PORT
, LED_PIN
); /* set output register high (led off) */
65 gpio_set_mode(LED_PORT
, GPIO_MODE_OUTPUT_2_MHZ
,
66 GPIO_CNF_OUTPUT_PUSHPULL
, LED_PIN
);
69 /*--------------------------------------------------------------------------*/
71 /*--------------------------------------------------------------------------*/
73 #define IRMP_TIMER_NUMBER 3
74 #define IRMP_TIMER CONCAT(TIM, IRMP_TIMER_NUMBER)
76 #define IRMP_TIMER_CR1 TIM_CR1(IRMP_TIMER)
77 #define IRMP_TIMER_DIER TIM_DIER(IRMP_TIMER)
78 #define IRMP_TIMER_SR TIM_SR(IRMP_TIMER)
79 #define IRMP_TIMER_ARR TIM_ARR(IRMP_TIMER)
80 #define IRMP_TIMER_RCC CONCAT(RCC_TIM, IRMP_TIMER_NUMBER)
81 #define NVIC_IRMP_TIMER_IRQ CONCAT(CONCAT(NVIC_TIM, IRMP_TIMER_NUMBER), _IRQ)
82 #define IRMP_TIMER_ISR CONCAT(CONCAT(tim, IRMP_TIMER_NUMBER), _isr)
85 /** Retrieve the actual input clock of a timer
87 @param[in] timer_peripheral Unsigned int32. Timer register address base
88 @returns Unsigned int32. frequency value.
90 uint32_t timer_internal_clock_get(uint32_t timer_peripheral
)
92 uint32_t timer_frequency
;
94 /* Get preripheral bus frequency and prescaler mask */
95 if ((timer_peripheral
>= TIM2
&& timer_peripheral
<= TIM5
)
96 || (timer_peripheral
>= TIM12
&& timer_peripheral
<= TIM14
))
98 timer_frequency
= rcc_apb1_frequency
;
100 timer_frequency
= rcc_apb2_frequency
;
102 /* Timer clock is doubled, if the APB prescaler is greater than 1 */
103 if (timer_frequency
!= rcc_ahb_frequency
)
104 timer_frequency
*= 2;
106 return timer_frequency
;
110 * Intialize the irmp interrupt timer
112 void irmp_timer_init (void)
114 #if DEBUG_IRMP_TIMER_INT
115 /* Output pin for debugging */
116 rcc_periph_clock_enable(RCC_GPIOA
);
117 gpio_set_mode(GPIOA
, GPIO_MODE_OUTPUT_2_MHZ
,
118 GPIO_CNF_OUTPUT_PUSHPULL
, GPIO2
);
120 /* Enable timer clock. */
121 rcc_periph_clock_enable(IRMP_TIMER_RCC
);
122 nvic_set_priority(NVIC_IRMP_TIMER_IRQ
, 4*16);
123 nvic_enable_irq(NVIC_IRMP_TIMER_IRQ
);
125 #if USE_OPENCM3_API /* Using API functions: */
127 /* Timer global mode:
131 * (These are actually default values after reset, so this call
132 * is strictly unnecessary, but demos the api for alternative settings)
134 timer_set_mode(IRMP_TIMER
, TIM_CR1_CKD_CK_INT
,
135 TIM_CR1_CMS_EDGE
, TIM_CR1_DIR_UP
);
136 timer_set_period(IRMP_TIMER
, timer_internal_clock_get(IRMP_TIMER
) / F_INTERRUPTS
- 1);
137 /* Enable Channel 1 compare interrupt to recalculate compare values */
138 timer_enable_irq(IRMP_TIMER
, TIM_DIER_UIE
);
139 /* Counter enable. */
140 timer_enable_counter(IRMP_TIMER
);
144 IRMP_TIMER_CR1
= TIM_CR1_CKD_CK_INT
| TIM_CR1_CMS_EDGE
| TIM_CR1_DIR_UP
;
145 IRMP_TIMER_ARR
= timer_internal_clock_get(IRMP_TIMER
) / F_INTERRUPTS
- 1;
147 /* Enable Timer interrupt and timer */
148 IRMP_TIMER_DIER
= TIM_DIER_UIE
;
149 IRMP_TIMER_CR1
|= TIM_CR1_CEN
;
154 void IRMP_TIMER_ISR(void)
156 #if DEBUG_IRMP_TIMER_INT
157 # if USE_OPENCM3_API /* Using API functions: */
159 gpio_clear(GPIOA
, GPIO2
);
160 /* Clear update interrupt flag. */
161 timer_clear_flag(IRMP_TIMER
, TIM_SR_UIF
);
162 # else /* Manually */
163 GPIO_BRR(GPIOA
) = GPIO2
;
166 /* Clear update interrupt flag. */
167 IRMP_TIMER_SR
= ~TIM_SR_UIF
;
169 (void) irmp_ISR(); // call irmp ISR
171 // call other timer interrupt routines...
173 #if DEBUG_IRMP_TIMER_INT
174 # if USE_OPENCM3_API /* Using API functions: */
175 gpio_set(GPIOA
, GPIO2
);
176 # else /* Manually */
177 GPIO_BSRR(GPIOA
) = GPIO2
;
182 /*--------------------------------------------------------------------------*/
184 /** Test if a IR protocol is supported
186 * Return true, if proto is valid protocol number and the protocol
187 * is enabled in irmpconfig.h
189 int irmp_protocol_is_supported(int proto
)
191 #if IRMP_SUPPORT_SIRCS_PROTOCOL
192 if (proto
== IRMP_SIRCS_PROTOCOL
) return 1;
194 #if IRMP_SUPPORT_NEC_PROTOCOL
195 if (proto
== IRMP_NEC_PROTOCOL
) return 1;
197 #if IRMP_SUPPORT_SAMSUNG_PROTOCOL
198 if (proto
== IRMP_SAMSUNG_PROTOCOL
) return 1;
200 #if IRMP_SUPPORT_KASEIKYO_PROTOCOL
201 if (proto
== IRMP_KASEIKYO_PROTOCOL
) return 1;
203 #if IRMP_SUPPORT_JVC_PROTOCOL
204 if (proto
== IRMP_JVC_PROTOCOL
) return 1;
206 #if IRMP_SUPPORT_NEC16_PROTOCOL
207 if (proto
== IRMP_NEC16_PROTOCOL
) return 1;
209 #if IRMP_SUPPORT_NEC42_PROTOCOL
210 if (proto
== IRMP_NEC42_PROTOCOL
) return 1;
212 #if IRMP_SUPPORT_MATSUSHITA_PROTOCOL
213 if (proto
== IRMP_MATSUSHITA_PROTOCOL
) return 1;
215 #if IRMP_SUPPORT_DENON_PROTOCOL
216 if (proto
== IRMP_DENON_PROTOCOL
) return 1;
218 #if IRMP_SUPPORT_RC5_PROTOCOL
219 if (proto
== IRMP_RC5_PROTOCOL
) return 1;
221 #if IRMP_SUPPORT_RC6_PROTOCOL
222 if (proto
== IRMP_RC6_PROTOCOL
) return 1;
224 #if IRMP_SUPPORT_IR60_PROTOCOL
225 if (proto
== IRMP_IR60_PROTOCOL
) return 1;
227 #if IRMP_SUPPORT_GRUNDIG_PROTOCOL
228 if (proto
== IRMP_GRUNDIG_PROTOCOL
) return 1;
230 #if IRMP_SUPPORT_SIEMENS_PROTOCOL
231 if (proto
== IRMP_SIEMENS_PROTOCOL
) return 1;
233 #if IRMP_SUPPORT_NOKIA_PROTOCOL
234 if (proto
== IRMP_NOKIA_PROTOCOL
) return 1;
236 #if IRMP_SUPPORT_BOSE_PROTOCOL
237 if (proto
== IRMP_BOSE_PROTOCOL
) return 1;
239 #if IRMP_SUPPORT_KATHREIN_PROTOCOL
240 if (proto
== IRMP_KATHREIN_PROTOCOL
) return 1;
242 #if IRMP_SUPPORT_NUBERT_PROTOCOL
243 if (proto
== IRMP_NUBERT_PROTOCOL
) return 1;
245 #if IRMP_SUPPORT_FAN_PROTOCOL
246 if (proto
== IRMP_FAN_PROTOCOL
) return 1;
248 #if IRMP_SUPPORT_SPEAKER_PROTOCOL
249 if (proto
== IRMP_SPEAKER_PROTOCOL
) return 1;
251 #if IRMP_SUPPORT_BANG_OLUFSEN_PROTOCOL
252 if (proto
== IRMP_BANG_OLUFSEN_PROTOCOL
) return 1;
254 #if IRMP_SUPPORT_RECS80_PROTOCOL
255 if (proto
== IRMP_RECS80_PROTOCOL
) return 1;
257 #if IRMP_SUPPORT_RECS80EXT_PROTOCOL
258 if (proto
== IRMP_RECS80EXT_PROTOCOL
) return 1;
260 #if IRMP_SUPPORT_THOMSON_PROTOCOL
261 if (proto
== IRMP_THOMSON_PROTOCOL
) return 1;
263 #if IRMP_SUPPORT_NIKON_PROTOCOL
264 if (proto
== IRMP_NIKON_PROTOCOL
) return 1;
266 #if IRMP_SUPPORT_NETBOX_PROTOCOL
267 if (proto
== IRMP_NETBOX_PROTOCOL
) return 1;
269 #if IRMP_SUPPORT_ORTEK_PROTOCOL
270 if (proto
== IRMP_ORTEK_PROTOCOL
) return 1;
272 #if IRMP_SUPPORT_TELEFUNKEN_PROTOCOL
273 if (proto
== IRMP_TELEFUNKEN_PROTOCOL
) return 1;
275 #if IRMP_SUPPORT_FDC_PROTOCOL
276 if (proto
== IRMP_FDC_PROTOCOL
) return 1;
278 #if IRMP_SUPPORT_RCCAR_PROTOCOL
279 if (proto
== IRMP_RCCAR_PROTOCOL
) return 1;
281 #if IRMP_SUPPORT_ROOMBA_PROTOCOL
282 if (proto
== IRMP_ROOMBA_PROTOCOL
) return 1;
284 #if IRMP_SUPPORT_RUWIDO_PROTOCOL
285 if (proto
== IRMP_RUWIDO_PROTOCOL
) return 1;
287 #if IRMP_SUPPORT_A1TVBOX_PROTOCOL
288 if (proto
== IRMP_A1TVBOX_PROTOCOL
) return 1;
290 #if IRMP_SUPPORT_LEGO_PROTOCOL
291 if (proto
== IRMP_LEGO_PROTOCOL
) return 1;
293 #if IRMP_SUPPORT_RCMM_PROTOCOL
294 if (proto
== IRMP_RCMM_PROTOCOL
) return 1;
296 #if IRMP_SUPPORT_LGAIR_PROTOCOL
297 if (proto
== IRMP_LGAIR_PROTOCOL
) return 1;
299 #if IRMP_SUPPORT_SAMSUNG48_PROTOCOL
300 if (proto
== IRMP_SAMSUNG48_PROTOCOL
) return 1;
302 #if IRMP_SUPPORT_MERLIN_PROTOCOL
303 if (proto
== IRMP_MERLIN_PROTOCOL
) return 1;
305 #if IRMP_SUPPORT_PENTAX_PROTOCOL
306 if (proto
== IRMP_PENTAX_PROTOCOL
) return 1;
308 #if IRMP_SUPPORT_S100_PROTOCOL
309 if (proto
== IRMP_S100_PROTOCOL
) return 1;
311 #if IRMP_SUPPORT_ACP24_PROTOCOL
312 if (proto
== IRMP_ACP24_PROTOCOL
) return 1;
314 #if IRMP_SUPPORT_TECHNICS_PROTOCOL
315 if (proto
== IRMP_TECHNICS_PROTOCOL
) return 1;
317 #if IRMP_SUPPORT_PANASONIC_PROTOCOL
318 if (proto
== IRMP_PANASONIC_PROTOCOL
) return 1;
320 #if IRMP_SUPPORT_MITSU_HEAVY_PROTOCOL
321 if (proto
== IRMP_MITSU_HEAVY_PROTOCOL
) return 1;
323 #if IRMP_SUPPORT_VINCENT_PROTOCOL
324 if (proto
== IRMP_VINCENT_PROTOCOL
) return 1;
326 #if IRMP_SUPPORT_SAMSUNGAH_PROTOCOL
327 if (proto
== IRMP_SAMSUNGAH_PROTOCOL
) return 1;
329 #if IRMP_SUPPORT_RADIO1_PROTOCOL
330 if (proto
== IRMP_RADIO1_PROTOCOL
) return 1;
337 * Print the names of all supported protocols, or the supported protocol
338 * numbers, if names are not enabled.
340 void print_supported_protocols(void)
342 printf("Supported IR protocols:");
343 for (int i
= 0; i
<= IRMP_N_PROTOCOLS
; i
++) {
344 if (irmp_protocol_is_supported(i
)) {
345 #if IRMP_PROTOCOL_NAMES == 1
346 printf(" %s", irmp_protocol_names
[i
]);
355 /*--------------------------------------------------------------------------*/
357 /** Let the board led do something
359 * The led should blink with 1 Hz
365 if (get_timer(ts
) >= 500) {
367 gpio_toggle(LED_PORT
, LED_PIN
);
375 setup_clock_and_gpios();
376 setvbuf(stdout
, NULL
, _IONBF
, 0);
377 serial_setup(CON_BAUDRATE
);
379 printf("\nIRMP on STM32F103 with libopencm3 demo\n"
380 " System frequency: %luHz\n"
381 "IRMP timer input frequency (CK_INT): %luHz\n"
382 " IRMP interrupt frequency: %uHz\n",
383 rcc_ahb_frequency
, timer_internal_clock_get(IRMP_TIMER
), F_INTERRUPTS
);
386 irmp_timer_init(); // initialize timer for irmp
387 irmp_init(); // initialize irmp
389 print_supported_protocols();
393 if (irmp_get_data (&irmp_data
))
395 printf("protocol: 0x%.2x", irmp_data
.protocol
);
396 #if IRMP_PROTOCOL_NAMES == 1
397 printf(" %-11s", irmp_protocol_names
[irmp_data
.protocol
]);
399 printf(" adress: 0x%.4x command: 0x%.4x flags: 0x%.2x\n",
400 irmp_data
.address
, irmp_data
.command
, irmp_data
.flags
);