AnsweredAssumed Answered

Android : spidev ioctl handlers to user space and running spidev_test app on imx6.

Question asked by Prasanna Kulkarni on Jul 18, 2018
Latest reply on Jul 24, 2018 by Prasanna Kulkarni

Hi All,

 

           Recently I have tried to integrate spidev driver and bring-up of /dev/spidevx.x at  user-space. I want to share this   experience on the blog so that it will be helpful to others.

 

We have used imx6solo and Android OS running on that with the Linux kernel 3.0.35.

 

1. There are many links available on how to enable spidev driver at kernel and registering spidev @ board file (on particular bus no & chipsel.) so it is assumed that /dev/spidevx.x is available on your device.

 

2. Using the SPI User Mode Device Driver

 


courtesy from  "Using SPI with Linux | armbedded.eu"  website. I have referred few points from this.

 

      There are two ways of of using the user mode spi device driver. You can call either the read/write functions or an ioctl(). With calling read/write you can only read or write at a time. I have taken a code from above mentioned website and built. yes I could able to write/read at a time using read/write APIs.

 

   But my requirement was full-duplex read and write, so we had to call the ioctl SPI_IOC_MESSAGE().

 

Now I will brief my contribution in this.

 

1. sample code for spi dev test spidev_test.c is available in the kernel Documentation/spi folder itself or at many websites.

 

2. problem was how to build/compile it ?? Everywhere it is mentioned that "Cross-compile with cross-gcc -I/path/to/cross-kernel/include"

 

3. How to build it exactly for an ARM architecture, how to direct the compiler to include header files syntax was not mentioned on the net.

Everyone tried in their own way and only mentioned how to run the binary. but the problem was how to compile it?  I have tried for 2 days with different methods and finally got it worked. methods listed below

 

              1.cd kernel_imx/Documentation/spi/

 

                                 $arm-linux-androideabi-gcc -o spidev_test -I../../include -I../../arch/arm/include spidev_test.c

 

                                 spi_test_dev.c:15:20: error: stdint.h: No such file or directory
                                 spi_test_dev.c:16:20: error: unistd.h: No such file or directory ..... lot of erros.

 

             2. made a project folder at external with following Android.mk

 

                 LOCAL_PATH:= $(call my-dir)
                   include $(CLEAR_VARS)

 

                     LOCAL_C_INCLUDES := \
                                         kernel_imx/include \
                                         kernel_imx/arch/arm/include
                     LOCAL_SRC_FILES:= spi_test_dev.c
                     LOCAL_MODULE := spi_test_dev
                     LOCAL_MODULE_TAGS := eng
                  include $(BUILD_EXECUTABLE)

 

         with folder contents as

 

               Android.mk  

 

               spi_test_dev.c

 

Got Lot of errors.

 

In file included from bionic/libc/include/sys/types.h:37:0,
                 from bionic/libc/include/unistd.h:33,
                 from external/spi-test/spi_test_dev.c:16:
kernel_imx/include/linux/types.h:13:2: warning: #warning "Attempt to use kernel headers from user space, see http://kernelnewbies.org/KernelHeaders" [-Wcpp]
In file included from kernel_imx/arch/arm/include/asm/page.h:204:0,
                 from bionic/libc/include/limits.h:109,
                 from bionic/libc/include/signal.h:33,
                 from bionic/libc/include/sys/select.h:34,
                 from bionic/libc/include/unistd.h:34,
                 from external/spi-test/spi_test_dev.c:16:
kernel_imx/arch/arm/include/asm/memory.h:19:25: fatal error: mach/memory.h: No such file or directory
compilation terminated.
make: *** [out/target/product/sabresd_6dq/obj/EXECUTABLES/spi_test_dev_intermediates/spi_test_dev.o] Error 1
make: *** Waiting for unfinished jobs....

 

4. method was follow Makefile given in kernel folder Documentation/spi/Makefile

-------------------------------------------------------------------------------------------------------------------------

# kbuild trick to avoid linker error. Can be omitted if a module is built.
obj- := dummy.o

 

# List of programs to build
hostprogs-y := spidev_test spidev_fdx

 

# Tell kbuild to always build the programs
always := $(hostprogs-y)

 

HOSTCFLAGS_spidev_test.o += -I$(objtree)/usr/include
HOSTCFLAGS_spidev_fdx.o += -I$(objtree)/usr/include

-----------------------------------------------------------------------------------------------------------------------------


So this also added as part of kernel build source and it got built without any errors. when I pushed the binary to device and tried to execute but got error not executable: magic 7F45

 

5. Thought of one more method, will use google ndk kit for compiling and  used the following command

Set cross-compiler for arm

$ export NDK=~/usr/android-ndk-r7
$ export NDK_TOOLCHAIN=${NDK}/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin
/arm-linux-androideabi-
$ export NDK_SYSROOT=${NDK}/platforms/android-9/arch-arm

         In order to compile it for Android we need to set CC and CFLAGS. CC will point to the cross-compiler from the
NDK toolchain. CFLAGS will set sysroot to point to the NDK directory that has the header files and libraries.

 

make CC=${NDK_TOOLCHAIN}gcc CFLAGS=--sysroot=${NDK_SYSROOT} spi_test_dev

 

 spi_test_dev.c:23:30: error: linux/spi/spidev.h: No such file or directory
spi_test_dev.c: In function 'transfer':
spi_test_dev.c:52: error: variable 'tr' has initializer but incomplete type
spi_test_dev.c:53: error: unknown field 'tx_buf' specified in initializer
spi_test_dev.c:53: warning: excess elements in struct initializer
spi_test_dev.c:53: warning: (near initialization for 'tr')
spi_test_dev.c:54: error: unknown field 'rx_buf' specified in initializer
spi_test_dev.c:54: warning: excess elements in struct initializer
spi_test_dev.c:54: warning: (near initialization for 'tr')
spi_test_dev.c:55: error: unknown field 'len' specified in initializer
spi_test_dev.c:55: warning: excess elements in struct initializer
spi_test_dev.c:55: warning: (near initialization for 'tr')
spi_test_dev.c:56: error: unknown field 'delay_usecs' specified in initializer
spi_test_dev.c:56: warning: excess elements in struct initializer
spi_test_dev.c:56: warning: (near initialization for 'tr')
spi_test_dev.c:57: error: unknown field 'speed_hz' specified in initializer
spi_test_dev.c:57: warning: excess elements in struct initializer
spi_test_dev.c:57: warning: (near initialization for 'tr')
spi_test_dev.c:58: error: unknown field 'bits_per_word' specified in initializer
spi_test_dev.c:58: warning: excess elements in struct initializer
spi_test_dev.c:58: warning: (near initialization for 'tr')
spi_test_dev.c:52: error: storage size of 'tr' isn't known
spi_test_dev.c: In function 'parse_opts':
spi_test_dev.c:126: error: 'SPI_LOOP' undeclared (first use in this function)
spi_test_dev.c:126: error: (Each undeclared identifier is reported only once
spi_test_dev.c:126: error: for each function it appears in.)
spi_test_dev.c:129: error: 'SPI_CPHA' undeclared (first use in this function)
spi_test_dev.c:132: error: 'SPI_CPOL' undeclared (first use in this function)
spi_test_dev.c:135: error: 'SPI_LSB_FIRST' undeclared (first use in this function)
spi_test_dev.c:138: error: 'SPI_CS_HIGH' undeclared (first use in this function)
spi_test_dev.c:141: error: 'SPI_3WIRE' undeclared (first use in this function)
spi_test_dev.c: In function 'main':
spi_test_dev.c:164: error: 'SPI_IOC_WR_MODE' undeclared (first use in this function)
spi_test_dev.c:168: error: 'SPI_IOC_RD_MODE' undeclared (first use in this function)
spi_test_dev.c:175: error: 'SPI_IOC_WR_BITS_PER_WORD' undeclared (first use in this function)
spi_test_dev.c:179: error: 'SPI_IOC_RD_BITS_PER_WORD' undeclared (first use in this function)
spi_test_dev.c:186: error: 'SPI_IOC_WR_MAX_SPEED_HZ' undeclared (first use in this function)
spi_test_dev.c:190: error: 'SPI_

 


6. So finally thought in a very vague method, Simply copy pasted spidev.h file from kernel source to -->> android-ndk-r7/platforms/android-4/arch-arm/usr/include/linux/spi/ folder.

 

Set cross-compiler for arm

$ export NDK=~/usr/android-ndk-r7
$ export NDK_TOOLCHAIN=${NDK}/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin
/arm-linux-androideabi-
$ export NDK_SYSROOT=${NDK}/platforms/android-4/arch-arm

         In order to compile it for Android we need to set CC and CFLAGS. CC will point to the cross-compiler from the
NDK toolchain. CFLAGS will set sysroot to point to the NDK directory that has the header files and libraries.

make CC=${NDK_TOOLCHAIN}gcc CFLAGS=--sysroot=${NDK_SYSROOT} spidev_test
android-ndk-r7/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc --sysroot=/android-ndk-r7/platforms/android-4/arch-arm/    spidev_test.c   -o spidev_test (Binary)

 

 It Got built without any errors. pushed the binary

 

root@sabresd_6dq:/ # spi_test_dev           [/dev/spidev0.0 hardcoded]                                
spidev spi0.0: spi_imx_setup: mode 3, 8 bpw, 1000000 hz
spidev spi0.0: setup mode 3, 8 bits/w, 1000000 Hz max --> 0
spidev spi0.0: spi mode 03
spidev spi0.0: spi_imx_setup: mode 3, 8 bpw, 1000000 hz
spidev spi0.0: setup mode 3, 8 bits/w, 1000000 Hz max --> 0
spidev spi0.0: 8 bits per word
spidev spi0.0: spi_imx_setup: mode 3, 8 bpw, 1000000 hz
spidev spi0.0: setup mode 3, 8 bits/w, 1000000 Hz max --> 0
spidev spi0.0: 1000000 Hz (max)
spi mode: 3
bits per word: 8

 


7F FF FF FF FF FF
A0 00 00 00 00 4A
FF FF FF FF FF FF
FF FF FF FF FF FF
FF FF FF FF FF FF
EF 56 DF 77 DD 56
F8 2A

 

 Finaly SPIDEV Loopback application ran successfully and could able to write/read the data.!!!!!!!!!!!!!!

Comments are well received if I have done any mistakes in the above non-working cases or any other methods are available.

Outcomes