[HowTo] Enable full duplex SPI

Started by Cosik, October 21, 2014, 07:38:36 PM

Previous topic - Next topic



In my project I need to use full duplex communication with RF module, so I started looking how to use SPI.

I didn't test it on image distributed by Olimex, because I need to use custom kernel.

At first we need to download kernel source, for example:
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

Next we should perform initial kernel configuration for A20:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- sun7i_defconfig

Now we need to patch our kernel in few steps:
1. create file linux-sunxi/drivers/spi/spi-sun7i.c with this content

2. To linux-sunxi/drivers/spi/Makefile at the end add:
obj-$(CONFIG_SPI_SUN7I)         += spi-sun7i.o

3. Update linux-sunxi/drivers/spi/Kconfig:

config SPI_SUN7I
   tristate "SUN7I SPI Controller"
   depends on ARCH_SUN7I
      Allwinner Soc SPI controller,present on SUN7I chips.

        bool "SUN7I SPI Normal DMA mode select"
        depends on SPI_SUN7I
          This selects SPI DMA mode with DMA transfer
          Y select NDMA mode and N select DDMA mode

4. Update kernel config

It's important to have hard compiled spidev in kernel.

Now we can compile kernel with command:
make -j4 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- uImage modules
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=output modules_install

Also we need to update FEX file, important is to set full_duplex to 1, example:
modalias = "spidev"
max_speed_hz = 12000000
bus_num = 3
chip_select = 0
mode = 0
full_duplex = 1
manual_cs = 0

Now we can test install kernel, modules and then test them. For test I used pyA20 and kernel/linux-sunxi/Documentation/spi/spidev_fdx.c

To get working correct spi, we also need to update /usr/include/linux/spi/spidev.h on our board with:
struct spi_ioc_transfer {
__u64 tx_buf;
__u64 rx_buf;

__u32 len;
__u32 speed_hz;

__u16 interbyte_usecs;
__u16 delay_usecs;
__u8 bits_per_word;
__u8 cs_change;
__u32 pad;

Test results:
pyA20 from Olimex didn't correct support full duplex.

Here are commend which I used to test SPI in python
>>> from pyA20 import spi
>>> spi.open("/dev/spidev1.0")
>>> spi.xfer([0x01, 0x02], 2)
[14, 8]

Here are results

indexstart-timeend-timeevent?MOSI dataMISO data
020,00 ns20,00 nstrueCS_LOW
114,60 μs14,60 μsfalse0
214,60 μs14,60 μsfalse14
335,94 μs35,94 μsfalse0
435,94 μs35,94 μsfalse8
5115,92 μs115,92 μsfalse1
6115,92 μs115,92 μsfalse8
7137,26 μs137,26 μsfalse2
8137,26 μs137,26 μsfalse8
9418,80 μs418,80 μstrueCS_HIGH

Problem is that this function first read SPI and then send data, and didn't return read data during sending data.

spidev_fdx is working better but not enough good for me, here are results.
./spidev_fdx -v -m1 -r2 /dev/spidev1.0
/dev/spidev1.0: spi mode 0, 8 bits per word, 100000 Hz max
response( 1,  2):  08
read( 2,  2): 0e 08,

indexstart-timeend-timeevent?MOSI dataMISO data
020,00 ns20,00 nstrueCS_LOW
113,98 μs13,98 μsfalse0
213,98 μs13,98 μsfalse14
3155,16 μs155,16 μsfalse0
4155,16 μs155,16 μsfalse8
5259,48 μs259,48 μstrueCS_HIGH
6430,06 μs430,06 μstrueCS_LOW
7443,22 μs443,22 μsfalse0
8443,22 μs443,22 μsfalse14
9464,54 μs464,54 μsfalse0
10464,54 μs464,54 μsfalse8
11513,76 μs513,76 μstrueCS_HIGH

Kernel compile
Fex edit
Orginal information source

Feedback is expected ;)


Did you test by looping MISO to MOSI ?



No, I tested it with real device. 0x0E is device status and 0x08 is default value in 0x00 register.

Or you suggest to perform test on loop back?


Quote from: Cosik on October 21, 2014, 09:48:51 PM

Or you suggest to perform test on loop back?
Can be interesting too but that was only a question on how you perform your test :-)


I did some test with the following test c code


I put a wire between MOSI and MISO. here is the result.

./spi-test -C -L -D /dev/spidev2.0  0x10,0x20,0x30
10 20 30
10 20 30

So seem to work.

I have also try with python code but i have an issue

Python 2.7.3 (default, Mar 14 2014, 17:55:54)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from pyA20 import spi
>>> spi.open("/dev/spidev2.0")
>>> spi.xfer([0x01, 0x02], 2)

Segmentation fault

So have an issue with the python code.
I run the test on a 3.4.103+ kernel compiled with information you provide.



I also tested it on 3.4.103 and everything is "working". Did you compile pyA20 on new kernel and update spidev.h? If you could, pleas show me yours spidev.h :)