Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: Allow using secondary Wire buses #23

Open
matthijskooijman opened this issue Oct 31, 2020 · 8 comments
Open

Feature request: Allow using secondary Wire buses #23

matthijskooijman opened this issue Oct 31, 2020 · 8 comments
Labels
enhancement New feature or request

Comments

@matthijskooijman
Copy link

On some boards, such as STM32 boards (and probably SAMD boards too), there are multiple I²C controllers available, typically named Wire, Wire1, etc.

Currently, this library always uses Wire hardcoded, but it would be convenient if a secondary bus could also be used.

There is already a sensirion_i2c_select_bus(uint8_t idx) function declared, but it is never defined anywhere. Also, since I'm not sure whether there is a standard way to detect how much Wire objects are defined, this API might be hard to implement on Arduino. Therefore, I'd suggest implementing a selection function that actually passes the Wire, Wire1, etc objects as a reference. The type of these seems to be TwoWire on most cores, but just in case cores use other names, I'd suggest using decltype(Wire) instead.

So, that would be something like this (untested, should probably be split between .h and .cpp files as well, but just to get the general idea):

using SensirionWireType = decltype(Wire);

SensirionWireType *SensirionWire = &Wire;

sensirion_i2c_select_bus(SensirionWireType& bus)
{
  SensirionWire = &bus;
}

And then replace all other Wire. with SensirionWire-> too.

This allows a sketch to do e.g.:

sensirion_i2c_select_bus(Wire1);
sensirion_i2c_init();

It can even switch between multiple buses at runtime, as long as it does call sensiron_i2c_init() once for each bus beforehand.

@winkj
Copy link
Member

winkj commented Oct 31, 2020

Sounds good; this is partly because all the interfaces in sensirion_hw_i2c_implementation.cpp use generic - i.e. not platform specific - APIs, which is why we had the sensirion_i2c_select_bus() call in there with an index; changing the interface to an Arduino SDK one would break compilation on other platforms.

So this will require a little bit more thought on our end, or potentially just foregoing compatibility with embedded-common in the interest of better support of Arduino platform needs

@matthijskooijman
Copy link
Author

changing the interface to an Arduino SDK one would break compilation on other platforms.

Yeah, so maybe adding a function (i.e. sensirion_i2c_select_wire(...) or so) could work? And then just ignoring the existing sensirion_i2c_select_bus()?

Even though the existing index-based API isn't necessarily bad, I'm afraid it will be hard to implement fully portably Arduino, since there is no generic index -> Wire object API, or a standardized and documented way to figure out how many wire interfaces there are.

Looking more closely, it does seem that there is a WIRE_INTERFACES_COUNT macro that is at least used by the Arduino sam, Arduino samd, Adafruit samd, stm32l0 and stm32l4 cores, so that could be a reasonably standard way to do this maybe? It seems that Teensy implements WIRE_IMPLEMENT_WIREX macros instead. So an alternative could be maybe:

int16_t sensirion_i2c_select_bus(uint8_t bus_idx) {
  switch (bus_idx) {
    case 0:
      SensirionWire = &Wire;
      return 0;
#if defined WIRE_IMPLEMENT_WIRE1 || WIRE_INTERFACES_COUNT > 1
    case 1:
      SensirionWire = &Wire1;
      return 0;
#endif
#if defined WIRE_IMPLEMENT_WIRE2 || WIRE_INTERFACES_COUNT > 2
    case 1:
      SensirionWire = &Wire2;
      return 0;
#endif
#if defined WIRE_IMPLEMENT_WIRE3 || WIRE_INTERFACES_COUNT > 3
    case 1:
      SensirionWire = &Wire3;
      return 0;
#endif
    default:
      return STATUS_FAIL;
  }
}

(as an alternative implementation for sensirion_i2c_select_bus, the other changes suggested above are still needed)

@abrauchli
Copy link

The generic usage we thought of is quite similar but shifts more logic in to the i2c read and write functions based on the current context. A quick recap: The HAL implementation is aware of all three implementations: sensirion_i2c_read, sensirion_i2c_write and sensirion_i2c_select_bus - the latter being the trigger to switching the context (since we don't pass context objects, those have to be maintained separate, e.g. as globals.) Thus, we modify the behavior of sensirion_i2c_read depending on the context, which is triggered by the index. E.g. the read function would then look like this switch (index) { case 1: Wire1.read(); // ...

@matthijskooijman
Copy link
Author

Ah, that would probably be even better, since then the code will even work when Wire and Wire1 have different types somehow.

@winkj winkj added the enhancement New feature or request label Jan 27, 2021
matthijskooijman added a commit to meetjestad/arduino-sps that referenced this issue May 21, 2021
This makes the library work on the MJS2020 hardware. This is obviously a
hack, but until the library supports configuring it dynamically (see
Sensirion#23), this is the best we
can do.
@mirlang
Copy link

mirlang commented Sep 20, 2023

+1

@winkj
Copy link
Member

winkj commented Sep 20, 2023

The cleanest way forward would be to port this to https://github.com/Sensirion/arduino-core/ since that allows selecting Wire objects already.

In the interest of time, maybe we could just modify sensiron_i2c_init() to take a reference to an initialized Wire object... @psachs, thoughts?

@matthijskooijman
Copy link
Author

Any further thoughts on this issue? Would be good if we could switch back to an unmodified arduino-sps library for our project.

@psachs
Copy link
Member

psachs commented Oct 28, 2024

If it helps you in any way. We already have a newer driver for SCD30 that allows you to provide the Wire and I2C address on initialization. The driver is available on Arduino library and PlatformIO.

https://github.com/Sensirion/arduino-i2c-scd30

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants