1////////////////////////////////////////////////////////////////////////////////
2// //
3// This software is supplied under the terms of a license agreement or //
4// nondisclosure agreement with Mitov Software and may not be copied //
5// or disclosed except in accordance with the terms of that agreement. //
6// Copyright(c) 2002-2016 Mitov Software. All Rights Reserved. //
7// //
8////////////////////////////////////////////////////////////////////////////////
9
10#ifndef _MITOV_AK8963_h
11#define _MITOV_COMPASS_AK8963_h
12
13#include <Mitov.h>
14#include <Wire.h> //I2C Arduino Library
15#include <Mitov_Basic_I2C.h>
16
17namespace Mitov
18{
19//---------------------------------------------------------------------------
20 enum CompassAK8963Mode { cmSingleMeasurement, cm8Hz, cm100Hz, cmExternalTrigger };
21//---------------------------------------------------------------------------
22 namespace CompassAK8963Const
23 {
24 const byte CompassModes[] =
25 {
26 0b00000001,
27 0b00000010,
28 0b00000110,
29 0b00000100
30 };
31 }
32//---------------------------------------------------------------------------
33 class CompassAK8963 : public Mitov::EnabledComponent, public Mitov::ClockingSupport
34 {
35 typedef Mitov::EnabledComponent inherited;
36
37 protected:
38 static const byte MPU9150_RA_MAG_ST1 = 0x02;
39 static const byte MPU9150_RA_MAG_XOUT_L = 0x03;
40 static const byte MPU9150_RA_MAG_XOUT_H = 0x04;
41 static const byte MPU9150_RA_MAG_YOUT_L = 0x05;
42 static const byte MPU9150_RA_MAG_YOUT_H = 0x06;
43 static const byte MPU9150_RA_MAG_ZOUT_L = 0x07;
44 static const byte MPU9150_RA_MAG_ZOUT_H = 0x08;
45 static const byte MPU9150_RA_MAG_ST2 = 0x09;
46 static const byte MPU9150_RA_MAG_CNTL1 = 0x0A;
47 static const byte MPU9150_RA_MAG_CNTL2 = 0x0B;
48
49 static const byte MPU9150_RA_MAG_ASAX = 0x10;
50 static const byte MPU9150_RA_MAG_ASAY = 0x11;
51 static const byte MPU9150_RA_MAG_ASAZ = 0x12;
52
53 public:
54 OpenWire::SourcePin OutputPins[ 3 ];
55
56 OpenWire::SinkPin ResetInputPin;
57 OpenWire::SourcePin OverflowOutputPin;
58
59 public:
60 CompassAK8963Mode Mode : 2;
61 bool Enabled : 1;
62 bool SelfTest : 1; // Added to save space as bitfield
63 byte Address : 2;
64 bool HighResolution : 1;
65
66 protected:
67 float CompassAdjustmentValues[ 3 ];
68
69 protected:
70 void PerformRead()
71 {
72 const float CompassCoefficients[] =
73 {
74 10.0f *4219.0f / 8190.0f,
75 10.0f *4219.0f / 32760.0f
76 };
77
78 uint8_t AIntValues[ 7 ];
79 if( ReadBytes( MPU9150_RA_MAG_XOUT_L, 7, AIntValues ))
80 for( int i = 0; i < 3; ++i )
81 {
82 float AValue = (( ((int16_t)AIntValues[ i * 2 + 1 ] ) << 8 ) | AIntValues[ i * 2 ] ) * CompassCoefficients[ HighResolution & 1 ] * CompassAdjustmentValues[ i ];
83 OutputPins[ i ].Notify( &AValue );
84 }
85
86 }
87
88 void ReadSensors()
89 {
90 uint8_t AIntValue;
91
92 if( Mode == cmSingleMeasurement )
93 {
94 UpdateCompassControlReg();
95 delay(10);
96 PerformRead();
97 }
98
99 if( ReadBytes( MPU9150_RA_MAG_ST1, 1, &AIntValue ))
100 {
101 OverflowOutputPin.SendValue( AIntValue & 0b00000010 );
102 if( AIntValue & 0b00000001 )
103 PerformRead();
104 }
105
106 }
107
108 void UpdateCompassControlReg()
109 {
110 byte AValue;
111 if( Enabled )
112 AValue = CompassAK8963Const::CompassModes[ Mode ];
113
114 else
115 AValue = 0;
116
117 AValue |= ( HighResolution ? 0b00010000 : 0 );
118
119 WriteByte( MPU9150_RA_MAG_CNTL1, AValue );
120 }
121
122 void ReagCompassAdjustmentValues()
123 {
124 uint8_t AValues[ 3 ];
125
126 ReadBytes( MPU9150_RA_MAG_ASAX, sizeof( AValues ), AValues );
127 for( int i = 0; i < 3; ++i )
128 CompassAdjustmentValues[ i ] = (((float) AValues[ i ] ) - 128.0f) / 256.0f + 1.0f;
129
130 }
131
132 protected:
133 inline void WriteByte( byte ARegister, byte AData )
134 {
135 I2C::WriteByte( Address + 0x0C, ARegister, AData );
136 }
137
138 bool ReadBytes( uint8_t regAddr, uint8_t length, void *data )
139 {
140 return I2C::ReadBytes( Address + 0x0C, regAddr, length, data );
141 }
142
143 protected:
144 virtual void SystemStart() override
145 {
146 UpdateCompassControlReg();
147 ReagCompassAdjustmentValues();
148
149 inherited::SystemStart();
150 }
151
152 virtual void SystemLoopBegin( unsigned long currentMicros ) override
153 {
154
155 if( Enabled )
156 if( ! ClockInputPin.IsConnected() )
157 ReadSensors();
158
159 inherited::SystemLoopBegin( currentMicros );
160 }
161
162 protected:
163 virtual void DoClockReceive( void *_Data ) override
164 {
165 ReadSensors();
166 }
167
168 void DoResetReceive( void *_Data )
169 {
170 WriteByte( MPU9150_RA_MAG_CNTL2, 0b00000001 );
171 }
172
173 public:
174 CompassAK8963() :
175 Mode( cm100Hz ),
176 Enabled( true ),
177 SelfTest( false ),
178 HighResolution( true ),
179 Address( 0 )
180 {
181 ResetInputPin.SetCallback( MAKE_CALLBACK( CompassAK8963::DoResetReceive ));
182 }
183 };
184//---------------------------------------------------------------------------
185 class CompassAK8963I2C : public Mitov::CompassAK8963
186 {
187 typedef Mitov::CompassAK8963 inherited;
188 };
189//---------------------------------------------------------------------------
190}
191
192#endif