Hi everyone!
This is my first post to this forum, so go easy on me .
About three months ago we (three guys in a mancave) bought an old Matsuura MC-500V with a very old computer and control system, from the beginning we planned to retrofit the CNC to be controlled by a modern controller. From experience in the past with Dynomotion we knew that the universality of the KFlop should be sufficient for a successful retrofit. In this topic ill keep track of the progress, success, difficulties and failures. Lets start with pictures of the self claimed "MINI-MASTER":
And its computer + servo drives and IO:
We were impressed by the neatly ordered wiring + interfacing system and planned to keep as much as possible intact. By reading the documentation we quickly learned that the axes are actuated by 200V DC servo's with analog controlled servo drives. With this knowledge we ordered a KFlop and Kanalog. We will be designing PCB's to realise the wire to connector interfaces for all the analog interfacing. The other 80% of the IO is connected to two IO interface boards like this (the green one):
The two interfaces interface between the (old)computer (adres/data bus) and the IO (most of the MDI / user interface buttons, indicator LEDs, spindle, tool changer pneumatics and some to be determined stuff). We thought; what if we could design a coupler between the adres/data bus of the IO interface card and the adres/data bus of the KFlop (that is supposed to go to the Konnect extension). This would satisfy our goal to keep almost all of of the wiring of the machine intact and would by far be the most universal (we could gradually expand the implemented functionality by only firmware updates ). So the reverse engineering started:
After a couple of evenings fiddling and measuring around with the card in the Matsuura and a logic analyser on the original bus I was able to write a test program to control all reed relays ( 6*8Bits output ) and for what I have seen also the filtered inputs (4*8bits) on the bench with a Arduino. This was enough result to motivate me to start with the next step: try and interface with the KFlop. I did some measurements on the KFlop + I found the konnect protocol description here:
https://en.industryarena.com/forum/s...g--340204.html
and
http://www.cnczone.com/forums/dynomo...ect-kflop.html
My first go-to attempt was to try (with some help of interrupts) connect the KFlop directly to a STM32F303, I was confident that a STM32 running at 72MHz would be fast enough to interface with the adres/data bus of the KFlop, I was wrong . As m_c in the second link claimed; "However, even with an STM32 clocked to 172MHz, I couldn't get it to respond fast enough. It should be a reasonably simple thing to implement in a FPGA for those with the skills to program such things." the STM was indeed WAY TO SLOW. With the need / desire to still interface the KFlop with the IO board I had no other (easy) option than to refresh my VHDL skill and implement the KFlop interface side on an FPGA. I ordered a Cyclone 2 dev board on ebay and started practicing VHDL:
Altera Cyclone II EP2C5T144 FPGA CPLD Entwicklungs board DevelI2Copment IO SPI | eBay
After a couple of days being confronted with how far my skills had rusted I was able to realise and simulate the interface in Modelsim with the delays as if it was all implemented on the FPGA (gate level simulation):
The VHDL Code - Still in very very very early stage but good enough to evaluate its ability to interface with the KFlop:
Code:
library ieee ;
use ieee.std_logic_1164.all;
use work.all;
entity KonnectToSpi is
port(
RST : in std_logic; -- ToKFLOP
CLK : in std_logic; -- ToKFLOP
CLKIN : in std_logic; -- ToKFLOP
STARTIN : in std_logic; -- ToKFLOP
dataBus : inout std_logic_vector (7 downto 0); -- ToKFLOP
LEDs : out std_logic_vector (2 downto 0); -- Debug output LEDS to visualise example output
konnectSelectedOut : out std_logic := '0'; -- Debug output, goes high when adress m
outputEnable : out std_logic := '0' -- Debug output
);
end KonnectToSpi;
architecture behaviour of KonnectToSpi is
signal STARTINRisingEdge : std_logic := '0';
signal STARTINFallingEdge : std_logic := '0';
signal konnectSelected : std_logic := '0';
signal statePointer : integer range 0 to 16;
signal statePointerBuffer : integer range 0 to 16;
signal input0 : std_logic_vector(7 downto 0) := x"00"; -- Will receive data from desired output
constant input1 : std_logic_vector(7 downto 0) := x"01"; -- Sample fake data
constant input2 : std_logic_vector(7 downto 0) := x"03"; -- Sample fake data
constant input3 : std_logic_vector(7 downto 0) := x"07"; -- Sample fake data
constant signature : std_logic_vector(7 downto 0) := x"A5"; -- Signature
signal dataBusBuffer : std_logic_vector(7 downto 0) := x"00";
begin
process(CLK, RST)
variable resyncCLKIN : std_logic_vector(2 downto 0) := b"111";
variable resyncSTARTIN : std_logic_vector(2 downto 0) := b"000";
begin
if RST = '0' then
dataBus <= "ZZZZZZZZ";
LEDs <= "111";
outputEnable <= '0';
elsif rising_edge(CLK) then
resyncCLKIN := resyncCLKIN(1 downto 0) & CLKIN;
resyncSTARTIN := resyncSTARTIN(1 downto 0) & STARTIN;
if (((resyncSTARTIN(1) and not resyncSTARTIN(2)) = '1') OR (statePointer = 15)) then
statePointer <= 0;
konnectSelected <= '0';
end if;
if ((resyncSTARTIN(2) and not resyncSTARTIN(1)) = '1') and (dataBus = "00001111") then
konnectSelected <= '1';
end if;
if ((resyncCLKIN(1) XOR resyncCLKIN(2)) = '1') and (statePointer < 16) and (konnectSelected = '1') then
statePointer <= statePointer + 1;
if(statePointerBuffer = 1) then
input0 <= dataBus;
LEDs <= not dataBus(2 downto 0);
end if;
if(statePointerBuffer = 3) then
--output1 <= dataBus; -- Nothing to output to yet
end if;
case statePointerBuffer is
when 4 => dataBusBuffer <= not input0;
when 6 => dataBusBuffer <= not input1;
when 8 => dataBusBuffer <= not input2;
when 10 => dataBusBuffer <= not input3;
when 12 => dataBusBuffer <= signature;
when others => dataBusBuffer <= x"00";
end case;
else
statePointerBuffer <= statePointer;
end if;
if (CLKIN = '1') AND (statePointerBuffer > 3) AND (statePointerBuffer < 14) then
dataBus <= dataBusBuffer;
outputEnable <= '1';
else
dataBus <= "ZZZZZZZZ";
outputEnable <= '0';
end if;
end if;
end process;
konnectSelectedOut <= konnectSelected;
end behaviour;
In the future I will update this to act as multiple Konnects and add an interface to SPI.
And its corresponding testBench:
Code:
library ieee ;
use ieee.std_logic_1164.all;
use work.all;
entity interfacetestbench is
end interfacetestbench;
architecture behaviour of interfacetestbench is
procedure wait_until_rising_edges(signal clk : in std_logic; n : in integer) is
begin
for i in 1 to n loop
wait until rising_edge(clk);
wait for 1 ns;
end loop;
end procedure;
component KonnectToSpi
port(
RST : in std_logic;
CLK : in std_logic;
CLKIN : in std_logic;
STARTIN : in std_logic;
dataBus : inout STD_LOGIC_VECTOR (7 DOWNTO 0);
LEDs : out std_logic_vector (2 downto 0);
konnectSelectedOut : out std_logic;
outputEnable : out std_logic
);
end component;
-- Inputs
signal RST : std_logic := '0';
signal CLK : std_logic := '0';
signal CLKIN : std_logic := '1';
signal STARTIN : std_logic := '0';
-- Outputs
signal dataBus : STD_LOGIC_VECTOR (7 DOWNTO 0);
signal LEDs : std_logic_vector (2 downto 0);
signal konnectSelectedOut : std_logic;
signal outputEnable : std_logic;
begin
UUT: KonnectToSpi port map (
RST => RST,
CLK => CLK,
CLKIN => CLKIN,
STARTIN => STARTIN,
dataBus => dataBus,
LEDs => LEDs,
konnectSelectedOut => konnectSelectedOut,
outputEnable => outputEnable
);
resetPulse: process
begin
RST <= '1';
wait for 10 ns;
RST <= '0';
wait for 10 ns;
RST <= '1';
wait;
end process;
xtal: process
begin
CLK <= '0';
wait for 20 ns;
CLK <= '1';
wait for 20 ns;
end process;
WaveformInput: process
begin
dataBus <= "LLLLLLLL";
wait_until_rising_edges(CLK,20);
CLKIN <= '0';
wait_until_rising_edges(CLK,5);
dataBus <= "00000000";
wait_until_rising_edges(CLK,10);
STARTIN <= '1';
wait_until_rising_edges(CLK,10);
dataBus <= "0000" & "1111"; -- Set addres on the bus over here
wait_until_rising_edges(CLK,10);
STARTIN <= '0'; -- Addres maching should be sampled on this falling edge
wait_until_rising_edges(CLK,10);
CLKIN <= '1'; -- Command bits should be read by the interface on this rising edge
wait_until_rising_edges(CLK,4);
dataBus <= "00000000"; -- Reset the databits
wait_until_rising_edges(CLK,4);
dataBus <= "00010101"; -- Ouput(0) should be presented to the interface here
wait_until_rising_edges(CLK,12);
CLKIN <= '0'; -- Output(0) should be sampled on this falling edge by the interface
wait_until_rising_edges(CLK,10);
CLKIN <= '1';
wait_until_rising_edges(CLK,4);
dataBus <= "11000011"; -- Ouput(1) should be presented to the interface here
wait_until_rising_edges(CLK,16);
CLKIN <= '0'; -- Output(1) should be sampled on this falling edge by the interface
wait_until_rising_edges(CLK,4);
dataBus <= "LLLLLLLL";
wait_until_rising_edges(CLK,8);
CLKIN <= '1';
wait_until_rising_edges(CLK,20); -- Input (0) interface should tell first inputs
CLKIN <= '0';
wait_until_rising_edges(CLK,10); -- Interface should go the high impedance
CLKIN <= '1';
wait_until_rising_edges(CLK,20); -- Input (1)
CLKIN <= '0';
wait_until_rising_edges(CLK,10); -- Interface should go the high impedance
CLKIN <= '1';
wait_until_rising_edges(CLK,20); -- Input (2)
CLKIN <= '0';
wait_until_rising_edges(CLK,10); -- Interface should go the high impedance
CLKIN <= '1';
wait_until_rising_edges(CLK,20); -- Input (3)
CLKIN <= '0';
wait_until_rising_edges(CLK,10); -- Interface should go the high impedance
CLKIN <= '1';
wait_until_rising_edges(CLK,50); -- Interface should present signature 0xA5
wait;
end process;
end;
And once implemented on the FPGA the proof of concept worked!
https://www.youtube.com/embed/bPkRl1-i5uc
In the meantime the guys worked on cleaning, reverse engineering and experimenting with the machine:
More updates to come!
Similar Threads: