Could someone double-check this driver?
/// <summary>
/// Driver for the Bosch SMB380 Accelerometer
/// </summary>
public sealed class SMB380
{
#region Fields
private const float G2Multiplier = 2.0f;
private const float G4Multiplier = 4.0f;
private const float G8Multiplier = 8.0f;
private SPI spi;
private byte[] read = new byte[2];
private byte[] write = new byte[2];
private float lowGThreshold = 0.3137255f;
private float highGThreshold = 2.5098039f;
private float anyMotionThreshold;
private InterruptPort interruptPort;
private float gMultiplier = G4Multiplier;
private short bandwidthInHz = 1500;
private bool areInterruptsEnabled = true;
#endregion Fields
#region Events
/// <summary>
/// Raised asynchronously when the Low G Threshold is reached.
/// </summary>
public event ThresholdReachedEventHandler ThresholdReached;
#endregion Events
#region Constructor
static SMB380()
{
Instance = new SMB380();
}
private SMB380()
{
spi = new SPI(new SPI.Configuration((Cpu.Pin)FEZ_Pin.Digital.UEXT10, false, 0, 0, true, true, 200, SPI.SPI_module.SPI2));
//Enabled latched interrupts
WriteRegister(0x15, (byte)(ReadRegister(0x15) | 0x10));
interruptPort = new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.UEXT4, false, Port.ResistorMode.PullDown, Port.InterruptMode.InterruptEdgeHigh);
interruptPort.OnInterrupt += OnInterrupt;
interruptPort.EnableInterrupt();
}
#endregion Constructor
#region Event Handlers
private void OnInterrupt(uint data1, uint data2, DateTime time)
{
//LG
byte register = ReadRegister(0x09);
if ((register & (byte)0x08) > 0)
{
WriteRegister(0x09, (byte)(register & 0xF7));
RaiseThresholdReached(time, ThresholdType.LowG);
}
//HG
if ((register & (byte)0x04) > 0)
{
WriteRegister(0x09, (byte)(register & 0xFB));
RaiseThresholdReached(time, ThresholdType.HighG);
}
//Clear the interrupt on the smb380
WriteRegister(0x0A, (byte)(ReadRegister(0x0A) | 0x40));
}
private void RaiseThresholdReached(DateTime time, ThresholdType thresholdType)
{
Thread thread = new Thread(() =>
{
ThresholdReachedEventHandler localHandler = ThresholdReached;
if (localHandler != null)
{
localHandler(this, new ThresholdReachedEventArgs(thresholdType, time));
}
Dispatcher.Run();
});
thread.Start();
}
#endregion Event Handlers
#region Properties
/// <summary>
/// Gets the current instance of the SMB380
/// </summary>
public static SMB380 Instance { get; private set; }
/// <summary>
/// Gets the Acceleration in g's in the X-direction
/// </summary>
public float AccelerationX
{
get
{
short lsb = (sbyte)ReadRegister(0x02); //LSB 6 7
short msb = (sbyte)ReadRegister(0x03); //MSB 0 7
return ExtractAcceleration(lsb, msb);
}
}
/// <summary>
/// Gets the Acceleration in g's in the Y-direction
/// </summary>
public float AccelerationY
{
get
{
short lsb = (sbyte)ReadRegister(0x04); //LSB 6 7
short msb = (sbyte)ReadRegister(0x05); //MSB 0 7
return ExtractAcceleration(lsb, msb);
}
}
/// <summary>
/// Gets the Acceleration in g's in the Z-direction
/// </summary>
public float AccelerationZ
{
get
{
short lsb = (sbyte)ReadRegister(0x06); //LSB 6 7
short msb = (sbyte)ReadRegister(0x07); //MSB 0 7
return ExtractAcceleration(lsb, msb);
}
}
/// <summary>
/// Gets or sets the range of the accelerometer.
/// </summary>
public GRange Range
{
get
{
return (GRange)((ReadRegister(0x14) & 0x18) >> 3);
}
set
{
byte val = ReadRegister(0x14);//xxx Range(2) Bandwidth(3)
val &= (byte)(0xE7 | ((byte)value << 3));
WriteRegister(0x14, val);
gMultiplier = value == GRange.G8 ? G8Multiplier : value == GRange.G4 ? G4Multiplier : G2Multiplier;
}
}
/// <summary>
/// Gets or sets the filter bandwidth.
/// </summary>
public FilterBandwidth Bandwidth
{
get
{
return (FilterBandwidth)(ReadRegister(0x14) & 0x07);
}
set
{
if (value != Bandwidth)
{
byte val = ReadRegister(0x14);//xxx Range(2) Bandwidth(3)
val &= (byte)(0xF8 | (byte)value);
WriteRegister(0x14, val);
switch (value)
{
case FilterBandwidth.Hz25:
bandwidthInHz = 25;
break;
case FilterBandwidth.Hz50:
bandwidthInHz = 50;
break;
case FilterBandwidth.Hz100:
bandwidthInHz = 100;
break;
case FilterBandwidth.Hz190:
bandwidthInHz = 190;
break;
case FilterBandwidth.Hz375:
bandwidthInHz = 375;
break;
case FilterBandwidth.Hz750:
bandwidthInHz = 750;
break;
default://case FilterBandwidth.Hz1500:
bandwidthInHz = 1500;
break;
}
}
}
}
/// <summary>
/// Gets or sets a value indicating whether or not an event should be raised when all 3 axes drop below the LowGThreshold.
/// </summary>
public bool IsLowGThresholdEnabled
{
get
{
return (ReadRegister(0x0B) & (byte)0x01) > 0;
}
set
{
WriteRegister(0x0B, (byte)((ReadRegister(0x0B) & 0xFE) | (byte)(value ? 0x01 : 0x00)));
RefreshAreInterruptsEnabled();
}
}
/// <summary>
/// Gets or sets a value indicating whether or not an event should be raised when any of axes exceeds the HighGThreshold.
/// </summary>
public bool IsHighGThresholdEnabled
{
get
{
return (ReadRegister(0x0B) & (byte)0x10) > 0;
}
set
{
WriteRegister(0x0B, (byte)((ReadRegister(0x0B) & 0xFD) | (byte)(value ? 0x10 : 0x00)));
RefreshAreInterruptsEnabled();
}
}
/// <summary>
/// Gets or sets the Low-G Threshold in g's.
/// </summary>
public float LowGThreshold
{
get
{
return lowGThreshold;
}
set
{
ValidateThresholdValue(value);
lowGThreshold = value;
WriteRegister(0x0C, ConvertThresholdFromGs(value));
}
}
/// <summary>
/// Gets or sets the duration, in ms, of any axis being below the Low-G threshold before an event is raised (if IsLowGThresholdEnabled.)
/// </summary>
public byte LowGDuration
{
get
{
return ReadRegister(0x0D);
}
set
{
WriteRegister(0x0D, value);
}
}
/// <summary>
/// Gets or sets the duration, in ms, of any axis being below the Low-G threshold before an event is raised (if IsHighGThresholdEnabled.)
/// </summary>
public byte HighGDuration
{
get
{
return ReadRegister(0x0F);
}
set
{
WriteRegister(0x0F, value);
}
}
/// <summary>
/// Gets or sets the High-G Threshold in g's
/// </summary>
public float HighGThreshold
{
get
{
return highGThreshold;
}
set
{
ValidateThresholdValue(value);
highGThreshold = value;
WriteRegister(0x0C, ConvertThresholdFromGs(value));
}
}
/// <summary>
/// Gets or sets a value indicating whether or not an event should be raised for any motion exceeding the AnyMotionThreshold.
/// </summary>
public bool IsAnyMotionThresholdEnabled
{
get
{
return (ReadRegister(0x0B) & (byte)0x40) > 0;
}
set
{
if (value != IsAnyMotionThresholdEnabled)
{
if (value)
{
WriteRegister(0x15, (byte)(ReadRegister(0x15) | 0x40));//Enable Advanced Interrupts
WriteRegister(0x0B, (byte)(ReadRegister(0x0B) | 0x40));//Enable Any Motion Interrupt
}
else
{
WriteRegister(0x15, (byte)(ReadRegister(0x15) | 0xBF));//Disable Advanced Interrupts
WriteRegister(0x0B, (byte)(ReadRegister(0x0B) | 0xBF));//Disable Any Motion Interrupt
}
RefreshAreInterruptsEnabled();
}
}
}
/// <summary>
/// Gets or sets the Any Motion Threshold in g's.
/// </summary>
public float AnyMotionThreshold
{
get
{
return anyMotionThreshold;
}
set
{
ValidateThresholdValue(value);
anyMotionThreshold = value;
WriteRegister(0x10, ConvertThresholdFromGs(value));
}
}
/// <summary>
/// Gets or sets the Any Motion Duration; this is in number of (consecutive) samples and the actual time will depend on bandwidth. A time representation of the duration may be
/// obtained through the AnyMotionDurationTime property.
/// </summary>
public AnyMotionDuration AnyMotionDuration
{
get
{
return (AnyMotionDuration)(ReadRegister(0x11) >> 6);
}
set
{
WriteRegister(0x11, (byte)((ReadRegister(0x11) & 0x3F) | ((byte)value << 6)));
}
}
/// <summary>
///
/// </summary>
public TimeSpan AnyMotionDurationTime
{
get
{
return TimeSpan.FromTicks((long)((3.0f / (2.0f * (float)bandwidthInHz)) * TimeSpan.TicksPerSecond));
}
}
#endregion Properties
#region Methods
/// <summary>
/// Perform a soft reset of the smb380 - this is effectively "restore defaults" for all settings.
/// </summary>
public void SoftReset()
{
WriteRegister(0x0A, (byte)(ReadRegister(0x0A) | 0x02));
}
#endregion Methods
#region Private Helpers
private void RefreshAreInterruptsEnabled()
{
bool newAreInterruptsEnabled = IsHighGThresholdEnabled || IsLowGThresholdEnabled || IsAnyMotionThresholdEnabled;
if (areInterruptsEnabled != newAreInterruptsEnabled)
{
if (areInterruptsEnabled = newAreInterruptsEnabled)
{
WriteRegister(0x15, (byte)(ReadRegister(0x15) | 0x10));//Enable latched interrupts
interruptPort.EnableInterrupt();
}
else
{
interruptPort.DisableInterrupt();
WriteRegister(0x15, (byte)(ReadRegister(0x15) & 0xEF));//Disable latched interrupts
WriteRegister(0x0A, (byte)(ReadRegister(0x0A) & 0xBF));//Reset any current interrupt
}
}
}
private byte ReadRegister(byte address)
{
write[0] = (byte)(0x80 | address);
write[1] = 0xFF;
spi.WriteRead(write, read);
return read[1];
}
private void WriteRegister(byte address, byte value)
{
write[0] = address;
write[1] = value;
spi.WriteRead(write, read);
}
private float ExtractAcceleration(short lsb, short msb)
{
return (float)(((((short)((msb << 2) | (lsb >> 6))) << 4) >> 4) / 512.0f) * gMultiplier;
}
private void ValidateThresholdValue(float value)
{
GRange range = Range;
if (value < 0)
{
throw new ArgumentOutOfRangeException("value", "Threshold values must be positive; the absolute value of acceleration is used for threshold comparisons");
}
else if (value > 8.0f)
{
throw new ArgumentOutOfRangeException("value", "Threshold must be less than 8.0g's and greater than -8.0g's");
}
else if (range != GRange.G8 && value > 4.0f)
{
throw new ArgumentOutOfRangeException("value", "Threshold must be less than 4.0g's and greater than -4.0g's when Range is not G8");
}
else if (range == GRange.G2 && value > 2.0f)
{
throw new ArgumentOutOfRangeException("value", "Threshold must be less than 2.0g's and greater than -2.0g's when Range is G2");
}
}
private byte ConvertThresholdFromGs(float value)
{
return (byte)((255.0f * value) / gMultiplier);
}
#endregion
}
I’ve set my range to +/- 2g and I still get a good 1g on my z-axis and -.5 on my x. The y never strays more than .002g’s from 0 on a 25Hz bandwidth setting. I also don’t seem to get anything after resetting memory until I shake the thing really hard…which seems weird…though my years with Nintendo have taught me that occasionally you have to weird things with technology to make them work right