]>
Commit | Line | Data |
---|---|---|
1 | /*------------------------------------------------------------------------------\r | |
2 | * irsnd-main.c - demo program to test the IRSND encoder 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 derived from irsnd-main-avr.c, which is\r | |
7 | * Copyright (c) 2010-2016 Frank Meyer - frank(at)fli4l.de\r | |
8 | *\r | |
9 | * The program demonstrates the integration of IRSND in a libopencm3 environment,\r | |
10 | * and how to use the libopencm3 api functions, or alternatively direct\r | |
11 | * register access, using the macros defined by libopencm3.\r | |
12 | *\r | |
13 | * This demo runs on the Generic STM32F103C8T6 Development Board, aka bluepill.\r | |
14 | *\r | |
15 | * This program is free software; you can redistribute it and/or modify\r | |
16 | * it under the terms of the GNU General Public License as published by\r | |
17 | * the Free Software Foundation; either version 2 of the License, or\r | |
18 | * (at your option) any later version.\r | |
19 | *------------------------------------------------------------------------------\r | |
20 | */\r | |
21 | \r | |
22 | #include "irsnd.h"\r | |
23 | #include "timer.h"\r | |
24 | #include <libopencm3/stm32/rcc.h>\r | |
25 | #include <libopencm3/stm32/gpio.h>\r | |
26 | \r | |
27 | \r | |
28 | /* The folloing macros can also be defined in the Makefile */\r | |
29 | /* If 0 or undefined, use direct register access where appropriate,\r | |
30 | * else use the libopencm3 api functions everywhere. */\r | |
31 | #ifndef USE_OPENCM3_API\r | |
32 | #define USE_OPENCM3_API 0\r | |
33 | #endif\r | |
34 | \r | |
35 | /* Toggle a pin on irmp timer isr entry and exit */\r | |
36 | #ifndef DEBUG_IRMP_TIMER_INT\r | |
37 | #define DEBUG_IRMP_TIMER_INT 0\r | |
38 | #endif\r | |
39 | \r | |
40 | #define LED_PORT GPIOC\r | |
41 | #define LED_PIN GPIO13\r | |
42 | #define LED_PORT_RCC RCC_GPIOC\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(LED_PORT_RCC);\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 | static void led_on(void)\r | |
76 | {\r | |
77 | gpio_clear(LED_PORT, LED_PIN);\r | |
78 | }\r | |
79 | \r | |
80 | static void led_off(void)\r | |
81 | {\r | |
82 | gpio_set(LED_PORT, LED_PIN);\r | |
83 | }\r | |
84 | \r | |
85 | static void debug_led_on(void)\r | |
86 | {\r | |
87 | #if DEBUG_IRMP_TIMER_INT\r | |
88 | # if USE_OPENCM3_API /* Using API functions: */\r | |
89 | gpio_clear(DEBUG_LED_PORT, DEBUG_LED_PIN);\r | |
90 | #else\r | |
91 | GPIO_BRR(DEBUG_LED_PORT) = DEBUG_LED_PIN;\r | |
92 | # endif\r | |
93 | #endif\r | |
94 | }\r | |
95 | \r | |
96 | static void debug_led_off(void)\r | |
97 | {\r | |
98 | #if DEBUG_IRMP_TIMER_INT\r | |
99 | # if USE_OPENCM3_API /* Using API functions: */\r | |
100 | gpio_set(DEBUG_LED_PORT, DEBUG_LED_PIN);\r | |
101 | #else\r | |
102 | GPIO_BSRR(DEBUG_LED_PORT) = DEBUG_LED_PIN;\r | |
103 | # endif\r | |
104 | #endif\r | |
105 | }\r | |
106 | \r | |
107 | /*--------------------------------------------------------------------------*/\r | |
108 | /* IRMP */\r | |
109 | /*--------------------------------------------------------------------------*/\r | |
110 | \r | |
111 | #define IRSND_TICK_TIMER_NUMBER 3\r | |
112 | #define IRSND_TICK_TIMER TIM3\r | |
113 | \r | |
114 | #define IRSND_TICK_TIMER_CR1 TIM_CR1(IRSND_TICK_TIMER)\r | |
115 | #define IRSND_TICK_TIMER_DIER TIM_DIER(IRSND_TICK_TIMER)\r | |
116 | #define IRSND_TICK_TIMER_SR TIM_SR(IRSND_TICK_TIMER)\r | |
117 | #define IRSND_TICK_TIMER_ARR TIM_ARR(IRSND_TICK_TIMER)\r | |
118 | #define IRSND_TICK_TIMER_RCC CONCAT(RCC_TIM, IRSND_TICK_TIMER_NUMBER)\r | |
119 | #define NVIC_IRSND_TICK_TIMER_IRQ CONCAT(CONCAT(NVIC_TIM, IRSND_TICK_TIMER_NUMBER), _IRQ)\r | |
120 | #define IRSND_TICK_TIMER_ISR CONCAT(CONCAT(tim, IRSND_TICK_TIMER_NUMBER), _isr)\r | |
121 | \r | |
122 | \r | |
123 | /** Retrieve the actual input clock of a timer\r | |
124 | \r | |
125 | @param[in] timer_peripheral Unsigned int32. Timer register address base\r | |
126 | @returns Unsigned int32. frequency value.\r | |
127 | */\r | |
128 | uint32_t timer_internal_clock_get(uint32_t timer_peripheral)\r | |
129 | {\r | |
130 | uint32_t timer_frequency;\r | |
131 | \r | |
132 | /* Get preripheral bus frequency and prescaler mask */\r | |
133 | #ifdef STM32F0\r | |
134 | timer_frequency = rcc_apb1_frequency;\r | |
135 | #else\r | |
136 | if (timer_peripheral < PERIPH_BASE_APB2)\r | |
137 | {\r | |
138 | timer_frequency = rcc_apb1_frequency;\r | |
139 | } else {\r | |
140 | timer_frequency = rcc_apb2_frequency;\r | |
141 | }\r | |
142 | #endif /* STM32F0 */\r | |
143 | /* Timer clock is doubled, if the APB prescaler is greater than 1 */\r | |
144 | if (timer_frequency != rcc_ahb_frequency)\r | |
145 | timer_frequency *= 2;\r | |
146 | \r | |
147 | return timer_frequency;\r | |
148 | }\r | |
149 | \r | |
150 | /**\r | |
151 | * Intialize the irmp interrupt timer\r | |
152 | */\r | |
153 | void irsnd_tick_timer_init(void)\r | |
154 | {\r | |
155 | #if DEBUG_IRMP_TIMER_INT\r | |
156 | /* Output pin for debugging */\r | |
157 | rcc_periph_clock_enable(DEBUG_LED_PORT_RCC);\r | |
158 | gpio_set(DEBUG_LED_PORT, DEBUG_LED_PIN);\r | |
159 | gpio_set_mode(DEBUG_LED_PORT, GPIO_MODE_OUTPUT_2_MHZ,\r | |
160 | GPIO_CNF_OUTPUT_PUSHPULL, DEBUG_LED_PIN);\r | |
161 | #endif\r | |
162 | /* Enable timer clock. */\r | |
163 | rcc_periph_clock_enable(IRSND_TICK_TIMER_RCC);\r | |
164 | nvic_set_priority(NVIC_IRSND_TICK_TIMER_IRQ, 4*16);\r | |
165 | nvic_enable_irq(NVIC_IRSND_TICK_TIMER_IRQ);\r | |
166 | \r | |
167 | #if USE_OPENCM3_API /* Using API functions: */\r | |
168 | \r | |
169 | /* Timer global mode:\r | |
170 | * - No divider\r | |
171 | * - Alignment edge\r | |
172 | * - Direction up\r | |
173 | * (These are actually default values after reset, so this call\r | |
174 | * is strictly unnecessary, but demos the api for alternative settings)\r | |
175 | */\r | |
176 | timer_set_mode(IRSND_TICK_TIMER, TIM_CR1_CKD_CK_INT,\r | |
177 | TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);\r | |
178 | timer_set_period(IRSND_TICK_TIMER, timer_internal_clock_get(IRSND_TICK_TIMER) / F_INTERRUPTS - 1);\r | |
179 | /* Enable timer update interrupt */\r | |
180 | timer_enable_irq(IRSND_TICK_TIMER, TIM_DIER_UIE);\r | |
181 | /* Counter enable. */\r | |
182 | timer_enable_counter(IRSND_TICK_TIMER);\r | |
183 | \r | |
184 | #else /* Manually */\r | |
185 | \r | |
186 | IRSND_TICK_TIMER_CR1 = TIM_CR1_CKD_CK_INT | TIM_CR1_CMS_EDGE | TIM_CR1_DIR_UP;\r | |
187 | IRSND_TICK_TIMER_ARR = timer_internal_clock_get(IRSND_TICK_TIMER) / F_INTERRUPTS - 1;\r | |
188 | \r | |
189 | /* Enable timer update interrupt */\r | |
190 | IRSND_TICK_TIMER_DIER = TIM_DIER_UIE;\r | |
191 | /* Finally enable the timer */\r | |
192 | IRSND_TICK_TIMER_CR1 |= TIM_CR1_CEN;\r | |
193 | \r | |
194 | #endif\r | |
195 | }\r | |
196 | \r | |
197 | void IRSND_TICK_TIMER_ISR(void)\r | |
198 | {\r | |
199 | debug_led_on();\r | |
200 | \r | |
201 | /* Clear update interrupt flag. */\r | |
202 | #if USE_OPENCM3_API /* Using API functions: */\r | |
203 | timer_clear_flag(IRSND_TICK_TIMER, TIM_SR_UIF);\r | |
204 | #else\r | |
205 | IRSND_TICK_TIMER_SR = ~TIM_SR_UIF;\r | |
206 | #endif\r | |
207 | \r | |
208 | (void) irsnd_ISR(); // call irmp ISR\r | |
209 | // call other timer interrupt routines...\r | |
210 | \r | |
211 | debug_led_off();\r | |
212 | }\r | |
213 | \r | |
214 | /*---------------------------------------------------------------------------------------------------------------------------------------------------\r | |
215 | * MAIN: main routine\r | |
216 | *---------------------------------------------------------------------------------------------------------------------------------------------------\r | |
217 | */\r | |
218 | int\r | |
219 | main (void)\r | |
220 | {\r | |
221 | static uint32_t ts;\r | |
222 | IRMP_DATA irmp_data;\r | |
223 | \r | |
224 | setup_clock_and_gpios();\r | |
225 | systick_setup();\r | |
226 | irsnd_init(); // initialize irsnd\r | |
227 | irsnd_tick_timer_init(); // initialize timer\r | |
228 | \r | |
229 | for (;;)\r | |
230 | {\r | |
231 | irmp_data.protocol = IRMP_NEC_PROTOCOL; // use NEC protocol\r | |
232 | irmp_data.address = 0x4eb1; // Marantz RMC-12\r | |
233 | irmp_data.command = 0x001e; // SYSTEM 1 POWER\r | |
234 | irmp_data.flags = 0; // don't repeat frame\r | |
235 | ts = get_timer(0);\r | |
236 | \r | |
237 | led_on();\r | |
238 | irsnd_send_data (&irmp_data, TRUE); // send frame, wait for completion\r | |
239 | while (irsnd_is_busy()) // wait till frame is\r | |
240 | ; // completely sent\r | |
241 | led_off();\r | |
242 | \r | |
243 | while (get_timer(ts) < 1000)\r | |
244 | ;\r | |
245 | }\r | |
246 | }\r |