[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [microblaze-uclinux] spi and spidev usage



Hello,

I use the SPI subsystem to control a touchscreen and the intensity of a
LCD display. I send you 2 programs I have written to test the
functionality of the peripherals. Hope you can figure out who the SPI
device driver has to be used.

Regards,
   Hans

John Williams <jwilliams@xxxxxxxxxxxxxx> wrote:
> Hi Carsten,
> 
> On Wed, Jan 21, 2009 at 5:23 AM, Bartsch Carsten <cbartsch@xxxxxxxxxx> wrote:
> 
> > I'm trying to use SPI. I added a 2nd SPI core to my FPGA.
> > The software-part is based on petalinux-mmu-v0.10.
> >
> > The drivers spi and spidev can be build, the kernel says
> > xilinx_spi 0: at 0x83400000 mapped to 0xC8100000, irq=0
> > xilinx_spi 1: at 0x83500000 mapped to 0xC8120000, irq=1
> > and in the list of /proc/devices there are character devices
> > 123 xilinx_spi and 153 spidev.
> >
> > Can I test to access these devices already?
> >
> > The spidev documentation says to configure the SPI-slaves in the
> > board initialization code using spi_register_board_info or
> > defining tables of devices
> > static struct spi_board_info spi_board_info[] __initdata = {...
> >
> > Where can I do this?
> 
> I've not used spidev however typically we place these platform
> initialisers in arch/microblaze/platform/common - there is xspi.c in
> there, however it sets up platform_device info for the xps_spi
> controller itself.  You may have a liitle more work to do using
> spidev.
> 
> > The documentation told me to use udev or mdev to populate /dev
> > dynamically.
> > mdev is not available in the busybox config (maybe to old) and udev
> > cannot
> > be build. I don't need dynamic configuration.
> >
> > Can I add the devices in the makefile of my platform instead?
> 
> Yes, edit vendors/<myvendor>/<myplatform>/Makefile
> 
> under the romfs:: target you can do something like
> [tab]touch $(ROMFSDIR)/@devname,c,maj,min
> 
> where
>  *  [tab] is a proper tab character
>  * devname is the device node name
>  * c is for char, b for clock device
>  * maj is major number
>  * min is minor number
> 
> alternatively, you can add it to vendors/PetaLogix/common/common.mak,
> look for "DEVICES =" string
> 
> Regards,
> 
> John
> ___________________________
> microblaze-uclinux mailing list
> microblaze-uclinux@xxxxxxxxxxxxxx
> Project Home Page : http://www.itee.uq.edu.au/~jwilliams/mblaze-uclinux
> Mailing List Archive : http://www.itee.uq.edu.au/~listarch/microblaze-uclinux/

-- 
Dr. Johann Pfefferl   ------------   mailto j.pfefferl at eubus dot net
Eubus GmbH          http://www.eubus.net ++++ http://www.ebmhydraxc.com
Gollierstr. 70
D-80339 Muenchen
Phone: +49 (0)89 45 22 578-67     Fax: +49 (0)89 45 22 578-55
Registergericht Muenchen HRB 145 336, Ust-Id Nr. DE 225 783 933
Geschaeftsfuehrer: Volker Ulrich
==
 -o)   A computer program does what you tell it to do,
 /\\        not what you want it to do.               
_\_v-                                                 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/types.h> /* __u16 */
#include <linux/xspi_ioctl.h>

#define SPI_DEVICE "/dev/xspi0"
#define SPI_DEV_ID 0

static void usage(char *prgname)
{
  fprintf(stderr, "Usage: %s [options]\n"
      "Following options are recognized:\n"
      "\t-s <spi_dev>\tSPI device file\n"
      "\t-h\tShow this help text\n"
      "\n\nDefault SPI device is %s\n",
      prgname, SPI_DEVICE);
  exit(1);
}

int write_spi_value(int spi_fd, __u16 val)
{
  int ret;
  struct xspi_ioc_transfer_data xitd;
  char *spi_data = (char*)&val;

  xitd.slave_index = SPI_DEV_ID;
  xitd.write_buf = spi_data;
  xitd.read_buf = NULL;
  xitd.count = sizeof(val);
  if(0 > (ret = ioctl(spi_fd, XSPI_IOC_TRANSFER, &xitd))) {
    perror("ioctl XSPI_IOC_TRANSFER failed");
    return ret;
  }
  return 0;
}

int main(int argc, char **argv)
{
  int o, spi_fd;
  __u16 val;
  char spi_devname[16];

  strncpy(spi_devname, SPI_DEVICE, sizeof(spi_devname)-1);

  while(0 <= (o = getopt(argc, argv, "s:h"))) {
    switch(o) {
      case 's':
        strncpy(spi_devname, optarg, sizeof(spi_devname)-1);
        break;
      case 'h':
      default:
        usage(argv[0]);
        break;
    }
  }

  // Open the SPI device
  spi_fd = open(spi_devname, O_RDWR);
  if (0 > spi_fd) {
    perror(spi_devname);
    return EXIT_FAILURE;
  }

  for(val = 0; val < 0x100; val++) {
    write_spi_value(spi_fd, val);
    printf("Written value 0x%02x\n", val);
    usleep(100 * 1000);
  }
  close(spi_fd);
  return EXIT_SUCCESS;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/types.h> /* __u16 */
#include <linux/xgpio_ioctl.h>
#include <linux/xspi_ioctl.h>

#define SPI_TOUCH_DEVICE "/dev/xspi1"
#define GPIO_DEVICE "/dev/xgpio1"
#define SPI_TOUCH_XY_POS_SLAVE_INDEX 0
#define GPIO_CHANNEL 1

#define SAMPLE_TIME_USEC 100000

#define CLAMP_VALUE(v, min, max) { if((v) < (min)) v = min; else if((v) > (max)) v = max; }

typedef struct {
  int button_pressed, xpos, ypos;
} mouse_event_t;

#if 1
__attribute((__unused__)) static void hexdump(unsigned char *data, int len)
{
  int j;

  for(j = 0; j < len; j++, data++) {
    printf("%02x ", *data);
    if(15 == j % 16)
      printf("\n");
  }
  if(15 != j % 16)
    printf("\n");
}
#else
#define hexdump(...)
#endif

static void usage(char *prgname)
{
  fprintf(stderr, "Usage: %s [options]\n"
      "Following options are recognized:\n"
      "\t-g <gpio_dev>\tGPIO device file\n"
      "\t-s <spi_dev>\tSPI device file\n"
      "\t-h\tShow this help text\n"
      "\n\nDefault SPI device is %s\n"
      "Default GPIO device is %s\n",
      prgname,
      SPI_TOUCH_DEVICE, GPIO_DEVICE);
  exit(1);
}

void diep(char *s)
{
  perror(s);
  exit(1);
}

#define NUM_SAMPLES 16
int read_touch_value_array(int spi_fd, int addr)
{
  int ret;
  char spi_data[1+NUM_SAMPLES*2];
  int sum, cnt;
  struct xspi_ioc_transfer_data xitd;

  do {
    xitd.slave_index = SPI_TOUCH_XY_POS_SLAVE_INDEX;
    xitd.write_buf = xitd.read_buf = spi_data;
    memset(spi_data, 0, sizeof(spi_data));
    for(ret = 0; ret < sizeof(spi_data); ret += 2)
      spi_data[ret] = addr;
    xitd.count = sizeof(spi_data);
    if(0 > (ret = ioctl(spi_fd, XSPI_IOC_TRANSFER, &xitd))) {
      perror("ioctl read_touch_value");
      return ret;
    }
    cnt = sum = 0;
    for(ret = 1; ret < sizeof(spi_data); ret += 2) {
      int val = ((((int)spi_data[ret] << 8) | (int)spi_data[ret+1] )>>3) & 0xFFF;
      if(val < 4000) {
        printf("%2d. val=%d\n", ret/2, val);
        sum += val;
        ++cnt;
      }
      else {
        printf("%2d. val=%d :-(((((((\n", ret/2, val);
      }
    }
  } while(!cnt);
  return cnt ? sum/cnt: 0;
  //return ((((int)spi_data[1] << 8) | (int)spi_data[2] )>>3) & 0xFFF;
}


int read_touch_value(int spi_fd, char addr)
{
  int ret;
  char spi_data[3];
  struct xspi_ioc_transfer_data xitd;

  xitd.slave_index = SPI_TOUCH_XY_POS_SLAVE_INDEX;
  xitd.write_buf = xitd.read_buf = spi_data;
  spi_data[0] = addr;
  spi_data[1] = 0;
  spi_data[2] = 0;
  xitd.count = sizeof(spi_data);
  if(0 > (ret = ioctl(spi_fd, XSPI_IOC_TRANSFER, &xitd))) {
    perror("ioctl read_touch_value");
    return ret;
  }
  return ((((int)spi_data[1] << 8) | (int)spi_data[2] )>>3) & 0xFFF;
}

int init_touch_controller(int spi_fd)
{
  int t0, t1;
  /* Read Chip id of the touch controller */
  int val = read_touch_value(spi_fd, 0xE3);
  printf("AD7873 chip id=0x%x\n", val);
  if(0x800 != val) {
    printf("Chip id (0x800) of touch controller not correct!!\n");
    return 0;
  }
  t0 = read_touch_value(spi_fd, 0x87);
  t1 = read_touch_value(spi_fd, 0xF7);
  t0 = (t1-t0)*25*249/4096 - 273;
  printf("Touch temperature: %dC\n", t0);
  printf("Touch X+: %d\n", read_touch_value(spi_fd, 0x97));
  printf("Touch Y+: %d\n", read_touch_value(spi_fd, 0xD7));
  printf("Touch Z+: %d\n", read_touch_value(spi_fd, 0xB7));

  val = read_touch_value(spi_fd, 0xE1);
  val = read_touch_value(spi_fd, 0x91);
  val = read_touch_value(spi_fd, 0xD1);
  return 1;
}

int xbig4000, ybig4000, xbig1500, ybig1500, xgood, ygood;

int main(int argc, char **argv)
{
  int r, o, cnt;
  int gpio_fd;
  char spi_devname[16], gpio_devname[16];

  xbig4000 = ybig4000 = xbig1500 = ybig1500 = xgood = ygood = 0;

  strncpy(spi_devname, SPI_TOUCH_DEVICE, sizeof(spi_devname)-1);
  strncpy(gpio_devname, GPIO_DEVICE, sizeof(gpio_devname)-1);

  while(0 <= (o = getopt(argc, argv, "g:s:h"))) {
    switch(o) {
      case 'g':
        strncpy(gpio_devname, optarg, sizeof(gpio_devname)-1);
        break;
      case 's':
        strncpy(spi_devname, optarg, sizeof(spi_devname)-1);
        break;
      case 'h':
      default:
        usage(argv[0]);
        break;
    }
  }

  if(0 < (gpio_fd = open(gpio_devname, O_RDWR))) {
    struct xgpio_ioctl_data gpio_info;
    int spi_fd;

    // Open the SPI device
    spi_fd = open(spi_devname, O_RDWR);
    if (0 > spi_fd) {
      perror(spi_devname);
      return 1;
    }

    printf("Operating with: %s %s\n", spi_devname, gpio_devname);

    memset(&gpio_info, 0, sizeof(gpio_info));
    gpio_info.chan = GPIO_CHANNEL;
    /* Mark all pins as input */
    gpio_info.mask = ~0;
    if(0 > (r = ioctl(gpio_fd, XGPIO_TRISTATE, &gpio_info))) {
      perror("ioctl XGPIO_TRISTATE failed");
      return 5;
    }
    else {
      int button_pressed_old = 0;

      if(!init_touch_controller(spi_fd)) {
        printf("init_touch_controller function failed\n");
        return -1;
      }

      printf("Press/Release the touch screen\n");
      cnt = 0;
      while(1) {

        r = ioctl(gpio_fd, XGPIO_IN, &gpio_info);
        if(!r) { /* Input operation is ok */
          int button_pressed = !(gpio_info.data & 1);

          if(button_pressed) {
            if(!button_pressed_old) {
              int l;
              int xval, yval;

#define NUM_SAMPLE_LOOPS 1
              for(l = 0; l < NUM_SAMPLE_LOOPS; l++) {
                /* y value handling */
                xval = read_touch_value_array(spi_fd, 0xD1);
                yval = read_touch_value_array(spi_fd, 0x91);
                if(xval > 3500)
                  ++xbig4000;
                else if(xval > 1000)
                  ++xbig1500;
                else
                  ++xgood;
                if(yval > 3500)
                  ++ybig4000;
                else if(yval > 1000)
                  ++ybig1500;
                else
                  ++ygood;
              }
              printf("You can release the button now\n");
              printf("xbig4000=%3d xbig1500=%3d xgood=%3d\n", xbig4000, xbig1500, xgood);
              printf("ybig4000=%3d ybig1500=%3d ygood=%3d\n", ybig4000, ybig1500, ygood);
            }
          }
          else {
            button_pressed_old = 0;
          }
        }
        else
          perror("Failed to perform a XGPIO_IN operation");
        usleep(SAMPLE_TIME_USEC);
      }
    }
    close(gpio_fd);
    close(spi_fd);
  }
  else {
    perror(gpio_devname);
    return 3;
  }
  return 0;
}