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.

Need help switching to 16 bits per word for SPI

Other Parts Discussed in Thread: AM3359

I'm using spidev access to use SPI on an AM3359 running linux.  I want to send 16 bits per word so I'm using the following command:

status1 = ioctl(fd1, SPI_IOC_WR_BITS_PER_WORD, &bits);

where bits is 16

When I run the code I get an error: "SPI_IOC_MESSAGE: Input/output error"

When I change the bits value to 8, the code runs without error.  Is there another place I need to set the bits per word to 16 to run without error?

Thanks,

Alex

  • Hi Alex,
     
    I'm no Linux expert but the McSPI channel must be disabled by clearing MCSPI_CHxCTRL Register bit EN, then the word length can be set in MCSPI_CHxCONF Register field WL, and finally the McSPI channel must be reenabled by setting MCSPI_CHxCTRL Register bit EN.
  • I'll give this a try but I need some help.  

    First, I'm trying to understand the relationship between spidev and McSPI.  Do I understand correctly that, from Linux, I use spidev functions that use the McSPI driver to operate the hardware SPI IO?

    When I use the function call,

    status1 = ioctl(fd1, SPI_IOC_WR_BITS_PER_WORD, &bits);

    and read it back, I get the correct value of 16 bits back.  So would this imply that this setting doesn't set the McSPI bits per word value?  Or is it just because the channel wasn't disabled before changing the value?  I don't see a way from spidev functions to disable the channel.

    With that out of the way, what is the syntax for setting these registers from Linux?  Do I use iowrite function?  How do I determine the base address of SPI channel 1 from linux userspace?

    Thanks,

    Alex

  • Did you set the IOC mode to write?  SPI_IOC_WR_MODE.

    I set both IOC_RD_BITS & IOC_WR_BITS.  I've confirmed that 8, 16, or 32 bits are transferred per SPI operation

  • I did set the SPI mode using SPI_IOC_WR_MODE, and I'm using Mode 0, CPOL=0, CPHA=0.

    Here is code that causes the error:

    ***************************************************************************************************************************


    #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <string.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> #include <linux/types.h> #include <linux/spi/spidev.h> static int verbose; int main(void){ char bits = 16; char mode = 0; int fd1=0; int len = 7; struct spi_ioc_transfer xfer1[2]; int buf1[32], *bp1; int status1; memset(xfer1, 0, sizeof xfer1); memset(buf1, 0, sizeof buf1); fd1 = open("/dev/spidev1.0", O_RDWR); if (fd1 < 0) { printf("SPI1 : can't open device"); return -1; } status1 = ioctl(fd1, SPI_IOC_WR_BITS_PER_WORD, &bits); if (status1 < 0) { perror("SPI_IOC_MESSAGE"); return; } status1 = ioctl(fd1, SPI_IOC_WR_MODE, &mode); if (status1 < 0) { perror("SPI_IOC_MESSAGE"); return; } buf1[0] = 0xE800; buf1[1] = 0xE900; buf1[2] = 0xEA00; buf1[3] = 0xEB00; buf1[4] = 0xEC00; buf1[5] = 0xE800; buf1[6] = 0xE900; xfer1[0].tx_buf = (unsigned long)buf1; xfer1[0].len = 7; xfer1[1].rx_buf = (unsigned long)buf1; xfer1[1].len = 7; status1 = ioctl(fd1, SPI_IOC_MESSAGE(2), xfer1); if (status1 < 0) { perror("SPI_IOC_MESSAGE"); return; } printf("response(%2d, %2d): ", len, status1); for (bp1 = buf1; len; len--) printf(" %04x", *bp1++); printf("\n"); }

    ***************************************************************************************************************************

    and here is the spi entry in my board-am335x.c file:

    ***************************************************************************************************************************

    static struct spi_board_info am335x_spi0_slave_info[] = {
    .modalias = "spidev",
    .irq = -1,
    .max_speed_hz = 24000000,
    .bus_num = 1,
    .chip_select = 0,
    };

    ***************************************************************************************************************************

    Thanks for the help!

    Alex

  • I probed the SPI lines and see that I am actually transferring 16-bit values now.  However, the overall problem still exists that the code errors with "SPI_IOC_MESSAGE: Input/output error".  I get this error and the SPI stops transferring 3-4 words into a 9 word transfer length.

    Why would I get "SPI_IOC_MESSAGE: Input/output error", especially after several successful word transfers?

    Thanks,

    Alex

  • I found the solution to the IO error.  The length value "len" in the spi_ioc_transfer structure defines transfer bytes.  I was using it as words.  So for 16 bit transfers "len" would be 2.

    Thanks for all the help!

    Alex