Skip to content

Commit 274ff24

Browse files
committed
cpu/atmega: adds state and applies changes from review
1 parent 88ce769 commit 274ff24

1 file changed

Lines changed: 44 additions & 27 deletions

File tree

  • cpu/atmega_common/periph

cpu/atmega_common/periph/gpio.c

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,14 @@
7070
#define GPIO_PC_INT_NUMOF (8U)
7171
#endif
7272

73+
/* holds the callback and argument for regular interrupts */
7374
static gpio_isr_ctx_t config[GPIO_EXT_INT_NUMOF];
75+
/* holds the callback and argument for pin change interrupts */
7476
static gpio_isr_ctx_t pcint[GPIO_PC_INT_NUMOF];
77+
/* stores the configured flank for the respective pcint */
7578
static 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
330347
ISR(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
336353
ISR(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
343360
ISR(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
350367
ISR(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

Comments
 (0)