|
1 | 1 | /* |
2 | 2 | * Copyright (C) 2015 HAW Hamburg |
3 | 3 | * 2016 INRIA |
4 | | -
|
| 4 | + * 2017 TU Braunschweig, IBR |
| 5 | + * |
5 | 6 | * |
6 | 7 | * This file is subject to the terms and conditions of the GNU Lesser |
7 | 8 | * General Public License v2.1. See the file LICENSE in the top level |
|
19 | 20 | * @author René Herthel <rene-herthel@outlook.de> |
20 | 21 | * @author Francisco Acosta <francisco.acosta@inria.fr> |
21 | 22 | * @author Laurent Navet <laurent.navet@gmail.com> |
| 23 | + * @author Robert Hartung <hartung@ibr.cs.tu-bs.de> |
22 | 24 | * |
23 | 25 | * @} |
24 | 26 | */ |
|
31 | 33 | #include "cpu.h" |
32 | 34 | #include "periph/gpio.h" |
33 | 35 | #include "periph_conf.h" |
| 36 | +#include "board.h" |
34 | 37 |
|
35 | 38 | #define GPIO_BASE_PORT_A (0x20) |
36 | 39 | #define GPIO_OFFSET_PORT_H (0xCB) |
|
57 | 60 | #define GPIO_EXT_INT_NUMOF (2U) |
58 | 61 | #endif |
59 | 62 |
|
| 63 | +#ifdef AVR_USE_PCINT |
| 64 | +#if defined(PCINT3_vect) |
| 65 | +#define GPIO_PC_INT_NUMOF (32U) |
| 66 | +#elif defined(PCINT2_vect) |
| 67 | +#define GPIO_PC_INT_NUMOF (24U) |
| 68 | +#elif defined(PCINT1_vect) |
| 69 | +#define GPIO_PC_INT_NUMOF (16U) |
| 70 | +#elif defined(PCINT0_vect) |
| 71 | +#define GPIO_PC_INT_NUMOF (8U) |
| 72 | +#endif |
| 73 | +#endif |
| 74 | + |
| 75 | +/* holds the callback and argument for regular interrupts */ |
60 | 76 | static gpio_isr_ctx_t config[GPIO_EXT_INT_NUMOF]; |
| 77 | +#ifdef AVR_USE_PCINT |
| 78 | +/* holds the callback and argument for pin change interrupts */ |
| 79 | +static gpio_isr_ctx_t pcint[GPIO_PC_INT_NUMOF]; |
| 80 | +/* stores the configured flank for the respective pcint */ |
| 81 | +static gpio_flank_t pcint_flank[GPIO_PC_INT_NUMOF]; |
| 82 | +/* stores the last state of each port */ |
| 83 | +static uint8_t pcint_state[GPIO_PC_INT_NUMOF / 8]; |
| 84 | +#endif |
61 | 85 |
|
62 | 86 | /** |
63 | 87 | * @brief Extract the pin number of the given pin |
@@ -134,16 +158,65 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, |
134 | 158 | gpio_cb_t cb, void *arg) |
135 | 159 | { |
136 | 160 | uint8_t pin_num = _pin_num(pin); |
| 161 | + uint8_t port_num = _port_num(pin); |
137 | 162 |
|
138 | 163 | if ((_port_num(pin) == PORT_D && pin_num > 3) |
139 | 164 | #if defined (PORTE) |
140 | | - || (_port_num(pin) == PORT_E && pin_num < 4) |
141 | | - || (_port_num(pin) != PORT_D && _port_num(pin) != PORT_E) |
142 | | -#elif defined(CPU_ATMEGA328P) |
143 | | - || (pin_num < 2) || (_port_num(pin) != PORT_D) |
| 165 | + || (_port_num(pin) == PORT_E && pin_num < 4) |
| 166 | + || (_port_num(pin) != PORT_D && _port_num(pin) != PORT_E) |
| 167 | +#elif defined(CPU_ATMEGA328P) /* INT0: PD2, INT1: PD3 */ |
| 168 | + || (pin_num < 2) || (_port_num(pin) != PORT_D) |
| 169 | +#elif defined(CPU_ATMEGA1284P) /* INT0: PD2, INT1: PD3, INT2: PB2 */ |
| 170 | + || ((pin_num < 2) && (_port_num(pin) == PORT_D)) |
| 171 | + || ((pin_num < 2) && (_port_num(pin) == PORT_B)) |
| 172 | + || ((pin_num > 2) && (_port_num(pin) == PORT_B)) |
| 173 | + || (_port_num(pin) == PORT_C) |
| 174 | + || (_port_num(pin) == PORT_A) |
| 175 | +#endif |
| 176 | + || ((mode != GPIO_IN) && (mode != GPIO_IN_PU))) { |
| 177 | + |
| 178 | + /* If pin change interrupts are enabled, enable mask and interrupt */ |
| 179 | + #ifdef GPIO_PC_INT_NUMOF |
| 180 | + gpio_init(pin, mode); |
| 181 | + cli(); |
| 182 | + switch (_port_num(pin)) { |
| 183 | + case 0: |
| 184 | + PCMSK0 |= (1 << pin_num); |
| 185 | + PCICR |= (1 << PCIE0); |
| 186 | + break; |
| 187 | + case 1: |
| 188 | + PCMSK1 |= (1 << pin_num); |
| 189 | + PCICR |= (1 << PCIE1); |
| 190 | + break; |
| 191 | +#ifdef PCIE2 |
| 192 | + case 2: |
| 193 | + PCMSK2 |= (1 << pin_num); |
| 194 | + PCICR |= (1 << PCIE2); |
| 195 | + break; |
144 | 196 | #endif |
145 | | - || ((mode != GPIO_IN) && (mode != GPIO_IN_PU))) { |
| 197 | +#ifdef PCIE3 |
| 198 | + case 3: |
| 199 | + PCMSK3 |= (1 << pin_num); |
| 200 | + PCICR |= (1 << PCIE3); |
| 201 | + break; |
| 202 | +#endif |
| 203 | + default: |
| 204 | + return -1; |
| 205 | + break; |
| 206 | + } |
| 207 | + /* set configuration */ |
| 208 | + int pcint_num = _port_num(pin) * 8 + pin_num; |
| 209 | + pcint[pcint_num].cb = cb; |
| 210 | + pcint[pcint_num].arg = arg; |
| 211 | + pcint_flank[pcint_num] = flank; |
| 212 | + /* store current value of the port */ |
| 213 | + pcint_state[_port_num(pin)] = (_SFR_MEM8(_pin_addr( GPIO_PIN( _port_num(pin), pin_num ) ))); |
| 214 | + /* enable global interrupt flag */ |
| 215 | + sei(); |
| 216 | + return 0; |
| 217 | + #else /* if no pin change interrupts are used */ |
146 | 218 | return -1; |
| 219 | + #endif /* GPIO_PC_INT_NUMOF */ |
147 | 220 | } |
148 | 221 |
|
149 | 222 | gpio_init(pin, mode); |
@@ -237,61 +310,122 @@ void gpio_write(gpio_t pin, int value) |
237 | 310 | } |
238 | 311 | } |
239 | 312 |
|
| 313 | +#ifdef GPIO_PC_INT_NUMOF |
| 314 | +/* inline function that is used by the PCINT ISR */ |
| 315 | +static inline void pcint_handler(uint8_t port_num, volatile uint8_t *mask_reg) |
| 316 | +{ |
| 317 | + uint8_t pin_num = 0; |
| 318 | + /* calculate changed bits */ |
| 319 | + uint8_t state = _SFR_MEM8(_pin_addr(GPIO_PIN(port_num, 1))); |
| 320 | + /* get pins that changed */ |
| 321 | + uint8_t change = pcint_state[port_num] ^ state; |
| 322 | + |
| 323 | + /* apply mask to change */ |
| 324 | + change &= *mask_reg; |
| 325 | + /* loop through all changed pins with enabled pcint */ |
| 326 | + while (change > 0) { |
| 327 | + /* check if this pin is enabled & has changed */ |
| 328 | + if (change & 0x1) { |
| 329 | + uint8_t pin_mask = (1 << pin_num); |
| 330 | + gpio_flank_t flank = pcint_flank[ port_num * 8 + pin_num ]; |
| 331 | + /* trigger only on correct flank */ |
| 332 | + if (flank == GPIO_BOTH || ((state & pin_mask) && flank == GPIO_RISING) || (!(state & pin_mask) && flank == GPIO_FALLING)) { |
| 333 | + /* finally execute callback routine */ |
| 334 | + __enter_isr(); |
| 335 | + pcint[port_num * 8 + pin_num].cb( pcint[port_num * 8 + pin_num].arg ); |
| 336 | + __exit_isr(); |
| 337 | + } |
| 338 | + } |
| 339 | + change = change >> 1; |
| 340 | + pin_num++; |
| 341 | + } |
| 342 | + |
| 343 | + /* store current state */ |
| 344 | + pcint_state[port_num] = state; |
| 345 | +} |
| 346 | + |
| 347 | +#ifndef AVR_CONTEXT_SWAP_INTERRUPT_VECT_NUM |
| 348 | +#error gpio.c requires the definition of AVR_CONTEXT_SWAP_INTERRUPT_VECT_NUM |
| 349 | +#endif |
| 350 | + |
| 351 | +/* |
| 352 | + * PCINT0 is always defined, if GPIO_PC_INT_NUMOF is defined |
| 353 | + */ |
| 354 | +#if PCINT0_vect_num != AVR_CONTEXT_SWAP_INTERRUPT_VECT_NUM |
| 355 | +ISR(PCINT0_vect, ISR_BLOCK) { |
| 356 | + pcint_handler(0, &PCMSK0); |
| 357 | +} |
| 358 | +#endif /* AVR_CONTEXT_SWAP_INTERRUPT_VECT */ |
| 359 | +#if defined(PCINT1_vect) |
| 360 | +#if PCINT1_vect_num != AVR_CONTEXT_SWAP_INTERRUPT_VECT_NUM |
| 361 | +ISR(PCINT1_vect, ISR_BLOCK) { |
| 362 | + pcint_handler(1, &PCMSK1); |
| 363 | +} |
| 364 | +#endif /* AVR_CONTEXT_SWAP_INTERRUPT_VECT */ |
| 365 | +#endif /* PCINT1_vect */ |
| 366 | +#if defined(PCINT2_vect) |
| 367 | +#if PCINT2_vect_num != AVR_CONTEXT_SWAP_INTERRUPT_VECT_NUM |
| 368 | +ISR(PCINT2_vect, ISR_BLOCK) { |
| 369 | + pcint_handler(2, &PCMSK2); |
| 370 | +} |
| 371 | +#endif /* AVR_CONTEXT_SWAP_INTERRUPT_VECT */ |
| 372 | +#endif /* PCINT2_vect */ |
| 373 | +#if defined(PCINT3_vect) |
| 374 | +#if PCINT3_vect_num != AVR_CONTEXT_SWAP_INTERRUPT_VECT_NUM |
| 375 | +ISR(PCINT3_vect, ISR_BLOCK) { |
| 376 | + pcint_handler(3, &PCMSK3); |
| 377 | +} |
| 378 | +#endif /* AVR_CONTEXT_SWAP_INTERRUPT_VECT */ |
| 379 | +#endif /* PCINT3_vect */ |
| 380 | +#endif /* GPIO_PC_INT_NUMOF */ |
| 381 | + |
240 | 382 | static inline void irq_handler(uint8_t pin_num) |
241 | 383 | { |
242 | 384 | __enter_isr(); |
243 | 385 | config[pin_num].cb(config[pin_num].arg); |
244 | 386 | __exit_isr(); |
245 | 387 | } |
246 | 388 |
|
247 | | -ISR(INT0_vect, ISR_BLOCK) |
248 | | -{ |
| 389 | +ISR(INT0_vect, ISR_BLOCK){ |
249 | 390 | irq_handler(0); /**< predefined interrupt pin */ |
250 | 391 | } |
251 | 392 |
|
252 | | -ISR(INT1_vect, ISR_BLOCK) |
253 | | -{ |
| 393 | +ISR(INT1_vect, ISR_BLOCK){ |
254 | 394 | irq_handler(1); /**< predefined interrupt pin */ |
255 | 395 | } |
256 | 396 |
|
257 | 397 | #if defined(INT2_vect) |
258 | | -ISR(INT2_vect, ISR_BLOCK) |
259 | | -{ |
| 398 | +ISR(INT2_vect, ISR_BLOCK){ |
260 | 399 | irq_handler(2); /**< predefined interrupt pin */ |
261 | 400 | } |
262 | 401 | #endif |
263 | 402 |
|
264 | 403 | #if defined(INT3_vect) |
265 | | -ISR(INT3_vect, ISR_BLOCK) |
266 | | -{ |
| 404 | +ISR(INT3_vect, ISR_BLOCK){ |
267 | 405 | irq_handler(3); /**< predefined interrupt pin */ |
268 | 406 | } |
269 | 407 | #endif |
270 | 408 |
|
271 | 409 | #if defined(INT4_vect) |
272 | | -ISR(INT4_vect, ISR_BLOCK) |
273 | | -{ |
| 410 | +ISR(INT4_vect, ISR_BLOCK){ |
274 | 411 | irq_handler(4); /**< predefined interrupt pin */ |
275 | 412 | } |
276 | 413 | #endif |
277 | 414 |
|
278 | 415 | #if defined(INT5_vect) |
279 | | -ISR(INT5_vect, ISR_BLOCK) |
280 | | -{ |
| 416 | +ISR(INT5_vect, ISR_BLOCK){ |
281 | 417 | irq_handler(5); /**< predefined interrupt pin */ |
282 | 418 | } |
283 | 419 | #endif |
284 | 420 |
|
285 | 421 | #if defined(INT6_vect) |
286 | | -ISR(INT6_vect, ISR_BLOCK) |
287 | | -{ |
| 422 | +ISR(INT6_vect, ISR_BLOCK){ |
288 | 423 | irq_handler(6); /**< predefined interrupt pin */ |
289 | 424 | } |
290 | 425 | #endif |
291 | 426 |
|
292 | 427 | #if defined(INT7_vect) |
293 | | -ISR(INT7_vect, ISR_BLOCK) |
294 | | -{ |
| 428 | +ISR(INT7_vect, ISR_BLOCK){ |
295 | 429 | irq_handler(7); /**< predefined interrupt pin */ |
296 | 430 | } |
297 | 431 | #endif |
0 commit comments