embassy-rs / embassy

Modern embedded framework, using Rust and async.
https://embassy.dev
Apache License 2.0
5.33k stars 736 forks source link

Sensor output depends on awaits order #3390

Open OlivierLemoine opened 2 days ago

OlivierLemoine commented 2 days ago

Hi, first of all, Embassy has been great for me and my team and I would like to thank you for that. However, I have found a strange thing on our project:

Depending on the order on which we wait for tasks, we have a coherent sensor reading or not:

unwrap!(spawner.spawn(sensor_reading(stts22h)));
unwrap!(spawner.spawn(pipe_data_to_usb(p.USB, p.PA12, p.PA11)));

If sensor_reading is called first, the temperature readings are coherent (~20℃). If pipe_data is called first, the temperature readings do not make sense and it depends on the compilation:

My colleague and I have managed to reproduce this consistently on each other's hardware.

Our hardware is an ASTRA1B from ST Electronics featuring on board sensors (including the stts22h temperature sensor) and an ST32WB55G.

I got an MVP repo here : https://github.com/432-Technologies/embassy-task-order

My team and I can give you all the help you need.

Thank you.

Dirbaio commented 2 days ago

It's possible the i2c sensor has some timing requirements (like wait at least X between doing A and B) that you accidentally meet if you run the tasks in one order and not the other, could be fixable by adding delays.

it's also possible it's a bug in async i2c (that part of the code has been a bit troublesome historically). Can you try changing to blocking i2c and see if it still happens? If that's the case then maybe oscilloscope traces could help see what's async i2c doing "wrong".

OlivierLemoine commented 2 days ago

Indeed, the blocking version does not show the same behavior.

However, what still surprise me is the fact that when requesting the ID of the sensor, it is always valid, no matter the order.

Does it have something to do with the fact that the ID is an u8 and the temperature value is a u16 (meaning 2 bytes requested) ?

Dirbaio commented 2 days ago

it should work. blocking and async i2c should behave exactly the same, if they dont' it's likely a bug. (it could also be that the chip is timing sensitive, and changing blocking<->async changes the timing)

to confirm you'd have to look at the i2c signals with a logic analyzer / oscilloscope and see if they look good...