Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: heros_leg_readout_torque_addition heros_leg_readout_torque_addition heros_leg_readout_torque_addition_V3
as5048.h
00001 #ifndef _AS5048_H_ 00002 #define _AS5048_H_ 00003 00004 #include "mbed.h" 00005 /** 00006 * Interfacing with the AMS AS5048A magnetic rotary sensor using SPI protocol 00007 * AS5048 uses 16-bit transfer; 00008 * We use two 8-bit transfers for compatibility with 8-bit SPI master devices 00009 * SPI protocol: 00010 * Mode = 1: 00011 * clock polarity = 0 --> clock pulse is high 00012 * clock phase = 1 --> sample on falling edge of clock pulse 00013 * Code was succesfully tested on the FRDM KL25Z and K22F. The same code fails 00014 * on the K64F for some reason. Sampling using a logic analyzer does however 00015 * show the same results for al three boards. 00016 */ 00017 class As5048 { 00018 00019 00020 public: 00021 00022 static const int kNumSensorBits = 14; // 14-bits sensor 00023 static const uint16_t kCountsPerRev = 0x4000; // 2**NUM_SENSOR_BITS 00024 static const uint16_t kMask = 0x3FFF; // 2**NUM_SENSOR_BITS - 1 00025 static const int kParity = 1; // even parity 00026 00027 static const int kSpiFrequency = 1000000; // AS5048 max 10 MHz 00028 static const int kSpiBitsPerTransfer = 8; 00029 static const int kSpiMode = 1; 00030 00031 static const float kDegPerRev = 360.0f; // 360 degrees/rev 00032 static const float kRadPerRev = 6.28318530718f; // 2*pi rad/rev 00033 00034 // AS5048 flags 00035 typedef enum { 00036 AS_FLAG_PARITY = 0x8000, 00037 AS_FLAG_READ = 0x4000, 00038 } As5048Flag; 00039 00040 // AS5048 commands 00041 typedef enum { 00042 AS_CMD_NOP = 0x0000, 00043 AS_CMD_ERROR = 0x0001 | AS_FLAG_READ, // Reads error register of sensor and clear error flags 00044 AS_CMD_DIAGNOSTICS = 0x3FFD | AS_FLAG_READ, // Reads automatic gain control and diagnostics info 00045 AS_CMD_MAGNITUDE = 0x3FFE | AS_FLAG_READ, 00046 AS_CMD_ANGLE = 0x3FFF | AS_FLAG_PARITY | AS_FLAG_READ, 00047 } As5048Command; 00048 00049 // AS5048 diagnostics 00050 typedef enum { 00051 AS_DIAG_CORDIC_OVERFLOW = 0x0200, 00052 AS_DIAG_HIGH_MAGNETIC = 0x0400, 00053 AS_DIAG_LOW_MAGNETIC = 0x0800, 00054 } As5048Diagnostics; 00055 00056 /** 00057 * Creates an object of num_sensors daisy chained AS5048 sensors; 00058 * default number of sensors in chain is 1 00059 * @param mosi: pinname of the mosi pin of the spi communication 00060 * @param miso: pinname of the miso pin of the spi communication 00061 * @param sck: pinname of the clock pin of the spi communication 00062 * @param cs: pinname of the chip select pin of the spi communication 00063 * @param num_sensors = 1: number of sensors in daisy chain 00064 */ 00065 As5048(PinName mosi, PinName miso, PinName sck, PinName cs, int num_sensors = 1): 00066 kNumSensors_(num_sensors), 00067 chip_(cs), 00068 spi_(mosi, miso, sck) 00069 { 00070 DeselectChip(); 00071 00072 spi_.format(kSpiBitsPerTransfer, kSpiMode); 00073 spi_.frequency(kSpiFrequency); 00074 00075 read_buffer_ = new uint16_t[kNumSensors_]; 00076 angle_buffer_ = new uint16_t[kNumSensors_]; 00077 angle_offset_ = new uint16_t[kNumSensors_]; 00078 directions_ = new bool[kNumSensors_]; 00079 00080 for (int i=0; i<kNumSensors_; ++i) { 00081 read_buffer_[i] = 0; 00082 angle_buffer_[i] = 0; 00083 angle_offset_[i] = 0; 00084 directions_[i] = true; 00085 } 00086 00087 last_command_ = AS_CMD_NOP; 00088 } 00089 00090 00091 /** 00092 * Destructor, memory deallocation 00093 */ 00094 ~As5048() 00095 { 00096 delete [] read_buffer_; 00097 delete [] angle_buffer_; 00098 delete [] angle_offset_; 00099 delete [] directions_; 00100 } 00101 00102 /** 00103 * Parity check 00104 * @param n: integer to check 00105 * @return: true if ok 00106 */ 00107 static bool CheckParity(int n) 00108 { 00109 int parity = n; 00110 for(int i=1; i <= kNumSensorBits+1; ++i) { 00111 n >>= 1; 00112 parity ^= n; 00113 } 00114 return (parity & kParity) == 0; 00115 } 00116 00117 /** 00118 * Update the buffer with angular measurements 00119 * NOTE 1: 00120 * If the last command sent through Transfer was *not* AS_CMD_ANGLE 00121 * then we need an additional Transfer; this takes more time! 00122 * This should not occur, since Transfer is not *yet* used elsewhere. 00123 * NOTE 2: 00124 * We run a parity check on the results from the transfer. We only 00125 * update the angle_buffer_ with values that pass the parity check. 00126 * Measurement using Timer on K64F for last_command_ == AS_CMD_ANGLE 00127 * shows this function takes 87 or 88 us. 00128 */ 00129 void UpdateAngleBuffer() 00130 { 00131 // ensure that the new results indeed will be angles 00132 if (last_command_ != AS_CMD_ANGLE) { 00133 Transfer(AS_CMD_ANGLE); 00134 } 00135 00136 // update the read buffer 00137 Transfer(AS_CMD_ANGLE); 00138 00139 // update the angle buffer with parity checked values 00140 for (int i=0; i<kNumSensors_; ++i) { 00141 if (CheckParity(read_buffer_[i])) { 00142 // only update angles when parity is correct 00143 angle_buffer_[i] = read_buffer_[i]; 00144 } 00145 } 00146 } 00147 00148 /** 00149 * @return: pointer to read_buffer_ 00150 */ 00151 const uint16_t* get_read_buffer () { return read_buffer_; } 00152 00153 /** 00154 * @return: pointer to angle_buffer_ 00155 */ 00156 const uint16_t* get_angle_buffer () { return angle_buffer_; } 00157 00158 /** 00159 * @return: pointer to angle_offet_ 00160 */ 00161 const uint16_t* get_angle_offset () { return angle_offset_; } 00162 00163 /** 00164 * @return: pointer to directions_ 00165 */ 00166 const bool * get_directions_ () { return directions_;} 00167 00168 /** 00169 * You get the angles from two UpdateAngleBuffer() calls before 00170 * @return: 14 bits absolute position 00171 */ 00172 int getAngle(int i_sensor=0) 00173 { 00174 int ans = ((int) (angle_buffer_[i_sensor] & kMask)) - angle_offset_[i_sensor]; 00175 return directions_[i_sensor]?ans:-ans; 00176 } 00177 00178 /** 00179 * You get the angles from two UpdateAngleBuffer() calls before 00180 * @return: revolution ratio in [0,1] 00181 */ 00182 float getAngleRatio(int i_sensor=0) { return (float) getAngle(i_sensor) / kCountsPerRev; } 00183 00184 /** 00185 * You get the angles from two UpdateAngleBuffer() calls before 00186 * @return: angle in degrees 00187 */ 00188 float getAngleDegrees(int i_sensor=0) { return getAngleRatio(i_sensor) * kDegPerRev; } 00189 00190 /** 00191 * You get the angles from two UpdateAngleBuffer() calls before 00192 * @return: angle in radians 00193 */ 00194 float getAngleRadians(int i_sensor=0) { return getAngleRatio(i_sensor) * kRadPerRev; } 00195 00196 /** 00197 * Set direction for a sensor 00198 * @param i_sensor: id of sensor for which the offset is to be set 00199 * @param dir: true positive, false negative 00200 * @return: true if i_sensor in [0,kNumSensor_) 00201 */ 00202 bool setDirection(int i_sensor, bool dir) 00203 { 00204 if (i_sensor>-1 and i_sensor<kNumSensors_) { 00205 directions_[i_sensor] = dir; 00206 return true; 00207 } 00208 return false; 00209 } 00210 00211 /** 00212 * Set direction for the first sensor 00213 * @param dir: true positive, false negative 00214 * @return: true if i_sensor in [0,kNumSensor_) 00215 */ 00216 bool setDirection(bool dir) 00217 { 00218 return setDirection(0,dir); 00219 } 00220 00221 00222 /** 00223 * Set offset for a sensor 00224 * @param i_sensor: id of sensor for which the offset is to be set 00225 * @param offset: offset in counts [0,2**14-1] 00226 * @return: true if i_sensor in [0,kNumSensor_) 00227 */ 00228 bool setOffset(int i_sensor, uint16_t offset) 00229 { 00230 if (i_sensor>-1 and i_sensor<kNumSensors_) { 00231 angle_offset_[i_sensor] = offset; 00232 return true; 00233 } 00234 return false; 00235 } 00236 00237 /** 00238 * Set offset for the first sensor 00239 * @param offset: offset in counts [0,2**14-1] 00240 * @return: true if i_sensor in [0,kNumSensor_) 00241 */ 00242 bool setOffset(uint16_t offset) { return setOffset(0,offset); } 00243 00244 /** 00245 * Set offset for a sensor 00246 * @param i_sensor: id of sensor for which the offset is to be set 00247 * @param offset_ratio: offset in ratio in [0,1] 00248 * @return: true if i_sensor in [0,kNumSensor_) 00249 */ 00250 bool setOffsetRatio (int i_sensor, float offset_ratio) 00251 { 00252 return setOffset(i_sensor,offset_ratio*kCountsPerRev); 00253 } 00254 00255 /** 00256 * Set offset for the first sensor 00257 * @param offset_ratio: offset in ratio in [0,1] 00258 * @return: true if i_sensor in [0,kNumSensor_) 00259 */ 00260 bool setOffsetRatio(float offset_ratio) 00261 { 00262 return setOffsetRatio(0,offset_ratio); 00263 } 00264 00265 /** 00266 * Set offset for a sensor 00267 * @param i_sensor: id of sensor for which the offset is to be set 00268 * @param offset_degrees: offset in degrees in [0,360] 00269 * @return: true if i_sensor in [0,kNumSensor_) 00270 */ 00271 bool setOffsetDegrees(int i_sensor, float offset_degrees) 00272 { 00273 return setOffsetRatio(i_sensor,offset_degrees / kDegPerRev); 00274 } 00275 00276 /** 00277 * Set offset for the first sensor 00278 * @param offset_degrees: offset in degrees in [0,360] 00279 * @return: true if i_sensor in [0,kNumSensor_) 00280 */ 00281 bool setOffsetDegrees(float offset_degrees) 00282 { 00283 return setOffsetDegrees(0, offset_degrees); 00284 } 00285 00286 /** 00287 * Set offset for a sensor 00288 * @param i_sensor: id of sensor for which the offset is to be set 00289 * @param offset_radians: offset in radians in [0,2*pi] 00290 * @return: true if i_sensor in [0,kNumSensor_) 00291 */ 00292 bool setOffsetRadians(int i_sensor, float offset_radians) 00293 { 00294 return setOffsetRatio(i_sensor, offset_radians / kRadPerRev); 00295 } 00296 00297 /** 00298 * Set offset for the first sensor 00299 * @param offset_radians: offset in radians in [0,2*pi] 00300 * @return: true if i_sensor in [0,kNumSensor_) 00301 */ 00302 bool setOffsetRadians(float offset_radians) 00303 { 00304 return setOffsetRadians(0, offset_radians); 00305 } 00306 00307 00308 00309 00310 protected: 00311 00312 00313 00314 /** 00315 * Select (low) chip, and wait 1 us (at least 350 ns) 00316 */ 00317 void SelectChip() { chip_.write(0); wait_us(1); } 00318 00319 /** 00320 * Deselect (high) chip, and wait 1 us (at least 350 ns) 00321 */ 00322 void DeselectChip() { chip_.write(1); wait_us(1); } 00323 00324 /** 00325 * SPI transfer between each of the daisy chained sensors 00326 * @param cmd: Command to send 00327 */ 00328 void Transfer(As5048Command cmd) 00329 { 00330 SelectChip(); 00331 for(int i=0; i<kNumSensors_; ++i){ 00332 read_buffer_[i] = spi_.write(cmd>>8) << 8; 00333 read_buffer_[i] |= spi_.write(cmd & 0x00FF); 00334 } 00335 DeselectChip(); 00336 last_command_ = cmd; 00337 } 00338 00339 const int kNumSensors_; // number of sensors in daisy chain 00340 DigitalOut chip_; // chip select port 00341 SPI spi_; // mbed spi communiation object 00342 00343 uint16_t* read_buffer_; // buffer for results from last transfer 00344 uint16_t* angle_buffer_; // buffer for angle results from last transfer 00345 uint16_t* angle_offset_; // offset array for each sensor 00346 bool* directions_; // direction true positive, false negative 00347 00348 As5048Command last_command_;// command sent during last Transfer 00349 00350 }; 00351 #endif
Generated on Wed Jul 20 2022 05:36:22 by
1.7.2