microbit: Added configuration support for accelerometer sample rate and range

MicroBitAccelerometer now contans methods to allow dynamic selection of sample range
(from +/-2g to +/-8g) and sample frequency (up to 800Hz). The default settings and behaviour
remain consistent.
This commit is contained in:
Joe Finney 2015-09-08 23:16:15 +01:00
parent 380b999440
commit 9ccf0a7688
2 changed files with 188 additions and 24 deletions

View File

@ -32,6 +32,10 @@
*/
#define MMA8653_WHOAMI_VAL 0x5A
#define MMA8653_SAMPLE_RANGES 3
#define MMA8653_SAMPLE_RATES 8
struct MMA8653Sample
{
int16_t x;
@ -39,6 +43,21 @@ struct MMA8653Sample
int16_t z;
};
struct MMA8653SampleRateConfig
{
uint32_t sample_period;
uint8_t ctrl_reg1;
};
struct MMA8653SampleRangeConfig
{
uint8_t sample_range;
uint8_t xyz_data_cfg;
};
extern const MMA8653SampleRangeConfig MMA8653SampleRange[];
extern const MMA8653SampleRateConfig MMA8653SampleRate[];
/**
* Class definition for MicroBit Accelerometer.
*
@ -52,8 +71,9 @@ class MicroBitAccelerometer : public MicroBitComponent
* Used to track asynchronous events in the event bus.
*/
//if you are adding status here - don't it's in MicroBitComponent!!!
uint16_t address; // I2C address of this accelerometer.
uint16_t samplePeriod; // The time between samples, in milliseconds.
uint8_t sampleRange; // The sample range of the accelerometer in g.
MMA8653Sample sample; // The last sample read.
DigitalIn int1; // Data ready interrupt.
@ -72,12 +92,47 @@ class MicroBitAccelerometer : public MicroBitComponent
*/
MicroBitAccelerometer(uint16_t id, uint16_t address);
/**
* Configures the accelerometer for G range and sample rate defined
* in this object. The nearest values are chosen to those defined
* that are supported by the hardware. The instance variables are then
* updated to reflect reality.
*/
void configure();
/**
* Reads the acceleration data from the accelerometer, and stores it in our buffer.
* This is called by the tick() member function, if the interrupt is set!
*/
void update();
/**
* Attempts to set the sample rate of the accelerometer to the specified value (in ms).
* n.b. the requested rate may not be possible on the hardware. In this case, the
* nearest lower rate is chosen.
* @param period the requested time between samples, in milliseconds.
*/
void setPeriod(int period);
/**
* Reads the currently configured sample rate of the accelerometer.
* @return The time between samples, in milliseconds.
*/
int getPeriod();
/**
* Attempts to set the sample range of the accelerometer to the specified value (in g).
* n.b. the requested range may not be possible on the hardware. In this case, the
* nearest lower rate is chosen.
* @param range The requested sample range of samples, in g.
*/
void setRange(int range);
/**
* Reads the currently configured sample range of the accelerometer.
* @return The sample range, in g.
*/
int getRange();
/**
* Attempts to determine the 8 bit ID from the accelerometer.

View File

@ -7,6 +7,61 @@
#include "MicroBit.h"
/**
* Configures the accelerometer for G range and sample rate defined
* in this object. The nearest values are chosen to those defined
* that are supported by the hardware. The instance variables are then
* updated to reflect reality.
*/
void MicroBitAccelerometer::configure()
{
const MMA8653SampleRangeConfig *actualSampleRange;
const MMA8653SampleRateConfig *actualSampleRate;
// First find the nearest sample rate to that specified.
actualSampleRate = &MMA8653SampleRate[MMA8653_SAMPLE_RATES-1];
for (int i=MMA8653_SAMPLE_RATES-1; i>=0; i--)
{
if(MMA8653SampleRate[i].sample_period < this->samplePeriod * 1000)
break;
actualSampleRate = &MMA8653SampleRate[i];
}
// Now find the nearest sample range to that specified.
actualSampleRange = &MMA8653SampleRange[MMA8653_SAMPLE_RANGES-1];
for (int i=MMA8653_SAMPLE_RANGES-1; i>=0; i--)
{
if(MMA8653SampleRange[i].sample_range < this->sampleRange)
break;
actualSampleRange = &MMA8653SampleRange[i];
}
// OK, we have the correct data. Update our local state.
this->samplePeriod = actualSampleRate->sample_period / 1000;
this->sampleRange = actualSampleRange->sample_range;
// Now configure the accelerometer accordingly.
// First place the device into standby mode, so it can be configured.
writeCommand(MMA8653_CTRL_REG1, 0x00);
// Enable high precisiosn mode. This consumes a bit more power, but still only 184 uA!
writeCommand(MMA8653_CTRL_REG2, 0x10);
// Enable the INT1 interrupt pin.
writeCommand(MMA8653_CTRL_REG4, 0x01);
// Select the DATA_READY event source to be routed to INT1
writeCommand(MMA8653_CTRL_REG5, 0x01);
// Configure for the selected g range.
writeCommand(MMA8653_XYZ_DATA_CFG, actualSampleRange->xyz_data_cfg);
// Bring the device back online, with 10bit wide samples at the requested frequency.
writeCommand(MMA8653_CTRL_REG1, actualSampleRate->ctrl_reg1 | 0x01);
}
/**
* Issues a standard, 2 byte I2C command write to the accelerometer.
* Blocks the calling thread until complete.
@ -54,21 +109,12 @@ MicroBitAccelerometer::MicroBitAccelerometer(uint16_t id, uint16_t address) : sa
this->id = id;
this->address = address;
// Enable the accelerometer.
// First place the device into standby mode, so it can be configured.
writeCommand(MMA8653_CTRL_REG1, 0x00);
// Update our internal state for 50Hz at +/- 2g (50Hz has a period af 20ms).
this->samplePeriod = 20;
this->sampleRange = 2;
// Enable the INT1 interrupt pin.
writeCommand(MMA8653_CTRL_REG4, 0x01);
// Select the DATA_READY event source to be routed to INT1
writeCommand(MMA8653_CTRL_REG5, 0x01);
// Configure for a +/- 2g range.
writeCommand(MMA8653_XYZ_DATA_CFG, 0x00);
// Bring the device back online, with 10bit wide samples at a 50Hz frequency.
writeCommand(MMA8653_CTRL_REG1, 0x21);
// Configure and enable the accelerometer.
this->configure();
// indicate that we're ready to receive tick callbacks.
uBit.flags |= MICROBIT_FLAG_ACCELEROMETER_RUNNING;
@ -98,6 +144,7 @@ int MicroBitAccelerometer::whoAmI()
void MicroBitAccelerometer::update()
{
int8_t data[6];
static int count=0;
readCommand(MMA8653_OUT_X_MSB, (uint8_t *)data, 6);
@ -106,18 +153,15 @@ void MicroBitAccelerometer::update()
sample.y = data[2];
sample.z = data[4];
// Scale into millig (approx!)
sample.x *= 16;
sample.y *= 16;
sample.z *= 16;
// Normalize the data in the 0..1024 range.
sample.x *= 8;
sample.y *= 8;
sample.z *= 8;
// Invert the x and y axes, so that the reference frame aligns with micro:bit expectations
sample.x = -sample.x;
sample.y = -sample.y;
// We ignore the LSB bits for now, as they're just noise...
// TODO: Revist this when we have working samples to see if additional resolution is needed.
#if CONFIG_ENABLED(USE_ACCEL_LSB)
// Add in LSB values.
sample.x += (data[1] / 64);
@ -125,9 +169,56 @@ void MicroBitAccelerometer::update()
sample.z += (data[5] / 64);
#endif
// Scale into millig (approx!)
sample.x *= this->sampleRange;
sample.y *= this->sampleRange;
sample.z *= this->sampleRange;
//TODO: Issue an event.
};
/**
* Attempts to set the sample rate of the accelerometer to the specified value (in ms).
* n.b. the requested rate may not be possible on the hardware. In this case, the
* nearest lower rate is chosen.
* @param period the requested time between samples, in milliseconds.
*/
void MicroBitAccelerometer::setPeriod(int period)
{
this->samplePeriod = period;
this->configure();
}
/**
* Reads the currently configured sample rate of the accelerometer.
* @return The time between samples, in milliseconds.
*/
int MicroBitAccelerometer::getPeriod()
{
return (int)samplePeriod;
}
/**
* Attempts to set the sample range of the accelerometer to the specified value (in g).
* n.b. the requested range may not be possible on the hardware. In this case, the
* nearest lower rate is chosen.
* @param range The requested sample range of samples, in g.
*/
void MicroBitAccelerometer::setRange(int range)
{
this->sampleRange = range;
this->configure();
}
/**
* Reads the currently configured sample range of the accelerometer.
* @return The sample range, in g.
*/
int MicroBitAccelerometer::getRange()
{
return (int)sampleRange;
}
/**
* Reads the X axis value of the latest update from the accelerometer.
* Currently limited to +/- 2g
@ -182,6 +273,7 @@ void MicroBitAccelerometer::idleTick()
{
// Poll interrupt line from accelerometer.
// n.b. Default is Active LO. Interrupt is cleared in data read.
//
if(!int1)
update();
}
@ -193,3 +285,20 @@ int MicroBitAccelerometer::isIdleCallbackNeeded()
{
return !int1;
}
const MMA8653SampleRangeConfig MMA8653SampleRange[MMA8653_SAMPLE_RANGES] = {
{2, 0},
{4, 1},
{8, 2}
};
const MMA8653SampleRateConfig MMA8653SampleRate[MMA8653_SAMPLE_RATES] = {
{1250, 0x00},
{2500, 0x08},
{5000, 0x10},
{10000, 0x18},
{20000, 0x20},
{80000, 0x28},
{160000, 0x30},
{640000, 0x38}
};