Issues compiling custom I2C driver

Hey,

Trying to compile a custom driver for an I2C device and running into issues getting the actual DT node to link with the driver at build time.

Specifically, (because it looks like it'll never go in) I'm trying to use this driver https://github.com/zephyrproject-rtos/zephyr/pull/48389 

My filesystem is set up as follows (other files omitted):

application_repo/
├─ drivers/
│  ├─ sensor/
│  │  ├─ mcp9600/
│  │  │  ├─ CMakeLists.txt
│  │  │  ├─ mcp9600.c
│  │  │  ├─ mcp9600.h
│  │  ├─ CMakeLists.txt
│  ├─ CMakeLists.txt
├─ dts/
│  ├─ bindings/
│  │  ├─ sensor/
│  │  │  ├─ microchip,mcp9600.yaml 
├─ boards/
│  ├─ arm/
│  │  ├─ board_name/
│  │  │  ├─ board_name.dts (and others) 
├─ src/
│  ├─ main.c
├─ CMakeLists.txt
├─ prj.conf

I have included all driver code in CMakeFiles correctly and removed all ifdef guards, and double checked the driver CMakeList is getting added with a fatal error test message.

I have added the device to the devicetree with this inside the i2c node (the other sensors work fine)

&i2c1 {
  label = "I2C1";
  clock-frequency = <100000>;
  compatible = "nordic,nrf-twim";
  status = "okay";
  pinctrl-0 = <&i2c1_default>;
  pinctrl-1 = <&i2c1_sleep>;
  pinctrl-names = "default", "sleep";

  lis2dh: lis2dh@19 {
    compatible = "st,lis2dh";
    label = "LIS2DH_I2C";
    reg = <0x19>;
    irq-gpios = <&gpio0 29 0>;
  };

  bme280: bme280@77 {
    compatible = "bosch,bme280";
    reg = <0x77>;
    label = "BME280_I2C";
  };

  mcp9600: mcp9600@67 {
    compatible = "microchip,mcp9600";
    label = "MCP9600_I2C";
    reg = <0x67>;
    status = "okay";
  };
};

I've tried also putting it in an overlay file just for this board as well.

It appears the node is getting compiled from DT as the following are all present in the build directory.

CONFIG_DT_HAS_MICROCHIP_MCP9600_ENABLED=y

set_target_properties(devicetree_target PROPERTIES "DT_NODE|/soc/peripheral@40000000/i2c@9000/mcp9600@67" TRUE)
set_target_properties(devicetree_target PROPERTIES "DT_NODELABEL|mcp9600" "/soc/peripheral@40000000/i2c@9000/mcp9600@67")
set_target_properties(devicetree_target PROPERTIES "DT_PROP|/soc/peripheral@40000000/i2c@9000/mcp9600@67|reg" "103;")
set_target_properties(devicetree_target PROPERTIES "DT_PROP|/soc/peripheral@40000000/i2c@9000/mcp9600@67|status" "okay")
set_target_properties(devicetree_target PROPERTIES "DT_PROP|/soc/peripheral@40000000/i2c@9000/mcp9600@67|compatible" "microchip,mcp9600;")
set_target_properties(devicetree_target PROPERTIES "DT_PROP|/soc/peripheral@40000000/i2c@9000/mcp9600@67|label" "MCP9600_I2C")
set_target_properties(devicetree_target PROPERTIES "DT_PROP|/soc/peripheral@40000000/i2c@9000/mcp9600@67|wakeup-source" "False")
set_target_properties(devicetree_target PROPERTIES "DT_REG|/soc/peripheral@40000000/i2c@9000/mcp9600@67|NUM" "1")
set_target_properties(devicetree_target PROPERTIES "DT_REG|/soc/peripheral@40000000/i2c@9000/mcp9600@67|ADDR" "0x67;")
set_target_properties(devicetree_target PROPERTIES "DT_REG|/soc/peripheral@40000000/i2c@9000/mcp9600@67|SIZE" "NONE;")

extern const struct device DEVICE_DT_NAME_GET(DT_N_S_soc_S_peripheral_40000000_S_i2c_9000_S_mcp9600_67); /* dts_ord_96 */

But in the output map, the driver is never actually present causing my app to not compile. The zephyr_pre0.map file stops at __device_dts_ord_95 and doesn't include the mcp9600. You can see it include the other sensors here.

 .z_device_POST_KERNEL90_
                0x000000000002c29c       0x18 zephyr/drivers/sensor/bme280/libdrivers__sensor__bme280.a(bme280.c.obj)
                0x000000000002c29c                __device_dts_ord_94
 .z_device_POST_KERNEL90_
                0x000000000002c2b4       0x18 zephyr/drivers/sensor/lis2dh/libdrivers__sensor__lis2dh.a(lis2dh.c.obj)
                0x000000000002c2b4                __device_dts_ord_95
                0x000000000002c2cc                __device_APPLICATION_start = .
 *(SORT_BY_NAME(SORT_BY_ALIGNMENT(.z_device_APPLICATION[0-9]_*)))
 *(SORT_BY_NAME(SORT_BY_ALIGNMENT(.z_device_APPLICATION[1-9][0-9]_*)))
                0x000000000002c2cc                __device_SMP_start = .
 *(SORT_BY_NAME(SORT_BY_ALIGNMENT(.z_device_SMP[0-9]_*)))
 *(SORT_BY_NAME(SORT_BY_ALIGNMENT(.z_device_SMP[1-9][0-9]_*)))
                0x000000000002c2cc                __device_end = .

I've slightly changed the driver code from the PR, but the DT_INST_FOREACH_STATUS_OKAY macro is still not finding any instances to compile, I get a "too few arguments in invocation of macro Z_FOR_LOOP_1" error on that line.

I have included the correct #define DT_DRV_COMPAT microchip_mcp9600 in the c file as well.

#define MCP9600_DEFINE(inst)                                                                                                              \
  static struct mcp9600_data mcp9600_data_##inst;                                                                                         \
  static const struct mcp9600_config mcp9600_config_##inst = {                                                                            \
      .i2c = I2C_DT_SPEC_INST_GET(inst),                                                                                                  \
  };                                                                                                                                      \
                                                                                                                                          \
  DEVICE_DT_INST_DEFINE(inst, mcp9600_init, NULL, &mcp9600_data_##inst, &mcp9600_config_##inst, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \
                        &mcp9600_api_functions);

DT_INST_FOREACH_STATUS_OKAY(MCP9600_DEFINE)

Do I need to put these files elsewhere? Every other sample I've looked at seems to follow this same structure. I'm on SDK 2.1.1 for reference. If needed I can share the full project in a confidential environment.

Thanks in advance Slight smile

Parents
  • Hi,

    I tried this, and seems to work.

    First I download https://patch-diff.githubusercontent.com/raw/zephyrproject-rtos/zephyr/pull/48389.diff and placed it in \v2.1.2\zephyr

    Then I apply the commit:

    Then for instance opened the lis2dh example project and added the following to the overlay file:

    &i2c0 {
        mcp9600: mcp9600@67 {
            compatible = "microchip,mcp9600";
            label = "MCP9600_I2C";
            reg = <0x67>;
            status = "okay";
          };
    };
    And in main.c I added microchip_mcp9600 similar to st_lis2dh:
    void main(void)
    {
    	const struct device *sensor = DEVICE_DT_GET_ANY(st_lis2dh);
    
    	if (sensor == NULL) {
    		printf("sensor No device found\n");
    		//return; // commented out to ensure the core run further.
    	}
    	if (!device_is_ready(sensor)) {
    		printf("sensorDevice %s is not ready\n", sensor->name);
    		//return; // commented out to ensure the core run further.
    	}
    
    	const struct device *sensor2 = DEVICE_DT_GET_ANY(microchip_mcp9600);
    
    	if (sensor2 == NULL) {
    		printf("sensor2 No device found\n");
    		return;
    	}
    	if (!device_is_ready(sensor2)) {
    		printf("sensor2 Device %s is not ready\n", sensor2->name);
    		return;
    	}
    Build and flash.
    I don't have any sensor connected, so I get the standard reply "is not ready".
    Best regards,
    Kenneth
  • A solution that doesn't require every one of my team to custom-patch zephyr for every out-of-tree sensor would be nice if possible. Understandable if nrf SDK isn't set up for this at the moment, however could this raised internally as a feature request?

Reply Children
No Data
Related