1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/cpu/atmega_common/periph/gpio_ll_irq.c
Marian Buschsieweke 04ab5a74f3
cpu/atmega_common: implement periph/gpio_ll{,_irq}
Co-authored-by: Gunar Schorcht <gunar@schorcht.net>
Co-authored-by: Alexandre Abadie <alexandre.abadie@inria.fr>
2022-05-02 14:44:55 +02:00

180 lines
3.4 KiB
C

/*
* Copyright (C) 2015 HAW Hamburg
* 2016 INRIA
* 2022 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License v2.1. See the file LICENSE in the top level directory for more
* details.
*/
/**
* @ingroup cpu_atmega_common
* @ingroup drivers_periph_gpio_ll_irq
* @{
*
* @file
* @brief IRQ implementation of the GPIO Low-Level API for ATmega
*
* @author René Herthel <rene-herthel@outlook.de>
* @author Francisco Acosta <francisco.acosta@inria.fr>
* @author Laurent Navet <laurent.navet@gmail.com>
* @author Robert Hartung <hartung@ibr.cs.tu-bs.de>
* @author Torben Petersen <petersen@ibr.cs.tu-bs.de>
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*
* @}
*/
#include <avr/interrupt.h>
#include <errno.h>
#include "cpu.h"
#include "irq.h"
#include "periph/gpio_ll_irq.h"
#include "periph_conf.h"
#include "periph_cpu.h"
#define ENABLE_DEBUG 0
#include "debug.h"
struct isr_ctx {
gpio_ll_cb_t cb;
void *arg;
};
static struct isr_ctx isr_ctx[GPIO_EXT_INT_NUMOF];
static void clear_pending_irqs(uint8_t exti)
{
EIFR |= 1 << exti;
}
void gpio_ll_irq_mask(gpio_port_t port, uint8_t pin)
{
uint8_t exti = atmega_pin2exti(GPIO_PORT_NUM(port), pin);
EIMSK &= ~(1 << exti);
}
void gpio_ll_irq_unmask(gpio_port_t port, uint8_t pin)
{
uint8_t exti = atmega_pin2exti(GPIO_PORT_NUM(port), pin);
EIMSK |= 1 << exti;
}
void gpio_ll_irq_unmask_and_clear(gpio_port_t port, uint8_t pin)
{
uint8_t exti = atmega_pin2exti(GPIO_PORT_NUM(port), pin);
clear_pending_irqs(exti);
EIMSK |= 1 << exti;
}
static void set_trigger(uint8_t exti, gpio_irq_trig_t trig)
{
exti <<= 1;
volatile uint8_t *eicr = &EICRA;
#ifdef EICRB
if (exti >= 8) {
eicr = & EICRB;
exti -= 8;
}
#endif
/* being a bit more verbose here to avoid two read-modify-write cycles,
* as the compiler won't optimize access to volatile memory */
uint8_t tmp = *eicr;
tmp &= ~(0x3 << exti);
tmp |= trig << exti;
*eicr = tmp;
}
int gpio_ll_irq(gpio_port_t port, uint8_t pin, gpio_irq_trig_t trig,
gpio_ll_cb_t cb, void *arg)
{
int port_num = GPIO_PORT_NUM(port);
assert((trig != GPIO_TRIGGER_LEVEL_HIGH) && cb);
if (!atmega_has_pin_exti(port_num, pin)) {
return -ENOTSUP;
}
uint8_t exti = atmega_pin2exti(port_num, pin);
unsigned irq_state = irq_disable();
/* set callback */
isr_ctx[exti].cb = cb;
isr_ctx[exti].arg = arg;
/* setup IRQ */
set_trigger(exti, trig);
clear_pending_irqs(exti);
EIMSK |= 1 << exti;
irq_restore(irq_state);
return 0;
}
static void isr_exti(uint8_t exti)
{
avr8_enter_isr();
isr_ctx[exti].cb(isr_ctx[exti].arg);
avr8_exit_isr();
}
#ifdef INT0_vect
ISR(INT0_vect, ISR_BLOCK)
{
isr_exti(0);
}
#endif
#ifdef INT1_vect
ISR(INT1_vect, ISR_BLOCK)
{
isr_exti(1);
}
#endif
#ifdef INT2_vect
ISR(INT2_vect, ISR_BLOCK)
{
isr_exti(2);
}
#endif
#ifdef INT3_vect
ISR(INT3_vect, ISR_BLOCK)
{
isr_exti(3);
}
#endif
#ifdef INT4_vect
ISR(INT4_vect, ISR_BLOCK)
{
isr_exti(4);
}
#endif
#ifdef INT5_vect
ISR(INT5_vect, ISR_BLOCK)
{
isr_exti(5);
}
#endif
#ifdef INT6_vect
ISR(INT6_vect, ISR_BLOCK)
{
isr_exti(6);
}
#endif
#ifdef INT7_vect
ISR(INT7_vect, ISR_BLOCK)
{
isr_exti(7);
}
#endif