initial commit
This commit is contained in:
@@ -0,0 +1,435 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file Adafruit_LIS3DH.cpp
|
||||
@author K. Townsend / Limor Fried (Adafruit Industries)
|
||||
@license BSD (see license.txt)
|
||||
|
||||
This is a library for the Adafruit LIS3DH Accel breakout board
|
||||
----> https://www.adafruit.com/products/2809
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
@section HISTORY
|
||||
|
||||
v1.0 - First release
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_CPlay_LIS3DH.h>
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Instantiates a new LIS3DH class in I2C or SPI mode
|
||||
*/
|
||||
/**************************************************************************/
|
||||
// I2C
|
||||
Adafruit_CPlay_LIS3DH::Adafruit_CPlay_LIS3DH()
|
||||
: _cs(-1), _mosi(-1), _miso(-1), _sck(-1), _sensorID(-1)
|
||||
{
|
||||
}
|
||||
|
||||
Adafruit_CPlay_LIS3DH::Adafruit_CPlay_LIS3DH(int8_t cspin)
|
||||
: _cs(cspin), _mosi(-1), _miso(-1), _sck(-1), _sensorID(-1)
|
||||
{ }
|
||||
|
||||
Adafruit_CPlay_LIS3DH::Adafruit_CPlay_LIS3DH(int8_t cspin, int8_t mosipin, int8_t misopin, int8_t sckpin)
|
||||
: _cs(cspin), _mosi(mosipin), _miso(misopin), _sck(sckpin), _sensorID(-1)
|
||||
{ }
|
||||
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Setups the HW (reads coefficients values, etc.)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_CPlay_LIS3DH::begin(uint8_t i2caddr) {
|
||||
_i2caddr = i2caddr;
|
||||
|
||||
|
||||
if (_cs == -1) {
|
||||
// i2c
|
||||
Wire.begin();
|
||||
} else {
|
||||
digitalWrite(_cs, HIGH);
|
||||
pinMode(_cs, OUTPUT);
|
||||
|
||||
#ifndef __AVR_ATtiny85__
|
||||
if (_sck == -1) {
|
||||
// hardware SPI
|
||||
SPI.begin();
|
||||
} else {
|
||||
// software SPI
|
||||
pinMode(_sck, OUTPUT);
|
||||
pinMode(_mosi, OUTPUT);
|
||||
pinMode(_miso, INPUT);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
for (uint8_t i=0; i<0x30; i++) {
|
||||
Serial.print("$");
|
||||
Serial.print(i, HEX); Serial.print(" = 0x");
|
||||
Serial.println(readRegister8(i), HEX);
|
||||
}
|
||||
*/
|
||||
|
||||
/* Check connection */
|
||||
uint8_t deviceid = readRegister8(LIS3DH_REG_WHOAMI);
|
||||
if (deviceid != 0x33)
|
||||
{
|
||||
/* No LIS3DH detected ... return false */
|
||||
//Serial.println(deviceid, HEX);
|
||||
return false;
|
||||
}
|
||||
|
||||
// enable all axes, normal mode
|
||||
writeRegister8(LIS3DH_REG_CTRL1, 0x07);
|
||||
// 400Hz rate
|
||||
setDataRate(LIS3DH_DATARATE_400_HZ);
|
||||
|
||||
// High res & BDU enabled
|
||||
writeRegister8(LIS3DH_REG_CTRL4, 0x88);
|
||||
|
||||
// DRDY on INT1
|
||||
writeRegister8(LIS3DH_REG_CTRL3, 0x10);
|
||||
|
||||
// Turn on orientation config
|
||||
//writeRegister8(LIS3DH_REG_PL_CFG, 0x40);
|
||||
|
||||
// enable adcs
|
||||
writeRegister8(LIS3DH_REG_TEMPCFG, 0x80);
|
||||
|
||||
/*
|
||||
for (uint8_t i=0; i<0x30; i++) {
|
||||
Serial.print("$");
|
||||
Serial.print(i, HEX); Serial.print(" = 0x");
|
||||
Serial.println(readRegister8(i), HEX);
|
||||
}
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Adafruit_CPlay_LIS3DH::read(void) {
|
||||
// read x y z at once
|
||||
|
||||
if (_cs == -1) {
|
||||
// i2c
|
||||
Wire.beginTransmission(_i2caddr);
|
||||
Wire.write(LIS3DH_REG_OUT_X_L | 0x80); // 0x80 for autoincrement
|
||||
Wire.endTransmission();
|
||||
|
||||
Wire.requestFrom(_i2caddr, 6);
|
||||
x = Wire.read(); x |= ((uint16_t)Wire.read()) << 8;
|
||||
y = Wire.read(); y |= ((uint16_t)Wire.read()) << 8;
|
||||
z = Wire.read(); z |= ((uint16_t)Wire.read()) << 8;
|
||||
}
|
||||
#ifndef __AVR_ATtiny85__
|
||||
else {
|
||||
#if SPI_HAS_TRANSACTION
|
||||
if (_sck == -1)
|
||||
SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
|
||||
#endif
|
||||
digitalWrite(_cs, LOW);
|
||||
spixfer(LIS3DH_REG_OUT_X_L | 0x80 | 0x40); // read multiple, bit 7&6 high
|
||||
|
||||
x = spixfer(); x |= ((uint16_t)spixfer()) << 8;
|
||||
y = spixfer(); y |= ((uint16_t)spixfer()) << 8;
|
||||
z = spixfer(); z |= ((uint16_t)spixfer()) << 8;
|
||||
|
||||
digitalWrite(_cs, HIGH);
|
||||
#if SPI_HAS_TRANSACTION
|
||||
if (_sck == -1)
|
||||
SPI.endTransaction(); // release the SPI bus
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
uint8_t range = getRange();
|
||||
uint16_t divider = 1;
|
||||
if (range == LIS3DH_RANGE_16_G) divider = 1365;
|
||||
if (range == LIS3DH_RANGE_8_G) divider = 4096;
|
||||
if (range == LIS3DH_RANGE_4_G) divider = 8190;
|
||||
if (range == LIS3DH_RANGE_2_G) divider = 16380;
|
||||
|
||||
x_g = (float)x / divider;
|
||||
y_g = (float)y / divider;
|
||||
z_g = (float)z / divider;
|
||||
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Read the auxilary ADC
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
int16_t Adafruit_CPlay_LIS3DH::readADC(uint8_t adc) {
|
||||
if ((adc < 1) || (adc > 3)) return 0;
|
||||
uint16_t value;
|
||||
|
||||
adc--;
|
||||
|
||||
uint8_t reg = LIS3DH_REG_OUTADC1_L + adc*2;
|
||||
|
||||
if (_cs == -1) {
|
||||
// i2c
|
||||
Wire.beginTransmission(_i2caddr);
|
||||
Wire.write(reg | 0x80); // 0x80 for autoincrement
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom(_i2caddr, 2);
|
||||
value = Wire.read(); value |= ((uint16_t)Wire.read()) << 8;
|
||||
}
|
||||
#ifndef __AVR_ATtiny85__
|
||||
else {
|
||||
#if SPI_HAS_TRANSACTION
|
||||
if (_sck == -1)
|
||||
SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
|
||||
#endif
|
||||
digitalWrite(_cs, LOW);
|
||||
spixfer(reg | 0x80 | 0x40); // read multiple, bit 7&6 high
|
||||
|
||||
value = spixfer(); value |= ((uint16_t)spixfer()) << 8;
|
||||
|
||||
digitalWrite(_cs, HIGH);
|
||||
#if SPI_HAS_TRANSACTION
|
||||
if (_sck == -1)
|
||||
SPI.endTransaction(); // release the SPI bus
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Set INT to output for single or double click
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
void Adafruit_CPlay_LIS3DH::setClick(uint8_t c, uint8_t clickthresh, uint8_t timelimit, uint8_t timelatency, uint8_t timewindow) {
|
||||
if (!c) {
|
||||
//disable int
|
||||
uint8_t r = readRegister8(LIS3DH_REG_CTRL3);
|
||||
r &= ~(0x80); // turn off I1_CLICK
|
||||
writeRegister8(LIS3DH_REG_CTRL3, r);
|
||||
writeRegister8(LIS3DH_REG_CLICKCFG, 0);
|
||||
return;
|
||||
}
|
||||
// else...
|
||||
|
||||
writeRegister8(LIS3DH_REG_CTRL3, 0x80); // turn on int1 click
|
||||
writeRegister8(LIS3DH_REG_CTRL5, 0x08); // latch interrupt on int1
|
||||
|
||||
if (c == 1)
|
||||
writeRegister8(LIS3DH_REG_CLICKCFG, 0x15); // turn on all axes & singletap
|
||||
if (c == 2)
|
||||
writeRegister8(LIS3DH_REG_CLICKCFG, 0x2A); // turn on all axes & doubletap
|
||||
|
||||
|
||||
writeRegister8(LIS3DH_REG_CLICKTHS, clickthresh); // arbitrary
|
||||
writeRegister8(LIS3DH_REG_TIMELIMIT, timelimit); // arbitrary
|
||||
writeRegister8(LIS3DH_REG_TIMELATENCY, timelatency); // arbitrary
|
||||
writeRegister8(LIS3DH_REG_TIMEWINDOW, timewindow); // arbitrary
|
||||
}
|
||||
|
||||
uint8_t Adafruit_CPlay_LIS3DH::getClick(void) {
|
||||
return readRegister8(LIS3DH_REG_CLICKSRC);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Sets the g range for the accelerometer
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_CPlay_LIS3DH::setRange(lis3dh_range_t range)
|
||||
{
|
||||
uint8_t r = readRegister8(LIS3DH_REG_CTRL4);
|
||||
r &= ~(0x30);
|
||||
r |= range << 4;
|
||||
writeRegister8(LIS3DH_REG_CTRL4, r);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Sets the g range for the accelerometer
|
||||
*/
|
||||
/**************************************************************************/
|
||||
lis3dh_range_t Adafruit_CPlay_LIS3DH::getRange(void)
|
||||
{
|
||||
/* Read the data format register to preserve bits */
|
||||
return (lis3dh_range_t)((readRegister8(LIS3DH_REG_CTRL4) >> 4) & 0x03);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Sets the data rate for the LIS3DH (controls power consumption)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_CPlay_LIS3DH::setDataRate(lis3dh_dataRate_t dataRate)
|
||||
{
|
||||
uint8_t ctl1 = readRegister8(LIS3DH_REG_CTRL1);
|
||||
ctl1 &= ~(0xF0); // mask off bits
|
||||
ctl1 |= (dataRate << 4);
|
||||
writeRegister8(LIS3DH_REG_CTRL1, ctl1);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Sets the data rate for the LIS3DH (controls power consumption)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
lis3dh_dataRate_t Adafruit_CPlay_LIS3DH::getDataRate(void)
|
||||
{
|
||||
return (lis3dh_dataRate_t)((readRegister8(LIS3DH_REG_CTRL1) >> 4)& 0x0F);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the most recent sensor event
|
||||
*/
|
||||
/**************************************************************************/
|
||||
bool Adafruit_CPlay_LIS3DH::getEvent(sensors_event_t *event) {
|
||||
/* Clear the event */
|
||||
memset(event, 0, sizeof(sensors_event_t));
|
||||
|
||||
event->version = sizeof(sensors_event_t);
|
||||
event->sensor_id = _sensorID;
|
||||
event->type = SENSOR_TYPE_ACCELEROMETER;
|
||||
event->timestamp = 0;
|
||||
|
||||
read();
|
||||
|
||||
event->acceleration.x = x_g * SENSORS_GRAVITY_STANDARD;
|
||||
event->acceleration.y = y_g * SENSORS_GRAVITY_STANDARD;
|
||||
event->acceleration.z = z_g * SENSORS_GRAVITY_STANDARD;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Gets the sensor_t data
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_CPlay_LIS3DH::getSensor(sensor_t *sensor) {
|
||||
/* Clear the sensor_t object */
|
||||
memset(sensor, 0, sizeof(sensor_t));
|
||||
|
||||
/* Insert the sensor name in the fixed length char array */
|
||||
strncpy (sensor->name, "LIS3DH", sizeof(sensor->name) - 1);
|
||||
sensor->name[sizeof(sensor->name)- 1] = 0;
|
||||
sensor->version = 1;
|
||||
sensor->sensor_id = _sensorID;
|
||||
sensor->type = SENSOR_TYPE_ACCELEROMETER;
|
||||
sensor->min_delay = 0;
|
||||
sensor->max_value = 0;
|
||||
sensor->min_value = 0;
|
||||
sensor->resolution = 0;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Low level SPI
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
uint8_t Adafruit_CPlay_LIS3DH::spixfer(uint8_t x) {
|
||||
#ifndef __AVR_ATtiny85__
|
||||
if (_sck == -1)
|
||||
return SPI.transfer(x);
|
||||
|
||||
// software spi
|
||||
//Serial.println("Software SPI");
|
||||
uint8_t reply = 0;
|
||||
for (int i=7; i>=0; i--) {
|
||||
reply <<= 1;
|
||||
digitalWrite(_sck, LOW);
|
||||
digitalWrite(_mosi, x & (1<<i));
|
||||
digitalWrite(_sck, HIGH);
|
||||
if (digitalRead(_miso))
|
||||
reply |= 1;
|
||||
}
|
||||
return reply;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Writes 8-bits to the specified destination register
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void Adafruit_CPlay_LIS3DH::writeRegister8(uint8_t reg, uint8_t value) {
|
||||
if (_cs == -1) {
|
||||
Wire.beginTransmission((uint8_t)_i2caddr);
|
||||
Wire.write((uint8_t)reg);
|
||||
Wire.write((uint8_t)value);
|
||||
Wire.endTransmission();
|
||||
}
|
||||
#ifndef __AVR_ATtiny85__
|
||||
else {
|
||||
#if SPI_HAS_TRANSACTION
|
||||
if (_sck == -1)
|
||||
SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
|
||||
#endif
|
||||
digitalWrite(_cs, LOW);
|
||||
spixfer(reg & ~0x80); // write, bit 7 low
|
||||
spixfer(value);
|
||||
digitalWrite(_cs, HIGH);
|
||||
#if SPI_HAS_TRANSACTION
|
||||
if (_sck == -1)
|
||||
SPI.endTransaction(); // release the SPI bus
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Reads 8-bits from the specified register
|
||||
*/
|
||||
/**************************************************************************/
|
||||
uint8_t Adafruit_CPlay_LIS3DH::readRegister8(uint8_t reg) {
|
||||
uint8_t value;
|
||||
|
||||
if (_cs == -1) {
|
||||
Wire.beginTransmission(_i2caddr);
|
||||
Wire.write((uint8_t)reg);
|
||||
Wire.endTransmission();
|
||||
|
||||
Wire.requestFrom(_i2caddr, 1);
|
||||
value = Wire.read();
|
||||
}
|
||||
#ifndef __AVR_ATtiny85__
|
||||
else {
|
||||
#if SPI_HAS_TRANSACTION
|
||||
if (_sck == -1)
|
||||
SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0));
|
||||
#endif
|
||||
digitalWrite(_cs, LOW);
|
||||
spixfer(reg | 0x80); // read, bit 7 high
|
||||
value = spixfer(0);
|
||||
digitalWrite(_cs, HIGH);
|
||||
#if SPI_HAS_TRANSACTION
|
||||
if (_sck == -1)
|
||||
SPI.endTransaction(); // release the SPI bus
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
return value;
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file Adafruit_LIS3DH.h
|
||||
@author K. Townsend / Limor Fried (Adafruit Industries)
|
||||
@license BSD (see license.txt)
|
||||
|
||||
This is a library for the Adafruit LIS3DH Accel breakout board
|
||||
----> https://www.adafruit.com/products/2809
|
||||
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
@section HISTORY
|
||||
|
||||
v1.0 - First release
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef ADAFRUIT_CPLAY_LIS3DH_H
|
||||
#define ADAFRUIT_CPLAY_LIS3DH_H
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include <Wire.h>
|
||||
#ifndef __AVR_ATtiny85__
|
||||
#include <SPI.h>
|
||||
#endif
|
||||
#include "utility/Adafruit_CPlay_Sensor.h"
|
||||
|
||||
/*=========================================================================
|
||||
I2C ADDRESS/BITS
|
||||
-----------------------------------------------------------------------*/
|
||||
#define LIS3DH_DEFAULT_ADDRESS (0x18) // if SDO/SA0 is 3V, its 0x19
|
||||
/*=========================================================================*/
|
||||
|
||||
#define LIS3DH_REG_STATUS1 0x07
|
||||
#define LIS3DH_REG_OUTADC1_L 0x08
|
||||
#define LIS3DH_REG_OUTADC1_H 0x09
|
||||
#define LIS3DH_REG_OUTADC2_L 0x0A
|
||||
#define LIS3DH_REG_OUTADC2_H 0x0B
|
||||
#define LIS3DH_REG_OUTADC3_L 0x0C
|
||||
#define LIS3DH_REG_OUTADC3_H 0x0D
|
||||
#define LIS3DH_REG_INTCOUNT 0x0E
|
||||
#define LIS3DH_REG_WHOAMI 0x0F
|
||||
#define LIS3DH_REG_TEMPCFG 0x1F
|
||||
#define LIS3DH_REG_CTRL1 0x20
|
||||
#define LIS3DH_REG_CTRL2 0x21
|
||||
#define LIS3DH_REG_CTRL3 0x22
|
||||
#define LIS3DH_REG_CTRL4 0x23
|
||||
#define LIS3DH_REG_CTRL5 0x24
|
||||
#define LIS3DH_REG_CTRL6 0x25
|
||||
#define LIS3DH_REG_REFERENCE 0x26
|
||||
#define LIS3DH_REG_STATUS2 0x27
|
||||
#define LIS3DH_REG_OUT_X_L 0x28
|
||||
#define LIS3DH_REG_OUT_X_H 0x29
|
||||
#define LIS3DH_REG_OUT_Y_L 0x2A
|
||||
#define LIS3DH_REG_OUT_Y_H 0x2B
|
||||
#define LIS3DH_REG_OUT_Z_L 0x2C
|
||||
#define LIS3DH_REG_OUT_Z_H 0x2D
|
||||
#define LIS3DH_REG_FIFOCTRL 0x2E
|
||||
#define LIS3DH_REG_FIFOSRC 0x2F
|
||||
#define LIS3DH_REG_INT1CFG 0x30
|
||||
#define LIS3DH_REG_INT1SRC 0x31
|
||||
#define LIS3DH_REG_INT1THS 0x32
|
||||
#define LIS3DH_REG_INT1DUR 0x33
|
||||
#define LIS3DH_REG_CLICKCFG 0x38
|
||||
#define LIS3DH_REG_CLICKSRC 0x39
|
||||
#define LIS3DH_REG_CLICKTHS 0x3A
|
||||
#define LIS3DH_REG_TIMELIMIT 0x3B
|
||||
#define LIS3DH_REG_TIMELATENCY 0x3C
|
||||
#define LIS3DH_REG_TIMEWINDOW 0x3D
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LIS3DH_RANGE_16_G = 0b11, // +/- 16g
|
||||
LIS3DH_RANGE_8_G = 0b10, // +/- 8g
|
||||
LIS3DH_RANGE_4_G = 0b01, // +/- 4g
|
||||
LIS3DH_RANGE_2_G = 0b00 // +/- 2g (default value)
|
||||
} lis3dh_range_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LIS3DH_AXIS_X = 0x0,
|
||||
LIS3DH_AXIS_Y = 0x1,
|
||||
LIS3DH_AXIS_Z = 0x2,
|
||||
} lis3dh_axis_t;
|
||||
|
||||
|
||||
/* Used with register 0x2A (LIS3DH_REG_CTRL_REG1) to set bandwidth */
|
||||
typedef enum
|
||||
{
|
||||
LIS3DH_DATARATE_400_HZ = 0b0111, // 400Hz
|
||||
LIS3DH_DATARATE_200_HZ = 0b0110, // 200Hz
|
||||
LIS3DH_DATARATE_100_HZ = 0b0101, // 100Hz
|
||||
LIS3DH_DATARATE_50_HZ = 0b0100, // 50Hz
|
||||
LIS3DH_DATARATE_25_HZ = 0b0011, // 25Hz
|
||||
LIS3DH_DATARATE_10_HZ = 0b0010, // 10 Hz
|
||||
LIS3DH_DATARATE_1_HZ = 0b0001, // 1 Hz
|
||||
LIS3DH_DATARATE_POWERDOWN = 0,
|
||||
LIS3DH_DATARATE_LOWPOWER_1K6HZ = 0b1000,
|
||||
LIS3DH_DATARATE_LOWPOWER_5KHZ = 0b1001,
|
||||
|
||||
} lis3dh_dataRate_t;
|
||||
|
||||
class Adafruit_CPlay_LIS3DH : public Adafruit_Sensor {
|
||||
public:
|
||||
Adafruit_CPlay_LIS3DH(void);
|
||||
Adafruit_CPlay_LIS3DH(int8_t cspin);
|
||||
Adafruit_CPlay_LIS3DH(int8_t cspin, int8_t mosipin, int8_t misopin, int8_t sckpin);
|
||||
|
||||
bool begin(uint8_t addr = LIS3DH_DEFAULT_ADDRESS);
|
||||
|
||||
void read();
|
||||
int16_t readADC(uint8_t a);
|
||||
|
||||
void setRange(lis3dh_range_t range);
|
||||
lis3dh_range_t getRange(void);
|
||||
|
||||
void setDataRate(lis3dh_dataRate_t dataRate);
|
||||
lis3dh_dataRate_t getDataRate(void);
|
||||
|
||||
bool getEvent(sensors_event_t *event);
|
||||
void getSensor(sensor_t *sensor);
|
||||
|
||||
uint8_t getOrientation(void);
|
||||
|
||||
void setClick(uint8_t c, uint8_t clickthresh, uint8_t timelimit = 10, uint8_t timelatency = 20, uint8_t timewindow = 255);
|
||||
uint8_t getClick(void);
|
||||
|
||||
int16_t x, y, z;
|
||||
float x_g, y_g, z_g;
|
||||
|
||||
private:
|
||||
|
||||
uint8_t readRegister8(uint8_t reg);
|
||||
void writeRegister8(uint8_t reg, uint8_t value);
|
||||
uint8_t spixfer(uint8_t x = 0xFF);
|
||||
|
||||
|
||||
int32_t _sensorID;
|
||||
int8_t _i2caddr;
|
||||
|
||||
// SPI
|
||||
int8_t _cs, _mosi, _miso, _sck;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,158 @@
|
||||
// Adafruit Circuit Playground microphone library
|
||||
// by Phil Burgess / Paint Your Dragon.
|
||||
// Fast Fourier transform section is derived from
|
||||
// ELM-ChaN FFT library (see comments in ffft.S).
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "Adafruit_CPlay_Mic.h"
|
||||
|
||||
#define DC_OFFSET (1023 / 3)
|
||||
#define NOISE_THRESHOLD 3
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Reads ADC for given interval (in milliseconds, 1-65535), returns max
|
||||
// deviation from DC_OFFSET (e.g. 0-341). Uses ADC free-run mode w/polling.
|
||||
// Any currently-installed ADC interrupt handler will be temporarily
|
||||
// disabled while this runs.
|
||||
|
||||
int Adafruit_CPlay_Mic::peak(uint16_t ms) {
|
||||
uint8_t admux_save, adcsra_save, adcsrb_save, timsk0_save, channel;
|
||||
uint16_t i, nSamples;
|
||||
int16_t adc, adcMin, adcMax;
|
||||
|
||||
nSamples = (9615L * ms + 500) / 1000;
|
||||
if(!nSamples) nSamples = 1;
|
||||
|
||||
channel = analogPinToChannel(4); // Pin A4 to ADC channel
|
||||
admux_save = ADMUX; // Save ADC config registers
|
||||
adcsra_save = ADCSRA;
|
||||
adcsrb_save = ADCSRB;
|
||||
|
||||
// Init ADC free-run mode; f = ( 8MHz/prescaler ) / 13 cycles/conversion
|
||||
ADCSRA = 0; // Stop ADC interrupt, if any
|
||||
ADMUX = _BV(REFS0) | channel; // Aref=AVcc, channel sel, right-adj
|
||||
ADCSRB = 0; // Free run mode, no high MUX bit
|
||||
ADCSRA = _BV(ADEN) | // ADC enable
|
||||
_BV(ADSC) | // ADC start
|
||||
_BV(ADATE) | // Auto trigger
|
||||
_BV(ADIF) | // Reset interrupt flag
|
||||
_BV(ADPS2) | _BV(ADPS1); // 64:1 / 13 = 9615 Hz
|
||||
|
||||
// ADC conversion-ready bit is polled for each sample rather than using
|
||||
// an interrupt; avoids contention with application or other library
|
||||
// using ADC ISR for other things (there can be only one) while still
|
||||
// providing the speed & precise timing of free-run mode (a loop of
|
||||
// analogRead() won't get you that).
|
||||
adcMin = 1023;
|
||||
adcMax = 0;
|
||||
for(i=0; i<nSamples; i++) {
|
||||
while(!(ADCSRA & _BV(ADIF))); // Wait for ADC result
|
||||
adc = ADC; // 0-1023
|
||||
ADCSRA |= _BV(ADIF); // Clear bit
|
||||
if(adc < adcMin) adcMin = adc;
|
||||
if(adc > adcMax) adcMax = adc;
|
||||
}
|
||||
|
||||
ADMUX = admux_save; // Restore ADC config
|
||||
ADCSRB = adcsrb_save;
|
||||
ADCSRA = adcsra_save;
|
||||
(void)analogRead(A4); // Purge residue from ADC register
|
||||
|
||||
adcMin = abs(adcMin - DC_OFFSET);
|
||||
adcMax = abs(adcMax - DC_OFFSET);
|
||||
if(adcMin > DC_OFFSET) adcMin = DC_OFFSET;
|
||||
if(adcMax > DC_OFFSET) adcMax = DC_OFFSET;
|
||||
if(adcMin > adcMax) adcMax = adcMin;
|
||||
|
||||
return adcMax;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Captures ADC audio samples at maximum speed supported by 32u4 (9615 Hz).
|
||||
// Ostensibly for FFT code (below), but might have other uses. Uses ADC
|
||||
// free-run mode w/polling. Any currently-installed ADC interrupt handler
|
||||
// will be temporarily disabled while this runs. No other interrupts are
|
||||
// disabled; as long as interrupt handlers are minor (e.g. Timer/Counter 0
|
||||
// handling of millis() and micros()), this isn't likely to lose readings.
|
||||
|
||||
void Adafruit_CPlay_Mic::capture(int16_t *buf, uint8_t nSamples) {
|
||||
uint8_t admux_save, adcsra_save, adcsrb_save, timsk0_save, channel;
|
||||
int16_t adc;
|
||||
|
||||
channel = analogPinToChannel(4); // Pin A4 to ADC channel
|
||||
admux_save = ADMUX; // Save ADC config registers
|
||||
adcsra_save = ADCSRA;
|
||||
adcsrb_save = ADCSRB;
|
||||
|
||||
// Init ADC free-run mode; f = ( 8MHz/prescaler ) / 13 cycles/conversion
|
||||
ADCSRA = 0; // Stop ADC interrupt, if any
|
||||
ADMUX = _BV(REFS0) | channel; // Aref=AVcc, channel sel, right-adj
|
||||
ADCSRB = 0; // Free run mode, no high MUX bit
|
||||
ADCSRA = _BV(ADEN) | // ADC enable
|
||||
_BV(ADSC) | // ADC start
|
||||
_BV(ADATE) | // Auto trigger
|
||||
_BV(ADIF) | // Reset interrupt flag
|
||||
_BV(ADPS2) | _BV(ADPS1); // 64:1 / 13 = 9615 Hz
|
||||
|
||||
// ADC conversion-ready bit is polled for each sample rather than using
|
||||
// an interrupt; avoids contention with application or other library
|
||||
// using ADC ISR for other things (there can be only one) while still
|
||||
// providing the speed & precise timing of free-run mode (a loop of
|
||||
// analogRead() won't get you that).
|
||||
for(uint8_t i=0; i<nSamples; i++) {
|
||||
while(!(ADCSRA & _BV(ADIF))); // Wait for ADC result
|
||||
adc = ADC;
|
||||
ADCSRA |= _BV(ADIF); // Clear bit
|
||||
// FFT requires signed inputs; ADC output is unsigned. DC offset is
|
||||
// NOT 512 on Circuit Playground because it uses a 1.1V OpAmp input
|
||||
// as the midpoint, and may swing asymmetrically on the high side.
|
||||
// Sign-convert and then clip range to +/- DC_OFFSET.
|
||||
if(adc <= (DC_OFFSET - NOISE_THRESHOLD)) {
|
||||
adc -= DC_OFFSET;
|
||||
} else if(adc >= (DC_OFFSET + NOISE_THRESHOLD)) {
|
||||
adc -= DC_OFFSET;
|
||||
if(adc > (DC_OFFSET * 2)) adc = DC_OFFSET * 2;
|
||||
} else {
|
||||
adc = 0; // Below noise threshold
|
||||
}
|
||||
buf[i] = adc;
|
||||
}
|
||||
|
||||
ADMUX = admux_save; // Restore ADC config
|
||||
ADCSRB = adcsrb_save;
|
||||
ADCSRA = adcsra_save;
|
||||
(void)analogRead(A4); // Purge residue from ADC register
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Performs one cycle of fast Fourier transform (FFT) with audio captured
|
||||
// from mic on A4. Output is 32 'bins,' each covering an equal range of
|
||||
// frequencies from 0 to 4800 Hz (i.e. 0-150 Hz, 150-300 Hz, 300-450, etc).
|
||||
// Needs about 450 bytes free RAM to operate.
|
||||
|
||||
typedef struct {
|
||||
int16_t r;
|
||||
int16_t i;
|
||||
} complex_t;
|
||||
|
||||
extern "C" { // In ffft.S
|
||||
void fft_input(const int16_t *, complex_t *),
|
||||
fft_execute(complex_t *),
|
||||
fft_output(complex_t *, uint16_t *);
|
||||
}
|
||||
|
||||
void Adafruit_CPlay_Mic::fft(
|
||||
uint16_t *spectrum) { // Spectrum output buffer, uint16_t[32]
|
||||
if(spectrum) {
|
||||
int16_t capBuf[64]; // Audio capture buffer
|
||||
complex_t butterfly[64]; // FFT "butterfly" buffer
|
||||
|
||||
capture(capBuf, 64); // Collect mic data into capBuf
|
||||
fft_input(capBuf, butterfly); // Samples -> complex #s
|
||||
fft_execute(butterfly); // Process complex data
|
||||
fft_output(butterfly, spectrum); // Complex -> spectrum (32 bins)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Adafruit Circuit Playground microphone library
|
||||
// by Phil Burgess / Paint Your Dragon.
|
||||
// Fast Fourier transform section is derived from
|
||||
// ELM-ChaN FFT library (see comments in ffft.S).
|
||||
|
||||
#ifndef ADAFRUIT_CPLAY_MIC_H
|
||||
#define ADAFRUIT_CPLAY_MIC_H
|
||||
|
||||
class Adafruit_CPlay_Mic {
|
||||
public:
|
||||
Adafruit_CPlay_Mic(void) {}; // Empty constructor
|
||||
int peak(uint16_t ms);
|
||||
void capture(int16_t *buf, uint8_t nSamples),
|
||||
fft(uint16_t *spectrum);
|
||||
};
|
||||
|
||||
#endif // ADAFRUIT_CPLAY_MIC_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,179 @@
|
||||
/*--------------------------------------------------------------------
|
||||
This file is part of the Adafruit NeoPixel library.
|
||||
|
||||
NeoPixel 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 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
NeoPixel 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 NeoPixel. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
--------------------------------------------------------------------*/
|
||||
|
||||
#ifndef ADAFRUIT_CPLAY_NEOPIXEL_H
|
||||
#define ADAFRUIT_CPLAY_NEOPIXEL_H
|
||||
|
||||
#if (ARDUINO >= 100)
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#include <pins_arduino.h>
|
||||
#endif
|
||||
|
||||
// The order of primary colors in the NeoPixel data stream can vary
|
||||
// among device types, manufacturers and even different revisions of
|
||||
// the same item. The third parameter to the Adafruit_NeoPixel
|
||||
// constructor encodes the per-pixel byte offsets of the red, green
|
||||
// and blue primaries (plus white, if present) in the data stream --
|
||||
// the following #defines provide an easier-to-use named version for
|
||||
// each permutation. e.g. NEO_GRB indicates a NeoPixel-compatible
|
||||
// device expecting three bytes per pixel, with the first byte
|
||||
// containing the green value, second containing red and third
|
||||
// containing blue. The in-memory representation of a chain of
|
||||
// NeoPixels is the same as the data-stream order; no re-ordering of
|
||||
// bytes is required when issuing data to the chain.
|
||||
|
||||
// Bits 5,4 of this value are the offset (0-3) from the first byte of
|
||||
// a pixel to the location of the red color byte. Bits 3,2 are the
|
||||
// green offset and 1,0 are the blue offset. If it is an RGBW-type
|
||||
// device (supporting a white primary in addition to R,G,B), bits 7,6
|
||||
// are the offset to the white byte...otherwise, bits 7,6 are set to
|
||||
// the same value as 5,4 (red) to indicate an RGB (not RGBW) device.
|
||||
// i.e. binary representation:
|
||||
// 0bWWRRGGBB for RGBW devices
|
||||
// 0bRRRRGGBB for RGB
|
||||
|
||||
// RGB NeoPixel permutations; white and red offsets are always same
|
||||
// Offset: W R G B
|
||||
#define NEO_RGB ((0 << 6) | (0 << 4) | (1 << 2) | (2))
|
||||
#define NEO_RBG ((0 << 6) | (0 << 4) | (2 << 2) | (1))
|
||||
#define NEO_GRB ((1 << 6) | (1 << 4) | (0 << 2) | (2))
|
||||
#define NEO_GBR ((2 << 6) | (2 << 4) | (0 << 2) | (1))
|
||||
#define NEO_BRG ((1 << 6) | (1 << 4) | (2 << 2) | (0))
|
||||
#define NEO_BGR ((2 << 6) | (2 << 4) | (1 << 2) | (0))
|
||||
|
||||
// RGBW NeoPixel permutations; all 4 offsets are distinct
|
||||
// Offset: W R G B
|
||||
#define NEO_WRGB ((0 << 6) | (1 << 4) | (2 << 2) | (3))
|
||||
#define NEO_WRBG ((0 << 6) | (1 << 4) | (3 << 2) | (2))
|
||||
#define NEO_WGRB ((0 << 6) | (2 << 4) | (1 << 2) | (3))
|
||||
#define NEO_WGBR ((0 << 6) | (3 << 4) | (1 << 2) | (2))
|
||||
#define NEO_WBRG ((0 << 6) | (2 << 4) | (3 << 2) | (1))
|
||||
#define NEO_WBGR ((0 << 6) | (3 << 4) | (2 << 2) | (1))
|
||||
|
||||
#define NEO_RWGB ((1 << 6) | (0 << 4) | (2 << 2) | (3))
|
||||
#define NEO_RWBG ((1 << 6) | (0 << 4) | (3 << 2) | (2))
|
||||
#define NEO_RGWB ((2 << 6) | (0 << 4) | (1 << 2) | (3))
|
||||
#define NEO_RGBW ((3 << 6) | (0 << 4) | (1 << 2) | (2))
|
||||
#define NEO_RBWG ((2 << 6) | (0 << 4) | (3 << 2) | (1))
|
||||
#define NEO_RBGW ((3 << 6) | (0 << 4) | (2 << 2) | (1))
|
||||
|
||||
#define NEO_GWRB ((1 << 6) | (2 << 4) | (0 << 2) | (3))
|
||||
#define NEO_GWBR ((1 << 6) | (3 << 4) | (0 << 2) | (2))
|
||||
#define NEO_GRWB ((2 << 6) | (1 << 4) | (0 << 2) | (3))
|
||||
#define NEO_GRBW ((3 << 6) | (1 << 4) | (0 << 2) | (2))
|
||||
#define NEO_GBWR ((2 << 6) | (3 << 4) | (0 << 2) | (1))
|
||||
#define NEO_GBRW ((3 << 6) | (2 << 4) | (0 << 2) | (1))
|
||||
|
||||
#define NEO_BWRG ((1 << 6) | (2 << 4) | (3 << 2) | (0))
|
||||
#define NEO_BWGR ((1 << 6) | (3 << 4) | (2 << 2) | (0))
|
||||
#define NEO_BRWG ((2 << 6) | (1 << 4) | (3 << 2) | (0))
|
||||
#define NEO_BRGW ((3 << 6) | (1 << 4) | (2 << 2) | (0))
|
||||
#define NEO_BGWR ((2 << 6) | (3 << 4) | (1 << 2) | (0))
|
||||
#define NEO_BGRW ((3 << 6) | (2 << 4) | (1 << 2) | (0))
|
||||
|
||||
// Add NEO_KHZ400 to the color order value to indicate a 400 KHz
|
||||
// device. All but the earliest v1 NeoPixels expect an 800 KHz data
|
||||
// stream, this is the default if unspecified. Because flash space
|
||||
// is very limited on ATtiny devices (e.g. Trinket, Gemma), v1
|
||||
// NeoPixels aren't handled by default on those chips, though it can
|
||||
// be enabled by removing the ifndef/endif below -- but code will be
|
||||
// bigger. Conversely, can disable the NEO_KHZ400 line on other MCUs
|
||||
// to remove v1 support and save a little space.
|
||||
|
||||
#define NEO_KHZ800 0x0000 // 800 KHz datastream
|
||||
#ifndef __AVR_ATtiny85__
|
||||
#define NEO_KHZ400 0x0100 // 400 KHz datastream
|
||||
#endif
|
||||
|
||||
// If 400 KHz support is enabled, the third parameter to the constructor
|
||||
// requires a 16-bit value (in order to select 400 vs 800 KHz speed).
|
||||
// If only 800 KHz is enabled (as is default on ATtiny), an 8-bit value
|
||||
// is sufficient to encode pixel color order, saving some space.
|
||||
|
||||
#ifdef NEO_KHZ400
|
||||
typedef uint16_t neoPixelType;
|
||||
#else
|
||||
typedef uint8_t neoPixelType;
|
||||
#endif
|
||||
|
||||
class Adafruit_CPlay_NeoPixel {
|
||||
|
||||
public:
|
||||
|
||||
// Constructor: number of LEDs, pin number, LED type
|
||||
Adafruit_CPlay_NeoPixel(uint16_t n, uint8_t p=6, neoPixelType t=NEO_GRB + NEO_KHZ800);
|
||||
Adafruit_CPlay_NeoPixel(void);
|
||||
~Adafruit_CPlay_NeoPixel();
|
||||
|
||||
void
|
||||
begin(void),
|
||||
show(void),
|
||||
setPin(uint8_t p),
|
||||
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b),
|
||||
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w),
|
||||
setPixelColor(uint16_t n, uint32_t c),
|
||||
setBrightness(uint8_t),
|
||||
clear(),
|
||||
updateLength(uint16_t n),
|
||||
updateType(neoPixelType t);
|
||||
uint8_t
|
||||
*getPixels(void) const,
|
||||
getBrightness(void) const;
|
||||
uint16_t
|
||||
numPixels(void) const;
|
||||
static uint32_t
|
||||
Color(uint8_t r, uint8_t g, uint8_t b),
|
||||
Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w);
|
||||
uint32_t
|
||||
getPixelColor(uint16_t n) const;
|
||||
inline bool
|
||||
canShow(void) { return (micros() - endTime) >= 50L; }
|
||||
|
||||
private:
|
||||
|
||||
boolean
|
||||
#ifdef NEO_KHZ400 // If 400 KHz NeoPixel support enabled...
|
||||
is800KHz, // ...true if 800 KHz pixels
|
||||
#endif
|
||||
begun; // true if begin() previously called
|
||||
uint16_t
|
||||
numLEDs, // Number of RGB LEDs in strip
|
||||
numBytes; // Size of 'pixels' buffer below (3 or 4 bytes/pixel)
|
||||
int8_t
|
||||
pin; // Output pin number (-1 if not yet set)
|
||||
uint8_t
|
||||
brightness,
|
||||
*pixels, // Holds LED color values (3 or 4 bytes each)
|
||||
rOffset, // Index of red byte within each 3- or 4-byte pixel
|
||||
gOffset, // Index of green byte
|
||||
bOffset, // Index of blue byte
|
||||
wOffset; // Index of white byte (same as rOffset if no white)
|
||||
uint32_t
|
||||
endTime; // Latch timing reference
|
||||
#ifdef __AVR__
|
||||
volatile uint8_t
|
||||
*port; // Output PORT register
|
||||
uint8_t
|
||||
pinMask; // Output PORT bitmask
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif // ADAFRUIT_CPLAY_NEOPIXEL_H
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software< /span>
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* Update by K. Townsend (Adafruit Industries) for lighter typedefs, and
|
||||
* extended sensor support to include color, voltage and current */
|
||||
|
||||
#ifndef _ADAFRUIT_SENSOR_H
|
||||
#define _ADAFRUIT_SENSOR_H
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#include "Print.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
/* Intentionally modeled after sensors.h in the Android API:
|
||||
* https://github.com/android/platform_hardware_libhardware/blob/master/include/hardware/sensors.h */
|
||||
|
||||
/* Constants */
|
||||
#define SENSORS_GRAVITY_EARTH (9.80665F) /**< Earth's gravity in m/s^2 */
|
||||
#define SENSORS_GRAVITY_MOON (1.6F) /**< The moon's gravity in m/s^2 */
|
||||
#define SENSORS_GRAVITY_SUN (275.0F) /**< The sun's gravity in m/s^2 */
|
||||
#define SENSORS_GRAVITY_STANDARD (SENSORS_GRAVITY_EARTH)
|
||||
#define SENSORS_MAGFIELD_EARTH_MAX (60.0F) /**< Maximum magnetic field on Earth's surface */
|
||||
#define SENSORS_MAGFIELD_EARTH_MIN (30.0F) /**< Minimum magnetic field on Earth's surface */
|
||||
#define SENSORS_PRESSURE_SEALEVELHPA (1013.25F) /**< Average sea level pressure is 1013.25 hPa */
|
||||
#define SENSORS_DPS_TO_RADS (0.017453293F) /**< Degrees/s to rad/s multiplier */
|
||||
#define SENSORS_GAUSS_TO_MICROTESLA (100) /**< Gauss to micro-Tesla multiplier */
|
||||
|
||||
/** Sensor types */
|
||||
typedef enum
|
||||
{
|
||||
SENSOR_TYPE_ACCELEROMETER = (1), /**< Gravity + linear acceleration */
|
||||
SENSOR_TYPE_MAGNETIC_FIELD = (2),
|
||||
SENSOR_TYPE_ORIENTATION = (3),
|
||||
SENSOR_TYPE_GYROSCOPE = (4),
|
||||
SENSOR_TYPE_LIGHT = (5),
|
||||
SENSOR_TYPE_PRESSURE = (6),
|
||||
SENSOR_TYPE_PROXIMITY = (8),
|
||||
SENSOR_TYPE_GRAVITY = (9),
|
||||
SENSOR_TYPE_LINEAR_ACCELERATION = (10), /**< Acceleration not including gravity */
|
||||
SENSOR_TYPE_ROTATION_VECTOR = (11),
|
||||
SENSOR_TYPE_RELATIVE_HUMIDITY = (12),
|
||||
SENSOR_TYPE_AMBIENT_TEMPERATURE = (13),
|
||||
SENSOR_TYPE_OBJECT_TEMPERATURE = (14),
|
||||
SENSOR_TYPE_VOLTAGE = (15),
|
||||
SENSOR_TYPE_CURRENT = (16),
|
||||
SENSOR_TYPE_COLOR = (17)
|
||||
} sensors_type_t;
|
||||
|
||||
/** struct sensors_vec_s is used to return a vector in a common format. */
|
||||
typedef struct {
|
||||
union {
|
||||
float v[3];
|
||||
struct {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
};
|
||||
/* Orientation sensors */
|
||||
struct {
|
||||
float roll; /**< Rotation around the longitudinal axis (the plane body, 'X axis'). Roll is positive and increasing when moving downward. -90°<=roll<=90° */
|
||||
float pitch; /**< Rotation around the lateral axis (the wing span, 'Y axis'). Pitch is positive and increasing when moving upwards. -180°<=pitch<=180°) */
|
||||
float heading; /**< Angle between the longitudinal axis (the plane body) and magnetic north, measured clockwise when viewing from the top of the device. 0-359° */
|
||||
};
|
||||
};
|
||||
int8_t status;
|
||||
uint8_t reserved[3];
|
||||
} sensors_vec_t;
|
||||
|
||||
/** struct sensors_color_s is used to return color data in a common format. */
|
||||
typedef struct {
|
||||
union {
|
||||
float c[3];
|
||||
/* RGB color space */
|
||||
struct {
|
||||
float r; /**< Red component */
|
||||
float g; /**< Green component */
|
||||
float b; /**< Blue component */
|
||||
};
|
||||
};
|
||||
uint32_t rgba; /**< 24-bit RGBA value */
|
||||
} sensors_color_t;
|
||||
|
||||
/* Sensor event (36 bytes) */
|
||||
/** struct sensor_event_s is used to provide a single sensor event in a common format. */
|
||||
typedef struct
|
||||
{
|
||||
int32_t version; /**< must be sizeof(struct sensors_event_t) */
|
||||
int32_t sensor_id; /**< unique sensor identifier */
|
||||
int32_t type; /**< sensor type */
|
||||
int32_t reserved0; /**< reserved */
|
||||
int32_t timestamp; /**< time is in milliseconds */
|
||||
union
|
||||
{
|
||||
float data[4];
|
||||
sensors_vec_t acceleration; /**< acceleration values are in meter per second per second (m/s^2) */
|
||||
sensors_vec_t magnetic; /**< magnetic vector values are in micro-Tesla (uT) */
|
||||
sensors_vec_t orientation; /**< orientation values are in degrees */
|
||||
sensors_vec_t gyro; /**< gyroscope values are in rad/s */
|
||||
float temperature; /**< temperature is in degrees centigrade (Celsius) */
|
||||
float distance; /**< distance in centimeters */
|
||||
float light; /**< light in SI lux units */
|
||||
float pressure; /**< pressure in hectopascal (hPa) */
|
||||
float relative_humidity; /**< relative humidity in percent */
|
||||
float current; /**< current in milliamps (mA) */
|
||||
float voltage; /**< voltage in volts (V) */
|
||||
sensors_color_t color; /**< color in RGB component values */
|
||||
};
|
||||
} sensors_event_t;
|
||||
|
||||
/* Sensor details (40 bytes) */
|
||||
/** struct sensor_s is used to describe basic information about a specific sensor. */
|
||||
typedef struct
|
||||
{
|
||||
char name[12]; /**< sensor name */
|
||||
int32_t version; /**< version of the hardware + driver */
|
||||
int32_t sensor_id; /**< unique sensor identifier */
|
||||
int32_t type; /**< this sensor's type (ex. SENSOR_TYPE_LIGHT) */
|
||||
float max_value; /**< maximum value of this sensor's value in SI units */
|
||||
float min_value; /**< minimum value of this sensor's value in SI units */
|
||||
float resolution; /**< smallest difference between two values reported by this sensor */
|
||||
int32_t min_delay; /**< min delay in microseconds between events. zero = not a constant rate */
|
||||
} sensor_t;
|
||||
|
||||
class Adafruit_Sensor {
|
||||
public:
|
||||
// Constructor(s)
|
||||
Adafruit_Sensor() {}
|
||||
virtual ~Adafruit_Sensor() {}
|
||||
|
||||
// These must be defined by the subclass
|
||||
virtual void enableAutoRange(bool enabled) {};
|
||||
virtual bool getEvent(sensors_event_t*) = 0;
|
||||
virtual void getSensor(sensor_t*) = 0;
|
||||
|
||||
private:
|
||||
bool _autoRange;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,90 @@
|
||||
// Adafruit Circuit Playground speaker library
|
||||
// by Phil Burgess / Paint Your Dragon.
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "Adafruit_CPlay_Speaker.h"
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Sets up Circuit Playground speaker for PWM audio output: enables 48 KHz
|
||||
// high-speed PWM mode, configures Timer/Counter 4, sets PWM duty cycle to
|
||||
// 50% (speaker idle position).
|
||||
|
||||
void Adafruit_CPlay_Speaker::begin(void) {
|
||||
// Set up Timer4 for fast PWM on !OC4A
|
||||
PLLFRQ = (PLLFRQ & 0xCF) | 0x30; // Route PLL to async clk
|
||||
TCCR4A = _BV(COM4A0) | _BV(PWM4A); // Clear on match, PWMA on
|
||||
TCCR4B = _BV(PWM4X) |_BV(CS40); // PWM invert, 1:1 prescale
|
||||
TCCR4D = 0; // Fast PWM mode
|
||||
TCCR4E = 0; // Not enhanced mode
|
||||
TC4H = 0; // Not 10-bit mode
|
||||
DT4 = 0; // No dead time
|
||||
OCR4C = 255; // TOP
|
||||
OCR4A = 127; // 50% duty (idle position) to start
|
||||
started = true;
|
||||
pinMode(5, OUTPUT); // Enable output
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Turns off PWM output to the speaker.
|
||||
|
||||
void Adafruit_CPlay_Speaker::end(void) {
|
||||
pinMode(5, INPUT);
|
||||
TCCR4A = 0; // PWMA off
|
||||
started = false;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Sets speaker position (0-255; 127=idle), enables PWM output if needed.
|
||||
|
||||
void Adafruit_CPlay_Speaker::set(uint8_t value) {
|
||||
if(!started) begin();
|
||||
TCCR4A = value;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Plays digitized 8-bit audio from a PROGMEM (flash memory) buffer. Maybe
|
||||
// 1-3 seconds tops depending on sampling rate (e.g. 8000 Hz data =
|
||||
// 8 Kbytes/second). Max ~20K space avail on Circuit Playground.
|
||||
// This function currently "blocks" -- it will not play sounds in the
|
||||
// background while other code runs.
|
||||
|
||||
void Adafruit_CPlay_Speaker::playSound(
|
||||
const uint8_t *data, uint16_t bytesToGo, uint16_t sampleRate) {
|
||||
|
||||
if(sampleRate < 7620) sampleRate = 7620; // Because 8-bit delay counter
|
||||
|
||||
uint8_t interval = (F_CPU / 4 + sampleRate / 2) / sampleRate - 6,
|
||||
x, counter;
|
||||
|
||||
if(!started) begin();
|
||||
|
||||
// Trying cycle counting here (instead of interrupt) to avoid ISR
|
||||
// conflicts (some sketches may need their own timers or related
|
||||
// interrupts -- a precious resource!). Could also try this using
|
||||
// micros(), but that might lack adequate resolution.
|
||||
asm volatile(
|
||||
"movw r30 , %[data]" "\n\t" // Z = data
|
||||
"audioSampleLoop:"
|
||||
"lpm %[x] , Z+" "\n\t" // x = pgm_read_byte(data++)
|
||||
"sts %[pwmReg] , %[x]" "\n\t" // OCR4A = x
|
||||
"mov %[counter] , %[interval]" "\n\t" // counter = interval
|
||||
"audioDelayLoop:" "\n\t"
|
||||
"nop" "\n\t"
|
||||
"dec %[counter]" "\n\t" // counter--
|
||||
"brne audioDelayLoop" "\n\t" // if(counter) goto audioDelay
|
||||
"sbiw %[bytesToGo], 1" "\n\t" // bytesToGo--
|
||||
"brne audioSampleLoop" "\n" // if(bytesToGo) goto audioSample
|
||||
: [x] "+r" (x),
|
||||
[counter] "+r" (counter),
|
||||
[bytesToGo] "+w" (bytesToGo)
|
||||
: [data] "e" (data),
|
||||
[pwmReg] "M" (_SFR_ADDR(OCR4A)),
|
||||
[interval] "r" (interval)
|
||||
: "r30", "r31" ); // Z is clobbered
|
||||
|
||||
OCR4A = 127; // Idle position for next sound
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Adafruit Circuit Playground speaker library
|
||||
// by Phil Burgess / Paint Your Dragon.
|
||||
|
||||
#ifndef ADAFRUIT_CPLAY_SPEAKER_H
|
||||
#define ADAFRUIT_CPLAY_SPEAKER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
class Adafruit_CPlay_Speaker {
|
||||
public:
|
||||
Adafruit_CPlay_Speaker(void) { started = false; };
|
||||
void begin(void),
|
||||
end(void),
|
||||
set(uint8_t value),
|
||||
playSound(const uint8_t *data, uint16_t length, uint16_t sampleRate),
|
||||
say(const uint8_t *address);
|
||||
|
||||
private:
|
||||
boolean started;
|
||||
};
|
||||
|
||||
#endif // ADAFRUIT_CPLAY_SPEAKER_H
|
||||
@@ -0,0 +1,805 @@
|
||||
/*
|
||||
Boards.h - Hardware Abstraction Layer for Firmata library
|
||||
Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved.
|
||||
Copyright (C) 2009-2016 Jeff Hoefs. All rights 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.
|
||||
|
||||
See file LICENSE.txt for further informations on licensing terms.
|
||||
|
||||
Last updated April 10th, 2016
|
||||
*/
|
||||
|
||||
#ifndef Firmata_Boards_h
|
||||
#define Firmata_Boards_h
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include "Arduino.h" // for digitalRead, digitalWrite, etc
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
// Normally Servo.h must be included before Firmata.h (which then includes
|
||||
// this file). If Servo.h wasn't included, this allows the code to still
|
||||
// compile, but without support for any Servos. Hopefully that's what the
|
||||
// user intended by not including Servo.h
|
||||
#ifndef MAX_SERVOS
|
||||
#define MAX_SERVOS 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
Firmata Hardware Abstraction Layer
|
||||
|
||||
Firmata is built on top of the hardware abstraction functions of Arduino,
|
||||
specifically digitalWrite, digitalRead, analogWrite, analogRead, and
|
||||
pinMode. While these functions offer simple integer pin numbers, Firmata
|
||||
needs more information than is provided by Arduino. This file provides
|
||||
all other hardware specific details. To make Firmata support a new board,
|
||||
only this file should require editing.
|
||||
|
||||
The key concept is every "pin" implemented by Firmata may be mapped to
|
||||
any pin as implemented by Arduino. Usually a simple 1-to-1 mapping is
|
||||
best, but such mapping should not be assumed. This hardware abstraction
|
||||
layer allows Firmata to implement any number of pins which map onto the
|
||||
Arduino implemented pins in almost any arbitrary way.
|
||||
|
||||
|
||||
General Constants:
|
||||
|
||||
These constants provide basic information Firmata requires.
|
||||
|
||||
TOTAL_PINS: The total number of pins Firmata implemented by Firmata.
|
||||
Usually this will match the number of pins the Arduino functions
|
||||
implement, including any pins pins capable of analog or digital.
|
||||
However, Firmata may implement any number of pins. For example,
|
||||
on Arduino Mini with 8 analog inputs, 6 of these may be used
|
||||
for digital functions, and 2 are analog only. On such boards,
|
||||
Firmata can implement more pins than Arduino's pinMode()
|
||||
function, in order to accommodate those special pins. The
|
||||
Firmata protocol supports a maximum of 128 pins, so this
|
||||
constant must not exceed 128.
|
||||
|
||||
TOTAL_ANALOG_PINS: The total number of analog input pins implemented.
|
||||
The Firmata protocol allows up to 16 analog inputs, accessed
|
||||
using offsets 0 to 15. Because Firmata presents the analog
|
||||
inputs using different offsets than the actual pin numbers
|
||||
(a legacy of Arduino's analogRead function, and the way the
|
||||
analog input capable pins are physically labeled on all
|
||||
Arduino boards), the total number of analog input signals
|
||||
must be specified. 16 is the maximum.
|
||||
|
||||
VERSION_BLINK_PIN: When Firmata starts up, it will blink the version
|
||||
number. This constant is the Arduino pin number where a
|
||||
LED is connected.
|
||||
|
||||
|
||||
Pin Mapping Macros:
|
||||
|
||||
These macros provide the mapping between pins as implemented by
|
||||
Firmata protocol and the actual pin numbers used by the Arduino
|
||||
functions. Even though such mappings are often simple, pin
|
||||
numbers received by Firmata protocol should always be used as
|
||||
input to these macros, and the result of the macro should be
|
||||
used with with any Arduino function.
|
||||
|
||||
When Firmata is extended to support a new pin mode or feature,
|
||||
a pair of macros should be added and used for all hardware
|
||||
access. For simple 1:1 mapping, these macros add no actual
|
||||
overhead, yet their consistent use allows source code which
|
||||
uses them consistently to be easily adapted to all other boards
|
||||
with different requirements.
|
||||
|
||||
IS_PIN_XXXX(pin): The IS_PIN macros resolve to true or non-zero
|
||||
if a pin as implemented by Firmata corresponds to a pin
|
||||
that actually implements the named feature.
|
||||
|
||||
PIN_TO_XXXX(pin): The PIN_TO macros translate pin numbers as
|
||||
implemented by Firmata to the pin numbers needed as inputs
|
||||
to the Arduino functions. The corresponding IS_PIN macro
|
||||
should always be tested before using a PIN_TO macro, so
|
||||
these macros only need to handle valid Firmata pin
|
||||
numbers for the named feature.
|
||||
|
||||
|
||||
Port Access Inline Funtions:
|
||||
|
||||
For efficiency, Firmata protocol provides access to digital
|
||||
input and output pins grouped by 8 bit ports. When these
|
||||
groups of 8 correspond to actual 8 bit ports as implemented
|
||||
by the hardware, these inline functions can provide high
|
||||
speed direct port access. Otherwise, a default implementation
|
||||
using 8 calls to digitalWrite or digitalRead is used.
|
||||
|
||||
When porting Firmata to a new board, it is recommended to
|
||||
use the default functions first and focus only on the constants
|
||||
and macros above. When those are working, if optimized port
|
||||
access is desired, these inline functions may be extended.
|
||||
The recommended approach defines a symbol indicating which
|
||||
optimization to use, and then conditional complication is
|
||||
used within these functions.
|
||||
|
||||
readPort(port, bitmask): Read an 8 bit port, returning the value.
|
||||
port: The port number, Firmata pins port*8 to port*8+7
|
||||
bitmask: The actual pins to read, indicated by 1 bits.
|
||||
|
||||
writePort(port, value, bitmask): Write an 8 bit port.
|
||||
port: The port number, Firmata pins port*8 to port*8+7
|
||||
value: The 8 bit value to write
|
||||
bitmask: The actual pins to write, indicated by 1 bits.
|
||||
*/
|
||||
|
||||
/*==============================================================================
|
||||
* Board Specific Configuration
|
||||
*============================================================================*/
|
||||
|
||||
#ifndef digitalPinHasPWM
|
||||
#define digitalPinHasPWM(p) IS_PIN_DIGITAL(p)
|
||||
#endif
|
||||
|
||||
// Arduino Duemilanove, Diecimila, and NG
|
||||
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)
|
||||
#if defined(NUM_ANALOG_INPUTS) && NUM_ANALOG_INPUTS == 6
|
||||
#define TOTAL_ANALOG_PINS 6
|
||||
#define TOTAL_PINS 20 // 14 digital + 6 analog
|
||||
#else
|
||||
#define TOTAL_ANALOG_PINS 8
|
||||
#define TOTAL_PINS 22 // 14 digital + 8 analog
|
||||
#endif
|
||||
#define VERSION_BLINK_PIN 13
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19)
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS)
|
||||
#define IS_PIN_PWM(p) digitalPinHasPWM(p)
|
||||
#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) ((p) == 18 || (p) == 19)
|
||||
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 14)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) ((p) - 2)
|
||||
#define ARDUINO_PINOUT_OPTIMIZE 1
|
||||
|
||||
|
||||
// Wiring (and board)
|
||||
#elif defined(WIRING)
|
||||
#define VERSION_BLINK_PIN WLED
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_ANALOG(p) ((p) >= FIRST_ANALOG_PIN && (p) < (FIRST_ANALOG_PIN+TOTAL_ANALOG_PINS))
|
||||
#define IS_PIN_PWM(p) digitalPinHasPWM(p)
|
||||
#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL)
|
||||
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - FIRST_ANALOG_PIN)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) (p)
|
||||
|
||||
|
||||
// old Arduinos
|
||||
#elif defined(__AVR_ATmega8__)
|
||||
#define TOTAL_ANALOG_PINS 6
|
||||
#define TOTAL_PINS 20 // 14 digital + 6 analog
|
||||
#define VERSION_BLINK_PIN 13
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19)
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 19)
|
||||
#define IS_PIN_PWM(p) digitalPinHasPWM(p)
|
||||
#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) ((p) == 18 || (p) == 19)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 14)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) ((p) - 2)
|
||||
#define ARDUINO_PINOUT_OPTIMIZE 1
|
||||
|
||||
|
||||
// Arduino Mega
|
||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
#define TOTAL_ANALOG_PINS 16
|
||||
#define TOTAL_PINS 70 // 54 digital + 16 analog
|
||||
#define VERSION_BLINK_PIN 13
|
||||
#define PIN_SERIAL1_RX 19
|
||||
#define PIN_SERIAL1_TX 18
|
||||
#define PIN_SERIAL2_RX 17
|
||||
#define PIN_SERIAL2_TX 16
|
||||
#define PIN_SERIAL3_RX 15
|
||||
#define PIN_SERIAL3_TX 14
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 54 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_PWM(p) digitalPinHasPWM(p)
|
||||
#define IS_PIN_SERVO(p) ((p) >= 2 && (p) - 2 < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) ((p) == 20 || (p) == 21)
|
||||
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
|
||||
#define IS_PIN_SERIAL(p) ((p) > 13 && (p) < 20)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 54)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) ((p) - 2)
|
||||
|
||||
|
||||
// Arduino DUE
|
||||
#elif defined(__SAM3X8E__)
|
||||
#define TOTAL_ANALOG_PINS 12
|
||||
#define TOTAL_PINS 66 // 54 digital + 12 analog
|
||||
#define VERSION_BLINK_PIN 13
|
||||
#define PIN_SERIAL1_RX 19
|
||||
#define PIN_SERIAL1_TX 18
|
||||
#define PIN_SERIAL2_RX 17
|
||||
#define PIN_SERIAL2_TX 16
|
||||
#define PIN_SERIAL3_RX 15
|
||||
#define PIN_SERIAL3_TX 14
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 54 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_PWM(p) digitalPinHasPWM(p)
|
||||
#define IS_PIN_SERVO(p) ((p) >= 2 && (p) - 2 < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) ((p) == 20 || (p) == 21) // 70 71
|
||||
#define IS_PIN_SERIAL(p) ((p) > 13 && (p) < 20)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 54)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) ((p) - 2)
|
||||
|
||||
|
||||
// Arduino/Genuino MKR1000
|
||||
#elif defined(ARDUINO_SAMD_MKR1000)
|
||||
#define TOTAL_ANALOG_PINS 7
|
||||
#define TOTAL_PINS 22 // 8 digital + 3 spi + 2 i2c + 2 uart + 7 analog
|
||||
#define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 21) && !IS_PIN_SERIAL(p))
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 15 && (p) < 15 + TOTAL_ANALOG_PINS)
|
||||
#define IS_PIN_PWM(p) digitalPinHasPWM(p)
|
||||
#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4
|
||||
#define IS_PIN_I2C(p) ((p) == 11 || (p) == 12) // SDA = 11, SCL = 12
|
||||
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
|
||||
#define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL1_RX || (p) == PIN_SERIAL1_TX) //defined in variant.h RX = 13, TX = 14
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 15)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) (p) // deprecated since v2.4
|
||||
|
||||
|
||||
// Arduino Zero
|
||||
// Note this will work with an Arduino Zero Pro, but not with an Arduino M0 Pro
|
||||
// Arduino M0 Pro does not properly map pins to the board labeled pin numbers
|
||||
#elif defined(_VARIANT_ARDUINO_ZERO_)
|
||||
#define TOTAL_ANALOG_PINS 6
|
||||
#define TOTAL_PINS 25 // 14 digital + 6 analog + 2 i2c + 3 spi
|
||||
#define TOTAL_PORTS 3 // set when TOTAL_PINS > num digitial I/O pins
|
||||
#define VERSION_BLINK_PIN LED_BUILTIN
|
||||
//#define PIN_SERIAL1_RX 0 // already defined in zero core variant.h
|
||||
//#define PIN_SERIAL1_TX 1 // already defined in zero core variant.h
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 19)
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS)
|
||||
#define IS_PIN_PWM(p) digitalPinHasPWM(p)
|
||||
#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4
|
||||
#define IS_PIN_I2C(p) ((p) == 20 || (p) == 21) // SDA = 20, SCL = 21
|
||||
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK) // SS = A2
|
||||
#define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 14)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) (p) // deprecated since v2.4
|
||||
|
||||
|
||||
// Arduino 101
|
||||
#elif defined(_VARIANT_ARDUINO_101_X_)
|
||||
#define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS
|
||||
#define TOTAL_PINS NUM_DIGITAL_PINS // 15 digital (including ATN pin) + 6 analog
|
||||
#define VERSION_BLINK_PIN LED_BUILTIN
|
||||
#define PIN_SERIAL1_RX 0
|
||||
#define PIN_SERIAL1_TX 1
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 20)
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS)
|
||||
#define IS_PIN_PWM(p) digitalPinHasPWM(p) // 3, 5, 6, 9
|
||||
#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS) // deprecated since v2.4
|
||||
#define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL) // SDA = 18, SCL = 19
|
||||
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
|
||||
#define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 14)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) (p) // deprecated since v2.4
|
||||
|
||||
|
||||
// Teensy 1.0
|
||||
#elif defined(__AVR_AT90USB162__)
|
||||
#define TOTAL_ANALOG_PINS 0
|
||||
#define TOTAL_PINS 21 // 21 digital + no analog
|
||||
#define VERSION_BLINK_PIN 6
|
||||
#define PIN_SERIAL1_RX 2
|
||||
#define PIN_SERIAL1_TX 3
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_ANALOG(p) (0)
|
||||
#define IS_PIN_PWM(p) digitalPinHasPWM(p)
|
||||
#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) (0)
|
||||
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
|
||||
#define IS_PIN_SERIAL(p) ((p) == 2 || (p) == 3)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) (0)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) (p)
|
||||
|
||||
|
||||
// Teensy 2.0
|
||||
#elif defined(__AVR_ATmega32U4__) && defined(CORE_TEENSY)
|
||||
#define TOTAL_ANALOG_PINS 12
|
||||
#define TOTAL_PINS 25 // 11 digital + 12 analog
|
||||
#define VERSION_BLINK_PIN 11
|
||||
#define PIN_SERIAL1_RX 7
|
||||
#define PIN_SERIAL1_TX 8
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 11 && (p) <= 22)
|
||||
#define IS_PIN_PWM(p) digitalPinHasPWM(p)
|
||||
#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) ((p) == 5 || (p) == 6)
|
||||
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
|
||||
#define IS_PIN_SERIAL(p) ((p) == 7 || (p) == 8)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) (((p) < 22) ? 21 - (p) : 11)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) (p)
|
||||
|
||||
|
||||
// Teensy 3.0, 3.1 and 3.2
|
||||
#elif defined(__MK20DX128__) || defined(__MK20DX256__)
|
||||
#define TOTAL_ANALOG_PINS 14
|
||||
#define TOTAL_PINS 38 // 24 digital + 10 analog-digital + 4 analog
|
||||
#define VERSION_BLINK_PIN 13
|
||||
#define PIN_SERIAL1_RX 0
|
||||
#define PIN_SERIAL1_TX 1
|
||||
#define PIN_SERIAL2_RX 9
|
||||
#define PIN_SERIAL2_TX 10
|
||||
#define PIN_SERIAL3_RX 7
|
||||
#define PIN_SERIAL3_TX 8
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 33)
|
||||
#define IS_PIN_ANALOG(p) (((p) >= 14 && (p) <= 23) || ((p) >= 34 && (p) <= 38))
|
||||
#define IS_PIN_PWM(p) digitalPinHasPWM(p)
|
||||
#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) ((p) == 18 || (p) == 19)
|
||||
#define IS_PIN_SERIAL(p) (((p) > 6 && (p) < 11) || ((p) == 0 || (p) == 1))
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) (((p) <= 23) ? (p) - 14 : (p) - 24)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) (p)
|
||||
|
||||
|
||||
// Teensy-LC
|
||||
#elif defined(__MKL26Z64__)
|
||||
#define TOTAL_ANALOG_PINS 13
|
||||
#define TOTAL_PINS 27 // 27 digital + 13 analog-digital
|
||||
#define VERSION_BLINK_PIN 13
|
||||
#define PIN_SERIAL1_RX 0
|
||||
#define PIN_SERIAL1_TX 1
|
||||
#define PIN_SERIAL2_RX 9
|
||||
#define PIN_SERIAL2_TX 10
|
||||
#define PIN_SERIAL3_RX 7
|
||||
#define PIN_SERIAL3_TX 8
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) <= 26)
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 14)
|
||||
#define IS_PIN_PWM(p) digitalPinHasPWM(p)
|
||||
#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) ((p) == 18 || (p) == 19)
|
||||
#define IS_PIN_SERIAL(p) (((p) > 6 && (p) < 11) || ((p) == 0 || (p) == 1))
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 14)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) (p)
|
||||
|
||||
|
||||
// Teensy++ 1.0 and 2.0
|
||||
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
||||
#define TOTAL_ANALOG_PINS 8
|
||||
#define TOTAL_PINS 46 // 38 digital + 8 analog
|
||||
#define VERSION_BLINK_PIN 6
|
||||
#define PIN_SERIAL1_RX 2
|
||||
#define PIN_SERIAL1_TX 3
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 38 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_PWM(p) digitalPinHasPWM(p)
|
||||
#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) ((p) == 0 || (p) == 1)
|
||||
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
|
||||
#define IS_PIN_SERIAL(p) ((p) == 2 || (p) == 3)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 38)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) (p)
|
||||
|
||||
|
||||
// Leonardo
|
||||
#elif defined(__AVR_ATmega32U4__)
|
||||
#define TOTAL_ANALOG_PINS 12
|
||||
#define TOTAL_PINS 30 // 14 digital + 12 analog + 4 SPI (D14-D17 on ISP header)
|
||||
#define VERSION_BLINK_PIN 13
|
||||
#define PIN_SERIAL1_RX 0
|
||||
#define PIN_SERIAL1_TX 1
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 18 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_PWM(p) ((p) == 3 || (p) == 5 || (p) == 6 || (p) == 9 || (p) == 10 || (p) == 11 || (p) == 13)
|
||||
#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) ((p) == 2 || (p) == 3)
|
||||
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
|
||||
#define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) (p) - 18
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) (p)
|
||||
|
||||
|
||||
// Intel Galileo Board (gen 1 and 2) and Intel Edison
|
||||
#elif defined(ARDUINO_LINUX)
|
||||
#define TOTAL_ANALOG_PINS 6
|
||||
#define TOTAL_PINS 20 // 14 digital + 6 analog
|
||||
#define VERSION_BLINK_PIN 13
|
||||
#define PIN_SERIAL1_RX 0
|
||||
#define PIN_SERIAL1_TX 1
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 19)
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 19)
|
||||
#define IS_PIN_PWM(p) digitalPinHasPWM(p)
|
||||
#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL)
|
||||
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
|
||||
#define IS_PIN_SERIAL(p) ((p) == 0 || (p) == 1)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 14)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) ((p) - 2)
|
||||
|
||||
|
||||
// RedBearLab BLE Nano with factory switch settings (S1 - S10)
|
||||
#elif defined(BLE_NANO)
|
||||
#define TOTAL_ANALOG_PINS 6
|
||||
#define TOTAL_PINS 15 // 9 digital + 3 analog
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 14)
|
||||
#define IS_PIN_ANALOG(p) ((p) == 8 || (p) == 9 || (p) == 10 || (p) == 11 || (p) == 12 || (p) == 14) //A0~A5
|
||||
#define IS_PIN_PWM(p) ((p) == 3 || (p) == 5 || (p) == 6)
|
||||
#define IS_PIN_SERVO(p) ((p) >= 2 && (p) <= 7)
|
||||
#define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL)
|
||||
#define IS_PIN_SPI(p) ((p) == CS || (p) == MOSI || (p) == MISO || (p) == SCK)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 8)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) (p)
|
||||
|
||||
|
||||
// Sanguino
|
||||
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
|
||||
#define TOTAL_ANALOG_PINS 8
|
||||
#define TOTAL_PINS 32 // 24 digital + 8 analog
|
||||
#define VERSION_BLINK_PIN 0
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 24 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_PWM(p) digitalPinHasPWM(p)
|
||||
#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) ((p) == 16 || (p) == 17)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 24)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) ((p) - 2)
|
||||
|
||||
|
||||
// Illuminato
|
||||
#elif defined(__AVR_ATmega645__)
|
||||
#define TOTAL_ANALOG_PINS 6
|
||||
#define TOTAL_PINS 42 // 36 digital + 6 analog
|
||||
#define VERSION_BLINK_PIN 13
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 36 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_PWM(p) digitalPinHasPWM(p)
|
||||
#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) ((p) == 4 || (p) == 5)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 36)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) ((p) - 2)
|
||||
|
||||
|
||||
// Pic32 chipKIT FubarinoSD
|
||||
#elif defined(_BOARD_FUBARINO_SD_)
|
||||
#define TOTAL_ANALOG_PINS NUM_ANALOG_PINS // 15
|
||||
#define TOTAL_PINS NUM_DIGITAL_PINS // 45, All pins can be digital
|
||||
#define MAX_SERVOS NUM_DIGITAL_PINS
|
||||
#define VERSION_BLINK_PIN PIN_LED1
|
||||
#define IS_PIN_DIGITAL(p) 1
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 30 && (p) <= 44)
|
||||
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_I2C(p) ((p) == 1 || (p) == 2)
|
||||
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) (14 - (p - 30))
|
||||
#define PIN_TO_PWM(p) (p)
|
||||
#define PIN_TO_SERVO(p) (p)
|
||||
|
||||
|
||||
// Pic32 chipKIT FubarinoMini
|
||||
// Note, FubarinoMini analog pin 20 will not function in Firmata as analog input due to limitation in analog mapping
|
||||
#elif defined(_BOARD_FUBARINO_MINI_)
|
||||
#define TOTAL_ANALOG_PINS 14 // We have to fake this because of the poor analog pin mapping planning in FubarinoMini
|
||||
#define TOTAL_PINS NUM_DIGITAL_PINS // 33
|
||||
#define MAX_SERVOS NUM_DIGITAL_PINS
|
||||
#define VERSION_BLINK_PIN PIN_LED1
|
||||
#define IS_PIN_DIGITAL(p) ((p) != 14 && (p) != 15 && (p) != 31 && (p) != 32)
|
||||
#define IS_PIN_ANALOG(p) ((p) == 0 || ((p) >= 3 && (p) <= 13))
|
||||
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_I2C(p) ((p) == 25 || (p) == 26)
|
||||
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) (p)
|
||||
#define PIN_TO_PWM(p) (p)
|
||||
#define PIN_TO_SERVO(p) (p)
|
||||
|
||||
|
||||
// Pic32 chipKIT UNO32
|
||||
#elif defined(_BOARD_UNO_) && defined(__PIC32) // NOTE: no _BOARD_UNO32_ to use
|
||||
#define TOTAL_ANALOG_PINS NUM_ANALOG_PINS // 12
|
||||
#define TOTAL_PINS NUM_DIGITAL_PINS // 47 All pins can be digital
|
||||
#define MAX_SERVOS NUM_DIGITAL_PINS // All pins can be servo with SoftPWMservo
|
||||
#define VERSION_BLINK_PIN PIN_LED1
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 2)
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 25)
|
||||
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_I2C(p) ((p) == 45 || (p) == 46)
|
||||
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 14)
|
||||
#define PIN_TO_PWM(p) (p)
|
||||
#define PIN_TO_SERVO(p) (p)
|
||||
|
||||
|
||||
// Pic32 chipKIT DP32
|
||||
#elif defined(_BOARD_DP32_)
|
||||
#define TOTAL_ANALOG_PINS 15 // Really only has 9, but have to override because of mistake in variant file
|
||||
#define TOTAL_PINS NUM_DIGITAL_PINS // 19
|
||||
#define MAX_SERVOS NUM_DIGITAL_PINS // All pins can be servo with SoftPWMservo
|
||||
#define VERSION_BLINK_PIN PIN_LED1
|
||||
#define IS_PIN_DIGITAL(p) (((p) != 1) && ((p) != 4) && ((p) != 5) && ((p) != 15) && ((p) != 16))
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 6 && (p) <= 14)
|
||||
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_I2C(p) ((p) == 2 || (p) == 3)
|
||||
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) (p)
|
||||
#define PIN_TO_PWM(p) (p)
|
||||
#define PIN_TO_SERVO(p) (p)
|
||||
|
||||
|
||||
// Pic32 chipKIT uC32
|
||||
#elif defined(_BOARD_UC32_)
|
||||
#define TOTAL_ANALOG_PINS NUM_ANALOG_PINS // 12
|
||||
#define TOTAL_PINS NUM_DIGITAL_PINS // 47 All pins can be digital
|
||||
#define MAX_SERVOS NUM_DIGITAL_PINS // All pins can be servo with SoftPWMservo
|
||||
#define VERSION_BLINK_PIN PIN_LED1
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 2)
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 25)
|
||||
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_I2C(p) ((p) == 45 || (p) == 46)
|
||||
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 14)
|
||||
#define PIN_TO_PWM(p) (p)
|
||||
#define PIN_TO_SERVO(p) (p)
|
||||
|
||||
|
||||
// Pic32 chipKIT WF32
|
||||
#elif defined(_BOARD_WF32_)
|
||||
#define TOTAL_ANALOG_PINS NUM_ANALOG_PINS
|
||||
#define TOTAL_PINS NUM_DIGITAL_PINS
|
||||
#define MAX_SERVOS NUM_DIGITAL_PINS
|
||||
#define VERSION_BLINK_PIN PIN_LED1
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 49) // Accounts for SD and WiFi dedicated pins
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 25)
|
||||
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_I2C(p) ((p) == 34 || (p) == 35)
|
||||
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 14)
|
||||
#define PIN_TO_PWM(p) (p)
|
||||
#define PIN_TO_SERVO(p) (p)
|
||||
|
||||
|
||||
// Pic32 chipKIT WiFire
|
||||
#elif defined(_BOARD_WIFIRE_)
|
||||
#define TOTAL_ANALOG_PINS NUM_ANALOG_PINS // 14
|
||||
#define TOTAL_PINS NUM_DIGITAL_PINS // 71
|
||||
#define MAX_SERVOS NUM_DIGITAL_PINS
|
||||
#define VERSION_BLINK_PIN PIN_LED1
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) <= 47) // Accounts for SD and WiFi dedicated pins
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 25)
|
||||
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_I2C(p) ((p) == 34 || (p) == 35)
|
||||
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) <= 25 ? ((p) - 14) : (p) - 36)
|
||||
#define PIN_TO_PWM(p) (p)
|
||||
#define PIN_TO_SERVO(p) (p)
|
||||
|
||||
|
||||
// Pic32 chipKIT MAX32
|
||||
#elif defined(_BOARD_MEGA_) && defined(__PIC32) // NOTE: no _BOARD_MAX32_ to use
|
||||
#define TOTAL_ANALOG_PINS NUM_ANALOG_PINS // 16
|
||||
#define TOTAL_PINS NUM_DIGITAL_PINS // 87
|
||||
#define MAX_SERVOS NUM_DIGITAL_PINS
|
||||
#define VERSION_BLINK_PIN PIN_LED1
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 2)
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 54 && (p) <= 69)
|
||||
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_I2C(p) ((p) == 34 || (p) == 35)
|
||||
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 54)
|
||||
#define PIN_TO_PWM(p) (p)
|
||||
#define PIN_TO_SERVO(p) (p)
|
||||
|
||||
|
||||
// Pic32 chipKIT Pi
|
||||
#elif defined(_BOARD_CHIPKIT_PI_)
|
||||
#define TOTAL_ANALOG_PINS 16
|
||||
#define TOTAL_PINS NUM_DIGITAL_PINS // 19
|
||||
#define MAX_SERVOS NUM_DIGITAL_PINS
|
||||
#define VERSION_BLINK_PIN PIN_LED1
|
||||
#define IS_PIN_DIGITAL(p) (((p) >= 2) && ((p) <= 3) || (((p) >= 8) && ((p) <= 13)) || (((p) >= 14) && ((p) <= 17)))
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 14 && (p) <= 17)
|
||||
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_I2C(p) ((p) == 16 || (p) == 17)
|
||||
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) <= 15 ? (p) - 14 : (p) - 12)
|
||||
//#define PIN_TO_ANALOG(p) (((p) <= 16) ? ((p) - 14) : ((p) - 16))
|
||||
#define PIN_TO_PWM(p) (p)
|
||||
#define PIN_TO_SERVO(p) (p)
|
||||
|
||||
// Pinoccio Scout
|
||||
// Note: digital pins 9-16 are usable but not labeled on the board numerically.
|
||||
// SS=9, MOSI=10, MISO=11, SCK=12, RX1=13, TX1=14, SCL=15, SDA=16
|
||||
#elif defined(ARDUINO_PINOCCIO)
|
||||
#define TOTAL_ANALOG_PINS 8
|
||||
#define TOTAL_PINS NUM_DIGITAL_PINS // 32
|
||||
#define VERSION_BLINK_PIN 23
|
||||
#define PIN_SERIAL1_RX 13
|
||||
#define PIN_SERIAL1_TX 14
|
||||
#define IS_PIN_DIGITAL(p) (((p) >= 2) && ((p) <= 16)) || (((p) >= 24) && ((p) <= 31))
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 24 && (p) <= 31)
|
||||
#define IS_PIN_PWM(p) digitalPinHasPWM(p)
|
||||
#define IS_PIN_SERVO(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_I2C(p) ((p) == SCL || (p) == SDA)
|
||||
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
|
||||
#define IS_PIN_SERIAL(p) ((p) == 13 || (p) == 14)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 24)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) ((p) - 2)
|
||||
|
||||
// ESP8266
|
||||
// note: boot mode GPIOs 0, 2 and 15 can be used as outputs, GPIOs 6-11 are in use for flash IO
|
||||
#elif defined(ESP8266)
|
||||
#define TOTAL_ANALOG_PINS NUM_ANALOG_INPUTS
|
||||
#define TOTAL_PINS A0 + NUM_ANALOG_INPUTS
|
||||
#define PIN_SERIAL_RX 3
|
||||
#define PIN_SERIAL_TX 1
|
||||
#define IS_PIN_DIGITAL(p) (((p) >= 0 && (p) <= 5) || ((p) >= 12 && (p) < A0))
|
||||
#define IS_PIN_ANALOG(p) ((p) >= A0 && (p) < A0 + NUM_ANALOG_INPUTS)
|
||||
#define IS_PIN_PWM(p) digitalPinHasPWM(p)
|
||||
#define IS_PIN_SERVO(p) (IS_PIN_DIGITAL(p) && (p) < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) ((p) == SDA || (p) == SCL)
|
||||
#define IS_PIN_SPI(p) ((p) == SS || (p) == MOSI || (p) == MISO || (p) == SCK)
|
||||
#define IS_PIN_INTERRUPT(p) (digitalPinToInterrupt(p) > NOT_AN_INTERRUPT)
|
||||
#define IS_PIN_SERIAL(p) ((p) == PIN_SERIAL_RX || (p) == PIN_SERIAL_TX)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - A0)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) (p)
|
||||
#define DEFAULT_PWM_RESOLUTION 10
|
||||
|
||||
|
||||
// anything else
|
||||
#else
|
||||
#error "Please edit Boards.h with a hardware abstraction for this board"
|
||||
#endif
|
||||
|
||||
// as long this is not defined for all boards:
|
||||
#ifndef IS_PIN_SPI
|
||||
#define IS_PIN_SPI(p) 0
|
||||
#endif
|
||||
|
||||
#ifndef IS_PIN_SERIAL
|
||||
#define IS_PIN_SERIAL(p) 0
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_PWM_RESOLUTION
|
||||
#define DEFAULT_PWM_RESOLUTION 8
|
||||
#endif
|
||||
|
||||
/*==============================================================================
|
||||
* readPort() - Read an 8 bit port
|
||||
*============================================================================*/
|
||||
|
||||
static inline unsigned char readPort(byte, byte) __attribute__((always_inline, unused));
|
||||
static inline unsigned char readPort(byte port, byte bitmask)
|
||||
{
|
||||
#if defined(ARDUINO_PINOUT_OPTIMIZE)
|
||||
if (port == 0) return (PIND & 0xFC) & bitmask; // ignore Rx/Tx 0/1
|
||||
if (port == 1) return ((PINB & 0x3F) | ((PINC & 0x03) << 6)) & bitmask;
|
||||
if (port == 2) return ((PINC & 0x3C) >> 2) & bitmask;
|
||||
return 0;
|
||||
#else
|
||||
unsigned char out = 0, pin = port * 8;
|
||||
if (IS_PIN_DIGITAL(pin + 0) && (bitmask & 0x01) && digitalRead(PIN_TO_DIGITAL(pin + 0))) out |= 0x01;
|
||||
if (IS_PIN_DIGITAL(pin + 1) && (bitmask & 0x02) && digitalRead(PIN_TO_DIGITAL(pin + 1))) out |= 0x02;
|
||||
if (IS_PIN_DIGITAL(pin + 2) && (bitmask & 0x04) && digitalRead(PIN_TO_DIGITAL(pin + 2))) out |= 0x04;
|
||||
if (IS_PIN_DIGITAL(pin + 3) && (bitmask & 0x08) && digitalRead(PIN_TO_DIGITAL(pin + 3))) out |= 0x08;
|
||||
if (IS_PIN_DIGITAL(pin + 4) && (bitmask & 0x10) && digitalRead(PIN_TO_DIGITAL(pin + 4))) out |= 0x10;
|
||||
if (IS_PIN_DIGITAL(pin + 5) && (bitmask & 0x20) && digitalRead(PIN_TO_DIGITAL(pin + 5))) out |= 0x20;
|
||||
if (IS_PIN_DIGITAL(pin + 6) && (bitmask & 0x40) && digitalRead(PIN_TO_DIGITAL(pin + 6))) out |= 0x40;
|
||||
if (IS_PIN_DIGITAL(pin + 7) && (bitmask & 0x80) && digitalRead(PIN_TO_DIGITAL(pin + 7))) out |= 0x80;
|
||||
return out;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* writePort() - Write an 8 bit port, only touch pins specified by a bitmask
|
||||
*============================================================================*/
|
||||
|
||||
static inline unsigned char writePort(byte, byte, byte) __attribute__((always_inline, unused));
|
||||
static inline unsigned char writePort(byte port, byte value, byte bitmask)
|
||||
{
|
||||
#if defined(ARDUINO_PINOUT_OPTIMIZE)
|
||||
if (port == 0) {
|
||||
bitmask = bitmask & 0xFC; // do not touch Tx & Rx pins
|
||||
byte valD = value & bitmask;
|
||||
byte maskD = ~bitmask;
|
||||
cli();
|
||||
PORTD = (PORTD & maskD) | valD;
|
||||
sei();
|
||||
} else if (port == 1) {
|
||||
byte valB = (value & bitmask) & 0x3F;
|
||||
byte valC = (value & bitmask) >> 6;
|
||||
byte maskB = ~(bitmask & 0x3F);
|
||||
byte maskC = ~((bitmask & 0xC0) >> 6);
|
||||
cli();
|
||||
PORTB = (PORTB & maskB) | valB;
|
||||
PORTC = (PORTC & maskC) | valC;
|
||||
sei();
|
||||
} else if (port == 2) {
|
||||
bitmask = bitmask & 0x0F;
|
||||
byte valC = (value & bitmask) << 2;
|
||||
byte maskC = ~(bitmask << 2);
|
||||
cli();
|
||||
PORTC = (PORTC & maskC) | valC;
|
||||
sei();
|
||||
}
|
||||
return 1;
|
||||
#else
|
||||
byte pin = port * 8;
|
||||
if ((bitmask & 0x01)) digitalWrite(PIN_TO_DIGITAL(pin + 0), (value & 0x01));
|
||||
if ((bitmask & 0x02)) digitalWrite(PIN_TO_DIGITAL(pin + 1), (value & 0x02));
|
||||
if ((bitmask & 0x04)) digitalWrite(PIN_TO_DIGITAL(pin + 2), (value & 0x04));
|
||||
if ((bitmask & 0x08)) digitalWrite(PIN_TO_DIGITAL(pin + 3), (value & 0x08));
|
||||
if ((bitmask & 0x10)) digitalWrite(PIN_TO_DIGITAL(pin + 4), (value & 0x10));
|
||||
if ((bitmask & 0x20)) digitalWrite(PIN_TO_DIGITAL(pin + 5), (value & 0x20));
|
||||
if ((bitmask & 0x40)) digitalWrite(PIN_TO_DIGITAL(pin + 6), (value & 0x40));
|
||||
if ((bitmask & 0x80)) digitalWrite(PIN_TO_DIGITAL(pin + 7), (value & 0x80));
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef TOTAL_PORTS
|
||||
#define TOTAL_PORTS ((TOTAL_PINS + 7) / 8)
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* Firmata_Boards_h */
|
||||
@@ -0,0 +1,668 @@
|
||||
/*
|
||||
Firmata.cpp - Firmata library v2.5.3 - 2016-06-18
|
||||
Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved.
|
||||
Copyright (C) 2009-2016 Jeff Hoefs. All rights 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.
|
||||
|
||||
See file LICENSE.txt for further informations on licensing terms.
|
||||
*/
|
||||
|
||||
//******************************************************************************
|
||||
//* Includes
|
||||
//******************************************************************************
|
||||
|
||||
#include "CP_Firmata.h"
|
||||
#include "HardwareSerial.h"
|
||||
|
||||
extern "C" {
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
//* Support Functions
|
||||
//******************************************************************************
|
||||
|
||||
/**
|
||||
* Split a 16-bit byte into two 7-bit values and write each value.
|
||||
* @param value The 16-bit value to be split and written separately.
|
||||
*/
|
||||
void FirmataClass::sendValueAsTwo7bitBytes(int value)
|
||||
{
|
||||
FirmataStream->write(value & 0x7F); // LSB
|
||||
FirmataStream->write(value >> 7 & 0x7F); // MSB
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method to write the beginning of a Sysex message transmission.
|
||||
*/
|
||||
void FirmataClass::startSysex(void)
|
||||
{
|
||||
FirmataStream->write(START_SYSEX);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method to write the end of a Sysex message transmission.
|
||||
*/
|
||||
void FirmataClass::endSysex(void)
|
||||
{
|
||||
FirmataStream->write(END_SYSEX);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
//* Constructors
|
||||
//******************************************************************************
|
||||
|
||||
/**
|
||||
* The Firmata class.
|
||||
* An instance named "Firmata" is created automatically for the user.
|
||||
*/
|
||||
FirmataClass::FirmataClass()
|
||||
{
|
||||
firmwareVersionCount = 0;
|
||||
firmwareVersionVector = 0;
|
||||
systemReset();
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
//* Public Methods
|
||||
//******************************************************************************
|
||||
|
||||
/**
|
||||
* Initialize the default Serial transport at the default baud of 57600.
|
||||
*/
|
||||
void FirmataClass::begin(void)
|
||||
{
|
||||
begin(57600);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the default Serial transport and override the default baud.
|
||||
* Sends the protocol version to the host application followed by the firmware version and name.
|
||||
* blinkVersion is also called. To skip the call to blinkVersion, call Firmata.disableBlinkVersion()
|
||||
* before calling Firmata.begin(baud).
|
||||
* @param speed The baud to use. 57600 baud is the default value.
|
||||
*/
|
||||
void FirmataClass::begin(long speed)
|
||||
{
|
||||
Serial.begin(speed);
|
||||
FirmataStream = &Serial;
|
||||
blinkVersion();
|
||||
printVersion(); // send the protocol version
|
||||
printFirmwareVersion(); // send the firmware name and version
|
||||
}
|
||||
|
||||
/**
|
||||
* Reassign the Firmata stream transport.
|
||||
* @param s A reference to the Stream transport object. This can be any type of
|
||||
* transport that implements the Stream interface. Some examples include Ethernet, WiFi
|
||||
* and other UARTs on the board (Serial1, Serial2, etc).
|
||||
*/
|
||||
void FirmataClass::begin(Stream &s)
|
||||
{
|
||||
FirmataStream = &s;
|
||||
// do not call blinkVersion() here because some hardware such as the
|
||||
// Ethernet shield use pin 13
|
||||
printVersion();
|
||||
printFirmwareVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the Firmata protocol version to the Firmata host application.
|
||||
*/
|
||||
void FirmataClass::printVersion(void)
|
||||
{
|
||||
FirmataStream->write(REPORT_VERSION);
|
||||
FirmataStream->write(FIRMATA_PROTOCOL_MAJOR_VERSION);
|
||||
FirmataStream->write(FIRMATA_PROTOCOL_MINOR_VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Blink the Firmata protocol version to the onboard LEDs (if the board has an onboard LED).
|
||||
* If VERSION_BLINK_PIN is not defined in Boards.h for a particular board, then this method
|
||||
* does nothing.
|
||||
* The first series of flashes indicates the firmware major version (2 flashes = 2).
|
||||
* The second series of flashes indicates the firmware minor version (5 flashes = 5).
|
||||
*/
|
||||
void FirmataClass::blinkVersion(void)
|
||||
{
|
||||
#if defined(VERSION_BLINK_PIN)
|
||||
if (blinkVersionDisabled) return;
|
||||
// flash the pin with the protocol version
|
||||
pinMode(VERSION_BLINK_PIN, OUTPUT);
|
||||
strobeBlinkPin(VERSION_BLINK_PIN, FIRMATA_FIRMWARE_MAJOR_VERSION, 40, 210);
|
||||
delay(250);
|
||||
strobeBlinkPin(VERSION_BLINK_PIN, FIRMATA_FIRMWARE_MINOR_VERSION, 40, 210);
|
||||
delay(125);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a means to disable the version blink sequence on the onboard LED, trimming startup
|
||||
* time by a couple of seconds.
|
||||
* Call this before Firmata.begin(). It only applies when using the default Serial transport.
|
||||
*/
|
||||
void FirmataClass::disableBlinkVersion()
|
||||
{
|
||||
blinkVersionDisabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the firmware name and version to the Firmata host application. The major and minor version
|
||||
* numbers are the first 2 bytes in the message. The following bytes are the characters of the
|
||||
* firmware name.
|
||||
*/
|
||||
void FirmataClass::printFirmwareVersion(void)
|
||||
{
|
||||
byte i;
|
||||
|
||||
if (firmwareVersionCount) { // make sure that the name has been set before reporting
|
||||
startSysex();
|
||||
FirmataStream->write(REPORT_FIRMWARE);
|
||||
FirmataStream->write(firmwareVersionVector[0]); // major version number
|
||||
FirmataStream->write(firmwareVersionVector[1]); // minor version number
|
||||
for (i = 2; i < firmwareVersionCount; ++i) {
|
||||
sendValueAsTwo7bitBytes(firmwareVersionVector[i]);
|
||||
}
|
||||
endSysex();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name and version of the firmware. This is not the same version as the Firmata protocol
|
||||
* (although at times the firmware version and protocol version may be the same number).
|
||||
* @param name A pointer to the name char array
|
||||
* @param major The major version number
|
||||
* @param minor The minor version number
|
||||
*/
|
||||
void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte minor)
|
||||
{
|
||||
const char *firmwareName;
|
||||
const char *extension;
|
||||
|
||||
// parse out ".cpp" and "applet/" that comes from using __FILE__
|
||||
extension = strstr(name, ".cpp");
|
||||
firmwareName = strrchr(name, '/');
|
||||
|
||||
if (!firmwareName) {
|
||||
// windows
|
||||
firmwareName = strrchr(name, '\\');
|
||||
}
|
||||
if (!firmwareName) {
|
||||
// user passed firmware name
|
||||
firmwareName = name;
|
||||
} else {
|
||||
firmwareName ++;
|
||||
}
|
||||
|
||||
if (!extension) {
|
||||
firmwareVersionCount = strlen(firmwareName) + 2;
|
||||
} else {
|
||||
firmwareVersionCount = extension - firmwareName + 2;
|
||||
}
|
||||
|
||||
// in case anyone calls setFirmwareNameAndVersion more than once
|
||||
free(firmwareVersionVector);
|
||||
|
||||
firmwareVersionVector = (byte *) malloc(firmwareVersionCount + 1);
|
||||
firmwareVersionVector[firmwareVersionCount] = 0;
|
||||
firmwareVersionVector[0] = major;
|
||||
firmwareVersionVector[1] = minor;
|
||||
strncpy((char *)firmwareVersionVector + 2, firmwareName, firmwareVersionCount - 2);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Serial Receive Handling
|
||||
|
||||
/**
|
||||
* A wrapper for Stream::available()
|
||||
* @return The number of bytes remaining in the input stream buffer.
|
||||
*/
|
||||
int FirmataClass::available(void)
|
||||
{
|
||||
return FirmataStream->available();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process incoming sysex messages. Handles REPORT_FIRMWARE and STRING_DATA internally.
|
||||
* Calls callback function for STRING_DATA and all other sysex messages.
|
||||
* @private
|
||||
*/
|
||||
void FirmataClass::processSysexMessage(void)
|
||||
{
|
||||
switch (storedInputData[0]) { //first byte in buffer is command
|
||||
case REPORT_FIRMWARE:
|
||||
printFirmwareVersion();
|
||||
break;
|
||||
case STRING_DATA:
|
||||
if (currentStringCallback) {
|
||||
byte bufferLength = (sysexBytesRead - 1) / 2;
|
||||
byte i = 1;
|
||||
byte j = 0;
|
||||
while (j < bufferLength) {
|
||||
// The string length will only be at most half the size of the
|
||||
// stored input buffer so we can decode the string within the buffer.
|
||||
storedInputData[j] = storedInputData[i];
|
||||
i++;
|
||||
storedInputData[j] += (storedInputData[i] << 7);
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
// Make sure string is null terminated. This may be the case for data
|
||||
// coming from client libraries in languages that don't null terminate
|
||||
// strings.
|
||||
if (storedInputData[j - 1] != '\0') {
|
||||
storedInputData[j] = '\0';
|
||||
}
|
||||
(*currentStringCallback)((char *)&storedInputData[0]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (currentSysexCallback)
|
||||
(*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a single int from the input stream. If the value is not = -1, pass it on to parse(byte)
|
||||
*/
|
||||
void FirmataClass::processInput(void)
|
||||
{
|
||||
int inputData = FirmataStream->read(); // this is 'int' to handle -1 when no data
|
||||
if (inputData != -1) {
|
||||
parse(inputData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse data from the input stream.
|
||||
* @param inputData A single byte to be added to the parser.
|
||||
*/
|
||||
void FirmataClass::parse(byte inputData)
|
||||
{
|
||||
int command;
|
||||
|
||||
if (parsingSysex) {
|
||||
if (inputData == END_SYSEX) {
|
||||
//stop sysex byte
|
||||
parsingSysex = false;
|
||||
//fire off handler function
|
||||
processSysexMessage();
|
||||
} else {
|
||||
//normal data byte - add to buffer
|
||||
storedInputData[sysexBytesRead] = inputData;
|
||||
sysexBytesRead++;
|
||||
}
|
||||
} else if ( (waitForData > 0) && (inputData < 128) ) {
|
||||
waitForData--;
|
||||
storedInputData[waitForData] = inputData;
|
||||
if ( (waitForData == 0) && executeMultiByteCommand ) { // got the whole message
|
||||
switch (executeMultiByteCommand) {
|
||||
case ANALOG_MESSAGE:
|
||||
if (currentAnalogCallback) {
|
||||
(*currentAnalogCallback)(multiByteChannel,
|
||||
(storedInputData[0] << 7)
|
||||
+ storedInputData[1]);
|
||||
}
|
||||
break;
|
||||
case DIGITAL_MESSAGE:
|
||||
if (currentDigitalCallback) {
|
||||
(*currentDigitalCallback)(multiByteChannel,
|
||||
(storedInputData[0] << 7)
|
||||
+ storedInputData[1]);
|
||||
}
|
||||
break;
|
||||
case SET_PIN_MODE:
|
||||
if (currentPinModeCallback)
|
||||
(*currentPinModeCallback)(storedInputData[1], storedInputData[0]);
|
||||
break;
|
||||
case SET_DIGITAL_PIN_VALUE:
|
||||
if (currentPinValueCallback)
|
||||
(*currentPinValueCallback)(storedInputData[1], storedInputData[0]);
|
||||
break;
|
||||
case REPORT_ANALOG:
|
||||
if (currentReportAnalogCallback)
|
||||
(*currentReportAnalogCallback)(multiByteChannel, storedInputData[0]);
|
||||
break;
|
||||
case REPORT_DIGITAL:
|
||||
if (currentReportDigitalCallback)
|
||||
(*currentReportDigitalCallback)(multiByteChannel, storedInputData[0]);
|
||||
break;
|
||||
}
|
||||
executeMultiByteCommand = 0;
|
||||
}
|
||||
} else {
|
||||
// remove channel info from command byte if less than 0xF0
|
||||
if (inputData < 0xF0) {
|
||||
command = inputData & 0xF0;
|
||||
multiByteChannel = inputData & 0x0F;
|
||||
} else {
|
||||
command = inputData;
|
||||
// commands in the 0xF* range don't use channel data
|
||||
}
|
||||
switch (command) {
|
||||
case ANALOG_MESSAGE:
|
||||
case DIGITAL_MESSAGE:
|
||||
case SET_PIN_MODE:
|
||||
case SET_DIGITAL_PIN_VALUE:
|
||||
waitForData = 2; // two data bytes needed
|
||||
executeMultiByteCommand = command;
|
||||
break;
|
||||
case REPORT_ANALOG:
|
||||
case REPORT_DIGITAL:
|
||||
waitForData = 1; // one data byte needed
|
||||
executeMultiByteCommand = command;
|
||||
break;
|
||||
case START_SYSEX:
|
||||
parsingSysex = true;
|
||||
sysexBytesRead = 0;
|
||||
break;
|
||||
case SYSTEM_RESET:
|
||||
systemReset();
|
||||
break;
|
||||
case REPORT_VERSION:
|
||||
Firmata.printVersion();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns true if the parser is actively parsing data.
|
||||
*/
|
||||
boolean FirmataClass::isParsingMessage(void)
|
||||
{
|
||||
return (waitForData > 0 || parsingSysex);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Output Stream Handling
|
||||
|
||||
/**
|
||||
* Send an analog message to the Firmata host application. The range of pins is limited to [0..15]
|
||||
* when using the ANALOG_MESSAGE. The maximum value of the ANALOG_MESSAGE is limited to 14 bits
|
||||
* (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG
|
||||
* message.
|
||||
* @param pin The analog pin to send the value of (limited to pins 0 - 15).
|
||||
* @param value The value of the analog pin (0 - 1024 for 10-bit analog, 0 - 4096 for 12-bit, etc).
|
||||
* The maximum value is 14-bits (16384).
|
||||
*/
|
||||
void FirmataClass::sendAnalog(byte pin, int value)
|
||||
{
|
||||
// pin can only be 0-15, so chop higher bits
|
||||
FirmataStream->write(ANALOG_MESSAGE | (pin & 0xF));
|
||||
sendValueAsTwo7bitBytes(value);
|
||||
}
|
||||
|
||||
/* (intentionally left out asterix here)
|
||||
* STUB - NOT IMPLEMENTED
|
||||
* Send a single digital pin value to the Firmata host application.
|
||||
* @param pin The digital pin to send the value of.
|
||||
* @param value The value of the pin.
|
||||
*/
|
||||
void FirmataClass::sendDigital(byte pin, int value)
|
||||
{
|
||||
/* TODO add single pin digital messages to the protocol, this needs to
|
||||
* track the last digital data sent so that it can be sure to change just
|
||||
* one bit in the packet. This is complicated by the fact that the
|
||||
* numbering of the pins will probably differ on Arduino, Wiring, and
|
||||
* other boards.
|
||||
*/
|
||||
|
||||
// TODO: the digital message should not be sent on the serial port every
|
||||
// time sendDigital() is called. Instead, it should add it to an int
|
||||
// which will be sent on a schedule. If a pin changes more than once
|
||||
// before the digital message is sent on the serial port, it should send a
|
||||
// digital message for each change.
|
||||
|
||||
// if(value == 0)
|
||||
// sendDigitalPortPair();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send an 8-bit port in a single digital message (protocol v2 and later).
|
||||
* Send 14-bits in a single digital message (protocol v1).
|
||||
* @param portNumber The port number to send. Note that this is not the same as a "port" on the
|
||||
* physical microcontroller. Ports are defined in order per every 8 pins in ascending order
|
||||
* of the Arduino digital pin numbering scheme. Port 0 = pins D0 - D7, port 1 = pins D8 - D15, etc.
|
||||
* @param portData The value of the port. The value of each pin in the port is represented by a bit.
|
||||
*/
|
||||
void FirmataClass::sendDigitalPort(byte portNumber, int portData)
|
||||
{
|
||||
FirmataStream->write(DIGITAL_MESSAGE | (portNumber & 0xF));
|
||||
FirmataStream->write((byte)portData % 128); // Tx bits 0-6 (protocol v1 and higher)
|
||||
FirmataStream->write(portData >> 7); // Tx bits 7-13 (bit 7 only for protocol v2 and higher)
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a sysex message where all values after the command byte are packet as 2 7-bit bytes
|
||||
* (this is not always the case so this function is not always used to send sysex messages).
|
||||
* @param command The sysex command byte.
|
||||
* @param bytec The number of data bytes in the message (excludes start, command and end bytes).
|
||||
* @param bytev A pointer to the array of data bytes to send in the message.
|
||||
*/
|
||||
void FirmataClass::sendSysex(byte command, byte bytec, byte *bytev)
|
||||
{
|
||||
byte i;
|
||||
startSysex();
|
||||
FirmataStream->write(command);
|
||||
for (i = 0; i < bytec; i++) {
|
||||
sendValueAsTwo7bitBytes(bytev[i]);
|
||||
}
|
||||
endSysex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a string to the Firmata host application.
|
||||
* @param command Must be STRING_DATA
|
||||
* @param string A pointer to the char string
|
||||
*/
|
||||
void FirmataClass::sendString(byte command, const char *string)
|
||||
{
|
||||
if (command == STRING_DATA) {
|
||||
sendSysex(command, strlen(string), (byte *)string);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a string to the Firmata host application.
|
||||
* @param string A pointer to the char string
|
||||
*/
|
||||
void FirmataClass::sendString(const char *string)
|
||||
{
|
||||
sendString(STRING_DATA, string);
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper for Stream::available().
|
||||
* Write a single byte to the output stream.
|
||||
* @param c The byte to be written.
|
||||
*/
|
||||
void FirmataClass::write(byte c)
|
||||
{
|
||||
FirmataStream->write(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach a generic sysex callback function to a command (options are: ANALOG_MESSAGE,
|
||||
* DIGITAL_MESSAGE, REPORT_ANALOG, REPORT DIGITAL, SET_PIN_MODE and SET_DIGITAL_PIN_VALUE).
|
||||
* @param command The ID of the command to attach a callback function to.
|
||||
* @param newFunction A reference to the callback function to attach.
|
||||
*/
|
||||
void FirmataClass::attach(byte command, callbackFunction newFunction)
|
||||
{
|
||||
switch (command) {
|
||||
case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break;
|
||||
case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break;
|
||||
case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break;
|
||||
case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break;
|
||||
case SET_PIN_MODE: currentPinModeCallback = newFunction; break;
|
||||
case SET_DIGITAL_PIN_VALUE: currentPinValueCallback = newFunction; break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach a callback function for the SYSTEM_RESET command.
|
||||
* @param command Must be set to SYSTEM_RESET or it will be ignored.
|
||||
* @param newFunction A reference to the system reset callback function to attach.
|
||||
*/
|
||||
void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction)
|
||||
{
|
||||
switch (command) {
|
||||
case SYSTEM_RESET: currentSystemResetCallback = newFunction; break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach a callback function for the STRING_DATA command.
|
||||
* @param command Must be set to STRING_DATA or it will be ignored.
|
||||
* @param newFunction A reference to the string callback function to attach.
|
||||
*/
|
||||
void FirmataClass::attach(byte command, stringCallbackFunction newFunction)
|
||||
{
|
||||
switch (command) {
|
||||
case STRING_DATA: currentStringCallback = newFunction; break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach a generic sysex callback function to sysex command.
|
||||
* @param command The ID of the command to attach a callback function to.
|
||||
* @param newFunction A reference to the sysex callback function to attach.
|
||||
*/
|
||||
void FirmataClass::attach(byte command, sysexCallbackFunction newFunction)
|
||||
{
|
||||
currentSysexCallback = newFunction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detach a callback function for a specified command (such as SYSTEM_RESET, STRING_DATA,
|
||||
* ANALOG_MESSAGE, DIGITAL_MESSAGE, etc).
|
||||
* @param command The ID of the command to detatch the callback function from.
|
||||
*/
|
||||
void FirmataClass::detach(byte command)
|
||||
{
|
||||
switch (command) {
|
||||
case SYSTEM_RESET: currentSystemResetCallback = NULL; break;
|
||||
case STRING_DATA: currentStringCallback = NULL; break;
|
||||
case START_SYSEX: currentSysexCallback = NULL; break;
|
||||
default:
|
||||
attach(command, (callbackFunction)NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pin The pin to get the configuration of.
|
||||
* @return The configuration of the specified pin.
|
||||
*/
|
||||
byte FirmataClass::getPinMode(byte pin)
|
||||
{
|
||||
return pinConfig[pin];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the pin mode/configuration. The pin configuration (or mode) in Firmata represents the
|
||||
* current function of the pin. Examples are digital input or output, analog input, pwm, i2c,
|
||||
* serial (uart), etc.
|
||||
* @param pin The pin to configure.
|
||||
* @param config The configuration value for the specified pin.
|
||||
*/
|
||||
void FirmataClass::setPinMode(byte pin, byte config)
|
||||
{
|
||||
if (pinConfig[pin] == PIN_MODE_IGNORE)
|
||||
return;
|
||||
|
||||
pinConfig[pin] = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pin The pin to get the state of.
|
||||
* @return The state of the specified pin.
|
||||
*/
|
||||
int FirmataClass::getPinState(byte pin)
|
||||
{
|
||||
return pinState[pin];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the pin state. The pin state of an output pin is the pin value. The state of an
|
||||
* input pin is 0, unless the pin has it's internal pull up resistor enabled, then the value is 1.
|
||||
* @param pin The pin to set the state of
|
||||
* @param state Set the state of the specified pin
|
||||
*/
|
||||
void FirmataClass::setPinState(byte pin, int state)
|
||||
{
|
||||
pinState[pin] = state;
|
||||
}
|
||||
|
||||
// sysex callbacks
|
||||
/*
|
||||
* this is too complicated for analogReceive, but maybe for Sysex?
|
||||
void FirmataClass::attachSysex(sysexFunction newFunction)
|
||||
{
|
||||
byte i;
|
||||
byte tmpCount = analogReceiveFunctionCount;
|
||||
analogReceiveFunction* tmpArray = analogReceiveFunctionArray;
|
||||
analogReceiveFunctionCount++;
|
||||
analogReceiveFunctionArray = (analogReceiveFunction*) calloc(analogReceiveFunctionCount, sizeof(analogReceiveFunction));
|
||||
for(i = 0; i < tmpCount; i++) {
|
||||
analogReceiveFunctionArray[i] = tmpArray[i];
|
||||
}
|
||||
analogReceiveFunctionArray[tmpCount] = newFunction;
|
||||
free(tmpArray);
|
||||
}
|
||||
*/
|
||||
|
||||
//******************************************************************************
|
||||
//* Private Methods
|
||||
//******************************************************************************
|
||||
|
||||
/**
|
||||
* Resets the system state upon a SYSTEM_RESET message from the host software.
|
||||
* @private
|
||||
*/
|
||||
void FirmataClass::systemReset(void)
|
||||
{
|
||||
byte i;
|
||||
|
||||
waitForData = 0; // this flag says the next serial input will be data
|
||||
executeMultiByteCommand = 0; // execute this after getting multi-byte data
|
||||
multiByteChannel = 0; // channel data for multiByteCommands
|
||||
|
||||
for (i = 0; i < MAX_DATA_BYTES; i++) {
|
||||
storedInputData[i] = 0;
|
||||
}
|
||||
|
||||
parsingSysex = false;
|
||||
sysexBytesRead = 0;
|
||||
|
||||
if (currentSystemResetCallback)
|
||||
(*currentSystemResetCallback)();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flashing the pin for the version number
|
||||
* @private
|
||||
* @param pin The pin the LED is attached to.
|
||||
* @param count The number of times to flash the LED.
|
||||
* @param onInterval The number of milliseconds for the LED to be ON during each interval.
|
||||
* @param offInterval The number of milliseconds for the LED to be OFF during each interval.
|
||||
*/
|
||||
void FirmataClass::strobeBlinkPin(byte pin, int count, int onInterval, int offInterval)
|
||||
{
|
||||
byte i;
|
||||
for (i = 0; i < count; i++) {
|
||||
delay(offInterval);
|
||||
digitalWrite(pin, HIGH);
|
||||
delay(onInterval);
|
||||
digitalWrite(pin, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
// make one instance for the user to use
|
||||
FirmataClass Firmata;
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
Firmata.h - Firmata library v2.5.3 - 2016-06-18
|
||||
Copyright (c) 2006-2008 Hans-Christoph Steiner. All rights reserved.
|
||||
Copyright (C) 2009-2015 Jeff Hoefs. All rights 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.
|
||||
|
||||
See file LICENSE.txt for further informations on licensing terms.
|
||||
*/
|
||||
|
||||
#ifndef Firmata_h
|
||||
#define Firmata_h
|
||||
|
||||
#include "CP_Boards.h" /* Hardware Abstraction Layer + Wiring/Arduino */
|
||||
|
||||
/* Version numbers for the protocol. The protocol is still changing, so these
|
||||
* version numbers are important.
|
||||
* Query using the REPORT_VERSION message.
|
||||
*/
|
||||
#define FIRMATA_PROTOCOL_MAJOR_VERSION 2 // for non-compatible changes
|
||||
#define FIRMATA_PROTOCOL_MINOR_VERSION 5 // for backwards compatible changes
|
||||
#define FIRMATA_PROTOCOL_BUGFIX_VERSION 1 // for bugfix releases
|
||||
|
||||
/* Version numbers for the Firmata library.
|
||||
* The firmware version will not always equal the protocol version going forward.
|
||||
* Query using the REPORT_FIRMWARE message.
|
||||
*/
|
||||
#define FIRMATA_FIRMWARE_MAJOR_VERSION 2
|
||||
#define FIRMATA_FIRMWARE_MINOR_VERSION 5
|
||||
#define FIRMATA_FIRMWARE_BUGFIX_VERSION 3
|
||||
|
||||
/* DEPRECATED as of Firmata v2.5.1. As of 2.5.1 there are separate version numbers for
|
||||
* the protocol version and the firmware version.
|
||||
*/
|
||||
#define FIRMATA_MAJOR_VERSION 2 // same as FIRMATA_PROTOCOL_MAJOR_VERSION
|
||||
#define FIRMATA_MINOR_VERSION 5 // same as FIRMATA_PROTOCOL_MINOR_VERSION
|
||||
#define FIRMATA_BUGFIX_VERSION 1 // same as FIRMATA_PROTOCOL_BUGFIX_VERSION
|
||||
|
||||
#define MAX_DATA_BYTES 64 // max number of data bytes in incoming messages
|
||||
|
||||
// Arduino 101 also defines SET_PIN_MODE as a macro in scss_registers.h
|
||||
#ifdef SET_PIN_MODE
|
||||
#undef SET_PIN_MODE
|
||||
#endif
|
||||
|
||||
// message command bytes (128-255/0x80-0xFF)
|
||||
#define DIGITAL_MESSAGE 0x90 // send data for a digital port (collection of 8 pins)
|
||||
#define ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM)
|
||||
#define REPORT_ANALOG 0xC0 // enable analog input by pin #
|
||||
#define REPORT_DIGITAL 0xD0 // enable digital input by port pair
|
||||
//
|
||||
#define SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc
|
||||
#define SET_DIGITAL_PIN_VALUE 0xF5 // set value of an individual digital pin
|
||||
//
|
||||
#define REPORT_VERSION 0xF9 // report protocol version
|
||||
#define SYSTEM_RESET 0xFF // reset from MIDI
|
||||
//
|
||||
#define START_SYSEX 0xF0 // start a MIDI Sysex message
|
||||
#define END_SYSEX 0xF7 // end a MIDI Sysex message
|
||||
|
||||
// extended command set using sysex (0-127/0x00-0x7F)
|
||||
/* 0x00-0x0F reserved for user-defined commands */
|
||||
#define SERIAL_MESSAGE 0x60 // communicate with serial devices, including other boards
|
||||
#define ENCODER_DATA 0x61 // reply with encoders current positions
|
||||
#define SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq
|
||||
#define STRING_DATA 0x71 // a string message with 14-bits per char
|
||||
#define STEPPER_DATA 0x72 // control a stepper motor
|
||||
#define ONEWIRE_DATA 0x73 // send an OneWire read/write/reset/select/skip/search request
|
||||
#define SHIFT_DATA 0x75 // a bitstream to/from a shift register
|
||||
#define I2C_REQUEST 0x76 // send an I2C read/write request
|
||||
#define I2C_REPLY 0x77 // a reply to an I2C read request
|
||||
#define I2C_CONFIG 0x78 // config I2C settings such as delay times and power pins
|
||||
#define EXTENDED_ANALOG 0x6F // analog write (PWM, Servo, etc) to any pin
|
||||
#define PIN_STATE_QUERY 0x6D // ask for a pin's current mode and value
|
||||
#define PIN_STATE_RESPONSE 0x6E // reply with pin's current mode and value
|
||||
#define CAPABILITY_QUERY 0x6B // ask for supported modes and resolution of all pins
|
||||
#define CAPABILITY_RESPONSE 0x6C // reply with supported modes and resolution
|
||||
#define ANALOG_MAPPING_QUERY 0x69 // ask for mapping of analog to pin numbers
|
||||
#define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info
|
||||
#define REPORT_FIRMWARE 0x79 // report name and version of the firmware
|
||||
#define SAMPLING_INTERVAL 0x7A // set the poll rate of the main loop
|
||||
#define SCHEDULER_DATA 0x7B // send a createtask/deletetask/addtotask/schedule/querytasks/querytask request to the scheduler
|
||||
#define SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages
|
||||
#define SYSEX_REALTIME 0x7F // MIDI Reserved for realtime messages
|
||||
// these are DEPRECATED to make the naming more consistent
|
||||
#define FIRMATA_STRING 0x71 // same as STRING_DATA
|
||||
#define SYSEX_I2C_REQUEST 0x76 // same as I2C_REQUEST
|
||||
#define SYSEX_I2C_REPLY 0x77 // same as I2C_REPLY
|
||||
#define SYSEX_SAMPLING_INTERVAL 0x7A // same as SAMPLING_INTERVAL
|
||||
|
||||
// pin modes
|
||||
//#define INPUT 0x00 // defined in Arduino.h
|
||||
//#define OUTPUT 0x01 // defined in Arduino.h
|
||||
#define PIN_MODE_ANALOG 0x02 // analog pin in analogInput mode
|
||||
#define PIN_MODE_PWM 0x03 // digital pin in PWM output mode
|
||||
#define PIN_MODE_SERVO 0x04 // digital pin in Servo output mode
|
||||
#define PIN_MODE_SHIFT 0x05 // shiftIn/shiftOut mode
|
||||
#define PIN_MODE_I2C 0x06 // pin included in I2C setup
|
||||
#define PIN_MODE_ONEWIRE 0x07 // pin configured for 1-wire
|
||||
#define PIN_MODE_STEPPER 0x08 // pin configured for stepper motor
|
||||
#define PIN_MODE_ENCODER 0x09 // pin configured for rotary encoders
|
||||
#define PIN_MODE_SERIAL 0x0A // pin configured for serial communication
|
||||
#define PIN_MODE_PULLUP 0x0B // enable internal pull-up resistor for pin
|
||||
#define PIN_MODE_IGNORE 0x7F // pin configured to be ignored by digitalWrite and capabilityResponse
|
||||
#define TOTAL_PIN_MODES 13
|
||||
// DEPRECATED as of Firmata v2.5
|
||||
#define ANALOG 0x02 // same as PIN_MODE_ANALOG
|
||||
#define PWM 0x03 // same as PIN_MODE_PWM
|
||||
#define SERVO 0x04 // same as PIN_MODE_SERVO
|
||||
#define SHIFT 0x05 // same as PIN_MODE_SHIFT
|
||||
#define I2C 0x06 // same as PIN_MODE_I2C
|
||||
#define ONEWIRE 0x07 // same as PIN_MODE_ONEWIRE
|
||||
#define STEPPER 0x08 // same as PIN_MODE_STEPPER
|
||||
#define ENCODER 0x09 // same as PIN_MODE_ENCODER
|
||||
#define IGNORE 0x7F // same as PIN_MODE_IGNORE
|
||||
|
||||
extern "C" {
|
||||
// callback function types
|
||||
typedef void (*callbackFunction)(byte, int);
|
||||
typedef void (*systemResetCallbackFunction)(void);
|
||||
typedef void (*stringCallbackFunction)(char *);
|
||||
typedef void (*sysexCallbackFunction)(byte command, byte argc, byte *argv);
|
||||
}
|
||||
|
||||
// TODO make it a subclass of a generic Serial/Stream base class
|
||||
class FirmataClass
|
||||
{
|
||||
public:
|
||||
FirmataClass();
|
||||
/* Arduino constructors */
|
||||
void begin();
|
||||
void begin(long);
|
||||
void begin(Stream &s);
|
||||
/* querying functions */
|
||||
void printVersion(void);
|
||||
void blinkVersion(void);
|
||||
void printFirmwareVersion(void);
|
||||
//void setFirmwareVersion(byte major, byte minor); // see macro below
|
||||
void setFirmwareNameAndVersion(const char *name, byte major, byte minor);
|
||||
void disableBlinkVersion();
|
||||
/* serial receive handling */
|
||||
int available(void);
|
||||
void processInput(void);
|
||||
void parse(unsigned char value);
|
||||
boolean isParsingMessage(void);
|
||||
/* serial send handling */
|
||||
void sendAnalog(byte pin, int value);
|
||||
void sendDigital(byte pin, int value); // TODO implement this
|
||||
void sendDigitalPort(byte portNumber, int portData);
|
||||
void sendString(const char *string);
|
||||
void sendString(byte command, const char *string);
|
||||
void sendSysex(byte command, byte bytec, byte *bytev);
|
||||
void write(byte c);
|
||||
/* attach & detach callback functions to messages */
|
||||
void attach(byte command, callbackFunction newFunction);
|
||||
void attach(byte command, systemResetCallbackFunction newFunction);
|
||||
void attach(byte command, stringCallbackFunction newFunction);
|
||||
void attach(byte command, sysexCallbackFunction newFunction);
|
||||
void detach(byte command);
|
||||
|
||||
/* access pin state and config */
|
||||
byte getPinMode(byte pin);
|
||||
void setPinMode(byte pin, byte config);
|
||||
/* access pin state */
|
||||
int getPinState(byte pin);
|
||||
void setPinState(byte pin, int state);
|
||||
|
||||
/* utility methods */
|
||||
void sendValueAsTwo7bitBytes(int value);
|
||||
void startSysex(void);
|
||||
void endSysex(void);
|
||||
|
||||
private:
|
||||
Stream *FirmataStream;
|
||||
/* firmware name and version */
|
||||
byte firmwareVersionCount;
|
||||
byte *firmwareVersionVector;
|
||||
/* input message handling */
|
||||
byte waitForData; // this flag says the next serial input will be data
|
||||
byte executeMultiByteCommand; // execute this after getting multi-byte data
|
||||
byte multiByteChannel; // channel data for multiByteCommands
|
||||
byte storedInputData[MAX_DATA_BYTES]; // multi-byte data
|
||||
/* sysex */
|
||||
boolean parsingSysex;
|
||||
int sysexBytesRead;
|
||||
/* pin configuration */
|
||||
byte pinConfig[TOTAL_PINS];
|
||||
int pinState[TOTAL_PINS];
|
||||
|
||||
/* callback functions */
|
||||
callbackFunction currentAnalogCallback;
|
||||
callbackFunction currentDigitalCallback;
|
||||
callbackFunction currentReportAnalogCallback;
|
||||
callbackFunction currentReportDigitalCallback;
|
||||
callbackFunction currentPinModeCallback;
|
||||
callbackFunction currentPinValueCallback;
|
||||
systemResetCallbackFunction currentSystemResetCallback;
|
||||
stringCallbackFunction currentStringCallback;
|
||||
sysexCallbackFunction currentSysexCallback;
|
||||
|
||||
boolean blinkVersionDisabled;
|
||||
|
||||
/* private methods ------------------------------ */
|
||||
void processSysexMessage(void);
|
||||
void systemReset(void);
|
||||
void strobeBlinkPin(byte pin, int count, int onInterval, int offInterval);
|
||||
};
|
||||
|
||||
extern FirmataClass Firmata;
|
||||
|
||||
/*==============================================================================
|
||||
* MACROS
|
||||
*============================================================================*/
|
||||
|
||||
/* shortcut for setFirmwareNameAndVersion() that uses __FILE__ to set the
|
||||
* firmware name. It needs to be a macro so that __FILE__ is included in the
|
||||
* firmware source file rather than the library source file.
|
||||
*/
|
||||
#define setFirmwareVersion(x, y) setFirmwareNameAndVersion(__FILE__, x, y)
|
||||
|
||||
#endif /* Firmata_h */
|
||||
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
CapacitiveSense.h v.04 - Capacitive Sensing Library for 'duino / Wiring
|
||||
https://github.com/PaulStoffregen/CapacitiveSensor
|
||||
http://www.pjrc.com/teensy/td_libs_CapacitiveSensor.html
|
||||
http://playground.arduino.cc/Main/CapacitiveSensor
|
||||
Copyright (c) 2009 Paul Bagder All right reserved.
|
||||
Version 05 by Paul Stoffregen - Support non-AVR board: Teensy 3.x, Arduino Due
|
||||
Version 04 by Paul Stoffregen - Arduino 1.0 compatibility, issue 146 fix
|
||||
vim: set ts=4:
|
||||
*/
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#include "pins_arduino.h"
|
||||
#include "WConstants.h"
|
||||
#endif
|
||||
|
||||
#include "CPlay_CapacitiveSensor.h"
|
||||
|
||||
// Constructor /////////////////////////////////////////////////////////////////
|
||||
// Function that handles the creation and setup of instances
|
||||
|
||||
CPlay_CapacitiveSensor::CPlay_CapacitiveSensor(uint8_t sendPin, uint8_t receivePin)
|
||||
{
|
||||
// initialize this instance's variables
|
||||
// Serial.begin(9600); // for debugging
|
||||
error = 1;
|
||||
loopTimingFactor = 300; // determined empirically - a hack
|
||||
|
||||
CS_Timeout_Millis = (2000 * (float)loopTimingFactor * (float)F_CPU) / 16000000;
|
||||
CS_AutocaL_Millis = 20000;
|
||||
|
||||
// Serial.print("timwOut = ");
|
||||
// Serial.println(CS_Timeout_Millis);
|
||||
// get pin mapping and port for send Pin - from PinMode function in core
|
||||
|
||||
#ifdef NUM_DIGITAL_PINS
|
||||
if (sendPin >= NUM_DIGITAL_PINS) error = -1;
|
||||
if (receivePin >= NUM_DIGITAL_PINS) error = -2;
|
||||
#endif
|
||||
|
||||
// sendpin to OUTPUT
|
||||
#ifdef ARDUINO_TEEONARDU_FLORA
|
||||
// terrible hack!
|
||||
DDRD |= _BV(5);
|
||||
#else
|
||||
pinMode(sendPin, OUTPUT);
|
||||
#endif
|
||||
|
||||
pinMode(receivePin, INPUT); // receivePin to INPUT
|
||||
|
||||
#ifdef ARDUINO_TEEONARDU_FLORA
|
||||
// terrible hack!
|
||||
PORTD &= ~_BV(5);
|
||||
#else
|
||||
digitalWrite(sendPin, LOW);
|
||||
#endif
|
||||
|
||||
sBit = PIN_TO_BITMASK(sendPin); // get send pin's ports and bitmask
|
||||
sReg = PIN_TO_BASEREG(sendPin); // get pointer to output register
|
||||
|
||||
rBit = PIN_TO_BITMASK(receivePin); // get receive pin's ports and bitmask
|
||||
rReg = PIN_TO_BASEREG(receivePin);
|
||||
|
||||
// get pin mapping and port for receive Pin - from digital pin functions in Wiring.c
|
||||
leastTotal = 0x0FFFFFFFL; // input large value for autocalibrate begin
|
||||
lastCal = millis(); // set millis for start
|
||||
}
|
||||
|
||||
// Public Methods //////////////////////////////////////////////////////////////
|
||||
// Functions available in Wiring sketches, this library, and other libraries
|
||||
|
||||
long CPlay_CapacitiveSensor::capacitiveSensor(uint8_t samples)
|
||||
{
|
||||
total = 0;
|
||||
if (samples == 0) return 0;
|
||||
if (error < 0) return -1; // bad pin
|
||||
|
||||
|
||||
for (uint8_t i = 0; i < samples; i++) { // loop for samples parameter - simple lowpass filter
|
||||
if (SenseOneCycle() < 0) return -2; // variable over timeout
|
||||
}
|
||||
|
||||
// only calibrate if time is greater than CS_AutocaL_Millis and total is less than 10% of baseline
|
||||
// this is an attempt to keep from calibrating when the sensor is seeing a "touched" signal
|
||||
|
||||
if ( (millis() - lastCal > CS_AutocaL_Millis) && abs(total - leastTotal) < (int)(.10 * (float)leastTotal) ) {
|
||||
|
||||
// Serial.println(); // debugging
|
||||
// Serial.println("auto-calibrate");
|
||||
// Serial.println();
|
||||
// delay(2000); */
|
||||
|
||||
leastTotal = 0x0FFFFFFFL; // reset for "autocalibrate"
|
||||
lastCal = millis();
|
||||
}
|
||||
/*else{ // debugging
|
||||
Serial.print(" total = ");
|
||||
Serial.print(total);
|
||||
|
||||
Serial.print(" leastTotal = ");
|
||||
Serial.println(leastTotal);
|
||||
|
||||
Serial.print("total - leastTotal = ");
|
||||
x = total - leastTotal ;
|
||||
Serial.print(x);
|
||||
Serial.print(" .1 * leastTotal = ");
|
||||
x = (int)(.1 * (float)leastTotal);
|
||||
Serial.println(x);
|
||||
} */
|
||||
|
||||
// routine to subtract baseline (non-sensed capacitance) from sensor return
|
||||
if (total < leastTotal) leastTotal = total; // set floor value to subtract from sensed value
|
||||
return(total - leastTotal);
|
||||
|
||||
}
|
||||
|
||||
long CPlay_CapacitiveSensor::capacitiveSensorRaw(uint8_t samples)
|
||||
{
|
||||
total = 0;
|
||||
if (samples == 0) return 0;
|
||||
if (error < 0) return -1; // bad pin - this appears not to work
|
||||
|
||||
for (uint8_t i = 0; i < samples; i++) { // loop for samples parameter - simple lowpass filter
|
||||
if (SenseOneCycle() < 0) return -2; // variable over timeout
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
void CPlay_CapacitiveSensor::reset_CS_AutoCal(void){
|
||||
leastTotal = 0x0FFFFFFFL;
|
||||
}
|
||||
|
||||
void CPlay_CapacitiveSensor::set_CS_AutocaL_Millis(unsigned long autoCal_millis){
|
||||
CS_AutocaL_Millis = autoCal_millis;
|
||||
}
|
||||
|
||||
void CPlay_CapacitiveSensor::set_CS_Timeout_Millis(unsigned long timeout_millis){
|
||||
CS_Timeout_Millis = (timeout_millis * (float)loopTimingFactor * (float)F_CPU) / 16000000; // floats to deal with large numbers
|
||||
}
|
||||
|
||||
// Private Methods /////////////////////////////////////////////////////////////
|
||||
// Functions only available to other functions in this library
|
||||
|
||||
int CPlay_CapacitiveSensor::SenseOneCycle(void)
|
||||
{
|
||||
noInterrupts();
|
||||
DIRECT_WRITE_LOW(sReg, sBit); // sendPin Register low
|
||||
DIRECT_MODE_INPUT(rReg, rBit); // receivePin to input (pullups are off)
|
||||
DIRECT_MODE_OUTPUT(rReg, rBit); // receivePin to OUTPUT
|
||||
DIRECT_WRITE_LOW(rReg, rBit); // pin is now LOW AND OUTPUT
|
||||
delayMicroseconds(10);
|
||||
DIRECT_MODE_INPUT(rReg, rBit); // receivePin to input (pullups are off)
|
||||
DIRECT_WRITE_HIGH(sReg, sBit); // sendPin High
|
||||
interrupts();
|
||||
|
||||
while ( !DIRECT_READ(rReg, rBit) && (total < CS_Timeout_Millis) ) { // while receive pin is LOW AND total is positive value
|
||||
total++;
|
||||
}
|
||||
//Serial.print("SenseOneCycle(1): "); Serial.println(total);
|
||||
|
||||
if (total > CS_Timeout_Millis) {
|
||||
return -2; // total variable over timeout
|
||||
}
|
||||
|
||||
// set receive pin HIGH briefly to charge up fully - because the while loop above will exit when pin is ~ 2.5V
|
||||
noInterrupts();
|
||||
DIRECT_WRITE_HIGH(rReg, rBit);
|
||||
DIRECT_MODE_OUTPUT(rReg, rBit); // receivePin to OUTPUT - pin is now HIGH AND OUTPUT
|
||||
DIRECT_WRITE_HIGH(rReg, rBit);
|
||||
DIRECT_MODE_INPUT(rReg, rBit); // receivePin to INPUT (pullup is off)
|
||||
DIRECT_WRITE_LOW(sReg, sBit); // sendPin LOW
|
||||
interrupts();
|
||||
|
||||
#ifdef FIVE_VOLT_TOLERANCE_WORKAROUND
|
||||
DIRECT_MODE_OUTPUT(rReg, rBit);
|
||||
DIRECT_WRITE_LOW(rReg, rBit);
|
||||
delayMicroseconds(10);
|
||||
DIRECT_MODE_INPUT(rReg, rBit); // receivePin to INPUT (pullup is off)
|
||||
#else
|
||||
while ( DIRECT_READ(rReg, rBit) && (total < CS_Timeout_Millis) ) { // while receive pin is HIGH AND total is less than timeout
|
||||
total++;
|
||||
}
|
||||
#endif
|
||||
//Serial.print("SenseOneCycle(2): ");
|
||||
//Serial.println(total);
|
||||
|
||||
if (total >= CS_Timeout_Millis) {
|
||||
return -2; // total variable over timeout
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
CapacitiveSense.h v.04 - Capacitive Sensing Library for 'duino / Wiring
|
||||
https://github.com/PaulStoffregen/CapacitiveSensor
|
||||
http://www.pjrc.com/teensy/td_libs_CapacitiveSensor.html
|
||||
http://playground.arduino.cc/Main/CapacitiveSensor
|
||||
Copyright (c) 2008 Paul Bagder All rights reserved.
|
||||
Version 05 by Paul Stoffregen - Support non-AVR board: Teensy 3.x, Arduino Due
|
||||
Version 04 by Paul Stoffregen - Arduino 1.0 compatibility, issue 146 fix
|
||||
vim: set ts=4:
|
||||
*/
|
||||
|
||||
// ensure this library description is only included once
|
||||
#ifndef CapacitiveSensor_h
|
||||
#define CapacitiveSensor_h
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
// Direct I/O through registers and bitmask (from OneWire library)
|
||||
|
||||
#if defined(__AVR__)
|
||||
#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin)))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint8_t
|
||||
#define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0)
|
||||
#define DIRECT_MODE_INPUT(base, mask) ((*((base)+1)) &= ~(mask), (*((base)+2)) &= ~(mask))
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+1)) |= (mask))
|
||||
#define DIRECT_WRITE_LOW(base, mask) ((*((base)+2)) &= ~(mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+2)) |= (mask))
|
||||
|
||||
#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK66FX1M0__) || defined(__MK64FX512__)
|
||||
#define PIN_TO_BASEREG(pin) (portOutputRegister(pin))
|
||||
#define PIN_TO_BITMASK(pin) (1)
|
||||
#define IO_REG_TYPE uint8_t
|
||||
#define IO_REG_ASM
|
||||
#define DIRECT_READ(base, mask) (*((base)+512))
|
||||
#define DIRECT_MODE_INPUT(base, mask) (*((base)+640) = 0)
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+640) = 1)
|
||||
#define DIRECT_WRITE_LOW(base, mask) (*((base)+256) = 1)
|
||||
#define DIRECT_WRITE_HIGH(base, mask) (*((base)+128) = 1)
|
||||
|
||||
#elif defined(__MKL26Z64__)
|
||||
#define PIN_TO_BASEREG(pin) (portOutputRegister(pin))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint8_t
|
||||
#define IO_REG_ASM
|
||||
#define DIRECT_READ(base, mask) ((*((base)+16) & (mask)) ? 1 : 0)
|
||||
#define DIRECT_MODE_INPUT(base, mask) (*((base)+20) &= ~(mask))
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+20) |= (mask))
|
||||
#define DIRECT_WRITE_LOW(base, mask) (*((base)+8) = (mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) (*((base)+4) = (mask))
|
||||
|
||||
#elif defined(__SAM3X8E__)
|
||||
#define PIN_TO_BASEREG(pin) (&(digitalPinToPort(pin)->PIO_PER))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_ASM
|
||||
#define DIRECT_READ(base, mask) (((*((base)+15)) & (mask)) ? 1 : 0)
|
||||
#define DIRECT_MODE_INPUT(base, mask) ((*((base)+5)) = (mask))
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+4)) = (mask))
|
||||
#define DIRECT_WRITE_LOW(base, mask) ((*((base)+13)) = (mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+12)) = (mask))
|
||||
|
||||
#elif defined(__PIC32MX__)
|
||||
#define PIN_TO_BASEREG(pin) (portModeRegister(digitalPinToPort(pin)))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_ASM
|
||||
#define DIRECT_READ(base, mask) (((*(base+4)) & (mask)) ? 1 : 0) //PORTX + 0x10
|
||||
#define DIRECT_MODE_INPUT(base, mask) ((*(base+2)) = (mask)) //TRISXSET + 0x08
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) ((*(base+1)) = (mask)) //TRISXCLR + 0x04
|
||||
#define DIRECT_WRITE_LOW(base, mask) ((*(base+8+1)) = (mask)) //LATXCLR + 0x24
|
||||
#define DIRECT_WRITE_HIGH(base, mask) ((*(base+8+2)) = (mask)) //LATXSET + 0x28
|
||||
|
||||
#elif defined(ARDUINO_ARCH_ESP8266)
|
||||
#define PIN_TO_BASEREG(pin) (portOutputRegister(digitalPinToPort(pin)))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_ASM
|
||||
#define DIRECT_READ(base, mask) (((*(base+6)) & (mask)) ? 1 : 0) //GPIO_IN_ADDRESS
|
||||
#define DIRECT_MODE_INPUT(base, mask) ((*(base+5)) = (mask)) //GPIO_ENABLE_W1TC_ADDRESS
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) ((*(base+4)) = (mask)) //GPIO_ENABLE_W1TS_ADDRESS
|
||||
#define DIRECT_WRITE_LOW(base, mask) ((*(base+2)) = (mask)) //GPIO_OUT_W1TC_ADDRESS
|
||||
#define DIRECT_WRITE_HIGH(base, mask) ((*(base+1)) = (mask)) //GPIO_OUT_W1TS_ADDRESS
|
||||
|
||||
#elif defined(__SAMD21G18A__)
|
||||
// runs extremely slow/unreliable on Arduino Zero - help wanted....
|
||||
#define PIN_TO_BASEREG(pin) portModeRegister(digitalPinToPort(pin))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_ASM
|
||||
#define DIRECT_READ(base, mask) (((*((base)+8)) & (mask)) ? 1 : 0)
|
||||
#define DIRECT_MODE_INPUT(base, mask) ((*((base)+1)) = (mask))
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+2)) = (mask))
|
||||
#define DIRECT_WRITE_LOW(base, mask) ((*((base)+5)) = (mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+6)) = (mask))
|
||||
|
||||
#elif defined(RBL_NRF51822)
|
||||
#define PIN_TO_BASEREG(pin) (0)
|
||||
#define PIN_TO_BITMASK(pin) (pin)
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_ASM
|
||||
#define DIRECT_READ(base, pin) nrf_gpio_pin_read(pin)
|
||||
#define DIRECT_WRITE_LOW(base, pin) nrf_gpio_pin_clear(pin)
|
||||
#define DIRECT_WRITE_HIGH(base, pin) nrf_gpio_pin_set(pin)
|
||||
#define DIRECT_MODE_INPUT(base, pin) nrf_gpio_cfg_input(pin, NRF_GPIO_PIN_NOPULL)
|
||||
#define DIRECT_MODE_OUTPUT(base, pin) nrf_gpio_cfg_output(pin)
|
||||
|
||||
#elif defined(__arc__)
|
||||
|
||||
#include "scss_registers.h"
|
||||
#include "portable.h"
|
||||
#include "avr/pgmspace.h"
|
||||
|
||||
#define GPIO_ID(pin) (g_APinDescription[pin].ulGPIOId)
|
||||
#define GPIO_TYPE(pin) (g_APinDescription[pin].ulGPIOType)
|
||||
#define GPIO_BASE(pin) (g_APinDescription[pin].ulGPIOBase)
|
||||
#define DIR_OFFSET_SS 0x01
|
||||
#define DIR_OFFSET_SOC 0x04
|
||||
#define EXT_PORT_OFFSET_SS 0x0A
|
||||
#define EXT_PORT_OFFSET_SOC 0x50
|
||||
|
||||
/* GPIO registers base address */
|
||||
#define PIN_TO_BASEREG(pin) ((volatile uint32_t *)g_APinDescription[pin].ulGPIOBase)
|
||||
#define PIN_TO_BITMASK(pin) pin
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_ASM
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
IO_REG_TYPE directRead(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
|
||||
{
|
||||
IO_REG_TYPE ret;
|
||||
if (SS_GPIO == GPIO_TYPE(pin)) {
|
||||
ret = READ_ARC_REG(((IO_REG_TYPE)base + EXT_PORT_OFFSET_SS));
|
||||
} else {
|
||||
ret = MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, EXT_PORT_OFFSET_SOC);
|
||||
}
|
||||
return ((ret >> GPIO_ID(pin)) & 0x01);
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directModeInput(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
|
||||
{
|
||||
if (SS_GPIO == GPIO_TYPE(pin)) {
|
||||
WRITE_ARC_REG(READ_ARC_REG((((IO_REG_TYPE)base) + DIR_OFFSET_SS)) & ~(0x01 << GPIO_ID(pin)),
|
||||
((IO_REG_TYPE)(base) + DIR_OFFSET_SS));
|
||||
} else {
|
||||
MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) &= ~(0x01 << GPIO_ID(pin));
|
||||
}
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directModeOutput(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
|
||||
{
|
||||
if (SS_GPIO == GPIO_TYPE(pin)) {
|
||||
WRITE_ARC_REG(READ_ARC_REG(((IO_REG_TYPE)(base) + DIR_OFFSET_SS)) | (0x01 << GPIO_ID(pin)),
|
||||
((IO_REG_TYPE)(base) + DIR_OFFSET_SS));
|
||||
} else {
|
||||
MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) |= (0x01 << GPIO_ID(pin));
|
||||
}
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directWriteLow(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
|
||||
{
|
||||
if (SS_GPIO == GPIO_TYPE(pin)) {
|
||||
WRITE_ARC_REG(READ_ARC_REG(base) & ~(0x01 << GPIO_ID(pin)), base);
|
||||
} else {
|
||||
MMIO_REG_VAL(base) &= ~(0x01 << GPIO_ID(pin));
|
||||
}
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directWriteHigh(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
|
||||
{
|
||||
if (SS_GPIO == GPIO_TYPE(pin)) {
|
||||
WRITE_ARC_REG(READ_ARC_REG(base) | (0x01 << GPIO_ID(pin)), base);
|
||||
} else {
|
||||
MMIO_REG_VAL(base) |= (0x01 << GPIO_ID(pin));
|
||||
}
|
||||
}
|
||||
|
||||
#define DIRECT_READ(base, pin) directRead(base, pin)
|
||||
#define DIRECT_MODE_INPUT(base, pin) directModeInput(base, pin)
|
||||
#define DIRECT_MODE_OUTPUT(base, pin) directModeOutput(base, pin)
|
||||
#define DIRECT_WRITE_LOW(base, pin) directWriteLow(base, pin)
|
||||
#define DIRECT_WRITE_HIGH(base, pin) directWriteHigh(base, pin)
|
||||
|
||||
#endif
|
||||
|
||||
// some 3.3V chips with 5V tolerant pins need this workaround
|
||||
//
|
||||
#if defined(__MK20DX256__)
|
||||
#define FIVE_VOLT_TOLERANCE_WORKAROUND
|
||||
#endif
|
||||
|
||||
// library interface description
|
||||
class CPlay_CapacitiveSensor
|
||||
{
|
||||
// user-accessible "public" interface
|
||||
public:
|
||||
// methods
|
||||
CPlay_CapacitiveSensor(uint8_t sendPin = 0, uint8_t receivePin = 0);
|
||||
long capacitiveSensorRaw(uint8_t samples);
|
||||
long capacitiveSensor(uint8_t samples);
|
||||
void set_CS_Timeout_Millis(unsigned long timeout_millis);
|
||||
void reset_CS_AutoCal();
|
||||
void set_CS_AutocaL_Millis(unsigned long autoCal_millis);
|
||||
// library-accessible "private" interface
|
||||
private:
|
||||
// variables
|
||||
int error;
|
||||
unsigned long leastTotal;
|
||||
unsigned int loopTimingFactor;
|
||||
unsigned long CS_Timeout_Millis;
|
||||
unsigned long CS_AutocaL_Millis;
|
||||
unsigned long lastCal;
|
||||
unsigned long total;
|
||||
IO_REG_TYPE sBit; // send pin's ports and bitmask
|
||||
volatile IO_REG_TYPE *sReg;
|
||||
IO_REG_TYPE rBit; // receive pin's ports and bitmask
|
||||
volatile IO_REG_TYPE *rReg;
|
||||
// methods
|
||||
int SenseOneCycle(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
#CapacitiveSensor Library#
|
||||
|
||||
CapacitiveSensor lets you create sensors that can detect touch or proximity.
|
||||
|
||||
http://www.pjrc.com/teensy/td_libs_CapacitiveSensor.html
|
||||
|
||||
http://playground.arduino.cc/Main/CapacitiveSensor
|
||||
|
||||
http://www.youtube.com/watch?v=BHQPqQ_5ulc
|
||||
|
||||
CapacitiveSensor was originally written by Paul Badger and is now maintained by Paul Stoffregen.
|
||||
|
||||

|
||||
@@ -0,0 +1,67 @@
|
||||
// This is a mash-up of the Due show() code + insights from Michael Miller's
|
||||
// ESP8266 work for the NeoPixelBus library: github.com/Makuna/NeoPixelBus
|
||||
// Needs to be a separate .c file to enforce ICACHE_RAM_ATTR execution.
|
||||
|
||||
#ifdef ESP8266
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <eagle_soc.h>
|
||||
|
||||
static uint32_t _getCycleCount(void) __attribute__((always_inline));
|
||||
static inline uint32_t _getCycleCount(void) {
|
||||
uint32_t ccount;
|
||||
__asm__ __volatile__("rsr %0,ccount":"=a" (ccount));
|
||||
return ccount;
|
||||
}
|
||||
|
||||
void ICACHE_RAM_ATTR espShow(
|
||||
uint8_t pin, uint8_t *pixels, uint32_t numBytes, boolean is800KHz) {
|
||||
|
||||
#define CYCLES_800_T0H (F_CPU / 2500000) // 0.4us
|
||||
#define CYCLES_800_T1H (F_CPU / 1250000) // 0.8us
|
||||
#define CYCLES_800 (F_CPU / 800000) // 1.25us per bit
|
||||
#define CYCLES_400_T0H (F_CPU / 2000000) // 0.5uS
|
||||
#define CYCLES_400_T1H (F_CPU / 833333) // 1.2us
|
||||
#define CYCLES_400 (F_CPU / 400000) // 2.5us per bit
|
||||
|
||||
uint8_t *p, *end, pix, mask;
|
||||
uint32_t t, time0, time1, period, c, startTime, pinMask;
|
||||
|
||||
pinMask = _BV(pin);
|
||||
p = pixels;
|
||||
end = p + numBytes;
|
||||
pix = *p++;
|
||||
mask = 0x80;
|
||||
startTime = 0;
|
||||
|
||||
#ifdef NEO_KHZ400
|
||||
if(is800KHz) {
|
||||
#endif
|
||||
time0 = CYCLES_800_T0H;
|
||||
time1 = CYCLES_800_T1H;
|
||||
period = CYCLES_800;
|
||||
#ifdef NEO_KHZ400
|
||||
} else { // 400 KHz bitstream
|
||||
time0 = CYCLES_400_T0H;
|
||||
time1 = CYCLES_400_T1H;
|
||||
period = CYCLES_400;
|
||||
}
|
||||
#endif
|
||||
|
||||
for(t = time0;; t = time0) {
|
||||
if(pix & mask) t = time1; // Bit high duration
|
||||
while(((c = _getCycleCount()) - startTime) < period); // Wait for bit start
|
||||
GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinMask); // Set high
|
||||
startTime = c; // Save start time
|
||||
while(((c = _getCycleCount()) - startTime) < t); // Wait high duration
|
||||
GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinMask); // Set low
|
||||
if(!(mask >>= 1)) { // Next bit/byte
|
||||
if(p >= end) break;
|
||||
pix = *p++;
|
||||
mask = 0x80;
|
||||
}
|
||||
}
|
||||
while((_getCycleCount() - startTime) < period); // Wait for last bit
|
||||
}
|
||||
|
||||
#endif // ESP8266
|
||||
@@ -0,0 +1,431 @@
|
||||
;-----------------------------------------------------------------------------;
|
||||
; Fixed-point FFT routines for megaAVRs (C)ChaN, 2005
|
||||
;-----------------------------------------------------------------------------;
|
||||
; * This program is opened under license policy of following trems.
|
||||
;
|
||||
; Copyright (C) 2005, ChaN, all right reserved.
|
||||
;
|
||||
; * This program is a free software and there is NO WARRANTY.
|
||||
; * No restriction on use. You can use, modify and redistribute it for
|
||||
; personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY.
|
||||
; * Redistributions of source code must retain the above copyright notice.
|
||||
;
|
||||
;-----------------------------------------------------------------------------;
|
||||
;
|
||||
; void fft_input (const int16_t *array_src, complex_t *array_bfly);
|
||||
; void fft_execute (complex_t *array_bfly);
|
||||
; void fft_output (complex_t *array_bfly, uint16_t *array_dst);
|
||||
;
|
||||
; <array_src>: Wave form to be processed.
|
||||
; <array_bfly>: Complex array for butterfly operations.
|
||||
; <array_dst>: Spectrum output buffer.
|
||||
;
|
||||
; These functions must be called in sequence to do a DFT in FFT algorithm.
|
||||
; fft_input() fills the complex array with a wave form to prepare butterfly
|
||||
; operations. A hamming window is applied at the same time.
|
||||
; fft_execute() executes the butterfly operations.
|
||||
; fft_output() re-orders the results, converts the complex spectrum into
|
||||
; scalar spectrum and output it in linear scale.
|
||||
;
|
||||
;----------------------------------------------------------------------------;
|
||||
; THIS CODE HAS BEEN MODIFIED FROM ITS ORIGINAL FORM - it is pared down
|
||||
; to handle 64 points only, for the Circuit Playground microphone library.
|
||||
; Original FFFT code can be found on GitHub.
|
||||
;----------------------------------------------------------------------------;
|
||||
|
||||
.list
|
||||
|
||||
#define FFT_N 64
|
||||
#define FFT_B 6
|
||||
|
||||
#define T0L r0
|
||||
#define T0H r1
|
||||
#define T2L r2
|
||||
#define T2H r3
|
||||
#define T4L r4
|
||||
#define T4H r5
|
||||
#define T6L r6
|
||||
#define T6H r7
|
||||
#define T8L r8
|
||||
#define T8H r9
|
||||
#define T10L r10
|
||||
#define T10H r11
|
||||
#define T12L r12
|
||||
#define T12H r13
|
||||
#define T14L r14
|
||||
#define T14H r15
|
||||
#define AL r16
|
||||
#define AH r17
|
||||
#define BL r18
|
||||
#define BH r19
|
||||
#define CL r20
|
||||
#define CH r21
|
||||
#define DL r22
|
||||
#define DH r23
|
||||
#define EL r24
|
||||
#define EH r25
|
||||
#define XL r26
|
||||
#define XH r27
|
||||
#define YL r28
|
||||
#define YH r29
|
||||
#define ZL r30
|
||||
#define ZH r31
|
||||
|
||||
.macro ldiw dh,dl, abs
|
||||
ldi \dl, lo8(\abs)
|
||||
ldi \dh, hi8(\abs)
|
||||
.endm
|
||||
|
||||
.macro subiw dh,dl, abs
|
||||
subi \dl, lo8(\abs)
|
||||
sbci \dh, hi8(\abs)
|
||||
.endm
|
||||
|
||||
.macro addw dh,dl, sh,sl
|
||||
add \dl, \sl
|
||||
adc \dh, \sh
|
||||
.endm
|
||||
|
||||
.macro addd d3,d2,d1,d0, s3,s2,s1,s0
|
||||
add \d0, \s0
|
||||
adc \d1, \s1
|
||||
adc \d2, \s2
|
||||
adc \d3, \s3
|
||||
.endm
|
||||
|
||||
.macro subw dh,dl, sh,sl
|
||||
sub \dl, \sl
|
||||
sbc \dh, \sh
|
||||
.endm
|
||||
|
||||
.macro subd d3,d2,d1,d0, s3,s2,s1,s0
|
||||
sub \d0, \s0
|
||||
sbc \d1, \s1
|
||||
sbc \d2, \s2
|
||||
sbc \d3, \s3
|
||||
.endm
|
||||
|
||||
.macro lddw dh,dl, src
|
||||
ldd \dl, \src
|
||||
ldd \dh, \src+1
|
||||
.endm
|
||||
|
||||
.macro ldw dh,dl, src
|
||||
ld \dl, \src
|
||||
ld \dh, \src
|
||||
.endm
|
||||
|
||||
.macro stw dst, sh,sl
|
||||
st \dst, \sl
|
||||
st \dst, \sh
|
||||
.endm
|
||||
|
||||
.macro clrw dh, dl
|
||||
clr \dh
|
||||
clr \dl
|
||||
.endm
|
||||
|
||||
.macro lsrw dh, dl
|
||||
lsr \dh
|
||||
ror \dl
|
||||
.endm
|
||||
|
||||
.macro asrw dh, dl
|
||||
asr \dh
|
||||
ror \dl
|
||||
.endm
|
||||
|
||||
.macro lslw dh, dl
|
||||
lsl \dl
|
||||
rol \dh
|
||||
.endm
|
||||
|
||||
.macro pushw dh, dl
|
||||
push \dh
|
||||
push \dl
|
||||
.endm
|
||||
|
||||
.macro popw dh, dl
|
||||
pop \dl
|
||||
pop \dh
|
||||
.endm
|
||||
|
||||
.macro lpmw dh,dl, src
|
||||
lpm \dl, \src
|
||||
lpm \dh, \src
|
||||
.endm
|
||||
|
||||
.macro rjne lbl
|
||||
breq 99f
|
||||
rjmp \lbl
|
||||
99:
|
||||
.endm
|
||||
|
||||
.macro FMULS16 d3,d2,d1,d0 ,s1h,s1l, s2h,s2l ;Fractional Multiply (19clk)
|
||||
fmuls \s1h, \s2h
|
||||
movw \d2, T0L
|
||||
fmul \s1l, \s2l
|
||||
movw \d0, T0L
|
||||
adc \d2, EH ;EH: zero reg.
|
||||
fmulsu \s1h, \s2l
|
||||
sbc \d3, EH
|
||||
add \d1, T0L
|
||||
adc \d2, T0H
|
||||
adc \d3, EH
|
||||
fmulsu \s2h, \s1l
|
||||
sbc \d3, EH
|
||||
add \d1, T0L
|
||||
adc \d2, T0H
|
||||
adc \d3, EH
|
||||
.endm
|
||||
|
||||
.macro SQRT32 ; 32bit square root (526..542clk)
|
||||
clr T6L
|
||||
clr T6H
|
||||
clr T8L
|
||||
clr T8H
|
||||
ldi BL, 1
|
||||
ldi BH, 0
|
||||
clr CL
|
||||
clr CH
|
||||
ldi DH, 16
|
||||
90: lsl T2L
|
||||
rol T2H
|
||||
rol T4L
|
||||
rol T4H
|
||||
rol T6L
|
||||
rol T6H
|
||||
rol T8L
|
||||
rol T8H
|
||||
lsl T2L
|
||||
rol T2H
|
||||
rol T4L
|
||||
rol T4H
|
||||
rol T6L
|
||||
rol T6H
|
||||
rol T8L
|
||||
rol T8H
|
||||
brpl 91f
|
||||
add T6L, BL
|
||||
adc T6H, BH
|
||||
adc T8L, CL
|
||||
adc T8H, CH
|
||||
rjmp 92f
|
||||
91: sub T6L, BL
|
||||
sbc T6H, BH
|
||||
sbc T8L, CL
|
||||
sbc T8H, CH
|
||||
92: lsl BL
|
||||
rol BH
|
||||
rol CL
|
||||
andi BL, 0b11111000
|
||||
ori BL, 0b00000101
|
||||
sbrc T8H, 7
|
||||
subi BL, 2
|
||||
dec DH
|
||||
brne 90b
|
||||
lsr CL
|
||||
ror BH
|
||||
ror BL
|
||||
lsr CL
|
||||
ror BH
|
||||
ror BL
|
||||
.endm
|
||||
|
||||
;----------------------------------------------------------------------------;
|
||||
; Constant Tables
|
||||
|
||||
.global tbl_window
|
||||
tbl_window: ; tbl_window[] = ... (This is a Hamming window)
|
||||
.dc.w 2621, 2693, 2910, 3270, 3768, 4401, 5161, 6042, 7036, 8132, 9320, 10588, 11926, 13318, 14753, 16216
|
||||
.dc.w 17694, 19171, 20634, 22069, 23462, 24799, 26068, 27256, 28352, 29345, 30226, 30987, 31619, 32117, 32477, 32694
|
||||
.dc.w 32766, 32694, 32477, 32117, 31619, 30987, 30226, 29345, 28352, 27256, 26068, 24799, 23462, 22069, 20634, 19171
|
||||
.dc.w 17694, 16216, 14753, 13318, 11926, 10588, 9320, 8132, 7036, 6042, 5161, 4401, 3768, 3270, 2910, 2693
|
||||
tbl_cos_sin: ; Table of {cos(x),sin(x)}, (0 <= x < pi, in FFT_N/2 steps)
|
||||
.dc.w 32767, 0, 32609, 3211, 32137, 6392, 31356, 9511, 30272, 12539, 28897, 15446, 27244, 18204, 25329, 20787
|
||||
.dc.w 23169, 23169, 20787, 25329, 18204, 27244, 15446, 28897, 12539, 30272, 9511, 31356, 6392, 32137, 3211, 32609
|
||||
.dc.w 0, 32766, -3211, 32609, -6392, 32137, -9511, 31356, -12539, 30272, -15446, 28897, -18204, 27244, -20787, 25329
|
||||
.dc.w -23169, 23169, -25329, 20787, -27244, 18204, -28897, 15446, -30272, 12539, -31356, 9511, -32137, 6392, -32609, 3211
|
||||
tbl_bitrev: ; tbl_bitrev[] = ...
|
||||
.dc.w 0*4, 32*4, 16*4, 48*4, 8*4, 40*4, 24*4, 56*4, 4*4, 36*4, 20*4, 52*4, 12*4, 44*4, 28*4, 60*4
|
||||
.dc.w 2*4, 34*4, 18*4, 50*4, 10*4, 42*4, 26*4, 58*4, 6*4, 38*4, 22*4, 54*4, 14*4, 46*4, 30*4, 62*4
|
||||
|
||||
;----------------------------------------------------------------------------;
|
||||
.global fft_input
|
||||
.func fft_input
|
||||
fft_input:
|
||||
pushw T2H,T2L
|
||||
pushw AH,AL
|
||||
pushw YH,YL
|
||||
|
||||
movw XL, EL ;X = array_src;
|
||||
movw YL, DL ;Y = array_bfly;
|
||||
clr EH ;Zero
|
||||
ldiw ZH,ZL, tbl_window ;Z = &tbl_window[0];
|
||||
ldiw AH,AL, FFT_N ;A = FFT_N;
|
||||
1: lpmw BH,BL, Z+ ;B = *Z++; (window)
|
||||
ldw CH,CL, X+ ;C = *X++; (I-axis)
|
||||
FMULS16 DH,DL,T2H,T2L, BH,BL, CH,CL ;D = B * C;
|
||||
stw Y+, DH,DL ;*Y++ = D;
|
||||
stw Y+, DH,DL ;*Y++ = D;
|
||||
subiw AH,AL, 1 ;while(--A)
|
||||
brne 1b ;/
|
||||
|
||||
popw YH,YL
|
||||
popw AH,AL
|
||||
popw T2H,T2L
|
||||
clr r1
|
||||
ret
|
||||
.endfunc
|
||||
|
||||
;----------------------------------------------------------------------------;
|
||||
.global fft_execute
|
||||
.func fft_execute
|
||||
fft_execute:
|
||||
pushw T2H,T2L
|
||||
pushw T4H,T4L
|
||||
pushw T6H,T6L
|
||||
pushw T8H,T8L
|
||||
pushw T10H,T10L
|
||||
pushw T12H,T12L
|
||||
pushw T14H,T14L
|
||||
pushw AH,AL
|
||||
pushw YH,YL
|
||||
|
||||
movw ZL, EL ;Z = array_bfly;
|
||||
ldiw EH,EL, 1 ;E = 1;
|
||||
ldiw XH,XL, FFT_N/2 ;X = FFT_N/2;
|
||||
1: ldi AL, 4 ;T12 = E; (angular speed)
|
||||
mul EL, AL ;
|
||||
movw T12L, T0L ;
|
||||
mul EH, AL ;
|
||||
add T12H, T0L ;/
|
||||
movw T14L, EL ;T14 = E;
|
||||
pushw EH,EL
|
||||
movw YL, ZL ;Z = &array_bfly[0];
|
||||
mul XL, AL ;Y = &array_bfly[X];
|
||||
addw YH,YL, T0H,T0L ;
|
||||
mul XH, AL ;
|
||||
add YH, T0L ;/
|
||||
pushw ZH,ZL
|
||||
2: clrw T10H,T10L ;T10 = 0 (angle)
|
||||
clr EH ;Zero reg.
|
||||
3: lddw AH,AL, Z+0 ;A = *Z - *Y; *Z++ += *Y;
|
||||
asrw AH,AL ;
|
||||
lddw DH,DL, Y+0 ;
|
||||
asrw DH,DL ;
|
||||
movw CL, AL ;
|
||||
subw AH,AL, DH,DL ;
|
||||
addw CH,CL, DH,DL ;
|
||||
stw Z+, CH,CL ;/
|
||||
lddw BH,BL, Z+0 ;B = *Z - *Y; *Z++ += *Y;
|
||||
asrw BH,BL ;
|
||||
lddw DH,DL, Y+2 ;
|
||||
asrw DH,DL ;
|
||||
movw CL, BL ;
|
||||
subw BH,BL, DH,DL ;
|
||||
addw CH,CL, DH,DL ;
|
||||
stw Z+, CH,CL ;/
|
||||
movw T0L, ZL
|
||||
ldiw ZH,ZL, tbl_cos_sin ;C = cos(T10); D = sin(T10);
|
||||
addw ZH,ZL, T10H,T10L ;
|
||||
lpmw CH,CL, Z+ ;
|
||||
lpmw DH,DL, Z+ ;/
|
||||
movw ZL, T0L
|
||||
FMULS16 T4H,T4L,T2H,T2L, AH,AL, CH,CL ;*Y++ = A * C + B * D;
|
||||
FMULS16 T8H,T8L,T6H,T6L, BH,BL, DH,DL ;
|
||||
addd T4H,T4L,T2H,T2L, T8H,T8L,T6H,T6L;
|
||||
stw Y+, T4H,T4L ;/
|
||||
FMULS16 T4H,T4L,T2H,T2L, BH,BL, CH,CL ;*Y++ = B * C - A * D;
|
||||
FMULS16 T8H,T8L,T6H,T6L, AH,AL, DH,DL ;
|
||||
subd T4H,T4L,T2H,T2L, T8H,T8L,T6H,T6L;
|
||||
stw Y+, T4H,T4L ;/
|
||||
addw T10H,T10L, T12H,T12L ;T10 += T12; (next angle)
|
||||
#if FFT_N >= 128
|
||||
sbrs T10H, FFT_B - 7 ;while(T10 < pi)
|
||||
#else
|
||||
sbrs T10L, FFT_B + 1
|
||||
#endif
|
||||
rjmp 3b ;/
|
||||
ldi AL, 4 ;Y += X; Z += X; (skip split segment)
|
||||
mul XL, AL
|
||||
addw YH,YL, T0H,T0L ;
|
||||
addw ZH,ZL, T0H,T0L ;
|
||||
mul XH, AL ;
|
||||
add YH, T0L ;
|
||||
add ZH, T0L ;/
|
||||
ldi EL, 1 ;while(--T14)
|
||||
subw T14H,T14L, EH,EL ;
|
||||
rjne 2b ;/
|
||||
popw ZH,ZL
|
||||
popw EH,EL
|
||||
lslw EH,EL ;E *= 2;
|
||||
lsrw XH,XL ;while(X /= 2)
|
||||
adiw XL, 0 ;
|
||||
rjne 1b ;/
|
||||
|
||||
popw YH,YL
|
||||
popw AH,AL
|
||||
popw T14H,T14L
|
||||
popw T12H,T12L
|
||||
popw T10H,T10L
|
||||
popw T8H,T8L
|
||||
popw T6H,T6L
|
||||
popw T4H,T4L
|
||||
popw T2H,T2L
|
||||
; clr r1
|
||||
ret
|
||||
.endfunc
|
||||
|
||||
;----------------------------------------------------------------------------;
|
||||
.global fft_output
|
||||
.func fft_output
|
||||
fft_output:
|
||||
pushw T2H,T2L
|
||||
pushw T4H,T4L
|
||||
pushw T6H,T6L
|
||||
pushw T8H,T8L
|
||||
pushw T10H,T10L
|
||||
pushw AH,AL
|
||||
pushw YH,YL
|
||||
|
||||
movw T10L, EL ;T10 = array_bfly;
|
||||
movw YL, DL ;Y = array_output;
|
||||
ldiw ZH,ZL, tbl_bitrev ;Z = tbl_bitrev;
|
||||
clr EH ;Zero
|
||||
ldiw AH,AL, FFT_N / 2 ;A = FFT_N / 2; (plus only)
|
||||
1: lpmw XH,XL, Z+ ;X = *Z++;
|
||||
addw XH,XL, T10H,T10L ;X += array_bfly;
|
||||
ldw BH,BL, X+ ;B = *X++;
|
||||
ldw CH,CL, X+ ;C = *X++;
|
||||
FMULS16 T4H,T4L,T2H,T2L, BH,BL, BH,BL ;T4:T2 = B * B;
|
||||
FMULS16 T8H,T8L,T6H,T6L, CH,CL, CH,CL ;T8:T6 = C * C;
|
||||
addd T4H,T4L,T2H,T2L, T8H,T8L,T6H,T6L;T4:T2 += T8:T6;
|
||||
SQRT32 ;B = sqrt(T4:T2);
|
||||
stw Y+, BH,BL ;*Y++ = B;
|
||||
subiw AH,AL, 1 ;while(--A)
|
||||
rjne 1b ;/
|
||||
|
||||
popw YH,YL
|
||||
popw AH,AL
|
||||
popw T10H,T10L
|
||||
popw T8H,T8L
|
||||
popw T6H,T6L
|
||||
popw T4H,T4L
|
||||
popw T2H,T2L
|
||||
clr r1
|
||||
ret
|
||||
.endfunc
|
||||
|
||||
;----------------------------------------------------------------------------;
|
||||
.global fmuls_f
|
||||
.func fmuls_f
|
||||
fmuls_f:
|
||||
movw CL, EL ;C = E;
|
||||
clr EH ;Zero
|
||||
FMULS16 ZH,ZL,XH,XL, CH,CL, DH,DL ;Z:X = C * D;
|
||||
movw EL, ZL
|
||||
clr r1
|
||||
ret
|
||||
.endfunc
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
// Talkie library
|
||||
// Copyright 2011 Peter Knight
|
||||
// This code is released under GPLv2 license.
|
||||
|
||||
#include "Adafruit_CPlay_Speaker.h"
|
||||
|
||||
#define FS 8000 // Speech engine sample rate
|
||||
#define TICKS (FS / 40) // Speech data rate
|
||||
#define USEC ((1000000 + (FS / 2)) / FS) // Sample period (microseconds)
|
||||
|
||||
static const int16_t PROGMEM
|
||||
tmsK1[] = {0x82C0,0x8380,0x83C0,0x8440,0x84C0,0x8540,0x8600,0x8780,
|
||||
0x8880,0x8980,0x8AC0,0x8C00,0x8D40,0x8F00,0x90C0,0x92C0,
|
||||
0x9900,0xA140,0xAB80,0xB840,0xC740,0xD8C0,0xEBC0,0x0000,
|
||||
0x1440,0x2740,0x38C0,0x47C0,0x5480,0x5EC0,0x6700,0x6D40},
|
||||
tmsK2[] = {0xAE00,0xB480,0xBB80,0xC340,0xCB80,0xD440,0xDDC0,0xE780,
|
||||
0xF180,0xFBC0,0x0600,0x1040,0x1A40,0x2400,0x2D40,0x3600,
|
||||
0x3E40,0x45C0,0x4CC0,0x5300,0x5880,0x5DC0,0x6240,0x6640,
|
||||
0x69C0,0x6CC0,0x6F80,0x71C0,0x73C0,0x7580,0x7700,0x7E80};
|
||||
|
||||
static const int8_t PROGMEM
|
||||
tmsK3[] = {0x92,0x9F,0xAD,0xBA,0xC8,0xD5,0xE3,0xF0,
|
||||
0xFE,0x0B,0x19,0x26,0x34,0x41,0x4F,0x5C},
|
||||
tmsK4[] = {0xAE,0xBC,0xCA,0xD8,0xE6,0xF4,0x01,0x0F,
|
||||
0x1D,0x2B,0x39,0x47,0x55,0x63,0x71,0x7E},
|
||||
tmsK5[] = {0xAE,0xBA,0xC5,0xD1,0xDD,0xE8,0xF4,0xFF,
|
||||
0x0B,0x17,0x22,0x2E,0x39,0x45,0x51,0x5C},
|
||||
tmsK6[] = {0xC0,0xCB,0xD6,0xE1,0xEC,0xF7,0x03,0x0E,
|
||||
0x19,0x24,0x2F,0x3A,0x45,0x50,0x5B,0x66},
|
||||
tmsK7[] = {0xB3,0xBF,0xCB,0xD7,0xE3,0xEF,0xFB,0x07,
|
||||
0x13,0x1F,0x2B,0x37,0x43,0x4F,0x5A,0x66},
|
||||
tmsK8[] = {0xC0,0xD8,0xF0,0x07,0x1F,0x37,0x4F,0x66},
|
||||
tmsK9[] = {0xC0,0xD4,0xE8,0xFC,0x10,0x25,0x39,0x4D},
|
||||
tmsK10[] = {0xCD,0xDF,0xF1,0x04,0x16,0x20,0x3B,0x4D},
|
||||
chirp[] = {0x00,0x2A,0xD4,0x32,0xB2,0x12,0x25,0x14,
|
||||
0x02,0xE1,0xC5,0x02,0x5F,0x5A,0x05,0x0F,
|
||||
0x26,0xFC,0xA5,0xA5,0xD6,0xDD,0xDC,0xFC,
|
||||
0x25,0x2B,0x22,0x21,0x0F,0xFF,0xF8,0xEE,
|
||||
0xED,0xEF,0xF7,0xF6,0xFA,0x00,0x03,0x02,0x01};
|
||||
|
||||
static const uint8_t PROGMEM
|
||||
tmsEnergy[] = {0x00,0x02,0x03,0x04,0x05,0x07,0x0A,0x0F,
|
||||
0x14,0x20,0x29,0x39,0x51,0x72,0xA1,0xFF},
|
||||
tmsPeriod[] = {0x00,0x10,0x11,0x12,0x13,0x14,0x15,0x16,
|
||||
0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,
|
||||
0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,
|
||||
0x27,0x28,0x29,0x2A,0x2B,0x2D,0x2F,0x31,
|
||||
0x33,0x35,0x36,0x39,0x3B,0x3D,0x3F,0x42,
|
||||
0x45,0x47,0x49,0x4D,0x4F,0x51,0x55,0x57,
|
||||
0x5C,0x5F,0x63,0x66,0x6A,0x6E,0x73,0x77,
|
||||
0x7B,0x80,0x85,0x8A,0x8F,0x95,0x9A,0xA0};
|
||||
|
||||
static const uint8_t *ptrAddr;
|
||||
static uint16_t buf;
|
||||
static uint8_t bufBits;
|
||||
|
||||
static inline uint8_t rev(uint8_t a) { // Reverse bit sequence in 8-bit value
|
||||
a = ( a >> 4) | ( a << 4); // 76543210 -> 32107654
|
||||
a = ((a & 0xCC) >> 2) | ((a & 0x33) << 2); // 32107654 -> 10325476
|
||||
a = ((a & 0xAA) >> 1) | ((a & 0x55) << 1); // 10325476 -> 01234567
|
||||
return a;
|
||||
}
|
||||
|
||||
static uint8_t getBits(uint8_t bits) {
|
||||
uint8_t value;
|
||||
if(bits > bufBits) {
|
||||
buf |= rev(pgm_read_byte(ptrAddr)) << (8 - bufBits);
|
||||
bufBits += 8;
|
||||
ptrAddr++; // Don't post-inc in pgm_read_byte! Is a macro.
|
||||
}
|
||||
value = buf >> (16 - bits);
|
||||
buf <<= bits;
|
||||
bufBits -= bits;
|
||||
return value;
|
||||
}
|
||||
|
||||
#define read8(base, bits) pgm_read_byte(&base[getBits(bits)]);
|
||||
#define read16(base, bits) pgm_read_word(&base[getBits(bits)]);
|
||||
|
||||
void Adafruit_CPlay_Speaker::say(const uint8_t *addr) {
|
||||
|
||||
int16_t x0=0, x1=0, x2=0, x3=0, x4=0,
|
||||
x5=0, x6=0, x7=0, x8=0, x9=0,
|
||||
synthK1, synthK2, u0;
|
||||
uint16_t synthEnergy, synthRand = 1;
|
||||
int8_t synthK3, synthK4, synthK5, synthK6,
|
||||
synthK7, synthK8, synthK9, synthK10;
|
||||
uint8_t periodCounter=0, nextPwm = 0x7F, synthPeriod;
|
||||
uint8_t iCount = TICKS;
|
||||
uint32_t nowTime, prevTime=0;
|
||||
|
||||
if(!started) begin();
|
||||
|
||||
buf = bufBits = 0; // Reset 'ROM' reader (global stuff)
|
||||
ptrAddr = addr;
|
||||
|
||||
for(;;) {
|
||||
while(((nowTime = micros()) - prevTime) < USEC);
|
||||
OCR4A = nextPwm;
|
||||
prevTime = nowTime;
|
||||
|
||||
if(++iCount >= TICKS) {
|
||||
// Read speech data, processing the variable size frames
|
||||
uint8_t energy;
|
||||
if((energy = getBits(4)) == 0) { // Rest frame
|
||||
synthEnergy = 0;
|
||||
} else if(energy == 0xF) { // Stop frame; silence
|
||||
TCCR4A = 0x7F;
|
||||
break;
|
||||
} else {
|
||||
synthEnergy = pgm_read_byte(&tmsEnergy[energy]);
|
||||
uint8_t repeat = getBits(1);
|
||||
synthPeriod = pgm_read_byte(&tmsPeriod[getBits(6)]);
|
||||
if(!repeat) { // A repeat frame uses last coefficients
|
||||
synthK1 = read16(tmsK1, 5); // All frames
|
||||
synthK2 = read16(tmsK2, 5); // use the first
|
||||
synthK3 = read8( tmsK3, 4); // 4 coefficients
|
||||
synthK4 = read8( tmsK4, 4);
|
||||
if(synthPeriod) {
|
||||
synthK5 = read8(tmsK5 , 4); // Voiced
|
||||
synthK6 = read8(tmsK6 , 4); // frames
|
||||
synthK7 = read8(tmsK7 , 4); // use
|
||||
synthK8 = read8(tmsK8 , 3); // six
|
||||
synthK9 = read8(tmsK9 , 3); // extra
|
||||
synthK10 = read8(tmsK10, 3); // coeffs
|
||||
}
|
||||
}
|
||||
}
|
||||
iCount = 0;
|
||||
}
|
||||
|
||||
if(synthPeriod) { // Voiced source
|
||||
if(++periodCounter >= synthPeriod) periodCounter = 0;
|
||||
u0 = (periodCounter >= sizeof(chirp)) ? 0 :
|
||||
(pgm_read_byte(&chirp[periodCounter]) *
|
||||
(uint32_t)synthEnergy) >> 8;
|
||||
} else { // Unvoiced source
|
||||
synthRand = (synthRand >> 1) ^ ((synthRand & 1) ? 0xB800 : 0);
|
||||
u0 = (synthRand & 1) ? synthEnergy : -synthEnergy;
|
||||
}
|
||||
u0 -= ((synthK10 * x9) +
|
||||
(synthK9 * x8)) >> 7;
|
||||
x9 = x8 + ((synthK9 * u0 ) >> 7);
|
||||
u0 -= ((synthK8 * x7 ) >> 7);
|
||||
x8 = x7 + ((synthK8 * u0 ) >> 7);
|
||||
u0 -= ((synthK7 * x6 ) >> 7);
|
||||
x7 = x6 + ((synthK7 * u0 ) >> 7);
|
||||
u0 -= ((synthK6 * x5 ) >> 7);
|
||||
x6 = x5 + ((synthK6 * u0 ) >> 7);
|
||||
u0 -= ((synthK5 * x4 ) >> 7);
|
||||
x5 = x4 + ((synthK5 * u0 ) >> 7);
|
||||
u0 -= ((synthK4 * x3 ) >> 7);
|
||||
x4 = x3 + ((synthK4 * u0 ) >> 7);
|
||||
u0 -= ((synthK3 * x2 ) >> 7);
|
||||
x3 = x2 + ((synthK3 * u0 ) >> 7);
|
||||
u0 -= ((synthK2 * (int32_t)x1 ) >> 15);
|
||||
x2 = x1 + ((synthK2 * (int32_t)u0 ) >> 15);
|
||||
u0 -= ((synthK1 * (int32_t)x0 ) >> 15);
|
||||
x1 = x0 + ((synthK1 * (int32_t)u0 ) >> 15);
|
||||
|
||||
if( u0 > 511) u0 = 511; // Output clamp
|
||||
else if(u0 < -512) u0 = -512;
|
||||
|
||||
x0 = u0;
|
||||
nextPwm = (u0 >> 2) + 0x80;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user