This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Linux/PROCESSOR-SDK-AM335X: SPI Read status register of NOR flash.

Part Number: PROCESSOR-SDK-AM335X

Tool/software: Linux

We are working on AM335x processor which is connected to MT25QL256ABA Micron Serial NOR Flash Memory.

We are checking SPI interface between them. Please find Schematic and DTS definitions below.

Note: Our NOR flash is connected to SPI0.

Schematic:


 


SPI definition in DTS:

spi0_pins: spi0_pins {
        pinctrl-single,pins = <
            AM33XX_IOPAD(0x950, PIN_INPUT_PULLUP | MUX_MODE0)     //spi0_sclk
            AM33XX_IOPAD(0x954, PIN_OUTPUT_PULLUP | MUX_MODE0)     //spi0_d0
            AM33XX_IOPAD(0x958, PIN_INPUT_PULLUP | MUX_MODE0)    //spi0_d1
            AM33XX_IOPAD(0x95c, PIN_OUTPUT | MUX_MODE0)        //spi0_cs0
        >;
    };

spi1_pins: spi1_pins {
        pinctrl-single,pins = <
            AM33XX_IOPAD(0x90c, PIN_OUTPUT_PULLUP | MUX_MODE2)   /* mii1_crs.spi1_d0 */
            AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE2)  /* mii1_rxerr.spi1_d1 */
            AM33XX_IOPAD(0x908, PIN_OUTPUT_PULLDOWN | MUX_MODE2) /* mii1_col.spi1_sclk */
            AM33XX_IOPAD(0x99c, PIN_OUTPUT | MUX_MODE3)         /* mcasp0_ahclkr.spi1_cs0 */
        >;
    };

&spi0
{
     #address-cells = <1>;
     #size-cells = <0>;
    pinctrl-names = "default";
    pinctrl-0 = <&spi0_pins>;
    ti,pindir-d0-out-d1-in = <1>;
    status = "okay";
     channel@0
        {
          #address-cells = <1>;
          #size-cells = <0>;
          compatible = "spidev";
        spi-max-frequency = <48000000>;
        reg = <0x0>;
    };
};

&spi1
{
    pinctrl-names = "default";
    pinctrl-0 = <&spi1_pins>;
    ti,pindir-d0-out-d1-in = <1>;
    status = "okay";
    spidev@1
    {
        compatible = "linux,spidev";
        spi-max-frequency = <48000000>;
        reg = <0x0>;
        status = "okay";
    };
};

u-boot-2018.01+gitAUTOINC+131dc82830-g131dc82830/configs/am335x_evm_defconfig:

CONFIG_SPI_FLASH=y
CONFIG_SPI_FLASH_WINBOND=y
CONFIG_OMAP3_SPI=y

After booting its is visible under devices.

root@am335x-evm:/boot# ls -lrt /dev/s
shm/       snd/       spidev0.0  spidev1.0  stderr     stdin      stdout     

When we try to run the following test program, it is either reading all 0's or 1's.

#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.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.1";
static uint8_t mode;
static uint8_t bits = 8;
static uint32_t speed = 500000;
static uint16_t delay;

static void transfer(int fd)
{
	int ret;
	uint8_t 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,
		0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD,
		0xF0, 0x0D,
	};
	uint8_t rx[ARRAY_SIZE(tx)] = {0, };
	struct spi_ioc_transfer tr = {
		.tx_buf = (unsigned long)tx,
		.rx_buf = (unsigned long)rx,
		.len = ARRAY_SIZE(tx),
		.delay_usecs = delay,
		.speed_hz = speed,
		.bits_per_word = bits,
	};

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

	for (ret = 0; ret < ARRAY_SIZE(tx); ret++) {
		if (!(ret % 6))
			puts("");
		printf("%.2X ", rx[ret]);
	}
	puts("");
}

static void print_usage(const char *prog)
{
	printf("Usage: %s [-DsbdlHOLC3]\n", prog);
	puts("  -D --device   device to use (default /dev/spidev1.1)\n"
	     "  -s --speed    max speed (Hz)\n"
	     "  -d --delay    delay (usec)\n"
	     "  -b --bpw      bits per word \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");
	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' },
			{ "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' },
			{ NULL, 0, 0, 0 },
		};
		int c;

		c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", 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 '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 'R':
			mode |= SPI_READY;
			break;
		default:
			print_usage(argv[0]);
			break;
		}
	}
}

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_MODE, &mode);
	if (ret == -1)
		pabort("can't set spi mode");

	ret = ioctl(fd, SPI_IOC_RD_MODE, &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: %d\n", mode);
	printf("bits per word: %d\n", bits);
	printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);

	transfer(fd);

	close(fd);

	return ret;
}


root@am335x-evm:/boot# ./spi_test.out -D /dev/spidev1.0 -b 16 -H -O 0 -C 0 -s 22000000                                                                 
spi mode: 7
bits per word: 16
max speed: 22000000 Hz (22000 KHz)

00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00
root@am335x-evm:/boot# ./spi_test.out -D /dev/spidev0.0 -b 16 -H -O 0 -C 0 -s 22000000
spi mode: 7
bits per word: 16
max speed: 22000000 Hz (22000 KHz)

FF FF FF FF FF FF
FF FF FF FF FF FF
FF FF FF FF FF FF
FF FF FF FF FF FF
FF FF FF FF FF FF
FF FF FF FF FF FF
FF FF
root@am335x-evm:/boot#

We tried one other program also.

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

static uint8_t mode;
static uint8_t bits = 8;
static uint32_t speed = 500000;
static uint16_t delay;
const char *device = "/dev/spidev0.0";

char buf[10];
char buf2[10];
struct spi_ioc_transfer xfer[2];
struct spi_ioc_transfer xfer1[2];

void spi_write(int file,int value)
{
    unsigned char buf[32];
    int status;
    buf[0] = 0x06;
    xfer1[0].tx_buf = (unsigned long)buf;
    xfer1[0].len = 1; /* Length of  command to write.*/
    status = ioctl(file, SPI_IOC_MESSAGE(1), xfer1);
    if (status < 0)
    {
        perror("SPI_IOC_MESSAGE");
        return;
    }
    sleep(2);
    buf[0] = 0x01;
    buf[1] = value;
    xfer1[0].tx_buf = (unsigned long)buf;
    xfer1[0].len = 2; /* Length of  command to write*/
    status = ioctl(file, SPI_IOC_MESSAGE(1), xfer1);
    if (status < 0)
    {
        perror("SPI_IOC_MESSAGE");
        return;
    }
    printf("env: %02x %02x\n", buf[0], buf[1]);
}

void spi_read(int file)
{
    int status;
    //memset(buf, 0, 10*sizeof(buf[0]));
    //memset(buf2, 0, 10*sizeof(buf2[0]));
    buf[0] = 0x05;//0x9E;
    xfer[0].tx_buf = (unsigned long)buf;
    xfer[0].len = 1; /* Length of  command to write*/
    xfer[1].rx_buf = (unsigned long) buf2;
    xfer[1].len = 1; /* Length of Data to read */
    status = ioctl(file, SPI_IOC_MESSAGE(2), xfer);
    if (status < 0)
    {
        perror("SPI_IOC_MESSAGE");
        return;
    }
    printf("read: %02x\n", buf2[0]);

}

int main(int argc, char *argv[])
{
    int file;
    memset(buf, 0, 10*sizeof(buf[0]));
    memset(buf2, 0, 10*sizeof(buf2[0]));
    if ((file = open(device,O_RDWR)) < 0)
    {
        printf("Failed to open the bus.");
        /* ERROR HANDLING; you can check errno to see what went wrong */
        exit(1);
    }

//    printf("success to open the bus.");

    if (ioctl(file, SPI_IOC_RD_MODE, &mode) < 0)
    {
        perror("SPI rd_mode");
        return -1;
    }

    if (ioctl(file, SPI_IOC_WR_BITS_PER_WORD, &bits)<0)
    {
        perror("can't set bits per word");
              return -1;
    }

    if (ioctl(file, SPI_IOC_RD_BITS_PER_WORD, &bits)<0)
    {
        perror("SPI bits_per_word");
        return -1;
    }

    if (ioctl(file, SPI_IOC_WR_MAX_SPEED_HZ, &speed)<0)
    {
        perror("can't set max speed hz");
        return -1;
    }

    if (ioctl(file, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0)
    {
        perror("SPI max_speed_hz");
        return -1;
    }
    int val;
//    printf("Enter value to set status: ");
//    scanf("%d",&val);
//    spi_write(file,val);
    spi_read(file);
    return 0;
}

For this also read is coming out to be ff.

Our hardware also, we've verified the voltages and clock. Everything looks fine.

I am unable to proceed further. Kindly someone help me how to solve this.

Regards

Vamsi

  • Hi Vamsi,

    From what I understand you are using AM335x custom board, correct?

    Do you use AM335x PSDK Linux v5.02?

    Regards,
    Pavel
  • Yes Pavel,

    Our custom board is similar to starter kit & SDK we are using is ti-processor-sdk-linux-am335x-evm-05.00.00.15.


    Regards
    Vamsi
  • Vamsi,

    You are using spi1_d0 and spidev1.0 in your test, but I do not see SPI1 attached to your SPI NOR flash. If I am not missing something, you should remove the reference to spi1 and spidev1.0, as I do not see how this are related to NOR flash.

    Check also below e2e threads:

    e2e.ti.com/.../770985
    e2e.ti.com/.../771421

    Regards,
    Pavel

  • I changed the device to spidev0.0. This time also output is all 0s.
    #include <stdint.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <getopt.h> #include <fcntl.h> #include <sys/ioctl.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/spidev0.0"; static uint8_t mode; static uint8_t bits = 8; static uint32_t speed = 500000; static uint16_t delay; static void transfer(int fd) { int ret; uint8_t 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, 0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD, 0xF0, 0x0D, }; uint8_t rx[ARRAY_SIZE(tx)] = {0, }; struct spi_ioc_transfer tr = { .tx_buf = (unsigned long)tx, .rx_buf = (unsigned long)rx, .len = ARRAY_SIZE(tx), .delay_usecs = delay, .speed_hz = speed, .bits_per_word = bits, }; ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); if (ret < 1) pabort("can't send spi message"); for (ret = 0; ret < ARRAY_SIZE(tx); ret++) { if (!(ret % 6)) puts(""); printf("%.2X ", rx[ret]); } puts(""); } static void print_usage(const char *prog) { printf("Usage: %s [-DsbdlHOLC3]\n", prog); puts(" -D --device device to use (default /dev/spidev1.1)\n" " -s --speed max speed (Hz)\n" " -d --delay delay (usec)\n" " -b --bpw bits per word \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"); 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' }, { "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' }, { NULL, 0, 0, 0 }, }; int c; c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", 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 '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 'R': mode |= SPI_READY; break; default: print_usage(argv[0]); break; } } } 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_MODE, &mode); if (ret == -1) pabort("can't set spi mode"); ret = ioctl(fd, SPI_IOC_RD_MODE, &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: %d\n", mode); printf("bits per word: %d\n", bits); printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); transfer(fd); close(fd); return ret; }
  • Vamsi,

    In your DTS file, you need to make below update:

    channel@0
    {
    #address-cells = <1>;
    #size-cells = <0>;
    -compatible = "spidev";
    +compatible = "rohm,dh2228fv";
    spi-max-frequency = <48000000>;
    reg = <0x0>;
    };

    In later version of kernels the compatible string was changed from "spidev" to "rohm,dh2228fv". Refer to the below pointers for details:

    software-dl.ti.com/.../Foundational_Components_Kernel_Drivers.html

    linux-4.14.x/drivers/spi/spidev.c

    static const struct of_device_id spidev_dt_ids[] = {
    { .compatible = "rohm,dh2228fv" },
    { .compatible = "lineartechnology,ltc2488" },
    { .compatible = "ge,achc" },
    { .compatible = "semtech,sx1301" },
    {},
    };


    If the issue is NOT resolved by this update, please provide me:

    - the latest version of your DTS file
    - the latest version of your console boot log plus spi_test execution and result in console
    - dump McSPI0 pinmux registers in user space (before spi_test execution) and provide me the values, you can use devmem2 or omapconf tool

    Regards,
    Pavel