]> git.donarmstrong.com Git - qmk_firmware.git/blob - tmk_core/tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_STM/TARGET_STM32F3XX/gpio_irq_api.c
Merge commit '1fe4406f374291ab2e86e95a97341fd9c475fcb8'
[qmk_firmware.git] / tmk_core / tool / mbed / mbed-sdk / libraries / mbed / targets / hal / TARGET_STM / TARGET_STM32F3XX / gpio_irq_api.c
1 /* mbed Microcontroller Library
2  *******************************************************************************
3  * Copyright (c) 2014, STMicroelectronics
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  *    this list of conditions and the following disclaimer in the documentation
13  *    and/or other materials provided with the distribution.
14  * 3. Neither the name of STMicroelectronics nor the names of its contributors
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *******************************************************************************
29  */
30 #include <stddef.h>
31 #include "cmsis.h"
32
33 #include "gpio_irq_api.h"
34 #include "pinmap.h"
35 #include "mbed_error.h"
36
37 #define EDGE_NONE (0)
38 #define EDGE_RISE (1)
39 #define EDGE_FALL (2)
40 #define EDGE_BOTH (3)
41
42 #define CHANNEL_NUM (7)
43
44 static uint32_t channel_ids[CHANNEL_NUM]  = {0, 0, 0, 0, 0, 0, 0};
45 static uint32_t channel_gpio[CHANNEL_NUM] = {0, 0, 0, 0, 0, 0, 0};
46 static uint32_t channel_pin[CHANNEL_NUM]  = {0, 0, 0, 0, 0, 0, 0};
47
48 static gpio_irq_handler irq_handler;
49
50 static void handle_interrupt_in(uint32_t irq_index) {
51     // Retrieve the gpio and pin that generate the irq
52     GPIO_TypeDef *gpio = (GPIO_TypeDef *)(channel_gpio[irq_index]);
53     uint32_t pin = (uint32_t)(1 << channel_pin[irq_index]);
54
55     // Clear interrupt flag
56     if (EXTI_GetITStatus(channel_pin[irq_index]) != RESET) {
57         EXTI_ClearITPendingBit(channel_pin[irq_index]);
58     }
59
60     if (channel_ids[irq_index] == 0) return;
61
62     // Check which edge has generated the irq
63     if ((gpio->IDR & pin) == 0) {
64         irq_handler(channel_ids[irq_index], IRQ_FALL);
65     } else  {
66         irq_handler(channel_ids[irq_index], IRQ_RISE);
67     }
68 }
69
70 static void gpio_irq0(void) {
71     handle_interrupt_in(0);   // EXTI line 0
72 }
73
74 static void gpio_irq1(void) {
75     handle_interrupt_in(1);   // EXTI line 1
76 }
77
78 static void gpio_irq2(void) {
79     handle_interrupt_in(2);   // EXTI line 2
80 }
81
82 static void gpio_irq3(void) {
83     handle_interrupt_in(3);   // EXTI line 3
84 }
85
86 static void gpio_irq4(void) {
87     handle_interrupt_in(4);   // EXTI line 4
88 }
89
90 static void gpio_irq5(void) {
91     handle_interrupt_in(5);   // EXTI lines 5 to 9
92 }
93
94 static void gpio_irq6(void) {
95     handle_interrupt_in(6);   // EXTI lines 10 to 15
96 }
97
98 extern uint32_t Set_GPIO_Clock(uint32_t port_idx);
99
100 int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32_t id) {
101     IRQn_Type irq_n = (IRQn_Type)0;
102     uint32_t vector = 0;
103     uint32_t irq_index;
104
105     if (pin == NC) return -1;
106
107     uint32_t port_index = STM_PORT(pin);
108     uint32_t pin_index  = STM_PIN(pin);
109
110     // Select irq number and interrupt routine
111     switch (pin_index) {
112         case 0:
113             irq_n = EXTI0_IRQn;
114             vector = (uint32_t)&gpio_irq0;
115             irq_index = 0;
116             break;
117         case 1:
118             irq_n = EXTI1_IRQn;
119             vector = (uint32_t)&gpio_irq1;
120             irq_index = 1;
121             break;
122         case 2:
123             irq_n = EXTI2_TS_IRQn;
124             vector = (uint32_t)&gpio_irq2;
125             irq_index = 2;
126             break;
127         case 3:
128             irq_n = EXTI3_IRQn;
129             vector = (uint32_t)&gpio_irq3;
130             irq_index = 3;
131             break;
132         case 4:
133             irq_n = EXTI4_IRQn;
134             vector = (uint32_t)&gpio_irq4;
135             irq_index = 4;
136             break;
137         case 5:
138         case 6:
139         case 7:
140         case 8:
141         case 9:
142             irq_n = EXTI9_5_IRQn;
143             vector = (uint32_t)&gpio_irq5;
144             irq_index = 5;
145             break;
146         case 10:
147         case 11:
148         case 12:
149         case 13:
150         case 14:
151         case 15:
152             irq_n = EXTI15_10_IRQn;
153             vector = (uint32_t)&gpio_irq6;
154             irq_index = 6;
155             break;
156         default:
157             error("This pin is not supported with InterruptIn.");
158             return -1;
159     }
160
161     // Enable GPIO clock
162     uint32_t gpio_add = Set_GPIO_Clock(port_index);
163
164     // Enable SYSCFG clock
165     RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
166
167     // Connect EXTI line to pin
168     SYSCFG_EXTILineConfig(port_index, pin_index);
169
170     // Configure EXTI line
171     EXTI_InitTypeDef EXTI_InitStructure;
172     EXTI_InitStructure.EXTI_Line = pin_index;
173     EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
174     EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
175     EXTI_InitStructure.EXTI_LineCmd = ENABLE;
176     EXTI_Init(&EXTI_InitStructure);
177
178     // Enable and set EXTI interrupt to the lowest priority
179     NVIC_InitTypeDef NVIC_InitStructure;
180     NVIC_InitStructure.NVIC_IRQChannel = irq_n;
181     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
182     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
183     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
184     NVIC_Init(&NVIC_InitStructure);
185
186     NVIC_SetVector(irq_n, vector);
187     NVIC_EnableIRQ(irq_n);
188
189     // Save informations for future use
190     obj->irq_n = irq_n;
191     obj->irq_index = irq_index;
192     obj->event = EDGE_NONE;
193     channel_ids[irq_index] = id;
194     channel_gpio[irq_index] = gpio_add;
195     channel_pin[irq_index] = pin_index;
196
197     irq_handler = handler;
198
199     return 0;
200 }
201
202 void gpio_irq_free(gpio_irq_t *obj) {
203     channel_ids[obj->irq_index] = 0;
204     channel_gpio[obj->irq_index] = 0;
205     channel_pin[obj->irq_index] = 0;
206     // Disable EXTI line
207     EXTI_InitTypeDef EXTI_InitStructure;
208     EXTI_StructInit(&EXTI_InitStructure);
209     EXTI_Init(&EXTI_InitStructure);
210     obj->event = EDGE_NONE;
211 }
212
213 void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
214     EXTI_InitTypeDef EXTI_InitStructure;
215
216     EXTI_InitStructure.EXTI_Line = channel_pin[obj->irq_index];
217     EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
218
219     if (event == IRQ_RISE) {
220         if ((obj->event == EDGE_FALL) || (obj->event == EDGE_BOTH)) {
221             EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
222             obj->event = EDGE_BOTH;
223         } else { // NONE or RISE
224             EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
225             obj->event = EDGE_RISE;
226         }
227     }
228
229     if (event == IRQ_FALL) {
230         if ((obj->event == EDGE_RISE) || (obj->event == EDGE_BOTH)) {
231             EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
232             obj->event = EDGE_BOTH;
233         } else { // NONE or FALL
234             EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
235             obj->event = EDGE_FALL;
236         }
237     }
238
239     if (enable) {
240         EXTI_InitStructure.EXTI_LineCmd = ENABLE;
241     } else {
242         EXTI_InitStructure.EXTI_LineCmd = DISABLE;
243     }
244
245     EXTI_Init(&EXTI_InitStructure);
246 }
247
248 void gpio_irq_enable(gpio_irq_t *obj) {
249     NVIC_EnableIRQ(obj->irq_n);
250 }
251
252 void gpio_irq_disable(gpio_irq_t *obj) {
253     NVIC_DisableIRQ(obj->irq_n);
254     obj->event = EDGE_NONE;
255 }