Skip to content

Conversation

avisconti
Copy link
Contributor

@avisconti avisconti commented Jul 31, 2024

A 16-bit value built using byte shifts and ORs from a given
couple of lsb and msb bytes will result to be the same on both
little-endian and big-endian architectures, e.g.

uint8_t lsb, msb;
int16_t val;

/* val is the same number on both le and be archs, but has
   different layout in memory */
val = (msb << 8) | lsb;

All the xyz_raw_get() APIs of stmemsc sensor module build the sensor
data using the above method and DO NOT hence require (it actually leads
to wrong values on big-endian machines) to use any le/be swap routines,
such as sys_le16_to_cpu().

Fix #75758

@avisconti avisconti added bug The issue is a bug, or the PR is fixing a bug priority: low Low impact/importance bug area: Drivers area: Sensors Sensors backport v3.7-branch Request backport to the v3.7-branch labels Jul 31, 2024
@avisconti avisconti added this to the v3.7.1 milestone Jul 31, 2024
@avisconti avisconti self-assigned this Jul 31, 2024
@avisconti avisconti requested a review from fabiobaltieri July 31, 2024 14:22
Copy link
Contributor

@yperess yperess left a comment

Choose a reason for hiding this comment

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

I'm a little confused, it's fine if we want access to the raw numbers, but the get function should convert things to the system endianess.

@avisconti
Copy link
Contributor Author

avisconti commented Aug 1, 2024

I'm a little confused, it's fine if we want access to the raw numbers, but the get function should convert things to the system endianess.

@yperess
I removed all the calls to sys_le16_to_cpu() when the data is already in the right system endianness. And this happens when the int16_t or int32_t are constructed from lsb/msb bytes with the shift operands. In some cases the constructions happens inside the raw_get() APIs, e.g. :

        iis3dhhc_acceleration_raw_get(data->ctx, raw_accel);
-       data->acc[0] = sys_le16_to_cpu(raw_accel[0]);
-       data->acc[1] = sys_le16_to_cpu(raw_accel[1]);
-       data->acc[2] = sys_le16_to_cpu(raw_accel[2]);
+       data->acc[0] = raw_accel[0];
+       data->acc[1] = raw_accel[1];
+       data->acc[2] = raw_accel[2];

with

int32_t iis3dhhc_acceleration_raw_get(const stmdev_ctx_t *ctx, int16_t *val)                                                                        
{
  uint8_t buff[6];
  int32_t ret; 

  ret = iis3dhhc_read_reg(ctx, IIS3DHHC_OUT_X_L_XL, buff, 6);
  val[0] = (int16_t)buff[1];
  val[0] = (val[0] * 256) + (int16_t)buff[0];
  val[1] = (int16_t)buff[3];
  val[1] = (val[1] * 256) + (int16_t)buff[2];
  val[2] = (int16_t)buff[5];
  val[2] = (val[2] * 256) + (int16_t)buff[4];

  return ret; 
}

If we do not remove the sys_le16_to_cpu() call, then in the big endian case the data will be swapped resulting in lsb/msb in the wrong place.
Let me know if it makes sense to you.

@avisconti
Copy link
Contributor Author

avisconti commented Aug 5, 2024

@yperess still any doubt?

@avisconti
Copy link
Contributor Author

Any feedback on this fix?

@fabiobaltieri fabiobaltieri requested a review from kartben August 7, 2024 14:25
@avisconti
Copy link
Contributor Author

@kartben do you possibly have any feedback on this fix? Thanks

@kartben
Copy link
Contributor

kartben commented Aug 13, 2024

@avisconti sorry, I am not really an expert on that stuff and was hoping maybe other sensor maintainers/collaborators could chime in to confirm it's the right approach. Thanks!

@avisconti
Copy link
Contributor Author

Even if big endian architectures are not so frequent I would like to see whether this approach is correct or not. Who can be added to the list of reviewers? @fabiobaltieri Fabio, do you know if there is anyone with some expertise on endianity? Thanks

Copy link
Member

@ubieda ubieda left a comment

Choose a reason for hiding this comment

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

If I understand this correctly: we're reverting these BE/LE omitting these sys_le16_to_cpu conversions because the ST HAL is already taking care of it.

May we capture that in the drivers code? Personally, I wouldn't have inferred it, had I not looked at the GH Issue.

@avisconti
Copy link
Contributor Author

If I understand this correctly: we're reverting these BE/LE omitting these sys_le16_to_cpu conversions because the ST HAL is already taking care of it.

Yes, correct.

May we capture that in the drivers code? Personally, I wouldn't have inferred it, had I not looked at the GH Issue.

Do you mean if we can reproduce it on a big endian system? If so, unfortunately I do not have access to such h/w setup.
And yes, the endianness it is always confusing me, but I think that in this case the issue is really there.

@MaureenHelm
Copy link
Member

The code changes look fine. It's clear that the byteswapping helpers aren't needed when the byte manipulation is done in the zephyr driver; what's a little less clear is when the ST HAL handles it under the hood. It would get repetitive to comment in every driver, so could you at least mention it in the commit message?

@ubieda
Copy link
Member

ubieda commented Aug 19, 2024

May we capture that in the drivers code? Personally, I wouldn't have inferred it, had I not looked at the GH Issue.

Do you mean if we can reproduce it on a big endian system? If so, unfortunately I do not have access to such h/w setup.

Sorry - I just meant if we could drop a comment explaining. Just what Maureen said.

@ubieda
Copy link
Member

ubieda commented Aug 19, 2024

As a side-note: A few months back I was able to compile/run big-endian on Linux with QEMU (using qemu-mips and mips-linux-gnu-gcc).

@avisconti
Copy link
Contributor Author

As a side-note: A few months back I was able to compile/run big-endian on Linux with QEMU (using qemu-mips and mips-linux-gnu-gcc).

Yeah, I was looking into something like that in fact, just to make some compile tests and clear my mind against any possible doubt. But I think that theory is pretty clear. So I will re-elaborate the commit message adding some more info as requested by Maureen and you.

@avisconti avisconti force-pushed the fix-75758-big-endian branch from 4275f06 to 3971d81 Compare August 26, 2024 17:23
@avisconti avisconti requested review from yperess and ubieda August 26, 2024 17:24
@avisconti
Copy link
Contributor Author

Added a better commit header and copied here on this PR as well.

A 16-bit value built using byte shifts and ORs from a given
couple of lsb and msb bytes will result to be the same on both
little-endian and big-endian architectures, e.g.

    uint8_t lsb, msb;
    int16_t val;

    /* val is the same number on both le and be archs, but has
       different layout in memory */
    val = (msb << 8) | lsb;

All the xyz_raw_get() APIs of stmemsc sensor module build the sensor
data using the above method and DO NOT hence require (it actually leads
to wrong values on big-endian machines) to use any le/be swap routines,
such as sys_le16_to_cpu().

Fix zephyrproject-rtos#75758

Signed-off-by: Armando Visconti <[email protected]>
@avisconti avisconti force-pushed the fix-75758-big-endian branch from 3971d81 to 62a6526 Compare August 27, 2024 08:14
@avisconti
Copy link
Contributor Author

repushed just to give a kick to ci to run again

@nashif nashif merged commit 9ea4cb9 into zephyrproject-rtos:main Aug 27, 2024
23 checks passed
@avisconti avisconti deleted the fix-75758-big-endian branch August 27, 2024 11:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: Drivers area: Sensors Sensors backport v3.7-branch Request backport to the v3.7-branch bug The issue is a bug, or the PR is fixing a bug priority: low Low impact/importance bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ST LIS2DUX12 driver: will not correctly read values on big-endian HW
7 participants