drivers: add driver for FXOS8700 3-axis accelerometer/magnetometer#8978
drivers: add driver for FXOS8700 3-axis accelerometer/magnetometer#8978aabadie merged 1 commit intoRIOT-OS:masterfrom
Conversation
9dda5b2 to
caffc42
Compare
|
Nice! This sensor can be found on the frdm-kw41z board. |
jnohlgard
left a comment
There was a problem hiding this comment.
Some comments below. I will test on the frdm-kw41z board. I can provide a board config for that particular setup when I get it running.
| */ | ||
| static const saul_reg_info_t fxos8700_saul_info[] = | ||
| { | ||
| HDC1000_SAUL_INFO |
drivers/fxos8700/fxos8700.c
Outdated
| DEBUG("[fxos8700] Could not read WHOAMI (%d)\n", rv); | ||
| return FXOS8700_NOBUS; | ||
| } | ||
| dev->whoami = config; |
There was a problem hiding this comment.
Is there any use case for saving this value? It seems like it is never used by the implementation.
drivers/include/fxos8700.h
Outdated
| } fxos8700_params_t; | ||
|
|
||
| /** | ||
| * @brief Device descriptor for a AT30TSE75x device |
There was a problem hiding this comment.
Copy pasta, and weird indentation
drivers/include/fxos8700.h
Outdated
| } fxos8700_t; | ||
|
|
||
| /** | ||
| * @brief Individual hybrid measurement |
drivers/include/fxos8700.h
Outdated
| uint8_t ydr:1; /*!< bit: 0 Start Conversion Event In */ | ||
| uint8_t xdr:1; /*!< bit: 1 Synchronization Event In */ | ||
| } bit; /*!< Structure used for bit access */ | ||
| uint8_t reg; /*!< Type used for register access */ |
There was a problem hiding this comment.
Here and everywhere else: use /** (and of course /**<) for doxygen comments in RIOT.
drivers/include/fxos8700.h
Outdated
| uint8_t xdr:1; /*!< bit: 1 Synchronization Event In */ | ||
| } bit; /*!< Structure used for bit access */ | ||
| uint8_t reg; /*!< Type used for register access */ | ||
| } FXOS8700_STATUS_Type; |
There was a problem hiding this comment.
This type, and the other bit fields below, are not actually used by the implementation.
Additionally, it is not required by a compiler to pack the bit fields in the struct, so this bit representation will not be guaranteed to match the hardware register bits. It is more robust to use bit mask macros or other bit operations in the implementation. The compiler should be smart enough to optimize the accesses in a good way when one of the operands is a numeric literal or static constant.
|
The cache does not handle multiple instances. |
|
Otherwise we will likely end up with various cache implementations in each sensor driver, with plenty of opportunity for mistakes and difficulties testing them in a reliable way. |
b22891e to
495a94a
Compare
|
I think it is a good verification to read the whoami register during init, to check that the device is responding and that the connected device is actually a FXOS8700 sensor by comparing the actual value against the expected value. Just that it does not need to be saved in the context struct. |
495a94a to
921de7a
Compare
|
@gebart. Thank you for the quick review! I resolved you comments. WHOAMI comparison is still here but its value is not saved now. Regarding the cache, I don't know how many sensors in RIOT are relevant (one sensor should provide multiple types of information). If this cache functionality is useful for many other sensors, we can think of generalizing it. But I think this should be another PR. |
52a33f5 to
933f2dd
Compare
drivers/fxos8700/fxos8700.c
Outdated
| int32_t acc_raw_z = (int32_t) ((data[4]<<6) | (data[5]>>2)); | ||
| acc->x = (int16_t)(acc_raw_x*244/1000); | ||
| acc->y = (int16_t)(acc_raw_y*244/1000); | ||
| acc->z = (int16_t)(acc_raw_z*244/1000); |
There was a problem hiding this comment.
Code style: add spaces around operators
There was a problem hiding this comment.
Also, for clarity it may be better to have parentheses around (raw * 244) / 1000, though it changes nothing in the generated code since the associativity is left to right for the multiplication and division operators.
drivers/fxos8700/fxos8700.c
Outdated
| if (mag) { | ||
| mag->x = (int16_t) ((data[6] <<8) | data[7]); | ||
| mag->y = (int16_t) ((data[8] <<8) | data[9]); | ||
| mag->z = (int16_t) ((data[10]<<8) | data[11]); |
There was a problem hiding this comment.
Spaces around bit shift operators
|
|
||
| int fxos8700_read_cached(const fxos8700_t *dev, fxos8700_measurement_t* acc, fxos8700_measurement_t* mag) | ||
| { | ||
| uint32_t now = xtimer_now_usec(); |
There was a problem hiding this comment.
Optional: It may be less computationally expensive to use xtimer_now and convert the renew interval to ticks instead, since you can precompute that us to tick conversion at compilation time rather than do a conversion from ticks to us in every read. See this as an optional comment, and maybe just remember for future drivers, I assume this function will be called somewhat infrequently since the renew interval is set to 1 second.
There was a problem hiding this comment.
Good point! I will remember for the future driver implementations which require frequent xtimer access 👍
|
Are you using this sensor externally or integrated on any dev board? Do you have any updated board configurations you want to add here? |
aabadie
left a comment
There was a problem hiding this comment.
Rough pass of review. I found problems with doxygen and style and have minor comments in the driver implementation (return code, defines, etc)
drivers/fxos8700/fxos8700_saul.c
Outdated
| */ | ||
|
|
||
| /** | ||
| * @ingroup driver_fxos8700 |
There was a problem hiding this comment.
should be drivers_fxos8700
drivers/fxos8700/fxos8700.c
Outdated
| static int fxos8700_read_regs(fxos8700_t* dev, uint8_t reg, uint8_t* data, size_t len) | ||
| { | ||
| i2c_acquire(dev->p.i2c); | ||
| if(i2c_read_regs(dev->p.i2c, dev->p.addr, reg, (char*) data, len) <= 0) { |
There was a problem hiding this comment.
missing space after if here and in other places below
drivers/fxos8700/fxos8700.c
Outdated
| return FXOS8700_BUSERR; | ||
| } | ||
|
|
||
| while(!(ready & 0x08)) { |
There was a problem hiding this comment.
missing space after while here and below. Maybe unscrustify the file ?
drivers/fxos8700/fxos8700.c
Outdated
| @@ -0,0 +1,205 @@ | |||
| /* | |||
| * Copyright (C) 2017 UC Berkeley | |||
drivers/fxos8700/fxos8700_saul.c
Outdated
| @@ -0,0 +1,58 @@ | |||
| /* | |||
| * Copyright (C) 2017 Hyung-Sin Kim | |||
drivers/include/fxos8700.h
Outdated
| } | ||
| #endif | ||
|
|
||
| /** @} */ |
There was a problem hiding this comment.
This line should be after #endif below
drivers/fxos8700/fxos8700.c
Outdated
| if (config != FXOS8700_WHO_AM_I_VAL) { | ||
| i2c_release(dev->p.i2c); | ||
| DEBUG("[fxos8700] WHOAMI is wrong (%2x)\n", config); | ||
| return FXOS8700_NOBUS; |
There was a problem hiding this comment.
Maybe add another return status for this case ? Something line FXOS8700_NODEV ?
drivers/fxos8700/fxos8700.c
Outdated
| /* Configure the ODR to maximum (400Hz in hybrid mode) */ | ||
| config = 0x00; | ||
| if (fxos8700_write_regs(dev, FXOS8700_REG_CTRL_REG1, &config, 1) != FXOS8700_OK) { | ||
| return FXOS8700_NOBUS; |
There was a problem hiding this comment.
Should it be FXOS8700_BUSERR instead ? Here and in other places below.
drivers/fxos8700/fxos8700.c
Outdated
| #define FXOS8700_RENEW_INTERVAL 1000000ul | ||
| #endif | ||
|
|
||
| #define ACCEL_ONLY_MODE 0x00 |
There was a problem hiding this comment.
Maybe put parenthesis around these hexadecimal defines
| i2c_acquire(dev->p.i2c); | ||
| if(i2c_read_regs(dev->p.i2c, dev->p.addr, reg, (char*) data, len) <= 0) { | ||
| DEBUG("[fxos8700] Can't read register 0x%x\n", reg); | ||
| i2c_release(dev->p.i2c); |
There was a problem hiding this comment.
You could use for example:
#define DEV_I2C (dev->p.i2c)at the beginning of this file. Same with addr attribute and maybe others
There was a problem hiding this comment.
I followed the style of the current HDC1000 implementation. Is this style a strict requirement?
There was a problem hiding this comment.
No, that was more a suggestion for future maintenance, technically it doesn't change anything.
72211b9 to
b7484c4
Compare
drivers/fxos8700/fxos8700.c
Outdated
| #define MAG_ONLY_MODE (0x01) | ||
| #define HYBRID_MODE (0x03) | ||
|
|
||
| static fxos8700_measurement_t acc_cached, mag_cached; |
There was a problem hiding this comment.
Instead of those static variable; why no having them as attributes of fxos8700_t ?
Because otherwise this will be a problem with multiple instances of this device as already reported by @gebart here.That could be a best temporary solution until we have a module for managing cache.
Maybe saul could do it ?
There was a problem hiding this comment.
I agree and updated this PR reflecting this comment. Thanks!
ef2c5c5 to
7e388d3
Compare
drivers/include/fxos8700.h
Outdated
| * @brief Device descriptor for a FXOS8700 device | ||
| */ | ||
| typedef struct { | ||
| fxos8700_measurement_t acc_cached; |
There was a problem hiding this comment.
The attributes of this struct are missing documentation, same with the fxos8700_measurement_t struct
|
Could you also add a test application ? |
ab7d496 to
64b1963
Compare
4b747d3 to
2e6a557
Compare
1098e15 to
9195661
Compare
|
@gebart, I checked that it works at least in my case (hamilton), as below. Dev: fxos8700 Type: SENSE_ACCEL Can you retry? |
|
I will check again tomorrow |
|
My frdm-kw41z is giving strange values, I will try again with a frdm-k22f board tomorrow |
jnohlgard
left a comment
There was a problem hiding this comment.
I found the source of my problems. Negative values of acceleration are not handled correctly, see my comment below regarding the bit shift
drivers/fxos8700/fxos8700.c
Outdated
| } | ||
|
|
||
| /* Read all data at once */ | ||
| if (fxos8700_read_regs(dev, FXOS8700_REG_OUT_X_MSB, &data[0], 12)) { |
There was a problem hiding this comment.
change magic 12 into sizeof something or a macro definition.
drivers/fxos8700/fxos8700.c
Outdated
| if (acc) { | ||
| int32_t acc_raw_x = (int32_t) ((data[0] << 6) | (data[1] >> 2)); | ||
| int32_t acc_raw_y = (int32_t) ((data[2] << 6) | (data[3] >> 2)); | ||
| int32_t acc_raw_z = (int32_t) ((data[4] << 6) | (data[5] >> 2)); |
There was a problem hiding this comment.
the shift of 6 loses the sign bit
There was a problem hiding this comment.
This gives reasonable results for negative numbers:
int32_t acc_raw_x = (int16_t) ((data[0] << 8) | data[1]) >> 2;
int32_t acc_raw_y = (int16_t) ((data[2] << 8) | data[3]) >> 2;
int32_t acc_raw_z = (int16_t) ((data[4] << 8) | data[5]) >> 2;
acc->x = (int16_t) ((acc_raw_x * 244) / 1000);
acc->y = (int16_t) ((acc_raw_y * 244) / 1000);
acc->z = (int16_t) ((acc_raw_z * 244) / 1000);
drivers/fxos8700/fxos8700.c
Outdated
| int32_t acc_raw_z = (int32_t) ((data[4] << 6) | (data[5] >> 2)); | ||
| acc->x = (int16_t) ((acc_raw_x * 244) / 1000); | ||
| acc->y = (int16_t) ((acc_raw_y * 244) / 1000); | ||
| acc->z = (int16_t) ((acc_raw_z * 244) / 1000); |
There was a problem hiding this comment.
You are really discarding quite a lot of bits of precision with this division. You could just as well configure the sensor to +/- 8 g range and use x * 976 / 1000 instead and get the benefit of an increased sensor range without any difference in accuracy compared to the current implementation
80b99b8 to
48d3bd9
Compare
|
@gebart, thank you for improving this driver!
|
48d3bd9 to
ba6ef8b
Compare
aabadie
left a comment
There was a problem hiding this comment.
Codewise it looks good now.
jnohlgard
left a comment
There was a problem hiding this comment.
My comment regarding the lost bits when using 2 or 4 g full scale range still applies, but I don't intend to block this PR just for that.
|
Optionally, change the division from 1000 to 100 and change the SAUL scale from -3 to -4 when +/- 2 G range is selected |
ba6ef8b to
67673b2
Compare
67673b2 to
beaf08b
Compare
|
@gebart, I updated, but I think this driver does not lose any bit regardless of resolution setting since it provides "FXOS8700_USE_ACC_RAW_VALUES" mode. |
|
👍 |
|
@Hyungsin in future PRs, please create fixup/squash commits for changes you add after the initial review to make the review process easier. You can amend typos or other minor corrections, but for anything a little bigger, such as when you added the different scaling factor configurations in this PR, use a separate commit. Then squash the commits when the reviewer requests it. It makes it easier for the reviewer to know what has changed between iterations. |
|
@gebart, good point. I should keep this in mind! |
|
All green here. Let's merge. |
This PR provides a driver for the FXOS8700 sensor, which reads 3-axis acceleration and magnetic field.
Driver implementation style is similar to HDC1000 driver.