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