LinuxCNC-RIO - RealtimeIO for LinuxCNC based on FPGA (ICE40 / ECP5)

More
1 year 4 months ago #330550 by meister
Here is an output from the generator using the Tangbob configuration as an example:

github.com/multigcs/riocore/tree/dev/doc/example-output/Tangbob

and here is a kind of documentation of the generated gateware:

www.multixmedia.org/Tangbob-Gateware/

Please Log in or Create an account to join the conversation.

More
1 year 4 months ago - 1 year 4 months ago #330552 by meister
here i can also show the structure of the frames or the rio.v:

this is the 'top' verilog module, the main module:

github.com/multigcs/riocore/blob/dev/doc...ngbob/Gateware/rio.v

there is a block in which the RX frames are split into individual 'output signals':
Code:
// PC -> FPGA (330 + FILL) // assign header_rx = {rx_data[327:320], rx_data[335:328], rx_data[343:336], rx_data[351:344]}; assign VAROUT128_MODBUS0_TXDATA = {rx_data[199:192], rx_data[207:200], rx_data[215:208], rx_data[223:216], rx_data[231:224], rx_data[239:232], rx_data[247:240], rx_data[255:248], rx_data[263:256], rx_data[271:264], rx_data[279:272], rx_data[287:280], rx_data[295:288], rx_data[303:296], rx_data[311:304], rx_data[319:312]}; assign VAROUT32_PWMOUT0_DTY = {rx_data[167:160], rx_data[175:168], rx_data[183:176], rx_data[191:184]}; assign VAROUT32_STEPDIR0_VELOCITY = {rx_data[135:128], rx_data[143:136], rx_data[151:144], rx_data[159:152]}; assign VAROUT32_STEPDIR1_VELOCITY = {rx_data[103:96], rx_data[111:104], rx_data[119:112], rx_data[127:120]}; assign VAROUT32_STEPDIR2_VELOCITY = {rx_data[71:64], rx_data[79:72], rx_data[87:80], rx_data[95:88]}; assign VAROUT32_STEPDIR3_VELOCITY = {rx_data[39:32], rx_data[47:40], rx_data[55:48], rx_data[63:56]}; assign VAROUT1_WLED0_0_GREEN = {rx_data[31]}; assign VAROUT1_WLED0_0_BLUE = {rx_data[30]}; assign VAROUT1_WLED0_0_RED = {rx_data[29]}; assign VAROUT1_BITOUT0_BIT = {rx_data[28]}; assign VAROUT1_BITOUT1_BIT = {rx_data[27]}; assign VAROUT1_PWMOUT0_ENABLE = {rx_data[26]}; assign VAROUT1_STEPDIR0_ENABLE = {rx_data[25]}; assign VAROUT1_STEPDIR1_ENABLE = {rx_data[24]}; assign VAROUT1_STEPDIR2_ENABLE = {rx_data[23]}; assign VAROUT1_STEPDIR3_ENABLE = {rx_data[22]}; // assign FILL = rx_data[21:0];

and a block in which the ‘input signals’ are assembled to the TX frame:
Code:
// FPGA -> PC (349 + FILL) assign tx_data = { header_tx[7:0], header_tx[15:8], header_tx[23:16], header_tx[31:24], timestamp[7:0], timestamp[15:8], timestamp[23:16], timestamp[31:24], MULTIPLEXED_INPUT_VALUE[7:0], MULTIPLEXED_INPUT_VALUE[15:8], MULTIPLEXED_INPUT_ID[7:0], VARIN128_MODBUS0_RXDATA[7:0], VARIN128_MODBUS0_RXDATA[15:8], VARIN128_MODBUS0_RXDATA[23:16], VARIN128_MODBUS0_RXDATA[31:24], VARIN128_MODBUS0_RXDATA[39:32], VARIN128_MODBUS0_RXDATA[47:40], VARIN128_MODBUS0_RXDATA[55:48], VARIN128_MODBUS0_RXDATA[63:56], VARIN128_MODBUS0_RXDATA[71:64], VARIN128_MODBUS0_RXDATA[79:72], VARIN128_MODBUS0_RXDATA[87:80], VARIN128_MODBUS0_RXDATA[95:88], VARIN128_MODBUS0_RXDATA[103:96], VARIN128_MODBUS0_RXDATA[111:104], VARIN128_MODBUS0_RXDATA[119:112], VARIN128_MODBUS0_RXDATA[127:120], VARIN32_STEPDIR0_POSITION[7:0], VARIN32_STEPDIR0_POSITION[15:8], VARIN32_STEPDIR0_POSITION[23:16], VARIN32_STEPDIR0_POSITION[31:24], VARIN32_STEPDIR1_POSITION[7:0], VARIN32_STEPDIR1_POSITION[15:8], VARIN32_STEPDIR1_POSITION[23:16], VARIN32_STEPDIR1_POSITION[31:24], VARIN32_STEPDIR2_POSITION[7:0], VARIN32_STEPDIR2_POSITION[15:8], VARIN32_STEPDIR2_POSITION[23:16], VARIN32_STEPDIR2_POSITION[31:24], VARIN32_STEPDIR3_POSITION[7:0], VARIN32_STEPDIR3_POSITION[15:8], VARIN32_STEPDIR3_POSITION[23:16], VARIN32_STEPDIR3_POSITION[31:24], VARIN1_BITIN0_BIT, VARIN1_BITIN1_BIT, VARIN1_BITIN2_BIT, VARIN1_BITIN3_BIT, VARIN1_BITIN4_BIT, 3'd0 };

in the case of the Tangbob, the two frames ‘rx_data’ and ‘tx_data’ are passed to the w5500 module, which then takes care of the data exchange with the host computer:
Code:
w5500 #( .MAC_ADDR({8'hAA, 8'hAF, 8'hFA, 8'hCC, 8'hE3, 8'h1C}), .IP_ADDR({8'd192, 8'd168, 8'd10, 8'd194}), .NET_MASK({8'd255, 8'd255, 8'd255, 8'd0}), .GW_ADDR({8'd192, 8'd168, 8'd10, 8'd1}), .PORT(2390), .BUFFER_SIZE(BUFFER_SIZE), .MSGID(32'h74697277), .DIVIDER(0) ) w55000 ( .clk(sysclk), .mosi(PINOUT_W55000_MOSI_RAW), .miso(PININ_W55000_MISO), .sclk(PINOUT_W55000_SCLK_RAW), .sel(PINOUT_W55000_SEL_RAW), .intr(1'd0), .rx_data(rx_data), .tx_data(tx_data), .sync(INTERFACE_SYNC) );

Now let's take a look at the signals from one of the Stepdir module instances:

the input/output signals have the following naming scheme: VAR[DIRECTION]_[MODULE_INSTANCE]_[SIGNALNAME]

* VAROUT32_STEPDIR0_VELOCITY : a 32 bit output value for the specified velocity (steprate)
* VAROUT1_STEPDIR0_ENABLE : a 1 bit output value to activate the stepper (enable signal)
* VARIN32_STEPDIR0_POSITION : a 32 bit input value to return the current position (step counter)


Code:
stepdir #( .PULSE_LEN(108), .DIR_DELAY(18) ) stepdir0 ( .clk(sysclk), .step(PINOUT_STEPDIR0_STEP_RAW), .dir(PINOUT_STEPDIR0_DIR_RAW), .velocity(VAROUT32_STEPDIR0_VELOCITY), .enable(VAROUT1_STEPDIR0_ENABLE & ~ERROR), .position(VARIN32_STEPDIR0_POSITION) );


the pin signals have the following naming scheme: PIN[DIRECTION]_[MODULE_INSTANCE]_[PINNAME]

however, they can also have suffixes, such as. _RAW / _INVERTED / _DEBOUNCED / ...
this is due to the modifiers pipeline that can be configured for each pin.
Last edit: 1 year 4 months ago by meister.

Please Log in or Create an account to join the conversation.

More
1 year 4 months ago #330625 by DMNZ
ok. i think i got it. you create a bus with width of the data frame, clock the data in/out via SPI, and map each peripheral to a certain bits in the bus to use as input/output control registers. very elegant, simple and lightweight, the only inconvenience it needs driver rebuild for peripherals changes.

compared to mesa which uses memory map with peripherals mapped to addresses in the memory and need cpu parsing to read write addresses. but this allows dynamic configuration of the driver.
The following user(s) said Thank You: meister

Please Log in or Create an account to join the conversation.

More
1 year 4 months ago #330638 by PCW
compared to mesa which uses memory map with peripherals mapped to addresses in the memory and need cpu parsing to read write addresses. but this allows dynamic configuration of the driver.

I should note that a CPU is not required with HostMot2 and no interface CPU is  used in PCI, SPI or EPP
interfaced configurations. Interface CPUs are only used with  Ethernet, USB, and serial interfaced
configurations to support the more complex wire protocol.

 
The following user(s) said Thank You: tommylight, meister

Please Log in or Create an account to join the conversation.

More
1 year 4 months ago - 1 year 4 months ago #330667 by DMNZ
yes. sorry. i did not mean to compare anything in a bad way. i only meant Ethernet. in fact, RIO also needs CPU for ethernet, it just placed outside of fpga in UDP2SPI Bridge with STM32.
i hope i got the difference in data frame at least, RIO has fixed static data frame while Mesa has dynamic data frame configured by reading IDROM at the driver initialization.
Last edit: 1 year 4 months ago by DMNZ.

Please Log in or Create an account to join the conversation.

More
1 year 4 months ago #330683 by meister
small correction , udp2spi is outdated, and the W5500 is controlled directly by the FPGA

Please Log in or Create an account to join the conversation.

Time to create page: 0.187 seconds
Powered by Kunena Forum