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.cpp
- 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 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. * */ #include "TLE5012B.h" //----------------------------------------------------------------------------- using namespace TLE5012; // none_class functions /*! * Gets the first byte of a 2 byte word * @param twoByteWord insert word of two bytes long * @return returns the first byte */ uint8_t getFirstByte(uint16_t twoByteWord) { return((uint8_t) (twoByteWord >> 8)); } /*! * Gets the second byte of the 2 byte word * @param twoByteWord insert word of two bytes long * @return returns the second byte */ uint8_t getSecondByte(uint16_t twoByteWord) { return((uint8_t) twoByteWord); } /*! * Function for calculation the CRC. * @param data byte long data for CRC check * @param length length of data * @return returns 8bit CRC */ uint8_t crc8(uint8_t* data, uint8_t length) { uint32_t crc; int16_t i, bit; crc = CRC_SEED; for (i = 0; i < length; i++) { crc ^= data[i]; for (bit = 0; bit < 8; bit++) { if ((crc & 0x80) != 0) { crc <<= 1; crc ^= CRC_POLYNOMIAL; } else { crc <<= 1; } } } return((~crc) & CRC_SEED); } /*! * Function for calculation of the CRC * @param crcData byte long data for CRC check * @param length length of data * @return runs crc8 calculation and returns CRC */ uint8_t crcCalc(uint8_t* crcData, uint8_t length) { return(crc8(crcData, length)); } /*! * Calculate the angle speed * @param angRange set angular range value * @param rawAngleSpeed raw speed value from read function * @param firMD * @param predictionVal * @return calculated angular speed */ double calculateAngleSpeed(double angRange, int16_t rawAngleSpeed, uint16_t firMD, uint16_t predictionVal) { double finalAngleSpeed; double microsecToSec = 0.000001; double firMDVal; if (firMD == 1) { firMDVal = 42.7; } else if (firMD == 0) { firMDVal = 21.3; } else if (firMD == 2) { firMDVal = 85.3; } else if (firMD == 3) { firMDVal = 170.6; } else { firMDVal = 0; } finalAngleSpeed = ((angRange / POW_2_15) * ((double)rawAngleSpeed)) / (((double)predictionVal) * firMDVal * microsecToSec); return(finalAngleSpeed); } // end none class functions //----------------------------------------------------------------------------- errorTypes TLE5012B::begin(slaveNum slave) { _spiConnection->begin(&_cs); _slave = slave; writeSlaveNumber(_slave); return(readBlockCRC()); } /** * @brief * @note * @param * @retval */ void TLE5012B::triggerUpdate() { _spiConnection->triggerUpdate(); _cs = 0; wait_us(5); //grace period for register snapshot _cs = 1; } //----------------------------------------------------------------------------- // begin generic data transfer functions errorTypes TLE5012B::readFromSensor(uint16_t command, uint16_t& data, updTypes upd, safetyTypes safe) { errorTypes checkError = NO_ERROR; _command[0] = READ_SENSOR | command | upd | safe; uint16_t _received[MAX_REGISTER_MEM] = { 0 }; _spiConnection->sendReceiveSpi(&_cs, _command, 1, _received, 2); data = _received[0]; if (safe == SAFE_HIGH) { checkError = checkSafety(_received[1], _command[0], &_received[0], 1); if (checkError != NO_ERROR) { data = 0; } } return(checkError); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::readMoreRegisters(uint16_t command, uint16_t data[], updTypes upd, safetyTypes safe) { errorTypes checkError = NO_ERROR; _command[0] = READ_SENSOR | command | upd | safe; uint16_t _received[MAX_REGISTER_MEM] = { 0 }; uint16_t _recDataLength = (_command[0] & (0x000F)); // Number of registers to read _spiConnection->sendReceiveSpi(&_cs, _command, 1, _received, _recDataLength + safe); memcpy(data, _received, (_recDataLength) * sizeof(uint16_t)); if (safe == SAFE_HIGH) { checkError = checkSafety(_received[_recDataLength], _command[0], _received, _recDataLength); if (checkError != NO_ERROR) { data = 0; } } return(checkError); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::writeToSensor(uint16_t command, uint16_t dataToWrite, bool changeCRC) { uint16_t safety = 0; _command[0] = WRITE_SENSOR | command | SAFE_HIGH; _command[1] = dataToWrite; _spiConnection->sendReceiveSpi(&_cs, _command, 2, &safety, 1); errorTypes checkError = checkSafety(safety, _command[0], &_command[1], 1); //if we write to a register, which changes the CRC. if (changeCRC) { //Serial.println("h45"); checkError = regularCrcUpdate(); } return(checkError); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::writeTempCoeffUpdate(uint16_t dataToWrite) { uint16_t safety = 0; uint16_t readreg = 0; triggerUpdate(); _command[0] = WRITE_SENSOR | REG_TCO_Y | SAFE_HIGH; _command[1] = dataToWrite; _spiConnection->sendReceiveSpi(&_cs, _command, 2, &safety, 1); errorTypes checkError = checkSafety(safety, _command[0], &_command[1], 1); // checkError = readStatus(readreg); if (readreg & 0x0008) { checkError = regularCrcUpdate(); } return(checkError); } // end generic data transfer functions //----------------------------------------------------------------------------- // begin CRC functions errorTypes TLE5012B::checkSafety(uint16_t safety, uint16_t command, uint16_t* readreg, uint16_t length) { volatile errorTypes errorCheck = NO_ERROR; _safetyWord = safety; if (!(_safetyWord & SYSTEM_ERROR_MASK)) { errorCheck = SYSTEM_ERROR; //resetSafety(); } else if (!(_safetyWord & INTERFACE_ERROR_MASK)) { errorCheck = INTERFACE_ACCESS_ERROR; //resetSafety(); } else if (!(_safetyWord & INV_ANGLE_ERROR_MASK)) { errorCheck = INVALID_ANGLE_ERROR; //resetSafety(); } else { //resetSafety(); uint16_t lengthOfTemp = length * 2 + 2; uint8_t* temp = new uint8_t[lengthOfTemp]; temp[0] = getFirstByte(command); temp[1] = getSecondByte(command); for (uint16_t i = 0; i < length; i++) { temp[2 + 2 * i] = getFirstByte(readreg[i]); temp[2 + 2 * i + 1] = getSecondByte(readreg[i]); } uint8_t crcReceivedFinal = getSecondByte(safety); uint8_t crc = crcCalc(temp, lengthOfTemp); if (crc == crcReceivedFinal) { errorCheck = NO_ERROR; } else { errorCheck = CRC_ERROR; resetSafety(); } delete[] temp; } return(errorCheck); } /** * @brief * @note * @param * @retval */ void TLE5012B::resetSafety() { uint16_t command = READ_SENSOR + SAFE_HIGH; uint16_t receive[4]; triggerUpdate(); _spiConnection->sendReceiveSpi(&_cs, &command, 1, receive, 3); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::regularCrcUpdate() { readBlockCRC(); uint8_t temp[16]; for (uint8_t i = 0; i < CRC_NUM_REGISTERS; i++) { temp[2 * i] = getFirstByte(_registers[i]); temp[(2 * i) + 1] = getSecondByte(_registers[i]); } uint8_t crc = crcCalc(temp, 15); uint16_t firstTempByte = (uint16_t) temp[14]; uint16_t secondTempByte = (uint16_t) crc; uint16_t valToSend = (firstTempByte << 8) | secondTempByte; _registers[7] = valToSend; return(writeTempCoeffUpdate(valToSend)); } // end CRC functions //----------------------------------------------------------------------------- // begin read functions errorTypes TLE5012B::readBlockCRC() { _command[0] = READ_BLOCK_CRC; uint16_t _registers[CRC_NUM_REGISTERS + 1] = { 0 }; // Number of CRC Registers + 1 Register for Safety word //memset(_registers, 0, sizeof(_registers)); _spiConnection->sendReceiveSpi(&_cs, _command, 1, _registers, CRC_NUM_REGISTERS + 1); errorTypes checkError = checkSafety(_registers[8], READ_BLOCK_CRC, _registers, 8); resetSafety(); return(checkError); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::readStatus(uint16_t& data, updTypes upd, safetyTypes safe) { return(readFromSensor(REG_STAT, data, UPD_LOW, SAFE_HIGH)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::readActivationStatus(uint16_t& data, updTypes upd, safetyTypes safe) { return(readFromSensor(REG_ACSTAT, data, upd, safe)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::readSIL(uint16_t& data) { return(readFromSensor(REG_SIL, data, UPD_LOW, SAFE_HIGH)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::readIntMode1(uint16_t& data) { return(readFromSensor(REG_MOD_1, data, UPD_LOW, SAFE_HIGH)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::readIntMode2(uint16_t& data) { return(readFromSensor(REG_MOD_2, data, UPD_LOW, SAFE_HIGH)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::readIntMode3(uint16_t& data) { return(readFromSensor(REG_MOD_3, data, UPD_LOW, SAFE_HIGH)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::readIntMode4(uint16_t& data) { return(readFromSensor(REG_MOD_4, data, UPD_LOW, SAFE_HIGH)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::readOffsetX(uint16_t& data) { return(readFromSensor(REG_OFFX, data, UPD_LOW, SAFE_HIGH)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::readOffsetY(uint16_t& data) { return(readFromSensor(REG_OFFY, data, UPD_LOW, SAFE_HIGH)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::readSynch(uint16_t& data) { return(readFromSensor(REG_SYNCH, data, UPD_LOW, SAFE_HIGH)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::readIFAB(uint16_t& data) { return(readFromSensor(REG_IFAB, data, UPD_LOW, SAFE_HIGH)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::readTempCoeff(uint16_t& data) { return(readFromSensor(REG_TCO_Y, data, UPD_LOW, SAFE_HIGH)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::readTempDMag(uint16_t& data) { return(readFromSensor(REG_D_MAG, data, UPD_LOW, SAFE_HIGH)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::readTempIIFCnt(uint16_t& data) { return(readFromSensor(REG_IIF_CNT, data, UPD_LOW, SAFE_HIGH)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::readTempRaw(uint16_t& data) { return(readFromSensor(REG_T_RAW, data, UPD_LOW, SAFE_HIGH)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::readTempT25(uint16_t& data) { return(readFromSensor(REG_T25O, data, UPD_LOW, SAFE_HIGH)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::readRawX(int16_t& data) { uint16_t rawData = 0; errorTypes status = readFromSensor(REG_ADC_X, rawData); if (status != NO_ERROR) { return(status); } data = rawData; return(status); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::readRawY(int16_t& data) { uint16_t rawData = 0; errorTypes status = readFromSensor(REG_ADC_Y, rawData); if (status != NO_ERROR) { return(status); } data = rawData; return(status); } // end read functions //----------------------------------------------------------------------------- // begin get functions errorTypes TLE5012B::getAngleValue(double& angleValue) { int16_t rawAnglevalue = 0; return(getAngleValue(angleValue, rawAnglevalue, UPD_LOW, SAFE_HIGH)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::getAngleValue(double& angleValue, int16_t& rawAnglevalue, updTypes upd, safetyTypes safe) { uint16_t rawData = 0; errorTypes status = readFromSensor(REG_AVAL, rawData, upd, safe); if (status != NO_ERROR) { return(status); } rawData = (rawData & (DELETE_BIT_15)); //check if the value received is positive or negative if (rawData & CHECK_BIT_14) { rawData = rawData - CHANGE_UINT_TO_INT_15; } rawAnglevalue = rawData; angleValue = (ANGLE_360_VAL / POW_2_15) * ((double)rawAnglevalue); return(status); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::getTemperature(double& temperature) { int16_t rawTemp = 0; return(getTemperature(temperature, rawTemp, UPD_LOW, SAFE_HIGH)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::getTemperature(double& temperature, int16_t& rawTemp, updTypes upd, safetyTypes safe) { uint16_t rawData = 0; errorTypes status = readFromSensor(REG_FSYNC, rawData, upd, safe); if (status != NO_ERROR) { return(status); } rawData = (rawData & (DELETE_7BITS)); //check if the value received is positive or negative if (rawData & CHECK_BIT_9) { rawData = rawData - CHANGE_UNIT_TO_INT_9; } rawTemp = rawData; temperature = (rawTemp + TEMP_OFFSET) / (TEMP_DIV); return(status); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::getNumRevolutions(int16_t& numRev, updTypes upd, safetyTypes safe) { uint16_t rawData = 0; errorTypes status = readFromSensor(REG_AREV, rawData, upd, safe); if (status != NO_ERROR) { return(status); } rawData = (rawData & (DELETE_7BITS)); // //check if the value received is positive or negative if (rawData & CHECK_BIT_9) { rawData = rawData - CHANGE_UNIT_TO_INT_9; } numRev = rawData; return(status); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::getAngleSpeed(double& finalAngleSpeed) { int16_t rawSpeed = 0; return(getAngleSpeed(finalAngleSpeed, rawSpeed, UPD_LOW, SAFE_HIGH)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::getAngleSpeed(double& finalAngleSpeed, int16_t& rawSpeed, updTypes upd, safetyTypes safe) { int8_t numOfData = 0x5; uint16_t* rawData = new uint16_t[numOfData]; errorTypes status = readMoreRegisters(REG_ASPD + numOfData, rawData, upd, safe); if (status != NO_ERROR) { return(status); } // Prepare raw speed rawSpeed = rawData[0]; rawSpeed = (rawSpeed & (DELETE_BIT_15)); //check if the value received is positive or negative if (rawSpeed & CHECK_BIT_14) { rawSpeed = rawSpeed - CHANGE_UINT_TO_INT_15; } // Prepare firMDVal uint16_t firMDVal = rawData[3]; firMDVal >>= 14; // Prepare intMode2Prediction uint16_t intMode2Prediction = rawData[5]; if (intMode2Prediction & 0x0004) { intMode2Prediction = 3; } else { intMode2Prediction = 2; } // Prepare angle range uint16_t rawAngleRange = rawData[5]; rawAngleRange &= GET_BIT_14_4; rawAngleRange >>= 4; double angleRange = ANGLE_360_VAL * (POW_2_7 / (double)(rawAngleRange)); //checks the value of fir_MD according to which the value in the calculation of the speed will be determined //according to if prediction is enabled then, the formula for speed changes finalAngleSpeed = calculateAngleSpeed(angleRange, rawSpeed, firMDVal, intMode2Prediction); delete[] rawData; return(status); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::getAngleRange(double& angleRange) { uint16_t rawData = 0; errorTypes status = readIntMode2(rawData); if (status != NO_ERROR) { return(status); } //Angle Range is stored in bytes 14 - 4, so you have to do this bit shifting to get the right value rawData &= GET_BIT_14_4; rawData >>= 4; angleRange = ANGLE_360_VAL * (POW_2_7 / (double)(rawData)); return(status); } // end get functions //----------------------------------------------------------------------------- // begin write functions errorTypes TLE5012B::writeIntMode2(uint16_t dataToWrite) { return(writeToSensor(REG_MOD_2, dataToWrite, true)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::writeIntMode3(uint16_t dataToWrite) { return(writeToSensor(REG_MOD_3, dataToWrite, true)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::writeOffsetX(uint16_t dataToWrite) { return(writeToSensor(REG_OFFX, dataToWrite, true)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::writeOffsetY(uint16_t dataToWrite) { return(writeToSensor(REG_OFFY, dataToWrite, true)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::writeSynch(uint16_t dataToWrite) { return(writeToSensor(REG_SYNCH, dataToWrite, true)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::writeIFAB(uint16_t dataToWrite) { return(writeToSensor(REG_IFAB, dataToWrite, true)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::writeIntMode4(uint16_t dataToWrite) { return(writeToSensor(REG_MOD_4, dataToWrite, true)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::writeTempCoeff(uint16_t dataToWrite) { return(writeToSensor(REG_TCO_Y, dataToWrite, true)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::writeActivationStatus(uint16_t dataToWrite) { return(writeToSensor(REG_ACSTAT, dataToWrite, false)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::writeIntMode1(uint16_t dataToWrite) { return(writeToSensor(REG_MOD_1, dataToWrite, false)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::writeSIL(uint16_t dataToWrite) { return(writeToSensor(REG_SIL, dataToWrite, false)); } /** * @brief * @note * @param * @retval */ errorTypes TLE5012B::writeSlaveNumber(uint16_t dataToWrite) { return(writeToSensor(WRITE_SENSOR, dataToWrite, false)); } // end write functions