Custom SPI Device Driver exception when running

I am using VSCode with nRF Connect extension with the 2.9.1 SDK.

I am trying to write my own device driver for the Zephyr OS and the TI CC1101 chip. Since the tutorial isn't up to date yet I am trying to cobble together a lot of different things to make this work.

I have another ticket regarding that setup.

This ticket is about a work around that I found to get past some of those issues and just try to use my driver as a generic SPI device.

I have this in my overlay file:

&spi21 {
compatible = "nordic,nrf-spim";
status = "okay";
pinctrl-0 = <&spi21_default>;
pinctrl-1 = <&spi21_sleep>;
pinctrl-names = "default", "sleep";
cs-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
cc1101: cc1101@0 {
reg = <0>;
compatible = "vnd,spi-device";
spi-max-frequency = <2500000>;
//int_gpios = <&gpio1 7 (GPIO_ACTIVE_LOW)>, <&gpio0 34 (GPIO_ACTIVE_LOW)>;
//frequency = <868300>;
//bitrate = <38368>;
status = "okay";
};
};

&pinctrl {
spi21_default: spi21_default {
group1 {
psels = <NRF_PSEL(SPIM_SCK, 1, 11)>,
<NRF_PSEL(SPIM_MOSI, 1, 13)>,
<NRF_PSEL(SPIM_MISO, 1, 14)>;
};
};

spi21_sleep: spi21_sleep {
group1 {
psels = <NRF_PSEL(SPIM_SCK, 1, 11)>,
<NRF_PSEL(SPIM_MOSI, 1, 13)>,
<NRF_PSEL(SPIM_MISO, 1, 14)>;
low-power-enable;
};
};
};
In my .c file I have this to define the device object:
#define SPIOP SPI_WORD_SET(8) | SPI_TRANSFER_MSB
struct spi_dt_spec spispec = SPI_DT_SPEC_GET(DT_NODELABEL(cc1101), SPIOP, 0);
In the same file when I initialize the spispec object I use this:
if(!spispec.bus) {
printk("cc1101 not in devicetree\n");
return -1;
}

if (!device_is_ready(spispec.bus)) {
printk("cc1101 device is not ready\n");
return -1;
}

uint8_t chipVer = cc1101_find_chip(spispec.bus);
It gets past the check for bus being null and device_is_ready, so I would expect everything is ready to start using SPI on this device.
Inside the cc1101_find_chip function I eventually get to this line:
if (config->ncs.port != 0) {
gpio_pin_set_dt(&config->ncs, 0);
}
At this point here is the debug output values of config->ncs (which is a struct):
Notice that port is 0xffffffff
port is defined as a pointer in the gpio_dt_spec struct which is what ncs is defined as:
struct gpio_dt_spec {
/** GPIO device controlling the pin */
const struct device *port;
/** The pin's number on the device */
gpio_pin_t pin;
/** The pin's configuration flags as specified in devicetree */
gpio_dt_flags_t dt_flags;
};
When the internal nordic method gpio_pin_set function gets called with that point and that function tries to use port I get an exception (of course we would).
So what is going on here? I am following the code that should work to set up this device and yet the port is 0xffffffff.
Why?
  • Hi,

     

    It is a lot easier to read the code if you use insert -> code.

    It gets past the check for bus being null and device_is_ready, so I would expect everything is ready to start using SPI on this device.
    Inside the cc1101_find_chip function I eventually get to this line:
    if (config->ncs.port != 0) {
    gpio_pin_set_dt(&config->ncs, 0);
    }

    Is config a non-null variable? How is this declared etc?

    Is this the cs-gpios that you are trying to handle?

     

    Kind regards,

    Håkon

  • Sorry I didn't see the Insert Code. I will remember that in the future. Thanks for the tip.

    This is where config comes from:

    int cc1101_txrx(const struct device *dev, uint8_t reg, uint8_t *txb, uint8_t txlen, uint8_t *rxb, uint8_t rxlen)
    {
        const struct cc1101_config *config = dev->config;
    

    so it is the spispec that is passed in and created by the device tree stuff.

    Thank you for asking the question because as I look at this further it might be something in the cc1101 driver code that I got from github.

    If you are willing to look and maybe help figure it out, that code is here:

    github.com/.../cc1101

  • I am new to the device driver model and am starting to think this issue is because I am getting the spispec pointer using the regular method of getting a pointer to a device tree item instead of using the one that is specific to my device driver.

    The problem is probably related to the fact that I can't us the right one because I get a compiler error. The details of that are in this ticket:

     Adding SPI to a project 

    Is it true that if I can resolve the issue of getting my device driver the right way, the ncs field will probably be filled in for me?

  • I figured this all out. I had to modify some of the yaml for the dts device. There was a mix of comma and dash and they had to all be dashes.

    I also found that the code was referencing the cs-gpios of the SPI definition, so I had to move that from the spi part to the cc1101 part.

    Now it builds and the structure has what it needs.

    Files:

    Overlay

    &spi21 {
        compatible = "nordic,nrf-spim";
    	  status = "okay";
    	  pinctrl-0 = <&spi21_default>;
    	  pinctrl-1 = <&spi21_sleep>;
    	  pinctrl-names = "default", "sleep";
    	  cc1101: cc1101@0 {
    		reg = <0>;
    		compatible = "ti-cc1101";
    		spi-max-frequency = <2500000>;
    		cs-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
    		int_gpios = <&gpio1 7 (GPIO_ACTIVE_LOW)>, <&gpio0 34 (GPIO_ACTIVE_LOW)>;
    		frequency = <868300>;
    		bitrate = <38368>;
    		status = "okay";
    	};
    };
    


    ti-cc1101.yaml

    # Copyright (c) 2018, Linaro Limited
    # SPDX-License-Identifier: Apache-2.0
    
    description: Texas Instruments CC1101 wireless transceiver
    
    compatible: "ti-cc1101"
    
    include: spi-device.yaml
    
    properties:
      int_gpios:
        type: phandle-array
        required: true
        description: GPIOs connected to the GDO0 and GDO2 pins of the transceiver.
      cs-gpios:
         type: phandle-array
         description: GPIO connected nCS
     
      frequency:
        type: int
        description: The carrier frequency, in kHz.
      bitrate:
        type: int
        description: The bitrate in bit per second.

    .c file declaration

    const struct device *cs = DEVICE_DT_GET_ANY(ti_cc1101);
    

    It all compiles and the ncs member is filled out.

    I figured out a lot of this when I noticed this macro define:

    #define CC1101_DEFINE(inst)                                             \
        static struct cc1101_data cc1101_data_##inst = {                    \
            .frequency = DT_INST_PROP(inst, frequency),                     \
            .bitrate = DT_INST_PROP(inst, bitrate),                         \
        };                                                                  \
        static struct cc1101_config cc1101_config_##inst = {                \
            .spi = SPI_DT_SPEC_INST_GET(inst, SPI_WORD_SET(8), 150),        \
            .gdo0 = GPIO_DT_SPEC_INST_GET_BY_IDX(inst, int_gpios, 0),       \
            .gdo2 = GPIO_DT_SPEC_INST_GET_BY_IDX(inst, int_gpios, 1),       \
            .ncs = GPIO_DT_SPEC_INST_GET(inst, cs_gpios),                   \
        };                                                                  \
        DEVICE_DT_INST_DEFINE(inst, cc1101_init, NULL,                      \
                      &cc1101_data_##inst, &cc1101_config_##inst, POST_KERNEL,  \
                      99, NULL);
    
    
    DT_INST_FOREACH_STATUS_OKAY(CC1101_DEFINE)
    

    At that point I put the error about cs_gpios together with the fact that the spi part of the overlay had something like that, but the cc1101 didn't. I was assuming a child had access to its parents in the macro when really you have to move it from the parent to the child in the overlay.

    Makes me wonder if you talk about that in the tutorials anywhere because I have been through the beginner and intermediate tutorials and didn't see anything about that.

Related