10

I am running Arch Linux ARM on a Raspberry Pi 2 Model B, and I am attempting to communicate with a TFT display. I am writing a kernel module to interface with the display using SPI, and it works, but I cannot get the SPI frequency to go above 500 kHz. I have successfully used higher frequencies in the user space when using the BCM2835 library, so I know it is possible.

Using the following command to parse the device tree:

dtc -I fs /sys/firmware/devicetree/base | grep max-frequency

I can see that spi-max-frequency = <0x7735940>, which is hexadecimal for 150 MHz.

hexdump /sys/class/spi_master/spi0/of_node/spi-max-frequency

gives me 7307 4059, hexadecimal for the same number (just with the byte order reversed). In my kernel module, I did the following:

struct spi_board_info spiBoardInfo = {
    .modalias = "spi",
    .max_speed_hz = 32000000,
    .bus_num = 0,
    .chip_select = 0,
    .mode = 0
};

master = spi_busnum_to_master(spiBoardInfo.bus_num); spiDevice = spi_new_device(master, &spiBoardInfo); spiDevice->bits_per_word = 8; ret = spi_setup(spiDevice); printk(KERN_INFO "TFT: device max speed %ld\n", spiDevice->max_speed_hz);

which prints out 32000000, as expected (error checking code was removed above for brevity). To write to the slave, I use the following command

spi_write(spiDevice, &data, sizeof(data));

(I have also tried using spi_sync_transfer() and setting the speed there as well, to no avail). This command successfully writes the data, but at a speed of 500 kHz.

Does anyone know why I am being limited to this frequency?

EDIT

After investigating further, I strongly feel it has to do with the device tree. I added the following overlay:

/dts-v1/;
/plugin/;
/ {
    compatible = "brcm,bcm2708";
    fragment@0 {
            target = <&spidev0>;
            __overlay__ {
                    status = "disabled";
            };
    };
    fragment@1 {
            target = <&spi0>;
            __overlay__ {
                    #address-cells = <1>;
                    #size-cells = <0>;
                    status = "okay";
                    tft@0 {
                            compatible = "tft,st7789";
                            spi-max-frequency = <320000000>;
                            reg = <0>;
                    };
            };
    };
    __overrides__ {
            tft = <0>, "=0=1";
    };
};

And now receive:

spi-bcm2835 3f204000.spi: chipselect 0 already in use

The name of my kernel module is tft, and then I do the following:

static const struct of_device_id dtIDs[] = {
    {.compatible = "tft,st7789"},
    {}
};
MODULE_DEVICE_TABLE(of, dtIDs);

So it seems as if the SPI driver is not recognizing my kernel module as the owner of chipselect 0, and not letting me access SPI as a result. I feel as though if I got this working, I would get the correct speeds, as the spi-max-frequency will have been directly set for my driver.

goldilocks
  • 58,859
  • 17
  • 112
  • 227
Chris Loonam
  • 151
  • 6
  • 150MHz is a configuration limit, but the GPIO drivers (transistors) are limited, in most conditions to 10MHz or less.Officially, when driven as a clock, with 1.2V IO Supply and minimal load, the maximum GPIO switching frequency is 125MHZ – crasic Jun 06 '19 at 01:01
  • @crasic with the BCM2835 library I’m capable of getting at least 32 MHz. – Chris Loonam Jun 06 '19 at 01:03
  • " I have successfully used higher frequencies in the user space when using the BCM2835 library, so I know it is possible." was this done on exactly the same setup hardware wise? – crasic Jun 06 '19 at 01:03
  • Yes, identical. I actually can do them side by side, running the user space program using the library, and then using the kernel module. – Chris Loonam Jun 06 '19 at 01:04
  • 3
    As confirmation of my rule of thumb (10MHz is conservative). Library doc says "Although it is possible to select high speeds for the SPI interface, up to 125MHz (see bcm2835_spi_setClockDivider()) you should not expect to actually achieve those sorts of speeds with the RPi wiring. Our tests on RPi 2 show that the SPI CLK line when unloaded has a resonant frequency of about 40MHz, and when loaded, the MOSI and MISO lines ring at an even lower frequency. Measurements show that SPI waveforms are very poor and unusable at 62 and 125MHz. Dont expect any speed faster than 31MHz to work reliably." – crasic Jun 06 '19 at 01:06
  • Yes, I had read that. That’s why I was using 32 MHz (I was using 31.2 before, so I doubt that the 800 kHz are making the difference) – Chris Loonam Jun 06 '19 at 01:07
  • In any case, since it works side by side and , since you are doing kernel modules instead of using the library, there is likely some initialization that you are missing or is being taken care of by the library . – crasic Jun 06 '19 at 01:08
  • Seems odd, it should only be limited by spi master and spi device driver. Is it always 500kHz? What if you specify a number different than 32MHz (to confirm something is not dividing by 64)? What if you specify speed_hz < 500kHz? – domen Jun 06 '19 at 13:17
  • @domen I've tried lower frequencies, even something like 7 kHz, and it works as expected. I've also tried other frequencies above 500 kHz, and they do not work. – Chris Loonam Jun 06 '19 at 13:18
  • Have you read this account of Gordon's SPI experiments? – Seamus Aug 07 '21 at 05:09
  • I've been struggling with similar things this week. I seem to recall that the SPI clock is based on the VPU clock, and this clock can be limited by enabling the console UART and/or by running the Pi in composite video mode. Is the console UART enabled? /boot/config.txt::enable_uart=1? What is your reported system clock when you run vcgencmd measure_clock arm? – mhilden Nov 19 '21 at 15:19

0 Answers0