SimpleFOClibrary  2.1
MagneticSensorSPI.cpp
Go to the documentation of this file.
1 #include "MagneticSensorSPI.h"
2 
5  .spi_mode = SPI_MODE1,
6  .clock_speed = 1000000,
7  .bit_resolution = 14,
8  .angle_register = 0x3FFF,
9  .data_start_bit = 13,
10  .command_rw_bit = 14,
11  .command_parity_bit = 15
12 };
13 // AS5048 and AS5047 are the same as AS5147
16 
19  .spi_mode = SPI_MODE0,
20  .clock_speed = 1000000,
21  .bit_resolution = 14,
22  .angle_register = 0x0000,
23  .data_start_bit = 15,
24  .command_rw_bit = 0, // not required
25  .command_parity_bit = 0 // parity not implemented
26 };
27 
28 
29 // MagneticSensorSPI(int cs, float _bit_resolution, int _angle_register)
30 // cs - SPI chip select pin
31 // _bit_resolution sensor resolution bit number
32 // _angle_register - (optional) angle read register - default 0x3FFF
33 MagneticSensorSPI::MagneticSensorSPI(int cs, float _bit_resolution, int _angle_register){
34 
35  chip_select_pin = cs;
36  // angle read register of the magnetic sensor
37  angle_register = _angle_register ? _angle_register : DEF_ANGLE_REGISTER;
38  // register maximum value (counts per revolution)
39  cpr = pow(2,_bit_resolution);
40  spi_mode = SPI_MODE1;
41  clock_speed = 1000000;
42  bit_resolution = _bit_resolution;
43 
44  command_parity_bit = 15; // for backwards compatibilty
45  command_rw_bit = 14; // for backwards compatibilty
46  data_start_bit = 13; // for backwards compatibilty
47 }
48 
50  chip_select_pin = cs;
51  // angle read register of the magnetic sensor
52  angle_register = config.angle_register ? config.angle_register : DEF_ANGLE_REGISTER;
53  // register maximum value (counts per revolution)
54  cpr = pow(2, config.bit_resolution);
55  spi_mode = config.spi_mode;
56  clock_speed = config.clock_speed;
57  bit_resolution = config.bit_resolution;
58 
59  command_parity_bit = config.command_parity_bit; // for backwards compatibilty
60  command_rw_bit = config.command_rw_bit; // for backwards compatibilty
61  data_start_bit = config.data_start_bit; // for backwards compatibilty
62 }
63 
64 void MagneticSensorSPI::init(SPIClass* _spi){
65 
66  spi = _spi;
67 
68  // 1MHz clock (AMS should be able to accept up to 10MHz)
69  settings = SPISettings(clock_speed, MSBFIRST, spi_mode);
70 
71  //setup pins
72  pinMode(chip_select_pin, OUTPUT);
73 
74  //SPI has an internal SPI-device counter, it is possible to call "begin()" from different devices
75  spi->begin();
76 #ifndef ESP_H // if not ESP32 board
77  spi->setBitOrder(MSBFIRST); // Set the SPI_1 bit order
78  spi->setDataMode(spi_mode) ;
79  spi->setClockDivider(SPI_CLOCK_DIV8);
80 #endif
81 
82  digitalWrite(chip_select_pin, HIGH);
83  // velocity calculation init
84  angle_prev = 0;
85  velocity_calc_timestamp = _micros();
86 
87  // full rotations tracking number
88  full_rotation_offset = 0;
89  angle_data_prev = getRawCount();
90 }
91 
92 // Shaft angle calculation
93 // angle is in radians [rad]
95  // raw data from the sensor
96  float angle_data = getRawCount();
97 
98  // tracking the number of rotations
99  // in order to expand angle range form [0,2PI]
100  // to basically infinity
101  float d_angle = angle_data - angle_data_prev;
102  // if overflow happened track it as full rotation
103  if(abs(d_angle) > (0.8*cpr) ) full_rotation_offset += d_angle > 0 ? -_2PI : _2PI;
104  // save the current angle value for the next steps
105  // in order to know if overflow happened
106  angle_data_prev = angle_data;
107 
108  // return the full angle
109  // (number of full rotations)*2PI + current sensor angle
110  return full_rotation_offset + ( angle_data / (float)cpr) * _2PI;
111 }
112 
113 // Shaft velocity calculation
115  // calculate sample time
116  unsigned long now_us = _micros();
117  float Ts = (now_us - velocity_calc_timestamp)*1e-6;
118  // quick fix for strange cases (micros overflow)
119  if(Ts <= 0 || Ts > 0.5) Ts = 1e-3;
120 
121  // current angle
122  float angle_c = getAngle();
123  // velocity calculation
124  float vel = (angle_c - angle_prev)/Ts;
125 
126  // save variables for future pass
127  angle_prev = angle_c;
128  velocity_calc_timestamp = now_us;
129  return vel;
130 }
131 
132 
133 // function reading the raw counter of the magnetic sensor
134 int MagneticSensorSPI::getRawCount(){
135  return (int)MagneticSensorSPI::read(angle_register);
136 }
137 
138 // SPI functions
142 byte MagneticSensorSPI::spiCalcEvenParity(word value){
143  byte cnt = 0;
144  byte i;
145 
146  for (i = 0; i < 16; i++)
147  {
148  if (value & 0x1) cnt++;
149  value >>= 1;
150  }
151  return cnt & 0x1;
152 }
153 
154  /*
155  * Read a register from the sensor
156  * Takes the address of the register as a 16 bit word
157  * Returns the value of the register
158  */
159 word MagneticSensorSPI::read(word angle_register){
160 
161  word command = angle_register;
162 
163  if (command_rw_bit > 0) {
164  command = angle_register | (1 << command_rw_bit);
165  }
166  if (command_parity_bit > 0) {
167  //Add a parity bit on the the MSB
168  command |= ((word)spiCalcEvenParity(command) << command_parity_bit);
169  }
170 
171 #if !defined(_STM32_DEF_) // if not stm chips
172  //SPI - begin transaction
173  spi->beginTransaction(settings);
174 #endif
175 
176  //Send the command
177  digitalWrite(chip_select_pin, LOW);
178  digitalWrite(chip_select_pin, LOW);
179  spi->transfer16(command);
180  digitalWrite(chip_select_pin,HIGH);
181  digitalWrite(chip_select_pin,HIGH);
182 
183 #if defined( ESP_H ) // if ESP32 board
184  delayMicroseconds(50);
185 #else
186  delayMicroseconds(10);
187 #endif
188 
189  //Now read the response
190  digitalWrite(chip_select_pin, LOW);
191  digitalWrite(chip_select_pin, LOW);
192  word register_value = spi->transfer16(0x00);
193  digitalWrite(chip_select_pin, HIGH);
194  digitalWrite(chip_select_pin,HIGH);
195 
196 #if !defined(_STM32_DEF_) // if not stm chips
197  //SPI - end transaction
198  spi->endTransaction();
199 #endif
200 
201  register_value = register_value >> (1 + data_start_bit - bit_resolution); //this should shift data to the rightmost bits of the word
202 
203  const static word data_mask = 0xFFFF >> (16 - bit_resolution);
204 
205  return register_value & data_mask; // Return the data, stripping the non data (e.g parity) bits
206 }
207 
212 void MagneticSensorSPI::close(){
213  spi->end();
214 }
MagneticSensorSPI::getVelocity
float getVelocity() override
Definition: MagneticSensorSPI.cpp:114
MagneticSensorSPIConfig_s::bit_resolution
int bit_resolution
Definition: MagneticSensorSPI.h:15
AS5147_SPI
MagneticSensorSPIConfig_s AS5147_SPI
Definition: MagneticSensorSPI.cpp:4
AS5048_SPI
MagneticSensorSPIConfig_s AS5048_SPI
Definition: MagneticSensorSPI.cpp:14
MagneticSensorSPIConfig_s::clock_speed
long clock_speed
Definition: MagneticSensorSPI.h:14
MagneticSensorSPI.h
MagneticSensorSPIConfig_s::command_rw_bit
int command_rw_bit
Definition: MagneticSensorSPI.h:18
MagneticSensorSPIConfig_s::spi_mode
int spi_mode
Definition: MagneticSensorSPI.h:13
MagneticSensorSPI::spi_mode
int spi_mode
Definition: MagneticSensorSPI.h:50
MA730_SPI
MagneticSensorSPIConfig_s MA730_SPI
Definition: MagneticSensorSPI.cpp:18
MagneticSensorSPIConfig_s::angle_register
int angle_register
Definition: MagneticSensorSPI.h:16
MagneticSensorSPI::getAngle
float getAngle() override
Definition: MagneticSensorSPI.cpp:94
MagneticSensorSPI::MagneticSensorSPI
MagneticSensorSPI(int cs, float bit_resolution, int angle_register=0)
Definition: MagneticSensorSPI.cpp:33
DEF_ANGLE_REGISTER
#define DEF_ANGLE_REGISTER
Definition: MagneticSensorSPI.h:10
_2PI
#define _2PI
Definition: foc_utils.h:23
MagneticSensorSPI::init
void init(SPIClass *_spi=&SPI)
Definition: MagneticSensorSPI.cpp:64
MagneticSensorSPIConfig_s
Definition: MagneticSensorSPI.h:12
MagneticSensorSPIConfig_s::command_parity_bit
int command_parity_bit
Definition: MagneticSensorSPI.h:19
MagneticSensorSPIConfig_s::data_start_bit
int data_start_bit
Definition: MagneticSensorSPI.h:17
_micros
unsigned long _micros()
Definition: time_utils.cpp:21
MagneticSensorSPI::clock_speed
long clock_speed
Definition: MagneticSensorSPI.h:53
AS5047_SPI
MagneticSensorSPIConfig_s AS5047_SPI
Definition: MagneticSensorSPI.cpp:15