Accelerometer Z axis not working properly

Hi,

I’m using a Raptor with accelerometer module (1.1).
X and Y axes are wroking fine, but Z axis isn’t.

When placing the acc on a flat surface (Z+ axis is pointing up) and doing calibration for the orientation (0,0,1), I’m getting 1 from Z. this is ok.
But when I flip the acc, so that the Z+ axis is now pointing down, i get 1 again (soppose to be -1).
No matter at what position I put the acc, it changes only between 1 - 1.25.

Is there a known issue with this module?
Maybe the combination with the Raptor?

Details:
Accelerometer module - SACCL-GM-320
Raptor firmware version - 4.2.11.2 (also on the computer)

@ yakov.morgen - We were able to replicate the issue using hardware I2C. However, if you add the driver code to your solution, you can switch it to SoftwareI2C and it will work without a hitch.

Where can I find the driver code?
What exactly I need to do in order to switch to software i2c?

Thanks for the quick replay!

@ yakov.morgen - All drivers can be found here: http://gadgeteer.codeplex.com/SourceControl/latest

and you should be able to change the declaration and construction to SoftwareI2C in the premium libraries. Everything else should be the same :slight_smile:

What are the premium libraries? Where they are located?

you don’t need them - they are already present on your device (assuming you have a GHI Premium device). You just need to use, instead of the netmf (hardware) I2C libraries, the GHI.Premium.SoftwareI2C lib.

Can you please explain more specifically how to do it?

That’s strange…I get a 255 when on a flat surface with the IC facing up and a -255 when I flip it over so it seems to be working ok to me. Same 1.1 version of the accelerometer.

Using this simple code:


int x;
int y;
int z;

accel_G248.GetXYZ(out x, out y, out z);
Debug.Print("X=" + x + " " + "Y=" + y + " " + "Z=" + z);

Brett? James? help?

What are you asking by “more specifically how to do it”?

I think, convert HardwareI2C to SoftwareI2C

I downloaded the software driver from NETMF,
Added the project to my solution and changed the reference for the Accelerometer class,
but it doesn’t work.

Is that what you mean - “convert HardwareI2C to SoftwareI2C” ?

When I try to build the project I get the following errors (in the output window):

Link failure: some assembly references cannot be resolved!!


Assembly: Hinge.Recorder (1.0.0.0) needs assembly 'GTM.Seeed.Accelerometer' (1.4.0.0)

Assembly: Hinge.Recorder (1.0.0.0) needs assembly 'mscorlib' (4.1.2821.0)

Assembly: GTM.Seeed.Accelerometer (1.4.0.0) needs assembly 'Gadgeteer' (2.41.0.0)

Assembly: GTM.Seeed.Accelerometer (1.4.0.0) needs assembly 'mscorlib' (4.1.2821.0)

Assembly: GTM.Seeed.Accelerometer (1.4.0.0) needs assembly 'Microsoft.SPOT.Native' (4.1.2821.0)

Error: a3000000

Waiting for debug commands...

The program '[3] Micro Framework application: Managed' has exited with code 0 (0x0).

Thanks andre.m, that worked.

I managed to compile and run the program - but I’m facing the same problem with the Accelerometer.
X and Y axes works properly, but Z axis isn’t.
(Only positive and wrong values)

We bought about 10 modules of the Accelerometer last year - and now we can’t do anything with them.

What do you suggest?
We need them all fixed.

Yes.
I switched to SoftwareI2C as he said.
Changed the solution to 4.2 as you said.
Same problem.

You said you had 10 of the modules. Are you always testing with the same one? If so, can you try it with another one?

I tried it with 3 of them.
All with the same problem.

This is the start of my program:

using System;
using System.Collections;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Presentation.Shapes;
using Microsoft.SPOT.Touch;

using Gadgeteer.Networking;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using Gadgeteer.Modules.GHIElectronics;
using Gadgeteer.Modules.Seeed;

namespace Hinge.Recorder
{
    public partial class Program
    {
        // Sensors data arrays
        public ArrayList AccData = new ArrayList();
        public ArrayList Acc2Data = new ArrayList();
        public ArrayList CompassData = new ArrayList();
        public ArrayList Compass2Data = new ArrayList();

        // Recorders
        private System.IO.StreamWriter swAcc;
        private System.IO.StreamWriter swAcc2;
        private System.IO.StreamWriter swCompass;
        private System.IO.StreamWriter swCompass2;

        public int numberOfEntriesAcc, numberOfEntriesCompass;
        static long startTime;
        public bool recorderRunning = false;

        public static GT.StorageDevice _storage;

        // This method is run when the mainboard is powered up or reset.   
        void ProgramStarted()
        {
            /*******************************************************************************************
            Modules added in the Program.gadgeteer designer view are used by typing 
            their name followed by a period, e.g.  button.  or  camera.
            
            Many modules generate useful events. Type +=<tab><tab> to add a handler to an event, e.g.:
                button.ButtonPressed +=<tab><tab>
            
            If you want to do something periodically, use a GT.Timer and handle its Tick event, e.g.:
                GT.Timer timer = new GT.Timer(1000); // every second (1000ms)
                timer.Tick +=<tab><tab>
                timer.Start();
            *******************************************************************************************/


            // Use Debug.Print to show messages in Visual Studio's "Output" window during debugging.
            Debug.Print("Program Started");

            InitializeStorage();
            InitializeSensors();
        }

        void InitializeSensors()
        {
            //Sensors events
            accelerometer.MeasurementComplete += new Accelerometer.MeasurementCompleteEventHandler(accelerometer_MeasurementComplete);
            accelerometer2.MeasurementComplete += new Accelerometer.MeasurementCompleteEventHandler(accelerometer2_MeasurementComplete);
            compass.MeasurementComplete += new Compass.MeasurementCompleteEventHandler(compass_MeasurementComplete);          
            compass2.MeasurementComplete += new Compass.MeasurementCompleteEventHandler(compass2_MeasurementComplete);

            //Sensors Settings
            accelerometer.MeasurementRange = Accelerometer.Range.EightG;
            accelerometer.ContinuousMeasurementInterval = new TimeSpan(0, 0, 0, 0, 20);
            accelerometer2.MeasurementRange = Accelerometer.Range.EightG;
            accelerometer2.ContinuousMeasurementInterval = new TimeSpan(0, 0, 0, 0, 20);
            compass.ContinuousMeasurementInterval = new TimeSpan(0, 0, 0, 0, 20);
            compass2.ContinuousMeasurementInterval = new TimeSpan(0, 0, 0, 0, 20);

            button.ButtonPressed += button_ButtonPressed;
        }

And this is the cs file from the accelerometer software which referenced from my project:

using System;
using Microsoft.SPOT;

using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using GTI = Gadgeteer.Interfaces;

namespace Gadgeteer.Modules.Seeed
{
    /// <summary>
    /// An Accelerometer Gadgeteer module, based on the Freescale Semiconductor MMA7455L Three Axis Accelerometer IC.
    /// </summary>
    public class Accelerometer : GTM.Module
    {
        // Note: A constructor summary is auto-generated by the doc builder.
        /// <summary></summary>
        /// <param name="socketNumber">The socket that this module is plugged in to.</param>
        public Accelerometer(int socketNumber)
        {
            // This finds the Socket instance from the user-specified socket number.  
            // This will generate user-friendly error messages if the socket is invalid.
            // If there is more than one socket on this module, then instead of "null" for the last parameter, 
            // put text that identifies the socket to the user (e.g. "S" if there is a socket type S)
            Socket socket = Socket.GetSocket(socketNumber, true, this, null);

            offsets = new CalibrationOffsets(0, 0, 0);

            // This creates an GTI.InterruptInput interface. The interfaces under the GTI namespace provide easy ways to build common modules.
            // This also generates user-friendly error messages automatically, e.g. if the user chooses a socket incompatible with an interrupt input.
            this.int1 = new GTI.InterruptInput(socket, GT.Socket.Pin.Three, GTI.GlitchFilterMode.Off, GTI.ResistorMode.PullDown, GTI.InterruptMode.RisingEdge, this);

            i2c = new GTI.I2CBus(socket, 0x1D, 50, this);
            
            // This registers a handler for the interrupt event of the interrupt input (which is below)
            this.int1.Interrupt += new GTI.InterruptInput.InterruptEventHandler(int1_Interrupt);

            continuousTimer = new Gadgeteer.Timer(new TimeSpan(0, 0, 0, 0, 200));
            continuousTimer.Tick += new Timer.TickEventHandler(continuousTimer_Tick);

            OperatingMode = Mode.Measurement;
            MeasurementRange = Range.TwoG;            
        }

        private GTI.InterruptInput int1;
        private GTI.I2CBus i2c;

        private GT.Timer continuousTimer;
        private bool continuousMeasurement = false;

        private Range range = Range.TwoG;

        private bool autoResetThresholdDetection = false;

        // Used to store calibration settings in non-volatile memory
        private static ExtendedWeakReference calibrationEWR = null;

        [Serializable]
        private class CalibrationOffsets
        {
            public int X = 0;
            public int Y = 0;
            public int Z = 0;

            public CalibrationOffsets(int x, int y, int z)
            {
                X = x;
                Y = y;
                Z = z;
            }
        }

        private CalibrationOffsets offsets;

        private enum Mode
        {
            Standby = 0,
            Measurement = 1,
            LevelDetection = 2,
            PulseDetection = 3
        }

        private Mode OperatingMode
        {
            get
            {
                byte b = ReadByte(Register.MCTL);
                return (Mode)(b & 0x03); // Read bits 0 and 1
            }
            set
            {
                // Always set bits: Bit7 = 0, Bit6 (DRPD) = 1, Bit5 (SPI3W) = 0, Bit4 (STON) = 0
                Write(Register.MCTL, (byte)(0x40 | (((byte)range) << 2) | (byte)value));

            }
        }

        /// <summary>
        /// Measurement range.
        /// </summary>
        public enum Range
        {
            /// <summary>
            /// +/- 8G measurement range
            /// </summary>
            EightG = 0,
            /// <summary>
            /// +/- 2G measurement range
            /// </summary>
            TwoG = 1,
            /// <summary>
            /// +/- 4G measurement range
            /// </summary>
            FourG = 2
        }

        /// <summary>
        /// Sets or gets the measurement range.
        /// </summary>
        public Range MeasurementRange
        {
            get
            {
                byte b = ReadByte(Register.MCTL);
                range = (Range)((b & 0x0C) >> 2); // Read bits 2 and 3
                return range; 
            }
            set
            {
                // Always set bits: Bit7 = 0, Bit6 (DRPD) = 1, Bit5 (SPI3W) = 0, Bit4 (STON) = 0
                this.range = value;
                Write(Register.MCTL, (byte)(0x40 | (((byte)range) << 2) | (byte)OperatingMode));
            }
        }

        /// <summary>
        /// A set of acceleration readings.
        /// </summary>
        public class Acceleration
        {
            /// <summary>
            /// Acceleration in the X axis, in g.
            /// </summary>
            public double X { get; private set; }
            /// <summary>
            /// Acceleration in the Y axis, in g.
            /// </summary>
            public double Y { get; private set; }
            /// <summary>
            /// Acceleration in the Z axis, in g.
            /// </summary>
            public double Z { get; private set; }

            public Acceleration(double x, double y, double z)
            {
                this.X = x;
                this.Y = y;
                this.Z = z;
            }

            /// <summary>
            /// Provides a string representation of the <see cref="Acceleration"/> instance.
            /// </summary>
            /// <returns>A string describing the values contained in the object.</returns>
            public override string ToString()
            {
                return "X: " + X.ToString("f2") + " Y: " + Y.ToString("f2") + " Z: " + Z.ToString("f2");
            }
        }

        /// <summary>
        /// Gets or sets the interval at which continuous measurements are taken.
        /// </summary>
        /// <remarks>
        /// The default value for this property is 100 milliseconds.
        /// </remarks>
        public TimeSpan ContinuousMeasurementInterval
        {
            get
            {
                return continuousTimer.Interval;
            }
            set
            {
                continuousTimer.Stop();
                continuousTimer.Interval = value;
                if (continuousMeasurement) continuousTimer.Start();
            }
        }

        /// <summary>
        /// Obtains a single reading from the <see cref="Accelerometer"/> and raises the <see cref="MeasurementComplete"/> event when complete.
        /// </summary>
        /// <returns>This method returns the current acceleration, in g's (gravity units).</returns>
        public Acceleration RequestMeasurement()
        {
            // We use the 8-bit resolution mode (register XOUT8), because this can be used in 8G, 2G and 4G.
            // For 10-bit a different register (XOUTL) is needed and it is just 8G.
            // Ref: MMA7455L.pdf, Measurement Mode p.9
            // 
            // Calibration procedure is described in Freescale application note AN3745 (Ref.: MMA7455L.pdf, Offset Drift p.24)
            
            Read(Register.XOUT8, _readBuffer24);

            // Decode Two's Complement values.
            int x = ((((_readBuffer24[0] >> 7) == 1) ? -128 : 0) + (_readBuffer24[0] & 0x7F)) + offsets.X; 
            int y = ((((_readBuffer24[1] >> 7) == 1) ? -128 : 0) + (_readBuffer24[1] & 0x7F)) + offsets.Y; 
            int z = ((((_readBuffer24[2] >> 7) == 1) ? -128 : 0) + (_readBuffer24[2] & 0x7F)) + offsets.Z; 

            Acceleration acceleration = new Acceleration(ConvertDataToG(x), ConvertDataToG(y), ConvertDataToG(z));

            OnMeasurementCompleteEvent(this, acceleration);
            return acceleration;
        }


        private double ConvertDataToG(int data)
        {
            switch (this.range)
            {
                case Range.TwoG: return ((double)data / 128) * 2;
                case Range.FourG: return ((double)data / 128) * 4;
                case Range.EightG: return ((double)data / 128) * 8;
                default: throw new ArgumentOutOfRangeException();
            }
        }

        /// <summary>
        /// Calibrates the accelerometer.
        /// </summary>
        /// <param name="referenceAcceleration">An acceleration representing the resting orientation of the accelerometer.</param>
        public void Calibrate(Acceleration referenceAcceleration)
        {
            OperatingMode = Mode.Measurement;

            Range b = MeasurementRange;

            Read(Register.XOUT8, _readBuffer24);

            // Decode Two's Complement values.
            int x = ((((_readBuffer24[0] >> 7) == 1) ? -128 : 0) + (_readBuffer24[0] & 0x7F));
            int y = ((((_readBuffer24[1] >> 7) == 1) ? -128 : 0) + (_readBuffer24[1] & 0x7F));
            int z = ((((_readBuffer24[2] >> 7) == 1) ? -128 : 0) + (_readBuffer24[2] & 0x7F));

            double gravityValue = 0;

            switch (MeasurementRange)
            {
                case Range.TwoG : 
                    gravityValue = 64;
                    break;
                case Range.FourG:
                    gravityValue = 32;
                    break;
                case Range.EightG:
                    gravityValue = 16;
                    break;
            }

            offsets.X = -x + (int)(gravityValue * referenceAcceleration.X);
            offsets.Y = -y + (int)(gravityValue * referenceAcceleration.Y);
            offsets.Z = -z + (int)(gravityValue * referenceAcceleration.Z);
        }
      
        /// <summary>
        /// Calibrates the accelerometer. Make sure that the accelerometer is not moving and is resting on a flat surface when calling this method. Use the overload method to specify an
        /// arbitrary orientation to calibrate.
        /// </summary>
        public void Calibrate()
        {
            Calibrate(new Acceleration(0, 0, 1));
        }

        /// <summary>
        /// Saves the calibration values to non-volatile memory.
        /// </summary>
        public void SaveCalibration()
        {
            if (calibrationEWR == null)
            {
                calibrationEWR = ExtendedWeakReference.RecoverOrCreate(typeof(CalibrationOffsets), 0, ExtendedWeakReference.c_SurviveBoot | ExtendedWeakReference.c_SurvivePowerdown);
                calibrationEWR.Priority = (int)ExtendedWeakReference.PriorityLevel.NiceToHave;
            }

            calibrationEWR.Target = offsets;
        }

        /// <summary>
        /// Loads previously saved calibration settings.
        /// </summary>
        /// <returns>True if previously saved settinsg were found. False otherwise.</returns>
        public bool LoadCalibration()
        {
            if (calibrationEWR == null)
            {
                calibrationEWR = ExtendedWeakReference.RecoverOrCreate(typeof(CalibrationOffsets), 0, ExtendedWeakReference.c_SurviveBoot | ExtendedWeakReference.c_SurvivePowerdown);
                calibrationEWR.Priority = (int)ExtendedWeakReference.PriorityLevel.NiceToHave;
            }

            CalibrationOffsets savedOffsets = (CalibrationOffsets)calibrationEWR.Target;

            if (savedOffsets != null)
            {
                offsets = savedOffsets;
                return true;
            }
            else
            {
                offsets = new CalibrationOffsets(0, 0, 0);
            }

            return false;
        }

        /// <summary>
        /// Enables automatic detection and notification when an acceleration threshold is exceeded. This results in the <see cref="ThresholdExceeded"/> event being raised. Continous measurement is disabled when threshold detection mode is enabled.
        /// </summary>
        /// <param name="threshold">Acceleration threshold, between -8.0 and 8.0 G.</param>
        /// <param name="enableX">Enable threshold detection in the X axis.</param>
        /// <param name="enableY">Enable threshold detection in the Y axis.</param>
        /// <param name="enableZ">Enable threshold detection in the Z axis.</param>
        /// <param name="absolute">Absoulte threshold detection. If set to true the sign of the threshold is ignored, and the absolute value of the acceleration is compared with the absolute value of the threshold. If set to false, the sign of the threshold will be taken into account, the event will only be raised if the acceleration falls below a negative threshold or above a positive threshold.</param>
        /// <param name="detectFreefall">Freefall detection. If set to true, the <see cref="ThresholdExceeded"/> event will be raised when the acceleration in all the enabled axes is less than the absolute threshold. In order to detect freefall correctly, set the threshold to a small value and enable detection on all axes.</param>
        /// <param name="autoReset">Automatically reset the thershold detection. If set to false, the <see cref="ThresholdExceeded"/> will be raised only once, until the <see cref="ResetThresholdDetection"/> method is called manually. If set to true, the <see cref="ResetThresholdDetection"/> will be called automatically, and the event will be continously raised as long as the thershold conditions are exceeded.</param>
        public void EnableThresholdDetection(double threshold, bool enableX, bool enableY, bool enableZ, bool absolute, bool detectFreefall, bool autoReset)
        {
            StopContinuousMeasurements();
            OperatingMode = Mode.LevelDetection;
            MeasurementRange = Range.EightG;

            autoResetThresholdDetection = autoReset;
            
            byte b = 0x00;
            b |= (byte) ((enableX ? 0 : 1)<< 3);
            b |= (byte) ((enableY ? 0 : 1)<< 4);
            b |= (byte) ((enableZ ? 0 : 1)<< 5);
            b |= (byte)((absolute ? 0 : 1) << 6);
            Write(Register.CTL1, b);

            b = 0x00;
            b |= (byte)((detectFreefall ? 1 : 0));
            Write(Register.CTL2, b);

            if (absolute)
            {
                int thresholdValue = System.Math.Abs((int) ((threshold / 8.0) * 128.0));
                Write(Register.LDTH, (byte)(thresholdValue & 0x7F));                             
            }
            else
            {

                byte thresholdValue = (byte)((threshold / 8.0) * 128.0);
                Write(Register.LDTH, (byte)(thresholdValue));
            }

            // Clear the interrupts
            ResetThresholdDetection();
        }

        /// <summary>
        /// Reset the threshold detection process, configured by the <see cref="EnableThresholdDetection"/> method.
        /// </summary>
        public void ResetThresholdDetection()
        {
            // Clear the interrupts
            Write(Register.INTRST, 0x03);
            Write(Register.INTRST, 0x00);
        }


        void int1_Interrupt(GTI.InterruptInput sender, bool value)
        {
            if (OperatingMode == Mode.LevelDetection)
            {
                OnThresholdExceededEvent(this);

                if (autoResetThresholdDetection)
                {
                    ResetThresholdDetection();
                }
            }
        }

        /// <summary>
        /// Starts continuous measurements.
        /// </summary>
        /// <remarks>
        /// When this method is called, <see cref="Accelerometer"/> begins taking continuous measurements.
        /// At each <see cref="ContinuousMeasurementInterval"/>, it calls the <see cref="RequestMeasurement"/> method,
        /// which raises the <see cref="MeasurementComplete"/> event.
        /// </remarks>
        public void StartContinuousMeasurements()
        {
            this.OperatingMode = Mode.Measurement;
            continuousMeasurement = true;
            continuousTimer.Start();
        }

        /// <summary>
        /// Stops continuous measurements.
        /// </summary>
        public void StopContinuousMeasurements()
        {
            continuousMeasurement = false;
            continuousTimer.Stop();
        }

        /// <summary>
        /// Represents the delegate used for the <see cref="MeasurementComplete"/> event.
        /// </summary>
        /// <param name="sender">The object that raised the event.</param>
        /// <param name="acceleration">The <see cref="Acceleration"/> object that contains the results of the reading.</param>
        public delegate void MeasurementCompleteEventHandler(Accelerometer sender, Acceleration acceleration);

        /// <summary>
        /// Event raised when a measurement reading is completed.
        /// </summary>
        public event MeasurementCompleteEventHandler MeasurementComplete;

        private MeasurementCompleteEventHandler _OnMeasurementComplete;

        /// <summary>
        /// Raises the <see cref="MeasurementComplete"/> event.
        /// </summary>
        /// <param name="sender">The object that raised the event.</param>
        /// <param name="acceleration">The <see cref="Acceleration"/> object that contains the results of the reading.</param>
        protected virtual void OnMeasurementCompleteEvent(Accelerometer sender, Acceleration acceleration)
        {
            if (_OnMeasurementComplete == null) _OnMeasurementComplete = new MeasurementCompleteEventHandler(OnMeasurementCompleteEvent);
            if (Program.CheckAndInvoke(MeasurementComplete, _OnMeasurementComplete, sender, acceleration))
            {
                MeasurementComplete(sender, acceleration);
            }
        }

        /// <summary>
        /// Represents the delegate used for the <see cref="ThresholdExceeded"/> event.
        /// </summary>
        /// <param name="sender">The object that raised the event.</param>
        public delegate void ThresholdExceededEventHandler(Accelerometer sender);

        /// <summary>
        /// Event raised when an acceleration threshold is exceeded.
        /// </summary>
        public event ThresholdExceededEventHandler ThresholdExceeded;

        private ThresholdExceededEventHandler _OnThresholdExceeded;

        /// <summary>
        /// Raises the <see cref="MeasurementComplete"/> event.
        /// </summary>
        /// <param name="sender">The object that raised the event.</param>        
        protected virtual void OnThresholdExceededEvent(Accelerometer sender)
        {
            if (_OnThresholdExceeded == null) _OnThresholdExceeded = new ThresholdExceededEventHandler(OnThresholdExceededEvent);
            if (Program.CheckAndInvoke(ThresholdExceeded, _OnThresholdExceeded, sender))
            {
                ThresholdExceeded(sender);
            }
        }

        void continuousTimer_Tick(Timer timer)
        {
            if (!continuousMeasurement)
            {
                timer.Stop();
                return;
            }
            RequestMeasurement();
        }


        private enum Register : byte
        {
            // From MMA7455L Datasheet, pg. 21.              
            // Bit 7    Bit 6    Bit 5    Bit 4    Bit 3    Bit 2    Bit 1    Bit 0   
            // ---------------------------------------------------------------------
            XOUTL = 0x00,  // 10 bits output value X LSB             XOUT[7]  XOUT[6]  XOUT[5]  XOUT[4]  XOUT[3]  XOUT[2]  XOUT[1]  XOUT[0]
            XOUTH = 0x01,  // 10 bits output value X MSB                                                                   XOUT[9]  XOUT[8]
            YOUTL = 0x02,  // 10 bits output value Y LSB             YOUT[7]  YOUT[6]  YOUT[5]  YOUT[4]  YOUT[3]  YOUT[2]  YOUT[1]  YOUT[0]
            YOUTH = 0x03,  // 10 bits output value Y MSB                                                                   YOUT[9]  YOUT[8]
            ZOUTL = 0x04,  // 10 bits output value Z LSB             ZOUT[7]  ZOUT[6]  ZOUT[5]  ZOUT[4]  ZOUT[3]  ZOUT[2]  ZOUT[1]  ZOUT[0]
            ZOUTH = 0x05,  // 10 bits output value Z MSB                                                                   ZOUT[9]  ZOUT[8]
            XOUT8 = 0x06,  // 8 bits output value X                  XOUT[7]  XOUT[6]  XOUT[5]  XOUT[4]  XOUT[3]  XOUT[2]  XOUT[1]  XOUT[0]
            YOUT8 = 0x07,  // 8 bits output value Y                  YOUT[7]  YOUT[6]  YOUT[5]  YOUT[4]  YOUT[3]  YOUT[2]  YOUT[1]  YOUT[0]
            ZOUT8 = 0x08,  // 8 bits output value Z                  ZOUT[7]  ZOUT[6]  ZOUT[5]  ZOUT[4]  ZOUT[3]  ZOUT[2]  ZOUT[1]  ZOUT[0]
            STATUS = 0x09, // Status registers                                                                       PERR     DOVR     DRDY
            DETSRC = 0x0A, // Detection source registers                 LDX      LDY      LDZ      PDX      PDY      PDZ     INT2     INT1
            TOUT = 0x0B,   // Temperature output value (Optional)     TMP[7]   TMP[6]   TMP[5]   TMP[4]    TMP[3]  TMP[2]   TMP[1]   TMP[0]
            I2CAD = 0x0D,  // I2C device address I2CDIS                        DAD[6]   DAD[5]   DAD[4]    DAD[3]  DAD[2]   DAD[1]   DAD[0]
            USRINF = 0x0E, // User information (Optional)              UI[7]    UI[6]    UI[5]    UI[4]     UI[3]   UI[2]    UI[1]    UI[0]
            WHOAMI = 0x0F, // "Who am I" value (Optional)              ID[7]    ID[6]    ID[5]    ID[4]     ID[3]   ID[2]    ID[1]    ID[0]
            XOFFL = 0x10,  // Offset drift X value (LSB)             XOFF[7]  XOFF[6]  XOFF[5]  XOFF[4]  XOFF[3]  XOFF[2]  XOFF[1]  XOFF[0]
            XOFFH = 0x11,  // Offset drift X value (MSB)                                                         XOFF[10]  XOFF[9]  XOFF[8]
            YOFFL = 0x12,  // Offset drift Y value (LSB)             YOFF[7]  YOFF[6]  YOFF[5]  YOFF[4]  YOFF[3]  YOFF[2]  YOFF[1]  YOFF[0]
            YOFFH = 0x13,   // Offset drift Y value (MSB)                                                         YOFF[10]  YOFF[9]  YOFF[8]
            ZOFFL = 0x14,  // Offset drift Z value (LSB)             ZOFF[7]  ZOFF[6]  ZOFF[5]  ZOFF[4]  ZOFF[3]  ZOFF[2]  ZOFF[1]  ZOFF[0]
            ZOFFH = 0x15,  // Offset drift Z value (MSB)                                                         ZOFF[10]  ZOFF[9]  ZOFF[8]
            MCTL = 0x16,   // Mode control                                       DRPD    SPI3W     STON  GLVL[1]  GLVL[0]   MOD[1]   MOD[0]
            INTRST = 0x17, // Interrupt latch reset                                                                        CLRINT2  CLRINT1
            CTL1 = 0x18,  // Control 1                                 DFBW    THOPT      ZDA      YDA      XDA INTRG[1] INTRG[0]   INTPIN
            CTL2 = 0x19,   // Control 2                                                                              DRVO     PDPL     LDPL
            LDTH = 0x1A,   // Level detection threshold limit value  LDTH[7]  LDTH[6]  LDTH[5]  LDTH[4]  LDTH[3]  LDTH[2]  LDTH[1]  LDTH[0]
            PDTH = 0x1B,   // Pulse detection threshold limit value  PDTH[7]  PDTH[6]  PDTH[5]  PDTH[4]  PDTH[3]  PDTH[2]  PDTH[1]  PDTH[0]
            PW = 0x1C,     // Pulse duration value                     PD[7]    PD[6]    PD[5]    PD[4]    PD[3]    PD[2]    PD[1]    PD[0]
            LT = 0x1D,     // Latency time value                       LT[7]    LT[6]    LT[5]    LT[4]    LT[3]    LT[2]    LT[1]    LT[0]
            TW = 0x1E      // Time window for 2nd pulse value          TW[7]    TW[6]    TW[5]    TW[4]    TW[3]    TW[2]    TW[1]    TW[0]
        }

        private byte[] _readBuffer8 = new byte[1];
        private byte[] _writeBuffer8 = new byte[1];
        private byte[] _writeBuffer16 = new byte[2];
        private byte[] _readBuffer24 = new byte[3];
        private byte[] _readBuffer48 = new byte[6];

        private byte ReadByte(Register register)
        {
            _writeBuffer8[0] = (byte)register;
            i2c.WriteRead(_writeBuffer8, _readBuffer8, 1000);
            return _readBuffer8[0];
        }

        private void Read(Register register, byte[] readBuffer)
        {
            _writeBuffer8[0] = (byte)register;
            i2c.WriteRead(_writeBuffer8, readBuffer, 1000);
        }

        private void Write(Register register, byte value)
        {
            _writeBuffer16[0] = (byte)register;
            _writeBuffer16[1] = (byte)value;
            i2c.Write(_writeBuffer16, 1000);
        }

    }
}

can you highlight what code changes you made to the Accelerometer module’s driver?

So I guess I switched the wrong driver.
I switched the Acc driver.

Where can I get the SoftwareI2C? I couldn’t find it in the link you posted before.