summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Arduino-SPI.cpp201
-rw-r--r--lib/Arduino-SPI.h324
-rw-r--r--lib/Arduino.h27
-rw-r--r--lib/arduino-stub.cpp285
-rw-r--r--lib/led.c4
-rw-r--r--lib/stdc++-minimal.cpp53
6 files changed, 887 insertions, 7 deletions
diff --git a/lib/Arduino-SPI.cpp b/lib/Arduino-SPI.cpp
new file mode 100644
index 0000000..0a7ac91
--- /dev/null
+++ b/lib/Arduino-SPI.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2010 by Cristian Maglie <c.maglie@arduino.cc>
+ * Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (Transaction API)
+ * Copyright (c) 2014 by Matthijs Kooijman <matthijs@stdin.nl> (SPISettings AVR)
+ * Copyright (c) 2014 by Andrew J. Kroll <xxxajk@gmail.com> (atomicity fixes)
+ * SPI Master library for arduino.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either the GNU General Public License version 2
+ * or the GNU Lesser General Public License version 2.1, both as
+ * published by the Free Software Foundation.
+ */
+
+#include "Arduino-SPI.h"
+
+SPIClass SPI;
+
+uint8_t SPIClass::initialized = 0;
+uint8_t SPIClass::interruptMode = 0;
+uint8_t SPIClass::interruptMask = 0;
+uint8_t SPIClass::interruptSave = 0;
+#ifdef SPI_TRANSACTION_MISMATCH_LED
+uint8_t SPIClass::inTransactionFlag = 0;
+#endif
+
+void SPIClass::begin()
+{
+ uint8_t sreg = SREG;
+ noInterrupts(); // Protect from a scheduler and prevent transactionBegin
+ if (!initialized) {
+ // Set SS to high so a connected chip will be "deselected" by default
+ uint8_t port = digitalPinToPort(SS);
+ uint8_t bit = digitalPinToBitMask(SS);
+ volatile uint8_t *reg = portModeRegister(port);
+
+ // if the SS pin is not already configured as an output
+ // then set it high (to enable the internal pull-up resistor)
+ if(!(*reg & bit)){
+ digitalWrite(SS, HIGH);
+ }
+
+ // When the SS pin is set as OUTPUT, it can be used as
+ // a general purpose output port (it doesn't influence
+ // SPI operations).
+ pinMode(SS, OUTPUT);
+
+ // Warning: if the SS pin ever becomes a LOW INPUT then SPI
+ // automatically switches to Slave, so the data direction of
+ // the SS pin MUST be kept as OUTPUT.
+ SPCR |= _BV(MSTR);
+ SPCR |= _BV(SPE);
+
+ // Set direction register for SCK and MOSI pin.
+ // MISO pin automatically overrides to INPUT.
+ // By doing this AFTER enabling SPI, we avoid accidentally
+ // clocking in a single bit since the lines go directly
+ // from "input" to SPI control.
+ // http://code.google.com/p/arduino/issues/detail?id=888
+ pinMode(SCK, OUTPUT);
+ pinMode(MOSI, OUTPUT);
+ }
+ initialized++; // reference count
+ SREG = sreg;
+}
+
+void SPIClass::end() {
+ uint8_t sreg = SREG;
+ noInterrupts(); // Protect from a scheduler and prevent transactionBegin
+ // Decrease the reference counter
+ if (initialized)
+ initialized--;
+ // If there are no more references disable SPI
+ if (!initialized) {
+ SPCR &= ~_BV(SPE);
+ interruptMode = 0;
+ #ifdef SPI_TRANSACTION_MISMATCH_LED
+ inTransactionFlag = 0;
+ #endif
+ }
+ SREG = sreg;
+}
+
+// mapping of interrupt numbers to bits within SPI_AVR_EIMSK
+#if defined(__AVR_ATmega32U4__)
+ #define SPI_INT0_MASK (1<<INT0)
+ #define SPI_INT1_MASK (1<<INT1)
+ #define SPI_INT2_MASK (1<<INT2)
+ #define SPI_INT3_MASK (1<<INT3)
+ #define SPI_INT4_MASK (1<<INT6)
+#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
+ #define SPI_INT0_MASK (1<<INT0)
+ #define SPI_INT1_MASK (1<<INT1)
+ #define SPI_INT2_MASK (1<<INT2)
+ #define SPI_INT3_MASK (1<<INT3)
+ #define SPI_INT4_MASK (1<<INT4)
+ #define SPI_INT5_MASK (1<<INT5)
+ #define SPI_INT6_MASK (1<<INT6)
+ #define SPI_INT7_MASK (1<<INT7)
+#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
+ #define SPI_INT0_MASK (1<<INT4)
+ #define SPI_INT1_MASK (1<<INT5)
+ #define SPI_INT2_MASK (1<<INT0)
+ #define SPI_INT3_MASK (1<<INT1)
+ #define SPI_INT4_MASK (1<<INT2)
+ #define SPI_INT5_MASK (1<<INT3)
+ #define SPI_INT6_MASK (1<<INT6)
+ #define SPI_INT7_MASK (1<<INT7)
+#else
+ #ifdef INT0
+ #define SPI_INT0_MASK (1<<INT0)
+ #endif
+ #ifdef INT1
+ #define SPI_INT1_MASK (1<<INT1)
+ #endif
+ #ifdef INT2
+ #define SPI_INT2_MASK (1<<INT2)
+ #endif
+#endif
+
+void SPIClass::usingInterrupt(uint8_t interruptNumber)
+{
+ uint8_t mask = 0;
+ uint8_t sreg = SREG;
+ noInterrupts(); // Protect from a scheduler and prevent transactionBegin
+ switch (interruptNumber) {
+ #ifdef SPI_INT0_MASK
+ case 0: mask = SPI_INT0_MASK; break;
+ #endif
+ #ifdef SPI_INT1_MASK
+ case 1: mask = SPI_INT1_MASK; break;
+ #endif
+ #ifdef SPI_INT2_MASK
+ case 2: mask = SPI_INT2_MASK; break;
+ #endif
+ #ifdef SPI_INT3_MASK
+ case 3: mask = SPI_INT3_MASK; break;
+ #endif
+ #ifdef SPI_INT4_MASK
+ case 4: mask = SPI_INT4_MASK; break;
+ #endif
+ #ifdef SPI_INT5_MASK
+ case 5: mask = SPI_INT5_MASK; break;
+ #endif
+ #ifdef SPI_INT6_MASK
+ case 6: mask = SPI_INT6_MASK; break;
+ #endif
+ #ifdef SPI_INT7_MASK
+ case 7: mask = SPI_INT7_MASK; break;
+ #endif
+ default:
+ interruptMode = 2;
+ break;
+ }
+ interruptMask |= mask;
+ if (!interruptMode)
+ interruptMode = 1;
+ SREG = sreg;
+}
+
+void SPIClass::notUsingInterrupt(uint8_t interruptNumber)
+{
+ // Once in mode 2 we can't go back to 0 without a proper reference count
+ if (interruptMode == 2)
+ return;
+ uint8_t mask = 0;
+ uint8_t sreg = SREG;
+ noInterrupts(); // Protect from a scheduler and prevent transactionBegin
+ switch (interruptNumber) {
+ #ifdef SPI_INT0_MASK
+ case 0: mask = SPI_INT0_MASK; break;
+ #endif
+ #ifdef SPI_INT1_MASK
+ case 1: mask = SPI_INT1_MASK; break;
+ #endif
+ #ifdef SPI_INT2_MASK
+ case 2: mask = SPI_INT2_MASK; break;
+ #endif
+ #ifdef SPI_INT3_MASK
+ case 3: mask = SPI_INT3_MASK; break;
+ #endif
+ #ifdef SPI_INT4_MASK
+ case 4: mask = SPI_INT4_MASK; break;
+ #endif
+ #ifdef SPI_INT5_MASK
+ case 5: mask = SPI_INT5_MASK; break;
+ #endif
+ #ifdef SPI_INT6_MASK
+ case 6: mask = SPI_INT6_MASK; break;
+ #endif
+ #ifdef SPI_INT7_MASK
+ case 7: mask = SPI_INT7_MASK; break;
+ #endif
+ default:
+ break;
+ // this case can't be reached
+ }
+ interruptMask &= ~mask;
+ if (!interruptMask)
+ interruptMode = 0;
+ SREG = sreg;
+}
diff --git a/lib/Arduino-SPI.h b/lib/Arduino-SPI.h
new file mode 100644
index 0000000..5206a09
--- /dev/null
+++ b/lib/Arduino-SPI.h
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2010 by Cristian Maglie <c.maglie@arduino.cc>
+ * Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (Transaction API)
+ * Copyright (c) 2014 by Matthijs Kooijman <matthijs@stdin.nl> (SPISettings AVR)
+ * Copyright (c) 2014 by Andrew J. Kroll <xxxajk@gmail.com> (atomicity fixes)
+ * SPI Master library for arduino.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either the GNU General Public License version 2
+ * or the GNU Lesser General Public License version 2.1, both as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _SPI_H_INCLUDED
+#define _SPI_H_INCLUDED
+
+#include <Arduino.h>
+
+// SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(),
+// usingInterrupt(), and SPISetting(clock, bitOrder, dataMode)
+#define SPI_HAS_TRANSACTION 1
+
+// SPI_HAS_NOTUSINGINTERRUPT means that SPI has notUsingInterrupt() method
+#define SPI_HAS_NOTUSINGINTERRUPT 1
+
+// SPI_ATOMIC_VERSION means that SPI has atomicity fixes and what version.
+// This way when there is a bug fix you can check this define to alert users
+// of your code if it uses better version of this library.
+// This also implies everything that SPI_HAS_TRANSACTION as documented above is
+// available too.
+#define SPI_ATOMIC_VERSION 1
+
+// Uncomment this line to add detection of mismatched begin/end transactions.
+// A mismatch occurs if other libraries fail to use SPI.endTransaction() for
+// each SPI.beginTransaction(). Connect an LED to this pin. The LED will turn
+// on if any mismatch is ever detected.
+//#define SPI_TRANSACTION_MISMATCH_LED 5
+
+#ifndef LSBFIRST
+#define LSBFIRST 0
+#endif
+#ifndef MSBFIRST
+#define MSBFIRST 1
+#endif
+
+#define SPI_CLOCK_DIV4 0x00
+#define SPI_CLOCK_DIV16 0x01
+#define SPI_CLOCK_DIV64 0x02
+#define SPI_CLOCK_DIV128 0x03
+#define SPI_CLOCK_DIV2 0x04
+#define SPI_CLOCK_DIV8 0x05
+#define SPI_CLOCK_DIV32 0x06
+
+#define SPI_MODE0 0x00
+#define SPI_MODE1 0x04
+#define SPI_MODE2 0x08
+#define SPI_MODE3 0x0C
+
+#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR
+#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
+#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
+
+// define SPI_AVR_EIMSK for AVR boards with external interrupt pins
+#if defined(EIMSK)
+ #define SPI_AVR_EIMSK EIMSK
+#elif defined(GICR)
+ #define SPI_AVR_EIMSK GICR
+#elif defined(GIMSK)
+ #define SPI_AVR_EIMSK GIMSK
+#endif
+
+class SPISettings {
+public:
+ SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
+ if (__builtin_constant_p(clock)) {
+ init_AlwaysInline(clock, bitOrder, dataMode);
+ } else {
+ init_MightInline(clock, bitOrder, dataMode);
+ }
+ }
+ SPISettings() {
+ init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0);
+ }
+private:
+ void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
+ init_AlwaysInline(clock, bitOrder, dataMode);
+ }
+ void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
+ __attribute__((__always_inline__)) {
+ // Clock settings are defined as follows. Note that this shows SPI2X
+ // inverted, so the bits form increasing numbers. Also note that
+ // fosc/64 appears twice
+ // SPR1 SPR0 ~SPI2X Freq
+ // 0 0 0 fosc/2
+ // 0 0 1 fosc/4
+ // 0 1 0 fosc/8
+ // 0 1 1 fosc/16
+ // 1 0 0 fosc/32
+ // 1 0 1 fosc/64
+ // 1 1 0 fosc/64
+ // 1 1 1 fosc/128
+
+ // We find the fastest clock that is less than or equal to the
+ // given clock rate. The clock divider that results in clock_setting
+ // is 2 ^^ (clock_div + 1). If nothing is slow enough, we'll use the
+ // slowest (128 == 2 ^^ 7, so clock_div = 6).
+ uint8_t clockDiv;
+
+ // When the clock is known at compiletime, use this if-then-else
+ // cascade, which the compiler knows how to completely optimize
+ // away. When clock is not known, use a loop instead, which generates
+ // shorter code.
+ if (__builtin_constant_p(clock)) {
+ if (clock >= F_CPU / 2) {
+ clockDiv = 0;
+ } else if (clock >= F_CPU / 4) {
+ clockDiv = 1;
+ } else if (clock >= F_CPU / 8) {
+ clockDiv = 2;
+ } else if (clock >= F_CPU / 16) {
+ clockDiv = 3;
+ } else if (clock >= F_CPU / 32) {
+ clockDiv = 4;
+ } else if (clock >= F_CPU / 64) {
+ clockDiv = 5;
+ } else {
+ clockDiv = 6;
+ }
+ } else {
+ uint32_t clockSetting = F_CPU / 2;
+ clockDiv = 0;
+ while (clockDiv < 6 && clock < clockSetting) {
+ clockSetting /= 2;
+ clockDiv++;
+ }
+ }
+
+ // Compensate for the duplicate fosc/64
+ if (clockDiv == 6)
+ clockDiv = 7;
+
+ // Invert the SPI2X bit
+ clockDiv ^= 0x1;
+
+ // Pack into the SPISettings class
+ spcr = _BV(SPE) | _BV(MSTR) | ((bitOrder == LSBFIRST) ? _BV(DORD) : 0) |
+ (dataMode & SPI_MODE_MASK) | ((clockDiv >> 1) & SPI_CLOCK_MASK);
+ spsr = clockDiv & SPI_2XCLOCK_MASK;
+ }
+ uint8_t spcr;
+ uint8_t spsr;
+ friend class SPIClass;
+};
+
+
+class SPIClass {
+public:
+ // Initialize the SPI library
+ static void begin();
+
+ // If SPI is used from within an interrupt, this function registers
+ // that interrupt with the SPI library, so beginTransaction() can
+ // prevent conflicts. The input interruptNumber is the number used
+ // with attachInterrupt. If SPI is used from a different interrupt
+ // (eg, a timer), interruptNumber should be 255.
+ static void usingInterrupt(uint8_t interruptNumber);
+ // And this does the opposite.
+ static void notUsingInterrupt(uint8_t interruptNumber);
+ // Note: the usingInterrupt and notUsingInterrupt functions should
+ // not to be called from ISR context or inside a transaction.
+ // For details see:
+ // https://github.com/arduino/Arduino/pull/2381
+ // https://github.com/arduino/Arduino/pull/2449
+
+ // Before using SPI.transfer() or asserting chip select pins,
+ // this function is used to gain exclusive access to the SPI bus
+ // and configure the correct settings.
+ inline static void beginTransaction(SPISettings settings) {
+ if (interruptMode > 0) {
+ uint8_t sreg = SREG;
+ noInterrupts();
+
+ #ifdef SPI_AVR_EIMSK
+ if (interruptMode == 1) {
+ interruptSave = SPI_AVR_EIMSK;
+ SPI_AVR_EIMSK &= ~interruptMask;
+ SREG = sreg;
+ } else
+ #endif
+ {
+ interruptSave = sreg;
+ }
+ }
+
+ #ifdef SPI_TRANSACTION_MISMATCH_LED
+ if (inTransactionFlag) {
+ pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
+ digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
+ }
+ inTransactionFlag = 1;
+ #endif
+
+ SPCR = settings.spcr;
+ SPSR = settings.spsr;
+ }
+
+ // Write to the SPI bus (MOSI pin) and also receive (MISO pin)
+ inline static uint8_t transfer(uint8_t data) {
+ SPDR = data;
+ /*
+ * The following NOP introduces a small delay that can prevent the wait
+ * loop form iterating when running at the maximum speed. This gives
+ * about 10% more speed, even if it seems counter-intuitive. At lower
+ * speeds it is unnoticed.
+ */
+ asm volatile("nop");
+ while (!(SPSR & _BV(SPIF))) ; // wait
+ return SPDR;
+ }
+ inline static uint16_t transfer16(uint16_t data) {
+ union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } in, out;
+ in.val = data;
+ if (!(SPCR & _BV(DORD))) {
+ SPDR = in.msb;
+ asm volatile("nop"); // See transfer(uint8_t) function
+ while (!(SPSR & _BV(SPIF))) ;
+ out.msb = SPDR;
+ SPDR = in.lsb;
+ asm volatile("nop");
+ while (!(SPSR & _BV(SPIF))) ;
+ out.lsb = SPDR;
+ } else {
+ SPDR = in.lsb;
+ asm volatile("nop");
+ while (!(SPSR & _BV(SPIF))) ;
+ out.lsb = SPDR;
+ SPDR = in.msb;
+ asm volatile("nop");
+ while (!(SPSR & _BV(SPIF))) ;
+ out.msb = SPDR;
+ }
+ return out.val;
+ }
+ inline static void transfer(void *buf, size_t count) {
+ if (count == 0) return;
+ uint8_t *p = (uint8_t *)buf;
+ SPDR = *p;
+ while (--count > 0) {
+ uint8_t out = *(p + 1);
+ while (!(SPSR & _BV(SPIF))) ;
+ uint8_t in = SPDR;
+ SPDR = out;
+ *p++ = in;
+ }
+ while (!(SPSR & _BV(SPIF))) ;
+ *p = SPDR;
+ }
+ // After performing a group of transfers and releasing the chip select
+ // signal, this function allows others to access the SPI bus
+ inline static void endTransaction(void) {
+ #ifdef SPI_TRANSACTION_MISMATCH_LED
+ if (!inTransactionFlag) {
+ pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
+ digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
+ }
+ inTransactionFlag = 0;
+ #endif
+
+ if (interruptMode > 0) {
+ #ifdef SPI_AVR_EIMSK
+ uint8_t sreg = SREG;
+ #endif
+ noInterrupts();
+ #ifdef SPI_AVR_EIMSK
+ if (interruptMode == 1) {
+ SPI_AVR_EIMSK = interruptSave;
+ SREG = sreg;
+ } else
+ #endif
+ {
+ SREG = interruptSave;
+ }
+ }
+ }
+
+ // Disable the SPI bus
+ static void end();
+
+ // This function is deprecated. New applications should use
+ // beginTransaction() to configure SPI settings.
+ inline static void setBitOrder(uint8_t bitOrder) {
+ if (bitOrder == LSBFIRST) SPCR |= _BV(DORD);
+ else SPCR &= ~(_BV(DORD));
+ }
+ // This function is deprecated. New applications should use
+ // beginTransaction() to configure SPI settings.
+ inline static void setDataMode(uint8_t dataMode) {
+ SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode;
+ }
+ // This function is deprecated. New applications should use
+ // beginTransaction() to configure SPI settings.
+ inline static void setClockDivider(uint8_t clockDiv) {
+ SPCR = (SPCR & ~SPI_CLOCK_MASK) | (clockDiv & SPI_CLOCK_MASK);
+ SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((clockDiv >> 2) & SPI_2XCLOCK_MASK);
+ }
+ // These undocumented functions should not be used. SPI.transfer()
+ // polls the hardware flag which is automatically cleared as the
+ // AVR responds to SPI's interrupt
+ inline static void attachInterrupt() { SPCR |= _BV(SPIE); }
+ inline static void detachInterrupt() { SPCR &= ~_BV(SPIE); }
+
+private:
+ static uint8_t initialized;
+ static uint8_t interruptMode; // 0=none, 1=mask, 2=global
+ static uint8_t interruptMask; // which interrupts to mask
+ static uint8_t interruptSave; // temp storage, to restore state
+ #ifdef SPI_TRANSACTION_MISMATCH_LED
+ static uint8_t inTransactionFlag;
+ #endif
+};
+
+extern SPIClass SPI;
+
+#endif
diff --git a/lib/Arduino.h b/lib/Arduino.h
index 3698392..ac7031d 100644
--- a/lib/Arduino.h
+++ b/lib/Arduino.h
@@ -143,8 +143,8 @@ void delayMicroseconds(unsigned int us);
// void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
// uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder);
-// void attachInterrupt(uint8_t, void (*)(void), int mode);
-// void detachInterrupt(uint8_t);
+void attachInterrupt(uint8_t, void (*)(void), int mode);
+void detachInterrupt(uint8_t);
// Get the bit location within the hardware port of the given virtual pin.
// This comes from the pins_*.c file for the active board configuration.
@@ -215,6 +215,29 @@ extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
#define TIMER5B 17
#define TIMER5C 18
+
+#define EXTERNAL_INT_0 0
+#define EXTERNAL_INT_1 1
+#define EXTERNAL_INT_2 2
+#define EXTERNAL_INT_3 3
+#define EXTERNAL_INT_4 4
+#define EXTERNAL_INT_5 5
+#define EXTERNAL_INT_6 6
+#define EXTERNAL_INT_7 7
+
+#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega128RFA1__) || defined(__AVR_ATmega256RFR2__) || \
+ defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega8U2__)
+#define EXTERNAL_NUM_INTERRUPTS 8
+#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__)
+#define EXTERNAL_NUM_INTERRUPTS 3
+#elif defined(__AVR_ATmega32U4__)
+#define EXTERNAL_NUM_INTERRUPTS 5
+#else
+#define EXTERNAL_NUM_INTERRUPTS 2
+#endif
+
+typedef void (*voidFuncPtr)(void);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/lib/arduino-stub.cpp b/lib/arduino-stub.cpp
index d848e8d..38bc168 100644
--- a/lib/arduino-stub.cpp
+++ b/lib/arduino-stub.cpp
@@ -329,7 +329,7 @@ void init()
* real cooperative scheduler.
*/
static void __empty() {
- // Empty
+ // Empty
}
void yield(void) __attribute__ ((weak, alias("__empty")));
@@ -762,6 +762,287 @@ void analogWrite(uint8_t pin, int val)
}
// ******************
+// this is from Arduino's WInterrupts.c
+
+static void nothing(void) {
+}
+
+static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS] = {
+#if EXTERNAL_NUM_INTERRUPTS > 8
+ #warning There are more than 8 external interrupts. Some callbacks may not be initialized.
+ nothing,
+#endif
+#if EXTERNAL_NUM_INTERRUPTS > 7
+ nothing,
+#endif
+#if EXTERNAL_NUM_INTERRUPTS > 6
+ nothing,
+#endif
+#if EXTERNAL_NUM_INTERRUPTS > 5
+ nothing,
+#endif
+#if EXTERNAL_NUM_INTERRUPTS > 4
+ nothing,
+#endif
+#if EXTERNAL_NUM_INTERRUPTS > 3
+ nothing,
+#endif
+#if EXTERNAL_NUM_INTERRUPTS > 2
+ nothing,
+#endif
+#if EXTERNAL_NUM_INTERRUPTS > 1
+ nothing,
+#endif
+#if EXTERNAL_NUM_INTERRUPTS > 0
+ nothing,
+#endif
+};
+// volatile static voidFuncPtr twiIntFunc;
+
+void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) {
+ if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
+ intFunc[interruptNum] = userFunc;
+
+ // Configure the interrupt mode (trigger on low input, any change, rising
+ // edge, or falling edge). The mode constants were chosen to correspond
+ // to the configuration bits in the hardware register, so we simply shift
+ // the mode into place.
+
+ // Enable the interrupt.
+
+ switch (interruptNum) {
+#if defined(__AVR_ATmega32U4__)
+ // I hate doing this, but the register assignment differs between the 1280/2560
+ // and the 32U4. Since avrlib defines registers PCMSK1 and PCMSK2 that aren't
+ // even present on the 32U4 this is the only way to distinguish between them.
+ case 0:
+ EICRA = (EICRA & ~((1<<ISC00) | (1<<ISC01))) | (mode << ISC00);
+ EIMSK |= (1<<INT0);
+ break;
+ case 1:
+ EICRA = (EICRA & ~((1<<ISC10) | (1<<ISC11))) | (mode << ISC10);
+ EIMSK |= (1<<INT1);
+ break;
+ case 2:
+ EICRA = (EICRA & ~((1<<ISC20) | (1<<ISC21))) | (mode << ISC20);
+ EIMSK |= (1<<INT2);
+ break;
+ case 3:
+ EICRA = (EICRA & ~((1<<ISC30) | (1<<ISC31))) | (mode << ISC30);
+ EIMSK |= (1<<INT3);
+ break;
+ case 4:
+ EICRB = (EICRB & ~((1<<ISC60) | (1<<ISC61))) | (mode << ISC60);
+ EIMSK |= (1<<INT6);
+ break;
+#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
+ case 2:
+ EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
+ EIMSK |= (1 << INT0);
+ break;
+ case 3:
+ EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
+ EIMSK |= (1 << INT1);
+ break;
+ case 4:
+ EICRA = (EICRA & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
+ EIMSK |= (1 << INT2);
+ break;
+ case 5:
+ EICRA = (EICRA & ~((1 << ISC30) | (1 << ISC31))) | (mode << ISC30);
+ EIMSK |= (1 << INT3);
+ break;
+ case 0:
+ EICRB = (EICRB & ~((1 << ISC40) | (1 << ISC41))) | (mode << ISC40);
+ EIMSK |= (1 << INT4);
+ break;
+ case 1:
+ EICRB = (EICRB & ~((1 << ISC50) | (1 << ISC51))) | (mode << ISC50);
+ EIMSK |= (1 << INT5);
+ break;
+ case 6:
+ EICRB = (EICRB & ~((1 << ISC60) | (1 << ISC61))) | (mode << ISC60);
+ EIMSK |= (1 << INT6);
+ break;
+ case 7:
+ EICRB = (EICRB & ~((1 << ISC70) | (1 << ISC71))) | (mode << ISC70);
+ EIMSK |= (1 << INT7);
+ break;
+#else
+ case 0:
+ #if defined(EICRA) && defined(ISC00) && defined(EIMSK)
+ EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
+ EIMSK |= (1 << INT0);
+ #elif defined(MCUCR) && defined(ISC00) && defined(GICR)
+ MCUCR = (MCUCR & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
+ GICR |= (1 << INT0);
+ #elif defined(MCUCR) && defined(ISC00) && defined(GIMSK)
+ MCUCR = (MCUCR & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
+ GIMSK |= (1 << INT0);
+ #else
+ #error attachInterrupt not finished for this CPU (case 0)
+ #endif
+ break;
+
+ case 1:
+ #if defined(EICRA) && defined(ISC10) && defined(ISC11) && defined(EIMSK)
+ EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
+ EIMSK |= (1 << INT1);
+ #elif defined(MCUCR) && defined(ISC10) && defined(ISC11) && defined(GICR)
+ MCUCR = (MCUCR & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
+ GICR |= (1 << INT1);
+ #elif defined(MCUCR) && defined(ISC10) && defined(GIMSK) && defined(GIMSK)
+ MCUCR = (MCUCR & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
+ GIMSK |= (1 << INT1);
+ #else
+ #warning attachInterrupt may need some more work for this cpu (case 1)
+ #endif
+ break;
+
+ case 2:
+ #if defined(EICRA) && defined(ISC20) && defined(ISC21) && defined(EIMSK)
+ EICRA = (EICRA & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
+ EIMSK |= (1 << INT2);
+ #elif defined(MCUCR) && defined(ISC20) && defined(ISC21) && defined(GICR)
+ MCUCR = (MCUCR & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
+ GICR |= (1 << INT2);
+ #elif defined(MCUCR) && defined(ISC20) && defined(GIMSK) && defined(GIMSK)
+ MCUCR = (MCUCR & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
+ GIMSK |= (1 << INT2);
+ #endif
+ break;
+#endif
+ }
+ }
+}
+
+void detachInterrupt(uint8_t interruptNum) {
+ if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
+ // Disable the interrupt. (We can't assume that interruptNum is equal
+ // to the number of the EIMSK bit to clear, as this isn't true on the
+ // ATmega8. There, INT0 is 6 and INT1 is 7.)
+ switch (interruptNum) {
+#if defined(__AVR_ATmega32U4__)
+ case 0:
+ EIMSK &= ~(1<<INT0);
+ break;
+ case 1:
+ EIMSK &= ~(1<<INT1);
+ break;
+ case 2:
+ EIMSK &= ~(1<<INT2);
+ break;
+ case 3:
+ EIMSK &= ~(1<<INT3);
+ break;
+ case 4:
+ EIMSK &= ~(1<<INT6);
+ break;
+#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
+ case 2:
+ EIMSK &= ~(1 << INT0);
+ break;
+ case 3:
+ EIMSK &= ~(1 << INT1);
+ break;
+ case 4:
+ EIMSK &= ~(1 << INT2);
+ break;
+ case 5:
+ EIMSK &= ~(1 << INT3);
+ break;
+ case 0:
+ EIMSK &= ~(1 << INT4);
+ break;
+ case 1:
+ EIMSK &= ~(1 << INT5);
+ break;
+ case 6:
+ EIMSK &= ~(1 << INT6);
+ break;
+ case 7:
+ EIMSK &= ~(1 << INT7);
+ break;
+#else
+ case 0:
+ #if defined(EIMSK) && defined(INT0)
+ EIMSK &= ~(1 << INT0);
+ #elif defined(GICR) && defined(ISC00)
+ GICR &= ~(1 << INT0); // atmega32
+ #elif defined(GIMSK) && defined(INT0)
+ GIMSK &= ~(1 << INT0);
+ #else
+ #error detachInterrupt not finished for this cpu
+ #endif
+ break;
+
+ case 1:
+ #if defined(EIMSK) && defined(INT1)
+ EIMSK &= ~(1 << INT1);
+ #elif defined(GICR) && defined(INT1)
+ GICR &= ~(1 << INT1); // atmega32
+ #elif defined(GIMSK) && defined(INT1)
+ GIMSK &= ~(1 << INT1);
+ #else
+ #warning detachInterrupt may need some more work for this cpu (case 1)
+ #endif
+ break;
+
+ case 2:
+ #if defined(EIMSK) && defined(INT2)
+ EIMSK &= ~(1 << INT2);
+ #elif defined(GICR) && defined(INT2)
+ GICR &= ~(1 << INT2); // atmega32
+ #elif defined(GIMSK) && defined(INT2)
+ GIMSK &= ~(1 << INT2);
+ #elif defined(INT2)
+ #warning detachInterrupt may need some more work for this cpu (case 2)
+ #endif
+ break;
+#endif
+ }
+
+ intFunc[interruptNum] = nothing;
+ }
+}
+
+#define IMPLEMENT_ISR(vect, interrupt) \
+ ISR(vect) { \
+ intFunc[interrupt](); \
+ }
+
+#if defined(__AVR_ATmega32U4__)
+
+IMPLEMENT_ISR(INT0_vect, EXTERNAL_INT_0)
+IMPLEMENT_ISR(INT1_vect, EXTERNAL_INT_1)
+IMPLEMENT_ISR(INT2_vect, EXTERNAL_INT_2)
+IMPLEMENT_ISR(INT3_vect, EXTERNAL_INT_3)
+IMPLEMENT_ISR(INT6_vect, EXTERNAL_INT_4)
+
+#elif defined(EICRA) && defined(EICRB)
+
+IMPLEMENT_ISR(INT0_vect, EXTERNAL_INT_2)
+IMPLEMENT_ISR(INT1_vect, EXTERNAL_INT_3)
+IMPLEMENT_ISR(INT2_vect, EXTERNAL_INT_4)
+IMPLEMENT_ISR(INT3_vect, EXTERNAL_INT_5)
+IMPLEMENT_ISR(INT4_vect, EXTERNAL_INT_0)
+IMPLEMENT_ISR(INT5_vect, EXTERNAL_INT_1)
+IMPLEMENT_ISR(INT6_vect, EXTERNAL_INT_6)
+IMPLEMENT_ISR(INT7_vect, EXTERNAL_INT_7)
+
+#else
+
+IMPLEMENT_ISR(INT0_vect, EXTERNAL_INT_0)
+IMPLEMENT_ISR(INT1_vect, EXTERNAL_INT_1)
+
+#if defined(EICRA) && defined(ISC20)
+IMPLEMENT_ISR(INT2_vect, EXTERNAL_INT_2)
+#endif
+
+#endif
+
+
+// ******************
// this is from Arduino's WMath.cpp
void randomSeed(unsigned long seed)
@@ -795,5 +1076,3 @@ long map(long x, long in_min, long in_max, long out_min, long out_max)
unsigned int makeWord(unsigned int w) { return w; }
unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; }
-
-// end WMath.cpp
diff --git a/lib/led.c b/lib/led.c
index 192eb68..3949623 100644
--- a/lib/led.c
+++ b/lib/led.c
@@ -29,7 +29,7 @@
#define NUM_LEDS 2
#elif defined(__BOARD_teensy1__) || defined(__BOARD_teensy1pp__) || defined(__BOARD_teensy2__) || defined(__BOARD_teensy2pp__) || \
defined(__BOARD_arduinoNano__) || defined(__BOARD_arduinoNG__) || defined(__BOARD_arduino2009v2__) || defined(__BOARD_arduino2009__) || \
- defined(__BOARD_arduino10000__) || defined(__BOARD_arduinoUno__) || defined(__BOARD_feather32u4__) || \
+ defined(__BOARD_arduino10000__) || defined(__BOARD_arduinoUno__) || defined(__BOARD_feather32u4__) || defined(__BOARD_feather32u4lora__) || \
defined(__BOARD_hhd70dongle__) || defined(__BOARD_rda1846dongle__) || defined(__BOARD_culV3__) || \
defined(__BOARD_slowpandongle1__) || defined(__BOARD_slowpandongle2__) || defined(__BOARD_teenstep__) || \
defined(__BOARD_rhmixxx__) || defined(__BOARD_digispark__) || defined(__BOARD_robotdynMega2560__)
@@ -62,7 +62,7 @@
#define LED2_PINNUM 6
#endif
-#if defined(__BOARD_feather32u4__)
+#if defined(__BOARD_feather32u4__) || defined(__BOARD_feather32u4lora__)
#define LED_PORT PORTC
#define LED_DDR DDRC
#define LED_PINNUM 7
diff --git a/lib/stdc++-minimal.cpp b/lib/stdc++-minimal.cpp
new file mode 100644
index 0000000..982719b
--- /dev/null
+++ b/lib/stdc++-minimal.cpp
@@ -0,0 +1,53 @@
+/*
+ * spreadspace avr utils
+ *
+ *
+ * Copyright (C) 2014-2018 Christian Pointner <equinox@spreadspace.org>
+ *
+ * This file is part of spreadspace avr utils.
+ *
+ * spreadspace avr utils is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * spreadspace avr utils 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with spreadspace avr utils. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "stdlib.h"
+#include "stdio.h"
+
+extern "C" void __cxa_pure_virtual(void) __attribute__ ((__noreturn__));
+extern "C" void __cxa_deleted_virtual(void) __attribute__ ((__noreturn__));
+
+void __cxa_pure_virtual(void) {
+ // this only works with serialio, it won't work with usbio
+ // because we would need to call usbio_task() ...
+ printf("PANIC: __cxa_pure_virtual() got called ...\r\n");
+ for(;;);
+}
+
+void __cxa_deleted_virtual(void) {
+ // this only works with serialio, it won't work with usbio
+ // because we would need to call usbio_task() ...
+ printf("PANIC: __cxa_deleted_virtual() got called ...\r\n");
+ for(;;);
+}
+
+void * operator new(size_t n)
+{
+ void * const p = malloc(n);
+ // handle p == 0
+ return p;
+}
+
+void operator delete(void * p) // or delete(void *, std::size_t)
+{
+ free(p);
+}