Common Application Framework and custom Sensor with Sensor Manager Module

Hi folks,

I'm trying to build an application with the CAF, and I'd like to use the sensor manager module, but I've run into a few problems -- any help would be appreciated.

I'll start with my environment and hardware setup, then I'll share the areas I'm getting stuck, plus a few key snippets of code. I'm happy to provide more information in a followup.

===== Environment =====

  • Windows 11 Machine (MINGW bash terminal)
  • VSCode 1.86 + NRF Connect for VSCode v2023.11.301
  • Toolchain and SDK for nrfConnect v2.5.0

===== Hardware =====

  • Xiao BLE Sense (nRF52840)
  • LSM6DS3-TR-C IMU (built-in) (compatible with lsm6dsl example)

===== Description of steps =====

I'm trying to modify the caf_sensor_manager example (nrf/samples/caf_sensor_manager), which uses both the sensor aggregator and sensor manager modules to run the imu on my xiao board.

The initial example runs perfectly well on both my test environment (nrf52840dk) and on the xiao ble sense (with the sensor_stub and agg added into the dts overlay).

I disabled the sensor aggregator in KConfig, and wrote a new module ("sensor_print.c") that subscribes to sensor_event. This also works as expected, and I can access the sensor data and print it to the console from that module.

Next, I wanted to add the LSM6DS3 to the example, so I started following the procedure listed here: https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/nrf/libraries/caf/sensor_manager.html#configuration

  1. Physically connect the sensor (done, sensor is embedded)
  2. Add and enable sensor in the device tree file.
    1. /* SNIPPET FROM xiao_ble_sense.dts */
      &i2c0 {
      	compatible = "nordic,nrf-twim";
      	/* Cannot be used together with spi0. */
      	status = "okay";
      	pinctrl-0 = <&i2c0_default>;
      	pinctrl-1 = <&i2c0_sleep>;
      	pinctrl-names = "default", "sleep";
      	clock-frequency = <I2C_BITRATE_FAST>;
      
      	lsm6ds3tr_c: lsm6ds3tr-c@6a {
      		compatible = "st,lsm6dsl";
      		reg = <0x6a>;
      		irq-gpios = <&gpio0 11 GPIO_ACTIVE_HIGH>;
      		status = "okay";
      	};
      };
    2. As far as I can tell from reading the docs, ADDING means including the node in the dts and ENABLING means including a status="okay" entry in that node
  3. Enable the CONFIG_CAF_SENSOR_MANAGER and CONFIG_SENSOR KConfig options
    1. These options are enabled in my xiao_ble_sense.conf KConfig overlay, which is included in my build
  4. Enable the sensor of your choice in KConfig.
    1. Here is where I run into trouble

===== The Trouble =====

When I open the KConfig GUI for step 4, I encounter the following

The chip is disabled, and the option is greyed out. Trying to determine why, I observe the following

It seems that KConfig is telling me that DT does NOT have the ST_LSM6DSL enabled.

When I try to follow that to its definition, I observe the following.

The option which is failing is DT_HAS_ST_LSM6DSL_ENABLED

This led me to investigate whether my device tree has the LSM6DSL enabled.

my xiao_ble_sense.dts has:

&i2c0 {
    compatible = "nordic,nrf-twim";
    /* Cannot be used together with spi0. */
    status = "okay";
    pinctrl-0 = <&i2c0_default>;
    pinctrl-1 = <&i2c0_sleep>;
    pinctrl-names = "default", "sleep";
    clock-frequency = <I2C_BITRATE_FAST>;

    lsm6ds3tr_c: lsm6ds3tr-c@6a {
        compatible = "st,lsm6dsl";
        reg = <0x6a>;
        irq-gpios = <&gpio0 11 GPIO_ACTIVE_HIGH>;
        status = "okay";
    };
};

Notably, a node for lsm6ds3tr_c with compatible st,lsm6dsl, and status "okay".

Something is incorrect here, or I should be able to enable the KConfig lsm6dsl options, but I can't find what it is for the life of me.

===== Behavior Post-Problem =====

Despite this, I can configure the sensor in the manner suggested by step 5 of the device manager docs.

I configure the channels and sample rate for my device and can build and flash the code with no trouble.

When the code runs, I get only 0's off the sensor. (though the sensor_state_event reports the device as having status "ready" when checked).

===== Past Success with this sensor =====

I have standalone code for operating the LSM6DSL, and I've adapted that code to also work with the application event manager (a global trigger thread in a dedicated module submits an "imu_event")

I'd like to use the prebuilt CAF modules to run this sensor, but can't at present.

===== Questions =====

  1. What am I doing wrong that I cannot enable the LSM6DSL in KConfig?
  2. What are my next steps for implementing this?

Thank you so much for any help you can provide.

Best,

    - Finn

Parents
  • Hi again folks

    More confusion on my end.

    grepping for the option being counted as "n" (DT_HAS_ST_LSM6DSL_ENABLED) reveals the following:

    in the build for xiao, DT_HAS_ST_LSM6DSL_ENABLED is set to "Y",

    and checking that file info, in build_xiao/zephyr/.config, I see the following:

    But the KConfig option is still disabled.

    What should I do to enable my sensor?

    ===== Edits =====

    Which, come to think of it, if this is enabled in the zephyr build, the KConfig option should be enabled by default.

    If that's not the problem, what is?

    Thanks again

        - Finn

  • Hi Finn, and sorry about the wait. Things are busy here on DevZone these days.

    Just letting you know that I am looking into it.

    I'm glad that you have a sample with the LSM6DS3 running though. The issue is typically to find the one thing lacking in the dts or in KConfig, now you can atleast compare etc.

    Regards,

    Elfving

  • Hi Elfving,

    No worries about the wait - your help is much appreciated.

    I don't know if it's helpful, but I'll share what I've explored in the meantime.

    I have 3 programs that enable the IMU on my device.

    ===== Program 1 "LSM6DSL" =====

    This is a pretty spartan application.

    I made minimal edits to the example (zephyr/samples/sensor/lsm6dsl)

    src/main.c stands alone.

    A notable change is that to enable the lsm6ds3tr-c imu, the enable pin must be configured as high drive.

        lsm6ds3tr-c-en {
            compatible = "regulator-fixed-sync", "regulator-fixed";
            enable-gpios = <&gpio1 8 (GPIO_OPEN_SOURCE | GPIO_PULL_UP | NRF_GPIO_DRIVE_H1)>;
            regulator-name = "LSM6DS3TR_C_EN";
            regulator-boot-on;
            startup-delay-us = <3000>;
        };

    This code runs and prints current accel and gyro vals to the console once every 2 seconds.

    ===== Program 2 "aem_with_lsm" =====

    This is a slightly more involved application.

    Built on top of the app_event_manager sample (nrf/samples/app_event_manager)

    It implements a module based on LSM6DSL that configures a sensor (ODR and Trigger settings) and handles the sensor interrupt callback as an event containing the relevant sensor data.

    This code runs and prints accel and gyro data to the console at the configured ODR

    ===== Program 3 "caf_sensor_manager" =====

    This is an even more involved application and is where I'm running into trouble.

    I'd like to use the CAF sensor tools to configure my device.

    Right now, I've determined that the sensor is in the "Active" state, but I'm only getting 0s off of it.

    When I configure the device in sm_sensor_config (sensor_manager_def.h), I use

    {
            .dev = DEVICE_DT_GET(DT_NODELABEL(lsm6ds3tr_c)),
            .event_descr = "lsm6ds3tr_c",
            .chans = accel_chan,
            .chan_cnt = ARRAY_SIZE(accel_chan),
            .sampling_period_ms = 200,
            .active_events_limit = 3,
    }

    And get the outputs of format:

    lsm6ds3tr_c |  data[0]:   0.00  |  data[1]:   0.00  |  data[2]:   0.00  |  
    lsm6ds3tr_c |  data[0]:   0.00  |  data[1]:   0.00  |  data[2]:   0.00  |

    From my custom module at src/modules/sensor_print.c

    if(is_sensor_event(aeh)){
           
            const struct sensor_event *event = cast_sensor_event(aeh);
            const int data_count = (int)(sensor_event_get_data_cnt(event));
            // printk("DATA_COUNT: %d\n", data_count);

            struct sensor_value *data_arr = sensor_event_get_data_ptr(event);
            printk("%s |  ", event->descr);
            for(int i=0; i<data_count; i++){
                float temp = (float)data_arr[i].val1 + (float)(data_arr[i].val2) / (1000000.0);
                printk("data[%d]: %*.*f  |  ",
                    i,
                    6, 2, temp //width, precision,
                );
            }
            printk("\n");
            return false;
        }

    ===== Diff Checker =====

    Using VSCode's compare tool (https://vscode.one/diff-vscode/)

    To compare the devicetree_generated.h between aem_with_lsm and caf_sensor_manager, I found no differences in the configuration of the two device trees except that the ordinal values in caf sensor manager were shifted later by a few by the insertion of an aggregator and some (unused) buttons.

    Comparing the .config from each, I observe the following changes

    AEM CAF
    SPI=y SPI not set
    - Aggregator , gpio-keys, sensor stub enabled
    - CAF and CAF Events enabled
    Reset on fatal error=y not set

    NRFX_SPI=y

    NRFX_SPI2=y

    not set
    # CONFIG_LSM6DSL_TRIGGER_NONE is not set
    CONFIG_LSM6DSL_TRIGGER_GLOBAL_THREAD=y
    # CONFIG_LSM6DSL_TRIGGER_OWN_THREAD is not set
    CONFIG_LSM6DSL_TRIGGER=y
    CONFIG_LSM6DSL_TRIGGER_NONE=y
    # CONFIG_LSM6DSL_TRIGGER_GLOBAL_THREAD is not set
    # CONFIG_LSM6DSL_TRIGGER_OWN_THREAD is not set

    But I'm not sure how to carry this into a solution

    Anyways thank you very much

        - Finn

  • Once again, sorry about the wait -_-

    When I open the KConfig GUI for step 4, I encounter the following

    The chip is disabled, and the option is greyed out. Trying to determine why, I observe the following

    It being grayed out like that, I think means that it is not directly assignable, it is assigned or selected by something else. I find it strange that it is not selected there though. But in either case, you can check what does get selected in final build in build/zephyr/.config. On my side here, when I simply add the dts additions you provided as an overlay file to either the xiao board or the nRF52840DK, I get DT_HAS_ST_LSM6DSL_ENABLED=y automatically in build/zephyr/.config. 

    FinnBiggs said:

    and checking that file info, in build_xiao/zephyr/.config, I see the following:

    And it seems that you are seeing this on your side as well. Great!

    What am I doing wrong that I cannot enable the LSM6DSL in KConfig?

    You are not getting any build errors, right?

    Regards,

    Elfving

  • Hi Elfving,

    I'm not getting build errors, but I'm also not getting sensor readings. The value coming off of the LSM6 sensor is a row of zeros at whatever rate gets set in the sensor_def.h file.

    I wrongly attributed those zero-readings as due to KConfig not enabling the sensor (since it was greyed out and unchecked), but that doesn't seem to be the case.

    I found this Reddit Post about someone having a similar issue.

    It seems that CAF Sensor manager does not configure the sensor's ODR, and as a result polling the sensor never outputs any values.

    My solution code is this:

    /*** in my custom module (sensor_print.c) ***/
    /*** app_event_handler snippet***/
    
        if(is_module_state_event(aeh))
        {
            const struct module_state_event *event = cast_module_state_event(aeh);
        
            if (check_state(event, MODULE_ID(main), MODULE_STATE_READY)) {
        		int ret = init_sensor();
                if (ret != 0){
                    printk("Error condn %d in imu setup", ret);
                }
        	}
            return false; 
        }
    
    /*** init_sensor method ***/
    
    static int init_sensor()
    {
    
        /* set accel/gyro sampling frequency to 104 Hz */
        printk("Init_Sensor \n");
        struct sensor_value odr_attr;
        const struct device *const lsm6 = DEVICE_DT_GET_ONE(st_lsm6dsl);
    
        odr_attr.val1 = 104; odr_attr.val2 = 0;
        if (sensor_attr_set(lsm6, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0)
        {
            printf("Cannot set sampling frequency for accelerometer.\n");         
            return 0;   
        }
    
        if (sensor_attr_set(lsm6, SENSOR_CHAN_GYRO_XYZ, SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) 
        { 
            printf("Cannot set sampling frequency for gyro.\n"); 
            return 0;   
        }
    
        return 0;
    }

    Which now gives me a data stream to work with.

    The difficult thing about this, though, is that in my sensor_manager_def.h, the sensor is configured to be polled at an integer number of milliseconds.

    A lot of sensors have a list of specific frequencies at which they can be configured to run. My sensor (LSM6DS3TR_C), for example, only supports speeds in the following list : {0, 1.6, 12.5, 26, 52, 104, 208, 416, 833, 1.66k, 3.33k, 6.66k}(Hz).

    The application I am trying to port to Zephyr uses a pre-trained neural net on 104Hz imu data, and it's not possible to generate that data using the CAF Sensor Manager. (since I can't set the sample period to 104Hz = 9.615ms).

    ===========

    I would really like to be able to set up the CAF sensor manager to handle 104Hz data acquisition. If it's possible to configure that polling to the frequency I need, that would be phenomenal.

    Unless I'm misunderstanding a part of this module, though, I don't think CAF Sensor Manager is the right fit for my project.

    Instead, I'll use my custom App Event Manager module to submit sensor events on a Data Ready trigger.

    Thank you for the help, I would not have gotten this far without it!

    Best,

        - Finn

  • Hello Finn, I am deeply sorry about the delay on this case. I've been overlooking this for quite a while now.

    Has there been any development on this from your side?

    Regards,

    Elfving

  • Hello Elfving,

    No worries, I opted to move on to a different system for managing my sensor. I've configured the LSM6DSL as a non-CAF device and am using the provided drivers to run it as a globally triggered thread, which makes use of the IRQ pin to trigger my sensor at the frequency I need it to run.

    If you have insight as to how I might use CAF sensor drivers to set my device to 104Hz, (or other useful configuration settings such as i2c control), I would be very interested and appreciative. If not, I think it would be reasonable to close this question.

    As an aside, for folks in a similar situation:

    I'd recommend the the lsm6dsl sample (zephyr/samples/sensor/lsm6dsl/ ) and then use the global trigger thread (CONFIG_LSM6DSL_TRIGGER_GLOBAL_THREAD=y) to feed events to the App Event Manager, then go from there with your application.

    My current challenge is implementing additional functionalities using direct i2c and that discussion is here:  LSM6DSL Driver Limitations - advice to expand functionality. 

    I'd be quite grateful if you have insight on that front

    Best regards,

        - Finn

Reply
  • Hello Elfving,

    No worries, I opted to move on to a different system for managing my sensor. I've configured the LSM6DSL as a non-CAF device and am using the provided drivers to run it as a globally triggered thread, which makes use of the IRQ pin to trigger my sensor at the frequency I need it to run.

    If you have insight as to how I might use CAF sensor drivers to set my device to 104Hz, (or other useful configuration settings such as i2c control), I would be very interested and appreciative. If not, I think it would be reasonable to close this question.

    As an aside, for folks in a similar situation:

    I'd recommend the the lsm6dsl sample (zephyr/samples/sensor/lsm6dsl/ ) and then use the global trigger thread (CONFIG_LSM6DSL_TRIGGER_GLOBAL_THREAD=y) to feed events to the App Event Manager, then go from there with your application.

    My current challenge is implementing additional functionalities using direct i2c and that discussion is here:  LSM6DSL Driver Limitations - advice to expand functionality. 

    I'd be quite grateful if you have insight on that front

    Best regards,

        - Finn

Children
  • FinnBiggs said:
    If you have insight as to how I might use CAF sensor drivers to set my device to 104Hz

    I had a talk with one of the developers who's been using CAF for the nRF Desktop, and I believe you are right. The sampling period is defined in ms, so you can get some reasonable sampling frequency, but not 104Hz exactly. 

    I can put in a request for CAF to support a higher accuracy if that is something you'd be interested in. What accuracy would you need for this sensor? If we, lets say, let you set a polling interval in µs instead of ms to get a better accuracy, would that work for you? Allowing you to set a certain polling frequency in hertz and try to do some calculations to avoid possible drift might be best.

    As you are not using CAF at the moment though I assume this request isn't a big priority for you?

    Regards,

    Elfving

  • Hi Elfving,

    Thank you for checking on this. For me to be able to use CAF, it would really need to handle an assigned sensor frequency and/or make use of the interrupt pin to submit a sensor event. Now that I'm a little more immersed in this ecosystem, it looks like CAF sensor is best for very simple devices (e.g. thermocouple) that don't have interrupt systems.

    The higher accuracy (uS) may be useful for some folks, but it doesn't cover my development plan later-on. (I'll be swapping the configured functionality of my sensor via i2c to detect different kinds of input e.g. tap, freefall).

    Yes, though -- I am not using CAF, so this is lowest-priority.

    Best,

        - Finn

  • Understood.

    FinnBiggs said:
    Now that I'm a little more immersed in this ecosystem, it looks like CAF sensor is best for very simple devices (e.g. thermocouple) that don't have interrupt systems.

    I'm no CAF expert, but my understanding is the opposite, that you would typically use CAF for more complex applications. Eg. the Asset Tracker

    I've made a request for this, although with a low priority. Let me know if there is anything else, or if you want me to up the priority on this.

    Regards,

    Elfving

Related