|
17 | 17 | #include "cmsis.h"
|
18 | 18 |
|
19 | 19 | #include "gpio_irq_api.h"
|
| 20 | +#include "fsl_gpio_driver.h" |
| 21 | +#include "fsl_gpio_hal.h" |
| 22 | +#include "fsl_port_hal.h" |
20 | 23 | #include "error.h"
|
21 | 24 |
|
22 |
| -static void handle_interrupt_in(PORT_Type *port, int ch_base) { |
| 25 | +#define CHANNEL_NUM 160 |
23 | 26 |
|
| 27 | +static uint32_t channel_ids[CHANNEL_NUM] = {0}; |
| 28 | +static gpio_irq_handler irq_handler; |
| 29 | + |
| 30 | +#define IRQ_DISABLED (0) |
| 31 | +#define IRQ_RAISING_EDGE (9) |
| 32 | +#define IRQ_FALLING_EDGE (10) |
| 33 | +#define IRQ_EITHER_EDGE (11) |
| 34 | + |
| 35 | +static void handle_interrupt_in(PortName port, int ch_base) { |
| 36 | + uint32_t i; |
| 37 | + |
| 38 | + for (i = 0; i < 32; i++) { |
| 39 | + if (port_hal_read_pin_interrupt_flag(port, i)) { |
| 40 | + uint32_t id = channel_ids[ch_base + i]; |
| 41 | + if (id == 0) |
| 42 | + continue; |
| 43 | + |
| 44 | + gpio_irq_event event = IRQ_NONE; |
| 45 | + switch (BR_PORT_PCRn_IRQC(port, i)) { |
| 46 | + case IRQ_RAISING_EDGE: |
| 47 | + event = IRQ_RISE; |
| 48 | + break; |
| 49 | + |
| 50 | + case IRQ_FALLING_EDGE: |
| 51 | + event = IRQ_FALL; |
| 52 | + break; |
| 53 | + |
| 54 | + case IRQ_EITHER_EDGE: |
| 55 | + event = (gpio_hal_read_pin_input(port, i)) ? (IRQ_RISE) : (IRQ_FALL); |
| 56 | + break; |
| 57 | + } |
| 58 | + if (event != IRQ_NONE) |
| 59 | + irq_handler(id, event); |
| 60 | + } |
| 61 | + } |
| 62 | + port_hal_clear_port_interrupt_flag(port); |
24 | 63 | }
|
25 | 64 |
|
| 65 | +void gpio_irqA(void) {handle_interrupt_in(PortA, 0);} |
| 66 | +void gpio_irqB(void) {handle_interrupt_in(PortB, 32);} |
| 67 | +void gpio_irqC(void) {handle_interrupt_in(PortC, 64);} |
| 68 | +void gpio_irqD(void) {handle_interrupt_in(PortD, 96);} |
| 69 | +void gpio_irqE(void) {handle_interrupt_in(PortE, 128);} |
| 70 | + |
26 | 71 | int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32_t id) {
|
27 |
| - return 1; |
| 72 | + if (pin == NC) |
| 73 | + return -1; |
| 74 | + |
| 75 | + irq_handler = handler; |
| 76 | + |
| 77 | + obj->port = pin >> GPIO_PORT_SHIFT; |
| 78 | + obj->pin = pin & 0x7F; |
| 79 | + |
| 80 | + uint32_t ch_base, vector; |
| 81 | + IRQn_Type irq_n; |
| 82 | + switch (obj->port) { |
| 83 | + case PortA: |
| 84 | + ch_base = 0; |
| 85 | + irq_n = PORTA_IRQn; |
| 86 | + vector = (uint32_t)gpio_irqA; |
| 87 | + break; |
| 88 | + case PortB: |
| 89 | + ch_base = 32; |
| 90 | + irq_n = PORTB_IRQn; |
| 91 | + vector = (uint32_t)gpio_irqB; |
| 92 | + break; |
| 93 | + case PortC: |
| 94 | + ch_base = 64; |
| 95 | + irq_n = PORTC_IRQn; |
| 96 | + vector = (uint32_t)gpio_irqC; |
| 97 | + break; |
| 98 | + case PortD: |
| 99 | + ch_base = 96; |
| 100 | + irq_n = PORTD_IRQn; |
| 101 | + vector = (uint32_t)gpio_irqD; |
| 102 | + break; |
| 103 | + case PortE: |
| 104 | + ch_base = 128; |
| 105 | + irq_n = PORTE_IRQn; |
| 106 | + vector = (uint32_t)gpio_irqE; |
| 107 | + break; |
| 108 | + |
| 109 | + default: |
| 110 | + error("gpio_irq only supported on port A-E.\n"); |
| 111 | + break; |
| 112 | + } |
| 113 | + NVIC_SetVector(irq_n, vector); |
| 114 | + NVIC_EnableIRQ(irq_n); |
| 115 | + |
| 116 | + obj->ch = ch_base + obj->pin; |
| 117 | + channel_ids[obj->ch] = id; |
| 118 | + |
| 119 | + return 0; |
28 | 120 | }
|
29 | 121 |
|
30 | 122 | void gpio_irq_free(gpio_irq_t *obj) {
|
31 |
| - |
| 123 | + channel_ids[obj->ch] = 0; |
32 | 124 | }
|
33 | 125 |
|
34 | 126 | void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
|
| 127 | + port_interrupt_config_t irq_settings = kPortIntDisabled; |
| 128 | + |
| 129 | + switch (BR_PORT_PCRn_IRQC(obj->port, obj->pin)) { |
| 130 | + case IRQ_DISABLED: |
| 131 | + if (enable) |
| 132 | + irq_settings = (event == IRQ_RISE) ? (kPortIntRisingEdge) : (kPortIntFallingEdge); |
| 133 | + break; |
| 134 | + |
| 135 | + case IRQ_RAISING_EDGE: |
| 136 | + if (enable) { |
| 137 | + irq_settings = (event == IRQ_RISE) ? (kPortIntRisingEdge) : (kPortIntEitherEdge); |
| 138 | + } else { |
| 139 | + if (event == IRQ_FALL) |
| 140 | + irq_settings = kPortIntRisingEdge; |
| 141 | + } |
| 142 | + break; |
| 143 | + |
| 144 | + case IRQ_FALLING_EDGE: |
| 145 | + if (enable) { |
| 146 | + irq_settings = (event == IRQ_FALL) ? (kPortIntFallingEdge) : (kPortIntEitherEdge); |
| 147 | + } else { |
| 148 | + if (event == IRQ_RISE) |
| 149 | + irq_settings = kPortIntFallingEdge; |
| 150 | + } |
| 151 | + break; |
| 152 | + |
| 153 | + case IRQ_EITHER_EDGE: |
| 154 | + if (enable) { |
| 155 | + irq_settings = kPortIntEitherEdge; |
| 156 | + } else { |
| 157 | + irq_settings = (event == IRQ_RISE) ? (kPortIntFallingEdge) : (kPortIntRisingEdge); |
| 158 | + } |
| 159 | + break; |
| 160 | + } |
| 161 | + |
| 162 | + // Interrupt configuration and clear interrupt |
| 163 | + port_hal_configure_pin_interrupt(obj->port, obj->pin, irq_settings); |
| 164 | + port_hal_clear_pin_interrupt_flag(obj->port, obj->pin); |
| 165 | +} |
| 166 | + |
| 167 | +void gpio_irq_enable(gpio_irq_t *obj) { |
| 168 | + switch (obj->port) { |
| 169 | + case PortA: |
| 170 | + NVIC_EnableIRQ(PORTA_IRQn); |
| 171 | + break; |
| 172 | + case PortB: |
| 173 | + NVIC_EnableIRQ(PORTB_IRQn); |
| 174 | + break; |
| 175 | + case PortC: |
| 176 | + NVIC_EnableIRQ(PORTC_IRQn); |
| 177 | + break; |
| 178 | + case PortD: |
| 179 | + NVIC_EnableIRQ(PORTD_IRQn); |
| 180 | + break; |
| 181 | + case PortE: |
| 182 | + NVIC_EnableIRQ(PORTE_IRQn); |
| 183 | + break; |
| 184 | + } |
| 185 | +} |
35 | 186 |
|
| 187 | +void gpio_irq_disable(gpio_irq_t *obj) { |
| 188 | + switch (obj->port) { |
| 189 | + case PortA: |
| 190 | + NVIC_DisableIRQ(PORTA_IRQn); |
| 191 | + break; |
| 192 | + case PortB: |
| 193 | + NVIC_DisableIRQ(PORTB_IRQn); |
| 194 | + break; |
| 195 | + case PortC: |
| 196 | + NVIC_DisableIRQ(PORTC_IRQn); |
| 197 | + break; |
| 198 | + case PortD: |
| 199 | + NVIC_DisableIRQ(PORTD_IRQn); |
| 200 | + break; |
| 201 | + case PortE: |
| 202 | + NVIC_DisableIRQ(PORTE_IRQn); |
| 203 | + break; |
| 204 | + } |
36 | 205 | }
|
0 commit comments