├── keywords.txt ├── library.properties ├── examples ├── GetConfiguration │ └── GetConfiguration.ino ├── SetHwAddress │ └── SetHwAddress.ino ├── GetRPM │ └── GetRPM.ino └── SetConfiguration │ └── SetConfiguration.ino ├── LICENSE ├── README.md └── src ├── AM4096.h └── AM4096.cpp /keywords.txt: -------------------------------------------------------------------------------- 1 | # Keywords for AM4096 Encoder Arduino Library 2 | 3 | AM4096 KEYWORD1 4 | AM4096.h INCLUDE 5 | 6 | # Methods 7 | init KEYWORD2 8 | getDeviceId KEYWORD2 9 | findAM4096Device KEYWORD2 10 | setNewHwAddr KEYWORD2 11 | getConfiguration KEYWORD2 12 | updateConfiguration KEYWORD2 13 | readOutputDataRegisters KEYWORD2 14 | printAM4096Configuration KEYWORD2 15 | printAM4096OutputData KEYWORD2 16 | readReg KEYWORD2 17 | writeReg KEYWORD2 18 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=AM4096 2 | version=1.0.0 3 | author=Yasir Shahzad 4 | maintainer=Yasir Shahzad 5 | sentence=An Arduino library for interfacing with the AM4096 rotary magnetic encoder. 6 | paragraph=This library provides an interface for communicating with the AM4096 rotary magnetic encoder using the I2C protocol. The library enables easy access to the encoder's configuration and output data. It is useful for projects that require precise rotary position sensing. 7 | category=Sensors 8 | url=https://github.com/yasir-shahzad/AM4096 9 | architectures=* 10 | includes=AM4096.h 11 | 12 | -------------------------------------------------------------------------------- /examples/GetConfiguration/GetConfiguration.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * @file GetConfiguration.ino 3 | * @brief Example of using the AM4096 encoder to read configuration. 4 | */ 5 | 6 | 7 | 8 | #include 9 | #include // Include the header file 10 | 11 | const uint16_t DEVICE_ADDRESS = 0x5a; 12 | // Create an instance of the AM4096 encoder class with the specified address 13 | AM4096 encoder(DEVICE_ADDRESS); // I2C bus, device address 14 | AM4096_config_data currentConfiguration; 15 | 16 | void setup() { 17 | Serial.begin(9600); 18 | while(!Serial) { 19 | ; 20 | } 21 | Serial.println(F("Am4096 GetConfiguration Example")); 22 | Wire.begin(); 23 | // Initialize communication with the encoder 24 | encoder.init(); 25 | 26 | // Get the current configuration from the encoder 27 | encoder.getConfiguration(¤tConfiguration); 28 | 29 | // Print the configuration 30 | // Serial.println("Current Configuration:"); 31 | encoder.printAM4096Configuration(¤tConfiguration); 32 | } 33 | 34 | void loop() { 35 | // Your loop code (if needed) 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Yasir Shahzad 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/SetHwAddress/SetHwAddress.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * @file SetDeviceID.ino 3 | * @brief Example of using the AM4096 encoder to change its ID. 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | // Constants for configuration settings 10 | const uint16_t DEVICE_ADDRESS = 0x00; 11 | const uint16_t NEW_DEVICE_ADDRESS = 0x5A; // New device address 12 | 13 | // Create an instance of the AM4096 encoder class 14 | AM4096 encoder(DEVICE_ADDRESS); // device address 15 | 16 | void setup() { 17 | Serial.begin(9600); 18 | while (!Serial) { 19 | // Wait for serial port to connect 20 | } 21 | Serial.println(F("AM4096 SetHwAddress Example")); 22 | 23 | Wire.begin(); 24 | 25 | // Initialize the communication with the encoder 26 | if (encoder.init() != 0) { 27 | Serial.println("Device ID not correct"); 28 | while (1) { 29 | // Halt the program if device ID is incorrect 30 | } 31 | } else { 32 | Serial.println("Device ID correct"); 33 | } 34 | 35 | if (!encoder.setNewHwAddr(NEW_DEVICE_ADDRESS)) { 36 | Serial.println("Cannot set new ID"); 37 | } 38 | } 39 | 40 | void loop() { 41 | // Your loop code (if needed) 42 | } 43 | -------------------------------------------------------------------------------- /examples/GetRPM/GetRPM.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * @file GetRPM.ino 3 | * @brief Example of using the AM4096 encoder to read RPM. 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | // Specify the I2C address of the AM4096 encoder 10 | const uint8_t DEVICE_ADDRESS = 0x5B; 11 | 12 | // Create an instance of the AM4096 encoder class with the specified address 13 | AM4096 encoder(DEVICE_ADDRESS); 14 | 15 | // Structure to store the encoder output data 16 | AM4096_output_data outputData; 17 | 18 | void setup() { 19 | Serial.begin(9600); 20 | while (!Serial) { 21 | // Wait for serial port to connect (for debugging) 22 | } 23 | Serial.println(F("AM4096 GetRPM Example")); 24 | Wire.begin(); 25 | // Initialize communication with the encoder 26 | encoder.init(); 27 | } 28 | 29 | void loop() { 30 | // Read output data registers from the encoder 31 | int readStatus = encoder.readOutputDataRegisters(&outputData); 32 | 33 | // Check if the read was successful 34 | if (readStatus) { 35 | // Get the relative position (Rpos) field, which represents RPM 36 | uint16_t rpm = outputData.fields.Tho; 37 | 38 | // Print the RPM value 39 | Serial.print("RPM: "); 40 | Serial.println(rpm); 41 | } 42 | 43 | // Delay before the next reading 44 | delay(100); 45 | } 46 | -------------------------------------------------------------------------------- /examples/SetConfiguration/SetConfiguration.ino: -------------------------------------------------------------------------------- 1 | /** 2 | * @file GetConfiguration.ino 3 | * @brief Example of using the AM4096 encoder to read configuration. 4 | */ 5 | #include 6 | #include 7 | 8 | // Constants for configuration settings 9 | const uint16_t DEVICE_ADDRESS = 0x5A; 10 | 11 | // Create an instance of the AM4096 encoder class 12 | AM4096 encoder(DEVICE_ADDRESS); // I2C bus, device address 13 | 14 | // Creating a configuration data instance for AM4096 15 | AM4096_config_data config; 16 | 17 | void setup() 18 | { 19 | Serial.begin(9600); 20 | while(!Serial){ 21 | ; 22 | } 23 | Serial.println(F("Am4096 SetConfiguration Example")); 24 | Wire.begin(); 25 | // Initialize the communication with the encoder 26 | encoder.init(); 27 | 28 | config.fields.Reg35 = 0x01; // Set Regulator voltage bit 29 | config.fields.Slowint = 0x01; // Set Interpolator delay bit 30 | config.fields.Abridis = 0x01; // Set Enabling A B Ri outputs bit 31 | config.fields.Res = 0x04; // Set Interpolation factor rate 32 | config.fields.Sth = 0x07; // Set Tacho measuring range 33 | config.fields.SSIcfg = 0x03; // Set SSI settings 34 | config.fields.Dac = 0x03; // Set Linear voltage period selection 35 | config.fields.Dact = 0x01; // Set Select the output on Vout/Tout pin bit 36 | 37 | // Update the configuration 38 | int configurationUpdated = encoder.updateConfiguration(&config, true); 39 | if (!configurationUpdated) { 40 | Serial.println(F("Configuration updated")); 41 | } else { 42 | Serial.println(F("Error while updating configuration")); 43 | } 44 | } 45 | 46 | void loop() { 47 | // Your loop code (if needed) 48 | } 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AM4096 Encoder Arduino Library 2 | [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT) 3 | [![Installation instructions](https://www.ardu-badge.com/badge/AM4096.svg?)](https://www.ardu-badge.com/AM4096) 4 | [![Commits since latest](https://img.shields.io/github/commits-since/yasir-shahzad/AM4096/latest)](https://github.com/yasir-shahzad/AM4096/commits/master) 5 | [![Build Status](https://github.com/yasir-shahzad/AM4096/workflows/LibraryBuild/badge.svg)](https://github.com/yasir-shahzad/AM4096/actions) 6 | ![Hit Counter](https://visitor-badge.laobi.icu/badge?page_id=yasir-shahzad_AM4096) 7 | 8 | ![AM4096 Encoder](images/am4096.jpg) 9 | 10 | ## Description 11 | 12 | The AM4096 Encoder Arduino Library provides a convenient way to interface with the AM4096 rotary magnetic encoder chip using the I2C protocol. This library enables you to read configuration data and measurement output from the AM4096 encoder. 13 | 14 | The AM4096 encoder is a 12-bit rotary magnetic encoder chip that offers accurate position sensing for various applications. 15 | 16 | ## Features 17 | 18 | - Read configuration data from the AM4096 encoder. 19 | - Update configuration settings, including EEPROM updates. 20 | - Read measurement output data. 21 | - Find and initialize the encoder device. 22 | - Software-based I2C communication. 23 | 24 | ## Installation 25 | 26 | 1. Download the latest release of the library from [GitHub](https://github.com/yasir-shahzad/AM4096/releases). 27 | 2. Extract the downloaded ZIP file. 28 | 3. Move the extracted folder to the Arduino libraries directory. 29 | - For Windows: `Documents/Arduino/libraries` 30 | - For macOS: `~/Documents/Arduino/libraries` 31 | 32 | ## Documentation 33 | For more details on available methods and usage, refer to the library documentation. 34 | 35 | ## Contributing 36 | Contributions are welcome! If you find a bug or want to improve the library, please open an issue or submit a pull request. 37 | 38 | ## License 39 | This library is licensed under the MIT License. See the LICENSE file for more details. 40 | -------------------------------------------------------------------------------- /src/AM4096.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file AM4096.h 3 | * @brief AM4096 Arduino interface library. 4 | * 5 | * This file contains the AM4096 interface library for Arduino. 6 | * (c) Yasir Shahzad. Distributed under the MIT license. 7 | * For full terms, please refer to the LICENSE.md file. 8 | */ 9 | 10 | #ifndef __AM4096_H__ 11 | #define __AM4096_H__ 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #define AM4096_LOGS false 18 | 19 | #if AM4096_LOGS 20 | #include 21 | #endif 22 | 23 | #define AM4096_MEMORY_WORD_LEN 2 ///< AM4096 memory word length in Bytes 24 | #define AM4096_EEPROM_CONFIG_DATA_ADDR 0 ///< address of first word of AM4096 configuration in EEPROM 25 | #define AM4096_REGISTER_CONFIG_DATA_ADDR 48 ///< address of first word of AM4096 configuration in registers 26 | #define AM4096_CONFIG_DATA_LEN 4 ///< AM4096 configuration length in words 27 | #define AM4096_EEPROM_DEVICE_ID_ADDR 30 ///< addres of first word of AM4096 ID 28 | #define AM4096_EEPROM_DEVICE_ID_LEN 2 ///< AM4960 ID length in words 29 | #define AM4096_REGISTER_MEAS_DATA_ADDR 32 ///< address of first word of AM4096 measurement data in registers 30 | #define AM4096_REGISTER_MEAS_DATA_LEN 4 ///< AM4096 measurement data length in words 31 | #define AM4096_ADDR_FIRST 0 ///< AM4096 default hw address and begining of device's address space (I2C) 32 | #define AM4096_ADDR_LAST 127 ///< end of device's address space (I2C) 33 | #define AM4096_ERROR_NONE 0 ///< no error <==> success, non zero return code indicates error 34 | #define AM4096_EEPROM_WRITE_TIME 20 ///< EEPROM write time in ms 35 | 36 | /** 37 | * @brief Configuration data structure for the AM4096 encoder. 38 | * 39 | * This structure defines the configuration fields for the AM4096 encoder settings. 40 | * For detailed information about specific settings and valid values, refer to the product's datasheet: 41 | * Datasheet: https://www.rls.si/en/fileuploader/download/download/?d=0&file=custom%2Fupload%2FAM4096D02_06_EN_data_sheet.pdf 42 | * Product Page: https://www.rls.si/en/am4096-12-bit-rotary-magnetic-encoder-chip 43 | * 44 | * @sa AM4096_meas_fields 45 | */ 46 | 47 | struct AM4096_config_fields 48 | { 49 | uint16_t Addr : 7, ///< Device I2C address 50 | : 1, 51 | Reg35 : 1, ///< Regulator voltage 52 | Pdie : 1, ///< Internal power down 53 | Pdtr : 2, ///< Internal power down rate 54 | Slowint : 1, ///< Interpolator delay 55 | : 1, 56 | AGCdis : 1, ///< AGC disable 57 | Pdint : 1; ///< Interpolator power 58 | uint16_t Zin : 12,///< Zero position data 59 | Sign : 1, ///< Select the output direction 60 | : 1, 61 | Bufsel : 1, ///< Selects the output on pins U/Nsin, V/Psin, W/Ncos, Td/Pcos 62 | Abridis : 1; ///< Enabling A B Ri outputs 63 | uint16_t Hist : 7, ///< Digital hysteresis value in LSB at 12bit resolution 64 | Daa : 1, ///< Output position selection 65 | Nfil : 8; ///< Test parameters 66 | uint16_t Res : 3, ///< Interpolation factor rate 67 | UVW : 3, ///< UVW number of periods/turn 68 | Sth : 3, ///< Tacho measuring range 69 | : 2, 70 | SSIcfg : 2, ///< SSI settings 71 | Dac : 2, ///< Linear voltage period selection 72 | Dact : 1; ///< Select the output on Vout/Tout pin 73 | }; 74 | 75 | /** 76 | * @brief Output data structure for the AM4096 encoder 77 | * 78 | * This structure defines the output data fields of the AM4096 encoder. For detailed information about specific fields 79 | * and valid values, refer to the product's datasheet: 80 | * Datasheet: https://www.rls.si/en/fileuploader/download/download/?d=0&file=custom%2Fupload%2FAM4096D02_06_EN_data_sheet.pdf 81 | * Product Page: https://www.rls.si/en/am4096-12-bit-rotary-magnetic-encoder-chip 82 | * 83 | * @sa AM4096_config_fields 84 | */ 85 | struct AM4096_meas_fields 86 | { 87 | uint16_t Rpos : 12, ///< Relative position inf. 88 | : 3, 89 | SRCHRpos : 1; ///< Relative position output valid 90 | uint16_t Apos : 12, ///< Absolute position inf. 91 | : 3, 92 | SRCHApos : 1; ///< Absolute position outpout valid 93 | uint16_t : 13, 94 | Wel : 1, ///< Magnet too close status 95 | Weh : 1, ///< Magnet too far status 96 | : 1; 97 | uint16_t Tho : 10, ///< Tacho output data 98 | Thof : 1, ///< Tacho overflow info 99 | : 1, 100 | AGCgain : 4; ///< AGC disable 101 | }; 102 | 103 | 104 | /** 105 | * @brief Configuration data helper union. 106 | * @sa AM4096_config_fields 107 | */ 108 | union AM4096_config_data 109 | { 110 | AM4096_config_fields fields; 111 | uint16_t data[4]; 112 | }; 113 | 114 | /** 115 | * @brief Output data helper union. 116 | * @sa AM4096_meas_fields 117 | */ 118 | union AM4096_output_data 119 | { 120 | AM4096_meas_fields fields; 121 | uint16_t data[4]; 122 | }; 123 | 124 | /** 125 | * @brief AM4096 interface class. 126 | * 127 | * It allows to program AM4096 encoder and read its output and configuration registers. 128 | * @sa AM4096_config_data 129 | * @sa AM4096_output_data 130 | */ 131 | class AM4096 132 | { 133 | public: 134 | /** 135 | * @brief Create AM4096 interface. 136 | * @param i2c_bus pointer to I2C instance 137 | * @param address device address 138 | * @return 139 | */ 140 | AM4096(uint8_t address, TwoWire &i2c_bus = Wire); 141 | 142 | /** 143 | * @brief Initialise device. 144 | * 145 | * It initialise communication with device and reads its configuration and ID. If address is incorrect it starts 146 | * the search procedure to find first valid device. 147 | * @sa findAM4096Device() 148 | * @return AM4096_ERROR_NONE if success, non zero value on failure 149 | */ 150 | int init(); 151 | 152 | /** 153 | * @brief Get device ID. 154 | * @return device id 155 | */ 156 | uint32_t getDeviceId(); 157 | 158 | /** 159 | * @brief Start search procedure on i2c bus. 160 | * 161 | * It starts search procedure to look for first valid device. If found, class is initialised with this address. 162 | * You must call init() if device was found to use it. 163 | * @return AM4096_ERROR_NONE if success, non zero value on failure 164 | */ 165 | int findAM4096Device(); 166 | 167 | /** 168 | * @brief Set new device address. 169 | * @param address new address 170 | * @return AM4096_ERROR_NONE if success, non zero value on failure 171 | */ 172 | int setNewHwAddr(uint8_t address); 173 | 174 | /** 175 | * @brief Get current configuration. 176 | * @param conf_ptr pointer to configuration object to update 177 | */ 178 | void getConfiguration(AM4096_config_data * conf_ptr); 179 | 180 | /** 181 | * @brief Write new configuration to device. 182 | * @param conf_ptr pointer to configuration object 183 | * @param permament if true device's EEPROM is update, otherwise only registers are udpate and configuration will be lost after power cycle 184 | * @return AM4096_ERROR_NONE if success, non zero value on failures 185 | */ 186 | int updateConfiguration(AM4096_config_data * conf_ptr, bool permament=false); 187 | 188 | /** 189 | * @brief Read measurement data from device registers. 190 | * @param out_ptr pointer to output object to update 191 | * @return AM4096_ERROR_NONE if success, non zero value on failures 192 | */ 193 | int readOutputDataRegisters(AM4096_output_data * out_ptr); 194 | 195 | /** 196 | * @brief Prints formatted table with configuration registers. 197 | * 198 | * Works only if AM4096_LOGS is defined and set to 1 199 | * @param conf_ptr pointer to configuration to print out 200 | */ 201 | static void printAM4096Configuration(const AM4096_config_data * conf_ptr); 202 | 203 | /** 204 | * @brief Prints formatted table with measurement registers. 205 | * 206 | * Works only if AM4096_LOGS is defined and set to 1 207 | * @param out_ptr pointer to configuration to print out 208 | */ 209 | static void printAM4096OutputData(const AM4096_output_data * out_ptr); 210 | 211 | /** 212 | * @brief Write a 16bit word into AM4096 register/EEPROM. 213 | * @param addr register address 214 | * @param reg pointer to word 215 | * @return AM4096_ERROR_NONE if success, non zero value on failures 216 | */ 217 | int readReg(uint8_t addr, uint16_t * reg); 218 | 219 | /** 220 | * @brief Read a 16bit word from AM4096 register/EEPROM. 221 | * @param addr register address 222 | * @param reg pointer to word 223 | * @return AM4096_ERROR_NONE if success, non zero value on failures 224 | */ 225 | int writeReg(uint8_t addr, uint16_t * reg); 226 | 227 | private: 228 | TwoWire *i2cPort; //This stores the user's requested i2c port 229 | uint8_t _hw_addr; 230 | uint32_t _device_id; 231 | bool _initialised; 232 | AM4096_config_data _configuration; 233 | }; 234 | 235 | #endif /* __AM4096_H__ */ -------------------------------------------------------------------------------- /src/AM4096.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file AM4096.cpp 3 | * @brief AM4096 Arduino interface library. 4 | * 5 | * This file contains the AM4096 interface library for Arduino. 6 | * (c) Yasir Shahzad. Distributed under the MIT license. 7 | * For full terms, please refer to the LICENSE.md file. 8 | */ 9 | 10 | #include "AM4096.h" 11 | 12 | #if AM4096_LOGS 13 | #define AM_LOG(f_ , ...) printf((f_), ##__VA_ARGS__) 14 | #else 15 | #define AM_LOG(f_ , ...) do {} while (0) 16 | #endif 17 | 18 | #if AM4096_LOGS 19 | static const char CONFIG_STR[] = "*******CONFIG*******\r\n" 20 | "Addr : 0x%02X\r\n" 21 | "Reg35 : 0x%02X\r\n" 22 | "Pdie : 0x%02X\r\n" 23 | "Pdtr : 0x%02X\r\n" 24 | "Slowint : 0x%02X\r\n" 25 | "AGCdis : 0x%02X\r\n" 26 | "Pdint : 0x%02X\r\n" 27 | "Zin : 0x%02X\r\n" 28 | "Sign : 0x%02X\r\n" 29 | "Bufsel : 0x%02X\r\n" 30 | "Abridis : 0x%02X\r\n" 31 | "Hist : 0x%02X\r\n" 32 | "Daa : 0x%02X\r\n" 33 | "Nfil : 0x%02X\r\n" 34 | "Res : 0x%02X\r\n" 35 | "UVW : 0x%02X\r\n" 36 | "Sth : 0x%02X\r\n" 37 | "SSIcfg : 0x%02X\r\n" 38 | "Dac : 0x%02X\r\n" 39 | "Dact : 0x%02X\r\n" 40 | "*******************\r\n"; 41 | 42 | static const char OUTPUT_STR[] = "*******OUTPUT*******\r\n" 43 | "Rpos : 0x%02X\r\n" 44 | "SRCH : 0x%02X\r\n" 45 | "Apos : 0x%02X\r\n" 46 | "SRCH : 0x%02X\r\n" 47 | "Wel : 0x%02X\r\n" 48 | "Weh : 0x%02X\r\n" 49 | "Tho : 0x%02X\r\n" 50 | "Thof : 0x%02X\r\n" 51 | "AGCgain : 0x%02X\r\n" 52 | "********************\r\n"; 53 | #else 54 | static const char CONFIG_STR[] = ""; 55 | static const char OUTPUT_STR[] = ""; 56 | #endif 57 | 58 | AM4096::AM4096(uint8_t address, TwoWire &i2c_bus) 59 | : i2cPort(&i2c_bus), _hw_addr(address), _device_id(0), _initialised(false) 60 | { 61 | for(int i=0; ibeginTransmission(_hw_addr); 106 | i2cPort->write((int)reg_addr); 107 | if (reg_addr <= 0x1F) 108 | delayMicroseconds(20); // EEPROM CLK stretching 109 | if (i2cPort->endTransmission(false) != 0) 110 | { 111 | i2cPort->endTransmission(true); 112 | AM_LOG("Error while reading register ...\r\n"); 113 | return 0; 114 | } 115 | 116 | // Explicitly cast the arguments to uint8_t to resolve ambiguity 117 | i2cPort->requestFrom((uint8_t)_hw_addr,(uint8_t)2, (uint8_t)true); 118 | 119 | buffer[0] = i2cPort->read(); 120 | buffer[1] = i2cPort->read(); 121 | *data = (uint16_t)((buffer[0] << 8) & 0xff00) | (uint16_t)buffer[1]; 122 | return 1; 123 | } 124 | 125 | int AM4096::writeReg(uint8_t reg_addr, uint16_t * data) 126 | { 127 | bool flag = !((reg_addr < (AM4096_EEPROM_CONFIG_DATA_ADDR + AM4096_CONFIG_DATA_LEN)) || 128 | ((reg_addr >=AM4096_REGISTER_CONFIG_DATA_ADDR) && 129 | (reg_addr < (AM4096_REGISTER_CONFIG_DATA_ADDR + AM4096_CONFIG_DATA_LEN) ))); 130 | if(flag) 131 | return 1; 132 | 133 | char buffer[3]; 134 | buffer[0] = reg_addr; 135 | buffer[1] = (*data >> 8) & 0xFF; 136 | buffer[2] = *data & 0xFF; 137 | i2cPort->beginTransmission((int)_hw_addr); 138 | i2cPort->write(buffer, 3); 139 | if (i2cPort->endTransmission(true) != 0) 140 | { 141 | return 1; //return with error 142 | } 143 | 144 | if (reg_addr < (AM4096_EEPROM_CONFIG_DATA_ADDR + AM4096_CONFIG_DATA_LEN)) 145 | delay(AM4096_EEPROM_WRITE_TIME); 146 | return 0; 147 | } 148 | 149 | int AM4096::findAM4096Device() 150 | { 151 | int found_flag = 1, last_hw_addr = _hw_addr; 152 | AM_LOG("Starting searching procedure...\r\n"); 153 | _hw_addr = AM4096_ADDR_FIRST; 154 | 155 | while(found_flag && (_hw_addr <= AM4096_ADDR_LAST)) 156 | { 157 | if(found_flag = readReg(AM4096_REGISTER_CONFIG_DATA_ADDR, &_configuration.data[0]) == AM4096_ERROR_NONE) 158 | { 159 | _hw_addr++; 160 | delay(10); 161 | } 162 | } 163 | if(!found_flag) 164 | { 165 | _hw_addr = last_hw_addr; 166 | AM_LOG("Device with addr: 0x%02X found!\r\n", _hw_addr); 167 | return 0; 168 | } 169 | 170 | AM_LOG("No devices found!\r\n"); 171 | return 1; 172 | } 173 | 174 | uint32_t AM4096::getDeviceId() 175 | { 176 | return _device_id; 177 | } 178 | 179 | int AM4096::setNewHwAddr(uint8_t address) 180 | { 181 | if(address > 0x7F && _initialised) 182 | { 183 | AM_LOG("Can't set new addres!\r\n"); 184 | return 1; 185 | } 186 | _configuration.fields.Addr = address; 187 | int result = writeReg(AM4096_EEPROM_CONFIG_DATA_ADDR,&_configuration.data[0]); 188 | if(result) 189 | { 190 | AM_LOG("Can't set new addres!\r\n"); 191 | _configuration.fields.Addr = _hw_addr; 192 | return 1; 193 | } 194 | _hw_addr = address; 195 | AM_LOG("New addr 0x%02X set!\r\n", address); 196 | return 0; 197 | } 198 | 199 | void AM4096::getConfiguration(AM4096_config_data * conf_ptr) 200 | { 201 | assert(conf_ptr != NULL); 202 | *conf_ptr = _configuration; 203 | } 204 | 205 | void AM4096::printAM4096Configuration(const AM4096_config_data * conf_ptr) 206 | { 207 | if(conf_ptr == 0) 208 | return; 209 | AM_LOG( 210 | CONFIG_STR, 211 | conf_ptr->fields.Addr, 212 | conf_ptr->fields.Reg35, 213 | conf_ptr->fields.Pdie, 214 | conf_ptr->fields.Pdtr, 215 | conf_ptr->fields.Slowint, 216 | conf_ptr->fields.AGCdis, 217 | conf_ptr->fields.Pdint, 218 | conf_ptr->fields.Zin, 219 | conf_ptr->fields.Sign, 220 | conf_ptr->fields.Bufsel, 221 | conf_ptr->fields.Abridis, 222 | conf_ptr->fields.Hist, 223 | conf_ptr->fields.Daa, 224 | conf_ptr->fields.Nfil, 225 | conf_ptr->fields.Res, 226 | conf_ptr->fields.UVW, 227 | conf_ptr->fields.Sth, 228 | conf_ptr->fields.SSIcfg, 229 | conf_ptr->fields.Dac, 230 | conf_ptr->fields.Dact 231 | ); 232 | } 233 | 234 | void AM4096::printAM4096OutputData(const AM4096_output_data * out_ptr) 235 | { 236 | if(out_ptr == 0) 237 | return; 238 | AM_LOG( 239 | OUTPUT_STR, 240 | out_ptr->fields.Rpos, 241 | out_ptr->fields.SRCHRpos, 242 | out_ptr->fields.Apos, 243 | out_ptr->fields.SRCHApos, 244 | out_ptr->fields.Wel, 245 | out_ptr->fields.Weh, 246 | out_ptr->fields.Tho, 247 | out_ptr->fields.Thof, 248 | out_ptr->fields.AGCgain 249 | ); 250 | } 251 | 252 | int AM4096::updateConfiguration(AM4096_config_data * conf_ptr, bool permament) 253 | { 254 | assert(conf_ptr != NULL); 255 | const uint16_t mask[4] = {0xFF80, 0xE000, 0xFFFF, 0xFCFF}; 256 | 257 | if (conf_ptr->fields.Addr == 0) 258 | conf_ptr->fields.Addr = _configuration.fields.Addr; 259 | else if (conf_ptr->fields.Addr != _configuration.fields.Addr) 260 | return 1; 261 | 262 | int status = 0; 263 | if(permament) 264 | { 265 | // check if already in memory 266 | for(int i=0;i<4;i++) 267 | { 268 | if((_configuration.data[i] & mask[i]) == (conf_ptr->data[i] & mask[i])) 269 | status++; 270 | } 271 | if(status == 4) 272 | { 273 | AM_LOG("Configuration is identical to the one in the EEPROM!\r\n"); 274 | return 0; 275 | } 276 | status = 0; 277 | } 278 | uint16_t buffer[4]; 279 | for(int i=0;i<4;i++) buffer[i] = conf_ptr->data[i]; 280 | if(permament) 281 | { 282 | for (int i=0; i < AM4096_CONFIG_DATA_LEN; i++) 283 | status += writeReg(AM4096_EEPROM_CONFIG_DATA_ADDR + i, buffer+i); 284 | } 285 | else 286 | { 287 | for (int i = 0; i < AM4096_CONFIG_DATA_LEN; i++) 288 | status += writeReg(AM4096_REGISTER_CONFIG_DATA_ADDR + i, buffer+i); 289 | } 290 | 291 | if(status!=AM4096_ERROR_NONE) 292 | return status; 293 | 294 | for(int i=0;i<4;i++) _configuration.data[i] = buffer[i]; 295 | AM_LOG("Configuration succesfully written to memory!\r\n"); 296 | return status; 297 | } 298 | 299 | int AM4096::readOutputDataRegisters(AM4096_output_data * out_ptr) 300 | { 301 | assert(out_ptr != NULL); 302 | int status = 0; 303 | for(int i = 0; i < AM4096_REGISTER_MEAS_DATA_LEN; i++) 304 | status = readReg(AM4096_REGISTER_MEAS_DATA_ADDR + i, &out_ptr->data[i]); 305 | return status; 306 | } --------------------------------------------------------------------------------