aboutsummaryrefslogtreecommitdiff
path: root/avr/pcint.c
diff options
context:
space:
mode:
authorOtto Mattik <otto@mattik.org>2021-07-08 18:10:55 +0200
committerOtto Mattik <otto@mattik.org>2021-07-08 18:10:55 +0200
commitda34d97efb21719b2b332f8c60b2750d11bcde1f (patch)
tree2de9fe89f6d79b8ebfcde64c5e86204e904aedf2 /avr/pcint.c
downloadarmen-1.0.tar.gz
armen-1.0.zip
git: update to v1.0HEADv1.0master
Diffstat (limited to 'avr/pcint.c')
-rw-r--r--avr/pcint.c247
1 files changed, 247 insertions, 0 deletions
diff --git a/avr/pcint.c b/avr/pcint.c
new file mode 100644
index 0000000..4dea0c7
--- /dev/null
+++ b/avr/pcint.c
@@ -0,0 +1,247 @@
+/************************************************************************/
+/* */
+/* 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 <avr/interrupt.h>
+
+#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<<PCIE0 }
+#elif defined(__AVR_ATtiny84__)\
+ || defined(__AVR_ATtiny841__)
+ { 0x0032, 1<<PCIE0 },
+ { 0x0040, 1<<PCIE1 }
+#elif defined(__AVR_ATtiny1634__)
+ { 0x0047, 1<<PCIE0 },
+ { 0x0048, 1<<PCIE1 },
+ { 0x0049, 1<<PCIE2 }
+#elif defined(__AVR_ATmega328P__)\
+ || defined(__AVR_ATmega2560__)
+ { 0x006B, 1<<PCIE0 },
+ { 0x006C, 1<<PCIE1 },
+ { 0x006D, 1<<PCIE2 }
+ #endif
+};
+
+/*
+ * interrupt vectors
+*/
+ISR( INT0_vect )
+{
+ register uint8_t iflag;
+
+ iflag = _disable_intr( );
+#ifdef GIMSK
+ if( (MCUCR & 0x03) == INT_LOW )
+ GIMSK &= ~(1 << INT0);
+#else
+ if( (EICRA & 0x03) == INT_LOW )
+ EIMSK &= ~1;
+#endif
+ _wakeup( EVENT_INT0, 0 );
+ _enable_intr( iflag );
+}
+
+#if (GPIO_MAX_INT >= 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;
+ }
+ }
+}