cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Visitor
Visitor
421 Views
Registered: ‎11-13-2018

Readings from SPI MISO (EMIO) are always 0 (while the transaction correctly occurs on the bus)

Jump to solution

Hi,

I'm trying to perform some simple read/write on SPI using Petalinux 2018.2.

Using a PL-implemented SPI controller, the SPI communication works fine; thus no issue is expected on hardware side. I want to drop the PL-instantiated SPI controller and use the SPI0 through EMIO to perform the same task.

The test consists in two programs: the first one will set some memory on the device, the second will read it back. A scope on the SPI bus, registering MOSI,MISO, CLK and CS shows that the first program performs the access as expected, and that during the second one, the read request is sent and the device answers appropriately on MISO with the values set by the first program. The issue is that the second program displays 0 for received values.

Write program:

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

#define MY_SPI_WRITE (0 << 31)
#define MY_SPI_READ (1 << 31)

int main(int argc, char* argv[])
{
	int ret = 0;
	int spi_dev;
	int mode = SPI_MODE_3;
	struct spi_ioc_transfer xfer[2];
	uint32_t buffer[4];

	/* SPI_DEV */
	if ((spi_dev = open("/dev/spidev1.0",O_RDWR)) < 0)
	{
		printf("Failed to open the bus: %s\n", strerror(errno));
		return EXIT_FAILURE;
	}

	if (ioctl(spi_dev, SPI_IOC_WR_MODE, &mode)!=0)
	{
		printf("Failed to set SPI device mode: %s\n", strerror(errno));
		return EXIT_FAILURE;
	}

	buffer[0] = 0x100000 | MY_SPI_WRITE;
	buffer[1] = 0xFFFFFFFF;
	buffer[2] = 0x0;
	buffer[3] = 0x5555AAAA;
	memset(xfer, 0, sizeof xfer);
	xfer[0].tx_buf = (uint64_t)&buffer[0];
	xfer[0].len = sizeof(buffer[0]);

	xfer[1].tx_buf = (uint64_t)&buffer[1];
	xfer[1].len = 3*sizeof(buffer[0]);

	ret = ioctl(spi_dev, SPI_IOC_MESSAGE(2), xfer);
	if (ret != 4*sizeof(buffer[0]))
	{
		printf("Failed to write to the spi bus %d: %s\n", ret, strerror(errno));
		return EXIT_FAILURE;
	}

	printf("SPI write command for %d registers succesfully sent.\n", ndata);
	return EXIT_SUCCESS;
}

 

The read program

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

#define MY_SPI_WRITE (0 << 31)
#define MY_SPI_READ (1 << 31)

int main(int argc, char* argv[])
{
	int i;
	int ret = 0;
	int spi_dev;
	int mode = SPI_MODE_3;
	struct spi_ioc_transfer xfer[2];
	uint32_t buffer[4];

	/* SPI_DEV */
	if ((spi_dev = open("/dev/spidev1.0",O_RDWR)) < 0)
	{
		printf("Failed to open the bus: %s\n", strerror(errno));
		return EXIT_FAILURE;
	}

	if (ioctl(spi_dev, SPI_IOC_WR_MODE, &mode)!=0)
	{
		printf("Failed to set SPI device mode: %s\n", strerror(errno));
		return EXIT_FAILURE;
	}

	buffer[0] = 0x100000 | MY_SPI_READ;
	memset(xfer, 0, sizeof xfer);
	xfer[0].tx_buf = (uint64_t)&buffer[0];
	xfer[0].len = sizeof(buffer[0]);
	xfer[0].delay_usecs = 4; //need to wait 64 clk before read 3.2us@20MHz

	xfer[1].rx_buf = (uint64_t)&buffer[0];
	xfer[1].len = 3*sizeof(buffer[0]);

	ret = ioctl(spi_dev, SPI_IOC_MESSAGE(2), xfer);
	if (ret != 4*sizeof(buffer[0]))
	{
		printf("Failed to read on the spi bus %d: %s\n", ret, strerror(errno));
		return EXIT_FAILURE;
	}

	printf("SPI read result: %s\n", strerror(errno));
	for (i = 0; i < 3; i++)
	{
		printf("data[%d] = 0x%08x\n", i, buffer[i]);
	}

	return EXIT_SUCCESS;
}

The program results are :

SPI write command for 3 registers succesfully sent.

SPI read result: Success
data[0] = 0x00000000
data[1] = 0x00000000
data[2] = 0x00000000

I also enabled the kernel traces for spidev, and got:

[   62.962177] spidev spi1.0: setup mode 3, 8 bits/w, 5500000 Hz max --> 0
[   62.962184] spidev spi1.0: spi mode 3
[   62.962196] spidev spi1.0:   xfer len 4 tx 8bits 0 usec 5500000Hz
[   62.962202] spidev spi1.0:   xfer len 12 tx 8bits 0 usec 5500000Hz
[   62.962257] PLL: enable
[   62.962371] spidev spi1.0: cdns_spi_setup_transfer, mode 3, 8 bits/w, 3124999 clock speed
[   62.962403] spidev spi1.0: cdns_spi_setup_transfer, mode 3, 8 bits/w, 3124999 clock speed
[   66.020362] PLL: shutdown
[   82.514034] spidev spi1.0: setup mode 3, 8 bits/w, 5500000 Hz max --> 0
[   82.514041] spidev spi1.0: spi mode 3
[   82.514053] spidev spi1.0:   xfer len 4 tx 8bits 4 usec 5500000Hz
[   82.514059] spidev spi1.0:   xfer len 12 rx 8bits 0 usec 5500000Hz
[   82.514113] PLL: enable
[   82.514227] spidev spi1.0: cdns_spi_setup_transfer, mode 3, 8 bits/w, 3124999 clock speed
[   82.514263] spidev spi1.0: cdns_spi_setup_transfer, mode 3, 8 bits/w, 3124999 clock speed
[   85.988361] PLL: shutdown

So nothing seems wrong, except the read values. On RTL side, the zynq processing system signal "emio_spi0_s_i" is mapped directly to "project_spi_miso_i" at top level, an input std_logic constrained to the U8 pad, on which the signal arrives (when using the PL-instantiated SPI, this signal is just mapped to the PL-SPI (along with the other SPI signals) instead of the EMIO).

set_property PACKAGE_PIN U8 [get_ports {project_spi_miso_i}]
set_property IOSTANDARD LVCMOS18 [get_ports {project_spi_miso_i}]

Is there any reason for the signal reaching the pin U8 to be seen as always 0 by the userland ?

0 Kudos
Reply
1 Solution

Accepted Solutions
Visitor
Visitor
395 Views
Registered: ‎11-13-2018

Got it: I just should have read the TRM more carefully.

As I'm using a XCZU-4EG, a ZynqMP, I refer to UG1085, page 636 in v1.8: SPI EMIO signals.

Signals are just not used the way I imagined:

When using the SPI as master,

SPI0 Clock is spi0_sclk_o

SPI0 MOSI is spi0_m_o

SPI0 MISO is spi0_m_i

SPI0 Slave select 0 is spi0_ss_o_n (slave select 1&2 are on spi0_ss1_o_n and spi0_ss2_o_n)

spi0_sclk_t and spio_mo_t allow to release the bus when not communicating

The other signals are useful when using the IP as SPI slave.

PS: https://www.xilinx.com/support/answers/69276.html

View solution in original post

0 Kudos
Reply
1 Reply
Visitor
Visitor
396 Views
Registered: ‎11-13-2018

Got it: I just should have read the TRM more carefully.

As I'm using a XCZU-4EG, a ZynqMP, I refer to UG1085, page 636 in v1.8: SPI EMIO signals.

Signals are just not used the way I imagined:

When using the SPI as master,

SPI0 Clock is spi0_sclk_o

SPI0 MOSI is spi0_m_o

SPI0 MISO is spi0_m_i

SPI0 Slave select 0 is spi0_ss_o_n (slave select 1&2 are on spi0_ss1_o_n and spi0_ss2_o_n)

spi0_sclk_t and spio_mo_t allow to release the bus when not communicating

The other signals are useful when using the IP as SPI slave.

PS: https://www.xilinx.com/support/answers/69276.html

View solution in original post

0 Kudos
Reply