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_HMC5883L_h
11#define _MITOV_HMC5883L_h
12
13#include <Mitov.h>
14#include <Wire.h> //I2C Arduino Library
15
16namespace Mitov
17{
18
19 const byte HMC5883L_Address = 0x1E;
20 const byte HMC5883L_StatusRegister = 9;
21 const byte HMC5883L_ModeRegister = 2;
22 const byte HMC5883_REGISTER_MAG_CRA_REG_M = 0x00;
23 const byte HMC5883_REGISTER_MAG_CRB_REG_M = 0x01;
24 const byte HMC5883_REGISTER_MAG_OUT_X_H_M = 0x03;
25//---------------------------------------------------------------------------
26 enum HMC5883L_AveragedSamples { cas1, cas2, cas4, cas8 };
27 enum HMC5883L_Bias { cbNone, cbPositive, cbNegative };
28 enum HMC5883L_Gain { cg1370, cg1090, cg820, cg660, cg440, cg390, cg330, cg230 };
29//---------------------------------------------------------------------------
30 class HMC5883L_Compass : public Mitov::EnabledComponent, public Mitov::ClockingSupport
31 {
32 typedef Mitov::EnabledComponent inherited;
33
34 public:
35 OpenWire::TypedSourcePin<float> XOutputPin;
36 OpenWire::TypedSourcePin<float> YOutputPin;
37 OpenWire::TypedSourcePin<float> ZOutputPin;
38
39 public:
40 HMC5883L_AveragedSamples AveragedSamples : 2;
41 HMC5883L_Bias Bias : 2;
42 HMC5883L_Gain Gain : 3;
43 bool Idle : 1;
44
45 protected:
46 bool FClocked : 1;
47 bool FChangeOnly : 1;
48
49 public:
50 void SetIdle( bool AValue )
51 {
52 if( Idle == AValue )
53 return;
54
55 Idle = AValue;
56 SetIntIdle();
57 }
58
59 protected:
60 float FScale;
61
62 protected:
63 void SetIntIdle()
64 {
65 if( Idle )
66 WriteTo( HMC5883L_Address, 0b11 ); // Idle
67
68 else
69 WriteTo( HMC5883L_Address, 0b00 ); // Single measurement mode
70// WriteTo( HMC5883L_Address, 0b01 ); // Single measurement mode
71 }
72
73 bool DataAvailable()
74 {
75 StartReadFrom( HMC5883L_StatusRegister, 1 );
76
77 uint8_t AStatus = Wire.read();
78 return( AStatus & 1 );
79 }
80
81 void ReadCompass()
82 {
83 if( ! Enabled )
84 return;
85
86 if( ! DataAvailable() )
87 return;
88
89 FClocked = false;
90
91 StartReadFrom( HMC5883_REGISTER_MAG_OUT_X_H_M, 6 );
92
93 union T16BitData
94 {
95 uint8_t Bytes[ 2 ];
96 int16_t Value;
97 };
98
99 T16BitData A16BitValue;
100 float AValue;
101
102 A16BitValue.Bytes[ 1 ] = Wire.read();
103 A16BitValue.Bytes[ 0 ] = Wire.read();
104
105/*
106 float _magData_x = ((int16_t)A16BitValue.Bytes[ 0 ] ) | (((int16_t)A16BitValue.Bytes[ 1 ] ) << 8);
107
108 if( A16BitValue.Value != _magData_x )
109 {
110 Serial.print( A16BitValue.Value ); Serial.print( " " ); Serial.println( _magData_x );
111 }
112*/
113// A16BitValue.Bytes[ 0 ] = 0;
114// A16BitValue.Bytes[ 1 ] = 0;
115
116// Serial.print( "Scale: " ); Serial.println( FScale );
117// Serial.print( "Value: " ); Serial.print( A16BitValue.Bytes[ 0 ] ); Serial.print( " " ); Serial.println( A16BitValue.Bytes[ 1 ] );
118// Serial.print( "Value: " ); Serial.println( A16BitValue.Value );
119 AValue = A16BitValue.Value * FScale;
120
121 XOutputPin.SetValue( AValue, FChangeOnly );
122
123 A16BitValue.Bytes[ 1 ] = Wire.read();
124 A16BitValue.Bytes[ 0 ] = Wire.read();
125
126 AValue = A16BitValue.Value * FScale;
127
128 ZOutputPin.SetValue( AValue, FChangeOnly );
129
130 A16BitValue.Bytes[ 1 ] = Wire.read();
131 A16BitValue.Bytes[ 0 ] = Wire.read();
132
133 AValue = A16BitValue.Value * FScale;
134
135 YOutputPin.SetValue( AValue, FChangeOnly );
136
137 FChangeOnly = true;
138 }
139
140 virtual void DoClockReceive( void *_Data ) override
141 {
142 FClocked = true;
143 ReadCompass();
144 }
145
146 protected:
147 void WriteTo( byte ARegister, byte AData )
148 {
149// Serial.print( "WriteTo :" ); Serial.print( ARegister ); Serial.print( " " ); Serial.println( AData );
150 Wire.beginTransmission( HMC5883L_Address );
151 Wire.write( ARegister );
152 Wire.write( AData );
153 Wire.endTransmission();
154 }
155
156 void StartReadFrom( byte ARegister, byte ALength )
157 {
158// Serial.print( "StartReadFrom :" ); Serial.print( ARegister ); Serial.print( " " ); Serial.println( ALength );
159 Wire.beginTransmission( HMC5883L_Address );
160 Wire.write( ARegister );
161 Wire.endTransmission();
162
163 Wire.requestFrom( HMC5883L_Address, ALength );
164 while (Wire.available() < ALength);
165 }
166
167 virtual void SystemStart() override
168 {
169 uint8_t AValue;
170
171 WriteTo( HMC5883L_ModeRegister, 0 );
172
173 AValue = ( Bias & 0b11 ) + (( AveragedSamples & 0b11 ) << 5 );
174 WriteTo( HMC5883_REGISTER_MAG_CRA_REG_M, AValue );
175
176 AValue = ( Gain & 0b111 ) << 5;
177 WriteTo( HMC5883_REGISTER_MAG_CRB_REG_M, AValue );
178// Serial.println( AValue );
179// delay( 10000 );
180
181 switch( Gain )
182 {
183 case cg1370: FScale = 0.73; break;
184 case cg1090: FScale = 0.92; break;
185 case cg820: FScale = 1.22; break;
186 case cg660: FScale = 1.52; break;
187 case cg440: FScale = 2.27; break;
188 case cg390: FScale = 2.56; break;
189 case cg330: FScale = 3.03; break;
190 case cg230: FScale = 4.35; break;
191 }
192
193 SetIntIdle();
194 inherited::SystemStart();
195 }
196
197 virtual void SystemLoopBegin( unsigned long currentMicros ) override
198 {
199 if( Enabled )
200 if( FClocked || ( ! ClockInputPin.IsConnected() ))
201 ReadCompass();
202
203 inherited::SystemLoopBegin( currentMicros );
204 }
205
206 public:
207 HMC5883L_Compass() :
208 FClocked( false ),
209 FChangeOnly( false ),
210 AveragedSamples( cas1 ),
211 Bias( cbNone ),
212 Gain( cg1090 ),
213 Idle( false )
214 {
215 }
216 };
217}
218
219#endif