mirror of
https://github.com/pascallanger/DIY-Multiprotocol-TX-Module.git
synced 2025-02-05 13:58:13 +00:00
809 lines
22 KiB
C
809 lines
22 KiB
C
|
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||
|
|
||
|
/*
|
||
|
Part of the Wiring project - http://wiring.uniandes.edu.co
|
||
|
|
||
|
Copyright (c) 2004-05 Hernando Barragan
|
||
|
|
||
|
This library is free software; you can redistribute it and/or
|
||
|
modify it under the terms of the GNU Lesser General Public
|
||
|
License as published by the Free Software Foundation; either
|
||
|
version 2.1 of the License, or (at your option) any later version.
|
||
|
|
||
|
This library is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
Lesser General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU Lesser General
|
||
|
Public License along with this library; if not, write to the
|
||
|
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||
|
Boston, MA 02111-1307 USA
|
||
|
|
||
|
Modified 24 November 2006 by David A. Mellis
|
||
|
Modified 1 August 2010 by Mark Sproul
|
||
|
|
||
|
Updated for 'xmega' core by bob frazier, S.F.T. Inc. - http://mrp3.com/
|
||
|
|
||
|
In some cases, the xmega updates make assumptions about the pin assignments.
|
||
|
See 'pins_arduino.h' for more detail.
|
||
|
|
||
|
*/
|
||
|
|
||
|
#include <inttypes.h>
|
||
|
#include <avr/io.h>
|
||
|
#include <avr/interrupt.h>
|
||
|
#include <avr/pgmspace.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
#include "wiring_private.h"
|
||
|
|
||
|
// interrupts on the xmega are handled differently than the mega
|
||
|
// there are 2 interrupt vectors for each port. Typical xmega
|
||
|
// will use ports A, B, C, D, E, and R. The vectors for those
|
||
|
// are as follows:
|
||
|
//
|
||
|
// PORTn_INT0_vect
|
||
|
// - and -
|
||
|
// PORTn_INT1_vect
|
||
|
//
|
||
|
// where 'n' is A, B, C, D, E, or R
|
||
|
//
|
||
|
// Additional vectors are:
|
||
|
//
|
||
|
// OSC_XOSCF_vect (external oscillator failure, NMI)
|
||
|
//
|
||
|
// RTC_OVF_vect (real-time clock overflow)
|
||
|
// RTC_COMP_vect (real-time clock compare)
|
||
|
//
|
||
|
// TWIC_TWIS_vect (2-wire slave on port C)
|
||
|
// TWIC_TWIM_vect (2-wire master on port C)
|
||
|
// TWIE_TWIS_vect (2-wire slave on port E)
|
||
|
// TWIE_TWIM_vect (2-wire master on port E)
|
||
|
//
|
||
|
// timers - 'n' is C or D
|
||
|
// TCn0_OVF_vect (n timer 0 overflow)
|
||
|
// TCn1_OVF_vect (n timer 1 overflow)
|
||
|
// TCn2_LUNF_vect (n timer 2 low byte underflow)
|
||
|
// TCn2_HUNF_vect (n timer 2 high byte underflow)
|
||
|
// TCE0_OVF_vect (E timer 0 overflow)
|
||
|
// TCn0_ERR_vect (n timer 0 error)
|
||
|
// TCn1_ERR_vect (n timer 1 error)
|
||
|
// TCE0_ERR_vect (E timer 0 error)
|
||
|
// TCn0_CCA_vect (n timer 0 compare or capture A)
|
||
|
// TCn1_CCA_vect (n timer 1 compare or capture A)
|
||
|
// TCn2_LCMPA_vect (n timer 2 low-byte compare or capture A)
|
||
|
// TCE0_CCA_vect (E timer 0 compare or capture A)
|
||
|
// TCn0_CCB_vect (n timer 0 compare or capture B)
|
||
|
// TCn1_CCB_vect (n timer 1 compare or capture B)
|
||
|
// TCn2_LCMPB_vect (n timer 2 low-byte compare or capture B)
|
||
|
// TCE0_CCB_vect (E timer 0 compare or capture B)
|
||
|
// TCn0_CCC_vect (n timer 0 compare or capture C)
|
||
|
// TCn2_LCMPC_vect (n timer 2 low-byte compare or capture C)
|
||
|
// TCE0_CCC_vect (E timer 0 compare or capture C)
|
||
|
// TCn0_CCD_vect (n timer 0 compare or capture D)
|
||
|
// TCn2_LCMPD_vect (n timer 2 low-byte compare or capture D)
|
||
|
// TCE0_CCD_vect (E timer 0 compare or capture D)
|
||
|
//
|
||
|
// SPIn_INT_vect (SPI C or D)
|
||
|
//
|
||
|
// USARTn0_RXC_vect (USART 'n' [C or D] receive complete)
|
||
|
// USARTn0_DRE_vect (USART 'n' [C or D] data reg empty)
|
||
|
// USARTn0_TXC_vect (USART 'n' [C or D] transmit complete)
|
||
|
//
|
||
|
// NOTE: a 'USARTE' interrupt vector also exists, but isn't
|
||
|
// implemented on the D4 series
|
||
|
//
|
||
|
// ASYNC interrupts are only possible on pin 2 for each of the 5
|
||
|
// ports ('R' only has 2 pins, 0 and 1, so no async interrupt).
|
||
|
// Sleep modes typically need ASYNC interrupts to wake up.
|
||
|
|
||
|
// The interrupt will be handled for a particular port, and not for
|
||
|
// a particular interrupt. The 'attachInterrupt' function will default
|
||
|
// to pin 2 (asynchronous interrupt) unless otherwise specified in the
|
||
|
// 'mode' parameter.
|
||
|
|
||
|
// BOOTLOADER NOTES
|
||
|
//
|
||
|
// Bit 6 of the CTRL reg must be assigned to '0'. Bit 7 can be assigned
|
||
|
// to '1' to enable 'round robin' scheduling using the priority bits.
|
||
|
// Bits 0-2 (HILVLEN, MEDLVLEN, LOLVLEN) should also be assigned to '1'
|
||
|
// to allow all 3 interrupt levels to execute. ('D' manual 10.8.3 pg 102)
|
||
|
// The CTRL reg can be assigned to b10000111 to accomplish this. Bit 6
|
||
|
// needs to use the "configuration change protection" method to change it
|
||
|
// and may need to be assigned separately.
|
||
|
|
||
|
|
||
|
|
||
|
// interrupt mode - predefined values are LOW, CHANGE, RISING, FALLING, HIGH
|
||
|
// additional bits are 'or'd with mode
|
||
|
|
||
|
static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS];
|
||
|
static volatile uint8_t intPins[EXTERNAL_NUM_INTERRUPTS]; // added - store pins for this interrupt
|
||
|
// volatile static voidFuncPtr twiIntFunc;
|
||
|
|
||
|
|
||
|
// NOTE: I _HATE_ K&R style so I'll make it Allman style as I go along...
|
||
|
|
||
|
void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode)
|
||
|
{
|
||
|
uint8_t iPinBits, iPriBits, iModeBits, iInv, iNum, iMask;
|
||
|
uint8_t oldSREG;
|
||
|
uint8_t intInfo;
|
||
|
PORT_t *port;
|
||
|
|
||
|
|
||
|
// for compatibility with newer IDE, 'interruptNum' can be encoded with pin information.
|
||
|
// if it is, then the pin info will be derived from pin info in 'mode' and 'interruptNum'
|
||
|
// pin info will be incorporated into it.
|
||
|
|
||
|
intInfo = ((interruptNum & 0xe0) >> 5); // is an int pin encoded here by digitalPinToInterrupt ?
|
||
|
interruptNum &= 0x1f; // so the rest of the code will work correctly
|
||
|
|
||
|
if(interruptNum >= EXTERNAL_NUM_INTERRUPTS)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
iPinBits = (uint8_t)((mode & INT_MODE_PIN_MASK) >> 8);
|
||
|
|
||
|
if(intInfo)
|
||
|
{
|
||
|
intInfo = ((intInfo + 2) & 7); // convert to actual pin number
|
||
|
|
||
|
iPinBits |= _BV(intInfo); // set respective bit in 'iPinBits'
|
||
|
}
|
||
|
|
||
|
if(!iPinBits)
|
||
|
{
|
||
|
if(interruptNum == PORTR_INT0
|
||
|
#ifdef PORTR_INT1
|
||
|
|| interruptNum == PORTR_INT1
|
||
|
#endif // PORTR_INT1
|
||
|
) // not valid for these
|
||
|
{
|
||
|
return; // do nothing (for now)
|
||
|
}
|
||
|
|
||
|
iPinBits = _BV(2); // set bit for pin 2 if none specified [i.e. 'default']
|
||
|
}
|
||
|
|
||
|
iPriBits = (mode & INT_MODE_PRI_MASK)
|
||
|
>> INT_MODE_PRI_SHIFT;
|
||
|
|
||
|
if(!iPriBits) // not assigned
|
||
|
{
|
||
|
iPriBits = 3; // for now, just use the highest priority
|
||
|
}
|
||
|
|
||
|
mode &= INT_MODE_MODE_MASK;
|
||
|
iInv = 0;
|
||
|
|
||
|
if(mode == LOW) // normally will be this, for backward hardware compatibility
|
||
|
{
|
||
|
iModeBits = PORT_ISC_LEVEL_gc; // b011, high level continuously generates events
|
||
|
}
|
||
|
else if(mode == HIGH) // these constants correspond to the mega's bit mask on ISC00,ISC10
|
||
|
{
|
||
|
iModeBits = PORT_ISC_LEVEL_gc; // b011, high level continuously generates events
|
||
|
iInv = 1; // invert input (so 'high level' becomes 'low level')
|
||
|
|
||
|
// NOTE: this was verified by experimentation. The documentation is misleading, suggesting
|
||
|
// that a LEVEL interrupt triggered on HIGH, not on LOW. But it triggers on LOW. So
|
||
|
// if you want HIGH, you must invert it. Not the other way around. Yeah.
|
||
|
}
|
||
|
else if(mode == CHANGE)
|
||
|
{
|
||
|
iModeBits = PORT_ISC_BOTHEDGES_gc; // BOTHEDGES - see table 11-6
|
||
|
}
|
||
|
else if(mode == RISING)
|
||
|
{
|
||
|
iModeBits = PORT_ISC_RISING_gc; // b001, RISING
|
||
|
}
|
||
|
else if(mode == FALLING)
|
||
|
{
|
||
|
iModeBits = PORT_ISC_FALLING_gc; // b010, FALLING
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
iModeBits = PORT_ISC_BOTHEDGES_gc; // BOTH (the default - note INTPUT_DISABLED (sic) won't buffer the input, so it's useless except for analog channels)
|
||
|
}
|
||
|
|
||
|
if(iInv)
|
||
|
{
|
||
|
iModeBits |= _BV(PORT_INVEN_bp); // set the 'inverted' bit
|
||
|
}
|
||
|
|
||
|
oldSREG = SREG; // store the interrupt flag basically
|
||
|
|
||
|
cli(); // disable interrupts for a bit
|
||
|
|
||
|
intFunc[interruptNum] = userFunc;
|
||
|
intPins[interruptNum] = iPinBits; // save what pins I used
|
||
|
|
||
|
// Enable the interrupt (smaller code to use if/else and pointer)
|
||
|
|
||
|
iNum = 0;
|
||
|
if(interruptNum == PORTA_INT0
|
||
|
#ifdef PORTA_INT1
|
||
|
|| interruptNum == PORTA_INT1
|
||
|
#endif // PORTA_INT1
|
||
|
)
|
||
|
{
|
||
|
port = &PORTA;
|
||
|
#ifdef PORTA_INT1
|
||
|
if(interruptNum == PORTA_INT1)
|
||
|
{
|
||
|
iNum = 1;
|
||
|
}
|
||
|
#endif // PORTA_INT1
|
||
|
}
|
||
|
#if NUM_ANALOG_PINS > 8 /* which means we have PORT B */
|
||
|
else if(interruptNum == PORTB_INT0
|
||
|
#ifdef PORTB_INT1
|
||
|
|| interruptNum == PORTB_INT1
|
||
|
#endif // PORTB_INT1
|
||
|
)
|
||
|
{
|
||
|
port = &PORTB;
|
||
|
#ifdef PORTB_INT1
|
||
|
if(interruptNum == PORTB_INT1)
|
||
|
{
|
||
|
iNum = 1;
|
||
|
}
|
||
|
#endif // PORTB_INT1
|
||
|
}
|
||
|
#endif // NUM_ANALOG_PINS > 8
|
||
|
else if(interruptNum == PORTC_INT0
|
||
|
#ifdef PORTC_INT1
|
||
|
|| interruptNum == PORTC_INT1
|
||
|
#endif // PORTC_INT1
|
||
|
)
|
||
|
{
|
||
|
port = &PORTC;
|
||
|
#ifdef PORTC_INT1
|
||
|
if(interruptNum == PORTC_INT1)
|
||
|
{
|
||
|
iNum = 1;
|
||
|
}
|
||
|
#endif // PORTC_INT1
|
||
|
}
|
||
|
else if(interruptNum == PORTD_INT0
|
||
|
#ifdef PORTD_INT1
|
||
|
|| interruptNum == PORTD_INT1
|
||
|
#endif // PORTD_INT1
|
||
|
)
|
||
|
{
|
||
|
port = &PORTD;
|
||
|
#ifdef PORTD_INT1
|
||
|
if(interruptNum == PORTD_INT1)
|
||
|
{
|
||
|
iNum = 1;
|
||
|
}
|
||
|
#endif // PORTC_INT1
|
||
|
}
|
||
|
#if NUM_DIGITAL_PINS > 18 /* which means we have PORT E */
|
||
|
else if(interruptNum == PORTE_INT0
|
||
|
#ifdef PORTE_INT1
|
||
|
|| interruptNum == PORTE_INT1
|
||
|
#endif // PORTE_INT1
|
||
|
)
|
||
|
{
|
||
|
port = &PORTE;
|
||
|
#ifdef PORTE_INT1
|
||
|
if(interruptNum == PORTE_INT1)
|
||
|
{
|
||
|
iNum = 1;
|
||
|
}
|
||
|
#endif // PORTE_INT1
|
||
|
}
|
||
|
#endif // NUM_DIGITAL_PINS > 18
|
||
|
else if(interruptNum == PORTR_INT0
|
||
|
#ifdef PORTR_INT1
|
||
|
|| interruptNum == PORTR_INT1
|
||
|
#endif // PORTR_INT1
|
||
|
)
|
||
|
{
|
||
|
port = &PORTR;
|
||
|
#ifdef PORTR_INT1
|
||
|
if(interruptNum == PORTR_INT1)
|
||
|
{
|
||
|
iNum = 1;
|
||
|
}
|
||
|
#endif // PORTR_INT1
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return; // do nothing
|
||
|
}
|
||
|
|
||
|
// On certain processors there's only one interrupt, so it's called 'INTMASK'
|
||
|
// we test for this here
|
||
|
|
||
|
#ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
|
||
|
if(!iNum)
|
||
|
{
|
||
|
// set interrupt mask for PORT A, int 0 vector
|
||
|
port->INTMASK |= iPinBits; // enable int zero for these pins
|
||
|
port->INTCTRL = (port->INTCTRL & ~(PORT_INTLVL_gm))
|
||
|
| (iPriBits & 3);
|
||
|
}
|
||
|
#else // INT0MASK and INT1MASK supported
|
||
|
if(!iNum)
|
||
|
{
|
||
|
// set interrupt mask for PORT A, int 0 vector
|
||
|
port->INT0MASK |= iPinBits; // enable int zero for these pins
|
||
|
port->INTCTRL = (port->INTCTRL & ~(PORT_INT0LVL_gm))
|
||
|
| (iPriBits & 3);
|
||
|
}
|
||
|
else // if(iNum == 1)
|
||
|
{
|
||
|
port->INT1MASK |= iPinBits; // enable int zero for these pins
|
||
|
port->INTCTRL = (port->INTCTRL & ~(PORT_INT1LVL_gm))
|
||
|
| ((iPriBits & 3) << PORT_INT1LVL_gp);
|
||
|
}
|
||
|
#endif // INT0MASK and INT1MASK supported
|
||
|
|
||
|
for(iNum=0, iMask = 1; iNum < 8; iNum++, iMask <<= 1)
|
||
|
{
|
||
|
register8_t *pCTRL = &(port->PIN0CTRL) + iNum; // treat PIN0CTRL through PIN7CTRL as an array
|
||
|
|
||
|
// set corresponding 'type' in the interrupt control regs for the individual bits
|
||
|
|
||
|
if(iPinBits & iMask) // is this bit set in 'iPinBits'?
|
||
|
{
|
||
|
// enable the interrupt pin's mode bits and assign the 'invert' flag as needed
|
||
|
|
||
|
*pCTRL = (*pCTRL & ~(PORT_ISC_gm | PORT_INVEN_bm))
|
||
|
| iModeBits;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SREG = oldSREG; // restore it, interrupts (probably) re-enabled
|
||
|
// NOTE that this may throw an interrupt right away
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void detachInterrupt(uint8_t interruptNum)
|
||
|
{
|
||
|
uint8_t iPinBits, iNum, iMask;
|
||
|
uint8_t oldSREG;
|
||
|
PORT_t *port;
|
||
|
|
||
|
|
||
|
// NOTE: this function will turn OFF the 'invert' bit if it's set for a HIGH level interrupt
|
||
|
// and digitalRead _SHOULD_ be consistent before/after this call.
|
||
|
|
||
|
if(interruptNum >= EXTERNAL_NUM_INTERRUPTS)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
oldSREG = SREG; // keep track of interrupt flag state
|
||
|
|
||
|
cli(); // clear the interrupt flag
|
||
|
|
||
|
// grab 'pin bits' so I know what to flip around
|
||
|
iPinBits = intPins[interruptNum]; // what I used when I added it
|
||
|
|
||
|
intFunc[interruptNum] = 0;
|
||
|
intPins[interruptNum] = 0; // zero both of these
|
||
|
|
||
|
// disable the interrupt
|
||
|
|
||
|
// Enable the interrupt (smaller code to use if/else and pointer)
|
||
|
|
||
|
iNum = 0;
|
||
|
if(interruptNum == PORTA_INT0
|
||
|
#ifdef PORTA_INT1
|
||
|
|| interruptNum == PORTA_INT1
|
||
|
#endif // PORTA_INT1
|
||
|
)
|
||
|
{
|
||
|
port = &PORTA;
|
||
|
#ifdef PORTA_INT1
|
||
|
if(interruptNum == PORTA_INT1)
|
||
|
{
|
||
|
iNum = 1;
|
||
|
}
|
||
|
#endif // PORTA_INT1
|
||
|
}
|
||
|
#if NUM_ANALOG_PINS > 8 /* which means we have PORT B */
|
||
|
else if(interruptNum == PORTB_INT0
|
||
|
#ifdef PORTB_INT1
|
||
|
|| interruptNum == PORTB_INT1
|
||
|
#endif // PORTB_INT1
|
||
|
)
|
||
|
{
|
||
|
port = &PORTB;
|
||
|
#ifdef PORTB_INT1
|
||
|
if(interruptNum == PORTB_INT1)
|
||
|
{
|
||
|
iNum = 1;
|
||
|
}
|
||
|
#endif // PORTB_INT1
|
||
|
}
|
||
|
#endif // NUM_ANALOG_PINS > 8
|
||
|
else if(interruptNum == PORTC_INT0
|
||
|
#ifdef PORTC_INT1
|
||
|
|| interruptNum == PORTC_INT1
|
||
|
#endif // PORTC_INT1
|
||
|
)
|
||
|
{
|
||
|
port = &PORTC;
|
||
|
#ifdef PORTC_INT1
|
||
|
if(interruptNum == PORTC_INT1)
|
||
|
{
|
||
|
iNum = 1;
|
||
|
}
|
||
|
#endif // PORTC_INT1
|
||
|
}
|
||
|
else if(interruptNum == PORTD_INT0
|
||
|
#ifdef PORTD_INT1
|
||
|
|| interruptNum == PORTD_INT1
|
||
|
#endif // PORTD_INT1
|
||
|
)
|
||
|
{
|
||
|
port = &PORTD;
|
||
|
#ifdef PORTD_INT1
|
||
|
if(interruptNum == PORTD_INT1)
|
||
|
{
|
||
|
iNum = 1;
|
||
|
}
|
||
|
#endif // PORTD_INT1
|
||
|
}
|
||
|
#if NUM_DIGITAL_PINS > 18 /* which means we have PORT E */
|
||
|
else if(interruptNum == PORTE_INT0
|
||
|
#ifdef PORTE_INT1
|
||
|
|| interruptNum == PORTE_INT1
|
||
|
#endif // PORTE_INT1
|
||
|
)
|
||
|
{
|
||
|
port = &PORTE;
|
||
|
#ifdef PORTE_INT1
|
||
|
if(interruptNum == PORTE_INT1)
|
||
|
{
|
||
|
iNum = 1;
|
||
|
}
|
||
|
#endif // PORTE_INT1
|
||
|
}
|
||
|
#endif // NUM_DIGITAL_PINS > 18
|
||
|
else if(interruptNum == PORTR_INT0
|
||
|
#ifdef PORTR_INT1
|
||
|
|| interruptNum == PORTR_INT1
|
||
|
#endif // PORTR_INT1
|
||
|
)
|
||
|
{
|
||
|
port = &PORTR;
|
||
|
#ifdef PORTR_INT1
|
||
|
if(interruptNum == PORTR_INT1)
|
||
|
{
|
||
|
iNum = 1;
|
||
|
}
|
||
|
#endif // PORTR_INT1
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return; // do nothing
|
||
|
}
|
||
|
|
||
|
// On certain processors there's only one interrupt, so it's called 'INTMASK'
|
||
|
// we test for this here
|
||
|
|
||
|
#ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
|
||
|
if(!iNum)
|
||
|
{
|
||
|
// set interrupt mask for PORT A, int 0 vector
|
||
|
port->INTMASK = 0; // disable interrupts - TODO, read this instead of 'iPinBits' ?
|
||
|
port->INTCTRL &= ~(PORT_INTLVL_gm); // set interrupt control to 'OFF'
|
||
|
port->INTFLAGS = _BV(0); // clear the int flag
|
||
|
|
||
|
#else // INT0MASK and INT1MASK supported
|
||
|
if(!iNum)
|
||
|
{
|
||
|
// set interrupt mask for PORT A, int 0 vector
|
||
|
port->INT0MASK = 0; // disable interrupts - TODO, read this instead of 'iPinBits' ?
|
||
|
port->INTCTRL &= ~(PORT_INT0LVL_gm); // set interrupt control to 'OFF'
|
||
|
port->INTFLAGS = _BV(0); // clear the int 0 flag
|
||
|
}
|
||
|
else // if(iNum == 1)
|
||
|
{
|
||
|
#endif // INT0MASK and INT1MASK supported
|
||
|
// if this matches a CTS port, I do _NOT_ want to disable interrupts
|
||
|
#if defined(SERIAL_0_CTS_ENABLED) && defined(SERIAL_1_CTS_ENABLED)
|
||
|
if(SERIAL_0_CTS_PORT == port)
|
||
|
{
|
||
|
#ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
|
||
|
if(SERIAL_1_CTS_PORT == port)
|
||
|
{
|
||
|
port->INTMASK = SERIAL_0_CTS_PIN | SERIAL_1_CTS_PIN; // disable interrupts but leave BOTH enabled
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
port->INTMASK = SERIAL_0_CTS_PIN; // disable interrupts but leave THIS one enabled
|
||
|
}
|
||
|
|
||
|
port->INTCTRL |= PORT_INTLVL_gm; // max priority when I do this
|
||
|
#else // INT0MASK and INT1MASK supported
|
||
|
if(SERIAL_1_CTS_PORT == port)
|
||
|
{
|
||
|
port->INT1MASK = SERIAL_0_CTS_PIN | SERIAL_1_CTS_PIN; // disable interrupts but leave BOTH enabled
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
port->INT1MASK = SERIAL_0_CTS_PIN; // disable interrupts but leave THIS one enabled
|
||
|
}
|
||
|
|
||
|
port->INTCTRL |= PORT_INT1LVL_gm; // max priority when I do this
|
||
|
#endif // INT0MASK and INT1MASK supported
|
||
|
}
|
||
|
else if(SERIAL_1_CTS_PORT == port)
|
||
|
{
|
||
|
#ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
|
||
|
port->INTMASK = SERIAL_1_CTS_PIN; // disable interrupts but leave THIS one enabled
|
||
|
|
||
|
port->INTCTRL |= PORT_INTLVL_gm; // max priority when I do this
|
||
|
#else // INT0MASK and INT1MASK supported
|
||
|
port->INT1MASK = SERIAL_1_CTS_PIN; // disable interrupts but leave THIS one enabled
|
||
|
|
||
|
port->INTCTRL |= PORT_INT1LVL_gm; // max priority when I do this
|
||
|
#endif // INT0MASK and INT1MASK supported
|
||
|
}
|
||
|
#elif defined(SERIAL_0_CTS_ENABLED)
|
||
|
if(SERIAL_0_CTS_PORT == port)
|
||
|
{
|
||
|
#ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
|
||
|
port->INTMASK = SERIAL_0_CTS_PIN; // disable interrupts but leave THIS one enabled
|
||
|
|
||
|
port->INTCTRL |= PORT_INTLVL_gm; // max priority when I do this
|
||
|
#else // INT0MASK and INT1MASK supported
|
||
|
port->INT1MASK = SERIAL_0_CTS_PIN; // disable interrupts but leave THIS one enabled
|
||
|
|
||
|
port->INTCTRL |= PORT_INT1LVL_gm; // max priority when I do this
|
||
|
#endif // INT0MASK and INT1MASK supported
|
||
|
}
|
||
|
#elif defined(SERIAL_1_CTS_ENABLED)
|
||
|
if(SERIAL_1_CTS_PORT == port)
|
||
|
{
|
||
|
#ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
|
||
|
port->INTMASK = SERIAL_1_CTS_PIN; // disable interrupts but leave THIS one enabled
|
||
|
|
||
|
port->INTCTRL |= PORT_INTLVL_gm; // max priority when I do this
|
||
|
#else // INT0MASK and INT1MASK supported
|
||
|
port->INT1MASK = SERIAL_1_CTS_PIN; // disable interrupts but leave THIS one enabled
|
||
|
|
||
|
port->INTCTRL |= PORT_INT1LVL_gm; // max priority when I do this
|
||
|
#endif // INT0MASK and INT1MASK supported
|
||
|
}
|
||
|
#endif // SERIAL_0/1_CTS_ENABLED
|
||
|
|
||
|
#if defined(SERIAL_0_CTS_ENABLED) || defined(SERIAL_1_CTS_ENABLED)
|
||
|
else
|
||
|
#endif // SERIAL_0/1_CTS_ENABLED
|
||
|
|
||
|
{
|
||
|
#ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
|
||
|
port->INTMASK = 0; // disable interrupts - TODO, read this instead of 'iPinBits' ?
|
||
|
port->INTCTRL &= ~(PORT_INTLVL_gm); // set interrupt control to 'OFF'
|
||
|
#else // INT0MASK and INT1MASK supported
|
||
|
port->INT1MASK = 0; // disable interrupts - TODO, read this instead of 'iPinBits' ?
|
||
|
port->INTCTRL &= ~(PORT_INT1LVL_gm); // set interrupt control to 'OFF'
|
||
|
#endif // INT0MASK and INT1MASK supported
|
||
|
}
|
||
|
|
||
|
#ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
|
||
|
port->INTFLAGS = _BV(0); // clear the int 0 flag
|
||
|
#else // INT0MASK and INT1MASK supported
|
||
|
port->INTFLAGS = _BV(1); // clear the int 1 flag
|
||
|
#endif // INT0MASK and INT1MASK supported
|
||
|
}
|
||
|
|
||
|
for(iNum=0, iMask = 1; iNum < 8; iNum++, iMask <<= 1)
|
||
|
{
|
||
|
register8_t *pCTRL = &(port->PIN0CTRL) + iNum; // treat PIN0CTRL through PIN7CTRL as an array
|
||
|
|
||
|
// set corresponding 'type' in the interrupt control regs for the individual bits
|
||
|
|
||
|
if(iPinBits & iMask) // is this bit set in 'iPinBits'?
|
||
|
{
|
||
|
*pCTRL &= ~(PORT_ISC_gm | PORT_INVEN_bm); // turn off invert flag and reset to 'BOTH' (the default)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SREG = oldSREG; // restore it, interrupts (probably) re-enabled
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
|
||
|
ISR(PORTA_INT_vect)
|
||
|
#else // INT0MASK and INT1MASK supported
|
||
|
ISR(PORTA_INT0_vect)
|
||
|
#endif // INT0MASK and INT1MASK supported
|
||
|
{
|
||
|
if(intFunc[PORTA_INT0])
|
||
|
intFunc[PORTA_INT0]();
|
||
|
|
||
|
#ifdef PORTC_INT0MASK // INT0MASK and INT1MASK supported
|
||
|
}
|
||
|
|
||
|
ISR(PORTA_INT1_vect)
|
||
|
{
|
||
|
if(intFunc[PORTA_INT1])
|
||
|
intFunc[PORTA_INT1]();
|
||
|
#endif // INT0MASK and INT1MASK supported
|
||
|
|
||
|
#if defined(SERIAL_0_CTS_ENABLED)
|
||
|
if(SERIAL_0_CTS_PORT == &(PORTA)) // this should compile as a constant expression
|
||
|
{
|
||
|
serial_0_cts_callback();
|
||
|
}
|
||
|
#endif // SERIAL_0_CTS_ENABLED
|
||
|
|
||
|
#ifdef SERIAL_1_CTS_ENABLED
|
||
|
if(SERIAL_1_CTS_PORT == &(PORTA))
|
||
|
{
|
||
|
serial_1_cts_callback();
|
||
|
}
|
||
|
#endif // SERIAL_1_CTS_ENABLED
|
||
|
}
|
||
|
|
||
|
#if NUM_ANALOG_PINS > 8 /* which means we have PORT B */
|
||
|
ISR(PORTB_INT0_vect)
|
||
|
{
|
||
|
if(intFunc[PORTB_INT0])
|
||
|
intFunc[PORTB_INT0]();
|
||
|
}
|
||
|
|
||
|
ISR(PORTB_INT1_vect)
|
||
|
{
|
||
|
if(intFunc[PORTB_INT1])
|
||
|
intFunc[PORTB_INT1]();
|
||
|
|
||
|
#if defined(SERIAL_0_CTS_ENABLED)
|
||
|
if(SERIAL_0_CTS_PORT == &(PORTB)) // this should compile as a constant expression
|
||
|
{
|
||
|
serial_0_cts_callback();
|
||
|
}
|
||
|
#endif // SERIAL_0_CTS_ENABLED
|
||
|
|
||
|
#ifdef SERIAL_1_CTS_ENABLED
|
||
|
if(SERIAL_1_CTS_PORT == &(PORTB))
|
||
|
{
|
||
|
serial_1_cts_callback();
|
||
|
}
|
||
|
#endif // SERIAL_1_CTS_ENABLED
|
||
|
}
|
||
|
#endif // NUM_ANALOG_PINS > 8
|
||
|
|
||
|
#ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
|
||
|
ISR(PORTC_INT_vect)
|
||
|
#else // INT0MASK and INT1MASK supported
|
||
|
ISR(PORTC_INT0_vect)
|
||
|
#endif // INT0MASK and INT1MASK supported
|
||
|
{
|
||
|
if(intFunc[PORTC_INT0])
|
||
|
intFunc[PORTC_INT0]();
|
||
|
#ifdef PORTC_INT0MASK // INT0MASK and INT1MASK supported
|
||
|
}
|
||
|
|
||
|
ISR(PORTC_INT1_vect)
|
||
|
{
|
||
|
if(intFunc[PORTC_INT1])
|
||
|
intFunc[PORTC_INT1]();
|
||
|
#endif // INT0MASK and INT1MASK supported
|
||
|
|
||
|
#if defined(SERIAL_0_CTS_ENABLED)
|
||
|
if(SERIAL_0_CTS_PORT == &(PORTC)) // this should compile as a constant expression
|
||
|
{
|
||
|
serial_0_cts_callback();
|
||
|
}
|
||
|
#endif // SERIAL_0_CTS_ENABLED
|
||
|
|
||
|
#ifdef SERIAL_1_CTS_ENABLED
|
||
|
if(SERIAL_1_CTS_PORT == &(PORTC))
|
||
|
{
|
||
|
serial_1_cts_callback();
|
||
|
}
|
||
|
#endif // SERIAL_1_CTS_ENABLED
|
||
|
}
|
||
|
|
||
|
#ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
|
||
|
ISR(PORTD_INT_vect)
|
||
|
#else // INT0MASK and INT1MASK supported
|
||
|
ISR(PORTD_INT0_vect)
|
||
|
#endif // INT0MASK and INT1MASK supported
|
||
|
{
|
||
|
if(intFunc[PORTD_INT0])
|
||
|
intFunc[PORTD_INT0]();
|
||
|
#ifdef PORTC_INT0MASK // INT0MASK and INT1MASK supported
|
||
|
}
|
||
|
|
||
|
ISR(PORTD_INT1_vect)
|
||
|
{
|
||
|
if(intFunc[PORTD_INT1])
|
||
|
intFunc[PORTD_INT1]();
|
||
|
#endif // INT0MASK and INT1MASK supported
|
||
|
|
||
|
#if defined(SERIAL_0_CTS_ENABLED)
|
||
|
if(SERIAL_0_CTS_PORT == &(PORTD)) // this should compile as a constant expression
|
||
|
{
|
||
|
serial_0_cts_callback();
|
||
|
}
|
||
|
#endif // SERIAL_0_CTS_ENABLED
|
||
|
|
||
|
#ifdef SERIAL_1_CTS_ENABLED
|
||
|
if(SERIAL_1_CTS_PORT == &(PORTD))
|
||
|
{
|
||
|
serial_1_cts_callback();
|
||
|
}
|
||
|
#endif // SERIAL_1_CTS_ENABLED
|
||
|
}
|
||
|
|
||
|
|
||
|
#if NUM_DIGITAL_PINS > 18 /* which means we have PORT E */
|
||
|
ISR(PORTE_INT0_vect)
|
||
|
{
|
||
|
if(intFunc[PORTE_INT0])
|
||
|
intFunc[PORTE_INT0]();
|
||
|
}
|
||
|
|
||
|
ISR(PORTE_INT1_vect)
|
||
|
{
|
||
|
if(intFunc[PORTE_INT1])
|
||
|
intFunc[PORTE_INT1]();
|
||
|
|
||
|
#if defined(SERIAL_0_CTS_ENABLED)
|
||
|
if(SERIAL_0_CTS_PORT == &(PORTE)) // this should compile as a constant expression
|
||
|
{
|
||
|
serial_0_cts_callback();
|
||
|
}
|
||
|
#endif // SERIAL_0_CTS_ENABLED
|
||
|
|
||
|
#ifdef SERIAL_1_CTS_ENABLED
|
||
|
if(SERIAL_1_CTS_PORT == &(PORTE))
|
||
|
{
|
||
|
serial_1_cts_callback();
|
||
|
}
|
||
|
#endif // SERIAL_1_CTS_ENABLED
|
||
|
}
|
||
|
#endif // NUM_DIGITAL_PINS > 18
|
||
|
|
||
|
// TODO: ISRs for PORTF, PORTH, PORTJ, PORTK, PORTQ
|
||
|
|
||
|
#ifndef PORTC_INT0MASK /* meaning there's only one int vector and not two */
|
||
|
ISR(PORTR_INT_vect)
|
||
|
#else // INT0MASK and INT1MASK supported
|
||
|
ISR(PORTR_INT0_vect)
|
||
|
#endif // INT0MASK and INT1MASK supported
|
||
|
{
|
||
|
if(intFunc[PORTR_INT0])
|
||
|
intFunc[PORTR_INT0]();
|
||
|
#ifdef PORTC_INT0MASK // INT0MASK and INT1MASK supported
|
||
|
}
|
||
|
|
||
|
ISR(PORTR_INT1_vect)
|
||
|
{
|
||
|
if(intFunc[PORTR_INT1])
|
||
|
intFunc[PORTR_INT1]();
|
||
|
#endif // INT0MASK and INT1MASK supported
|
||
|
|
||
|
#if defined(SERIAL_0_CTS_ENABLED)
|
||
|
if(SERIAL_0_CTS_PORT == &(PORTR)) // this should compile as a constant expression
|
||
|
{
|
||
|
serial_0_cts_callback();
|
||
|
}
|
||
|
#endif // SERIAL_0_CTS_ENABLED
|
||
|
|
||
|
#ifdef SERIAL_1_CTS_ENABLED
|
||
|
if(SERIAL_1_CTS_PORT == &(PORTR))
|
||
|
{
|
||
|
serial_1_cts_callback();
|
||
|
}
|
||
|
#endif // SERIAL_1_CTS_ENABLED
|
||
|
}
|
||
|
|
||
|
|
||
|
|