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.
TLE5012B.h
- Committer:
- hudakz
- Date:
- 2020-09-19
- Revision:
- 0:4b76b1dc05cd
File content as of revision 0:4b76b1dc05cd:
/*!
* \name TLE5012B.h - Mbed port of Arduino library for the TLE5012B angle sensor.
* \author Infineon Technologies AG (Dr.Olaf Filies)
* \copyright 2019 Infineon Technologies AG
* \version 2.0.1
* \brief GMR-based angle sensor for angular position sensing in automotive applications
* \details Ported to Mbed by Zoltan Hudak 2020-08
*
* The TLE5012B is a 360° angle sensor that detects the orientation of a magnetic field.
* This is achieved by measuring sine and cosine angle components with monolithic integrated
* Giant Magneto Resistance (iGMR) elements. These raw signals (sine and cosine) are digitally
* processed internally to calculate the angle orientation of the magnetic field (magnet).
* The TLE5012B is a pre-calibrated sensor. The calibration parameters are stored in laser fuses.
* At start-up the values of the fuses are written into flip-flops, where these values can be changed
* by the application-specific parameters. Further precision of the angle measurement over a wide
* temperature range and a long lifetime can be improved by enabling an optional internal autocalibration
* algorithm. Data communications are accomplished with a bi-directional Synchronous Serial Communication (SSC)
* that is SPI-compatible. The sensor configuration is stored in registers, which are accessible by the
* SSC interface. Additionally four other interfaces are available with the TLE5012B: Pulse-Width-Modulation (PWM)
* Protocol, Short-PWM-Code (SPC) Protocol, Hall Switch Mode (HSM) and Incremental Interface (IIF). These interfaces
* can be used in parallel with SSC or alone. Pre-configured sensor derivates with different interface settings are available.
* Online diagnostic functions are provided to ensure reliable operation.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following
* disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided with the distribution.
*
* Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY,OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef TLE5012B_H
#define TLE5012B_H
#include "TLE5012B_SPI.h"
namespace TLE5012 {
// Sensor registers
#define READ_SENSOR 0x8000 //!< base command for read
#define WRITE_SENSOR 0x5000 //!< base command for write
#define READ_BLOCK_CRC 0x8088 //!< initialize block CRC check command
#define REG_STAT 0x0000 //!< STAT status register
#define REG_ACSTAT 0x0010 //!< ACSTAT activation status register
#define REG_AVAL 0x0020 //!< AVAL angle value register
#define REG_ASPD 0x0030 //!< ASPD angle speed register
#define REG_AREV 0x0040 //!< AREV angle revolution register
#define REG_FSYNC 0x0050 //!< FSYNC frame synchronization register
#define REG_MOD_1 0x0060 //!< MOD_1 interface mode1 register
#define REG_SIL 0x0070 //!< SIL register
#define REG_MOD_2 0x0080 //!< MOD_2 interface mode2 register
#define REG_MOD_3 0x0090 //!< MOD_3 interface mode3 register
#define REG_OFFX 0x00A0 //!< OFFX offset x
#define REG_OFFY 0x00B0 //!< OFFY offset y
#define REG_SYNCH 0x00C0 //!< SYNCH synchronicity
#define REG_IFAB 0x00D0 //!< IFAB register
#define REG_MOD_4 0x00E0 //!< MOD_4 interface mode4 register
#define REG_TCO_Y 0x00F0 //!< TCO_Y temperature coefficient register
#define REG_ADC_X 0x0100 //!< ADC_X ADC X-raw value
#define REG_ADC_Y 0x0110 //!< ADC_Y ADC Y-raw value
#define REG_D_MAG 0x0140 //!< D_MAG angle vector magnitude
#define REG_T_RAW 0x0150 //!< T_RAW temperature sensor raw-value
#define REG_IIF_CNT 0x0200 //!< IIF_CNT IIF counter value
#define REG_T25O 0x0300 //!< T25O temperature 25°c offset value
#define SYSTEM_ERROR_MASK 0x4000 //!< System error masks for safety words
#define INTERFACE_ERROR_MASK 0x2000 //!< Interface error masks for safety words
#define INV_ANGLE_ERROR_MASK 0x1000 //!< Angle error masks for safety words
#define CRC_POLYNOMIAL 0x1D //!< values used for calculating the CRC
#define CRC_SEED 0xFF
#define CRC_NUM_REGISTERS 0x0008 //!< number of CRC relevant registers
#define MAX_REGISTER_MEM 0x0030 //!< max readable register values buffer
#define DELETE_BIT_15 0x7FFF //!< Value used to delete everything except the first 15 bits
#define CHANGE_UINT_TO_INT_15 0x8000 //!< Value used to change unsigned 16bit integer into signed
#define CHECK_BIT_14 0x4000 //!<
#define GET_BIT_14_4 0x7FF0 //!<
#define DELETE_7BITS 0x01FF //!< values used to calculate 9 bit signed integer sent by the sensor
#define CHANGE_UNIT_TO_INT_9 0x0200 //!< Value used to change unsigned 9bit integer into signed
#define CHECK_BIT_9 0x0100
#define POW_2_15 32768.0 //!< values used to for final calculations of angle speed, revolutions, range and value
#define POW_2_7 128.0 //!<
#define ANGLE_360_VAL 360.0
#define TEMP_OFFSET 152.0 //!< values used to calculate the temperature
#define TEMP_DIV 2.776
//!< Prints a binary number with leading zeros (Automatic Handling)
#define PRINTBIN(Num) for (uint32_t t = (1UL<< (sizeof(Num)*8)-1); t; t >>= 1) Serial.write(Num & t ? '1' : '0');
//!< Prints a binary number with leading zeros (Automatic Handling) with space
#define PRINTBINS(Num) for (uint32_t t = (1UL<< (sizeof(Num)*8)-1); t; t >>= 1) Serial.write(Num & t ? " 1 " : " 0 ");
/*!
* Error types from safety word
*/
enum errorTypes
{
NO_ERROR = 0x00, //!< NO_ERROR = Safety word was OK
SYSTEM_ERROR = 0x01, //!< SYSTEM_ERROR = over/under voltage, VDD negative, GND off, ROM defect
INTERFACE_ACCESS_ERROR = 0x02, //!< INTERFACE_ACCESS_ERROR = wrong address or wrong lock
INVALID_ANGLE_ERROR = 0x03, //!< INVALID_ANGLE_ERROR = NO_GMR_A = 1 or NO_GMR_XY = 1
ANGLE_SPEED_ERROR = 0x04, //!< ANGLE_SPEED_ERROR = combined error, angular speed calculation wrong
CRC_ERROR = 0xFF //!< CRC_ERROR = Cyclic Redundancy Check (CRC), which includes the STAT and RESP bits wrong
};
/*!
* Set the UPDate bit high (read from update buffer) or low (read directly)
*/
enum updTypes
{
UPD_LOW = 0x0000, //!< read normal registers
UPD_HIGH = 0x0400, //!< read update buffer registers
};
/*!
* Switch on/off safety word generation
*/
enum safetyTypes
{
SAFE_LOW = 0x0000, //!< switch of safety word generation
SAFE_HIGH = 0x0001, //!< switch on safety word generation
};
/*!
* Offset for the slave number register to identify the
* right selected slave. Max 4 slaves with separated CSQ
* lines are possible. If more than one sensor is used on the SPI
* interface, than the SNR register must we written with the correct slave number
*/
enum slaveNum
{
TLE5012B_S0 = 0x0000, //!< TLE5012B_S0 default setting for only one sensor on the SPI
TLE5012B_S1 = 0x2000, //!< TLE5012B_S1 second sensor needs also a second CSQ
TLE5012B_S2 = 0x4000, //!< TLE5012B_S2 third sensor and dito
TLE5012B_S3 = 0x6000 //!< TLE5012B_S3 fourth sensor and dito
};
typedef struct safetyWord {//!< Safety word bit setting
bool STAT_RES; //!< bits 15:15 Indication of chip reset or watchdog overflow
bool STAT_ERR; //!< bits 14:14 System error
bool STAT_ACC; //!< bits 13:13 Interface access error
bool STAT_ANG; //!< bits 12:12 Invalid angle value
uint8_t RESP; //!< bits 11:8 Sensor number response indicator
uint8_t CRC_ADC; //!< bits 7:0 Status ADC Test
/*!
* Returns the safety word slave number to identify the sensor
* @return slaveNum setting in safety word
*/
slaveNum responseSlave(){
return (RESP == 0x7 ? TLE5012B_S3
: (RESP == 0xB ? TLE5012B_S2
: (RESP == 0xD ? TLE5012B_S1
: TLE5012B_S0)));
}
/*!
* Function separates safety word bits
* @param [in,out] reg actual safety or last fetched as default
* @return safety word
*/
uint16_t fetch_Safety(uint16_t reg)
{
CRC_ADC = (reg & 0x7F);
RESP = (reg & 0xF00) >> 8;
STAT_ANG = (reg & 0x1000) >> 12;
STAT_ACC = (reg & 0x2000) >> 13;
STAT_ERR = (reg & 0x4000) >> 14;
STAT_RES = (reg & 0x8000) >> 15;
return (reg);
}
} safetyWord_t;
/*!
* Class TLE5012B
*/
class TLE5012B
{
public:
TLE5012B(TLE5012B_SPI* spi, PinName cs) : _spiConnection(spi), _cs(cs), _slave(TLE5012B_S0) { }
~TLE5012B() {}
/**
* All these functions cover the SPI interface and should be implemented
* into XMC SPI wrapper.
* In 3wire SPI mode miso and mosi are connected together, so read and
* write operations are on the same line. In 4wire more read and write are
* separated. The system clock SCK and the sensor enable EN line are used
* for all slaves whereas the chip select line CS must we set unique for
* each slave. A max of four slaves on one SPI interface are possible
* @return CRC error type
* @param [in] slave slave offset setting for the SNR register, default is TLE5012B_S0
*/
errorTypes begin(slaveNum slave);
/*!
* Triggers an update in the register buffer. This function
* should be triggered once before UPD registers where read as
* it generates a snapshot of the UPD register values at trigger point
*/
void triggerUpdate();
/*!
* Reads the block of _registers from addresses 08 - 0F in order to figure out the CRC.
* ATTENTION: You need a memory chunk of unit16_t * CRC Registers + 1 * uint16_t for the safety word.
* @return CRC error type
*/
errorTypes readBlockCRC();
/*!
* General read function for reading _registers from the Tle5012b.
*
* structure of command word, the numbers represent the bit position of the 2 byte command
* 15 - 0 write, 1 read
* 14:11 - 0000 for default operational access for addresses between 0x00 - 0x04, 1010 for configuration access for addresses between 0x05 - 0x11
* 10 - 0 access to current value, 1 access to value in update buffer
* 9:4 - access to 6 bit register address
* 3:0 - 4 bit number of data words.
*
* @param [in] command the command for reading
* @param [out] data where the data received from the _registers will be stored
* @param [in] upd read from update (UPD_high) register or directly (default, UPD_low)
* @param [in] safe generate safety word (default, SAFE_high) or not (SAFE_low)
* @return CRC error type
*/
errorTypes readFromSensor(uint16_t command, uint16_t &data, updTypes upd=UPD_LOW, safetyTypes safe=SAFE_HIGH);
/*!
* Can be used to read 1 or more consecutive _registers, and the values
* used to read 1 or more than 1 consecutive _registers.
* The maximum amount of registers are limited by the bit 3-0 of the command word, which means
* you can read max 15 registers and one safety word at once.
* @param [in] command the command for reading
* @param [out] data where the data received from the _registers will be stored
* @param [in] upd read from update (UPD_high) register or directly (default, UPD_low)
* @param [in] safe generate safety word (default, SAFE_high) or no (SAFE_low)
* @return CRC error type
*/
errorTypes readMoreRegisters(uint16_t command, uint16_t data[], updTypes upd=UPD_LOW, safetyTypes safe=SAFE_HIGH);
/*!
* This functions reads the main status word for the sensor,
* mainly for checking with the additional safety word
* @param [out] data pointer with the received data word
* @param [in] upd read from update (UPD_high) register or directly (default, UPD_low)
* @param [in] safe generate safety word (default, SAFE_high) or no (SAFE_low)
* @return CRC error type
*/
errorTypes readStatus(uint16_t &data, updTypes upd=UPD_LOW, safetyTypes safe=SAFE_HIGH);
/*!
* This functions reads activation status word for the sensor,
* which held on/off information for all optional checks and additional functions
* @param [out] data pointer with the received data word
* @param [in] upd read from update (UPD_high) register or directly (default, UPD_low)
* @param [in] safe generate safety word (default, SAFE_high) or no (SAFE_low)
* @return CRC error type
*/
errorTypes readActivationStatus(uint16_t &data, updTypes upd=UPD_LOW, safetyTypes safe=SAFE_HIGH);
/*!
* The next functions are used primarily for storing the parameters and
* control of how the sensor works. The values stored in them are used to calculate
* the CRC, and their values are stored in the private component of the class, _registers.
* @param [out] data where the data received from the _registers will be stored
* @return CRC error type
*/
errorTypes readActiveStatus(uint16_t &data); //!< read register offset 0x01
errorTypes readIntMode1(uint16_t &data); //!< read register offset 0x06
errorTypes readSIL(uint16_t &data); //!< read register offset 0x07
errorTypes readIntMode2(uint16_t &data); //!< read register offset 0x08
errorTypes readIntMode3(uint16_t &data); //!< read register offset 0x09
errorTypes readOffsetX(uint16_t &data); //!< read register offset 0x0A
errorTypes readOffsetY(uint16_t &data); //!< read register offset 0x0B
errorTypes readSynch(uint16_t &data); //!< read register offset 0x0C
errorTypes readIFAB(uint16_t &data); //!< read register offset 0x0D
errorTypes readIntMode4(uint16_t &data); //!< read register offset 0x0E
errorTypes readTempCoeff(uint16_t &data); //!< read register offset 0x0F
errorTypes readTempDMag(uint16_t &data); //!< read register offset 0x14
errorTypes readTempRaw(uint16_t &data); //!< read register offset 0x15
errorTypes readTempIIFCnt(uint16_t &data); //!< read register offset 0x20
errorTypes readTempT25(uint16_t &data); //!< read register offset 0x30
/*!
* The rawX value is signed 16 bit value
* @param data pointer to 16bit word
* @return CRC error type
*/
errorTypes readRawX(int16_t &data);
/*!
* The rawY value is signed 16 bit value
* @param data pointer to 16bit word
* @return CRC error type
*/
errorTypes readRawY(int16_t &data);
/*!
* returns the Angle Range
* Angle Range is stored in bytes 14 - 4 of MOD_2.
* @param angleRange pointer to 16bit double value
* @return CRC error type
*/
errorTypes getAngleRange(double &angleRange);
/*!
* Returns the angleValue calculated on the base of a 15 bit signed integer.
* However, the register returns 16 bits, so we need to do some bit arithmetic.
* @param [in,out] angleValue pointer to 16bit double angle value
* @return CRC error type
*/
errorTypes getAngleValue(double &angleValue);
/*!
* Same function as before but also returns a pointer to the raw data
* @param [in,out] angleValue pointer to 16bit double angle value
* @param [in,out] rawAnglevalue point to an int16_t raw data value
* @param [in] upd read from update (UPD_high) register or directly (default, UPD_low)
* @param [in] safe generate safety word (default, SAFE_high) or no (SAFE_low)
* @return CRC error type
*/
errorTypes getAngleValue(double &angleValue, int16_t &rawAnglevalue, updTypes upd=UPD_LOW, safetyTypes safe=SAFE_HIGH);
/*!
* Returns the number of revolutions done from the angle value which is a 9 bit signed integer.
* However, the register returns 16 bits, so we need to do some bit arithmetic.
* Therefore the resulting revolution can b only between -256 < numRev < 256 and
* it will switch from positive to negative and vice versa values at the borders.
* @param [in,out] numRev pointer to 16bit word for the number of revolutions
* @param [in] upd read from update (UPD_high) register or directly (default, UPD_low)
* @param [in] safe generate safety word (default, SAFE_high) or no (SAFE_low)
* @return CRC error type
*/
errorTypes getNumRevolutions(int16_t &numRev, updTypes upd=UPD_LOW, safetyTypes safe=SAFE_HIGH);
/*!
* Return the temperature.
* The temperature value is a 9 bit signed integer.
* However, the register returns 16 bits, so we need to do some bit arithmetic.
* @param [in,out] temp pointer to 16bit double value of the temperature
* @return CRC error type
*/
errorTypes getTemperature(double &temp);
/*!
* Same as above but also returns a pointer to the raw data
* @param [in,out] temp pointer to 16bit double value of the temperature
* @param [in,out] rawTemp pointer to int16_t raw value data
* @param [in] upd read from update (UPD_high) register or directly (default, UPD_low)
* @param [in] safe generate safety word (default, SAFE_high) or no (SAFE_low)
* @return CRC error type
*/
errorTypes getTemperature(double &temp, int16_t &rawTemp, updTypes upd=UPD_LOW, safetyTypes safe=SAFE_HIGH);
/*!
* Returns the calculated angle speed.
* The angle speed is a 15 bit signed integer,
* however, the register returns 16 bits, so we need to do some bit arithmetic.
* @param [in,out] angleSpeed pointer to 16bit double value
* @return CRC error type
*/
errorTypes getAngleSpeed(double &angleSpeed);
/*!
* Same as above but also returns a pointer to the raw data
* @param [in,out] angleSpeed angleSpeed pointer to 16bit double value
* @param [in,out] rawSpeed pointer to int16_t raw value data
* @param [in] upd read from update (UPD_high) register or directly (default, UPD_low)
* @param [in] safe generate safety word (default, SAFE_high) or no (SAFE_low)
* @return CRC error type
*/
errorTypes getAngleSpeed(double &angleSpeed,int16_t &rawSpeed, updTypes upd=UPD_LOW, safetyTypes safe=SAFE_HIGH);
/*!
* Function sets the SNR register with the correct slave number
* @param [in] dataToWrite the new data that will be written to the register
* @return CRC error type
*/
errorTypes writeSlaveNumber(uint16_t dataToWrite);
/*!
* General write function for writing registers to the Tle5012b. The safety flag will be
* set always and only some of all registers are writable. See documentation for further information.
* @param [in] command the command to execute the write
* @param [in] dataToWrite the new data that will be written to the register
* @param [in] changeCRC the registerIndex helps figure out in which register the value changed,
* so that we don't need to read all the register again to calculate the CRC
* @return CRC error type
*/
errorTypes writeToSensor(uint16_t command, uint16_t dataToWrite, bool changeCRC);
/*!
* This function is used in order to update the CRC in the register 0F(second byte)
* @param [in] dataToWrite the new data that will be written to the register
* @return CRC error type
*/
errorTypes writeTempCoeffUpdate(uint16_t dataToWrite);
/*!
* Standard function used for updating the CRC
* @param [in] dataToWrite the new data that will be written to the register
* @return CRC error type
*/
errorTypes writeActivationStatus(uint16_t dataToWrite); //!< write register offset 0x01
errorTypes writeIntMode1(uint16_t dataToWrite); //!< write register offset 0x06
errorTypes writeSIL(uint16_t dataToWrite); //!< write register offset 0x07
errorTypes writeIntMode2(uint16_t dataToWrite); //!< write register offset 0x08
errorTypes writeIntMode3(uint16_t dataToWrite); //!< write register offset 0x09
errorTypes writeOffsetX(uint16_t dataToWrite); //!< write register offset 0x0A
errorTypes writeOffsetY(uint16_t dataToWrite); //!< write register offset 0x0B
errorTypes writeSynch(uint16_t dataToWrite); //!< write register offset 0x0C
errorTypes writeIFAB(uint16_t dataToWrite); //!< write register offset 0x0D
errorTypes writeIntMode4(uint16_t dataToWrite); //!< write register offset 0x0E
errorTypes writeTempCoeff(uint16_t dataToWrite); //!< write register offset 0x0F
private:
TLE5012B_SPI* _spiConnection;
DigitalOut _cs;
slaveNum _slave; //!< actual set slave number
safetyWord_t _safetyStatus; //!< actual safety status
uint16_t _safetyWord; //!< the last fetched safety word
uint16_t _command[2]; //!< command write data [0] = command, [1] = data to write
uint16_t _received[MAX_REGISTER_MEM]; //!< fetched data from sensor with last word = safety word
uint16_t _registers[CRC_NUM_REGISTERS]; //!< keeps track of the values stored in the 8 _registers, for which the CRC is calculated
/*!
* This function is called each time any register in the
* range 08 - 0F(first byte) is changed. It calculates the new CRC
* based on the value of all the _registers and then
* stores the value in 0F(second byte)
* @return CRC error type
*/
errorTypes regularCrcUpdate();
/*!
* checks the safety by looking at the safety word and calculating
* the CRC such that the data received is valid
* @param safety register with the CRC check data
* @param command the command to execute the write
* @param readreg pointer to the read data
* @param length the length of the data structure
* @return CRC error type
*/
errorTypes checkSafety(uint16_t safety, uint16_t command, uint16_t* readreg, uint16_t length);
/*!
* When an error occurs in the safety word, the error bit remains 0(error),
* until the status register is read again. Flushes out safety errors,
* that might have occurred by reading the register without a safety word.
* In case the safety word sends an error, this function is
* called so that the error bit is reset to 1.
*/
void resetSafety();
};
} // TLE5012 namespace
#endif