Available user-level tool for I2C device?

Yuli Barcohen yuli at arabellasw.com
Sun Oct 2 23:58:43 EST 2005


>>>>> Sam Song writes:

    Sam> Tolunay Orkun <listmember at orkun.us> wrote:
    Tolunay> I've a hwclock.c implementation for DS1307/DS1338. I do not
    Tolunay> know how close DS1337 was but it should not be too
    Tolunay> difficult to adapt.

    Sam> Tolunay, thank you so much for providing me this closest
    Sam> stuff. It can just work right on DS1337 on my board. I just
    Sam> added alarm register operation in it.  After finshing LM75
    Sam> porting on this board, I'd like to try to get a common i2c
    Sam> utility just like "imd" and "imm" in u-boot.

You can try the tool which I wrote to test SPI-connected MMC card and
different I2C chips (EEPROMs, temperature sensors, etc.). As it was
discussed on the list, our implementation of SPI uses I2C infrastructure
so the same tool works for both I2C and SPI. I attached to this mail the
source, brief documentation, and some examples.

-- 
========================================================================
 Yuli Barcohen       | Phone +972-9-765-1788 |  Software Project Leader
 yuli at arabellasw.com | Fax   +972-9-765-7494 | Arabella Software, Israel
========================================================================
-------------- next part --------------
/*
 * Copyright (C) 2005 Arabella Software Ltd.
 * Yuli Barcohen <yuli at arabellasw.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, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
 * USA.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <getopt.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>

#define READ  0x1234
#define WRITE 0x5678
#define XCHG  0xABCD

__u8 dat[16 * 1024];

struct i2c_msg msgs[256];

struct i2c_rdwr_ioctl_data xchg = {
   msgs,				/* pointers to i2c_msgs */
   sizeof(msgs)/sizeof(struct i2c_msg)	/* number of i2c_msgs */
};

static struct option long_options[] = {
   {"bus",      1, 0, 'b'},
   {"data-out", 1, 0, 'd'},
   {"data-len", 1, 0, 'l'},
   {"in-file",  1, 0, 'i'},
   {"out-file", 1, 0, 'o'},
   {"raw",      0, 0, 'r'},
   {"verbose",  0, 0, 'v'},
   {"help",     0, 0, 'h'},
   {0, 0, 0, 0}
};

int main(int argc, char *argv[])
{
   int opt, lopt_idx = 0;
   int raw = 0, verbose = 0, len = 0;
   char *data = NULL, *busdev = NULL, *infile = NULL, *outfile = NULL;
   long slave;
   int din = 0, dout = 1, dev;
   ssize_t count;
   char buf[128], hex[3];
   int i, j, k, m;
   int cur_msg = -1, ichar, ochar;
   unsigned l, p, cur_cmd = READ;

   while ((opt = getopt_long(argc, argv, "b:d:l:i:o:rvh", long_options, &lopt_idx)) != -1)
   {
      switch (opt)
      {
	 case 'b':
	    busdev = strdup(optarg);
	    break;
	 case 'd':
	    data = strdup(optarg);
	    if (data == NULL)
	    {
	       perror(NULL);
	       return 1;
	    }
	    break;
	 case 'l':
	    len = atoi(optarg);
	    break;
	 case 'i':
	    infile = strdup(optarg);
	    break;
	 case 'o':
	    outfile = strdup(optarg);
	    break;
	 case 'r':
	    raw = 1;
	    break;
	 case 'v':
	    verbose = 1;
	    break;
	 case 'h':
	    return 0;
      }
   }

   if (optind >= argc)
   {
      fprintf(stderr, "No slave address specified\n");
      return 2;
   }

   slave = strtol(argv[optind], NULL, 16);

   if (infile)
   {
      din = open(infile, O_RDONLY);
      if (din < 0)
      {
	 perror(infile);
	 return 3;
      }
   }

   if (outfile)
   {
      dout = open(outfile, O_WRONLY | O_CREAT | O_TRUNC,
		  S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
      if (dout < 0)
      {
	 perror(outfile);
	 close(din);
	 return 4;
      }
   }

   if (busdev == NULL)
      if (access("/dev/.devfsd", F_OK))
	 busdev = "/dev/i2c-0";
      else
	 busdev = "/dev/i2c/0";

   dev = open(busdev, O_RDWR);
   if (dev < 0)
   {
      perror(busdev);
      close(din);
      close(dout);
      return 5;
   }

   ioctl(dev, I2C_SLAVE, slave);

   hex[2] = 0;
   ochar = 0;
   while (count = read(din, buf, sizeof(buf)))
   {
      ichar = 0;
      while (ichar < count)
      {
	 switch (buf[ichar++])
	 {
	    case 'r': /* Read from the slave */
	       msgs[++cur_msg].addr = cur_cmd = READ;
	       sscanf(buf + ichar, "%u%n", &l, &k);
	       msgs[cur_msg].len = l;
	       msgs[cur_msg].buf = dat + ochar;
	       msgs[cur_msg].flags = I2C_M_RD;
	       ochar += l;
	       ichar += k;
	       break;

	    case 'w': /* Write to the slave */
	       msgs[++cur_msg].addr = cur_cmd = WRITE;
	       msgs[cur_msg].buf = dat + ochar;
	       msgs[cur_msg].len = 0;
	       msgs[cur_msg].flags = 0;
	       break;

	    case 'x': /* Data eXchange (I2C_RDWR) */
	       cur_cmd = XCHG;
	       msgs[++cur_msg].addr = slave;
	       msgs[cur_msg].buf = dat + ochar;
	       msgs[cur_msg].len = 0;
	       sscanf(buf + ichar, "%x%n", &l, &k);
	       msgs[cur_msg].flags = l;
	       ichar += k;
	       break;

	    case 'p': /* Pattern for eXchange timing */
	       if (cur_cmd == XCHG)
	       {
		  sscanf(buf + ichar, "%u%x%n", &l, &p, &k);
		  memset(dat + ochar, p, l);
		  msgs[cur_msg].len += l;
		  ochar += l;
		  ichar += k;
	       }
	       else
	       {
		  fprintf(stderr, "eXchage command required before Pattern\n");
		  goto finish;
	       }
	       break;

	    case 'u': /* rUn */
	       m = 0;
	       while (m <= cur_msg)
	       {
		  if (msgs[m].addr == READ)
		     read(dev, msgs[m].buf, msgs[m].len);
		  else if (msgs[m].addr == WRITE)
		     write(dev, msgs[m].buf, msgs[m].len);
		  else
		  {
		     xchg.msgs  = msgs + m;
		     xchg.nmsgs = 1;
		     m++;
		     while (m <= cur_msg)
		     {
			if ((msgs[m].addr != READ) && (msgs[m].addr != WRITE))
			{
			   xchg.nmsgs++;
			   m++;
			}
			else
			   break;
		     }
		     m--;

		     ioctl(dev, I2C_RDWR, &xchg);
		  }

		  m++;
	       }
	       for (m = 0; m <= cur_msg; m++)
	       {
		  if (msgs[m].flags & I2C_M_RD)
		     if (raw)
			write(dout, msgs[m].buf, msgs[m].len);
		     else
		     {
			for (i = 0; i < msgs[m].len; i++)
			{
			   sprintf(hex, "%2.2X", (unsigned)(msgs[m].buf[i]));
			   write(dout, hex, 2);
			}
			write(dout, "\n", 1);
		     }
	       }
	       cur_msg = -1;
	       ochar = 0;
	       break;

	    case ' ':
	    case '\t':
	    case '\n':
	    case '\r':
	       break;

	    default:
	       if (cur_cmd == READ)
	       {
		  fprintf(stderr, "Write or eXchage command required: %1.1s\n",
			  buf + ichar - 1);
		  goto finish;
	       }

	       if (isxdigit(buf[ichar - 1]) && isxdigit(buf[ichar]))
	       {
		  hex[0] = buf[ichar - 1];
		  hex[1] = buf[ichar++];
		  dat[ochar++] = (char)strtoul(hex, NULL, 16);
		  msgs[cur_msg].len++;
	       }
	       else
	       {
		  fprintf(stderr, "Illegal digit %2.2s\n", buf + ichar - 1);
		  goto finish;
	       }
	 }
      }
   }

  finish:
   close(din);
   close(dout);
   close(dev);

   return 0;
}
-------------- next part --------------
                              Using i2cspi

i2cspi takes I2C/SPI-related commands from a file (or standard input),
executes them and writes output read from the I2C/SPI peripherals to a
file (or standard output).

To run i2cspi, type the following:

   i2cspi [-b devname] [-i file] [-o file] [-r] slaveadr

where

   slaveadr	is the address of the I2C peripheral to be accessed.

Optional parameters (where supplied) are used as follows:

   -b devname	selects the bus; "devname" is the full device name of
                the I2C bus. Default is /dev/i2c-0.
   -i file	sets the input file to "file". If not specified, the
                standard input is used.
   -o file	sets the output file to "file". If not specified, the
                standard output is used.
   -r	        specifies raw mode (binary data is dumped raw to output
                instead of formatted by printf via %x). Rarely required. 

i2cspi input file format

The input file for i2cspi is a string of I2C/SPI commands entered as
ASCII text. All white-space (including carriage-returns, tabs, etc) are
taken as delimiters and otherwise ignored, so the commands may be
entered line-by-line or on a single line separated by white space. The
command letters do not need delimiters - they may appear immediately
before or after a numeric value (x1 is equivalent to x 1).

The following commands may be used in i2cspi:

   r n          read n (decimal number) bytes from the slave. In typical
                cases, this is rarely used since a write usually needs
                to precede a read operation.

   w seq	write a sequence of hex bytes to the peripheral. Each
                byte is represented by two hex characters; the sequence
                is terminated by white space. For most SPI peripherals,
                this command is only rarely used.

   x flags seq [p n]	this is the data exchange operation and is the
                        most commonly used SPI operation. Data is
                        written and read to the peripheral in
                        parallel. Note that the same number of clocks
                        are required for both read and write operation,
                        so you need to pad any write sequence to the
                        length of the read sequence that you wish to
                        read. Parameters for the 'x' command are as
                        follows:

      flags	are a hex number and as defined in the Linux I2C
                infrastructure. The two flags of relevance are:

         0x0001 - read data returning from the peripheral in parallel to
                  writing
         0x4000 - do not de-select the peripheral after the operation
                  has completed

      seq	is a sequence of hex bytes (2 characters per byte). If
      [p n] is specified, the sequence is repeated 'n' (decimal)
      times. This is useful for long sequences.

   u EXECUTE ALL PRECEDING COMMANDS. DO NOT FORGET THE 'U' COMMANDS
     SINCE WITHOUT IT NOTHING WILL HAPPEN! IN PARTICULAR, WE DO NOT
     ASSUME 'U' AT EOF, SO MAKE SURE YOUR INPUT FILE ENDS WITH A 'U'
     COMMAND.
-------------- next part --------------
# Reset MMC card and switch it to SPI mode
echo w400000000095u | i2cspi -b /dev/i2c/1 1

# Poll until the card passes reset and reports ready state
while true; do echo x1 410000000001p8 ffu | i2cspi -b /dev/i2c/1 1; sleep 10; done

# Read OCR
echo x1 7a0000000001ffffffffffffffu | i2cspi -b /dev/i2c/1 1

# Read CSD
echo x1 490000000001 p32 ffu | i2cspi -b /dev/i2c/1 1

# Read CID
echo x1 4a0000000001 p32 ffu | i2cspi -b /dev/i2c/1 1



More information about the Linuxppc-embedded mailing list