HMS anybus Linux
- The Anybus module allows the Armadeus board to communicate on 18 differents industrial network such as Profibus, Modbus-TCP/RTU, CANOpen, ...
- The following instructions is relative to Armadeus boards APF51-Dev and APF51 with FPGA. Please ensure you use the trunk version of Armadeus.
Contents
Creation of the FPGA design with POD
- The FPGA design is available in firmware/pod_scripts/apf51_anybus_interface.bin
- This design and the drivers must be generated by the POD script in your ARMadeus directory:
firmware/pod_scripts/apf51_anybus_interface.pod
don't forget to uncomment the selectprojecttree command value in this file, and replace the string «your_armadeus_directory» by your armadeus directory absolute complete path (avoid ~).
selectprojecttree your_armadeus_directory/target/linux/modules/fpga/POD
driver.selectprojecttree your_armadeus_directory/target/linux/modules/fpga/POD
driver.copydrivers
- Then, enable Drivers generated by POD and disable Drivers for wishbone example
$ make linux26-menuconfig
Device Drivers ---> Armadeus specific drivers ---> FPGA Drivers ---> [ ] Drivers for wishbone example <M> Drivers generated by POD
$ make linux26 ; make
- Reflash your linux kernel and rootfs
anybus_interface Linux driver installation
Kernel configuration
In your Armadeus directory, select the HMS Anybus linux driver anybus_interface:
$ make linux26-menuconfig
Device Drivers ---> [*] Network device support ---> <M> HMS Anybus driver
Loading the modules driver
- Load the driver generated by POD.
# modprobe pod_anybus_interface_platform
- Load the kernel driver.
# modprobe anybus_interface
- Check if the interface anybus0 is available.
# ifconfig anybus0 anybus0 Link encap:UNSPEC HWaddr 00-45-02-10-A0-0A-33-C7-00-00-00-00-00-00-00-00 NOARP MTU:520 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:10 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) Interrupt:83
- HWaddr :
- The two first bytes : 00-45 is the fieldbus type (Anybus-S Parallel Design Guide p21). Here, it is an anybus Modbus RTU module.
- 02-10 is the Application Interface Software Version bytes (Anybus-S Parallel Design Guide p20)
- A0-0A-33-C7 is the Module Serial Number (Anybus-S Parallel Design Guide p20).
- Mount the interface.
# ifconfig anybus0 up
Check the surface mounted LED on the Anybus module (not the front LEDs). This LED should blink at 1Hz if the module is initialised, and 2Hz if not. Then, you can use the interface.
anybus-tools
Description
anybus-tools is a set of tools used to communicate with your HMS Anybus module through the anybus_interface Linux driver.
Installation on your target
- In your Armadeus directory on your host:
$ make menuconfig
- Choose anybus-tools
Package Selection for the target ---> Armadeus specific tools/utilities ---> [*] anybus-tools
Then, reflash your rootfs.
Usage
- In the APF environnement
# anybus-tools
- The first window ask you which anybus interface you want to use (anybus0 by default).
Features
Edit input area
- Move in the HMS Anybus input area memory with arrow keys and edit a field hitting the < Enter > key.
Map output area
- Move in the HMS Anybus output area memory with arrow keys to watch messages received by the module.
Mailbox message
- Send and receive mailbox messages.
Read register
- Read a specific register in the HMS Anybus module memory.
Change interface
- Choose a different anybus interface.
About...
- Show "About..." dialog.
Help
- Display some help ...
Programmation
The anybus_interface driver is accessible by a short C program (as a classic network interface). However, some informations and options need to be set. Please include net/anybus_interface.h
Initialization
- Declare some structures and variable
- Structure ifreq will be used to do network interface request
- Structure sockaddr_ll is a socket descriptor.
- int sk is the socket id.
struct ifreq ifr;
struct sockaddr_ll addr;
int sock = 0;
- Initialize some fields
- The anybus_interface driver use AF_PACKET family with the non-connected protocol.
- Put the interface name in the ifreq structure.
addr.sll_family = AF_PACKET;
addr.sll_protocol = IPPROTO_UDP;
addr.sll_pkttype = PACKET_BROADCAST;
strncpy(ifr.ifr_name, "anybus0", strlen("anybus0"));
- Create the socket
if ((sock = socket(PF_PACKET , SOCK_RAW, AF_PACKET)) < 0 ) {
perror("socket");
return sock;
}
- And associate it with the anybus network interface
ioctl(sock, SIOCGIFINDEX, &ifr);
addr.sll_ifindex = ifr.ifr_ifindex;
- Bind the descriptor to the socket
if(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("bind");
return EXIT_FAILURE;
}
Communication (send/recv)
- First, you have to declare an anybus_frame structure
struct anybus_frame frame;
- This structure contain 3 fields :
- .reg : offset register of the anybus input/output memory.
- .len : Length of the data in this frame. The max len is given by ANYBUS_DATA_LEN.
- .data[n] : value at the address offset + n.
- Initialize and send the frame on the fieldbus
- The following code will write the 16bits words 0x1234 and 0x9876 in the HMS Anybus input memory at the address 0x12 and 0x14 (16bits access)
frame.reg = 0x12;
frame.len = 2;
frame.data[0] = 0x1234;
frame.data[1] = 0x9876;
if ((ret = send(sock, (void *)&frame, sizeof(frame), 0)) < 0) {
perror("send");
return ret;
}
- Receive a frame on the fieldbus
- The following code will receive the values read in the HMS Anybus Output memory. The frame.reg will be always 0 and .len will be always 256.
- The recv() function is blocking until the HMS Anybus Output memory is changed.
if((ret = recv(sock, (void *)&frame, sizeof(frame), 0)) < 0) {
perror("recv");
return ret;
}
ioctl
- Anybus ioctls are independent of the socket id. The driver implement a char device /dev/anybusX_device.
- Five ioctls commands are available.
- The structure given to the ioctl commands is:
struct mailbox_msg {
unsigned short id;
unsigned short msg_information;
unsigned short command_number;
unsigned short data_size;
unsigned short extended_word[8];
unsigned short data[ANYBUS_DATA_LEN];
};
or
struct anybus_register {
unsigned short address;
unsigned short value;
};
Mailbox read
- Initialize a mailbox_msg structure and a file id.
- Open the device's file.
- Do the ioctl command ANYBUS_MB_READ.
- close the device file.
struct mailbox_msg received_mail;
int fd_device;
fd_device = open("/dev/anybus0_interface", O_RDONLY);
if((ret = ioctl(fd_device, ANYBUS_MB_READ, &received_mail)) < 0) {
perror("ioctl");
return ret;
}
/* The fields of the received_mail structure contains now the informations about
the last mailbox message emitted by the HMS Anybus module. */
close(fd_device);
Note: It is possible to do a select() command on the device file /dev/anybusX_device. |
Mailbox write
- Initialize a mailbox_msg structure.
- Open the anybus device file.
- Fill the mail_to_send structure fields.
- Do the ioctl command ANYBUS_MB_READ.
- close the device file.
struct mailbox_msg mail_to_send;
int fd_device;
fd_device = open("/dev/anybus0_interface", O_RDONLY);
/* Fill the mail_to_send structure fields here */
if((ret = ioctl(fd_device, ANYBUS_MB_WRITE, &mail_to_send)) < 0) {
perror("ioctl");
return ret;
}
close(fd_device);
Map input area
- Declare a structure anybus_frame.
- Open the device file.
- Do the ioctl command ANYBUS_MAP_INPUT.
- Close the device file.
struct anybus_frame frame;
int fd_device;
fd_device = open("/dev/anybus0_interface", O_RDONLY);
if ((ret = ioctl(fd_device, ANYBUS_MAP_INPUT, frame.data)) < 0) {
perror("ioctl");
return ret;
}
/* The frame.data field has been filled */
close(fd_device);
Map output area
- Declare a structure anybus_frame.
- Open the device file.
- Do the ioctl command ANYBUS_MAP_OUTPUT.
- Close the device file.
struct anybus_frame frame;
int fd_device;
fd_device = open("/dev/anybus0_interface", O_RDONLY);
if ((ret = ioctl(fd_device, ANYBUS_MAP_OUTPUT, frame.data)) < 0)
return ret;
/* The frame.data field has been filled */
close(fd_device);
Read anybus register
- Declare a structure anybus_frame.
- Open the device file.
- Give the address register (here 0x7D5)
- Do the ioctl command ANYBUS_MAP_OUTPUT.
- Close the device file.
struct anybus_register anybus_reg
int fd_device;
fd_device = open("/dev/anybus0_interface", O_RDONLY);
anybus_reg.address = 0x7D5;
if ((ret = ioctl(fd_device, ANYBUS_READ_REG, &anybus_reg)) < 0) {
return ret;
}
/* The anybus_reg.value field has been filled */
close(fd_device);
closing the socket
close(sock);
Example
- Have a look to the source code anybus_tools in your armadeus directory, target/package/anybus_tools/