Skip to content

Commit

Permalink
support arduino due
Browse files Browse the repository at this point in the history
  • Loading branch information
neu-rah committed Oct 29, 2016
1 parent 3faf122 commit bbe2184
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 100 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.pioenvs
.clang_complete
.gcc-flags.json
.piolibdeps
*.gch
2 changes: 1 addition & 1 deletion examples/btnled/btnled.ino
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ void setled() {

void setup() {
pinMode(led,OUTPUT);
pinMode(btn,INPUT);
pinMode(btn,INPUT_PULLUP);
digitalWrite(btn,1);//pullup
PCattachInterrupt(btn,setled,CHANGE);
setled();//initial led status
Expand Down
127 changes: 69 additions & 58 deletions src/pcint.cpp
Original file line number Diff line number Diff line change
@@ -1,73 +1,84 @@
#include "pcint.h"

static int PCintMode[3][8];
static HANDLER_TYPE PCintFunc[3][8];
static bool PCintLast[3][8];//?we can use only 3 bytes... but will use more processing power calculating masks

#ifndef ARDUINO_SAM_DUE
static int PCintMode[3][8];
static HANDLER_TYPE PCintFunc[3][8];
static bool PCintLast[3][8];//?we can use only 3 bytes... but will use more processing power calculating masks
#endif
/*
* attach an interrupt to a specific pin using pin change interrupts.
*/
void PCattachInterrupt(uint8_t pin, class mixHandler userFunc, uint8_t mode) {
volatile uint8_t *pcmask=digitalPinToPCMSK(pin);
if (!pcmask) return;//runtime checking if pin has PCINT, i would prefer a compile time check
uint8_t bit = digitalPinToPCMSKbit(pin);
uint8_t mask = 1<<bit;
uint8_t pcicrBit=digitalPinToPCICRbit(pin);
PCintMode[pcicrBit][bit] = mode;
PCintFunc[pcicrBit][bit] = userFunc;
//initialize last status flags
PCintLast[pcicrBit][bit]=(*portInputRegister(digitalPinToPort(pin)))&digitalPinToBitMask(pin);
// set the mask
*pcmask |= mask;
// enable the interrupt
PCICR |= (1<<pcicrBit);
void PCattachInterrupt(uint8_t pin, HANDLER_TYPE userFunc, uint8_t mode) {
#ifdef ARDUINO_SAM_DUE
attachInterrupt(digitalPinToInterrupt(pin),userFunc,mode);
#else
volatile uint8_t *pcmask=digitalPinToPCMSK(pin);
if (!pcmask) return;//runtime checking if pin has PCINT, i would prefer a compile time check
uint8_t bit = digitalPinToPCMSKbit(pin);
uint8_t mask = 1<<bit;
uint8_t pcicrBit=digitalPinToPCICRbit(pin);
PCintMode[pcicrBit][bit] = mode;
PCintFunc[pcicrBit][bit] = userFunc;
//initialize last status flags
PCintLast[pcicrBit][bit]=(*portInputRegister(digitalPinToPort(pin)))&digitalPinToBitMask(pin);
// set the mask
*pcmask |= mask;
// enable the interrupt
PCICR |= (1<<pcicrBit);
#endif
}

void PCdetachInterrupt(uint8_t pin) {
volatile uint8_t *pcmask=digitalPinToPCMSK(pin);
if (!pcmask) return;//runtime checking if pin has PCINT, i would prefer a compile time check
// disable the mask.
*pcmask &= ~(1<<digitalPinToPCMSKbit(pin));
// if that's the last one, disable the interrupt.
if (*pcmask == 0)
PCICR &= ~(1<<digitalPinToPCICRbit(pin));
#ifdef ARDUINO_SAM_DUE
detachInterrupt(pin);
#else
volatile uint8_t *pcmask=digitalPinToPCMSK(pin);
if (!pcmask) return;//runtime checking if pin has PCINT, i would prefer a compile time check
// disable the mask.
*pcmask &= ~(1<<digitalPinToPCMSKbit(pin));
// if that's the last one, disable the interrupt.
if (*pcmask == 0)
PCICR &= ~(1<<digitalPinToPCICRbit(pin));
#endif
}

// common code for isr handler. "port" is the PCINT number.
// there isn't really a good way to back-map ports and masks to pins.
// here we consider only the first change found ignoring subsequent, assuming no interrupt cascade
static void PCint(uint8_t port) {
const uint8_t* map=pcintPinMapBank(port);//get 8 bits pin change map
for(int i=0;i<8;i++) {
uint8_t p=digitalPinFromPCINTBank(map,i);
if (p==-1)
continue;//its not assigned
//uint8_t bit = digitalPinToPCMSKbit(p);
//uint8_t mask = (1<<bit);
if (PCintFunc[port][i]!=NULL) {//only check active pins
bool stat=(*portInputRegister(digitalPinToPort(p)))&digitalPinToBitMask(p);
if (PCintLast[port][i]^stat) {//pin changed!
PCintLast[port][i]=stat;//register change
if (
(PCintMode[port][i]==CHANGE)
|| ((stat)&&(PCintMode[port][i]==RISING))
|| ((!stat)&&(PCintMode[port][i]==FALLING))
) {
PCintFunc[port][i]();
break;//if using concurrent interrupts remove this
#ifndef ARDUINO_SAM_DUE
// common code for isr handler. "port" is the PCINT number.
// there isn't really a good way to back-map ports and masks to pins.
// here we consider only the first change found ignoring subsequent, assuming no interrupt cascade
static void PCint(uint8_t port) {
const uint8_t* map=pcintPinMapBank(port);//get 8 bits pin change map
for(int i=0;i<8;i++) {
uint8_t p=digitalPinFromPCINTBank(map,i);
if (p==-1)
continue;//its not assigned
//uint8_t bit = digitalPinToPCMSKbit(p);
//uint8_t mask = (1<<bit);
if (PCintFunc[port][i]!=NULL) {//only check active pins
bool stat=(*portInputRegister(digitalPinToPort(p)))&digitalPinToBitMask(p);
if (PCintLast[port][i]^stat) {//pin changed!
PCintLast[port][i]=stat;//register change
if (
(PCintMode[port][i]==CHANGE)
|| ((stat)&&(PCintMode[port][i]==RISING))
|| ((!stat)&&(PCintMode[port][i]==FALLING))
) {
PCintFunc[port][i]();
break;//if using concurrent interrupts remove this
}
}
}
}
}
}

//AVR handle pin change... later figure out the pin
SIGNAL(PCINT0_vect) {
PCint(0);
}
SIGNAL(PCINT1_vect) {
PCint(1);
}
SIGNAL(PCINT2_vect) {
PCint(2);
}
//AVR handle pin change... later figure out the pin
SIGNAL(PCINT0_vect) {
PCint(0);
}
SIGNAL(PCINT1_vect) {
PCint(1);
}
SIGNAL(PCINT2_vect) {
PCint(2);
}
#endif
88 changes: 47 additions & 41 deletions src/pcint.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,61 +17,67 @@ Nov.2014 large changes
**/
#ifndef ARDUINO_PCINT_MANAGER
#define ARDUINO_PCINT_MANAGER

#if ARDUINO < 100
#include <WProgram.h>
#include <WProgram.h>
#else
#include <Arduino.h>
#include <Arduino.h>
#endif
#include "pins_arduino.h"

typedef void (*voidFuncPtr)(void);

#ifdef ARDUINO_SAM_DUE
//no payload support on arduino due
#define HANDLER_TYPE voidFuncPtr
#else
// PCINT reverse map
// because some avr's (like 2560) have a messed map we got to have this detailed pin reverse map
// still this makes the PCINT automatization very slow, risking interrupt collision
#if defined(digital_pin_to_pcint)
#define digitalPinFromPCINTSlot(slot,bit) pgm_read_byte(digital_pin_to_pcint+(((slot)<<3)+(bit)))
#define pcintPinMapBank(slot) ((uint8_t*)((uint8_t*)digital_pin_to_pcint+((slot)<<3)))
#else
#warning using maps!
#if ( defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega16u4__) )
//UNO
//const uint8_t PROGMEM pcintPinMap[3][8]={{8,9,10,11,12,13,-1,-1},{A0,A1,A2,A3,A4,A5,-1,-1},{0,1,2,3,4,5,6,7}};
const uint8_t pcintPinMap[3][8] PROGMEM={{8,9,10,11,12,13,-1,-1},{14,15,16,17,18,19,20,21},{0,1,2,3,4,5,6,7}};
#elif ( defined(__AVR_ATmega2560__) )
const uint8_t pcintPinMap[3][8] PROGMEM={{53,52,51,50,10,11,12,13},{0,15,14,-1,-1,-1,-1,-1},{A8,A9,A10,A11,A12,A13,A14,A15}};
#elif ( defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega644__))
#error "uC PCINT REVERSE MAP IS NOT DEFINED, ATmega1284P variant unknown"
#if defined(digital_pin_to_pcint)
#define digitalPinFromPCINTSlot(slot,bit) pgm_read_byte(digital_pin_to_pcint+(((slot)<<3)+(bit)))
#define pcintPinMapBank(slot) ((uint8_t*)((uint8_t*)digital_pin_to_pcint+((slot)<<3)))
#else
#warning "uC PCINT REVERSE MAP IS NOT DEFINED"
#warning using maps!
#if ( defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega16u4__) )
//UNO
const uint8_t pcintPinMap[3][8] PROGMEM={{8,9,10,11,12,13,-1,-1},{14,15,16,17,18,19,20,21},{0,1,2,3,4,5,6,7}};
#elif ( defined(__AVR_ATmega2560__) )
const uint8_t pcintPinMap[3][8] PROGMEM={{53,52,51,50,10,11,12,13},{0,15,14,-1,-1,-1,-1,-1},{A8,A9,A10,A11,A12,A13,A14,A15}};
#elif ( defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega644__))
#error "uC PCINT REVERSE MAP IS NOT DEFINED, ATmega1284P variant unknown"
//run the mkPCIntMap example to obtain a map for your board!
#else
#warning "uC PCINT REVERSE MAP IS NOT DEFINED"
//run the mkPCIntMap example to obtain a map for your board!
#endif
#define digitalPinFromPCINTSlot(slot,bit) pgm_read_byte(pcintPinMap+(((slot)<<3)+(bit)))
#define pcintPinMapBank(slot) ((uint8_t*)((uint8_t*)pcintPinMap+((slot)<<3)))
#endif
#define digitalPinFromPCINTSlot(slot,bit) pgm_read_byte(pcintPinMap+(((slot)<<3)+(bit)))
#define pcintPinMapBank(slot) ((uint8_t*)((uint8_t*)pcintPinMap+((slot)<<3)))
#endif
#define digitalPinFromPCINTBank(bank,bit) pgm_read_byte((uint8_t*)bank+bit)

//this handler can be used instead of any void(*)() and optionally it can have an associated void *
//and use it to call void(*)(void* payload)
struct mixHandler {
union {
void (*voidFunc)(void);
void (*payloadFunc)(void*);
} handler;
void *payload;
inline mixHandler():payload(NULL) {handler.voidFunc=NULL;}
inline mixHandler(void (*f)(void)):payload(NULL) {handler.voidFunc=f;}
inline mixHandler(void (*f)(void*),void *payload):payload(payload) {handler.payloadFunc=f;}
inline void operator()() {payload?handler.payloadFunc(payload):handler.voidFunc();}
inline bool operator==(void*ptr) {return handler.voidFunc==ptr;}
inline bool operator!=(void*ptr) {return handler.voidFunc!=ptr;}
};
#define digitalPinFromPCINTBank(bank,bit) pgm_read_byte((uint8_t*)bank+bit)
#define HANDLER_TYPE mixHandler

typedef void (*voidFuncPtr)(void);
//this handler can be used instead of any void(*)() and optionally it can have an associated void *
//and use it to call void(*)(void* payload)
struct mixHandler {
union {
void (*voidFunc)(void);
void (*payloadFunc)(void*);
} handler;
void *payload;
inline mixHandler():payload(NULL) {handler.voidFunc=NULL;}
inline mixHandler(void (*f)(void)):payload(NULL) {handler.voidFunc=f;}
inline mixHandler(void (*f)(void*),void *payload):payload(payload) {handler.payloadFunc=f;}
inline void operator()() {payload?handler.payloadFunc(payload):handler.voidFunc();}
inline bool operator==(void*ptr) {return handler.voidFunc==ptr;}
inline bool operator!=(void*ptr) {return handler.voidFunc!=ptr;}
};

#define HANDLER_TYPE mixHandler

/*
#endif
/*
* attach an interrupt to a specific pin using pin change interrupts.
*/
void PCattachInterrupt(uint8_t pin, class mixHandler userFunc, uint8_t mode);
void PCattachInterrupt(uint8_t pin, HANDLER_TYPE userFunc, uint8_t mode);

void PCdetachInterrupt(uint8_t pin);

Expand Down

0 comments on commit bbe2184

Please # to comment.