Occasional Extra SPI Clock Cycles

On somewhat rare occasions the SPI clock will trigger ~12 times for no apparent reason.

I have an IMU connected over SPI. In general Masters sends a byte to get the MSB of the hardware FIFO count, the IMU (slave) responds with a single byte. Then Master sends another byte to get the LSB and the IMU responds with a single byte. Master sends 0xB0 which is a request for FIFO data. The image below is logic analyzer trace of the this occurring.

But sometimes I see this. Where the slave responds with the LSB of the hardware FIFO count then there’s an extra ~12 clock cycles causing the slave to send another byte. But that should happen, obviously. The image below is a logic analyzer trace of the failure.

Close up of the clock at the point of failure.

The question is, what could cause these extra clock cycles, and on such rare occasions?

Using l4t-r32.4.2, but have also tested with the SPI drivers from here: https://developer.nvidia.com/embedded/l4t/r32_release_v6.1/sources/t210/public_sources.tbz2.

@AS409
Will check with developer if any suggestion for debug.

Are you using the spidev driver or a device-specific one? If device-specific, which one?
Is it your userspace code? Is it using read/write or ioctl to transfer data?

If it were an extra 8 bits I’d say the userspace code is sending a NULL byte for some reason but 12 bits is a little odd.

I’m another developer on this project. We have a custom kernel driver for an IMU. This driver is a spi_device driver. Here is our device tree node:

&spi1 { /* IMU */
    nvidia,clock-always-on;
    icm42688_0: imu@0 {
        compatible = "appareo,icm42688";
        reg = < 0 >;
        status = "okay";
        spi-max-frequency = <5000000>;
        pps-gpios = <&gpio TEGRA_GPIO(D, 3) GPIO_ACTIVE_LOW>;
        spi-cpol;
        spi-cpha;
        interrupt-parent = <&gpio>;
        interrupts = <TEGRA_GPIO(D, 3) 1>;
        #appareo,imu-cells = <0>;
        controller-data {
            nvidia,enable-hw-based-cs;
            nvidia,rx-clk-tap-delay = < 0x06 >;
        };
    };

    /delete-node/ spi@0;
    /delete-node/ spi@1;
};

We have a function that runs as a work task and reads how many bytes are in the devices FIFO. This read does two back to back reads. The first read always works correctly. The second read sometimes does an 8-bit read followed by a 12-bit read.

static ssize_t icm42688_fifo_pending_bytes(struct icm42688_device *hdev)
{
    int ret;
    u8 counth, countl;
    u16 count;

    /**
     * Note: reading COUNTH latches COUNTL
     * Despite some versions of the documentation
     * This order has been confirmed with an applications engineer through
     * a representative at Victory Sales
     */
    ret = icm42688_read1(hdev, ICM42688_REG_FIFO_COUNTH, &counth);
    if (ret != 0)
        return (ssize_t) ret;
    ret = icm42688_read1(hdev, ICM42688_REG_FIFO_COUNTL, &countl);
    if (ret != 0)
        return (ssize_t) ret;

    count = (((u16) counth) << 8) + ((u16) countl);

    hdev->stats.max_fifo_size = max(hdev->stats.max_fifo_size, (int)count);

    return count;
}

What happens is that extra read clocks out the first byte in the FIFO. This causes the remaining data in the FIFO to be off by one byte.

Can you do a fdtdump /sys/firmware/fdt and paste the output for spi@7000d600? A few things I noticed…

  • I’d try removing the clock-always-on parameter and see what that does.
  • I assume pps-gpios is handled by your driver. but usually interrupt settings are set at the parent controller level. Does you driver do something special with them at the device level?
  • You may wish to do a /delete-node/ prod-settings from the controller. It interferes with setting things like rx-clk-tap-delay.

There have been a bunch of SPI controller driver changes since 32.4.2 including more in the 32.6.1 which was released this week. Any chance you could try the kernel that comes with 32.6.1?

Oh, another thing you could try is to put a printk in your driver if a request for a word length other than 8 is received.