aboutsummaryrefslogtreecommitdiff
path: root/src/drivers/device
diff options
context:
space:
mode:
authorLorenz Meier <lm@inf.ethz.ch>2014-12-10 16:58:15 +0100
committerLorenz Meier <lm@inf.ethz.ch>2015-02-13 09:12:38 +0100
commitc0d246e8e4130c3df7d16a97f7c749827be18b29 (patch)
tree8dee7ec7e1dee4301d5cbb80636a3e5c61f993ac /src/drivers/device
parenteeb192730f813f2e3278103a7c899233e6da03b0 (diff)
downloadpx4-firmware-c0d246e8e4130c3df7d16a97f7c749827be18b29.tar.gz
px4-firmware-c0d246e8e4130c3df7d16a97f7c749827be18b29.tar.bz2
px4-firmware-c0d246e8e4130c3df7d16a97f7c749827be18b29.zip
CDEV::I2C: Enforce one speed per bus
Diffstat (limited to 'src/drivers/device')
-rw-r--r--src/drivers/device/i2c.cpp73
-rw-r--r--src/drivers/device/i2c.h4
2 files changed, 62 insertions, 15 deletions
diff --git a/src/drivers/device/i2c.cpp b/src/drivers/device/i2c.cpp
index 286778c01..33bb90fc9 100644
--- a/src/drivers/device/i2c.cpp
+++ b/src/drivers/device/i2c.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
*
- * Copyright (C) 2012 PX4 Development Team. All rights reserved.
+ * Copyright (c) 2012-2015 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -45,6 +45,8 @@
namespace device
{
+unsigned int I2C::_bus_clocks[3] = { 100000, 100000, 100000 };
+
I2C::I2C(const char *name,
const char *devname,
int bus,
@@ -77,11 +79,29 @@ I2C::~I2C()
}
int
+I2C::set_bus_clock(unsigned bus, unsigned clock_hz)
+{
+ int index = bus - 1;
+
+ if (index < 0 || index >= static_cast<int>(sizeof(_bus_clocks) / sizeof(_bus_clocks[0]))) {
+ return -EINVAL;
+ }
+
+ if (_bus_clocks[index] > 0) {
+ // debug("overriding clock of %u with %u Hz\n", _bus_clocks[index], clock_hz);
+ }
+ _bus_clocks[index] = clock_hz;
+
+ return OK;
+}
+
+int
I2C::init()
{
int ret = OK;
+ unsigned bus_index;
- /* attach to the i2c bus */
+ // attach to the i2c bus
_dev = up_i2cinitialize(_bus);
if (_dev == nullptr) {
@@ -90,6 +110,37 @@ I2C::init()
goto out;
}
+ // the above call fails for a non-existing bus index,
+ // so the index math here is safe.
+ bus_index = _bus - 1;
+
+ // abort if the max frequency we allow (the frequency we ask)
+ // is smaller than the bus frequency
+ if (_bus_clocks[bus_index] > _frequency) {
+ (void)up_i2cuninitialize(_dev);
+ log("FAIL: too slow for bus #%u: %u KHz, device max: %u KHz)",
+ _bus, _bus_clocks[bus_index] / 1000, _frequency / 1000);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ // set the bus frequency on the first access if it has
+ // not been set yet
+ if (_bus_clocks[bus_index] == 0) {
+ _bus_clocks[bus_index] = _frequency;
+ }
+
+ // set frequency for this instance once to the bus speed
+ // the bus speed is the maximum supported by all devices on the bus,
+ // as we have to prioritize performance over compatibility.
+ // If a new device requires a lower clock speed, this has to be
+ // manually set via "fmu i2c <bus> <clock>" before starting any
+ // drivers.
+ // This is necessary as automatically lowering the bus speed
+ // for maximum compatibility could induce timing issues on
+ // critical sensors the adopter might be unaware of.
+ I2C_SETFREQUENCY(_dev, _bus_clocks[bus_index]);
+
// call the probe function to check whether the device is present
ret = probe();
@@ -107,9 +158,13 @@ I2C::init()
}
// tell the world where we are
- log("on I2C bus %d at 0x%02x", _bus, _address);
+ log("on I2C bus %d at 0x%02x (bus: %u KHz, max: %u KHz)",
+ _bus, _address, _bus_clocks[bus_index] / 1000, _frequency / 1000);
out:
+ if ((ret != OK) && (_dev != nullptr)) {
+ up_i2cuninitialize(_dev);
+ }
return ret;
}
@@ -152,12 +207,6 @@ I2C::transfer(const uint8_t *send, unsigned send_len, uint8_t *recv, unsigned re
if (msgs == 0)
return -EINVAL;
- /*
- * I2C architecture means there is an unavoidable race here
- * if there are any devices on the bus with a different frequency
- * preference. Really, this is pointless.
- */
- I2C_SETFREQUENCY(_dev, _frequency);
ret = I2C_TRANSFER(_dev, &msgv[0], msgs);
/* success */
@@ -186,12 +235,6 @@ I2C::transfer(i2c_msg_s *msgv, unsigned msgs)
do {
- /*
- * I2C architecture means there is an unavoidable race here
- * if there are any devices on the bus with a different frequency
- * preference. Really, this is pointless.
- */
- I2C_SETFREQUENCY(_dev, _frequency);
ret = I2C_TRANSFER(_dev, msgv, msgs);
/* success */
diff --git a/src/drivers/device/i2c.h b/src/drivers/device/i2c.h
index 8518596ea..7bb4ae1af 100644
--- a/src/drivers/device/i2c.h
+++ b/src/drivers/device/i2c.h
@@ -59,6 +59,10 @@ public:
* Get the address
*/
int16_t get_address() const { return _address; }
+
+ static int set_bus_clock(unsigned bus, unsigned clock_hz);
+
+ static unsigned int _bus_clocks[3];
protected:
/**