This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm whether you accept or reject these cookies being set.

A cookie will be stored in your browser regardless of choice to prevent you being asked this question again. You will be able to change your cookie settings at any time using the link in the footer.

Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Spi clock problem
#1
Hello,
I´m trying to use the SPI bus to communicate with some E-ink screen via SPI.
 I got some communication with the screen but the communication is not accurate.  In the Screen data sheet the spi clock behavior should be:
28872727-b98bc80c-778a-11e7-8a01-fa589092a183.png (10.53 KB)
   

But when I use a test program to check the SPI bus:
28872711-ab366438-778a-11e7-8b28-89eb8d9tf13602.jpg (289.57 KB)
   

Is there a way to manage the SPI clock to do 8 bits pauses?

Thanks
Reply
#2
Could you share the test program for us ?
Reply
#3
(08-04-2017, 02:13 AM)jamess Wrote: Could you share the test program for us ?
 Yes, here you go.
Code:
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>

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


int main(int argc, char **argv)
{
    int i,fd;
    char wr_buf[]={0xff,0x00,0x1f,0x0f};
    char rd_buf[10];;

    if (argc<2) {
        printf("Usage:\n%s [device]\n", argv[0]);
        exit(1);
    }
      
    fd = open(argv[1], O_RDWR);
    if (fd<=0) {
        printf("%s: Device %s not found\n", argv[0], argv[1]);
        exit(1);
    }
    
    if (write(fd, wr_buf, ARRAY_SIZE(wr_buf)) != ARRAY_SIZE(wr_buf))
        perror("Write Error");
    if (read(fd, rd_buf, ARRAY_SIZE(rd_buf)) != ARRAY_SIZE(rd_buf))
        perror("Read Error");
    else
        for (i=0;i<ARRAY_SIZE(rd_buf);i++) {
        printf("0x%02X ", rd_buf[i]);
        if (i%2)
            printf("\n");
    }

    close(fd);
    return 0;
}

For synchronous transfer, you can have a look at the example from Documentation/spi. It is slightly changed, as the at91-spi driver does not support to change speed or bits per word via the ioctl-transfer interface. You can cross-compile it
with your-cross-gcc -o spidev-test -I/path-to-cross-kernel-include spidev-test.c. Of course you can also use your compiler on the target board (Make sure you have the package linux-libc-dev installed). Later you can run it like this: spidev-test -D /dev/spidev1.0.

/*
* SPI testing utility (using spidev driver)
*
* Copyright (c) 2007  MontaVista Software, Inc.
* Copyright (c) 2007  Anton Vorontsov
*
* 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 <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/spidev2.0";
static uint8_t mode = 0;
static uint8_t bits = 8;
static uint32_t speed = 1000000;
static uint16_t delay;

static void transfer(int fd)
{
    int ret;
    uint8_t tx[] = {
        0x80,0x81,0x81
    };
    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 = 0,
        .bits_per_word = 0,
    };

    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("");
}

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);
}

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' },
            { NULL, 0, 0, 0 },
        };
        int c;

        c = getopt_long(argc, argv, "D:s:d:b:lHOLC3", 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;
        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);
      for(;;)
    transfer(fd);

    close(fd);

    return ret;
}
Reply
#4
Thumbs Up 
Hello,

I have reproduced this issue, and there are two informally solutions.

First, you can send command/data one byte per tr(spi_ioc_transfer) in your test program.
It's easy that call transfer() and put only one byte in .tx_buf.
BTW, if you use this solution, please remember to mark below codes in transfer():

Quote:       if (ret == 1)
                pabort("can't send spi message");


Second, you can add the delay time manually into the driver of SPI controller after transferring a word.
Please reference to attached patch, and enter the kernel folder of codebase to type:

Quote:        git am THE_PATCH_NAME

I have validated this solution with WaveShare 3.5" & 4" touch screen, they can work well.


Please have a try and let me know if any question~
Thank you.

PS. BTW, could you please share the E-ink product number?

BR,
YC


Attached Files
.zip   0001-Add-delay-between-SPI-transfer-words.zip (Size: 1,005 bytes / Downloads: 14)
Reply
#5
Thanks for your help. But i have a silly question. How I compile the kernel?(https://github.com/TinkerBoard/debian_kernel)

Thanks!
Reply
#6
The E-Ink screen is PaPiRus Zero – ePaper / eInk Screen pHAT for Pi Zero.

Thanks!
Reply
#7
Ok, I already discover how to compiler the kernel.
During the kernel compilation:
sudo make rockchip_linux_defconfig
sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
I get an error:
/tinkercustom/debian_kernel/drivers/net/ethernet/stmicro/stmmac/eth_mac_tinker.c:39: Nicht definierter Verweis auf `at24_read_eeprom'
Reply
#8
for building kernel
$ make ARCH=arm miniarm-rk3288_defconfig -j16
$ make zImage ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j16

then you will get a file in the following path
arch/arm/boot/zImage

and just replace the zImage file in your sdcard
before you replace the file, we recommend to backup the original file first
Reply
#9
Thanks!
The problem is that there is a DMA error and I have to disable the DMA on the SPI driver according to https://github.com/rockchip-linux/kernel/issues/19.
I already solve and the Papirus E-Ink screen is working with the TinkerBoard.
Reply
#10
(08-18-2017, 09:51 AM)alr2000 Wrote: Thanks!
The problem is that there is a DMA error and I have to disable the DMA on the SPI driver according to https://github.com/rockchip-linux/kernel/issues/19.
I already solve and the Papirus E-Ink screen is working with the TinkerBoard.

Hi,

Did you also test the SPI clock with your test program after fixing the issue? 

Because our codebase (miniarm) already merged the fixing commit before I verified this issue.
And I have checked the DMA settings, it should not be enabled. 
I am surprising at the solution which is to disable DMA.

Could you please share the modified code? I would like to check again.

Thank you!
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)