In the most basic terms, in the EMC2 context, a charge pump is an HAL component that toggles a logic state at the rate of the thread that invokes it ( http://www.linuxcnc.org/docview/html/man/man9/charge_pump.9.html ). There is one input, charge-pump.enable which allows the output to toggle when no signal is connected (defaults to TRUE) or the input is TRUE. There is one output, charge-pump.out, which is either toggling TRUE/FALSE or is FALSE when the input is FALSE.
Input | Output ___________________ NC(TRUE) | Toggle TRUE | Toggle FALSE | FALSE
Typically, the charge pump is used as a check for EMC2 being up and running, also known as a watchdog.
The HAL component estop_latch ( http://www.linuxcnc.org/docview/html/man/man9/estop_latch.9.html ) also contains a charge pump, but is calls it a watchdog. The watchdog toggles while ok-out is TRUE. If a fault occurs, making fault-in TRUE, the watchdog stops at the last state and won't restart until the fault is cleared and estop_latch is reset (fault-in=FALSE, ok-in=TRUE, and reset=goes FALSE to TRUE). The watchdog frequency is the same as the charge_pump would be, or 1/(2 * thread period) (example below).
For systems that use the parallel ports for axes and/or peripheral control, the parallel port pins can be in unknown states as the computer boots up and EMC2 loads. This can invoke unwanted or unsafe action of the machine. To fix this, the axes and peripherals can be designed to be disabled or powered off until the charge pump becomes active. For machines that use hardware signal generators, this usually isn't a problem because EMC2 needs to be up and running in order for EMC2 to communicate to the signal generator. If any part of the machine is directly controlled by a parallel port pin, then the use of the charge pump should be considered. The charge pump can also be used to check for signals that could be shorted to ground or a DC voltage, such as limit switches and sensors (verify).
The term charge pump is used because when the charge pump signal is connected to a parallel port pin, the resulting 0 and 5 Volt toggling output can be considered a stream of 5 Volt charge packets. A common way to detect the charge pump signal is to "pump" the charge packets into a circuit that collects the packets and charges up a capacitor (charge bucket). If there are enough packets to charge up the capacitor, the capacitor voltage gets high enough to trip the detector circuit's output. If the charge pump is stuck TRUE or FALSE no packets get pumped, just a constant 0 or 5 Volts result, which the detector will not pass on. When the charge pump is toggling and stable, the capacitor will charge and the detector output will change.
To use the charge pump component,
"loadrt charge_pump"
is added to the .hal file for your machine's configuration. This makes the component available for use. To run it, the component needs to be attached to a thread, which typically would be "base-thread" or "servo-thread", for example,
"addf charge-pump base-thread".
Some configurations don't use a base thread, so charge pump may be run in the servo thread, or a base or other thread may be created. The bottom line is that the charge pump frequency is determined by the thread period, so if the charge pump frequency is critical, one needs to create a thread that will match. If the frequency is not critical, choose whichever thread you prefer. Each thread period is a half cycle, so the frequency is 1/(period * 2).
Example: A common base period is 50000 nanoseconds (see your .ini file), or .00005 seconds, f = 1/(.00005 * 2) = 10kHz. A common servo-thread is 1000000 nanoseconds, or 500Hz.
The next step is to connect the charge pump signal to the outside world. Typically, the output would be connected to a parallel port pin such as,
"net myCPname charge-pump.out => parport.0.pin-17-out".
With this, pin 17 would toggle when EMC2 starts. For more control, the enable could be connected to a signal that would control it. An example is,
"net notEstop iocontrol.0.user-enable-out => charge-pump.enable"
to have the charge pump run except with an e-stop, or
"net emcOn motion.motion-enabled => charge-pump.enable"
to start the charge pump when the red machine ON/OFF button is ON in AXIS. Other signals may be more appropriate in order to include other functions or a more complex e-stop system.
estop_latch is used in a similar way to the charge_pump usage described above,
"loadrt estop_latch" (add "count=N" if you need more than one) "addf estop-latch.N" (N = which one? 0, 1, 2..., a line is needed for each one) "net myWDname estop-latch.N.watchdog => parport.0.pin-17-out" "net ...." (connect up rest of estop_latch)
This Tormach configuration uses an estop_latch watchdog: http://git.linuxcnc.org/gitweb?p=emc2.git;a=tree;f=configs/tormach;hb=HEAD
Charge pump detectors can range from the capacitor circuit mentioned above to a PLC (verify) controller. Some examples are shown below.
(This is a work in progress and needs to be filled in. Those with information are invited to add or revise anything on this page.)
(diode/cap/schmitt)
(lm567 tone decoder)
I played with the above circuit on a breadboard but could not get a reliable output. My first guess is that this analog chip doesn't like a square wave input. A square wave has harmonics that the chip may be picking up. I may need to condition the input to look more like a sine wave. More to come.
---I made another try with fairly good success.
An opto-isolator chip on the input might be a good thing. The (open collector) output can sink up to 100mA, so a small mechanical relay or an SSR (solid state rely) can be connected to control mains voltage to power supplies, or DC to drivers. (See National datasheet: http://www.national.com/ds/LM/LM567.pdf )
This kit, with changes to some of the component values, may come in handy: http://www.ramseyelectronics.com/cgi-bin/commerce.exe?preadd=action&key=TD1
(PMDX)The PMDX-121, PMDX-122, PMDX-131, and PMDX-132 utilize an analog charge pump like the first schematic above except for the component values. They are optimized for operation with a charge pump with a minimum frequency of 100 Hz and a maximum of greater than 1 MHz. The values are chosen to require at least 3 full cycles of the charge pump signal before activation in order to ignore most BIOS and Windows boot sequences that test the parallel port.
The PMDX-125 and PMDX-126 (and probably any future products) utilize a micro-controller to count a minimum number of valid charge pump cycles before activation and to force deactivation after a fixed time interval without a charge pump cycle.
(CNC4PC)CNC4PC has a stand alone detector along with a detector on many of their breakout boards. They are intended to work with Mach's 12.5kHz pump. Information that could help someone understand how these detectors work and how to use these with EMC2 could be inserted here.
(AVR)I have made up a breadboard with an ATtiny2313 with software that times the interval between charge pump rising edges. The interval value is then compared to a parameter value. Any interval over the parameter is considered CP_GOOD. The reaction time to a fault condition can be less than 1ms, depending on the fault sensing algorithm. This could be very flexible. The following C file is just a first attempt. The serial connection is for getting a status display, but will move to a means for a user interface. The LEDs will will move to being a status display for normal use when the serial port is not connected.
~~~~~~~~~~ /* cp_serial-1a.c -- 2011/01/09 kwallace@wallacecompany.com ATtiny2313, 10 MHz Ext. Crystal/8 scaler, Fuse Hi = DF, Lo = 7F sudo avrdude -c usbtiny -p attiny2313 -U lfuse:w:0x7f:m -U hfuse:w:0xdf:m -U efuse:w:0xff:m */ #include <avr/io.h> #include <avr/interrupt.h> #include <stdlib.h> /* Prototypes */ void InitUART (unsigned char baudrate); unsigned char ReceiveByte (void); void TransmitByte (unsigned char data); /* Interrupt for Timer1 Input Capture */ unsigned int cp_cnt; ISR(TIMER1_CAPT_vect) { unsigned char sreg; sreg = SREG; /* Save global interrupt flag */ cli(); /* Disable interrupts */ cp_cnt=ICR1; /* Move the captured count for later processing */ SREG = sreg; /* Restore global interrupt flag */ TCNT1=0x0; /* Reset the counter to 0 */ sei(); } /* Interrupt for Timer1 Overflow */ ISR(TIMER1_OVF_vect) { PORTB = ~PORTB; // Toggle pins on Port B } main (void) { /* --- Set up Timer1, Normal Mode, PD6 input is ICP --- */ TCCR1B = (1<<ICNC1)|(1<<ICES1)|(1<<CS10); /* enable noise cancelling, capture on rising edge, clock on clkio/1*/ /* --- Set up serial port --- */ InitUART (7); /* Set the baudrate to 9600 bps using a 1.25MHz (10MHz crystal/8) */ // InitUART (12); /* Set the baudrate to 4800 bps using a 1.00MHz (8MHz internal osc/8) */ /* Set up LED to toggle on Timer1 overflow */ TIFR = 1<<TOV1; //Clear TOV1, clear pending interrupts TIMSK = 1<<TOIE1; //Enable Timer1 Overflow Interrupt DDRB = (1<<PB1)|(1<<PB0); //Set Port B pins 0 and 1 as output PORTB = (1<<PB0)|(0<<PB1); // Set port B pins 0 and 1, turn LED on PB1 off /* Set up Input Capture */ TIMSK|=(1<<ICIE1); //enable input capture interrupts sei(); unsigned char i; while (1) { if (ICR1 <= 10000) // If the count between rising edge interrupts is { // less than this value TransmitByte (76); // Then send an 'L' out the serial port } else { TransmitByte (72); // else send an 'H' } TransmitByte(13); // Always send a CR carriage return TransmitByte(10); // and LF line feed for (i = 0; i < 200; i++); // delay a little. This may not be needed, lifted from another example } } /* Initialize UART */ void InitUART (unsigned char baudrate) { UBRRL = baudrate; /* Set the baud rate */ UCSRB = (1 << RXEN) | (1 << TXEN); /* Enable UART receiver and transmitter */ UCSRC = (1 << UCSZ1) | (1 << UCSZ0); /* set to 8 data bits, 1 stop bit */ } /* Read and write functions */ unsigned char ReceiveByte (void) { while (!(UCSRA & (1 << RXC))); /* Wait for incoming data */ return UDR; /* Return the data */ } void TransmitByte (unsigned char data) { while (!(UCSRA & (1 << UDRE))); /* Wait for empty transmit buffer */ UDR = data; /* Start transmission */ }
~~~~~~~~~~
(PLC)
I know nothing about PLC's but I suspect there are Ladder components that could be assembled into a pump detector.
(KX3)
An example of a KX3 mill using a CNC4PC pump detector is here:
http://wiki.linuxcnc.org/cgi-bin/emcinfo.pl?KX3
(Mazak)An example of a Mazak mill mentioning a PMDX pump detector is here:
(Tormach)This Tormach configuration uses an estop_latch watchdog:
(more?)