/************************************************************************/ /* */ /* File: avr/pcint.c */ /* Description: pin change interruption driver. */ /* Version: 1.0 */ /* Author: Otto Mattik */ /* */ /* (C)Copyright Otto Mattik 2014-2021. */ /* */ /* This file is a part of 'armen' (a tiny operating system). */ /* 'armen' is distributed under the CeCILL-V2.1 licence. For more */ /* details about this licence, please visit the website cecill.info */ /* */ /************************************************************************/ #ifndef AVR_GPIO_C #error "do not use this code directly, it must be included via gpio.c" #endif #include "avr/core.h" #include #if defined(__AVR_ATtiny84__) #define GPIO_MAX_PCINT 2 #define GPIO_MAX_INT 1 #elif defined(__AVR_ATtiny841__) #define GPIO_MAX_PCINT 2 #define GPIO_MAX_INT 1 #elif defined(__AVR_ATtiny85__) #define GPIO_MAX_PCINT 1 #define GPIO_MAX_INT 1 #elif defined(__AVR_ATtiny1634__) #define GPIO_MAX_PCINT 3 #define GPIO_MAX_INT 1 #elif defined(__AVR_ATmega328P__) #define GPIO_MAX_PCINT 3 #define GPIO_MAX_INT 2 #elif defined(__AVR_ATmega2560__) #define GPIO_MAX_PCINT 3 #define GPIO_MAX_INT 3 /* really 8, limited to 3 by events mask */ #endif static struct { uint8_t* pcmsk; uint8_t pcie; } pcints[GPIO_MAX_PCINT] = { #if defined(__AVR_ATtiny85__) { 0x0015, 1<= 2) ISR( INT1_vect ) { register uint8_t iflag; iflag = _disable_intr( ); if( (EICRA & 0x0C) == INT_LOW ) EIMSK &= ~2; _wakeup( EVENT_INT1, 0 ); _enable_intr( iflag ); } #endif #if (GPIO_MAX_INT == 3) ISR( INT2_vect ) { register uint8_t iflag; iflag = _disable_intr( ); if( (EICRA & 0x30) == INT_LOW ) EIMSK &= ~4; _wakeup( EVENT_INT2, 0 ); _enable_intr( iflag ); } #endif ISR( PCINT0_vect ) { register uint8_t iflag; iflag = _disable_intr( ); _wakeup( EVENT_PCINT0, 0 ); _enable_intr( iflag ); } #ifndef PCINT_PER_PORT #if (GPIO_MAX_PCINT >= 2) ISR( PCINT1_vect, ISR_ALIASOF( PCINT0_vect ) ); #endif #if (GPIO_MAX_PCINT == 3) ISR( PCINT2_vect, ISR_ALIASOF( PCINT0_vect ) ); #endif #else #if (GPIO_MAX_PCINT >= 2) ISR( PCINT1_vect ) { register uint8_t iflag; iflag = _disable_intr( ); _wakeup( EVENT_PCINT1, 0 ); _enable_intr( iflag ); } #endif #if (GPIO_MAX_PCINT == 3) ISR( PCINT2_vect ) { register uint8_t iflag; iflag = _disable_intr( ); _wakeup( EVENT_PCINT2, 0 ); _enable_intr( iflag ); } #endif #endif /* * enable/disable interrupt on gpio pin change * * input: * interrupt interrupt number (0, 1, 2) * mode interrupt mode (LOW, CHANGE, RISING, FALLING, DISABLE) */ void gpio_int_enable( uint8_t interrupt, uint8_t mode ) { #ifdef CHECK_PARAM if( interrupt < GPIO_MAX_INT && mode <= INT_DISABLE ) #endif { if( mode == INT_DISABLE ) /* #if defined(__AVR_ATtiny84__)\ || defined(__AVR_ATtiny85__)\ || defined(__AVR_ATtiny841__)\ || defined(__AVR_ATtiny1634__) */ #ifdef GIMSK GIMSK &= ~(1 << INT0); else { MCUCR |= mode; GIMSK |= (1 << INT0); } #else EIMSK &= ~(1 << interrupt); else { #if 0 #if defined(__AVR_ATmega2560__) if( interrupt >= 4 ) EICRB |= (mode << (interrupt-4)); else #endif #endif EICRA |= (mode << interrupt); EIMSK |= (1 << interrupt); } #endif } } /* * enable/disable interrupt on gpio pin change * * input: * gpio gpio pin * enable true or false */ void gpio_pcint_enable( uint8_t gpio, uint8_t enable ) { #ifdef CHECK_PARAM if( gpio < (GPIO_MAX_PORT << 3) ) #endif { #if defined(__AVR_ATtiny1634__) if( gpio > 11 ) gpio += 4; if( gpio < 22 ) #elif defined(__AVR_ATmega328P__) if( gpio != 15 ) #elif defined(__AVR_ATmega2560__) if( gpio >= 8 && gpio <= 15 ) gpio -= 8; else if( gpio == 32 ) gpio = 8; else if( gpio >= 64 && gpio <= 70 ) gpio -= 55; else if( gpio >= 72 && gpio <= 79 ) gpio -= 56; else return; #endif { uint8_t port = gpio >> 3; uint8_t mask = 1 << (gpio & 7); if( enable != 0 ) { *pcints[port].pcmsk |= mask; /* #if defined(__AVR_ATtiny84__)\ || defined(__AVR_ATtiny85__)\ || defined(__AVR_ATtiny841__)\ || defined(__AVR_ATtiny1634__) */ #ifdef GIMSK GIMSK |= pcints[port].pcie; #else PCICR |= pcints[port].pcie; #endif } else *pcints[port].pcmsk &= ~mask; } } }