linguini1 opened a new pull request, #15789:
URL: https://github.com/apache/nuttx/pull/15789

   ## Summary
   
   Adds support for the LSM6DSO32 IMU by STM using the uORB framework. This 
only contains limited support for the I2C interface, interrupt and polling 
driven measurement and standard modes of operation (high performance ODRs). 
Features like interrupts besides DRDY, filtering, gesture recognition and 
acting as a bus master are not implemented.
   
   Accompanying documentation included.
   
   ## Impact
   
   This PR adds another available uORB driver to the NuttX sensor drivers.
   It impacts the build system by adding more Kconfig options and impacts the 
kernel with more driver source files.
   
   ## Testing
   
   All builds were performed on a Linux host. All testing was performed on an 
RP2040 MCU on a custom flight computer board.
   
   Below is the script that was used for testing.
   
   ```c
   #include <errno.h>
   #include <fcntl.h>
   #include <stdbool.h>
   #include <stdio.h>
   #include <stdlib.h>
   #include <unistd.h>
   
   #include <nuttx/sensors/lsm6dso32.h>
   #include <uORB/uORB.h>
   
   #define SAMPLE_FREQ 50
   #define ACCEL_NAME "sensor_accel0"
   #define GYRO_NAME "sensor_gyro0"
   
   int main(int argc, char **argv)
   {
     int err;
     unsigned frequency;
   
     int accel;
     struct sensor_accel accel_data;
   
     int gyro;
     struct sensor_gyro gyro_data;
   
     struct sensor_device_info_s info;
     bool update = false;
   
     printf("TESTING ACCELEROMETER IMPLEMENTATION\n");
   
     /* Get accelerometer metadata */
   
     const struct orb_metadata *accel_meta = orb_get_meta(ACCEL_NAME);
     if (accel_meta == NULL)
       {
         fprintf(stderr, "Failed to get metadata for %s\n", ACCEL_NAME);
         return EXIT_FAILURE;
       }
   
     /* Subscribe to accelerometer */
   
     accel = orb_subscribe(accel_meta);
     if (accel < 0)
       {
         fprintf(stderr, "Could not subsribe to %s: %d\n", ACCEL_NAME, errno);
         return EXIT_FAILURE;
       }
   
     /* Set sampling rate to 50Hz */
   
     err = orb_set_frequency(accel, SAMPLE_FREQ);
     if (err)
       {
         fprintf(stderr, "Wasn't able to set frequency to %uHz: %d\n",
                 SAMPLE_FREQ, err);
         return EXIT_FAILURE;
       }
   
     /* Show sampling rate */
   
     err = orb_get_frequency(accel, &frequency);
     if (err)
       {
         fprintf(stderr, "Could not verify frequency: %d\n", err);
         return EXIT_FAILURE;
       }
   
     printf("Sampling frequency is %uHz\n", frequency);
   
     /* Print sensor information */
   
     err = orb_ioctl(accel, SNIOC_GET_INFO, (unsigned long)&info);
     if (err < 0)
       {
         fprintf(stderr, "Could not get sensor information: %d", errno);
         return EXIT_FAILURE;
       }
   
     printf("Sensor: %s\n", info.name);
     printf("Manufacturer: %s\n", info.vendor);
     printf("Power consumption: %.2fmA\n", info.power);
     printf("Resolution: %.6f m/s^2\n", info.resolution);
     printf("Max range: %.2f m/s^2\n", info.max_range);
     printf("Min delay: %ld us\n", info.min_delay);
   
     /* Perform self-test */
   
     err = orb_ioctl(accel, SNIOC_SELFTEST, 0);
     if (err < 0)
       {
         fprintf(stderr, "Self test failed: %d\n", errno);
         return EXIT_FAILURE;
       }
     printf("Self test passed!\n");
   
     /* Loop forever while printing out tab separated data as X, Y, Z */
   
     for (int i = 0; i < 10;)
       {
         err = orb_check(accel, &update);
         if (err)
           {
             fprintf(stderr, "Failed to check for new accel_data: %d\n", err);
             continue;
           }
   
         /* Grab latest accel_data */
   
         if (update)
           {
             err = orb_copy(accel_meta, accel, &accel_data);
             if (err)
               {
                 fprintf(stderr, "Failed to get new accel_data: %d\n", err);
                 continue;
               }
   
             printf("%f\t%f\t%f\n", accel_data.x, accel_data.y, accel_data.z);
             i++;
           }
       }
   
     /* Subtract offset */
   
     float offsets[3] = {0.0f, -0.4f, 9.98f};
     err = orb_ioctl(accel, SNIOC_SET_CALIBVALUE, (unsigned long)offsets);
     if (err < 0)
       {
         fprintf(stderr, "Failed to set calibration values: %d", err);
         return EXIT_FAILURE;
       }
   
     printf("Offsets set: %.2f X, %.2f Y, %.2f Z\n", offsets[0], offsets[1],
            offsets[2]);
   
     /* Loop forever while printing out tab separated accel_data as X, Y, Z */
   
     for (int i = 0; i < 10;)
       {
         err = orb_check(accel, &update);
         if (err)
           {
             fprintf(stderr, "Failed to check for new accel_data: %d\n", err);
             continue;
           }
   
         /* Grab latest accel_data */
   
         if (update)
           {
             err = orb_copy(accel_meta, accel, &accel_data);
             if (err)
               {
                 fprintf(stderr, "Failed to get new accel_data: %d\n", err);
                 continue;
               }
   
             printf("%f\t%f\t%f\n", accel_data.x, accel_data.y, accel_data.z);
             i++;
           }
       }
   
     printf("TESTING GYROSCOPE IMPLEMENTATION\n");
   
     /* Get gyro metadata */
   
     const struct orb_metadata *gyro_meta = orb_get_meta(GYRO_NAME);
     if (gyro_meta == NULL)
       {
         fprintf(stderr, "Failed to get metadata for %s\n", GYRO_NAME);
         return EXIT_FAILURE;
       }
   
     /* Subscribe to gyroerometer */
   
     gyro = orb_subscribe(gyro_meta);
     if (gyro < 0)
       {
         fprintf(stderr, "Could not subsribe to %s: %d\n", GYRO_NAME, errno);
         return EXIT_FAILURE;
       }
   
     /* Set sampling rate to 50Hz */
   
     err = orb_set_frequency(gyro, SAMPLE_FREQ);
     if (err)
       {
         fprintf(stderr, "Wasn't able to set frequency to %uHz: %d\n",
                 SAMPLE_FREQ, err);
         return EXIT_FAILURE;
       }
   
     /* Show sampling rate */
   
     err = orb_get_frequency(gyro, &frequency);
     if (err)
       {
         fprintf(stderr, "Could not verify frequency: %d\n", err);
         return EXIT_FAILURE;
       }
   
     printf("Sampling frequency is %uHz\n", frequency);
   
     /* Print sensor information */
   
     err = orb_ioctl(gyro, SNIOC_GET_INFO, (unsigned long)&info);
     if (err < 0)
       {
         fprintf(stderr, "Could not get sensor information: %d", errno);
         return EXIT_FAILURE;
       }
   
     printf("Sensor: %s\n", info.name);
     printf("Manufacturer: %s\n", info.vendor);
     printf("Power consumption: %.2fmA\n", info.power);
     printf("Resolution: %.6f rad/s\n", info.resolution);
     printf("Max range: %.2f rad/s\n", info.max_range);
     printf("Min delay: %ld us\n", info.min_delay);
   
     /* Perform self-test */
   
     err = orb_ioctl(gyro, SNIOC_SELFTEST, 0);
     if (err < 0)
       {
         fprintf(stderr, "Self test failed: %d\n", errno);
         return EXIT_FAILURE;
       }
     printf("Self test passed!\n");
   
     /* Loop forever while printing out tab separated gyro_data as X, Y, Z */
   
     for (int i = 0; i < 10;)
       {
         err = orb_check(gyro, &update);
         if (err)
           {
             fprintf(stderr, "Failed to check for new gyro_data: %d\n", err);
             continue;
           }
   
         /* Grab latest gyro_data */
   
         if (update)
           {
             err = orb_copy(gyro_meta, gyro, &gyro_data);
             if (err)
               {
                 fprintf(stderr, "Failed to get new gyro_data: %d\n", err);
                 continue;
               }
   
             printf("%f\t%f\t%f\n", gyro_data.x, gyro_data.y, gyro_data.z);
             i++;
           }
       }
   
     /* Subtract offset */
   
     float offsets2[3] = {0.0f, -1.0f, 0.0f};
     err = orb_ioctl(gyro, SNIOC_SET_CALIBVALUE, (unsigned long)offsets2);
     if (err < 0)
       {
         fprintf(stderr, "Failed to set calibration values: %d", err);
         return EXIT_FAILURE;
       }
   
     printf("Offsets set: %.2f X, %.2f Y, %.2f Z\n", offsets2[0], offsets2[1],
            offsets2[2]);
   
     /* Loop forever while printing out tab separated gyro_data as X, Y, Z */
   
     for (int i = 0; i < 10;)
       {
         err = orb_check(gyro, &update);
         if (err)
           {
             fprintf(stderr, "Failed to check for new gyro_data: %d\n", err);
             continue;
           }
   
         /* Grab latest gyro_data */
   
         if (update)
           {
             err = orb_copy(gyro_meta, gyro, &gyro_data);
             if (err)
               {
                 fprintf(stderr, "Failed to get new gyro_data: %d\n", err);
                 continue;
               }
   
             printf("%f\t%f\t%f\n", gyro_data.x, gyro_data.y, gyro_data.z);
             i++;
           }
       }
   
     uint8_t id = 0;
     err = orb_ioctl(gyro, SNIOC_WHO_AM_I, (unsigned long)&id);
     if (err < 0)
       {
         fprintf(stderr, "Could not get WHOAMI value: %d\n", errno);
         return EXIT_FAILURE;
       }
     printf("WHOAMI: %02X\n", id);
   
     printf("Changing FSR of accelerometer to +/-32g\n");
     err = orb_ioctl(accel, SNIOC_SETFULLSCALE, LSM6DSO32_FSR_XL_32G);
     if (err < 0)
       {
         fprintf(stderr, "Could not get WHOAMI value: %d\n", errno);
         return EXIT_FAILURE;
       }
   
     printf("New measurement values:\n");
   
     for (int i = 0; i < 10;)
       {
         err = orb_check(accel, &update);
         if (err)
           {
             fprintf(stderr, "Failed to check for new accel_data: %d\n", err);
             continue;
           }
   
         /* Grab latest accel_data */
   
         if (update)
           {
             err = orb_copy(accel_meta, accel, &accel_data);
             if (err)
               {
                 fprintf(stderr, "Failed to get new accel_data: %d\n", err);
                 continue;
               }
   
             printf("%f\t%f\t%f\n", accel_data.x, accel_data.y, accel_data.z);
             i++;
           }
       }
   
     orb_unsubscribe(accel);
     orb_unsubscribe(gyro);
     return EXIT_SUCCESS;
   }
   ```
   
   This script tests the following:
   - Measurements are within the correct range for stationary board (i.e. 
9.81~m/s^2 in one axis, 0 in others and 0 angular velocity in any direction)
   - Self-tests for the sensors pass
   - Self-tests for the sensors do not affect subsequent measurements due to 
hysteresis
   - `WHOAMI` register is read and the value is correct
   - `SETFULLSCALE` changes the range of the sensor correctly and measurements 
are correct following this change
   - Measurement values are correctly modified by using `SET_CALIBVALUE`
   - Measurement frequency can be set
   - Changing FSR and ODR correctly changes the data in `get_info`
   - `get_info` returns the correct information depending on accel/gyro
   
   Here is the output of the script in interrupt-driven mode:
   
   ```console
   TESTING ACCELEROMETER IMPLEMENTATION
   Sampling frequency is 50Hz
   Sensor: LSM6DSO32
   Manufacturer: STMicro
   Power consumption: 0.55mA
   Resolution: 0.002392 m/s^2                                           
   Max range: 78.41 m/s^2                                               
   Min delay: 80000 us                                                  
   Self test passed!                                                    
   0.126820        -0.806385       19.946671                            
   0.126820        -0.806385       19.946671
   0.078963        -0.555138       13.189305
   0.021535        -0.023928       0.165106
   0.028714        -0.011964       0.052642
   0.033499        -0.007178       0.052642
   0.033499        -0.014357       0.057428
   0.035892        -0.016749       0.057428
   0.033499        -0.023928       0.055035
   0.031106        -0.019142       0.057428
   Offsets set: 0.00 X, -0.40 Y, 9.98 Z
   0.031106        -0.016749       0.059820
   0.031106        -0.009571       0.059820
   0.038285        -0.009571       0.052642
   0.031106        -0.014357       0.057428
   0.033499        -0.016749       0.057428
   0.026321        -0.021535       0.055035
   0.026321        -0.028714       0.052642
   0.028714        -0.023928       0.055035
   0.035892        -0.011964       0.059820
   0.035892        -0.016749       0.057428
   TESTING GYROSCOPE IMPLEMENTATION
   Sampling frequency is 50Hz
   Sensor: LSM6DSO32
   Manufacturer: STMicro
   Power consumption: 0.55mA
   Resolution: 0.000076 rad/s
   Max range: 2.50 rad/s
   Min delay: 80000 us
   Self test passed!
   0.001374        1.004123        0.001527
   0.001374        1.004123        0.001527
   0.001450        1.003894        0.001374
   0.001450        1.003818        0.001450
   0.001298        1.003894        0.001450
   0.000839        1.003742        0.001374
   0.000534        1.003894        0.001679
   0.000763        1.003742        0.001374
   0.000534        1.004047        0.001450
   0.000916        1.003971        0.001298
   Offsets set: 0.00 X, -1.00 Y, 0.00 Z
   0.001069        1.003818        0.001679
   0.001450        1.003818        0.001298
   0.001298        1.003818        0.001679
   0.001374        1.003665        0.001679
   0.001221        1.003894        0.001679
   0.001298        1.003665        0.001527
   0.001145        1.003589        0.001374
   0.000839        1.003589        0.001450
   0.000687        1.003742        0.001374
   0.000916        1.003894        0.001527
   WHOAMI: 6C
   Changing FSR of accelerometer to +/-32g
   New measurement values:
   0.035892        -0.016749       0.062213
   0.028714        -0.014357       0.064606
   0.028714        -0.019142       0.059820
   0.031106        -0.016749       0.069392
   0.031106        -0.014357       0.066999
   0.035892        -0.011964       0.059820
   0.035892        -0.011964       0.062213
   0.035892        -0.011964       0.059820
   0.033499        -0.014357       0.062213
   0.028714        -0.016749       0.066999
   ```
   
   Here is the output of the script in polling mode:
   
   ```console
   TESTING ACCELEROMETER IMPLEMENTATION
   Sampling frequency is 50Hz
   Sensor: LSM6DSO32
   Manufacturer: STMicro
   Power consumption: 0.55mA
   Resolution: 0.001196 m/s^2
   Max range: 39.20 m/s^2
   Min delay: 80000 us
   Self test passed!
   0.000000        0.000000        0.000000
   0.078963        -0.436692       9.978121
   0.076570        -0.429514       9.979318
   0.065803        -0.425925       9.979318
   0.076570        -0.445067       9.970942
   0.064606        -0.440282       9.970942
   0.053838        -0.443871       9.955389
   0.069392        -0.423532       9.978121
   0.074177        -0.423532       9.973335
   0.070588        -0.434299       9.986496
   Offsets set: 0.00 X, -0.40 Y, 9.98 Z
   0.059820        -0.130409       0.177070
   0.078963        -0.120838       0.180659
   0.075374        -0.117249       0.175873
   0.055035        -0.132802       0.165106
   0.072981        -0.120838       0.183052
   0.057428        -0.117249       0.163909
   0.080160        -0.108874       0.173481
   0.069392        -0.124427       0.177070
   0.069392        -0.116052       0.185445
   0.056231        -0.125624       0.180659
   TESTING GYROSCOPE IMPLEMENTATION
   Sampling frequency is 50Hz
   Sensor: LSM6DSO32
   Manufacturer: STMicro
   Power consumption: 0.55mA
   Resolution: 0.000076 rad/s
   Max range: 2.50 rad/s
   Min delay: 80000 us
   Self test passed!
   0.000000        0.000000        0.000000
   0.001221        0.003436        0.001527
   0.001069        0.003894        0.001450
   0.000992        0.003665        0.001450
   0.001221        0.003665        0.001450
   0.000839        0.003741        0.001527
   0.001298        0.003665        0.001603
   0.001450        0.003359        0.000839
   0.000916        0.003665        0.001374
   0.001603        0.003436        0.001069
   Offsets set: 0.00 X, -1.00 Y, 0.00 Z
   0.000534        1.003589        0.001298
   0.001450        1.003665        0.001450
   0.001603        1.003360        0.001527
   0.001679        1.003207        0.001374
   0.001374        1.003665        0.001603
   0.001756        1.003436        0.001298
   0.001298        1.003589        0.001603
   0.001527        1.003589        0.001527
   0.001603        1.003207        0.001221
   0.001069        1.003665        0.001450
   WHOAMI: 6C
   Changing FSR of accelerometer to +/-32g
   New measurement values:
   0.071785        -0.124427       0.212962
   0.033499        -0.033499       0.066999
   0.035892        -0.028714       0.066999
   0.035892        -0.033499       0.069392
   0.031106        -0.038285       0.066999
   0.040678        -0.023928       0.064606
   0.035892        -0.033499       0.071785
   0.033499        -0.031106       0.066999
   0.031106        -0.033499       0.066999
   0.031106        -0.038285       0.069392
   ```
   
   Here is the output of `uorb_listener` in polling mode (there is also a 
magnetometer on this board, only the accel and gyro readings are from this 
driver).
   
   ```console
   object_name:sensor_mag, object_instance:0
   object_name:sensor_gyro, object_instance:0
   object_name:sensor_accel, object_instance:0
   
sensor_mag(now:80440000):timestamp:80440000,x:-72.900002,y:0.150000,z:-242.700012,temperature:23.101563,s0
   
sensor_gyro(now:80450000):timestamp:80440000,x:-0.000076,y:0.000000,z:-0.000076,temperature:23.000000
   
sensor_accel(now:80450000):timestamp:80450000,x:0.041874,y:-0.029910,z:-0.010767,temperature:23.000000
   
sensor_mag(now:80470000):timestamp:80470000,x:-74.099998,y:0.450000,z:-241.800003,temperature:23.070313,s0
   
sensor_gyro(now:80470000):timestamp:80470000,x:-0.050701,y:-0.017944,z:0.028863,temperature:24.000000
   
sensor_accel(now:80480000):timestamp:80480000,x:0.011964,y:-0.002392,z:-0.297908,temperature:24.000000
   
sensor_mag(now:80500000):timestamp:80500000,x:-74.250000,y:-0.750000,z:-242.700012,temperature:23.066406,0
   
sensor_gyro(now:80500000):timestamp:80500000,x:-0.031994,y:-0.001985,z:-0.008704,temperature:24.000000
   
sensor_accel(now:80510000):timestamp:80510000,x:0.014357,y:-0.017946,z:0.025124,temperature:24.000000
   
sensor_mag(now:80530000):timestamp:80530000,x:-73.800003,y:0.450000,z:-243.449997,temperature:23.078125,s0
   Object name:sensor_mag0, recieved:4
   Object name:sensor_gyro0, recieved:3
   Object name:sensor_accel0, recieved:3
   Total number of received Message:10/10
   ```
   
   Here is the output of `uorb_listener` in interrupt-driven mode (there is 
also a magnetometer and barometer on this board, only the accel and gyro 
readings are from this driver).
   
   ```console
   nsh> uorb_listener -r 50 -n 10
   
   Mointor objects num:4
   object_name:sensor_mag, object_instance:0
   object_name:sensor_gyro, object_instance:0
   object_name:sensor_baro, object_instance:0
   object_name:sensor_accel, object_instance:0
   
sensor_mag(now:54820000):timestamp:54810000,x:-77.100006,y:0.150000,z:-243.600006,temperature:22.992188,s0
   
sensor_mag(now:54830000):timestamp:54830000,x:-75.599998,y:-0.150000,z:-243.300003,temperature:23.031250,0
   
sensor_gyro(now:54830000):timestamp:54820000,x:-0.039400,y:-0.034513,z:0.038331,temperature:23.000000
   
sensor_accel(now:54830000):timestamp:54820000,x:-0.007178,y:-0.093320,z:2.392835,temperature:23.000000
   
sensor_gyro(now:54840000):timestamp:54840000,x:-0.027107,y:-0.011377,z:-0.004886,temperature:24.000000
   
sensor_accel(now:54840000):timestamp:54840000,x:0.009571,y:-0.458228,z:9.941032,temperature:24.000000
   
sensor_baro(now:54850000):timestamp:54850000,pressure:505.600006,temperature:18.510000
   
sensor_mag(now:54850000):timestamp:54850000,x:-75.300003,y:0.600000,z:-243.300003,temperature:23.039063,s0
   
sensor_gyro(now:54860000):timestamp:54860000,x:0.126449,y:-0.159665,z:-0.030008,temperature:24.000000
   
sensor_accel(now:54860000):timestamp:54860000,x:0.039481,y:-0.513263,z:9.961371,temperature:24.000000
   Object name:sensor_mag0, recieved:3
   Object name:sensor_gyro0, recieved:3
   Object name:sensor_baro0, recieved:1
   Object name:sensor_accel0, recieved:3
   Total number of received Message:10/10
   ```
   
   Here are the system logs in debug mode when the driver is registered in 
polling mode:
   
   ```console
   lsm6dso32_register: LSM6DSO32 gyro using polling thread.
   lsm6dso32_register: LSM6DSO32 accel using polling thread.
   lsm6dso32_register: LSM6DSO32 driver registered!
   ```
   
   Here are the system logs in debug mode when the driver is registered in 
interrupt-driven mode:
   
   ```console
   lis2mdl_register: Registered LIS2MDL driver in interrupt driven mode.
   lis2mdl_register: Registered LIS2MDL driver.
   sensor_custom_register: Registering /dev/uorb/sensor_gyro0
   sensor_custom_register: Registering /dev/uorb/sensor_accel0
   lsm6dso32_register: LSM6DSO32 gyro interrupt handler attached to INT1.
   lsm6dso32_register: LSM6DSO32 accel interrupt handler attached to INT2.
   lsm6dso32_register: LSM6DSO32 driver registered!
   ```


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to