This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Zephyr nRF5340 SPI CS pin stay LOW while initializing another spi device in the bus

I have 2 devices in the same SPI bus defined in my devicetree. let's call them MAX30005_1 and MAX30005_2.

When the drivers initialize, they read a register of the device and check if it correspond to the PART id number from the manufacturer.

During the Zephyr OS initialization, the MAX30005_2 is initialized first than the MAX30005_1 even if it's being declared after it. But that's not the issue, 

When Zephyr initializing the first device (MAX30005_2) I can see the CS line of MAX30005_1 (which hasn't yet initialized) in LOW, and also I can see the change from High to Low of the CS line of the MAX30005_2 and the SPI clock running to comunicate with the MAX30005_2. 

This all means that both devices are selected at the same time which cause problems in the communication.

How can I initialize the CS gpios for both devices to be HIGH before the initialization of the SPI devices?

I'm using the nrf5340dk_nrf5340_cpuappns with an overlay with this info:

&spi3 {
compatible = "nordic,nrf-spim";
status = "okay";
sck-pin = <44>;
mosi-pin = <43>;
miso-pin = <42>;
cs-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>,
           <&gpio1 3 GPIO_ACTIVE_LOW>;

    afe1: max30005@0 {
        compatible = "maxim,max30005";
        status = "okay";
        reg = <0>;
        spi-max-frequency = <10000000>;
        label = "MAX30005_1";
    };
    afe2: max30005@1 {
        compatible = "maxim,max30005";
        status = "okay";
        reg = <1>;
        spi-max-frequency = <10000000>;
        label = "MAX30005_2";
    };
};

I've put here some information about the driver here:

some structures:



typedef struct max30005_spi_cfg {
	struct spi_config spi_conf;
	const char *cs_gpios_label;
} max30005_spi_cfg_t;

typedef struct max30005_data {
    const struct device *bus;
    const max30005_transfer_function_t *hw_tf;
    struct spi_cs_control cs_ctrl;
} max30005_data_t;

typedef union max30005_bus_cfg {
    const max30005_spi_cfg_t *spi_cfg;
} max30005_bus_cfg_t;
 

typedef struct max30005_config {
    const char *bus_name;
    int (*bus_init)(const struct device *dev);
    const max30005_bus_cfg_t bus_cfg;
} max30005_config_t;

the bus_init funtion points to max30005_spi_init function:

int max30005_spi_init(const struct device *dev)
{
	max30005_data_t *data = dev->data;
	const max30005_config_t *cfg = dev->config;
	const max30005_spi_cfg_t *spi_cfg = cfg->bus_cfg.spi_cfg;

	LOG_DBG("Initializing SPI %s",dev->name);

	data->hw_tf = &max30005_spi_transfer_fn;
	
	if (spi_cfg->cs_gpios_label != NULL) {
		
		/* handle SPI CS thru GPIO if it is the case */
		data->cs_ctrl.gpio_dev =
			    device_get_binding(spi_cfg->cs_gpios_label);
		if (!data->cs_ctrl.gpio_dev) {
			LOG_ERR("Unable to get GPIO SPI CS device");
			return -ENODEV;
		}

		LOG_INF("%s. SPI GPIO CS configured on %s:%u", dev->name,
			spi_cfg->cs_gpios_label, data->cs_ctrl.gpio_pin);
	}

	return 0;
}

int max30005_init(const struct device *dev)
{
  max30005_data_t *max30005 = dev->data;
  const max30005_config_t *cfg = dev->config;
  int status;
  uint8_t id;  

  max30005->bus = device_get_binding(cfg->bus_name);
  if (!max30005->bus) {
    LOG_ERR("Bus not found: %s", cfg->bus_name);
    return -EINVAL;
  }

  cfg->bus_init(dev);

  status = max30005->hw_tf->read_reg(dev, MAX30005_REG_PART_ID, &id);
  if (status < 0) {
    LOG_ERR("%s. Failed to read chip id",dev->name);
    return status;
  }
  

  if (id != MAX30005_PART_ID) {
    LOG_ERR("%s. Invalid chip ID: %02x\n", dev->name, id);
    return -EINVAL;
  }
  LOG_DBG("%s. part ID read",dev->name);


  LOG_INF("%s on bus=%s",dev->name, cfg->bus_name);

  return status;
}

these are the macros used to define and initialize the driver:

/*
 * Device creation macro, shared by MAX30005_DEFINE_SPI()
 */
#define MAX30005_DEVICE_INIT(inst)					\
	DEVICE_DT_INST_DEFINE(inst,					\
			    max30005_init,				\
			    NULL,					\
			    &max30005_data_##inst,			\
			    &max30005_config_##inst,			\
			    POST_KERNEL,				\
			    CONFIG_SENSOR_INIT_PRIORITY,		\
			    NULL);

#define MAX30005_HAS_CS(inst) DT_INST_SPI_DEV_HAS_CS_GPIOS(inst)


#define MAX30005_DATA_SPI_CS(inst)					\
	{ .cs_ctrl = {							\
		.gpio_pin = DT_INST_SPI_DEV_CS_GPIOS_PIN(inst),		\
		.gpio_dt_flags = DT_INST_SPI_DEV_CS_GPIOS_FLAGS(inst),	\
		},							\
	}

#define MAX30005_DATA_SPI(inst)						\
	COND_CODE_1(MAX30005_HAS_CS(inst),				\
		    (MAX30005_DATA_SPI_CS(inst)),				\
		    ({}))

#define MAX30005_SPI_CS_PTR(inst)						\
	COND_CODE_1(MAX30005_HAS_CS(inst),				\
		    (&(max30005_data_##inst.cs_ctrl)),			\
		    (NULL))

#define MAX30005_SPI_CS_LABEL(inst)					\
	COND_CODE_1(MAX30005_HAS_CS(inst),				\
		    (DT_INST_SPI_DEV_CS_GPIOS_LABEL(inst)), (NULL))

#define MAX30005_SPI_CFG(inst)						\
	(&(max30005_spi_cfg_t) {					\
		.spi_conf = {						\
			.frequency =					\
				DT_INST_PROP(inst, spi_max_frequency),	\
			.operation = (SPI_OP_MODE_MASTER | SPI_WORD_SET(8)),		\
			.slave = DT_INST_REG_ADDR(inst),		\
			.cs = MAX30005_SPI_CS_PTR(inst),			\
		},							\
		.cs_gpios_label = MAX30005_SPI_CS_LABEL(inst),		\
	})



#define MAX30005_CONFIG_SPI(inst)						\
	{								\
		.bus_name = DT_INST_BUS_LABEL(inst),			\
		.bus_init = max30005_spi_init,				\
		.bus_cfg = { .spi_cfg = MAX30005_SPI_CFG(inst)	}, \
	}

#define MAX30005_DEFINE_SPI(inst)						\
	static max30005_data_t max30005_data_##inst =			\
		MAX30005_DATA_SPI(inst);					\
	static const max30005_config_t max30005_config_##inst =	\
		MAX30005_CONFIG_SPI(inst);				\
	MAX30005_DEVICE_INIT(inst)



/*
 * Main instantiation macro. 
 */

#define MAX30005_DEFINE(inst)	MAX30005_DEFINE_SPI(inst)

DT_INST_FOREACH_STATUS_OKAY(MAX30005_DEFINE)

and the compat:

#define DT_DRV_COMPAT maxim_max30005

I've used the driver for the st,lis2dh as a template for this device

The driver works just fine after the initialization where both CS lines are high. The problem is just after reset where both CS pins initialize at low and when the first SPI is configured both devices are selected since both CS lines are in LOW

Parents Reply Children
Related