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