sserial: add support for 7i77 analog sserial remote, add also example program for it

Signed-off-by: Michael Geszkiewicz <micges@wp.pl>
This commit is contained in:
Michael Geszkiewicz 2014-09-19 02:00:26 +02:00
parent 8ba2c3e7a6
commit d29c36a809
7 changed files with 380 additions and 40 deletions

1
.gitignore vendored
View file

@ -3,3 +3,4 @@ libanyio*
mesaflash
mesaflash.exe
pci_encoder_read
pci_analog_write

View file

@ -55,7 +55,7 @@ headers = eth_boards.h pci_boards.h epp_boards.h usb_boards.h spi_boards.h seria
headers += common.h eeprom.h lbp.h eeprom_local.h eeprom_remote.h bitfile.h sserial_module.h hostmot2_def.h boards.h
headers += encoder_module.h
all: $(LIBANYIO) $(BIN) pci_encoder_read
all: $(LIBANYIO) $(BIN) pci_encoder_read pci_analog_write
$(LIBANYIO) : $(objects)
$(RM) $(LIBANYIO) $(BIN)
@ -125,8 +125,14 @@ pci_encoder_read.o : examples/pci_encoder_read.c $(LIBANYIO) $(headers)
pci_encoder_read: pci_encoder_read.o anyio.h encoder_module.h
$(CC) -o pci_encoder_read pci_encoder_read.o $(LIBANYIO) $(LIBS)
pci_analog_write.o : examples/pci_analog_write.c $(LIBANYIO) $(headers)
$(CC) $(CFLAGS) -c examples/pci_analog_write.c
pci_analog_write: pci_analog_write.o anyio.h sserial_module.h
$(CC) -o pci_analog_write pci_analog_write.o $(LIBANYIO) $(LIBS)
clean :
$(RM) *.o $(LIBANYIO) $(BIN) pci_encoder_read
$(RM) *.o $(LIBANYIO) $(BIN) pci_encoder_read pci_analog_write
.PHONY: install
install: $(BIN)

188
examples/pci_analog_write.c Normal file
View file

@ -0,0 +1,188 @@
//
// Copyright (C) 2013-2014 Michael Geszkiewicz
//
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
#include <string.h>
#include <stdio.h>
#include <getopt.h>
#include <ctype.h>
#include <stdlib.h>
#include <errno.h>
#include "../anyio.h"
#include "../sserial_module.h"
#ifdef __linux__
#include <pci/pci.h>
#elif _WIN32
#include "libpci/pci.h"
#endif
static int device_flag;
static int instance_flag;
static int instance = 0;
static int delay_flag;
static int delay = 50;
static int verbose_flag;
static board_access_t access;
static struct option long_options[] = {
{"device", required_argument, 0, 'd'},
{"instance", required_argument, 0, 'i'},
{"delay", required_argument, 0, 't'},
{"verbose", no_argument, &verbose_flag, 1},
{0, 0, 0, 0}
};
void print_short_usage() {
printf("Example program for writing analog output on pci boards\n");
printf("Syntax:\n");
printf(" pci_analog_write --device str [--instance i] [--delay d] [--verbose]\n");
printf(" --device select active device name\n");
printf(" --instance select analog output instance 'i' for reading, default 0\n");
printf(" --delay how long to wait between analog output writes in miliseconds, default 50\n");
printf(" --verbose printf additional info during execution\n");
}
int process_cmd_line(int argc, char *argv[]) {
int c;
while (1) {
/* getopt_long stores the option index here. */
int option_index = 0;
c = getopt_long(argc, argv, "", long_options, &option_index);
/* Detect the end of the options. */
if (c == -1) break;
switch (c) {
case 0: {
/* If this option set a flag, do nothing else now. */
if (long_options[option_index].flag != 0) break;
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
}
break;
case 'd': {
int i;
if (device_flag > 0) {
printf("Error: multiply --device option\n");
exit(-1);
}
access.device_name = optarg;
for (i = 0; optarg[i] != '\0'; i++)
access.device_name[i] = toupper(access.device_name[i]);
device_flag++;
}
break;
case 'i': {
if (instance_flag > 0) {
printf("Error: multiply --instance option\n");
exit(-1);
}
instance = strtol(optarg, NULL, 10);
instance_flag++;
}
break;
case 't': {
if (delay_flag > 0) {
printf("Error: multiply --delay option\n");
exit(-1);
}
delay = strtol(optarg, NULL, 10);
delay_flag++;
}
break;
case '?':
/* getopt_long already printed an error message. */
return -1;
break;
default:
abort();
}
}
return 0;
}
int main(int argc, char *argv[]) {
board_t *board = NULL;
int ret = 0;
sserial_module_t ssmod;
opd_mode_1_7i77_t out;
u32 *out_ptr = (u32 *) &out;
if (argc == 1) {
print_short_usage();
return 0;
}
if (process_cmd_line(argc, argv) == -1) {
return -1;
}
access.verbose = verbose_flag;
if (anyio_init(&access) != 0) { // init library
return -1;
}
ret = anyio_find_dev(&access); // find board
if (ret < 0) {
return -1;
}
board = anyio_get_dev(&access, 1); // if found the get board handle
if (board == NULL) {
printf("No %s board found\n", access.device_name);
return -1;
}
board->open(board); // open board for communication
board->print_info(board); // print what card it is
hm2_read_idrom(&(board->llio)); // read hostmot2 idrom
ret = sserial_init(&ssmod, board, 0, 1, SSLBP_REMOTE_7I77_ANALOG);
out.analog0 = 1 * 0xFFF / 10;
out.analog1 = 2 * 0xFFF / 10;
out.analog2 = 3 * 0xFFF / 10;
out.analog3 = 4 * 0xFFF / 10;
out.analog4 = 5 * 0xFFF / 10;
out.analog5 = 6 * 0xFFF / 10;
out.analogena = 1;
out.spinena = 1;
ssmod.interface0 = *out_ptr;
ssmod.interface1 = *(out_ptr + 1);
ssmod.interface2 = *(out_ptr + 2);
while (1) {
sserial_write(&ssmod);
printf("sserial remote status %x\n", ssmod.cs);
usleep(delay*1000); // wait delay ms
}
sserial_cleanup(&ssmod);
board->close(board); // close board communication
anyio_cleanup(&access); // close library
return 0;
}

View file

@ -56,8 +56,8 @@ struct llio_struct {
char board_name[16];
void *private;
hostmot2_t hm2;
sserial_interface_t ss_interface[HM2_MAX_SSERIAL_MODULES];
sserial_device_t ss_device[HM2_MAX_SSERIAL_CHANNELS];
sserial_interface_t ss_interface[HM2_SSERIAL_MAX_INTEFACES];
sserial_device_t ss_device[HM2_SSERIAL_MAX_CHANNELS];
int verbose;
};

View file

@ -214,6 +214,9 @@ typedef struct {
// SSERIAL MODULE
#define HM2_SSERIAL_MAX_INTEFACES 4
#define HM2_SSERIAL_MAX_CHANNELS 8
#define HM2_MODULE_SSERIAL 0x5A00
#define HM2_MODULE_SSERIAL_CMD HM2_MODULE_SSERIAL
#define HM2_MODULE_SSERIAL_DATA 0x5B00
@ -221,9 +224,9 @@ typedef struct {
#define HM2_MODULE_SSERIAL_INTERFACE0 0x5D00
#define HM2_MODULE_SSERIAL_INTERFACE1 0x5E00
#define HM2_MODULE_SSERIAL_INTERFACE2 0x5F00
#define HM2_MAX_SSERIAL_MODULES 2
#define HM2_MAX_SSERIAL_CHANNELS 16
#define SSLBP_TYPE_LOC 0
#define SSLBP_WIDTH_LOC 1
#define SSLBP_MAJOR_REV_LOC 2
#define SSLBP_MINOR_REV_LOC 3
#define SSLBP_CHANNEL_START_LOC 4
@ -248,7 +251,7 @@ typedef struct {
#define SSLBP_CMD_RESET (SSLBP_RESET)
#define SSLBP_CMD_DOIT(x) (SSLBP_DOIT | ((1 << x) & 0xFF))
#define SSLBP_CMD_READ(x) (SSLBP_REQUEST | SSLBP_READ | (x & 0x3FF))
//#define SSLBP_CMD_WRITE(x) (SSLBP_REQUEST | SSLBP_WRITE | ((x & 0xFF))
#define SSLBP_CMD_WRITE(x) (SSLBP_REQUEST | SSLBP_WRITE | ((x & 0x3FF))
#define LBP_DATA 0xA0
#define LBP_MODE 0xB0
@ -269,6 +272,9 @@ typedef struct {
#define LBP_ENCODER_H 0x18 // For Fanuc Absolute Encoders with separate
#define LBP_ENCODER_L 0x28 // part and full count fields
#define SSLBP_REMOTE_7I77_ANALOG 0x11000000
#define SSLBP_REMOTE_7I77_IO 0x12000000
struct sserial_pdd_struct {
u8 record_type;
u8 data_size;

View file

@ -21,6 +21,47 @@
#include <string.h>
#include "types.h"
#include "hostmot2.h"
#include "sserial_module.h"
// Temporarily enable the pins that are not masked by sserial_mode
static void enable_sserial_pins(llio_t *llio) {
int port_pin, port;
int pin = -1;
int chan_counts[] = {0,0,0,0,0,0,0,0};
for (port = 0; port < 2; port ++) {
u32 ddr_reg = 0;
u32 src_reg = 0;
for (port_pin = 0; port_pin < llio->hm2.idrom.port_width; port_pin++) {
pin++;
if (llio->hm2.pins[pin].sec_tag == HM2_GTAG_SSERIAL) {
// look for highest-indexed pin to determine number of channels
if ((llio->hm2.pins[pin].sec_pin & 0x0F) > chan_counts[llio->hm2.pins[pin].sec_chan]) {
chan_counts[llio->hm2.pins[pin].sec_chan] = (llio->hm2.pins[pin].sec_pin & 0x0F);
}
// check if the channel is enabled
//printf("sec unit = %i, sec pin = %i\n", llio->hm2.pins[pin].sec_chan, llio->hm2.pins[pin].sec_pin & 0x0F);
src_reg |= (1 << port_pin);
if (llio->hm2.pins[pin].sec_pin & 0x80)
ddr_reg |= (1 << port_pin);
}
}
llio->write(llio, 0x1100 + 4*port, &ddr_reg, sizeof(u32));
llio->write(llio, 0x1200 + 4*port, &src_reg, sizeof(u32));
}
}
// Return the physical ports to default
static void disable_sserial_pins(llio_t *llio) {
int port_pin, port;
u32 ddr_reg = 0;
u32 src_reg = 0;
for (port = 0; port < 2; port ++) {
llio->write(llio, 0x1100 + 4*port, &ddr_reg, sizeof(u32));
llio->write(llio, 0x1200 + 4*port, &src_reg, sizeof(u32));
}
}
void sslbp_send_local_cmd(llio_t *llio, int interface, u32 cmd) {
llio->write(llio, HM2_MODULE_SSERIAL_CMD + interface*0x40, &(cmd), sizeof(u32));
@ -108,44 +149,111 @@ void sslbp_read_remote_bytes(llio_t *llio, int interface, int channel, u32 addr,
}
}
// Temporarily enable the pins that are not masked by sserial_mode
void enable_sserial_pins(llio_t *llio) {
int port_pin, port;
int pin = -1;
int chan_counts[] = {0,0,0,0,0,0,0,0};
int sserial_init(sserial_module_t *ssmod, board_t *board, int interface_num, int channel_num, u32 remote_type) {
u32 cmd, status, data, addr;
u16 d;
int i;
hm2_module_desc_t *md = hm2_find_module(&(board->llio.hm2), HM2_GTAG_SSERIAL);
for (port = 0; port < 2; port ++) {
u32 ddr_reg = 0;
u32 src_reg = 0;
for (port_pin = 0; port_pin < llio->hm2.idrom.port_width; port_pin++) {
pin++;
if (llio->hm2.pins[pin].sec_tag == HM2_GTAG_SSERIAL) {
// look for highest-indexed pin to determine number of channels
if ((llio->hm2.pins[pin].sec_pin & 0x0F) > chan_counts[llio->hm2.pins[pin].sec_chan]) {
chan_counts[llio->hm2.pins[pin].sec_chan] = (llio->hm2.pins[pin].sec_pin & 0x0F);
}
// check if the channel is enabled
//printf("sec unit = %i, sec pin = %i\n", llio->hm2.pins[pin].sec_chan, llio->hm2.pins[pin].sec_pin & 0x0F);
src_reg |= (1 << port_pin);
if (llio->hm2.pins[pin].sec_pin & 0x80)
ddr_reg |= (1 << port_pin);
}
}
llio->write(llio, 0x1100 + 4*port, &ddr_reg, sizeof(u32));
llio->write(llio, 0x1200 + 4*port, &src_reg, sizeof(u32));
if (md == NULL) {
printf("No sserial module found.\n");
return -1;
}
if (interface_num >= HM2_SSERIAL_MAX_INTEFACES) {
printf("sserial inteface number too high.\n");
return -1;
}
if (channel_num >= HM2_SSERIAL_MAX_CHANNELS) {
printf("sserial channel number too high.\n");
return -1;
}
memset(ssmod, 0, sizeof(sserial_module_t));
ssmod->board = board;
ssmod->interface_num = interface_num;
ssmod->channel_num = channel_num;
ssmod->instance_stride = (md->strides & 0xF0) == 0 ? board->llio.hm2.idrom.instance_stride0 : board->llio.hm2.idrom.instance_stride1;
enable_sserial_pins(&(ssmod->board->llio));
sslbp_send_local_cmd(&(ssmod->board->llio), 0, SSLBP_CMD_RESET);
ssmod->interface.type = sslbp_read_local8(&(ssmod->board->llio), interface_num, SSLBP_TYPE_LOC);
ssmod->interface.width = sslbp_read_local8(&(ssmod->board->llio), interface_num, SSLBP_WIDTH_LOC);
ssmod->interface.ver_major = sslbp_read_local8(&(ssmod->board->llio), interface_num, SSLBP_MAJOR_REV_LOC);
ssmod->interface.ver_minor = sslbp_read_local8(&(ssmod->board->llio), interface_num, SSLBP_MINOR_REV_LOC);
ssmod->interface.gp_inputs = sslbp_read_local8(&(ssmod->board->llio), interface_num, SSLBP_CHANNEL_START_LOC);
ssmod->interface.gp_outputs = sslbp_read_local8(&(ssmod->board->llio), interface_num, SSLBP_CHANNEL_STRIDE_LOC);
ssmod->interface.processor_type = sslbp_read_local8(&(ssmod->board->llio), interface_num, SSLBP_PROCESSOR_TYPE_LOC);
ssmod->interface.channels_count = sslbp_read_local8(&(ssmod->board->llio), interface_num, SSLBP_NR_CHANNELS_LOC);
ssmod->interface.baud_rate = sslbp_read_local32(&(ssmod->board->llio), interface_num, ssmod->interface.gp_inputs + 42);
ssmod->interface.clock = sslbp_read_local32(&(ssmod->board->llio), interface_num, SSLBP_CLOCK_LOC);
if (0) {//ssmod->board->llio.verbose == 1) {
printf("SSLBP port %d:\n", interface_num);
printf(" interface type: %0x\n", ssmod->interface.type);
printf(" interface width: %d\n", ssmod->interface.width);
printf(" SSLBP Version: %d.%d\n", ssmod->interface.ver_major, ssmod->interface.ver_minor);
printf(" SSLBP Channel Start: %d\n", ssmod->interface.gp_inputs);
printf(" SSLBP Channel Stride: %d\n", ssmod->interface.gp_outputs);
printf(" SSLBP Processor Type: %x\n", ssmod->interface.processor_type);
printf(" SSLBP Channels: %d\n", ssmod->interface.channels_count);
printf(" SSLBP Baud Rate: %.1f Mb\n", ssmod->interface.baud_rate/1000000.0);
printf(" SSLBP Clock: %u MHz\n", ssmod->interface.clock/1000000);
}
cmd = 0;
board->llio.write(&(ssmod->board->llio), HM2_MODULE_SSERIAL_CS + interface_num*ssmod->instance_stride + channel_num*4, &(cmd), sizeof(u32));
sslbp_send_local_cmd(&(ssmod->board->llio), interface_num, SSLBP_CMD_START_SETUP_MODE(channel_num));
sslbp_wait_complete(&(ssmod->board->llio), interface_num);
if (sslbp_read_data(&(ssmod->board->llio), interface_num) != 0) {
printf("Error reading sserial interface %d channel %d\n", interface_num, channel_num);
return -1;
}
board->llio.read(&(ssmod->board->llio), HM2_MODULE_SSERIAL_CS + interface_num*ssmod->instance_stride + channel_num*4, &(status), sizeof(u32));
board->llio.read(&(ssmod->board->llio), HM2_MODULE_SSERIAL_INTERFACE0 + interface_num*ssmod->instance_stride + channel_num*4, &(status), sizeof(u32));
if ((status & 0xFF000000) != remote_type) {
printf("Found wrong remote at %d:%d, reqeust %x but found %x\n", interface_num, channel_num, remote_type, status);
return -1;
}
ssmod->device.unit = status;
board->llio.read(&(ssmod->board->llio), HM2_MODULE_SSERIAL_INTERFACE1 + interface_num*ssmod->instance_stride + channel_num*4, &(ssmod->device.name), sizeof(u32));
board->llio.read(&(ssmod->board->llio), HM2_MODULE_SSERIAL_INTERFACE2 + interface_num*ssmod->instance_stride + channel_num*4, &(status), sizeof(u32));
printf("device at %d:%d: %.*s (unit 0x%08X)\n", interface_num, channel_num, 4, ssmod->device.name, ssmod->device.unit);
sslbp_send_local_cmd(&(ssmod->board->llio), 0, SSLBP_CMD_STOPALL);
sslbp_wait_complete(&(ssmod->board->llio), 0);
cmd = 0;
board->llio.write(&(ssmod->board->llio), HM2_MODULE_SSERIAL_CS + channel_num*4, &(cmd), sizeof(cmd));
printf("starting device %d:%d\n", interface_num, channel_num);
sslbp_send_local_cmd(&(ssmod->board->llio), 0, SSLBP_CMD_START_NORMAL_MODE(channel_num));
sslbp_wait_complete(&(ssmod->board->llio), 0);
board->llio.read(&(ssmod->board->llio), HM2_MODULE_SSERIAL_DATA + channel_num*4, &(status), sizeof(u32));
if (status != 0) {
printf("Error while starting sserial: %X\n", status);
return -1;
}
return 0;
}
// Return the physical ports to default
void disable_sserial_pins(llio_t *llio) {
int port_pin, port;
u32 ddr_reg = 0;
u32 src_reg = 0;
int sserial_cleanup(sserial_module_t *ssmod) {
disable_sserial_pins(&(ssmod->board->llio));
for (port = 0; port < 2; port ++) {
llio->write(llio, 0x1100 + 4*port, &ddr_reg, sizeof(u32));
llio->write(llio, 0x1200 + 4*port, &src_reg, sizeof(u32));
}
return 0;
}
int sserial_write(sserial_module_t *ssmod) {
ssmod->board->llio.write(&(ssmod->board->llio), HM2_MODULE_SSERIAL_INTERFACE0 + ssmod->interface_num*ssmod->instance_stride + ssmod->channel_num*4, &(ssmod->interface0), sizeof(u32));
ssmod->board->llio.write(&(ssmod->board->llio), HM2_MODULE_SSERIAL_INTERFACE1 + ssmod->interface_num*ssmod->instance_stride + ssmod->channel_num*4, &(ssmod->interface1), sizeof(u32));
ssmod->board->llio.write(&(ssmod->board->llio), HM2_MODULE_SSERIAL_INTERFACE2 + ssmod->interface_num*ssmod->instance_stride + ssmod->channel_num*4, &(ssmod->interface2), sizeof(u32));
sslbp_send_local_cmd(&(ssmod->board->llio), 0, SSLBP_CMD_DOIT(1));
sslbp_wait_complete(&(ssmod->board->llio), 0);
ssmod->board->llio.read(&(ssmod->board->llio), HM2_MODULE_SSERIAL_DATA + ssmod->interface_num*ssmod->instance_stride + ssmod->channel_num*4, &(ssmod->data), sizeof(u32));
ssmod->board->llio.read(&(ssmod->board->llio), HM2_MODULE_SSERIAL_CS + ssmod->interface_num*ssmod->instance_stride + ssmod->channel_num*4, &(ssmod->cs), sizeof(u32));
return 0;
}
void sserial_module_init(llio_t *llio) {

View file

@ -19,8 +19,39 @@
#ifndef __SSERIAL_MODULE_H
#define __SSERIAL_MODULE_H
#include "boards.h"
#include "hostmot2.h"
struct opd_mode_1_7i77_struct {
unsigned int analog0 : 13;
unsigned int analog1 : 13;
unsigned int analog2 : 13;
unsigned int analog3 : 13;
unsigned int analog4 : 13;
unsigned int analog5 : 13;
unsigned int analogena : 1;
unsigned int spinena : 1;
unsigned int ignore1 : 16;
} __attribute__ ((__packed__));
typedef struct opd_mode_1_7i77_struct opd_mode_1_7i77_t;
typedef struct {
board_t *board;
int instance_stride;
int interface_num;
int channel_num;
u32 data;
u32 cs;
u32 interface0;
u32 interface1;
u32 interface2;
sserial_interface_t interface;
sserial_device_t device;
} sserial_module_t;
int sserial_init(sserial_module_t *ssmod, board_t *board, int interface_num, int channel_num, u32 remote_type);
int sserial_cleanup(sserial_module_t *ssmod);
void sserial_module_init(llio_t *llio);
#endif