aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2019-10-24 07:32:22 +0200
committerMatthias P. Braendli <matthias.braendli@mpb.li>2019-10-24 07:32:22 +0200
commitf3a56d229e2c3d333d53b9e31d5ca49afc3a11fe (patch)
tree666a86d8beb9e61bcfc23db7b82dff90698a4671
parent34ae543f410b1a2ccfdefb3e5942b2e4e8a13b05 (diff)
downloadglutte-batteries-f3a56d229e2c3d333d53b9e31d5ca49afc3a11fe.tar.gz
glutte-batteries-f3a56d229e2c3d333d53b9e31d5ca49afc3a11fe.tar.bz2
glutte-batteries-f3a56d229e2c3d333d53b9e31d5ca49afc3a11fe.zip
Pull in some Arduino code so that libraries are easier to use
-rw-r--r--sw/Makefile41
-rw-r--r--sw/lib/Arduino.h226
-rw-r--r--sw/lib/LTC24XX_general.cpp32
-rw-r--r--sw/lib/LTC24XX_general.h6
-rw-r--r--sw/lib/SPI.cpp201
-rw-r--r--sw/lib/SPI.h324
-rw-r--r--sw/lib/pins_arduino.h254
-rw-r--r--sw/lib/wiring_analog.c294
-rw-r--r--sw/lib/wiring_digital.c179
-rw-r--r--sw/lib/wiring_private.h72
-rw-r--r--sw/main.cpp4
11 files changed, 1615 insertions, 18 deletions
diff --git a/sw/Makefile b/sw/Makefile
index 9f23db2..5f8af16 100644
--- a/sw/Makefile
+++ b/sw/Makefile
@@ -22,18 +22,31 @@ BUILD_DIR=build
# Port/application object files
APP_NAME = sw
+HEADERS = \
+ lib/Arduino.h \
+ lib/DallasTemperature.h \
+ lib/delay.h \
+ lib/LTC24XX_general.h \
+ lib/OneWire.h \
+ lib/pins_arduino.h \
+ lib/SPI.h \
+ lib/uart.h \
+ lib/util/OneWire_direct_gpio.h \
+ lib/util/OneWire_direct_regtype.h \
+ lib/wiring_private.h
+
# Application object files
APP_CXX_OBJECTS = main.o
APP_OBJECTS =
# Library object files to build and use
-LIB_OBJECTS = uart.o
-LIB_CXX_OBJECTS =
+LIB_OBJECTS = uart.o wiring_analog.o wiring_digital.o
+LIB_CXX_OBJECTS = OneWire.o DallasTemperature.o LTC24XX_general.o SPI.o
LIB_ASM_OBJECTS =
LIB_DIR = lib
# Collection of built objects
-ALL_OBJECTS = $(LIB_OBJECTS) $(LIB_ASM_OBJECTS) $(APP_OBJECTS) $(APP_CXX_OBJECTS)
+ALL_OBJECTS = $(LIB_OBJECTS) $(LIB_ASM_OBJECTS) $(LIB_CXX_OBJECTS) $(APP_OBJECTS) $(APP_CXX_OBJECTS)
BUILT_OBJECTS = $(patsubst %,$(BUILD_DIR)/%,$(ALL_OBJECTS))
# Target application filenames (.elf and .hex) for each application object
@@ -46,10 +59,10 @@ vpath %.elf ./$(BUILD_DIR)
vpath %.hex ./$(BUILD_DIR)
# GCC flags
-DEFINES=-DUART_RX0_BUFFER_SIZE=64 -DUART_TX0_BUFFER_SIZE=64
-FLAGS=-g -mmcu=$(PART) -Os -Wall -Werror -DF_CPU=$(F_CPU) $(DEFINES)
+DEFINES=-DUART_RX0_BUFFER_SIZE=64 -DUART_TX0_BUFFER_SIZE=64 -DARDUINO=180
+FLAGS=-g -mmcu=$(PART) -Os -Wall -Wextra -Werror -DF_CPU=$(F_CPU) $(DEFINES) -ffunction-sections -fdata-sections -MMD -flto -fno-fat-lto-objects
CFLAGS=$(FLAGS) -std=c99
-CXXFLAGS=$(FLAGS) -std=c++11
+CXXFLAGS=$(FLAGS) -std=c++11 -fno-exceptions -fno-threadsafe-statics
INCLUDES=-I. -I$(LIB_DIR)
@@ -71,30 +84,30 @@ $(APP_HEX): %.hex: %.elf
# Application ELF files
$(APP_ELF): %.elf: $(LIB_OBJECTS) $(LIB_CXX_OBJECTS) $(LIB_ASM_OBJECTS) $(APP_OBJECTS) $(APP_CXX_OBJECTS)
- $(CXX) $(CXXFLAGS) $(BUILT_OBJECTS) --output $(BUILD_DIR)/$@ -Wl,-Map,$(BUILD_DIR)/$(basename $@).map
+ $(CXX) $(CXXFLAGS) $(BUILT_OBJECTS) --output $(BUILD_DIR)/$@ -flto -fuse-linker-plugin -Wl,--gc-sections -Wl,-Map,$(BUILD_DIR)/$(basename $@).map
# Application objects builder
-$(APP_OBJECTS): %.o: %.c
+$(APP_OBJECTS): %.o: %.c $(HEADERS)
$(CC) -c $(CFLAGS) $(INCLUDES) $< -o $(BUILD_DIR)/$(notdir $@)
-$(APP_CXX_OBJECTS): %.o: %.cpp
+$(APP_CXX_OBJECTS): %.o: %.cpp $(HEADERS)
$(CXX) -c $(CXXFLAGS) $(INCLUDES) $< -o $(BUILD_DIR)/$(notdir $@)
# Application objects builder
-$(LIB_OBJECTS): %.o: $(LIB_DIR)/%.c
+$(LIB_OBJECTS): %.o: $(LIB_DIR)/%.c $(HEADERS)
$(CC) -c $(CFLAGS) $(INCLUDES) $< -o $(BUILD_DIR)/$(notdir $@)
-$(LIB_CXX_OBJECTS): %.o: $(LIB_DIR)/%.cpp
+$(LIB_CXX_OBJECTS): %.o: $(LIB_DIR)/%.cpp $(HEADERS)
$(CXX) -c $(CXXFLAGS) $(INCLUDES) $< -o $(BUILD_DIR)/$(notdir $@)
$(LIB_ASM_OBJECTS): %.o: $(LIB_DIR)/%.s
- $(CC) -c $(CFLAGS) -x assembler-with-cpp $(INCLUDES) $< -o $(BUILD_DIR)/$(notdir $@)
+ $(CC) -c $(CFLAGS) -x assembler-with-cpp -flto -MMD $(INCLUDES) $< -o $(BUILD_DIR)/$(notdir $@)
# .lst file builder
-%.lst: %.c
+%.lst: %.c $(HEADERS)
$(CC) $(CFLAGS) $(INCLUDES) -Wa,-al $< > $@
-%.lst: %.cpp
+%.lst: %.cpp $(HEADERS)
$(CXX) $(CXXFLAGS) $(INCLUDES) -Wa,-al $< > $@
# Clean
diff --git a/sw/lib/Arduino.h b/sw/lib/Arduino.h
new file mode 100644
index 0000000..7922e79
--- /dev/null
+++ b/sw/lib/Arduino.h
@@ -0,0 +1,226 @@
+/*
+ Arduino.h - Main include file for the Arduino SDK
+ Copyright (c) 2005-2013 Arduino Team. All right reserved.
+
+ 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef Arduino_h
+#define Arduino_h
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <math.h>
+
+#include <avr/pgmspace.h>
+#include <avr/io.h>
+#include <avr/interrupt.h>
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+void yield(void);
+
+#define HIGH 0x1
+#define LOW 0x0
+
+#define INPUT 0x0
+#define OUTPUT 0x1
+#define INPUT_PULLUP 0x2
+
+#define PI 3.1415926535897932384626433832795
+#define HALF_PI 1.5707963267948966192313216916398
+#define TWO_PI 6.283185307179586476925286766559
+#define DEG_TO_RAD 0.017453292519943295769236907684886
+#define RAD_TO_DEG 57.295779513082320876798154814105
+#define EULER 2.718281828459045235360287471352
+
+#define SERIAL 0x0
+#define DISPLAY 0x1
+
+#define LSBFIRST 0
+#define MSBFIRST 1
+
+#define CHANGE 1
+#define FALLING 2
+#define RISING 3
+
+#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
+ #define DEFAULT 0
+ #define EXTERNAL 1
+ #define INTERNAL1V1 2
+ #define INTERNAL INTERNAL1V1
+#elif defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
+ #define DEFAULT 0
+ #define EXTERNAL 4
+ #define INTERNAL1V1 8
+ #define INTERNAL INTERNAL1V1
+ #define INTERNAL2V56 9
+ #define INTERNAL2V56_EXTCAP 13
+#else
+#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__)
+#define INTERNAL1V1 2
+#define INTERNAL2V56 3
+#else
+#define INTERNAL 3
+#endif
+#define DEFAULT 1
+#define EXTERNAL 0
+#endif
+
+// undefine stdlib's abs if encountered
+#ifdef abs
+#undef abs
+#endif
+
+#define min(a,b) ((a)<(b)?(a):(b))
+#define max(a,b) ((a)>(b)?(a):(b))
+#define abs(x) ((x)>0?(x):-(x))
+#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
+#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
+#define radians(deg) ((deg)*DEG_TO_RAD)
+#define degrees(rad) ((rad)*RAD_TO_DEG)
+#define sq(x) ((x)*(x))
+
+#define interrupts() sei()
+#define noInterrupts() cli()
+
+#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
+#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
+#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )
+
+#define lowByte(w) ((uint8_t) ((w) & 0xff))
+#define highByte(w) ((uint8_t) ((w) >> 8))
+
+#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
+#define bitSet(value, bit) ((value) |= (1UL << (bit)))
+#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
+#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
+
+// avr-libc defines _NOP() since 1.6.2
+#ifndef _NOP
+#define _NOP() do { __asm__ volatile ("nop"); } while (0)
+#endif
+
+typedef unsigned int word;
+
+#define bit(b) (1UL << (b))
+
+typedef bool boolean;
+typedef uint8_t byte;
+
+void init(void);
+void initVariant(void);
+
+int atexit(void (*func)()) __attribute__((weak));
+
+void pinMode(uint8_t, uint8_t);
+void digitalWrite(uint8_t, uint8_t);
+int digitalRead(uint8_t);
+int analogRead(uint8_t);
+void analogReference(uint8_t mode);
+void analogWrite(uint8_t, int);
+
+unsigned long millis(void);
+unsigned long micros(void);
+void delay(unsigned long);
+void delayMicroseconds(unsigned int us);
+unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout);
+unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout);
+
+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);
+
+// 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.
+
+#define analogInPinToBit(P) (P)
+
+// On the ATmega1280, the addresses of some of the port registers are
+// greater than 255, so we can't store them in uint8_t's.
+extern const uint16_t PROGMEM port_to_mode_PGM[];
+extern const uint16_t PROGMEM port_to_input_PGM[];
+extern const uint16_t PROGMEM port_to_output_PGM[];
+
+extern const uint8_t PROGMEM digital_pin_to_port_PGM[];
+// extern const uint8_t PROGMEM digital_pin_to_bit_PGM[];
+extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[];
+extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
+
+// 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.
+//
+// These perform slightly better as macros compared to inline functions
+//
+#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )
+#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )
+#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) )
+#define analogInPinToBit(P) (P)
+#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) )
+#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) )
+#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) )
+
+#define NOT_A_PIN 0
+#define NOT_A_PORT 0
+
+#define NOT_AN_INTERRUPT -1
+
+#ifdef ARDUINO_MAIN
+#define PA 1
+#define PB 2
+#define PC 3
+#define PD 4
+#define PE 5
+#define PF 6
+#define PG 7
+#define PH 8
+#define PJ 10
+#define PK 11
+#define PL 12
+#endif
+
+#define NOT_ON_TIMER 0
+#define TIMER0A 1
+#define TIMER0B 2
+#define TIMER1A 3
+#define TIMER1B 4
+#define TIMER1C 5
+#define TIMER2 6
+#define TIMER2A 7
+#define TIMER2B 8
+
+#define TIMER3A 9
+#define TIMER3B 10
+#define TIMER3C 11
+#define TIMER4A 12
+#define TIMER4B 13
+#define TIMER4C 14
+#define TIMER4D 15
+#define TIMER5A 16
+#define TIMER5B 17
+#define TIMER5C 18
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#include "pins_arduino.h"
+
+#endif
diff --git a/sw/lib/LTC24XX_general.cpp b/sw/lib/LTC24XX_general.cpp
index 615edff..57c34e0 100644
--- a/sw/lib/LTC24XX_general.cpp
+++ b/sw/lib/LTC24XX_general.cpp
@@ -67,13 +67,34 @@ ongoing work.
#include <stdint.h>
#include <Arduino.h>
-#include "Linduino.h"
#include <SPI.h>
-#include "LT_SPI.h"
-#include <Wire.h>
-#include "LT_I2C.h"
#include "LTC24XX_general.h"
+typedef union LT_union_int32_4bytes_u
+{
+ uint32_t LT_uint32;
+ int32_t LT_int32;
+ uint8_t LT_byte[4];
+} LT_union_int32_4bytes;
+
+static void output_low(uint8_t pin) {
+ digitalWrite(pin, 0);
+}
+
+static void output_high(uint8_t pin) {
+ digitalWrite(pin, 1);
+}
+
+static int input(uint8_t pin) {
+ return digitalRead(pin);
+}
+
+// Ignore cs, because the SPI initialisation specifies the chip select pin */
+static void spi_transfer_block(uint8_t /*ignore cs*/, uint8_t command[4], uint8_t data[4], uint8_t len)
+{
+ SPI.transfer(command, 4);
+ SPI.transfer(data, len);
+}
int8_t LTC24XX_EOC_timeout(uint8_t cs, uint16_t miso_timeout)
// Checks for EOC with a specified timeout (ms)
@@ -257,6 +278,7 @@ void LTC24XX_SPI_2ch_ping_pong_24bit_data(uint8_t cs, uint8_t *adc_channel, int3
}
+#if 0
//I2C functions
//! Reads from LTC24XX ADC that accepts an 8 bit configuration and returns a 24 bit result.
@@ -367,6 +389,8 @@ int8_t LTC24XX_I2C_16bit_command_32bit_data(uint8_t i2c_address,uint8_t adc_comm
return(ack); // Success
}
+#endif
+
// Calculates the voltage corresponding to an adc code, given the reference voltage (in volts)
float LTC24XX_SE_code_to_voltage(int32_t adc_code, float vref)
{
diff --git a/sw/lib/LTC24XX_general.h b/sw/lib/LTC24XX_general.h
index 42fd65a..6215063 100644
--- a/sw/lib/LTC24XX_general.h
+++ b/sw/lib/LTC24XX_general.h
@@ -123,6 +123,8 @@ ongoing work.
#ifndef LTC24XX_general_H
#define LTC24XX_general_H
+#include <stdint.h>
+
//! Define the SPI CS pin
#ifndef LTC24XX_CS
#define LTC24XX_CS QUIKEVAL_CS
@@ -341,6 +343,8 @@ void LTC24XX_SPI_2ch_ping_pong_24bit_data(uint8_t cs, //!< Chip Select
int32_t *code //!< 4 byte conversion code read from LTC24XX
);
+#if 0
+
// Read functions for I2C interface ADCs with a 32 bit output word. These functions are used with both
// Single-ended and differential parts, as there is no interpretation of the data done in
// the function. Also note that these functions can be used for devices that have shorter output lengths,
@@ -410,6 +414,8 @@ int8_t LTC24XX_I2C_16bit_command_24bit_data(uint8_t i2c_address, //!< I2
uint16_t eoc_timeout //!< Timeout (in milliseconds)
);
+#endif
+
//! Calculates the voltage corresponding to an ADC code, given the reference voltage.
//! Applies to Single-Ended input parts (LTC2400-type input)
//! @return Returns voltage calculated from ADC code.
diff --git a/sw/lib/SPI.cpp b/sw/lib/SPI.cpp
new file mode 100644
index 0000000..af14e07
--- /dev/null
+++ b/sw/lib/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 "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/sw/lib/SPI.h b/sw/lib/SPI.h
new file mode 100644
index 0000000..5206a09
--- /dev/null
+++ b/sw/lib/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/sw/lib/pins_arduino.h b/sw/lib/pins_arduino.h
new file mode 100644
index 0000000..2ea0190
--- /dev/null
+++ b/sw/lib/pins_arduino.h
@@ -0,0 +1,254 @@
+/*
+ pins_arduino.h - Pin definition functions for Arduino
+ Part of Arduino - http://www.arduino.cc/
+
+ Copyright (c) 2007 David A. Mellis
+
+ 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
+*/
+
+#ifndef Pins_Arduino_h
+#define Pins_Arduino_h
+
+#include <avr/pgmspace.h>
+
+#define NUM_DIGITAL_PINS 20
+#define NUM_ANALOG_INPUTS 6
+#define analogInputToDigitalPin(p) ((p < 6) ? (p) + 14 : -1)
+
+#if defined(__AVR_ATmega8__)
+#define digitalPinHasPWM(p) ((p) == 9 || (p) == 10 || (p) == 11)
+#else
+#define digitalPinHasPWM(p) ((p) == 3 || (p) == 5 || (p) == 6 || (p) == 9 || (p) == 10 || (p) == 11)
+#endif
+
+#define PIN_SPI_SS (10)
+#define PIN_SPI_MOSI (11)
+#define PIN_SPI_MISO (12)
+#define PIN_SPI_SCK (13)
+
+static const uint8_t SS = PIN_SPI_SS;
+static const uint8_t MOSI = PIN_SPI_MOSI;
+static const uint8_t MISO = PIN_SPI_MISO;
+static const uint8_t SCK = PIN_SPI_SCK;
+
+#define PIN_WIRE_SDA (18)
+#define PIN_WIRE_SCL (19)
+
+static const uint8_t SDA = PIN_WIRE_SDA;
+static const uint8_t SCL = PIN_WIRE_SCL;
+
+#define LED_BUILTIN 13
+
+#define PIN_A0 (14)
+#define PIN_A1 (15)
+#define PIN_A2 (16)
+#define PIN_A3 (17)
+#define PIN_A4 (18)
+#define PIN_A5 (19)
+#define PIN_A6 (20)
+#define PIN_A7 (21)
+
+static const uint8_t A0 = PIN_A0;
+static const uint8_t A1 = PIN_A1;
+static const uint8_t A2 = PIN_A2;
+static const uint8_t A3 = PIN_A3;
+static const uint8_t A4 = PIN_A4;
+static const uint8_t A5 = PIN_A5;
+static const uint8_t A6 = PIN_A6;
+static const uint8_t A7 = PIN_A7;
+
+#define digitalPinToPCICR(p) (((p) >= 0 && (p) <= 21) ? (&PCICR) : ((uint8_t *)0))
+#define digitalPinToPCICRbit(p) (((p) <= 7) ? 2 : (((p) <= 13) ? 0 : 1))
+#define digitalPinToPCMSK(p) (((p) <= 7) ? (&PCMSK2) : (((p) <= 13) ? (&PCMSK0) : (((p) <= 21) ? (&PCMSK1) : ((uint8_t *)0))))
+#define digitalPinToPCMSKbit(p) (((p) <= 7) ? (p) : (((p) <= 13) ? ((p) - 8) : ((p) - 14)))
+
+#define digitalPinToInterrupt(p) ((p) == 2 ? 0 : ((p) == 3 ? 1 : NOT_AN_INTERRUPT))
+
+#ifdef ARDUINO_MAIN
+
+// On the Arduino board, digital pins are also used
+// for the analog output (software PWM). Analog input
+// pins are a separate set.
+
+// ATMEL ATMEGA8 & 168 / ARDUINO
+//
+// +-\/-+
+// PC6 1| |28 PC5 (AI 5)
+// (D 0) PD0 2| |27 PC4 (AI 4)
+// (D 1) PD1 3| |26 PC3 (AI 3)
+// (D 2) PD2 4| |25 PC2 (AI 2)
+// PWM+ (D 3) PD3 5| |24 PC1 (AI 1)
+// (D 4) PD4 6| |23 PC0 (AI 0)
+// VCC 7| |22 GND
+// GND 8| |21 AREF
+// PB6 9| |20 AVCC
+// PB7 10| |19 PB5 (D 13)
+// PWM+ (D 5) PD5 11| |18 PB4 (D 12)
+// PWM+ (D 6) PD6 12| |17 PB3 (D 11) PWM
+// (D 7) PD7 13| |16 PB2 (D 10) PWM
+// (D 8) PB0 14| |15 PB1 (D 9) PWM
+// +----+
+//
+// (PWM+ indicates the additional PWM pins on the ATmega168.)
+
+// ATMEL ATMEGA1280 / ARDUINO
+//
+// 0-7 PE0-PE7 works
+// 8-13 PB0-PB5 works
+// 14-21 PA0-PA7 works
+// 22-29 PH0-PH7 works
+// 30-35 PG5-PG0 works
+// 36-43 PC7-PC0 works
+// 44-51 PJ7-PJ0 works
+// 52-59 PL7-PL0 works
+// 60-67 PD7-PD0 works
+// A0-A7 PF0-PF7
+// A8-A15 PK0-PK7
+
+
+// these arrays map port names (e.g. port B) to the
+// appropriate addresses for various functions (e.g. reading
+// and writing)
+const uint16_t PROGMEM port_to_mode_PGM[] = {
+ NOT_A_PORT,
+ NOT_A_PORT,
+ (uint16_t) &DDRB,
+ (uint16_t) &DDRC,
+ (uint16_t) &DDRD,
+};
+
+const uint16_t PROGMEM port_to_output_PGM[] = {
+ NOT_A_PORT,
+ NOT_A_PORT,
+ (uint16_t) &PORTB,
+ (uint16_t) &PORTC,
+ (uint16_t) &PORTD,
+};
+
+const uint16_t PROGMEM port_to_input_PGM[] = {
+ NOT_A_PORT,
+ NOT_A_PORT,
+ (uint16_t) &PINB,
+ (uint16_t) &PINC,
+ (uint16_t) &PIND,
+};
+
+const uint8_t PROGMEM digital_pin_to_port_PGM[] = {
+ PD, /* 0 */
+ PD,
+ PD,
+ PD,
+ PD,
+ PD,
+ PD,
+ PD,
+ PB, /* 8 */
+ PB,
+ PB,
+ PB,
+ PB,
+ PB,
+ PC, /* 14 */
+ PC,
+ PC,
+ PC,
+ PC,
+ PC,
+};
+
+const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = {
+ _BV(0), /* 0, port D */
+ _BV(1),
+ _BV(2),
+ _BV(3),
+ _BV(4),
+ _BV(5),
+ _BV(6),
+ _BV(7),
+ _BV(0), /* 8, port B */
+ _BV(1),
+ _BV(2),
+ _BV(3),
+ _BV(4),
+ _BV(5),
+ _BV(0), /* 14, port C */
+ _BV(1),
+ _BV(2),
+ _BV(3),
+ _BV(4),
+ _BV(5),
+};
+
+const uint8_t PROGMEM digital_pin_to_timer_PGM[] = {
+ NOT_ON_TIMER, /* 0 - port D */
+ NOT_ON_TIMER,
+ NOT_ON_TIMER,
+ // on the ATmega168, digital pin 3 has hardware pwm
+#if defined(__AVR_ATmega8__)
+ NOT_ON_TIMER,
+#else
+ TIMER2B,
+#endif
+ NOT_ON_TIMER,
+ // on the ATmega168, digital pins 5 and 6 have hardware pwm
+#if defined(__AVR_ATmega8__)
+ NOT_ON_TIMER,
+ NOT_ON_TIMER,
+#else
+ TIMER0B,
+ TIMER0A,
+#endif
+ NOT_ON_TIMER,
+ NOT_ON_TIMER, /* 8 - port B */
+ TIMER1A,
+ TIMER1B,
+#if defined(__AVR_ATmega8__)
+ TIMER2,
+#else
+ TIMER2A,
+#endif
+ NOT_ON_TIMER,
+ NOT_ON_TIMER,
+ NOT_ON_TIMER,
+ NOT_ON_TIMER, /* 14 - port C */
+ NOT_ON_TIMER,
+ NOT_ON_TIMER,
+ NOT_ON_TIMER,
+ NOT_ON_TIMER,
+};
+
+#endif
+
+// These serial port names are intended to allow libraries and architecture-neutral
+// sketches to automatically default to the correct port name for a particular type
+// of use. For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN,
+// the first hardware serial port whose RX/TX pins are not dedicated to another use.
+//
+// SERIAL_PORT_MONITOR Port which normally prints to the Arduino Serial Monitor
+//
+// SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial
+//
+// SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via Bridge library
+//
+// SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins.
+//
+// SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX
+// pins are NOT connected to anything by default.
+#define SERIAL_PORT_MONITOR Serial
+#define SERIAL_PORT_HARDWARE Serial
+
+#endif
diff --git a/sw/lib/wiring_analog.c b/sw/lib/wiring_analog.c
new file mode 100644
index 0000000..967c2b9
--- /dev/null
+++ b/sw/lib/wiring_analog.c
@@ -0,0 +1,294 @@
+/*
+ wiring_analog.c - analog input and output
+ Part of Arduino - http://www.arduino.cc/
+
+ Copyright (c) 2005-2006 David A. Mellis
+
+ 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 28 September 2010 by Mark Sproul
+*/
+
+#include "wiring_private.h"
+#include "pins_arduino.h"
+
+uint8_t analog_reference = DEFAULT;
+
+void analogReference(uint8_t mode)
+{
+ // can't actually set the register here because the default setting
+ // will connect AVCC and the AREF pin, which would cause a short if
+ // there's something connected to AREF.
+ analog_reference = mode;
+}
+
+int analogRead(uint8_t pin)
+{
+ uint8_t low, high;
+
+#if defined(analogPinToChannel)
+#if defined(__AVR_ATmega32U4__)
+ if (pin >= 18) pin -= 18; // allow for channel or pin numbers
+#endif
+ pin = analogPinToChannel(pin);
+#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
+ if (pin >= 54) pin -= 54; // allow for channel or pin numbers
+#elif defined(__AVR_ATmega32U4__)
+ if (pin >= 18) pin -= 18; // allow for channel or pin numbers
+#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__)
+ if (pin >= 24) pin -= 24; // allow for channel or pin numbers
+#else
+ if (pin >= 14) pin -= 14; // allow for channel or pin numbers
+#endif
+
+#if defined(ADCSRB) && defined(MUX5)
+ // the MUX5 bit of ADCSRB selects whether we're reading from channels
+ // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
+ ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
+#endif
+
+ // set the analog reference (high two bits of ADMUX) and select the
+ // channel (low 4 bits). this also sets ADLAR (left-adjust result)
+ // to 0 (the default).
+#if defined(ADMUX)
+#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
+ ADMUX = (analog_reference << 4) | (pin & 0x07);
+#else
+ ADMUX = (analog_reference << 6) | (pin & 0x07);
+#endif
+#endif
+
+ // without a delay, we seem to read from the wrong channel
+ //delay(1);
+
+#if defined(ADCSRA) && defined(ADCL)
+ // start the conversion
+ sbi(ADCSRA, ADSC);
+
+ // ADSC is cleared when the conversion finishes
+ while (bit_is_set(ADCSRA, ADSC));
+
+ // we have to read ADCL first; doing so locks both ADCL
+ // and ADCH until ADCH is read. reading ADCL second would
+ // cause the results of each conversion to be discarded,
+ // as ADCL and ADCH would be locked when it completed.
+ low = ADCL;
+ high = ADCH;
+#else
+ // we dont have an ADC, return 0
+ low = 0;
+ high = 0;
+#endif
+
+ // combine the two bytes
+ return (high << 8) | low;
+}
+
+// Right now, PWM output only works on the pins with
+// hardware support. These are defined in the appropriate
+// pins_*.c file. For the rest of the pins, we default
+// to digital output.
+void analogWrite(uint8_t pin, int val)
+{
+ // We need to make sure the PWM output is enabled for those pins
+ // that support it, as we turn it off when digitally reading or
+ // writing with them. Also, make sure the pin is in output mode
+ // for consistenty with Wiring, which doesn't require a pinMode
+ // call for the analog output pins.
+ pinMode(pin, OUTPUT);
+ if (val == 0)
+ {
+ digitalWrite(pin, LOW);
+ }
+ else if (val == 255)
+ {
+ digitalWrite(pin, HIGH);
+ }
+ else
+ {
+ switch(digitalPinToTimer(pin))
+ {
+ // XXX fix needed for atmega8
+ #if defined(TCCR0) && defined(COM00) && !defined(__AVR_ATmega8__)
+ case TIMER0A:
+ // connect pwm to pin on timer 0
+ sbi(TCCR0, COM00);
+ OCR0 = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR0A) && defined(COM0A1)
+ case TIMER0A:
+ // connect pwm to pin on timer 0, channel A
+ sbi(TCCR0A, COM0A1);
+ OCR0A = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR0A) && defined(COM0B1)
+ case TIMER0B:
+ // connect pwm to pin on timer 0, channel B
+ sbi(TCCR0A, COM0B1);
+ OCR0B = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR1A) && defined(COM1A1)
+ case TIMER1A:
+ // connect pwm to pin on timer 1, channel A
+ sbi(TCCR1A, COM1A1);
+ OCR1A = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR1A) && defined(COM1B1)
+ case TIMER1B:
+ // connect pwm to pin on timer 1, channel B
+ sbi(TCCR1A, COM1B1);
+ OCR1B = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR1A) && defined(COM1C1)
+ case TIMER1C:
+ // connect pwm to pin on timer 1, channel B
+ sbi(TCCR1A, COM1C1);
+ OCR1C = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR2) && defined(COM21)
+ case TIMER2:
+ // connect pwm to pin on timer 2
+ sbi(TCCR2, COM21);
+ OCR2 = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR2A) && defined(COM2A1)
+ case TIMER2A:
+ // connect pwm to pin on timer 2, channel A
+ sbi(TCCR2A, COM2A1);
+ OCR2A = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR2A) && defined(COM2B1)
+ case TIMER2B:
+ // connect pwm to pin on timer 2, channel B
+ sbi(TCCR2A, COM2B1);
+ OCR2B = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR3A) && defined(COM3A1)
+ case TIMER3A:
+ // connect pwm to pin on timer 3, channel A
+ sbi(TCCR3A, COM3A1);
+ OCR3A = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR3A) && defined(COM3B1)
+ case TIMER3B:
+ // connect pwm to pin on timer 3, channel B
+ sbi(TCCR3A, COM3B1);
+ OCR3B = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR3A) && defined(COM3C1)
+ case TIMER3C:
+ // connect pwm to pin on timer 3, channel C
+ sbi(TCCR3A, COM3C1);
+ OCR3C = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR4A)
+ case TIMER4A:
+ //connect pwm to pin on timer 4, channel A
+ sbi(TCCR4A, COM4A1);
+ #if defined(COM4A0) // only used on 32U4
+ cbi(TCCR4A, COM4A0);
+ #endif
+ OCR4A = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR4A) && defined(COM4B1)
+ case TIMER4B:
+ // connect pwm to pin on timer 4, channel B
+ sbi(TCCR4A, COM4B1);
+ OCR4B = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR4A) && defined(COM4C1)
+ case TIMER4C:
+ // connect pwm to pin on timer 4, channel C
+ sbi(TCCR4A, COM4C1);
+ OCR4C = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR4C) && defined(COM4D1)
+ case TIMER4D:
+ // connect pwm to pin on timer 4, channel D
+ sbi(TCCR4C, COM4D1);
+ #if defined(COM4D0) // only used on 32U4
+ cbi(TCCR4C, COM4D0);
+ #endif
+ OCR4D = val; // set pwm duty
+ break;
+ #endif
+
+
+ #if defined(TCCR5A) && defined(COM5A1)
+ case TIMER5A:
+ // connect pwm to pin on timer 5, channel A
+ sbi(TCCR5A, COM5A1);
+ OCR5A = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR5A) && defined(COM5B1)
+ case TIMER5B:
+ // connect pwm to pin on timer 5, channel B
+ sbi(TCCR5A, COM5B1);
+ OCR5B = val; // set pwm duty
+ break;
+ #endif
+
+ #if defined(TCCR5A) && defined(COM5C1)
+ case TIMER5C:
+ // connect pwm to pin on timer 5, channel C
+ sbi(TCCR5A, COM5C1);
+ OCR5C = val; // set pwm duty
+ break;
+ #endif
+
+ case NOT_ON_TIMER:
+ default:
+ if (val < 128) {
+ digitalWrite(pin, LOW);
+ } else {
+ digitalWrite(pin, HIGH);
+ }
+ }
+ }
+}
+
diff --git a/sw/lib/wiring_digital.c b/sw/lib/wiring_digital.c
new file mode 100644
index 0000000..27a62fc
--- /dev/null
+++ b/sw/lib/wiring_digital.c
@@ -0,0 +1,179 @@
+/*
+ wiring_digital.c - digital input and output functions
+ Part of Arduino - http://www.arduino.cc/
+
+ Copyright (c) 2005-2006 David A. Mellis
+
+ 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 28 September 2010 by Mark Sproul
+*/
+
+#define ARDUINO_MAIN
+#include "wiring_private.h"
+#include "pins_arduino.h"
+
+void pinMode(uint8_t pin, uint8_t mode)
+{
+ uint8_t bit = digitalPinToBitMask(pin);
+ uint8_t port = digitalPinToPort(pin);
+ volatile uint8_t *reg, *out;
+
+ if (port == NOT_A_PIN) return;
+
+ // JWS: can I let the optimizer do this?
+ reg = portModeRegister(port);
+ out = portOutputRegister(port);
+
+ if (mode == INPUT) {
+ uint8_t oldSREG = SREG;
+ cli();
+ *reg &= ~bit;
+ *out &= ~bit;
+ SREG = oldSREG;
+ } else if (mode == INPUT_PULLUP) {
+ uint8_t oldSREG = SREG;
+ cli();
+ *reg &= ~bit;
+ *out |= bit;
+ SREG = oldSREG;
+ } else {
+ uint8_t oldSREG = SREG;
+ cli();
+ *reg |= bit;
+ SREG = oldSREG;
+ }
+}
+
+// Forcing this inline keeps the callers from having to push their own stuff
+// on the stack. It is a good performance win and only takes 1 more byte per
+// user than calling. (It will take more bytes on the 168.)
+//
+// But shouldn't this be moved into pinMode? Seems silly to check and do on
+// each digitalread or write.
+//
+// Mark Sproul:
+// - Removed inline. Save 170 bytes on atmega1280
+// - changed to a switch statment; added 32 bytes but much easier to read and maintain.
+// - Added more #ifdefs, now compiles for atmega645
+//
+//static inline void turnOffPWM(uint8_t timer) __attribute__ ((always_inline));
+//static inline void turnOffPWM(uint8_t timer)
+static void turnOffPWM(uint8_t timer)
+{
+ switch (timer)
+ {
+ #if defined(TCCR1A) && defined(COM1A1)
+ case TIMER1A: cbi(TCCR1A, COM1A1); break;
+ #endif
+ #if defined(TCCR1A) && defined(COM1B1)
+ case TIMER1B: cbi(TCCR1A, COM1B1); break;
+ #endif
+ #if defined(TCCR1A) && defined(COM1C1)
+ case TIMER1C: cbi(TCCR1A, COM1C1); break;
+ #endif
+
+ #if defined(TCCR2) && defined(COM21)
+ case TIMER2: cbi(TCCR2, COM21); break;
+ #endif
+
+ #if defined(TCCR0A) && defined(COM0A1)
+ case TIMER0A: cbi(TCCR0A, COM0A1); break;
+ #endif
+
+ #if defined(TCCR0A) && defined(COM0B1)
+ case TIMER0B: cbi(TCCR0A, COM0B1); break;
+ #endif
+ #if defined(TCCR2A) && defined(COM2A1)
+ case TIMER2A: cbi(TCCR2A, COM2A1); break;
+ #endif
+ #if defined(TCCR2A) && defined(COM2B1)
+ case TIMER2B: cbi(TCCR2A, COM2B1); break;
+ #endif
+
+ #if defined(TCCR3A) && defined(COM3A1)
+ case TIMER3A: cbi(TCCR3A, COM3A1); break;
+ #endif
+ #if defined(TCCR3A) && defined(COM3B1)
+ case TIMER3B: cbi(TCCR3A, COM3B1); break;
+ #endif
+ #if defined(TCCR3A) && defined(COM3C1)
+ case TIMER3C: cbi(TCCR3A, COM3C1); break;
+ #endif
+
+ #if defined(TCCR4A) && defined(COM4A1)
+ case TIMER4A: cbi(TCCR4A, COM4A1); break;
+ #endif
+ #if defined(TCCR4A) && defined(COM4B1)
+ case TIMER4B: cbi(TCCR4A, COM4B1); break;
+ #endif
+ #if defined(TCCR4A) && defined(COM4C1)
+ case TIMER4C: cbi(TCCR4A, COM4C1); break;
+ #endif
+ #if defined(TCCR4C) && defined(COM4D1)
+ case TIMER4D: cbi(TCCR4C, COM4D1); break;
+ #endif
+
+ #if defined(TCCR5A)
+ case TIMER5A: cbi(TCCR5A, COM5A1); break;
+ case TIMER5B: cbi(TCCR5A, COM5B1); break;
+ case TIMER5C: cbi(TCCR5A, COM5C1); break;
+ #endif
+ }
+}
+
+void digitalWrite(uint8_t pin, uint8_t val)
+{
+ uint8_t timer = digitalPinToTimer(pin);
+ uint8_t bit = digitalPinToBitMask(pin);
+ uint8_t port = digitalPinToPort(pin);
+ volatile uint8_t *out;
+
+ if (port == NOT_A_PIN) return;
+
+ // If the pin that support PWM output, we need to turn it off
+ // before doing a digital write.
+ if (timer != NOT_ON_TIMER) turnOffPWM(timer);
+
+ out = portOutputRegister(port);
+
+ uint8_t oldSREG = SREG;
+ cli();
+
+ if (val == LOW) {
+ *out &= ~bit;
+ } else {
+ *out |= bit;
+ }
+
+ SREG = oldSREG;
+}
+
+int digitalRead(uint8_t pin)
+{
+ uint8_t timer = digitalPinToTimer(pin);
+ uint8_t bit = digitalPinToBitMask(pin);
+ uint8_t port = digitalPinToPort(pin);
+
+ if (port == NOT_A_PIN) return LOW;
+
+ // If the pin that support PWM output, we need to turn it off
+ // before getting a digital reading.
+ if (timer != NOT_ON_TIMER) turnOffPWM(timer);
+
+ if (*portInputRegister(port) & bit) return HIGH;
+ return LOW;
+}
diff --git a/sw/lib/wiring_private.h b/sw/lib/wiring_private.h
new file mode 100644
index 0000000..a277b14
--- /dev/null
+++ b/sw/lib/wiring_private.h
@@ -0,0 +1,72 @@
+/*
+ wiring_private.h - Internal header file.
+ Part of Arduino - http://www.arduino.cc/
+
+ Copyright (c) 2005-2006 David A. Mellis
+
+ 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
+*/
+
+#ifndef WiringPrivate_h
+#define WiringPrivate_h
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "Arduino.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#ifndef cbi
+#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
+#endif
+#ifndef sbi
+#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
+#endif
+
+uint32_t countPulseASM(volatile uint8_t *port, uint8_t bit, uint8_t stateMask, unsigned long maxloops);
+
+#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
+
+#endif
diff --git a/sw/main.cpp b/sw/main.cpp
index 712adc0..e849dea 100644
--- a/sw/main.cpp
+++ b/sw/main.cpp
@@ -33,6 +33,8 @@
#include <avr/eeprom.h>
#include <avr/wdt.h>
+#include "SPI.h"
+
extern "C" {
#include "uart.h"
}
@@ -210,6 +212,8 @@ int main()
DDRC = PINC_OUTPUTS;
DDRD = PIND_OUTPUTS;
+ SPI.begin();
+
// Warning: Bi-stable relays are still in unknown state!
/* Setup UART */