|
| 1 | +// I2Cdev library collection - Main I2C device class |
| 2 | +// Abstracts bit and byte I2C R/W functions into a convenient class |
| 3 | +// EFM32 stub port by Nicolas Baldeck <nicolas@pioupiou.fr> |
| 4 | +// Based on Arduino's I2Cdev by Jeff Rowberg <jeff@rowberg.net> |
| 5 | +// |
| 6 | +// Changelog: |
| 7 | +// 2015-01-02 - Initial release |
| 8 | + |
| 9 | + |
| 10 | +/* ============================================ |
| 11 | +I2Cdev device library code is placed under the MIT license |
| 12 | +Copyright (c) 2015 Jeff Rowberg, Nicolas Baldeck |
| 13 | +
|
| 14 | +Permission is hereby granted, free of charge, to any person obtaining a copy |
| 15 | +of this software and associated documentation files (the "Software"), to deal |
| 16 | +in the Software without restriction, including without limitation the rights |
| 17 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 18 | +copies of the Software, and to permit persons to whom the Software is |
| 19 | +furnished to do so, subject to the following conditions: |
| 20 | +
|
| 21 | +The above copyright notice and this permission notice shall be included in |
| 22 | +all copies or substantial portions of the Software. |
| 23 | +
|
| 24 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 25 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 26 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 27 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 28 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 29 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 30 | +THE SOFTWARE. |
| 31 | +=============================================== |
| 32 | +*/ |
| 33 | + |
| 34 | +#include <esp_log.h> |
| 35 | +#include <esp_err.h> |
| 36 | +#include <freertos/FreeRTOS.h> |
| 37 | +#include <freertos/task.h> |
| 38 | +#include "sdkconfig.h" |
| 39 | + |
| 40 | +#include "I2Cdev.h" |
| 41 | + |
| 42 | +#define I2C_NUM I2C_NUM_0 |
| 43 | + |
| 44 | +#undef ESP_ERROR_CHECK |
| 45 | +#define ESP_ERROR_CHECK(x) do { esp_err_t rc = (x); if (rc != ESP_OK) { ESP_LOGE("err", "esp_err_t = %d", rc); /*assert(0 && #x);*/} } while(0); |
| 46 | + |
| 47 | +/** Default constructor. |
| 48 | + */ |
| 49 | +I2Cdev::I2Cdev() { |
| 50 | +} |
| 51 | + |
| 52 | +/** Initialize I2C0 |
| 53 | + */ |
| 54 | +void I2Cdev::initialize() { |
| 55 | + |
| 56 | +} |
| 57 | + |
| 58 | +/** Enable or disable I2C |
| 59 | + * @param isEnabled true = enable, false = disable |
| 60 | + */ |
| 61 | +void I2Cdev::enable(bool isEnabled) { |
| 62 | + |
| 63 | +} |
| 64 | + |
| 65 | +/** Default timeout value for read operations. |
| 66 | + */ |
| 67 | +uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; |
| 68 | +/** Read a single bit from an 8-bit device register. |
| 69 | + * @param devAddr I2C slave device address |
| 70 | + * @param regAddr Register regAddr to read from |
| 71 | + * @param bitNum Bit position to read (0-7) |
| 72 | + * @param data Container for single bit value |
| 73 | + * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout) |
| 74 | + * @return Status of read operation (true = success) |
| 75 | + */ |
| 76 | +int8_t I2Cdev::readBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t *data, uint16_t timeout) { |
| 77 | + |
| 78 | + |
| 79 | + uint8_t b; |
| 80 | + uint8_t count = readByte(devAddr, regAddr, &b, timeout); |
| 81 | + *data = b & (1 << bitNum); |
| 82 | + return count; |
| 83 | +} |
| 84 | + |
| 85 | +/** Read multiple bits from an 8-bit device register. |
| 86 | + * @param devAddr I2C slave device address |
| 87 | + * @param regAddr Register regAddr to read from |
| 88 | + * @param bitStart First bit position to read (0-7) |
| 89 | + * @param length Number of bits to read (not more than 8) |
| 90 | + * @param data Container for right-aligned value (i.e. '101' read from any bitStart position will equal 0x05) |
| 91 | + * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout) |
| 92 | + * @return Status of read operation (true = success) |
| 93 | + */ |
| 94 | +int8_t I2Cdev::readBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data, uint16_t timeout) { |
| 95 | + // 01101001 read byte |
| 96 | + // 76543210 bit numbers |
| 97 | + // xxx args: bitStart=4, length=3 |
| 98 | + // 010 masked |
| 99 | + // -> 010 shifted |
| 100 | + uint8_t count, b; |
| 101 | + if ((count = readByte(devAddr, regAddr, &b, timeout)) != 0) { |
| 102 | + uint8_t mask = ((1 << length) - 1) << (bitStart - length + 1); |
| 103 | + b &= mask; |
| 104 | + b >>= (bitStart - length + 1); |
| 105 | + *data = b; |
| 106 | + } |
| 107 | + return count; |
| 108 | +} |
| 109 | + |
| 110 | +/** Read single byte from an 8-bit device register. |
| 111 | + * @param devAddr I2C slave device address |
| 112 | + * @param regAddr Register regAddr to read from |
| 113 | + * @param data Container for byte value read from device |
| 114 | + * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout) |
| 115 | + * @return Status of read operation (true = success) |
| 116 | + */ |
| 117 | +int8_t I2Cdev::readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_t timeout) { |
| 118 | + return readBytes(devAddr, regAddr, 1, data, timeout); |
| 119 | +} |
| 120 | + |
| 121 | +/** Read multiple bytes from an 8-bit device register. |
| 122 | + * @param devAddr I2C slave device address |
| 123 | + * @param regAddr First register regAddr to read from |
| 124 | + * @param length Number of bytes to read |
| 125 | + * @param data Buffer to store read data in |
| 126 | + * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout) |
| 127 | + * @return I2C_TransferReturn_TypeDef http://downloads.energymicro.com/documentation/doxygen/group__I2C.html |
| 128 | + */ |
| 129 | +int8_t I2Cdev::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout) { |
| 130 | + i2c_cmd_handle_t cmd; |
| 131 | + SelectRegister(devAddr, regAddr); |
| 132 | + |
| 133 | + cmd = i2c_cmd_link_create(); |
| 134 | + ESP_ERROR_CHECK(i2c_master_start(cmd)); |
| 135 | + ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (devAddr << 1) | I2C_MASTER_READ, 1)); |
| 136 | + |
| 137 | + if(length>1) |
| 138 | + ESP_ERROR_CHECK(i2c_master_read(cmd, data, length-1, 0)); |
| 139 | + |
| 140 | + ESP_ERROR_CHECK(i2c_master_read_byte(cmd, data+length-1, 1)); |
| 141 | + |
| 142 | + ESP_ERROR_CHECK(i2c_master_stop(cmd)); |
| 143 | + ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_NUM, cmd, 1000/portTICK_PERIOD_MS)); |
| 144 | + i2c_cmd_link_delete(cmd); |
| 145 | + |
| 146 | + return length; |
| 147 | +} |
| 148 | + |
| 149 | +bool I2Cdev::writeWord(uint8_t devAddr, uint8_t regAddr, uint16_t data){ |
| 150 | + |
| 151 | + uint8_t data1[] = {(uint8_t)(data>>8), (uint8_t)(data & 0xff)}; |
| 152 | + uint8_t data2[] = {(uint8_t)(data & 0xff), (uint8_t)(data>>8)}; |
| 153 | + writeBytes(devAddr, regAddr, 2, data1); |
| 154 | + return true; |
| 155 | +} |
| 156 | + |
| 157 | +void I2Cdev::SelectRegister(uint8_t dev, uint8_t reg){ |
| 158 | + i2c_cmd_handle_t cmd; |
| 159 | + |
| 160 | + cmd = i2c_cmd_link_create(); |
| 161 | + ESP_ERROR_CHECK(i2c_master_start(cmd)); |
| 162 | + ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (dev << 1) | I2C_MASTER_WRITE, 1)); |
| 163 | + ESP_ERROR_CHECK(i2c_master_write_byte(cmd, reg, 1)); |
| 164 | + ESP_ERROR_CHECK(i2c_master_stop(cmd)); |
| 165 | + ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_NUM, cmd, 1000/portTICK_PERIOD_MS)); |
| 166 | + i2c_cmd_link_delete(cmd); |
| 167 | +} |
| 168 | + |
| 169 | +/** write a single bit in an 8-bit device register. |
| 170 | + * @param devAddr I2C slave device address |
| 171 | + * @param regAddr Register regAddr to write to |
| 172 | + * @param bitNum Bit position to write (0-7) |
| 173 | + * @param value New bit value to write |
| 174 | + * @return Status of operation (true = success) |
| 175 | + */ |
| 176 | +bool I2Cdev::writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t data) { |
| 177 | + uint8_t b; |
| 178 | + readByte(devAddr, regAddr, &b); |
| 179 | + b = (data != 0) ? (b | (1 << bitNum)) : (b & ~(1 << bitNum)); |
| 180 | + return writeByte(devAddr, regAddr, b); |
| 181 | +} |
| 182 | + |
| 183 | +/** Write multiple bits in an 8-bit device register. |
| 184 | + * @param devAddr I2C slave device address |
| 185 | + * @param regAddr Register regAddr to write to |
| 186 | + * @param bitStart First bit position to write (0-7) |
| 187 | + * @param length Number of bits to write (not more than 8) |
| 188 | + * @param data Right-aligned value to write |
| 189 | + * @return Status of operation (true = success) |
| 190 | + */ |
| 191 | +bool I2Cdev::writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data) { |
| 192 | + // 010 value to write |
| 193 | + // 76543210 bit numbers |
| 194 | + // xxx args: bitStart=4, length=3 |
| 195 | + // 00011100 mask byte |
| 196 | + // 10101111 original value (sample) |
| 197 | + // 10100011 original & ~mask |
| 198 | + // 10101011 masked | value |
| 199 | + uint8_t b = 0; |
| 200 | + if (readByte(devAddr, regAddr, &b) != 0) { |
| 201 | + uint8_t mask = ((1 << length) - 1) << (bitStart - length + 1); |
| 202 | + data <<= (bitStart - length + 1); // shift data into correct position |
| 203 | + data &= mask; // zero all non-important bits in data |
| 204 | + b &= ~(mask); // zero all important bits in existing byte |
| 205 | + b |= data; // combine data with existing byte |
| 206 | + return writeByte(devAddr, regAddr, b); |
| 207 | + } else { |
| 208 | + return false; |
| 209 | + } |
| 210 | +} |
| 211 | + |
| 212 | +/** Write single byte to an 8-bit device register. |
| 213 | + * @param devAddr I2C slave device address |
| 214 | + * @param regAddr Register address to write to |
| 215 | + * @param data New byte value to write |
| 216 | + * @return Status of operation (true = success) |
| 217 | + */ |
| 218 | +bool I2Cdev::writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data) { |
| 219 | + i2c_cmd_handle_t cmd; |
| 220 | + |
| 221 | + cmd = i2c_cmd_link_create(); |
| 222 | + ESP_ERROR_CHECK(i2c_master_start(cmd)); |
| 223 | + ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (devAddr << 1) | I2C_MASTER_WRITE, 1)); |
| 224 | + ESP_ERROR_CHECK(i2c_master_write_byte(cmd, regAddr, 1)); |
| 225 | + ESP_ERROR_CHECK(i2c_master_write_byte(cmd, data, 1)); |
| 226 | + ESP_ERROR_CHECK(i2c_master_stop(cmd)); |
| 227 | + ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_NUM, cmd, 1000/portTICK_PERIOD_MS)); |
| 228 | + i2c_cmd_link_delete(cmd); |
| 229 | + |
| 230 | + return true; |
| 231 | +} |
| 232 | + |
| 233 | +/** Write single byte to an 8-bit device register. |
| 234 | + * @param devAddr I2C slave device address |
| 235 | + * @param regAddr Register address to write to |
| 236 | + * @param length Number of bytes to write |
| 237 | + * @param data Array of bytes to write |
| 238 | + * @return Status of operation (true = success) |
| 239 | + */ |
| 240 | +bool I2Cdev::writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data){ |
| 241 | + i2c_cmd_handle_t cmd; |
| 242 | + |
| 243 | + cmd = i2c_cmd_link_create(); |
| 244 | + ESP_ERROR_CHECK(i2c_master_start(cmd)); |
| 245 | + ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (devAddr << 1) | I2C_MASTER_WRITE, 1)); |
| 246 | + ESP_ERROR_CHECK(i2c_master_write_byte(cmd, regAddr, 1)); |
| 247 | + ESP_ERROR_CHECK(i2c_master_write(cmd, data, length-1, 0)); |
| 248 | + ESP_ERROR_CHECK(i2c_master_write_byte(cmd, data[length-1], 1)); |
| 249 | + ESP_ERROR_CHECK(i2c_master_stop(cmd)); |
| 250 | + ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_NUM, cmd, 1000/portTICK_PERIOD_MS)); |
| 251 | + i2c_cmd_link_delete(cmd); |
| 252 | + return true; |
| 253 | +} |
| 254 | + |
| 255 | + |
0 commit comments