Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions cpu/atmega1281/include/periph_cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@ enum {
PORT_G = 6, /**< port G */
};

/**
* @brief Available external interrupt pins on the ATmega1281 family
*
* In order of their interrupt number.
*/
#define CPU_ATMEGA_EXT_INTS { GPIO_PIN(PORT_D, 0), \
GPIO_PIN(PORT_D, 1), \
GPIO_PIN(PORT_D, 2), \
GPIO_PIN(PORT_D, 3), \
GPIO_PIN(PORT_E, 4), \
GPIO_PIN(PORT_E, 5), \
GPIO_PIN(PORT_E, 6), \
GPIO_PIN(PORT_E, 7) }

/**
* @name Defines for the I2C interface
* @{
Expand Down
11 changes: 10 additions & 1 deletion cpu/atmega1284p/include/periph_cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ extern "C" {
#define GPIO_PIN(x, y) ((x << 4) | y)

/**
* @brief Available ports on the ATmega328p family
* @brief Available ports on the ATmega1284p family
*/
enum {
PORT_A = 0, /**< port A */
Expand All @@ -44,6 +44,15 @@ enum {
PORT_D = 3 /**< port D */
};

/**
* @brief Available external interrupt pins on the ATmega1284p family
*
* In order of their interrupt number
*/
#define CPU_ATMEGA_EXT_INTS { GPIO_PIN(PORT_D, 2), \
GPIO_PIN(PORT_D, 3), \
GPIO_PIN(PORT_B, 2) }

/**
* @name Defines for the I2C interface
* @{
Expand Down
14 changes: 14 additions & 0 deletions cpu/atmega2560/include/periph_cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,20 @@ enum {
PORT_L = 10 /**< port L */
};

/**
* @brief Available external interrupt pins on the ATmega2560 family
*
* In order of their interrupt number.
*/
#define CPU_ATMEGA_EXT_INTS { GPIO_PIN(PORT_D, 0), \
GPIO_PIN(PORT_D, 1), \
GPIO_PIN(PORT_D, 2), \
GPIO_PIN(PORT_D, 3), \
GPIO_PIN(PORT_E, 4), \
GPIO_PIN(PORT_E, 5), \
GPIO_PIN(PORT_E, 6), \
GPIO_PIN(PORT_E, 7) }

/**
* @name Defines for the I2C interface
* @{
Expand Down
14 changes: 14 additions & 0 deletions cpu/atmega256rfr2/include/periph_cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ enum {
PORT_G = 6, /**< port G */
};

/**
* @brief Available external interrupt pins on the ATmega256rfr family
*
* In order of their interrupt number.
*/
#define CPU_ATMEGA_EXT_INTS { GPIO_PIN(PORT_D, 0), \
GPIO_PIN(PORT_D, 1), \
GPIO_PIN(PORT_D, 2), \
GPIO_PIN(PORT_D, 3), \
GPIO_PIN(PORT_E, 4), \
GPIO_PIN(PORT_E, 5), \
GPIO_PIN(PORT_E, 6), \
GPIO_PIN(PORT_E, 7) }

/**
* @name Defines for the I2C interface
* @{
Expand Down
8 changes: 8 additions & 0 deletions cpu/atmega328p/include/periph_cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ enum {
PORT_D = 3 /**< port D */
};

/**
* @brief Available external interrupt pins on the ATmega328p family
*
* In order of their interrupt number.
*/
#define CPU_ATMEGA_EXT_INTS { GPIO_PIN(PORT_D, 2), \
GPIO_PIN(PORT_D, 3) }

/**
* @name Defines for the I2C interface
* @{
Expand Down
116 changes: 46 additions & 70 deletions cpu/atmega_common/periph/gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "cpu.h"
#include "periph/gpio.h"
#include "periph_conf.h"
#include "periph_cpu.h"

#define GPIO_BASE_PORT_A (0x20)
#define GPIO_OFFSET_PORT_H (0xCB)
Expand All @@ -40,18 +41,18 @@
* @brief Define GPIO interruptions for an specific atmega CPU, by default
* 2 (for small atmega CPUs)
*/
#if defined(INT2_vect)
#define GPIO_EXT_INT_NUMOF (3U)
#elif defined(INT3_vect)
#define GPIO_EXT_INT_NUMOF (4U)
#elif defined(INT4_vect)
#define GPIO_EXT_INT_NUMOF (4U)
#elif defined(INT5_vect)
#define GPIO_EXT_INT_NUMOF (4U)
#if defined(INT7_vect)
#define GPIO_EXT_INT_NUMOF (8U)
#elif defined(INT6_vect)
#define GPIO_EXT_INT_NUMOF (7U)
#elif defined(INT5_vect)
#define GPIO_EXT_INT_NUMOF (6U)
#elif defined(INT4_vect)
#define GPIO_EXT_INT_NUMOF (5U)
#elif defined(INT3_vect)
#define GPIO_EXT_INT_NUMOF (4U)
#elif defined(INT7_vect)
#define GPIO_EXT_INT_NUMOF (4U)
#elif defined(INT2_vect)
#define GPIO_EXT_INT_NUMOF (3U)
#else
#define GPIO_EXT_INT_NUMOF (2U)
#endif
Expand Down Expand Up @@ -109,6 +110,21 @@ static inline uint16_t _pin_addr(gpio_t pin)
return (_port_addr(pin) - 0x02);
}

static inline int8_t _int_num(gpio_t pin)
{
uint8_t num;
const gpio_t ext_ints[GPIO_EXT_INT_NUMOF] = CPU_ATMEGA_EXT_INTS;

/* find pin in ext_ints array to get the interrupt number */
for (num = 0; num < GPIO_EXT_INT_NUMOF; num++) {
if (pin == ext_ints[num]) {
return num;
}
}

return -1;
}

int gpio_init(gpio_t pin, gpio_mode_t mode)
{
switch (mode) {
Expand All @@ -132,20 +148,14 @@ int gpio_init(gpio_t pin, gpio_mode_t mode)
int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank,
gpio_cb_t cb, void *arg)
{
uint8_t pin_num = _pin_num(pin);

if ((_port_num(pin) == PORT_D && pin_num > 3)
#if defined (PORTE)
|| (_port_num(pin) == PORT_E && pin_num < 4)
|| (_port_num(pin) != PORT_D && _port_num(pin) != PORT_E)
#elif defined(CPU_ATMEGA328P)
|| (pin_num < 2) || (_port_num(pin) != PORT_D)
#elif defined(CPU_ATMEGA1284P)
|| (_port_num(pin) == PORT_B && pin_num != 2)
|| (_port_num(pin) == PORT_D && pin_num < 2)
|| (_port_num(pin) != PORT_D && _port_num(pin) != PORT_D)
#endif
|| ((mode != GPIO_IN) && (mode != GPIO_IN_PU))) {
int8_t int_num = _int_num(pin);

if ((mode != GPIO_IN) && (mode != GPIO_IN_PU)) {
return -1;
}

/* not a valid interrupt pin */
if (int_num < 0) {
return -1;
}

Expand All @@ -154,35 +164,27 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank,
/* clear global interrupt flag */
cli();

#if defined(CPU_ATMEGA328P)
/* INT pins start at PD2 instead of at PD0 */
pin_num -= 2;
#elif defined(CPU_ATMEGA1284P)
/* INT pins start at PD2 instead of at PD0 on PORT_D */
if (_port_num(pin) == PORT_D) {
pin_num -= 2;
}
#endif

EIMSK |= (1 << pin_num);
/* enable interrupt number int_num */
EIMSK |= (1 << int_num);

/* configure the flank */
if (flank > GPIO_RISING) {
return -1;
}

if (pin_num < 4) {
EICRA |= (flank << (pin_num * 2));
/* apply flank to interrupt number int_num */
if (int_num < 4) {
EICRA |= (flank << (int_num * 2));
}
#if defined(EICRB)
else {
EICRB |= (flank << (pin_num * 2) % 4);
EICRB |= (flank << ((int_num % 4) * 2));
Copy link
Contributor

@kYc0o kYc0o Apr 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you tell more about this change? At a first glance it looks like the same, but I know there's a difference. I also wonder how it worked in the past.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is an example if int_num == 6:

  • Old behavior: multiply by 2 (== 12), then modulo 4 (remainder of 12/4 = 0), ergo use ISC40 and ISC41 in EICRB (wrong).
  • New behavior: modulo 4 (remainder of 6/4 = 2), then multiply by 2 (2*2 = 4), ergo use ISC60 and ISC61 in EICRB (right).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, thanks for the explanation!

}
#endif

/* set callback */
config[pin_num].cb = cb;
config[pin_num].arg = arg;
config[int_num].cb = cb;
config[int_num].arg = arg;

/* set global interrupt flag */
sei();
Expand All @@ -192,38 +194,12 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank,

void gpio_irq_enable(gpio_t pin)
{
#if defined(CPU_ATMEGA328P)
/* INT pins start at PD2 instead of at PD0 */
EIMSK |= (1 << (_pin_num(pin) - 2));
#elif defined(CPU_ATMEGA1284P)
/* INT pins start at PD2 instead of at PD0 on PORT_D */
if (_port_num(pin) == PORT_D) {
EIMSK |= (1 << (_pin_num(pin) - 2));
}
else {
EIMSK |= (1 << _pin_num(pin));
}
#else
EIMSK |= (1 << _pin_num(pin));
#endif
EIMSK |= (1 << _int_num(pin));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One Question: If I try to enable the IRQ for a non valid PIN, _pin_num will return -1. Is shifting with a negative shift count valid? According to this: https://stackoverflow.com/questions/4945703/left-shifting-with-a-negative-shift-count the behaviour for this is not defined.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pin validity is checked in gpio_init_int and afterwards presumed valid.

}

void gpio_irq_disable(gpio_t pin)
{
#if defined(CPU_ATMEGA328P)
/* INT pins start at PD2 instead of at PD0 */
EIMSK &= ~(1 << (_pin_num(pin) - 2));
#elif defined (CPU_ATMEGA1284P)
/* INT pins start at PD2 instead of at PD0 on PORT_D */
if (_port_num(pin) == PORT_D) {
EIMSK &= ~(1 << (_pin_num(pin) - 2));
}
else {
EIMSK &= ~(1 << _pin_num(pin));
}
#else
EIMSK &= ~(1 << _pin_num(pin));
#endif
EIMSK &= ~(1 << _int_num(pin));
}

int gpio_read(gpio_t pin)
Expand Down Expand Up @@ -261,10 +237,10 @@ void gpio_write(gpio_t pin, int value)
}
}

static inline void irq_handler(uint8_t pin_num)
static inline void irq_handler(uint8_t int_num)
{
__enter_isr();
config[pin_num].cb(config[pin_num].arg);
config[int_num].cb(config[int_num].arg);
__exit_isr();
}

Expand Down