diff options
Diffstat (limited to 'firmware/e300/battery/i2c_twi.c')
-rw-r--r-- | firmware/e300/battery/i2c_twi.c | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/firmware/e300/battery/i2c_twi.c b/firmware/e300/battery/i2c_twi.c new file mode 100644 index 000000000..f2c0491d3 --- /dev/null +++ b/firmware/e300/battery/i2c_twi.c @@ -0,0 +1,187 @@ +/* USRP E310 Firmware Atmel AVR TWI driver + * Copyright (C) 2014 Ettus Research + * This file is part of the USRP E310 Firmware + * The USRP E310 Firmware is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * The USRP E310 Firmware is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with the USRP E310 Firmware. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "i2c_twi.h" +#include "mcu_settings.h" +#include "utils.h" + +#include <stdbool.h> +#include <avr/io.h> +#include <util/twi.h> +#include <util/delay.h> + +static const uint8_t I2C_TIMEOUT = 10; + +static inline uint8_t I2C_READ_ADDR(const uint8_t x) +{ + return (x << 1) | 0x1; +} + +static inline uint8_t I2C_WRITE_ADDR(const uint8_t x) +{ + return (x << 1) & 0xfe; +} + +void i2c_twi_init_calc(uint32_t rate) +{ + uint8_t twbr; + twbr = ((F_CPU/rate)-16)/2; + + TWBR = twbr; + + PRR &= ~BIT(PRTWI); + + /* www.mikrocontroller.net/articles/AVR_TWI says this might help ... */ + TWCR &= ~(BIT(TWSTO) | BIT(TWEN)); + TWCR |= BIT(TWEN); +} + +void i2c_twi_init(i2c_speed_t speed) +{ + switch (speed) { + case I2C_SPEED_400K: + TWBR = 16; + break; + case I2C_SPEED_100K: + TWBR = 32; + break; + default: + TWBR = 32; + break; + } + + /* reset potential prescalers */ + TWSR = 0; + + /* www.mikrocontroller.net/articles/AVR_TWI says this might help ... */ + TWCR &= ~(BIT(TWSTO) | BIT(TWEN)); + TWCR |= BIT(TWEN); +} + +static void i2c_twi_wait_for_complete(void) +{ + uint8_t timeout = 100; + + do { + _delay_us(10); + timeout--; + } while(timeout && !(TWCR & (1<<TWINT))); +} + +static void i2c_twi_start(void) +{ + TWCR = BIT(TWINT) | BIT(TWEN) | BIT(TWSTA); + i2c_twi_wait_for_complete(); +} + +static void i2c_twi_stop(void) +{ + TWCR = BIT(TWINT) | BIT(TWEN) | BIT(TWSTO); +} + + +static uint8_t i2c_twi_recv_byte(bool ack) +{ + TWCR = BIT(TWINT) | BIT(TWEN) | (ack ? BIT(TWEA) : 0); + i2c_twi_wait_for_complete(); + return TWDR; +} + +static void i2c_twi_send_byte(uint8_t data) +{ + TWDR = data; + TWCR = BIT(TWINT) | BIT(TWEN); + i2c_twi_wait_for_complete(); +} + +int8_t i2c_twi_read(uint8_t addr, uint8_t reg, uint8_t *value) +{ + /* start the write transaction to select the register */ + i2c_twi_start(); + i2c_twi_send_byte(I2C_WRITE_ADDR(addr)); + i2c_twi_send_byte(reg); + + /* (re)start for the actual read transaction to read back */ + i2c_twi_start(); + i2c_twi_send_byte(I2C_READ_ADDR(addr)); + *value = i2c_twi_recv_byte(false); + i2c_twi_stop(); + + return 0; +} + +int8_t i2c_twi_write(uint8_t addr, uint8_t reg, uint8_t value) +{ + i2c_twi_start(); + i2c_twi_send_byte(I2C_WRITE_ADDR(addr)); + i2c_twi_send_byte(reg); + i2c_twi_send_byte(value); + i2c_twi_stop(); + + return 0; +} + +int8_t i2c_twi_read16(uint8_t addr, uint8_t reg, uint16_t *value) +{ + uint8_t msb, lsb; + + /* start the write transaction to select the register */ + i2c_twi_start(); + i2c_twi_send_byte(I2C_WRITE_ADDR(addr)); + i2c_twi_send_byte(reg); + + /* (re)start for the actual read transaction to read back MSB + * then LSB, fortunately the datashit describes the opposite w.r.t ACKs*/ + i2c_twi_start(); + i2c_twi_send_byte(I2C_READ_ADDR(addr)); + msb = i2c_twi_recv_byte(true); + lsb = i2c_twi_recv_byte(false); + i2c_twi_stop(); + + *value = (msb << 8) | lsb; + + return 0; +} + +int8_t i2c_twi_write16(uint8_t addr, uint8_t reg, uint16_t value) +{ + uint8_t msb, lsb; + + msb = value >> 8; + lsb = value & 0xff; + + i2c_twi_start(); + i2c_twi_send_byte(I2C_WRITE_ADDR(addr)); + i2c_twi_send_byte(reg); + i2c_twi_send_byte(msb); + i2c_twi_send_byte(lsb); + i2c_twi_stop(); + + return 0; +} + +/* +static const uint8_t I2C_ARA_ADDR = 0x0c; +uint8_t i2c_twi_smbus_ara(void) +{ + volatile uint8_t addr;; + + i2c_twi_start(); + i2c_twi_send_byte(I2C_READ_ADDR(I2C_ARA_ADDR)); + addr = i2c_twi_recv_byte(false); + i2c_twi_stop(); + return addr; +} +*/ |