cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
aynilian
Explorer
Explorer
5,545 Views
Registered: ‎07-05-2017

can't acces the PS SPI with Petalinux 2017.3

Jump to solution

Hi ,

 

can't access the PS SPI with Petalinux 2017.3 app build uisng IOCTL() function in my user space.

 

I created an app named "spidev"  with petalinux:

petalinux-create -t apps --name spidev --template c

 

copied the spidev.c that someone else used a few years back in the forum. See attached!.

 

included the app in the rootfs

petalinux-config -c rootfs

 

build the project

petalinux-build

 

copied the Boot.bin and image.ub in SD card and booted up the Zedboard.

 

Now if I run the app (spidev )  in the zedboard, I get an error stating " can't open device it is a directory"

 

In my code, "spidev.c" I am trying to figure out how to associate the SPI device to a device file  like this:

//static const char *device = "/dev/spidev32765.0";  this was the original code I copied, but device file did not exist
static const char *device = "/sys/devices/soc0/amba/e000d000.spi/spi_master/spi0/spi0.0";  tried this but it is a directory not a device.

 

I did a "find / -name 'spi*' " command in zedboard. I can see all these directory structures, that have SPI.

 

I have attached the  system.dts device tree for reference. Also below is the Zedboard session, SPI snippet from the device tree, and  Kernel configuration from the SPI driver selections.

 

Can someone tell me which directory the SPI device is pointed to so I can use it in the code like this:

static const char *device = "/xyz/bbb" ?

 

 

 

Screenshot from 2018-05-09 16-57-16.png

directory of all SPI references.

 

spi@e000d000 {
            clock-names = "ref_clk", "pclk";
            clocks = <0x1 0xa 0x1 0x2b>;
            compatible = "xlnx,zynq-qspi-1.0";
            status = "okay";
            interrupt-parent = <0x4>;
            interrupts = <0x0 0x13 0x4>;
            reg = <0xe000d000 0x1000>;
            #address-cells = <0x1>;
            #size-cells = <0x0>;
            u-boot,dm-pre-reloc;
            is-dual = <0x0>;
            num-cs = <0x1>;
            spi-rx-bus-width = <0x4>;
            spi-tx-bus-width = <0x4>;

            flash@0 {
                compatible = "n25q512a", "micron,m25p80";
                reg = <0x0>;
                spi-tx-bus-width = <0x1>;
                spi-rx-bus-width = <0x4>;
                spi-max-frequency = <0x2faf080>;
                #address-cells = <0x1>;
                #size-cells = <0x1>;

 

 

 

 

Screenshot from 2018-05-09 17-13-50.png

 

 

0 Kudos
Reply
1 Solution

Accepted Solutions
5,889 Views
Registered: ‎04-20-2017

here from my working system-user.dtsi in petalinux 2017.3/4

/include/ "system-conf.dtsi"
/ {
};

&spi0{
   #address-cells=<1>;
   #size-cells=<0>;
   status = "okay";


    axispidevice: spidev@0 {
         compatible = "spidev";
          reg = <0>;
           spi-max-frequency = <3125000>;
     };


};

View solution in original post

14 Replies
5,517 Views
Registered: ‎04-20-2017
I don't get your idea of copying the spidev.c file.

Your device tree does not show any spidev node, hence also no spidev device is exposed in userspace

I suggest you to read up on how use it and alter the device tree for it correctly
0 Kudos
Reply
aynilian
Explorer
Explorer
5,496 Views
Registered: ‎07-05-2017

Hi juergen, 

 

Thanks for taking the time to respond.

 

jk>don't get your idea of copying the spidev.c file.

 

spidev.c is just the name for an app that was created. I could have named it xyz.c.  It is a user space application that uses device files i.e /dev/xxx to read and write to a device. I use the command "petalinux-create -t apps --name spidev --template c"


jk>Your device tree does not show any spidev node, hence also no spidev device is exposed in userspace

 

The intent is not write a platform spidev driver to bind the device "compatible" field in the device tree to a "character, block, or Network" device on the device file system. This should have been done by including the suggested SPI drivers in the kernel configurations as shown in the Kernel setup picture.

 

 I have some working examples of GPIO and Block-Ram apps in Petalinux done in similar way.  Did not have to bind the "compatible" field in the device tree to a fops operation. All that was needed:

 fd = open ("/dev/mem", O_RDWR|O_SYNC) and use the mmap()  functin to get a userspace pointer or an ioctl() function to transfer data to the device.

 

Note: The petalinux build with the appropriate spi driver in the kernel configurations should have created the device files under /dev/...spi whatever... And this is what my question is. Where is this device file?

 

 jk> I suggest you to read up on how use it and alter the device tree for it correctly

 

As far as I have read and implemented platform device drivers for AXI-IP on a zynq petalinux system, a device tree is used or modified to match the compatible field in a match table specified in the driver. Not getting into the details on how to write a platform device driver for now, but If anyone is interested, I can share how a Platfrom device driver was implemented ( This is off tangent).  But my intent is not write a driver for SPI, since the drivers are already configured in the kernel. All I want to do is use the ioctl() function to transfer data to and from the device. Hence, my question "Where is this  /dev/ ???? SPI  device file?".  But if there are Xilinx user guides on how to use the ioctl() or mmap()  functions in user space applications that mention using the device tree, could you share the link.

 

Regard,

Aynilian

 

 

0 Kudos
Reply
5,473 Views
Registered: ‎04-20-2017
have a look at
https://www.kernel.org/doc/Documentation/spi/spidev

it says:
Do not try to manage the /dev character device special file nodes by hand.
That's error prone,

i might be misunderstanding you

- fix your device tree (i might be able to send you how my working node for the cadence spi looks like)
- when done right you will automatically get /dev/spidevB.C as described in the link
- you can open that and use the ioctl calls
0 Kudos
Reply
aynilian
Explorer
Explorer
5,417 Views
Registered: ‎07-05-2017

Hi Juergen,

 

The project file structure in petalinux 2017.3 has the system-user.dtsi that can be modified is under

<myproj>/project-spec/meta-user/recipes-bsp/device-tree/files

 

modifying the system-user.dtsi, will change the device tree "system.dtb" that is compiled under <myproj>/images/linux/system.dtb

 

I decompiled the system.dtb to system.dts and listed the spi poprt for reference. In it you can see the aliases for spi nodes. 

....

spi@e0006000 {
            compatible = "xlnx,zynq-spi-r1p6";
            reg = <0xe0006000 0x1000>;
            status = "okay";
            interrupt-parent = <0x4>;
            interrupts = <0x0 0x1a 0x4>;
            clocks = <0x1 0x19 0x1 0x22>;
            clock-names = "ref_clk", "pclk";
            #address-cells = <0x1>;
            #size-cells = <0x0>;
            is-decoded-cs = <0x0>;
            num-cs = <0x3>;
        };

 

 

..

aliases {
        ethernet0 = "/amba/ethernet@e000b000";
        serial0 = "/amba/serial@e0001000";
        spi0 = "/amba/spi@e000d000";
        spi1 = "/amba/spi@e0006000"; 

The highlighted is the SPI port I'm interested in, so I need to bind "spidev" to this spi1 node.

 

So I need to modify the system-user.dtsi to reflect node binding to spidev. There is a link that describes how to do this for system-top.dts. Here is the link: https://www.beyond-circuits.com/wordpress/tutorial/tutorial26/ but, in my build directory structure for 2017.3, there is no system-top.dts that I can modify.

 

 I can modify the .dtsi under:

<myproj>/project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi that looks like this:

 

/include/ "system-conf.dtsi"
/ {
&spi1{
    is-decoded-cs = <0>;
    num-cs = <1>;
    status = "okay";
    spidev@0x00 {
        compatible = "spidev";
        spi-max-frewquency = <1000000>;
        reg = <0>;
        };
    };
};

 

but the above modification does not compile.The petalinux-build does not know what is &spi1 alias.

So I tried this instead in system-user.dtsi. See below:

 

include/ "system-conf.dtsi"
/ {
    
        spi@e0006000 {
            compatible = "xlnx,zynq-spi-r1p6";
            reg = <0xe0006000 0x1000>;
            status = "okay";
            interrupt-parent = <0x4>;
            interrupts = <0x0 0x1a 0x4>;
            clocks = <0x1 0x19 0x1 0x22>;
            clock-names = "ref_clk", "pclk";
            #address-cells = <0x1>;
            #size-cells = <0x0>;
            is-decoded-cs = <0x0>;
            num-cs = <0x3>;
            spidev@0x00 {
                compatible = "spidev";
                    spi-max-frequency = <1000000>;
                    reg = <0>;
            };
        };
    
};

 

 

 

After running petalinux-build I see the system.dtb under ./images/linux/system.dtb (I converted it to system.dts). I see at the bottom section of the file, the appended section from system-user.dtsi. See second attachment system.dts.

 

booted the board with petalinux build, and looked for /dev/spi*, but  I see nothing.

 

searched for "find / -name 'spidev*' and I see this:
/sys/firmware/devicetree/base/spi@006000/spidev@0x00

 

 

If you would like to share your device tree file, I would appreciate it. Let me know your directory structure for where your modifying your device tree as well, and what  is the petalinux version you are using?

 

Thanks,

Aynilian

 

 

 

 

 

I

0 Kudos
Reply
aynilian
Explorer
Explorer
5,422 Views
Registered: ‎07-05-2017

Hi Juergen,

 

The project file structure in petalinux 2017.3 has the system-user.dtsi that can be modified is under

<myproj>/project-spec/meta-user/recipes-bsp/device-tree/files

 

modifying the system-user.dtsi, will change the device tree "system.dtb" that is compiled under <myproj>/images/linux/system.dtb

 

I decompiled the system.dtb to system.dts and listed the spi poprt for reference. In it you can see the aliases for spi nodes. 

....

spi@e0006000 {
            compatible = "xlnx,zynq-spi-r1p6";
            reg = <0xe0006000 0x1000>;
            status = "okay";
            interrupt-parent = <0x4>;
            interrupts = <0x0 0x1a 0x4>;
            clocks = <0x1 0x19 0x1 0x22>;
            clock-names = "ref_clk", "pclk";
            #address-cells = <0x1>;
            #size-cells = <0x0>;
            is-decoded-cs = <0x0>;
            num-cs = <0x3>;
        };

 

 

..

aliases {
        ethernet0 = "/amba/ethernet@e000b000";
        serial0 = "/amba/serial@e0001000";
        spi0 = "/amba/spi@e000d000";
        spi1 = "/amba/spi@e0006000"; 

The highlighted is the SPI port I'm interested in, so I need to bind "spidev" to this spi1 node.

 

So I need to modify the system-user.dtsi to reflect node binding to spidev. There is a link that describes how to do this for system-top.dts. Here is the link: https://www.beyond-circuits.com/wordpress/tutorial/tutorial26/ but, in my build directory structure for 2017.3, there is no system-top.dts that I can modify.

 

 I can modify the .dtsi under:

<myproj>/project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi that looks like this:

 

/include/ "system-conf.dtsi"
/ {
&spi1{
    is-decoded-cs = <0>;
    num-cs = <1>;
    status = "okay";
    spidev@0x00 {
        compatible = "spidev";
        spi-max-frewquency = <1000000>;
        reg = <0>;
        };
    };
};

 

but the above modification does not compile.The petalinux-build does not know what is &spi1 alias.

So I tried this instead in system-user.dtsi. See below:

 

include/ "system-conf.dtsi"
/ {
    
        spi@e0006000 {
            compatible = "xlnx,zynq-spi-r1p6";
            reg = <0xe0006000 0x1000>;
            status = "okay";
            interrupt-parent = <0x4>;
            interrupts = <0x0 0x1a 0x4>;
            clocks = <0x1 0x19 0x1 0x22>;
            clock-names = "ref_clk", "pclk";
            #address-cells = <0x1>;
            #size-cells = <0x0>;
            is-decoded-cs = <0x0>;
            num-cs = <0x3>;
            spidev@0x00 {
                compatible = "spidev";
                    spi-max-frequency = <1000000>;
                    reg = <0>;
            };
        };
    
};

 

 

 

After running petalinux-build I see the system.dtb under ./images/linux/system.dtb (I converted it to system.dts). I see at the bottom section of the file, the appended section from system-user.dtsi. See second attachment system.dts.

 

booted the board with petalinux build, and looked for /dev/spi*, but  I see nothing.

 

searched for "find / -name 'spidev*' and I see this:
/sys/firmware/devicetree/base/spi@006000/spidev@0x00

 

 

If you would like to share your device tree file, I would appreciate it. Let me know your directory structure for where your modifying your device tree as well, and what  is the petalinux version you are using?

 

Thanks,

Aynilian

 

 

 

 

 

I

0 Kudos
Reply
aynilian
Explorer
Explorer
5,416 Views
Registered: ‎07-05-2017

I got my system.dtb in <myproj>/images/linux/system.dtb update by writing in the <myproj>/project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi

 

Here is the syetem-user.dtsi

Screenshot from 2018-05-15 17-19-47.png

 

it updated the <myproj>/images/linux/system.dtb  like here is a section of it:

Screenshot from 2018-05-15 17-22-18.png

 

 

But booting up the petalinux kernel, on the Zedboard, I still don't see the /dev/spidev??.

 

 

Screenshot from 2018-05-15 19-11-41.png

 

Screenshot from 2018-05-15 19-13-27.png

Screenshot from 2018-05-15 19-14-52.png

 

 

Okay, I'm not sure what else can I do to create a /dev/spidev .

 

 

 

 

 

 

 

 

0 Kudos
Reply
5,404 Views
Registered: ‎04-20-2017
System-user.dtsi is the right place to modify

The code you posted is right in principle.

The reason it most likely does not find spi1 node are the additional brackets you put. /{}. Try to remove those.

You are aware of the typo in frequency?
0 Kudos
Reply
5,890 Views
Registered: ‎04-20-2017

here from my working system-user.dtsi in petalinux 2017.3/4

/include/ "system-conf.dtsi"
/ {
};

&spi0{
   #address-cells=<1>;
   #size-cells=<0>;
   status = "okay";


    axispidevice: spidev@0 {
         compatible = "spidev";
          reg = <0>;
           spi-max-frequency = <3125000>;
     };


};

View solution in original post

aynilian
Explorer
Explorer
5,376 Views
Registered: ‎07-05-2017

Hi Juergen,

 

Thanks for your help. It worked. I'm just going to go over all the steps from Vivado block design to Petalinux build to show whoever is intereseted how PS-SPI0 device node is created in Petalinux file system. Also, it is a great reminder for me a month from now to see how it was done.

 

1. Create project an RTL project in Vivado and in the IDE Create Block Design and instantiate "Zynq7 processing system"

Screenshot from 2018-05-16 16-08-45.png

Screenshot from 2018-05-16 16-09-58.png

Screenshot from 2018-05-16 15-43-25.png

 

Screenshot from 2018-05-16 16-12-16.png

I tied the EMIO PS-SPI0 pins to Zedboard's JB1 connector for probing.

 

After Synthesis - Place-Rout and Bit stream Generation, Export Hardware as shown below:

 

Screenshot from 2018-05-16 16-15-57.png

 

From Vivado Launch SDK and create a "zynq_fsbl" project and build all:

 

Screenshot from 2018-05-16 16-15-57.png

 

 

 

Screenshot from 2018-05-16 16-27-03.png

Screenshot from 2018-05-16 16-28-07.png

 

 

Now that you have build a Vivado Project, it is time to create a Petalinux Project using something like this:

Open a Linux Ubuntu console in your Ubuntu System.

 

Note: the bsp and project names will be different based on your personal preferecnes for installations directory names.

Run this command:

& petalinux-create -t project --name mmd_project_1 --source /opt/zed_bsp/avnet-digilent-zedboard-v2017.3-final.bsp --force

 

 

After creating the Petalinux Project directory (In this example it is "mmd_project_1"), get the hardware definition file from the Vivado Project that you just created.

 

$ petalinux-config --get-hw-description project_2/project_2.sdk --project mmd_project_1

The above command will lunch a configuration Screen. Select go through it and exit out.

 

$ cd <petalinux_project>  (in this case mmd_project_1) and run kernel menu configuration command.

~/mmd_project_1$ petalinux-config -c kernel

This will  launch the Kernel configuration screen. Select the Device-Drivers -> SPI support --> It should look like this:

 

Screenshot from 2018-05-16 16-45-12.png

 

 In the Directory:

~/mmd_project_1/project-spec/meta-user/recipes-bsp/device-tree/files$

Edited the "system-user.dtsi" to make it look like shown below. Do not touch any other device tree files. I

 

   

Screenshot from 2018-05-16 15-38-24.png

 

build the petalinux kernel using the command:

 ~/mmd_project_1 $ petalinux-build

 

After build is done, go to:

~/mmd_project_1 $ cd images/linux/  

You should see this file "system.dtb"

 

I just run this command to decompile the system.dtb to system.dts:

~/mmd_project_1/images/linux$ dtc -I dtb -O dts system.dtb >system.dts

 

You can look at the system.dts. The SPI0  tree section  should look like this:

 

 

Screenshot from 2018-05-16 17-01-21.png

 

 

Now run Petalinux-build command

~/mmd_project_1$ petalinux-build

 

Create an app named spitest.

:~/mmd_project_1$ petalinux-create -t apps --name spitest --template c

I have attached the spitest.c file to support post.

 

Go to spitest directory and compile the app:

~/mmd_project_1/project-spec/meta-user/recipes-apps/spitest/files$ arm-linux-gnueabihf-gcc spitest.c -lm -o spitest

 

copy the spitest binary file to the SD card or you can use SSH and copy it to your FPGA board.

 

cd   (To Root)

Run the package command. This is based on your petalinux project and Vivado project design files.:

 

$ petalinux-package --boot --format BIN --project mmd_project_1 --fsbl project_2/project_2.sdk/zynq_fsbl/Release/zynq_fsbl.elf --fpga project_2/project_2.runs/impl_1/spi_design_1_wrapper.bit --u-boot --force

 

cd to :

~/mmd_project_1/images/linux$

 

you should see a directory structure like this:

 

Screenshot from 2018-05-16 17-08-00.png

 

 

Copy BOOT.bin,  image.ub, and system.dtb  to the SD.

 

Screenshot from 2018-05-16 17-16-48.png

 

 

 

 

Boot the FPGA board using the newly copied SD mentioned above.

 

Connect the Serial USB port of the FPGA board to your PC with a terminal console program running:

 

After the board boots and you log in, mount the SD card on the FPGA Petalinux system.

 

Screenshot from 2018-05-16 17-19-14.png

 

cd into the SD card and look at the files, make sure the spitest is there.

 

Screenshot from 2018-05-16 17-21-55.png

 

Do:

# ls /dev/spi*

To make sure the spedev node is in the file system. In this case it is named: /dev/spidev1.0

 

Screenshot from 2018-05-16 17-23-29.png

 

Now you can run the spitest code with the appropriate option to transmit and receive data on the PS-SP0 port.

 

Screenshot from 2018-05-16 17-25-36.png

I scoped the SPICK and MOSI port on the JB1 connector on my zedboard and I can see transmit activity.

 

Here is the spitest.c code attached"

 

Let me know if you have any further questions.

Cheers!

 

 

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

 

/*
 * SPI testing utility (using spidev driver)
 *
 * Copyright (c) 2007  MontaVista Software, Inc.
 * Copyright (c) 2007  Anton Vorontsov <avorontsov@ru.mvista.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License.
 *
 * Cross-compile with cross-gcc -I/path/to/cross-kernel/include
 */

#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

static void pabort(const char *s)
{
    perror(s);
    abort();
}

static const char *device = "/dev/spidev1.0";
static uint32_t mode;
static uint8_t bits = 8;
static char *input_file;
static char *output_file;
static uint32_t speed = 500000;
static uint16_t delay;
static int verbose;

uint8_t default_tx[] = {
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0x40, 0x00, 0x00, 0x00, 0x00, 0x95,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xF0, 0x0D,
};

uint8_t default_rx[ARRAY_SIZE(default_tx)] = {0, };
char *input_tx;

static void hex_dump(const void *src, size_t length, size_t line_size,
             char *prefix)
{
    int i = 0;
    const unsigned char *address = src;
    const unsigned char *line = address;
    unsigned char c;

    printf("%s | ", prefix);
    while (length-- > 0) {
        printf("%02X ", *address++);
        if (!(++i % line_size) || (length == 0 && i % line_size)) {
            if (length == 0) {
                while (i++ % line_size)
                    printf("__ ");
            }
            printf(" | ");  /* right close */
            while (line < address) {
                c = *line++;
                printf("%c", (c < 33 || c == 255) ? 0x2E : c);
            }
            printf("\n");
            if (length > 0)
                printf("%s | ", prefix);
        }
    }
}

/*
 *  Unescape - process hexadecimal escape character
 *      converts shell input "\x23" -> 0x23
 */
static int unescape(char *_dst, char *_src, size_t len)
{
    int ret = 0;
    int match;
    char *src=_src;
    char *dst = _dst;
    unsigned int ch;

    while (*src) {
        if (*src== '\\' && *(src+1) == 'x') {
            match = sscanf(src + 2, "%2x", &ch);
            if (!match)
                pabort("malformed input string");

            src += 4;
            *dst++ = (unsigned char)ch;
        } else {
            *dst++ = *src++;
        }
        ret++;
    }
    return ret;
}

static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
{
    int ret;
    int out_fd;
    struct spi_ioc_transfer tr = {
        .tx_buf = (unsigned long)tx,
        .rx_buf = (unsigned long)rx,
        .len = len,
        .delay_usecs = delay,
        .speed_hz = speed,
        .bits_per_word = bits,
    };

    if (mode & SPI_TX_QUAD)
        tr.tx_nbits = 4;
    else if (mode & SPI_TX_DUAL)
        tr.tx_nbits = 2;
    if (mode & SPI_RX_QUAD)
        tr.rx_nbits = 4;
    else if (mode & SPI_RX_DUAL)
        tr.rx_nbits = 2;
    if (!(mode & SPI_LOOP)) {
        if (mode & (SPI_TX_QUAD | SPI_TX_DUAL))
            tr.rx_buf = 0;
        else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL))
            tr.tx_buf = 0;
    }

    ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
    if (ret < 1)
        pabort("can't send spi message");

    if (verbose)
        hex_dump(tx, len, 32, "TX");

    if (output_file) {
        out_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
        if (out_fd < 0)
            pabort("could not open output file");

        ret = write(out_fd, rx, len);
        if (ret != len)
            pabort("not all bytes written to output file");

        close(out_fd);
    }

    if (verbose || !output_file)
        hex_dump(rx, len, 32, "RX");
}

static void print_usage(const char *prog)
{
    printf("Usage: %s [-DsbdlHOLC3]\n", prog);
    puts("  -D --device   device to use (default /dev/spidev1.0)\n"
         "  -s --speed    max speed (Hz)\n"
         "  -d --delay    delay (usec)\n"
         "  -b --bpw      bits per word\n"
         "  -i --input    input data from a file (e.g. \"test.bin\")\n"
         "  -o --output   output data to a file (e.g. \"results.bin\")\n"
         "  -l --loop     loopback\n"
         "  -H --cpha     clock phase\n"
         "  -O --cpol     clock polarity\n"
         "  -L --lsb      least significant bit first\n"
         "  -C --cs-high  chip select active high\n"
         "  -3 --3wire    SI/SO signals shared\n"
         "  -v --verbose  Verbose (show tx buffer)\n"
         "  -p            Send data (e.g. \"1234\\xde\\xad\")\n"
         "  -N --no-cs    no chip select\n"
         "  -R --ready    slave pulls low to pause\n"
         "  -2 --dual     dual transfer\n"
         "  -4 --quad     quad transfer\n");
    exit(1);
}

static void parse_opts(int argc, char *argv[])
{
    while (1) {
        static const struct option lopts[] = {
            { "device",  1, 0, 'D' },
            { "speed",   1, 0, 's' },
            { "delay",   1, 0, 'd' },
            { "bpw",     1, 0, 'b' },
            { "input",   1, 0, 'i' },
            { "output",  1, 0, 'o' },
            { "loop",    0, 0, 'l' },
            { "cpha",    0, 0, 'H' },
            { "cpol",    0, 0, 'O' },
            { "lsb",     0, 0, 'L' },
            { "cs-high", 0, 0, 'C' },
            { "3wire",   0, 0, '3' },
            { "no-cs",   0, 0, 'N' },
            { "ready",   0, 0, 'R' },
            { "dual",    0, 0, '2' },
            { "verbose", 0, 0, 'v' },
            { "quad",    0, 0, '4' },
            { NULL, 0, 0, 0 },
        };
        int c;

        c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3NR24p:v",
                lopts, NULL);

        if (c == -1)
            break;

        switch (c) {
        case 'D':
            device = optarg;
            break;
        case 's':
            speed = atoi(optarg);
            break;
        case 'd':
            delay = atoi(optarg);
            break;
        case 'b':
            bits = atoi(optarg);
            break;
        case 'i':
            input_file = optarg;
            break;
        case 'o':
            output_file = optarg;
            break;
        case 'l':
            mode |= SPI_LOOP;
            break;
        case 'H':
            mode |= SPI_CPHA;
            break;
        case 'O':
            mode |= SPI_CPOL;
            break;
        case 'L':
            mode |= SPI_LSB_FIRST;
            break;
        case 'C':
            mode |= SPI_CS_HIGH;
            break;
        case '3':
            mode |= SPI_3WIRE;
            break;
        case 'N':
            mode |= SPI_NO_CS;
            break;
        case 'v':
            verbose = 1;
            break;
        case 'R':
            mode |= SPI_READY;
            break;
        case 'p':
            input_tx = optarg;
            break;
        case '2':
            mode |= SPI_TX_DUAL;
            break;
        case '4':
            mode |= SPI_TX_QUAD;
            break;
        default:
            print_usage(argv[0]);
            break;
        }
    }
    if (mode & SPI_LOOP) {
        if (mode & SPI_TX_DUAL)
            mode |= SPI_RX_DUAL;
        if (mode & SPI_TX_QUAD)
            mode |= SPI_RX_QUAD;
    }
}

static void transfer_escaped_string(int fd, char *str)
{
    size_t size = strlen(str + 1);
    uint8_t *tx;
    uint8_t *rx;

    tx = malloc(size);
    if (!tx)
        pabort("can't allocate tx buffer");

    rx = malloc(size);
    if (!rx)
        pabort("can't allocate rx buffer");

    size = unescape((char *)tx, str, size);
    transfer(fd, tx, rx, size);
    free(rx);
    free(tx);
}

static void transfer_file(int fd, char *filename)
{
    ssize_t bytes;
    struct stat sb;
    int tx_fd;
    uint8_t *tx;
    uint8_t *rx;

    if (stat(filename, &sb) == -1)
        pabort("can't stat input file");

    tx_fd = open(filename, O_RDONLY);
    if (fd < 0)
        pabort("can't open input file");

    tx = malloc(sb.st_size);
    if (!tx)
        pabort("can't allocate tx buffer");

    rx = malloc(sb.st_size);
    if (!rx)
        pabort("can't allocate rx buffer");

    bytes = read(tx_fd, tx, sb.st_size);
    if (bytes != sb.st_size)
        pabort("failed to read input file");

    transfer(fd, tx, rx, sb.st_size);
    free(rx);
    free(tx);
    close(tx_fd);
}

int main(int argc, char *argv[])
{
    int ret = 0;
    int fd;

    parse_opts(argc, argv);

    fd = open(device, O_RDWR);
    if (fd < 0)
        pabort("can't open device");

    /*
     * spi mode
     */
    ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
    if (ret == -1)
        pabort("can't set spi mode");

    ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode);
    if (ret == -1)
        pabort("can't get spi mode");

    /*
     * bits per word
     */
    ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
    if (ret == -1)
        pabort("can't set bits per word");

    ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
    if (ret == -1)
        pabort("can't get bits per word");

    /*
     * max speed hz
     */
    ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
    if (ret == -1)
        pabort("can't set max speed hz");

    ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
    if (ret == -1)
        pabort("can't get max speed hz");

    printf("spi mode: 0x%x\n", mode);
    printf("bits per word: %d\n", bits);
    printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);

    if (input_tx && input_file)
        pabort("only one of -p and --input may be selected");

    if (input_tx)
        transfer_escaped_string(fd, input_tx);
    else if (input_file)
        transfer_file(fd, input_file);
    else
        transfer(fd, default_tx, default_rx, sizeof(default_tx));

    close(fd);

    return ret;
}

 

 

 

 

4,501 Views
Registered: ‎04-20-2017
note that petalinux-build also builds your fsbl, you can omit the step of building it by yourself in SDK, i bet it will be helpful to others
0 Kudos
Reply
eyeray
Contributor
Contributor
3,262 Views
Registered: ‎10-29-2018

Hi @aynilian 

I have a question in your vivado design, why you put the SS_I in (ip)constant? 

Best Regards

0 Kudos
Reply
aynilian
Explorer
Explorer
3,239 Views
Registered: ‎07-05-2017

Hi eyeray,

I think I just tied it to a constant. I think the Zynq Technical Reference Manual (TRM) page 554 wants you to tie it to High.

trm_spi.png 

Regards!

eyeray
Contributor
Contributor
3,187 Views
Registered: ‎10-29-2018

Hi @aynilian 

Thanks for your answer.

I really appreciate it cause i missed such important information.

0 Kudos
Reply
in_peace
Observer
Observer
924 Views
Registered: ‎08-24-2020

hello, I confused ablout why the rx is different from tx?

0 Kudos
Reply