/******************** Accelerometer header ********************/
IntervalTimer timer;
volatile bool changed;
volatile int adjustment;
volatile unsigned int index;
volatile unsigned int time_array[MAX_REC_COUNT];
volatile float data_array[AXIS_COUNT][MAX_REC_COUNT];
/******************** Accelerometer cpp ********************/
Accelerometer* Accelerometer::self = NULL; // Self reference to instance //
/*
* Starts the sensor timer.
* @param timestamp the UTC timestamp reference.
*/
void Accelerometer::start() {
if (!active) {
noInterrupts();
adjustment = 0;
changed = false;
callback();
timer.begin(callback, 20000); // Start callbacks //
interrupts();
}
active = true;
}
/*
* Copies accumulated data and returns the number of new data items.
* @return the number of new data items.
*/
int Accelerometer::update(float* data, unsigned int* times) {
int counter;
noInterrupts();
// Copy data //
memcpy((float*)data, (float*)data_array, DATA_BYTES);
memcpy((unsigned int*)times, (unsigned int*)time_array, TIME_BYTES);
counter = index; // Un-interrupted copy //
index = 0; // Reset the index //
interrupts();
return counter;
}
/*
* Adjusts the sensor timing by the given number of milliseconds.
* @param ms the number of milliseconds to adjust the timer.
*/
void Accelerometer::adjust(int ms) {
noInterrupts();
adjustment = ms; // Un-interrupted copy //
interrupts();
}
/*
* The static timer callback function. [∆t: 16 µs]
*/
void Accelerometer::callback() {
// Only read data when storage available //
if (self->index < MAX_REC_COUNT) {
(self->sensor)->getAccelData(self->acc_array); // Using SPI1 to talk to the sensor //
self->data_array[AXIS_X][self->index] = self->acc_array[AXIS_X];
self->data_array[AXIS_Y][self->index] = self->acc_array[AXIS_Y];
self->data_array[AXIS_Z][self->index] = self->acc_array[AXIS_Z];
self->time_array[self->index] = millis();
self->index++;
} else {
//Serial.println("*** Accelerometer Data Overflow! ***");
}
if (self->adjustment) {
// Make timing adjustment //
self->timer.update((20000 + self->adjustment) * 1000); // Period in microseconds //
self->changed = true;
} else if (self->changed) {
// Restore regular timing //
self->timer.update(20000 * 1000); // Period in microseconds //
self->changed = false;
}
}
/******************** Sensor cpp ********************/
/*
* Reads the multi-axis acceleration.
* @param output the array to populate.
*/
void Sensor::getAccelData(float output[3]) {
byte data[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
readRegisters(AXIS_X, 9, data);
// Set 20-bit data //
output[0] = normalise((data[0] << 12) | (data[1] << 4) | (data[2] >> 4), 20) * SCALAR_X;
output[1] = normalise((data[3] << 12) | (data[4] << 4) | (data[5] >> 4), 20) * SCALAR_Y;
output[2] = normalise((data[6] << 12) | (data[7] << 4) | (data[8] >> 4), 20) * SCALAR_Z;
}
/*
* Reads multiple registers into the given array starting at the given address for the given count.
* @param address the register start address.
* @param count the number of registers to read.
* @param data the array to populate.
*/
void Sensor::readRegisters(int address, int count, byte* data) {
byte addr;
spi->beginTransaction(settings);
digitalWriteFast(CS_PIN, LOW);
addr = (address << 1) | READ_BYTE;
spi->transfer(addr);
for (int i = 0; i < count; i++) {
data[i] = spi->transfer(0x00);
address++;
}
digitalWriteFast(CS_PIN, HIGH);
spi->endTransaction();
}