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

drivers: sensor: add bosch bmm350 driver #85174

Merged
merged 1 commit into from
Mar 20, 2025

Conversation

maxd-nordic
Copy link
Contributor

@maxd-nordic maxd-nordic commented Feb 4, 2025

upstream Bosch's BMM350 driver.
this is necessary for the thingy91x.

@@ -0,0 +1,8 @@
# Copyright (c) 2024 Bosch Sensortec GmbH
Copy link
Collaborator

Choose a reason for hiding this comment

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

Update the copyright year

Suggested change
# Copyright (c) 2024 Bosch Sensortec GmbH
# Copyright (c) 2025 Bosch Sensortec GmbH

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not working for Bosch, I'm just integrating their code. Not sure if that's something I'm allowed to do.

Copy link
Collaborator

Choose a reason for hiding this comment

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

What do you mean with "their code", if you copied code then you should adhere to the original code's copyright. Otherwise if you produced this code, you shouldn't be putting Bosch's copyright, but your own.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Bosch wrote this code, including the copyright headers and sent it to me. I was told it's okay to share, so I'm doing that here.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I guess this is OK? @carlescufi

Copy link
Member

Choose a reason for hiding this comment

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

Bosch needs to clarify this directly I guess.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@kegov Could you confirm?

Copy link

Choose a reason for hiding this comment

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

@maxd-nordic & @gmarull , I confirm.

Copy link
Member

@gmarull gmarull left a comment

Choose a reason for hiding this comment

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

this PR contains many portions copied from https://github.com/boschsensortec/BMM350_SensorAPI, which is BSD-3 licensed. Unless Bosch explicitly says they are happy to share this code as Apache-2.0, this PR can't go in.

BMM350_GET_BITS(rx_buf[2], BMM350_PMU_CMD_VALUE);
}
} else {
ret = BMM350_E_NULL_PTR;
Copy link
Member

Choose a reason for hiding this comment

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

-1 on custom error handling schemes here, this is copy&paste from their "hal"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is this a blocker?

Copy link
Member

Choose a reason for hiding this comment

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

yes

Comment on lines 86 to 88
report_mag[0] = mag[0].val1 + mag[0].val2 / 100.0;
report_mag[1] = mag[1].val1 + mag[1].val2 / 100.0;
report_mag[2] = mag[2].val1 + mag[2].val2 / 100.0;
Copy link
Member

Choose a reason for hiding this comment

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

something's wrong if you can't use sensor_value_to_double/float

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll fix the order of magnitude here

Comment on lines 45 to 60
/* Setting scale in G, due to loss of precision if the SI unit m/s^2
* is used
*/
sampling_freq.val1 = 25; /* Hz from 0.78 to 400*/
sampling_freq.val2 = 0; /*not use*/
oversampling.val1 = 1; /*1 Normal mode 0suspend mode*/
oversampling.val2 = 0; /*not use*/
sensor_attr_set(dev, SENSOR_CHAN_MAGN_XYZ,
SENSOR_ATTR_SAMPLING_FREQUENCY,
&sampling_freq);
/* Set sampling frequency last as this also sets the appropriate
* power mode. If already sampling, change to 0.0Hz before changing
* other attributes
*/
sensor_attr_set(dev, SENSOR_CHAN_MAGN_XYZ, SENSOR_ATTR_OVERSAMPLING,
&oversampling);
Copy link
Member

Choose a reason for hiding this comment

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

doing pseudo-power management here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

which change would you like me to do here?

Copy link
Member

Choose a reason for hiding this comment

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

how does oversampling relate to "1 Normal mode 0suspend mode", this looks wrong

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is just odd naming. It does match the chip's datasheet though. The driver only supports "normal mode" and "suspend mode", but you could theoretically put other values in the register.

Copy link
Member

Choose a reason for hiding this comment

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

This still looks very wrong, this chip does support oversampling mode, I gave comments in other area, that it should be able to be configured

Copy link
Contributor Author

Choose a reason for hiding this comment

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

you can configure oversampling with this. there is just a special check for the value "0", that turns the chip into low power mode. What change do I need to make here?

@maxd-nordic
Copy link
Contributor Author

this PR contains many portions copied from https://github.com/boschsensortec/BMM350_SensorAPI, which is BSD-3 licensed. Unless Bosch explicitly says they are happy to share this code as Apache-2.0, this PR can't go in.

It was Bosch who gave me these files with the Apache-2.0 headers.

@maxd-nordic
Copy link
Contributor Author

Hey folks! Thanks for the reviews! Please have another look. I think I caught all of the change requests.

@maxd-nordic maxd-nordic force-pushed the bmm350-upstream branch 2 times, most recently from f98c10a to 71d6a76 Compare March 3, 2025 15:44
}
static uint8_t acc_odr_to_reg(const struct sensor_value *val)
{
double odr = sensor_value_to_double((struct sensor_value *)val);
Copy link
Member

Choose a reason for hiding this comment

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

Do you have to use double here? This could bring in a lot of code and cause some overhead for FPU-less processors

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Please don't make me rework this whole driver. Other Bosch drivers that are already part of Zephyr do the same.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

A later PR can change this behavior for all drivers that have it.

Copy link
Member

@XenuIsWatching XenuIsWatching Mar 19, 2025

Choose a reason for hiding this comment

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

I'm not sure why you need to rework this whole driver? You can easily do this with UQ27.5 fixed point format... might as well start somewhere with not using doubles then

static uint8_t acc_odr_to_reg(const struct sensor_value *val)
{
	/* Convert sensor_value to fixed-point UQ27.5 format */
	uint32_t fixed_odr = (val->val1 << 5) + (((uint64_t)val->val2 * 32) / 1000000);

	uint8_t reg = BMM350_DATA_RATE_100HZ;

	if ((fixed_odr >= 25) && (fixed_odr <= 50)) {
		/* 0.78125Hz to 1.5625Hz */
		reg = BMM350_DATA_RATE_1_5625HZ;
	} else if ((fixed_odr > 50) && (fixed_odr <= 100)) {
		/* 1.5625Hz to 3.125Hz */
		reg = BMM350_DATA_RATE_3_125HZ;
	} else if ((fixed_odr > 100) && (fixed_odr <= 200)) {
		/* 3.125Hz to 6.25Hz */
		reg = BMM350_DATA_RATE_6_25HZ;
	} else if ((fixed_odr > 200) && (fixed_odr <= 400)) {
		/* 6.25Hz to 12.5Hz */
		reg = BMM350_DATA_RATE_12_5HZ;
	} else if ((fixed_odr > 800) && (fixed_odr <= 1600)) {
		/* 12.5Hz to 25Hz */
		reg = BMM350_DATA_RATE_25HZ;
	} else if ((fixed_odr > 1600) && (fixed_odr <= 3200)) {
		/* 25Hz to 50Hz */
		reg = BMM350_DATA_RATE_50HZ;
	} else if ((fixed_odr > 3200) && (fixed_odr <= 6400)) {
		/* 50Hz to 100Hz */
		reg = BMM350_DATA_RATE_100HZ;
	} else if ((fixed_odr > 6400) && (fixed_odr <= 12800)) {
		/* 100Hz to 200Hz */
		reg = BMM350_DATA_RATE_200HZ;
	} else if ((fixed_odr > 12800) && (fixed_odr <= 25600)) {
		/* 200Hz to 400Hz */
		reg = BMM350_DATA_RATE_400HZ;
	} else if (fixed_odr > 25600) {
		/* 400Hz */
		reg = BMM350_DATA_RATE_400HZ;
	}
	return reg;
}

Copy link
Member

Choose a reason for hiding this comment

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

actually, on second thought, there are a few different ways to approach this such as with sensor_value_to_micro... but I have to agree with @teburd in another comment about this fuzzy approach, I'm reverting my block on this now

Comment on lines 749 to 746
if ((odr == BMM350_DATA_RATE_400HZ) && (performance >= BMM350_AVERAGING_2)) {
performance_fix = BMM350_NO_AVERAGING;
} else if ((odr == BMM350_DATA_RATE_200HZ) && (performance >= BMM350_AVERAGING_4)) {
performance_fix = BMM350_AVERAGING_2;
} else if ((odr == BMM350_DATA_RATE_100HZ) && (performance >= BMM350_AVERAGING_8)) {
performance_fix = BMM350_AVERAGING_4;
}
Copy link
Member

Choose a reason for hiding this comment

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

suggestion: it may be good to print a LOG_WRN about how it's adjusting the oversampling rate from what the application tried to specify

thread_stack_size = 1024
source "drivers/sensor/Kconfig.trigger_template"

config BMM350_SAMPLING_RATE_RUNTIME
Copy link
Member

Choose a reason for hiding this comment

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

I can't see where this is used

Comment on lines 26 to 38
config BMM350_THREAD_PRIORITY
int "Own thread priority"
depends on BMM350_TRIGGER_OWN_THREAD
default 10
help
Priority of the thread used by the driver to handle interrupts.

config BMM350_THREAD_STACK_SIZE
int "Own thread stack size"
depends on BMM350_TRIGGER_OWN_THREAD
default 1024
help
Stack size of thread used by the driver to handle interrupts.
Copy link
Member

Choose a reason for hiding this comment

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

These look like they are defined twice as they are already defined with the Kconfig.trigger_template

reg = BMM350_AVERAGING_8;
break;
default:
LOG_ERR("unsupported oversampling rate");
Copy link
Member

Choose a reason for hiding this comment

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

shouldn't this return a status code (-EINVAL) and not set to a 'default' value if a wrong value is tried, then of course bubble up the error code

@maxd-nordic maxd-nordic force-pushed the bmm350-upstream branch 2 times, most recently from 7c4e77a to afa35aa Compare March 14, 2025 14:55
@gmarull
Copy link
Member

gmarull commented Mar 17, 2025

will let sensor maintainers/collaborators finish the review

@teburd teburd requested review from afontaine-invn and removed request for kegov and yasinustunerg March 17, 2025 14:04
teburd
teburd previously requested changes Mar 17, 2025
Copy link
Collaborator

@teburd teburd left a comment

Choose a reason for hiding this comment

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

Please, no part specific samples. Either make the sample generic for the task or add overlays to existing samples (magn_polling/magn_trig) for the board+part you want to use.


uint8_t reg = BMM350_DATA_RATE_100HZ;

if ((odr >= 0.78125) && (odr <= 1.5625)) {
Copy link
Collaborator

@teburd teburd Mar 17, 2025

Choose a reason for hiding this comment

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

I really don't love these fuzzy ODR setters, but I know there's precedence in the tree for them.

What's weird about this idea is that you can set arbitrary ODRs and from the API response and call it may seem as if any ODR is possible because hey, it didn't fail!

The reality is the actual ODR is set to something else entirely... and unless you go read this attribute back you don't know.

Maybe ODR should be something we do more explicitly rather than with attributes. It's incredibly common, typically gets tied to some sample power mode (toggled/always on are common...) and really should give back the ODR in use rather than simply accepting any ODR and replying back with "Ok!"

TL;DR no changes required but I don't love this

return rslt;
}

static int bmm350_sample_fetch(const struct device *dev, enum sensor_channel chan)
Copy link
Collaborator

Choose a reason for hiding this comment

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

What happens if the sensor is suspended through PM API? We don't have a solid answer for this today with the fetch+get API other than the application doing the power management reference counting on the sensors. But if the device is suspended and this is called, what happens?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

All registers are available in suspend mode. They will not update when no measurements are run. Do you need this to be changed?

Copy link
Collaborator

@teburd teburd Mar 17, 2025

Choose a reason for hiding this comment

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

No, but this might be surprising behavior to a caller, maybe worth a warning log if CONFIG_DEBUG or something is toggled?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think this behaves as it should with the PM model.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It doesn't make sense to me to clutter the driver with this. Other drivers will also just try to fetch, no matter if the power mode allows for it.

Copy link
Collaborator

Choose a reason for hiding this comment

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

So will the registers continue to hold a reading from some past moment in time then or be all zeros?

Add driver for Bosch BMM350 magnetometer sensor.

Signed-off-by: Maximilian Deubel <maximilian.deubel@nordicsemi.no>
@maxd-nordic
Copy link
Contributor Author

@teburd @XenuIsWatching @yperess Could you please unblock this PR?

Copy link
Member

@XenuIsWatching XenuIsWatching left a comment

Choose a reason for hiding this comment

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

Copy link
Member

@XenuIsWatching XenuIsWatching left a comment

Choose a reason for hiding this comment

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

I changed my mind after think it about it more on the last comment,

lgtm now

@teburd teburd dismissed their stale review March 19, 2025 15:21

No blocking issues left, though I think some things need to be clarified in how sensor drivers should be written.

@carlescufi
Copy link
Member

Agreed to @MaureenHelm to add @teburd and @yperess as assignees as she is on vacation this week

@carlescufi carlescufi merged commit 878ab53 into zephyrproject-rtos:main Mar 20, 2025
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.