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:
parent
380b999440
commit
9ccf0a7688
2 changed files with 188 additions and 24 deletions
|
@ -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,13 +92,48 @@ 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.
|
||||
* @return the 8 bit ID returned by the accelerometer
|
||||
|
|
|
@ -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);
|
||||
|
||||
// Enable the INT1 interrupt pin.
|
||||
writeCommand(MMA8653_CTRL_REG4, 0x01);
|
||||
// Update our internal state for 50Hz at +/- 2g (50Hz has a period af 20ms).
|
||||
this->samplePeriod = 20;
|
||||
this->sampleRange = 2;
|
||||
|
||||
// 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);
|
||||
|
||||
|
@ -105,19 +152,16 @@ void MicroBitAccelerometer::update()
|
|||
sample.x = data[0];
|
||||
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}
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue