Post Go back to editing

LTC1858 and spidev

Hello,

I am working with the Eagle board from Diamond System that has Apalis imx6 on it and I would like to communicate with SPI component LTC1858 using /dev/spidev1.0. The TX nb of bits is 8 and the RX nb of bits is 14.

It seems like I can kind of get data back from the component (I checked with an oscilloscope, what I see is what I get, I can't check again until Friday), it's just that the values sent back are not what I am expecting. I'm wondering if maybe the configuration is sent wrong.... Not sure how to deal with the TX 8 bit and RX 14 bit business... I haven't done anything with CS. Is there something wrong with the code I have been using? Is there a library I could use instead?

Best regards,

Jennifer

/*
  * 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 <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.0";
 static uint8_t mode=0;
 static uint8_t bits = 8;
 static uint32_t speed = 1000;
 static uint16_t delay  ;
 
 static void printHexToBinary(uint16_t hex)
 {
   switch (hex)
   {
     case 0: printf("0000");
           break;
     case 1: printf("0001");
           break;
     case 2: printf("0010");
           break;
     case 3: printf("0011");
           break;
     case 4: printf("0100");
           break;
     case 5: printf("0101");
           break;
     case 6: printf("0110");
           break;
     case 7: printf("0111");
           break;
     case 8: printf("1000");
           break;
     case 9: printf("1001");
           break;
     case 10: printf("1010");
           break;
     case 11: printf("1011");
           break;
     case 12: printf("1100");
           break;
     case 13: printf("1101");
           break;
     case 14: printf("1110");
           break;
     case 15: printf("1111");
           break;
     default: break;
   }
 }
 
 static void transfer(int fd)
 {
     int ret;
         uint8_t tx[] = {
               (  0xAC )
     };
         uint8_t rx[2] = {0, };
     struct spi_ioc_transfer tr = {
         .tx_buf = (unsigned long)tx,
         .rx_buf = (unsigned long)rx,
              .len = ARRAY_SIZE(rx),
         .delay_usecs = delay,
         .speed_hz = speed,
         .bits_per_word = 8,
     };
     ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
     if (ret < 1)
         pabort("can't send spi message");
     for (ret = 0; ret < ARRAY_SIZE(rx); ret++) {
     //    if (!(ret % 6))
     //        puts("");
         printf("%.2X ", rx[ret]);
     }
     printf("\r\n");
         uint16_t total = (rx[0] << 8) + rx[1];
     printf("%d\r\n", total);
 
         printHexToBinary(rx[0]>>4);
     printHexToBinary(rx[0] & 0x0f);
     printHexToBinary((rx[1]>>4) & 0x0f);
     printHexToBinary(rx[1] & 0x0f);
         printf("\r\nvoltage: %f", (double)total*10/(4*16383));
     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;
 }

Parents
  • The values I get are 0.82x what I expect (for example, 10V input gives 8.2V spi data)

  • Hi Jennifer,

    I am not a programmer but if you can send me an oscilloscope photo showing CONVST, SCK, SDI and SDO and tell me what channel you are trying to read and what the input voltage on that channel is, I can tell you how the ADC should be responding. A schematic would also be helpful. If you have a large filter on the ADC inputs, the ADC will not have time to recover from the sample glitch. This could explain why the result is lower than expected, especially if the filter has a large resistor and small capacitor.

  • Hi Ghoover,

    Many thanks for your answer. I will be able to take pics with an oscilloscope on Friday and will get back to you with them.

  • Hi ghoover,

    Yesterday I thought it was starting to work when I changed the CONVST but now it doesn't seem to anymore.

    Here are some oscilloscope photos. The config I have is RD and CONVST tied together, trying to read from channels 4-5 in differential mode (I am sending 0x2800) , input voltage 3V.

    photo 1: CLK and SDI

    photo 2: CLK and SDO

    photo 3: CLK and CONVST

    Best regards,

    Jennifer

  • Sorry, forgot to mention I am trying to read channels 4-5 in 0-5V mode with 3V input

  • Hi Jennifer,

    Looking at your timing, it appears that you are sending the correct SDI word and the SDO word you are getting back is 0111 1111 0000 0000. This corresponds to about 2.48V. Can you describe how are you driving the analog inputs? Do you have an input filter? Does you circuit board have a good ground plane. What bypassing do you have? 

  • Hi ghoover,

    The 3V input is coming in from a power supply. There is no filter for the analog inputs. The Eagle board + power supply + ADC board have the same GND. DGND and AGND1..3 are wired together.

    There are:

    - 0.1uF and 10uF between DVP and DGND, and also between OVP and DGND

    I am still getting 0.82x what I expect.

    There is 6.7ms between the low edge of CONVST and the start of CLK. Isn't that a lot?

  • Does the power supply connect to the ADC inputs using long wires? A shielded cable is better.

    Is the power supply a linear supply or a switcher? A linear supply is better.

    Does the ADC board have a solid ground plane? This is essential for good performance.

    What bypassing is on REFCOMP? Is it located right next to the REFCOMP pin?

    What bypassing is on Vref?

    Are all ADC GND pins (both AGND and DGND) connected to the analog ground plane? See Figure 13 of the data sheet.

    6.7ms is a long delay between the falling edge of CONVST and the start of SCK. This shouldn't hurt the ADC performance.

  • Hi ghoover,

    The board we designed for the component is a single-sided prototype board to figure out how to use it/wire it correctly/interface it with our digital system.

    - the power supply connected to the ADC inputs is using long wires
    - the power supply is linear
    - the ADC board does not have a solid ground plane
    - Bypassing on REFCOMP is 10uF and 0.1uF both ceramic
    - Bypassing on Vref is 1uF ceramic
    - Bypassing capacitors are not placed very close to the pins, up to 3cm away

    Somehow the values seem better now again (even though nothing changed). It seems like just moving wires changes the performance. We haven't got a wiring configuration that outputs perfect values everytime (sometimes values change +- 0.01V).

  • AGND and DGND and COM are wired together but not to a solid ground plane as we don't have one yet

Reply Children
  • We get good values in single mode and in differential mode, if the reference of the values put in CH4 (and CH5 if we're in differential mode) are the same as DGND, AGND1..3. Is it possible measure signals on CH4 and CH5 that have a different reference that the GND used for SPI ? Would it help not to tie DGND and AGND1..3 together?