H3 SPI


Nick
 Share

5 5

Recommended Posts

This maybe something that just isn't available yet, but if I can help with the development I am happy to.

 

I have created the following patches as a starting point but they don't yet work.

 

Looking at the source code for the spidev module and comparing it to the H3 datasheet, it would appear that the H3 uses the sun6i spi register addresses. Though the datasheet lists the RX and TX buffers as 64 bytes whereas the sun6i spidev driver implements 128byte buffers. I'm assuming that this wont be a problem at least for testing as long as I don't try and transfer or receive more than 64 bytes.

 

As you can see from the dtsi patch, I have updated the module memory location and the IRQ & DMA channels. The clock gating appears to already be configured in the H3 dtsi file so hopefully that is correct.

--- /arch/arm/boot/dts/sun8i-h3.dtsi	2016-03-14 19:04:16.977158383 +0000
+++ ./sun8i-h3.dtsi	2016-03-14 21:49:55.806634593 +0000
@@ -591,5 +591,37 @@
 			interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
 		};
+		spi0_clk: clk@01c200a0 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-mod0-clk";
+			reg = <0x01c200a0 0x4>;
+			clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+			clock-output-names = "spi0";
+		};
+		spi0: spi@01c68000 {
+			compatible = "allwinner,sun6i-a31-spi";
+			reg = <0x01c68000 0x1000>;
+			interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ahb_gates 20>, <&spi0_clk>;
+			clock-names = "ahb", "mod";
+			dmas = <&dma SUN4I_DMA_DEDICATED 23>,
+			       <&dma SUN4I_DMA_DEDICATED 23>;
+			dma-names = "rx", "tx";
+			status = "disabled";
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+		spi0_pins_a: spi0@0 {
+			allwinner,pins = "PC2", "PC0", "PC1";
+			allwinner,function = "spi0";
+			allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+			allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+		};
+		spi0_cs0_pins_a: spi0_cs0@0 {
+			allwinner,pins = "PC3";
+			allwinner,function = "spi0";
+			allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+			allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+		};
 	};
 };
--- /arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts	2016-03-14 19:04:17.013140384 +0000
+++ ./sun8i-h3-orangepi-pc.dts	2016-03-14 21:50:23.646635423 +0000
@@ -104,3 +104,21 @@
 	/* USB VBUS is always on */
 	status = "okay";
 };
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi0_pins_a>,
+		    <&spi0_cs0_pins_a>;
+	status = "okay";
+	spi0_0 {
+	       #address-cells = <1>;
+	       #size-cells = <0>;
+
+	       compatible = "spidev";
+
+	       reg = <0>;
+	       spi-max-frequency = <500000>;
+	};
+};
+
+

At the moment the only feedback that I get is no /dev/spi* is there anyway of getting some debugging info from the driver printk's maybe?

Link to post
Share on other sites

Armbian is a community driven open source project. Do you like to contribute your code?

No I haven't I did a quick forum search but I (stupidly) ignored that one as my brain saw orange pi one and discounted it. I'll have a read through tonight and see if I can pick up any nuggets.

Would you prefer me to contribute anything I find to that thread or carry on with this one?

Link to post
Share on other sites

For making SPI working, not only DTS need to be patched, but also the SPIdev driver itself to become HW SPI friendly.

--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -695,6 +695,7 @@ static struct class *spidev_class;
 static const struct of_device_id spidev_dt_ids[] = {
        { .compatible = "rohm,dh2228fv" },
        { .compatible = "lineartechnology,ltc2488" },
+       { .compatible = "allwinner,sun4i-a10-spi" },
+       { .compatible = "allwinner,sun6i-a31-spi" },
        {},
 };
 MODULE_DEVICE_TABLE(of, spidev_dt_ids);

Here is in attachment my updated patches ...

 

BTW, to be able to submit those patches to Mainline in a near future, I had to do the same exercise directly on 4.5.0-rc6+, which I finally succeeded yesterday.

(I still other issues with this 4.5.0-rc6+, but not related to my patches themselves)

 

EDIT : The 4.5.0 has been released last Sunday, so I guess I will need to merge it again in the new 4.6.0-rcX branch ... ;-)

orangepipc-patches.zip

Link to post
Share on other sites

That's great work, thank you. I'll test them later and hopefully all will be well. 

I am a little confused as to why those lines aren't already in the driver though? I have successful run the spidev driver on the A20, which uses the sun4i-a10 model without having to patch spidev.

Link to post
Share on other sites

I am a little confused as to why those lines aren't already in the driver though? I have successful run the spidev driver on the A20, which uses the sun4i-a10 model without having to patch spidev.

Do you mean with 4.4.x ?

While doing some tests on my Olimex-Micro-A20, I've discovered that it was required there too. Maybe you had older version. This "spidev_dt_ids" list has been added in Mainline around November, I think. Before that, it wasn't required.

Link to post
Share on other sites

Yes 4.4.5, Zador helped me to get it running on a banana pi m1+ using Linux next and Jessie.

 

I've just checked spidev.c on my build VM and it doesn't contain the lines that you have added, however it appears that they are added via spi-sun4i.c and spi-sun6i.c

 

Here is an example form spi-sun6i.c

static const struct of_device_id sun6i_spi_match[] = {
	{ .compatible = "allwinner,sun6i-a31-spi", },
	{}
};
MODULE_DEVICE_TABLE(of, sun6i_spi_match);

I haven't read through the full driver code yet, but I would imagine that they are pulled in at some point and added to the struct.

Link to post
Share on other sites

There is something weird going on with the SPI, I seem to be getting a spurious short clock pulse. See the attached pic:

 

The blue trace is the active low CS line, the yellow trace is the CLK line.

 

As you can see, the CS line goes low and sometime later there is a burst of 8 bits, but in between the two events there is a very short extra pulse on the CLK line. I'm guessing this explains why I can't talk to the poor slave device  :(

 

Edit:

Finally got around to trying spitest...

root@opi:/# ./spitest -D /dev/spidev0.0 
can't send spi message: Success
Aborted
root@opi:/# ./spitest -D /dev/spidev0.0 -s 50000
can't send spi message: Success
Aborted
root@opi:/# ./spitest -D /dev/spidev0.0 -l
can't set spi mode: Invalid argument
Aborted
root@opi:/# 

post-706-0-73335800-1458767545_thumb.jpg

Link to post
Share on other sites

I've been looking at the missing spidev problem with the current mainline (4.7.2). I built armbian vanilla (mainline) Jessie on linux and noticed that although the correct spi device info has now been included in the device tree for h3 (sun8i-h3.dtsi) the changes martinayotte noted for the spidev driver have not been made. I tried adding his spidev patch file to the userpatches but it seems to be getting ignored or overwritten in the build script. Is there a way to rebuild without pulling in the git updates?

 

I note that there is a spidev.ko but loading it with modprobe doesnt create any spi devices

Link to post
Share on other sites

I've been using Dynamic Overlay to load SPIs into the DTS. There is no need to do any modprobe, since the Kernel will load it automatically when DTS is updated.

mkdir /sys/kernel/config/device-tree/overlays/spi
cat spidev-enable.dtbo > /sys/kernel/config/device-tree/overlays/spi/dtbo

 

 

// Enable the spidev interface
/dts-v1/;
/plugin/;

/ {
    compatible = "allwinner,sun8i-h3";

    fragment@0 {
    target-path = "/aliases";
    __overlay__ {
            /* Path to the SPI controller nodes */
            spi0 = "/soc@01c00000/spi@01c68000";
            spi1 = "/soc@01c00000/spi@01c69000";
        };
    };
    fragment@1 {
        target = <&spi0>;
        __overlay__ {
            pinctrl-names = "default";
            pinctrl-0 = <&spi0_pins_a>, <&spi0_cs0_pins_a>;
            status = "okay";
            #address-cells = <1>;
            #size-cells = <0>;
            spidev@0 {
                compatible = "spidev";
                reg = <0x0>;
                spi-max-frequency = <1000000>;
            };
        };
    };
    fragment@2 {
        target = <&spi1>;
        __overlay__ {
            pinctrl-names = "default";
            pinctrl-0 = <&spi1_pins_a>, <&spi1_cs0_pins_a>;
            status = "okay";
            #address-cells = <1>;
            #size-cells = <0>;
            spidev@0 {
                compatible = "spidev";
                reg = <0x0>;
                spi-max-frequency = <1000000>;
            };
        };
    };
};

 

Link to post
Share on other sites

I wish it was that easy :-)

If I use your overlay source directly and copy it to the overlay dtbo as you suggest I see the following errors in dmesg:

...

[  496.553300] Invalid device tree blob header
[  496.553371] create_overlay: failed to unflatten tree
 

I thought I needed to compile the dts first  into the dtbo  with:

 

dtc -O dtb -I dts -o spidev-enable.dtbo -b 0  spidev-enable.dts

But that gives an error too:

root@nanopineo:~# dtc -O dtb -I dts -o spidev-enable.dtbo -b 0  spidev-enable.dts
Error: spidev-enable.dts:3.2-8 syntax error

Of course it doesn't say what the syntax error is. I'm wondering it was something stupid like different line ending characters. That is sometimes as issue moving between windows and linux environments. I'll check that next.

 

But my question is: do you need to compile it first or will it happen automatically when its copied to the configfs?
 

Link to post
Share on other sites

Sorry if I didn't gave details earlier.

 

Yes, you need to compile the DTBO, but using the DTC compiler supporting Dynamic Overlays developped by Pantelis Antoniou.

 

I can be found there : https://github.com/pantoniou/dtc.git

 

With this version, You need to invoke it with '-@' option :

 

dtc -@ -O dtb -I dts -o spidev-enable.dtbo spidev-enable.dts

Link to post
Share on other sites

Thanks! It wasn't quite so obvious but I did get it to work eventually.

 

I found that building the default git mainline from pantoniou/dtc produced a dtc that would not accept the -@ option. However I noticed that there were several branches that were more recent  - e.g dt-overlays8. When I built that branch it produced a dtc that although it gave a few warnings did produce a dtbo that could be copied into the configfs and suddenly the spidevs showed up in /dev.

 

Here's exactly what I did:

 

I found that the dtc build required flex and bison so I installed them:

 

   apt-get install flex bison

 

I cloned the dtc git with the dt-overlays8 branch:

 

  git clone -b dt-overlays8 https://github.com/pantoniou/dtc

 

I built that version ( DTC 1.4.1-gf7da040f) and used that to compile the dts:

 

  dtc -@ -O dtb -I dts -o spidev-enable.dtbo spidev-enable.dts

 

There were a couple of warnings:

Warning (unit_address_vs_reg): Node /fragment@0 has a unit name, but no reg property
Warning (unit_address_vs_reg): Node /fragment@1 has a unit name, but no reg property
Warning (unit_address_vs_reg): Node /fragment@2 has a unit name, but no reg property

 

Then copied the result to the directory I created earlier:

 

sudo cat spidev-enable.dtbo > /sys/kernel/config/device-tree/overlays/spi/dtbo

 

Two spidevs then showed up in /dev!

 

 ls /dev/spi*
/dev/spidev0.0  /dev/spidev1.0

 

Now I'll have to wire up something (maybe a logic analyzer) to test them. I hope I don't have the spi speed problem I saw earlier...
 

Thanks again for your help. When it all works it is simply magical!

Link to post
Share on other sites

I'm still finding the H3 SPI to be too slow for driving LCD SPI displays.

I'm using the vanilla 4.7.2 kernel, applying overlays for I2C and SPI. Using a C program to directly access the spi with ioctl calls the best speed I was able to achieve for  single byte writes was  <30 Kb/sec. This is with 8 MHZ SPI clock. The speed limiting problem is still long delays on CS assert and deassert: 5us from CS assert to SPI data start, 25 us from SPI data end to CS deassert. The actual data time is about 1us with 8 MHz clock so ~97% of the time is wasted in the hardware CS delays, not counting the delay between sending bytes This makes the H3 many times slower with displays than Arduino, and far, far slower than Teensy which I've used for many IOT projects.

 

Legacy kernel experiments show the same sort of delays. I thought the more recent kernels might be better. But not yet.

 

I'd really like to use the Neo for projects that use SPI for small displays, or interfacing a digital radio chip or ADC, etc, but the slow speed is holding me back at the moment.  For example an IOT gateway. I know its not the H3 based hardware that's limiting the speed, just the driver and that can be fixed.

 

I'm interested in any ideas or experimental results anyone has on this topic.

Link to post
Share on other sites

In fact, H3 has 64 bytes FIFO, while some other AllWinner SoC has 128 bytes FIFO.

Yes, the patch committed few days ago allow large transfer, example, using flashcp to upload SPL into SPI Flash, it produce transfers of 4096 bytes.

I didn't check with a logic analyser how the CS line is reacting during such large transfer, but I presume kernel driver should only asserting CS to LOW during the whole transfer.

I will verify that when I get chance ...

Link to post
Share on other sites

The SPI select is driven by software, ie. drivers/spi.c not hardware.  Looking at spi.c

  1. spi_transfer_one_message
    1. assert CS
    2. setup/clear upper level call backs
    3. call into SPI driver sun6i_spi_transfer_one
      1. clear ISR callbacks etc
      2. setup SPI chip etc
      3. start the transfer.

So, even if the SPI transfer rate is increased, the about of time from CS is asserted to the first SPI data transfer should be constant (i.e the time it takes to execute the code)

Link to post
Share on other sites

hi there, please, I have orange pi lite and using spi to control ws2812b. My problem is, that firs led is green (when other are off), when I set all to blue first led is blue too, when all to green first is green, when all to red first is yellow. Any idea what is causing this issue?

Or any idea how to leave first LED off completely rather than being green? Thanks.

 

UPDATE: I found out GREEN is always in up (turned on) state for first LED in strip. So according to my opinion, final last data are somehow corrupted and therefore green part of first led is in "ON" state.

Link to post
Share on other sites

I've been using Dynamic Overlay to load SPIs into the DTS. There is no need to do any modprobe, since the Kernel will load it automatically when DTS is updated.

mkdir /sys/kernel/config/device-tree/overlays/spi
cat spidev-enable.dtbo > /sys/kernel/config/device-tree/overlays/spi/dtbo

 

 

// Enable the spidev interface

/dts-v1/;

/plugin/;

 

/ {

    compatible = "allwinner,sun8i-h3";

 

    fragment@0 {

    target-path = "/aliases";

    __overlay__ {

            /* Path to the SPI controller nodes */

            spi0 = "/soc@01c00000/spi@01c68000";

            spi1 = "/soc@01c00000/spi@01c69000";

        };

    };

    fragment@1 {

        target = <&spi0>;

        __overlay__ {

            pinctrl-names = "default";

            pinctrl-0 = <&spi0_pins_a>, <&spi0_cs0_pins_a>;

            status = "okay";

            #address-cells = <1>;

            #size-cells = <0>;

            spidev@0 {

                compatible = "spidev";

                reg = <0x0>;

                spi-max-frequency = <1000000>;

            };

        };

    };

    fragment@2 {

        target = <&spi1>;

        __overlay__ {

            pinctrl-names = "default";

            pinctrl-0 = <&spi1_pins_a>, <&spi1_cs0_pins_a>;

            status = "okay";

            #address-cells = <1>;

            #size-cells = <0>;

            spidev@0 {

                compatible = "spidev";

                reg = <0x0>;

                spi-max-frequency = <1000000>;

            };

        };

    };

};

 

 

 

 

I follow this thread and have a little problem. I compiled Linux-4.10 and it comes with /boot/dtb/overlay/sun8i-h3-spi0-spidev.dtbo, then I did this:

 

cat sun8i-h3-spi0-spidev.dtbo > /sys/kernel/config/device-tree/overlays/spi/dtbo

 

I got /dev/spidev0.0 but after reboot, the spidev0.0 is gone and need to do the command above again.

Can I put it to rc.local?, but I am not sure is this correct way to load spi overlay.

 

Please advise

Link to post
Share on other sites

Guest
This topic is now closed to further replies.
 Share

5 5