SimpleFOClibrary  2.1
MagneticSensorI2C.cpp
Go to the documentation of this file.
1 #include "MagneticSensorI2C.h"
2 
5  .chip_address = 0x36,
6  .bit_resolution = 12,
7  .angle_register = 0x0E,
8  .data_start_bit = 11
9 };
10 
13  .chip_address = 0x40, // highly configurable. if A1 and A2 are held low, this is probable value
14  .bit_resolution = 14,
15  .angle_register = 0xFE,
16  .data_start_bit = 15
17 };
18 
19 
20 // MagneticSensorI2C(uint8_t _chip_address, float _cpr, uint8_t _angle_register_msb)
21 // @param _chip_address I2C chip address
22 // @param _bit_resolution bit resolution of the sensor
23 // @param _angle_register_msb angle read register
24 // @param _bits_used_msb number of used bits in msb
25 MagneticSensorI2C::MagneticSensorI2C(uint8_t _chip_address, int _bit_resolution, uint8_t _angle_register_msb, int _bits_used_msb){
26  // chip I2C address
27  chip_address = _chip_address;
28  // angle read register of the magnetic sensor
29  angle_register_msb = _angle_register_msb;
30  // register maximum value (counts per revolution)
31  cpr = pow(2, _bit_resolution);
32 
33  // depending on the sensor architecture there are different combinations of
34  // LSB and MSB register used bits
35  // AS5600 uses 0..7 LSB and 8..11 MSB
36  // AS5048 uses 0..5 LSB and 6..13 MSB
37  // used bits in LSB
38  lsb_used = _bit_resolution - _bits_used_msb;
39  // extraction masks
40  lsb_mask = (uint8_t)( (2 << lsb_used) - 1 );
41  msb_mask = (uint8_t)( (2 << _bits_used_msb) - 1 );
42  wire = &Wire;
43 }
44 
46  chip_address = config.chip_address;
47 
48  // angle read register of the magnetic sensor
49  angle_register_msb = config.angle_register;
50  // register maximum value (counts per revolution)
51  cpr = pow(2, config.bit_resolution);
52 
53  int bits_used_msb = config.data_start_bit - 7;
54  lsb_used = config.bit_resolution - bits_used_msb;
55  // extraction masks
56  lsb_mask = (uint8_t)( (2 << lsb_used) - 1 );
57  msb_mask = (uint8_t)( (2 << bits_used_msb) - 1 );
58  wire = &Wire;
59 }
60 
61 void MagneticSensorI2C::init(TwoWire* _wire){
62 
63  wire = _wire;
64 
65  // I2C communication begin
66  wire->begin();
67 
68  // velocity calculation init
69  angle_prev = 0;
70  velocity_calc_timestamp = _micros();
71 
72  // full rotations tracking number
73  full_rotation_offset = 0;
74  angle_data_prev = getRawCount();
75 }
76 
77 // Shaft angle calculation
78 // angle is in radians [rad]
80  // raw data from the sensor
81  float angle_data = getRawCount();
82 
83  // tracking the number of rotations
84  // in order to expand angle range form [0,2PI]
85  // to basically infinity
86  float d_angle = angle_data - angle_data_prev;
87  // if overflow happened track it as full rotation
88  if(abs(d_angle) > (0.8*cpr) ) full_rotation_offset += d_angle > 0 ? -_2PI : _2PI;
89  // save the current angle value for the next steps
90  // in order to know if overflow happened
91  angle_data_prev = angle_data;
92  // return the full angle
93  // (number of full rotations)*2PI + current sensor angle
94  return (full_rotation_offset + ( angle_data / (float)cpr) * _2PI) ;
95 }
96 
97 // Shaft velocity calculation
99  // calculate sample time
100  unsigned long now_us = _micros();
101  float Ts = (now_us - velocity_calc_timestamp)*1e-6;
102  // quick fix for strange cases (micros overflow)
103  if(Ts <= 0 || Ts > 0.5) Ts = 1e-3;
104 
105  // current angle
106  float angle_c = getAngle();
107  // velocity calculation
108  float vel = (angle_c - angle_prev)/Ts;
109 
110  // save variables for future pass
111  angle_prev = angle_c;
112  velocity_calc_timestamp = now_us;
113  return vel;
114 }
115 
116 
117 // function reading the raw counter of the magnetic sensor
118 int MagneticSensorI2C::getRawCount(){
119  return (int)MagneticSensorI2C::read(angle_register_msb);
120 }
121 
122 // I2C functions
123 /*
124 * Read a register from the sensor
125 * Takes the address of the register as a uint8_t
126 * Returns the value of the register
127 */
128 int MagneticSensorI2C::read(uint8_t angle_reg_msb) {
129  // read the angle register first MSB then LSB
130  byte readArray[2];
131  uint16_t readValue = 0;
132  // notify the device that is aboout to be read
133  wire->beginTransmission(chip_address);
134  wire->write(angle_reg_msb);
135  wire->endTransmission(false);
136 
137  // read the data msb and lsb
138  wire->requestFrom(chip_address, (uint8_t)2);
139  for (byte i=0; i < 2; i++) {
140  readArray[i] = wire->read();
141  }
142 
143  // depending on the sensor architecture there are different combinations of
144  // LSB and MSB register used bits
145  // AS5600 uses 0..7 LSB and 8..11 MSB
146  // AS5048 uses 0..5 LSB and 6..13 MSB
147  readValue = ( readArray[1] & lsb_mask );
148  readValue += ( ( readArray[0] & msb_mask ) << lsb_used );
149  return readValue;
150 }
151 
152 /*
153 * Checks whether other devices have locked the bus. Can clear SDA locks.
154 * This should be called before sensor.init() on devices that suffer i2c slaves locking sda
155 * e.g some stm32 boards with AS5600 chips
156 * Takes the sda_pin and scl_pin
157 * Returns 0 for OK, 1 for other master and 2 for unfixable sda locked LOW
158 */
159 int MagneticSensorI2C::checkBus(byte sda_pin, byte scl_pin) {
160 
161  pinMode(scl_pin, INPUT_PULLUP);
162  pinMode(sda_pin, INPUT_PULLUP);
163  delay(250);
164 
165  if (digitalRead(scl_pin) == LOW) {
166  // Someone else has claimed master!");
167  return 1;
168  }
169 
170  if(digitalRead(sda_pin) == LOW) {
171  // slave is communicating and awaiting clocks, we are blocked
172  pinMode(scl_pin, OUTPUT);
173  for (byte i = 0; i < 16; i++) {
174  // toggle clock for 2 bytes of data
175  digitalWrite(scl_pin, LOW);
176  delayMicroseconds(20);
177  digitalWrite(scl_pin, HIGH);
178  delayMicroseconds(20);
179  }
180  pinMode(sda_pin, INPUT);
181  delayMicroseconds(20);
182  if (digitalRead(sda_pin) == LOW) {
183  // SDA still blocked
184  return 2;
185  }
186  _delay(1000);
187  }
188  // SDA is clear (HIGH)
189  pinMode(sda_pin, INPUT);
190  pinMode(scl_pin, INPUT);
191 
192  return 0;
193 }
MagneticSensorI2CConfig_s::angle_register
int angle_register
Definition: MagneticSensorI2C.h:13
MagneticSensorI2C::MagneticSensorI2C
MagneticSensorI2C(uint8_t _chip_address, int _bit_resolution, uint8_t _angle_register_msb, int _msb_bits_used)
Definition: MagneticSensorI2C.cpp:25
_delay
void _delay(unsigned long ms)
Definition: time_utils.cpp:5
MagneticSensorI2C.h
AS5048_I2C
MagneticSensorI2CConfig_s AS5048_I2C
Definition: MagneticSensorI2C.cpp:12
MagneticSensorI2CConfig_s::chip_address
int chip_address
Definition: MagneticSensorI2C.h:11
MagneticSensorI2CConfig_s::bit_resolution
int bit_resolution
Definition: MagneticSensorI2C.h:12
_2PI
#define _2PI
Definition: foc_utils.h:23
MagneticSensorI2CConfig_s
Definition: MagneticSensorI2C.h:10
MagneticSensorI2C::checkBus
int checkBus(byte sda_pin=SDA, byte scl_pin=SCL)
Definition: MagneticSensorI2C.cpp:159
_micros
unsigned long _micros()
Definition: time_utils.cpp:21
MagneticSensorI2C::init
void init(TwoWire *_wire=&Wire)
Definition: MagneticSensorI2C.cpp:61
MagneticSensorI2C::getAngle
float getAngle() override
Definition: MagneticSensorI2C.cpp:79
MagneticSensorI2CConfig_s::data_start_bit
int data_start_bit
Definition: MagneticSensorI2C.h:14
MagneticSensorI2C::getVelocity
float getVelocity() override
Definition: MagneticSensorI2C.cpp:98
AS5600_I2C
MagneticSensorI2CConfig_s AS5600_I2C
Definition: MagneticSensorI2C.cpp:4