hm@28: /************************************************************************************************** hm@28: * hm@28: * msr_module.c hm@28: * hm@28: * Kernelmodul für 2.6 Kernel zur Meßdatenerfassung, Steuerung und Regelung hm@28: * Zeitgeber ist der Timerinterrupt (tq) hm@28: * hm@28: * Autor: Wilhelm Hagemeister hm@28: * hm@28: * (C) Copyright IgH 2002 hm@28: * Ingenieurgemeinschaft IgH hm@28: * Heinz-Bäcker Str. 34 hm@28: * D-45356 Essen hm@28: * Tel.: +49 201/61 99 31 hm@28: * Fax.: +49 201/61 98 36 hm@28: * E-mail: hm@igh-essen.com hm@28: * hm@28: * hm@28: * $RCSfile: msr_module.c,v $ hm@28: * $Revision: 1.1 $ hm@28: * $Author: hm $ hm@28: * $Date: 2005/11/14 20:32:57 $ hm@28: * $State: Exp $ hm@28: * hm@28: * hm@28: * $Log: msr_module.c,v $ hm@28: * Revision 1.1 2005/11/14 20:32:57 hm hm@28: * Initial revision hm@28: * hm@28: * Revision 1.13 2005/06/17 11:35:13 hm hm@28: * *** empty log message *** hm@28: * hm@28: * hm@28: * hm@28: * hm@28: **************************************************************************************************/ hm@28: hm@28: hm@28: /*--includes-------------------------------------------------------------------------------------*/ hm@28: hm@28: hm@28: #ifndef __KERNEL__ hm@28: # define __KERNEL__ hm@28: #endif hm@28: #ifndef MODULE hm@28: # define MODULE hm@28: #endif hm@28: hm@28: #include hm@28: #include hm@28: hm@28: #include hm@28: #include hm@28: #include hm@28: #include /* everything... */ hm@28: #include hm@28: #include hm@28: #include hm@28: #include /* fuer get_cycles */ hm@28: #include /* error codes */ hm@28: #include /* maschine-specific registers */ hm@28: #include /* fuer HZ */ hm@28: #include hm@28: hm@28: #include "msr_param.h" //wird im Projektverzeichnis erwartet hm@28: hm@28: //#include hm@28: #include hm@28: #include hm@28: #include hm@28: #include hm@28: #include hm@28: #include hm@28: #include hm@28: #include hm@28: hm@28: hm@28: #include hm@28: hm@28: #include "../drivers/ec_master.h" hm@28: #include "../drivers/ec_device.h" hm@28: #include "../drivers/ec_types.h" hm@28: #include "../drivers/ec_module.h" hm@28: hm@28: #include "msr_jitter.h" hm@28: hm@28: MODULE_AUTHOR("Wilhelm Hagemeister, Ingenieurgemeinschaft IgH"); hm@28: MODULE_LICENSE("GPL"); hm@28: hm@28: /*--external functions---------------------------------------------------------------------------*/ hm@28: hm@28: /*--external data--------------------------------------------------------------------------------*/ hm@28: hm@28: #define HZREDUCTION (MSR_ABTASTFREQUENZ/HZ) hm@28: hm@28: extern wait_queue_head_t msr_read_waitqueue; hm@28: hm@28: extern struct msr_char_buf *msr_kanal_puffer; hm@28: hm@28: extern int proc_abtastfrequenz; hm@28: hm@28: /*--public data----------------------------------------------------------------------------------*/ hm@28: /*--local data-----------------------------------------------------------------------------------*/ hm@28: //struct timer_list timer; hm@28: hm@28: extern struct timeval process_time; hm@28: struct timeval msr_time_increment; // Increment per Interrupt hm@28: hm@28: //adeos hm@28: hm@28: static struct ipipe_domain this_domain; hm@28: hm@28: static struct ipipe_sysinfo sys_info; hm@28: hm@28: static EtherCAT_master_t *ecat_master = NULL; hm@28: hm@28: static EtherCAT_slave_t ecat_slaves[] = hm@28: { hm@28: hm@28: hm@28: #if 1 hm@28: // Block 1 hm@28: ECAT_INIT_SLAVE(Beckhoff_EK1100), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL4102), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL1014), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL3162), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL2004), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL3102), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL2004), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL2004), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL2004), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL2004), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL2004), hm@28: hm@28: // Block 2 hm@28: ECAT_INIT_SLAVE(Beckhoff_EK1100), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL1014), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL1014), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL1014), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL1014), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL1014), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL2004), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL2004), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL2004), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL2004), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL1014), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL1014), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL1014) hm@28: #endif hm@28: hm@28: #if 1 hm@28: // Block 3 hm@28: ,ECAT_INIT_SLAVE(Beckhoff_EK1100), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL3162), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL3162), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL3162), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL3162), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL3102), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL3102), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL3102), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL3102), hm@28: hm@28: ECAT_INIT_SLAVE(Beckhoff_EL4102), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL4102), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL4102), hm@28: ECAT_INIT_SLAVE(Beckhoff_EL4102) hm@28: hm@28: hm@28: #endif hm@28: }; hm@28: hm@28: #define ECAT_SLAVES_COUNT (sizeof(ecat_slaves) / sizeof(EtherCAT_slave_t)) hm@28: hm@28: #define USE_MSR_LIB hm@28: hm@28: #ifdef USE_MSR_LIB hm@28: double value; hm@28: int dig1; hm@28: #endif hm@28: hm@28: /****************************************************************************** hm@28: * hm@28: * Function: next2004 hm@28: * hm@28: *****************************************************************************/ hm@28: hm@28: hm@28: hm@28: static int next2004(int *wrap) hm@28: { hm@28: static int i = 0; hm@28: unsigned int j = 0; hm@28: hm@28: *wrap = 0; hm@28: hm@28: for (j = 0; j < ECAT_SLAVES_COUNT; j++) hm@28: { hm@28: i++; hm@28: hm@28: i %= ECAT_SLAVES_COUNT; hm@28: hm@28: if (i == 0) *wrap = 1; hm@28: hm@28: if (ecat_slaves[i].desc == Beckhoff_EL2004) hm@28: { hm@28: return i; hm@28: } hm@28: } hm@28: hm@28: return -1; hm@28: } hm@28: hm@28: hm@28: /****************************************************************************** hm@28: * hm@28: * Function: msr_controller_run() hm@28: * hm@28: *****************************************************************************/ hm@28: hm@28: static void msr_controller_run(void) hm@28: { hm@28: static int ms = 0; hm@28: static int cnt = 0; hm@28: static unsigned long int k = 0; hm@28: static int firstrun = 1; hm@28: hm@28: static int klemme = 0; hm@28: static int kanal = 0; hm@28: static int up_down = 0; hm@28: int wrap = 0; hm@28: hm@28: hm@28: // Prozessdaten lesen hm@28: msr_jitter_run(MSR_ABTASTFREQUENZ); hm@28: hm@28: if (!firstrun) hm@28: { hm@28: EtherCAT_read_process_data(ecat_master); hm@28: hm@28: // Daten lesen und skalieren hm@28: #ifdef USE_MSR_LIB hm@28: value = EtherCAT_read_value(&ecat_master->slaves[5], 0) / 3276.0; hm@28: dig1 = EtherCAT_read_value(&ecat_master->slaves[2], 0); hm@28: #endif hm@28: } hm@28: else hm@28: klemme = next2004(&wrap); hm@28: hm@28: hm@28: ms++; hm@28: ms %= 1000; hm@28: if (cnt++ > 20) hm@28: { hm@28: cnt = 0; hm@28: hm@28: if (++kanal > 3) hm@28: { hm@28: kanal = 0; hm@28: klemme = next2004(&wrap); hm@28: hm@28: if (wrap == 1) hm@28: { hm@28: if (up_down == 1) up_down = 0; hm@28: else up_down = 1; hm@28: } hm@28: } hm@28: } hm@28: hm@28: if (klemme >= 0) { hm@28: EtherCAT_write_value(&ecat_master->slaves[klemme], kanal,up_down); hm@28: //printk("ECAT write: Klemme: %d, Kanal: %d, Wert: %d\n",klemme,kanal,up_down); hm@28: } hm@28: hm@28: #if 0 hm@28: EtherCAT_write_value(&ecat_master->slaves[13], 1, ms > 500 ? 0 : 1); hm@28: EtherCAT_write_value(&ecat_master->slaves[14], 2, ms > 500 ? 0 : 1); hm@28: EtherCAT_write_value(&ecat_master->slaves[15], 3, ms > 500 ? 1 : 0); hm@28: #endif hm@28: hm@28: // Prozessdaten schreiben hm@28: rdtscl(k); hm@28: EtherCAT_write_process_data(ecat_master); hm@28: firstrun = 0; hm@28: hm@28: } hm@28: hm@28: /* hm@28: *************************************************************************************************** hm@28: * hm@28: * Function: msr_run(_interrupt) hm@28: * hm@28: * Beschreibung: Routine wird zyklisch im Timerinterrupt ausgeführt hm@28: * (hier muß alles rein, was Echtzeit ist ...) hm@28: * hm@28: * Parameter: Zeiger auf msr_data hm@28: * hm@28: * Rückgabe: hm@28: * hm@28: * Status: exp hm@28: * hm@28: *************************************************************************************************** hm@28: */ hm@28: hm@28: hm@28: void msr_run(unsigned irq) hm@28: { hm@28: hm@28: static int counter = 0; hm@28: #ifdef USE_MSR_LIB hm@28: hm@28: timeval_add(&process_time,&process_time,&msr_time_increment); hm@28: hm@28: MSR_ADEOS_INTERRUPT_CODE( hm@28: msr_controller_run(); hm@28: msr_write_kanal_list(); hm@28: ); hm@28: #else hm@28: msr_controller_run(); hm@28: #endif hm@28: /* und wieder in die Timerliste eintragen */ hm@28: /* und neu in die Taskqueue eintragen */ hm@28: // timer.expires += 1; hm@28: // add_timer(&timer); hm@28: hm@28: ipipe_control_irq(irq,0,IPIPE_ENABLE_MASK); //nicht weiterreichen hm@28: if(counter++ > HZREDUCTION) { hm@28: ipipe_propagate_irq(irq); //wie lange braucht der Rest der Pipeline ?? hm@28: counter = 0; hm@28: } hm@28: hm@28: hm@28: } hm@28: hm@28: void domain_entry (int iflag) { hm@28: printk("Domain %s started.\n", ipipe_current_domain->name); hm@28: hm@28: hm@28: ipipe_get_sysinfo(&sys_info); hm@28: ipipe_virtualize_irq(ipipe_current_domain,sys_info.archdep.tmirq, hm@28: &msr_run, NULL, IPIPE_HANDLE_MASK); hm@28: hm@28: ipipe_tune_timer(1000000000UL/MSR_ABTASTFREQUENZ,0); hm@28: hm@28: } hm@28: hm@28: /* hm@28: ******************************************************************************* hm@28: * hm@28: * Function: msr_register_channels hm@28: * hm@28: * Beschreibung: KanŽäle registrieren hm@28: * hm@28: * Parameter: hm@28: * hm@28: * RŽückgabe: hm@28: * hm@28: * Status: exp hm@28: * hm@28: ******************************************************************************* hm@28: */ hm@28: hm@28: int msr_globals_register(void) hm@28: { hm@28: #ifdef USE_MSR_LIB hm@28: msr_reg_kanal("/value", "V", &value, TDBL); hm@28: msr_reg_kanal("/dig1", "", &dig1, TINT); hm@28: #endif hm@28: /* msr_reg_kanal("/Taskinfo/Ecat/TX-Delay","us",&ecat_tx_delay,TUINT); hm@28: msr_reg_kanal("/Taskinfo/Ecat/RX-Delay","us",&ecat_rx_delay,TUINT); hm@28: msr_reg_kanal("/Taskinfo/Ecat/TX-Cnt","",&tx_intr,TUINT); hm@28: msr_reg_kanal("/Taskinfo/Ecat/RX-Cnt","",&rx_intr,TUINT); hm@28: msr_reg_kanal("/Taskinfo/Ecat/Total-Cnt","",&total_intr,TUINT); hm@28: */ hm@28: return 0; hm@28: } hm@28: hm@28: hm@28: /**************************************************************************************************** hm@28: * the init/clean material hm@28: ****************************************************************************************************/ hm@28: hm@28: hm@28: int __init init_module() hm@28: { hm@28: int result = 0; hm@28: hm@28: struct ipipe_domain_attr attr; //ipipe hm@28: hm@28: //als allererstes die RT-lib initialisieren hm@28: #ifdef USE_MSR_LIB hm@28: result = msr_rtlib_init(1,MSR_ABTASTFREQUENZ,10,&msr_globals_register); hm@28: hm@28: if (result < 0) { hm@28: msr_print_warn("msr_modul: can't initialize rtlib!"); hm@28: return result; hm@28: } hm@28: #endif hm@28: hm@28: msr_jitter_init(); hm@28: printk(KERN_INFO "=== Starting EtherCAT environment... ===\n"); hm@28: hm@28: if ((ecat_master = EtherCAT_master(0)) == NULL) hm@28: { hm@28: printk(KERN_ERR "No EtherCAT master available!\n"); hm@28: msr_rtlib_cleanup(); hm@28: return -1; hm@28: } hm@28: hm@28: printk("Checking EtherCAT slaves.\n"); hm@28: hm@28: if (EtherCAT_check_slaves(ecat_master, ecat_slaves, ECAT_SLAVES_COUNT) != 0) hm@28: { hm@28: printk(KERN_ERR "EtherCAT: Could not init slaves!\n"); hm@28: msr_rtlib_cleanup(); hm@28: return -1; hm@28: } hm@28: hm@28: printk("Activating all EtherCAT slaves.\n"); hm@28: hm@28: if (EtherCAT_activate_all_slaves(ecat_master) != 0) hm@28: { hm@28: printk(KERN_ERR "EtherCAT: Could not activate slaves!\n"); hm@28: msr_rtlib_cleanup(); hm@28: return -1; hm@28: } hm@28: hm@28: hm@28: do_gettimeofday(&process_time); hm@28: msr_time_increment.tv_sec=0; hm@28: msr_time_increment.tv_usec=(unsigned int)(1000000/MSR_ABTASTFREQUENZ); hm@28: hm@28: ipipe_init_attr (&attr); hm@28: attr.name = "IPIPE-MSR-MODULE"; hm@28: attr.priority = IPIPE_ROOT_PRIO + 1; hm@28: attr.entry = &domain_entry; hm@28: ipipe_register_domain(&this_domain,&attr); hm@28: hm@28: //den Timertakt hm@28: /* hm@28: init_timer(&timer); hm@28: hm@28: timer.function = msr_run; hm@28: timer.data = 0; hm@28: timer.expires = jiffies+10; // Das erste Mal sofort feuern hm@28: add_timer(&timer); hm@28: */ hm@28: return 0; /* succeed */ hm@28: } hm@28: hm@28: hm@28: //**************************************************************************** hm@28: void __exit cleanup_module() hm@28: hm@28: { hm@28: msr_print_info("msk_modul: unloading..."); hm@28: hm@28: hm@28: // del_timer_sync(&timer); hm@28: ipipe_tune_timer(1000000000UL/HZ,0); //alten Timertakt wieder herstellen hm@28: hm@28: ipipe_unregister_domain(&this_domain); hm@28: hm@28: hm@28: hm@28: printk(KERN_INFO "=== Stopping EtherCAT environment... ===\n"); hm@28: hm@28: if (ecat_master) hm@28: { hm@28: EtherCAT_clear_process_data(ecat_master); hm@28: printk(KERN_INFO "Deactivating slaves.\n"); hm@28: EtherCAT_deactivate_all_slaves(ecat_master); hm@28: } hm@28: hm@28: printk(KERN_INFO "=== EtherCAT environment stopped. ===\n"); hm@28: hm@28: // msr_controller_cleanup(); hm@28: #ifdef USE_MSR_LIB hm@28: msr_rtlib_cleanup(); hm@28: #endif hm@28: } hm@28: hm@28: MODULE_LICENSE("GPL"); hm@28: MODULE_AUTHOR ("Wilhelm Hagemeister "); hm@28: MODULE_DESCRIPTION ("EtherCAT test environment"); hm@28: hm@28: module_init(init_module); hm@28: module_exit(cleanup_module); hm@28: hm@28: hm@28: hm@28: hm@28: hm@28: hm@28: hm@28: hm@28: hm@28: hm@28: hm@28: hm@28: hm@28: hm@28: hm@28: