7070#define GPIO_PC_INT_NUMOF (8U)
7171#endif
7272
73+ /* holds the callback and argument for regular interrupts */
7374static gpio_isr_ctx_t config [GPIO_EXT_INT_NUMOF ];
75+ /* holds the callback and argument for pin change interrupts */
7476static gpio_isr_ctx_t pcint [GPIO_PC_INT_NUMOF ];
77+ /* stores the configured flank for the respective pcint */
7578static gpio_flank_t pcint_flank [GPIO_PC_INT_NUMOF ];
79+ /* stores the last state of each port */
80+ static uint8_t pcint_state [GPIO_PC_INT_NUMOF / 8 ];
7681
7782/**
7883 * @brief Extract the pin number of the given pin
@@ -194,9 +199,12 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank,
194199 break ;
195200 }
196201 /* set configuration */
197- pcint [port_num * 8 + pin_num ].cb = cb ;
198- pcint [port_num * 8 + pin_num ].arg = arg ;
199- pcint_flank [port_num * 8 + pin_num ] = flank ;
202+ int pcint_num = port_num * 8 + pin_num ;
203+ pcint [pcint_num ].cb = cb ;
204+ pcint [pcint_num ].arg = arg ;
205+ pcint_flank [pcint_num ] = flank ;
206+ /* store current value of the port */
207+ pcint_state [port_num ] = (_SFR_MEM8 (_pin_addr ( GPIO_PIN ( port_num , pin_num ) )));
200208 /* enable global interrupt flag */
201209 sei ();
202210 return 0 ;
@@ -293,28 +301,37 @@ void gpio_write(gpio_t pin, int value)
293301 }
294302}
295303
296- static inline void pcint_handler (uint8_t port_num , uint8_t pin_num )
304+ /* inline function that is used by the PCINT ISR */
305+ static inline void pcint_handler (uint8_t port_num , volatile uint8_t * mask_reg , volatile uint8_t * pin_reg )
297306{
298- int gpio_state = gpio_read ( GPIO_PIN (port_num , pin_num ) );
299- gpio_flank_t flank = pcint_flank [ port_num * 8 + pin_num ];
300-
301- if (flank == GPIO_BOTH || (gpio_state && flank == GPIO_RISING ) || (!gpio_state && flank == GPIO_FALLING )) {
302- __enter_isr ();
303- pcint [port_num * 8 + pin_num ].cb ( pcint [port_num * 8 + pin_num ].arg );
304- __exit_isr ();
307+ uint8_t pin_num = 0 ;
308+ /* calculate changed bits */
309+ uint8_t state = * pin_reg ;
310+ /* get pins that changed */
311+ uint8_t change = pcint_state [port_num ] ^ state ;
312+
313+ /* apply mask to change */
314+ change &= * mask_reg ;
315+ /* loop through all changed pins with enabled pcint */
316+ while (change > 1 ) {
317+ /* check if this pin is enabled & has changed */
318+ if (change & 0x1 ) {
319+ uint8_t pin_mask = (1 << pin_num );
320+ gpio_flank_t flank = pcint_flank [ port_num * 8 + pin_num ];
321+ /* trigger only on correct flank */
322+ if (flank == GPIO_BOTH || ((state & pin_mask ) && flank == GPIO_RISING ) || (!(state & pin_mask ) && flank == GPIO_FALLING )) {
323+ /* finally execute callback routine */
324+ __enter_isr ();
325+ pcint [port_num * 8 + pin_num ].cb ( pcint [port_num * 8 + pin_num ].arg );
326+ __exit_isr ();
327+ }
328+ }
329+ change = change >> 1 ;
330+ pin_num ++ ;
305331 }
306- }
307-
308- static inline uint8_t pcint_port_pin (volatile uint8_t * reg )
309- {
310- uint8_t pin = 0 ;
311- uint8_t val = * reg ;
312332
313- while (val > 1 ) {
314- val = val >> 1 ;
315- pin ++ ;
316- }
317- return pin ;
333+ /* store current state */
334+ pcint_state [port_num ] = state ;
318335}
319336
320337#ifdef GPIO_PC_INT_NUMOF
@@ -328,29 +345,29 @@ static inline uint8_t pcint_port_pin(volatile uint8_t *reg)
328345 */
329346#if PCINT0_vect_num != AVR_CONTEXT_SWAP_INTERRUPT_VECT_NUM
330347ISR (PCINT0_vect , ISR_BLOCK ) {
331- pcint_handler (0 , pcint_port_pin ( & PCMSK0 ) );
348+ pcint_handler (0 , & PCMSK0 , & PINA );
332349}
333350#endif /* AVR_CONTEXT_SWAP_INTERRUPT_VECT */
334351#if defined(PCINT1_vect )
335352#if PCINT1_vect_num != AVR_CONTEXT_SWAP_INTERRUPT_VECT_NUM
336353ISR (PCINT1_vect , ISR_BLOCK ) {
337- pcint_handler (1 , pcint_port_pin ( & PCMSK1 ) );
354+ pcint_handler (1 , & PCMSK1 , & PINB );
338355}
339356#endif /* AVR_CONTEXT_SWAP_INTERRUPT_VECT */
340357#endif /* PCINT1_vect */
341358#if defined(PCINT2_vect )
342359#if PCINT2_vect_num != AVR_CONTEXT_SWAP_INTERRUPT_VECT_NUM
343360ISR (PCINT2_vect , ISR_BLOCK ) {
344- pcint_handler (2 , pcint_port_pin ( & PCMSK2 ) );
361+ pcint_handler (2 , & PCMSK2 , & PINC );
345362}
346363#endif /* AVR_CONTEXT_SWAP_INTERRUPT_VECT */
347364#endif /* PCINT2_vect */
348365#if defined(PCINT3_vect )
349366#if PCINT3_vect_num != AVR_CONTEXT_SWAP_INTERRUPT_VECT_NUM
350367ISR (PCINT3_vect , ISR_BLOCK ) {
351- pcint_handler (3 , pcint_port_pin ( & PCMSK3 )); // pcint_port_pin(&PCMSK3)
368+ pcint_handler (3 , & PCMSK3 , & PIND );
352369}
353- #endif /* AVR_CONTEXT_SWAP_INTERRUPT_VECT */
370+ #endif /* AVR_CONTEXT_SWAP_INTERRUPT_VECT */
354371#endif /* PCINT3_vect */
355372#endif /* GPIO_PC_INT_NUMOF */
356373
0 commit comments