fp@220: /****************************************************************************** fp@220: * fp@220: * $Id$ fp@220: * fp@220: * Copyright (C) 2006 Florian Pose, Ingenieurgemeinschaft IgH fp@220: * fp@220: * This file is part of the IgH EtherCAT Master. fp@220: * fp@220: * The IgH EtherCAT Master is free software; you can redistribute it fp@220: * and/or modify it under the terms of the GNU General Public License fp@246: * as published by the Free Software Foundation; either version 2 of the fp@246: * License, or (at your option) any later version. fp@220: * fp@220: * The IgH EtherCAT Master is distributed in the hope that it will be fp@220: * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of fp@220: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the fp@220: * GNU General Public License for more details. fp@220: * fp@220: * You should have received a copy of the GNU General Public License fp@220: * along with the IgH EtherCAT Master; if not, write to the Free Software fp@220: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA fp@220: * fp@246: * The right to use EtherCAT Technology is granted and comes free of fp@246: * charge under condition of compatibility of product made by fp@246: * Licensee. People intending to distribute/sell products based on the fp@246: * code, have to sign an agreement to guarantee that products using fp@246: * software based on IgH EtherCAT master stay compatible with the actual fp@246: * EtherCAT specification (which are released themselves as an open fp@246: * standard) as the (only) precondition to have the right to use EtherCAT fp@246: * Technology, IP and trade marks. fp@246: * fp@220: *****************************************************************************/ fp@220: fp@220: #include fp@220: #include fp@220: #include fp@220: #include fp@220: fp@223: #include "../../include/ecrt.h" // EtherCAT realtime interface fp@325: #include "../../include/ecdb.h" // EtherCAT slave database fp@220: fp@820: /*****************************************************************************/ fp@820: fp@820: // module parameters fp@220: #define FREQUENCY 100 fp@818: #define CONFIGURE_MAPPING fp@809: #define EXTERNAL_MEMORY fp@457: fp@820: #define PFX "ec_mini: " fp@820: fp@820: /*****************************************************************************/ fp@220: fp@220: // EtherCAT fp@612: static ec_master_t *master = NULL; fp@818: static ec_master_state_t master_state = {}; fp@818: spinlock_t master_lock = SPIN_LOCK_UNLOCKED; fp@818: fp@612: static ec_domain_t *domain1 = NULL; fp@818: static ec_domain_state_t domain1_state = {}; fp@818: fp@820: static struct timer_list timer; fp@820: static unsigned int counter = 0; fp@820: fp@820: /*****************************************************************************/ fp@820: fp@820: // process data fp@820: static uint8_t *domain1_pd; // process data memory fp@820: fp@820: static unsigned int off_ana_in; // offsets for Pdo entries fp@820: static unsigned int off_dig_out; fp@820: fp@820: static unsigned int blink = 0; fp@820: fp@820: const static ec_pdo_entry_reg_t domain1_regs[] = { fp@820: {0, 1, Beckhoff_EL3162, 0x3101, 2, &off_ana_in}, fp@820: {0, 3, Beckhoff_EL2004, 0x3001, 1, &off_dig_out}, fp@820: {} fp@820: }; fp@820: fp@820: /*****************************************************************************/ fp@820: fp@818: #ifdef CONFIGURE_MAPPING fp@793: const ec_pdo_entry_info_t el3162_channel1[] = { fp@793: {0x3101, 1, 8}, // status fp@793: {0x3101, 2, 16} // value fp@793: }; fp@793: fp@793: const ec_pdo_entry_info_t el3162_channel2[] = { fp@793: {0x3102, 1, 8}, // status fp@793: {0x3102, 2, 16} // value fp@793: }; fp@793: fp@809: const ec_pdo_info_t el3162_mapping[] = { fp@793: {EC_DIR_INPUT, 0x1A00, 2, el3162_channel1}, fp@793: {EC_DIR_INPUT, 0x1A01, 2, el3162_channel2}, fp@792: }; fp@809: fp@809: const ec_pdo_entry_info_t el2004_channels[] = { fp@809: {0x3001, 1, 1}, // Value 1 fp@809: {0x3001, 2, 1}, // Value 2 fp@809: {0x3001, 3, 1}, // Value 3 fp@809: {0x3001, 4, 1} // Value 4 fp@809: }; fp@809: fp@809: const ec_pdo_info_t el2004_mapping[] = { fp@809: {EC_DIR_OUTPUT, 0x1600, 1, &el2004_channels[0]}, fp@809: {EC_DIR_OUTPUT, 0x1601, 1, &el2004_channels[1]}, fp@809: {EC_DIR_OUTPUT, 0x1602, 1, &el2004_channels[2]}, fp@809: {EC_DIR_OUTPUT, 0x1603, 1, &el2004_channels[3]}, fp@809: }; fp@792: #endif fp@792: fp@818: /*****************************************************************************/ fp@818: fp@818: void check_domain1_state(void) fp@818: { fp@818: ec_domain_state_t ds; fp@818: fp@818: ecrt_domain_state(domain1, &ds); fp@818: if (ds.working_counter != domain1_state.working_counter) fp@818: printk(KERN_INFO PFX "domain1 working_counter changed to %u.\n", fp@818: ds.working_counter); fp@818: fp@818: if (ds.wc_state != domain1_state.wc_state) fp@818: printk(KERN_INFO PFX "domain1 wc_state changed to %u.\n", fp@818: ds.wc_state); fp@818: fp@818: domain1_state = ds; fp@818: } fp@818: fp@818: /*****************************************************************************/ fp@818: fp@818: void check_master_state(void) fp@818: { fp@818: ec_master_state_t ms; fp@818: fp@818: spin_lock(&master_lock); fp@818: ecrt_master_state(master, &ms); fp@818: spin_unlock(&master_lock); fp@818: fp@818: if (ms.bus_state != master_state.bus_state) { fp@818: printk(KERN_INFO PFX "bus state changed to %i.\n", ms.bus_state); fp@818: } fp@818: if (ms.bus_tainted != master_state.bus_tainted) { fp@818: printk(KERN_INFO PFX "tainted flag changed to %u.\n", fp@818: ms.bus_tainted); fp@818: } fp@818: if (ms.slaves_responding != master_state.slaves_responding) { fp@818: printk(KERN_INFO PFX "slaves_responding changed to %u.\n", fp@818: ms.slaves_responding); fp@818: } fp@818: fp@818: master_state = ms; fp@818: } fp@220: fp@220: /*****************************************************************************/ fp@220: fp@820: void cyclic_task(unsigned long data) fp@820: { fp@818: // receive process data fp@220: spin_lock(&master_lock); fp@325: ecrt_master_receive(master); fp@220: ecrt_domain_process(domain1); fp@512: spin_unlock(&master_lock); fp@220: fp@818: // check process data state (optional) fp@818: check_domain1_state(); fp@512: fp@512: if (counter) { fp@512: counter--; fp@818: } else { // do this at FREQUENCY fp@512: counter = FREQUENCY; fp@818: fp@818: // calculate new process data fp@512: blink = !blink; fp@612: fp@818: // check for master state (optional) fp@818: check_master_state(); fp@818: } fp@818: fp@818: // write process data fp@846: EC_WRITE_U8(domain1_pd + off_dig_out, blink ? 0x06 : 0x09); fp@818: fp@818: // send process data fp@512: spin_lock(&master_lock); fp@509: ecrt_domain_queue(domain1); fp@325: ecrt_master_send(master); fp@220: spin_unlock(&master_lock); fp@220: fp@220: // restart timer fp@220: timer.expires += HZ / FREQUENCY; fp@220: add_timer(&timer); fp@220: } fp@220: fp@220: /*****************************************************************************/ fp@220: fp@220: int request_lock(void *data) fp@220: { fp@516: spin_lock(&master_lock); fp@226: return 0; // access allowed fp@220: } fp@220: fp@220: /*****************************************************************************/ fp@220: fp@220: void release_lock(void *data) fp@220: { fp@516: spin_unlock(&master_lock); fp@220: } fp@220: fp@220: /*****************************************************************************/ fp@220: fp@220: int __init init_mini_module(void) fp@220: { fp@818: #ifdef CONFIGURE_MAPPING fp@792: ec_slave_config_t *sc; fp@792: #endif fp@809: #ifdef EXTERNAL_MEMORY fp@809: unsigned int size; fp@809: #endif fp@792: fp@612: printk(KERN_INFO PFX "Starting...\n"); fp@220: fp@509: if (!(master = ecrt_request_master(0))) { fp@612: printk(KERN_ERR PFX "Requesting master 0 failed!\n"); fp@220: goto out_return; fp@220: } fp@220: fp@220: ecrt_master_callbacks(master, request_lock, release_lock, NULL); fp@220: fp@612: printk(KERN_INFO PFX "Registering domain...\n"); fp@509: if (!(domain1 = ecrt_master_create_domain(master))) { fp@612: printk(KERN_ERR PFX "Domain creation failed!\n"); fp@612: goto out_release_master; fp@612: } fp@612: fp@818: #ifdef CONFIGURE_MAPPING fp@792: printk(KERN_INFO PFX "Configuring Pdo mapping...\n"); fp@792: if (!(sc = ecrt_master_slave_config(master, 0, 1, Beckhoff_EL3162))) { fp@792: printk(KERN_ERR PFX "Failed to get slave configuration.\n"); fp@792: goto out_release_master; fp@792: } fp@792: fp@809: if (ecrt_slave_config_mapping(sc, 2, el3162_mapping)) { fp@809: printk(KERN_ERR PFX "Failed to configure Pdo mapping.\n"); fp@809: goto out_release_master; fp@809: } fp@809: fp@809: if (!(sc = ecrt_master_slave_config(master, 0, 3, Beckhoff_EL2004))) { fp@809: printk(KERN_ERR PFX "Failed to get slave configuration.\n"); fp@809: goto out_release_master; fp@809: } fp@809: fp@809: if (ecrt_slave_config_mapping(sc, 4, el2004_mapping)) { fp@792: printk(KERN_ERR PFX "Failed to configure Pdo mapping.\n"); fp@792: goto out_release_master; fp@792: } fp@792: #endif fp@792: fp@814: printk(KERN_INFO PFX "Registering Pdo entries...\n"); fp@792: if (ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs)) { fp@814: printk(KERN_ERR PFX "Pdo entry registration failed!\n"); fp@792: goto out_release_master; fp@792: } fp@635: fp@809: #ifdef EXTERNAL_MEMORY fp@809: if ((size = ecrt_domain_size(domain1))) { fp@820: if (!(domain1_pd = (uint8_t *) kmalloc(size, GFP_KERNEL))) { fp@809: printk(KERN_ERR PFX "Failed to allocate %u bytes of process data" fp@809: " memory!\n", size); fp@809: goto out_release_master; fp@809: } fp@820: ecrt_domain_external_memory(domain1, domain1_pd); fp@809: } fp@809: #endif fp@809: fp@612: printk(KERN_INFO PFX "Activating master...\n"); fp@220: if (ecrt_master_activate(master)) { fp@612: printk(KERN_ERR PFX "Failed to activate master!\n"); fp@809: #ifdef EXTERNAL_MEMORY fp@809: goto out_free_process_data; fp@809: #else fp@809: goto out_release_master; fp@809: #endif fp@809: } fp@809: fp@809: #ifndef EXTERNAL_MEMORY fp@809: // Get internal process data for domain fp@820: domain1_pd = ecrt_domain_data(domain1); fp@809: #endif fp@612: fp@612: printk(KERN_INFO PFX "Starting cyclic sample thread.\n"); fp@220: init_timer(&timer); fp@820: timer.function = cyclic_task; fp@220: timer.expires = jiffies + 10; fp@220: add_timer(&timer); fp@220: fp@612: printk(KERN_INFO PFX "Started.\n"); fp@220: return 0; fp@220: fp@809: #ifdef EXTERNAL_MEMORY fp@809: out_free_process_data: fp@820: kfree(domain1_pd); fp@809: #endif fp@809: out_release_master: fp@654: printk(KERN_ERR PFX "Releasing master...\n"); fp@220: ecrt_release_master(master); fp@809: out_return: fp@654: printk(KERN_ERR PFX "Failed to load. Aborting.\n"); fp@220: return -1; fp@220: } fp@220: fp@220: /*****************************************************************************/ fp@220: fp@220: void __exit cleanup_mini_module(void) fp@220: { fp@612: printk(KERN_INFO PFX "Stopping...\n"); fp@220: fp@449: del_timer_sync(&timer); fp@809: fp@809: #ifdef EXTERNAL_MEMORY fp@820: kfree(domain1_pd); fp@809: #endif fp@809: fp@612: printk(KERN_INFO PFX "Releasing master...\n"); fp@449: ecrt_release_master(master); fp@220: fp@654: printk(KERN_INFO PFX "Unloading.\n"); fp@220: } fp@220: fp@220: /*****************************************************************************/ fp@220: fp@220: MODULE_LICENSE("GPL"); fp@512: MODULE_AUTHOR("Florian Pose "); fp@512: MODULE_DESCRIPTION("EtherCAT minimal test environment"); fp@220: fp@220: module_init(init_mini_module); fp@220: module_exit(cleanup_mini_module); fp@220: fp@220: /*****************************************************************************/