7i96 to read Dynomotion KSTEP Mux Input
I have recently decided to switch to LinuxCNC from the KMotionCNC application provided by Dynomotion. This is mainly driven by my dislike of windows, however I would also like to take advantage of the active development of LinuxCNC and different screenset options.
In the immediate term, I am intending to re-use the Dynomotion KStep stepper driver board. It provides 2 relay driver outputs, a PWM to analog voltage converter, 4 stepper drivers, and 16 isolated field inputs. Interfacing all of these functions less the field inputs is via LVTLL pins. The inputs are multiplexed through 4 pins with 2 select pins. In the normal employment with the KFLOP motion control board the KFLOP appears to control the select pins, and then read the 4 input pins at a regular period.
I have a 7i96 on the way, and intend to use the 26 pin expansion port to interface directly with the KSTEP LVTLL inputs in the immediate term.
Reading through the HAL Mux options such as Mux Generic I understand how to read different combinations of inputs when they are all set externally, however wasn't sure how I would have LinuxCNC change the value of the select pins at regular intervals and then read the inputs. Is it as simple as setting the mux component to read both the inputs and select pins to determine its output, and then having a separate component that regularly changes the select pin values based on time?
Cheers,
Mick.
Please Log in or Create an account to join the conversation.
Driving muxed stepgens at step-rate might be challenging (requiring specific firmware on the 7i96) as the HAL components that you have found are typically only updated at 1kHz.
Reading back through the question, is it _only_ the field inputs that are multiplexed? In which case a bit of HAL magic and 1kHz is probably plenty.
Please Log in or Create an account to join the conversation.
Thanks for getting back to me, and apologies I should have been a bit clearer. You are correct that only the inputs are multiplexed.
I have done some more reading on the HAL, and I think the simplest approach would be to create nets for each of the select pins, input pins and logical inputs, then each time around the servo loop iterate through each combination of the select pins and read the inputs to the appropriate logical net. That is, set select pins to 00, read inputs, then select pins to 01, read inputs etc.
Does that logic make sense, or do you think there is a simpler way to do it? I saw reference to a demux component (linuxcnc.org/docs/html/man/man9/demux.9.html) but can't tell if its included in 2.8 as I can't see it in the 2.8 specific docs.
Cheers,
Mick.
Please Log in or Create an account to join the conversation.
linuxcnc.org/docs/2.8/html/man/man9/demux.9.html
Though I am not sure it does what you want.
In fact I am not sure what it does, and it looks like I wrote it
Is the situation that you set some control bits and a set of output pins report back a status? Presumably there is some delay before the outputs can be read?
How many select bits, and how many input bits are there?
I think that you could do this with a lot of bit-type mux_generic components, but it is probably going to be neater to use a custom component.
Please Log in or Create an account to join the conversation.
Noting the likelihood of a delay, it may be best to read one set of four inputs on each loop, then update the select bits for the next loop. A 4ms update time wouldn’t cause any issues in this use case, and it would be pretty simple to write.
Cheers
Mick
Please Log in or Create an account to join the conversation.
Noting the likelihood of a delay, it may be best to read one set of four inputs on each loop, then update the select bits for the next loop.
That was exactly what I was going to suggest.
This might work:
( linuxcnc.org/docs/2.8/html/hal/comp.html )
component kstep "demux component for the kstep board";
pin in bit _in-#[4] "input bits";
pin out bit _out-##[16] "output bits";
pin in bit sel-#[2] "select bits";
function _;
author "andypugh";
license "GPL2+";
;;
FUNCTION(_){
static int ctr;
static int tmp;
ctr += 1;
if (ctr == 4){
int i;
for (i = 0; i < 15; i++){
_out(i) = (tmp & 0x1);
tmp >>= 1;
}
tmp = 0;
ctr = 0;
}
tmp |= _in(0);
tmp <<= 1;
tmp |= _in(1);
tmp <<= 1;
tmp |= _in(2);
tmp <<= 1;
tmp |= _in(3);
sel(0) = ctr & 0x1;
sel(1) = ctr & 0x2;
}
Please Log in or Create an account to join the conversation.
I think I would have gotten a solution eventually, but it wouldn’t have been that elegant. To make sure I am understanding your approach:
1. Create counter to track number of bits read, and temp to hold the input. Make them static so they persist locally.
2. Increment counter, done here so the rolling if statement works correctly.
3. If counter equals 4, cycle is complete so copy temp to the output. Reset counter and temp to 0.
4. Read each input and copy it to temp, shifting to left after each read to store values in correct order.
5. Update select bits to update the input selection.
The only query I have is whether tmp and ctr should be initialised to 0 - or is this default behaviour in a .comp?
Also, I haven’t done much with bitwise operations in c. Does the final bitwise and between the counter and 0x2 evaluate the least significant bit, or the bit in the 2’s column as I think was intended?
Thanks again for providing that solution, seeing a specific example will greatly reduce the time I need to understand how to write components and let me focus on the overall solution.
Cheers,
Mick
Please Log in or Create an account to join the conversation.
The only query I have is whether tmp and ctr should be initialised to 0 - or is this default behaviour in a .comp?
Ideally cnt should init to 3 so that the "if" is true first time through. But I realised this late and editing is such a pain on this forum now...
It should all settle out within 4ms anyway.
Also, I haven’t done much with bitwise operations in c. Does the final bitwise and between the counter and 0x2 evaluate the least significant bit, or the bit in the 2’s column as I think was intended?
if cntr = b11 then cntr & 0x2 = cntr & b10 = b10.
But b10 != 0 so evaluates as "true" in the boolean.
((cntr & 0x2) != 0) might be better, ie work with 100% of CPUs and compilers.
Please Log in or Create an account to join the conversation.
I’ll give this a try when I have all the components. May be a little while as I have had a short notice trip for a few weeks come up.
Thanks again,
Mick.
Please Log in or Create an account to join the conversation.