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

driver/bme680: add I2C/SPI driver for BME680 device #12717

Merged
merged 7 commits into from
Mar 12, 2020

Conversation

dylad
Copy link
Member

@dylad dylad commented Nov 15, 2019

Contribution description

This PR provides support for BME680 sensor using the vendor driver from Bosch Sensortech as package.

The sensor provides measurement for temperature, humidity, pressure and VOC gas concentration. It can be connected either via I2C or via SPI. The driver supports multiple BME680 sensor and mixed I2C/SPI configurations.

The driver supports SAUL.

Testing procedure

Apply the parameters you want in the bme680_params.h file run tests/driver_bme680

  • with one I2C device

    DRIVER='bme680_i2c'  BOARD=... make -C tests/driver_bme680 flash test
    
  • with one SPI device

    DRIVER='bme680_spi'  BOARD=... make -C tests/driver_bme680 flash test
    
  • or with one I2C and one SPI device

    DRIVER='bme680_spi bme680_i2c'  BOARD=... make -C tests/driver_bme680 flash term
    

SAUL can be tested with tests/saul. The used interface(s) has/have to be defined with USEMODULE, for example

USEMODULE='bme680_spi bme680_i2c' BOARD=... make -C tests/saul flash term

Issues/PRs references

Replaces #10502

@dylad dylad added State: WIP State: The PR is still work-in-progress and its code is not in its final presentable form yet Type: new feature The issue requests / The PR implemements a new feature for RIOT Area: pkg Area: External package ports Area: drivers Area: Device drivers labels Nov 15, 2019
drivers/Makefile.dep Show resolved Hide resolved
drivers/Makefile.include Outdated Show resolved Hide resolved
@gschorcht
Copy link
Contributor

I will review and test it tomorrow.

@gschorcht
Copy link
Contributor

A comment on the naming of the package. If the number of packages imported in this way increases, it might be better to order them by category for readability. If not in separate directories then at least by starting the name with the category as we already do for test applications.

Therefore, I would suggest to call the package driver_bme680. It is the way I have already done for the VL53L1X in PR #10363. The vendor package used by the driver is called driver_vl53l1x. We should use a consistent naming scheme for drivers.

What do you think about it?

@dylad
Copy link
Member Author

dylad commented Nov 15, 2019

Therefore, I would suggest to call the package driver_bme680

I am not against and I'll apply this change unless someone is opposed to such naming scheme.

If the number of packages imported in this way increases

Agreed, but let's wait for some time if new drivers/pkgs appears in the future. I think I dedicated name with a category is better than a subfolder which will increase build complexity.

@dylad dylad added this to the Release 2020.01 milestone Nov 15, 2019
#endif /* BME680_SPI_MODE */

#ifndef BME680_NSS_PIN
#define BME680_NSS_PIN GPIO_PIN(PA, 5)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use a platform independent port identifier here to ensure that it is is compilable on all platforms.

Suggested change
#define BME680_NSS_PIN GPIO_PIN(PA, 5)
#define BME680_NSS_PIN GPIO_PIN(0, 5)

drivers/bme680/bme680.c Outdated Show resolved Hide resolved
pkg/bme680_driver/include/bme680_hal.h Outdated Show resolved Hide resolved
drivers/Makefile.dep Outdated Show resolved Hide resolved
drivers/Makefile.dep Outdated Show resolved Hide resolved
drivers/bme680/include/bme680_params.h Outdated Show resolved Hide resolved
drivers/bme680/include/bme680_params.h Outdated Show resolved Hide resolved
drivers/bme680/include/bme680_params.h Outdated Show resolved Hide resolved
pkg/bme680_driver/contrib/bme680_hal.c Outdated Show resolved Hide resolved
pkg/bme680_driver/contrib/bme680_hal.c Outdated Show resolved Hide resolved
tests/driver_bme680/Makefile Show resolved Hide resolved
ret = bme680_get_sensor_data(&data, &(dev.dev));
if(!ret) {
#ifndef BME680_FLOAT_POINT_COMPENSATION
printf("[bme680]: T %d degC, P %ld hPa, H %ld ", data.temperature,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use platform independent format defines here:

Suggested change
printf("[bme680]: T %d degC, P %ld hPa, H %ld ", data.temperature,
printf("[bme680]: T %" PRIi16 " degC, P %" PRIu32 " hPa, H %" PRIu32, data.temperature,

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, I also enforce display formatting. Tell me if it's wrong.

tests/driver_bme680/main.c Outdated Show resolved Hide resolved
tests/driver_bme680/main.c Outdated Show resolved Hide resolved
tests/driver_bme680/main.c Outdated Show resolved Hide resolved
tests/driver_bme680/main.c Outdated Show resolved Hide resolved
@gschorcht
Copy link
Contributor

Tested with I2C and it works as expected 👍

@herjulf
Copy link
Contributor

herjulf commented Nov 20, 2019

Many moons ago I did a implementation for Contiki
https://github.com/posjodin/contiki/tree/master/dev/bme680

IMO the Bosch lib was to bloated so I just rewrote from user manual code examples to keep the code compact, readable and with few dependencies. But I don't the implementation is very tested.

@herjulf
Copy link
Contributor

herjulf commented Nov 20, 2019

Also I bit disappointing to see there still no mapping between the resistance and the indoor Air Quality. Bosch is to blame.
IMO Bosch should provide a mapping. Otherwise the device is not so useful.

@tcschmidt
Copy link
Member

@MrKevinWeiss is this a poster child for SPI HIL testing?

@MrKevinWeiss
Copy link
Contributor

I don't know if this is a good candidate as this is a driver. If there are problems with the CPU implementations of the SPI than the HiL could assist with debugging.

@gschorcht
Copy link
Contributor

gschorcht commented Nov 21, 2019

@herjulf I did exactly the same two years ago for ESP-IDF which could be easily ported to RIOT and probably would have done it already 😉

This PR is the result of the review of PR #9909 which provided a driver that based on the vendor code but had only required parts of the code. At that time, we decided to try to use the original vendor driver as a package, see also #10502.

If code size is your concern, it may be interesting to know what code size PR #9909 and what code size this PR has.

@herjulf
Copy link
Contributor

herjulf commented Nov 21, 2019

@gschorcht . Thanks for this history and background and seems like we have similar experiences with drivers w/o Bosch API. Code size is of course interesting but my concerns is more about control and avoiding dependencies for long time maintainability. Anyway current work is now based on the Bosch library.

@dylad
Copy link
Member Author

dylad commented Dec 11, 2019

@gschorcht I pushed a couple of changes, especially the interface selection in the bme680_params.h file. Would you mind have another look please ?

In addition, this driver can use floating point if available on your MCU. By default, this package do not use it.

## Usage
Add `USEPKG += bme680_driver` in your Makefile and `#include "bme680_hal.h"` to your code. Refer to the code documentation for more information on the API.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove USEPKG += bme680_driver from documentation. It isn't necessary to add it to the application's makefile.

Even more, if you move

#include "bme680_hal.h"
#include "bme680_defs.h"

to bme680.h, the application has not to include them. Then it is enough to include bme680.h and bme680_params.h by the application. This makes the usage easier.

Suggested change
Add `USEPKG += bme680_driver` in your Makefile and `#include "bme680_hal.h"` to your code. Refer to the code documentation for more information on the API.
Refer to the code documentation for more information on the API.

drivers/include/bme680.h Show resolved Hide resolved
@gschorcht
Copy link
Contributor

Therefore, I would suggest to call the package driver_bme680

I am not against and I'll apply this change unless someone is opposed to such naming scheme.

What about this suggested change? I just want to have a naming that allows us to sort the large amount of different package types a bit. As the number of driver packages increases, they could all be called driver_*.

@gschorcht
Copy link
Contributor

gschorcht commented Mar 11, 2020

FYI. It works w. I2C BOARD=avr-rss2 with AtMega256RFR2. Also compiles with ENABLE_FP=1 but I'll assume float libs is needed for float printout. Capital O in ohms?

Thanks for testing. Sounds good.

@gschorcht
Copy link
Contributor

We should get it merged in near future, there is already a conflict with master again 😟

May I rebase and squash?

@roberthartung
Copy link
Member

We should get it merged in near future, there is already a conflict with master again

May I rebase and squash?

Yes, please do so. Will give the code a final review. Testing should be complete at this point. Thanks @janschlicht

@roberthartung
Copy link
Member

roberthartung commented Mar 12, 2020

It is now dynamic. If the value returned from the driver is greater than INT16_MAX, it uses kOhm. Otherwise it uses Ohm.

I still wrap my head around this. Is it safe to just switch from ohm to kilo ohm? Can there be a double meaning of a value?

@gschorcht
Copy link
Contributor

It is now dynamic. If the value returned from the driver is greater than INT16_MAX, it uses kOhm. Otherwise it uses Ohm.

I still wrap my head around this. Is it safe to just switch from ohm to kilo ohm? Can there be a double meaning of a value?

Hm, there is no other chance. Since the phydat module uses int16_t, there no other way than to scale down a value greater than +32,767 for SAUL. That's why the the value is divided by 1000 and the scale is set to 3 in that case. The phydat module then automatically converts the unit string from ohm to kohm as it does for other units. Even though the official unit would be kiloohm or also kilo ohm, that the way it is handled by the phydat module.

Add the vendor driver implementation from Bosch Sensortech as a package.
@roberthartung
Copy link
Member

It is now dynamic. If the value returned from the driver is greater than INT16_MAX, it uses kOhm. Otherwise it uses Ohm.

I still wrap my head around this. Is it safe to just switch from ohm to kilo ohm? Can there be a double meaning of a value?

Hm, there is no other chance. Since the phydat module uses int16_t, there no other way than to scale down a value greater than +32,767 for SAUL. That's why the the value is divided by 1000 and the scale is set to 3 in that case. The phydat module then automatically converts the unit string from ohm to kohm as it does for other units. Even though the official unit would be kiloohm or also kilo ohm, that the way it is handled by the phydat module.

Oh I see now. So you still know if you read the value, if it is in ohms or kilo ohms, you just have to look at the scale then. Nevermind my comment then :)

@gschorcht gschorcht force-pushed the pr/bme680_pkg_driver branch from d367276 to a1e2f36 Compare March 12, 2020 07:52
Copy link
Member

@roberthartung roberthartung left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@janschlicht and I tested some more cases. I2C, SPI, SPI + I2C and two I2C devices -> works like expected!

ACK from my side.

@dylad
Copy link
Member Author

dylad commented Mar 12, 2020

@janschlicht and I tested some more cases. I2C, SPI, SPI + I2C and two I2C devices -> works like expected!

Wow that's nice !

@gschorcht gschorcht removed the CI: needs squashing Commits in this PR need to be squashed; If set, CI systems will mark this PR as unmergable label Mar 12, 2020
@roberthartung
Copy link
Member

@janschlicht and I tested some more cases. I2C, SPI, SPI + I2C and two I2C devices -> works like expected!

Wow that's nice !

Yes! Even though adding the second set of I2C Parameters wasn't too easy. But I don't see a neat way of changing it. I suggest leaving the driver as is for now, until (when/if) this becomes an issue!

@roberthartung
Copy link
Member

@gschorcht I think some of your requested changes prevent merge?

@gschorcht gschorcht added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR and removed CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Mar 12, 2020
@roberthartung
Copy link
Member

@MichelRottleuthner @gschorcht @PeterKietzmann We can merge?!

@MichelRottleuthner
Copy link
Contributor

@roberthartung yes sure go ahead!

@roberthartung roberthartung merged commit dc6665d into RIOT-OS:master Mar 12, 2020
@dylad
Copy link
Member Author

dylad commented Mar 12, 2020

Awesome ! Thanks for merging @roberthartung
and thanks for tackling this @gschorcht !

@dylad dylad deleted the pr/bme680_pkg_driver branch March 12, 2020 13:05
@gschorcht
Copy link
Contributor

Thank you all for contributing, reviewing, testing and for merging.

The merge of this PR is an important milestone, as it is a good example of how a vendor driver can be used package. There are other PRs that do this in the same way, for example #10363. With our Arduino compatibility layer in sys/arduino it even becomes possible to reuse Arduino driver libraries.

data->val[0] = _gas[dev_index];
data->scale = 0;
}
data->unit = UNIT_OHM;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ohm?

Copy link
Contributor

@gschorcht gschorcht Mar 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, the gas measurement is returned as the resistance of the gas sensitive layer. What ever it means. Unfortunately, the datasheet gives no explanation or hints on how the value has to be interpreted 😟

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They just recommend to use the BSEC to get IAQ.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have the import of the BSEC as package on my ToDo list.

Copy link
Member

@maribu maribu Mar 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@boschsensortec: Care to help out here? Could you give a formula how to convert that value into something useful?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The biggest chalange will be that each user of the BSCE has to accept the license before it is downloadable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: drivers Area: Device drivers Area: pkg Area: External package ports CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: new feature The issue requests / The PR implemements a new feature for RIOT
Projects
None yet
Development

Successfully merging this pull request may close these issues.