multigcs / riocore

riocore
GNU General Public License v2.0
8 stars 3 forks source link

uart #6

Closed jschoch closed 2 days ago

jschoch commented 4 months ago

so the more I dig into this the more I am impressed with what you have accomplished but I also wonder if the complexity is too much? Anyway, it really is amazing that you have this working.

Regarding the Uart code. It seems that there isn't any generic uart code, the modbus sutff seems hardwired to the VFD code, and the uartbridge is hard wired to the LCNC host, the uart plugin has some oddness in it. I tried to hack it to work but it doesn't seem to do anything and I likely am not smart enough to do it.

Basically I reduced the buffer size to 16 and swapped out another value I had already working. I hooked my FTD1232 up with the TX pin connected to pin38 (mapped to RX) and typed into the COM port setup for 115200 baud.

Was this just never going to work? The encoder and bitin button pins both work, i just never see any data in the packet when I ran rio-test .... --debug

INTERFACE_SYNC and INTERFACE_TIMEOUT both don't seem to do anything much in this context so I assumed they could just be not used.

I think it would be nice to have a generic uart/modbus/spi examples someone could use to get started, maybe even better if there was some verilator to test with (on my list to learn). I'd like to try to get this working but I may need to be pointed in the right direction.

The easiest UART example would just echo the RX back to TX and also send the RX buffer via UDP for the test-GUI to show and or print out to the console via --debug.

Here's a diff, I just tried to make the changes in the Gateware dir.

choch@lcncN3700:~/dev/myfork_riocore/riocore/Output/udp_bridge_test$ diff Gateware Gateware2
diff Gateware/hash_new.txt Gateware2/hash_new.txt
1c1
< fc37c3350b81ba28a26adb8d64445bb5
\ No newline at end of file
---
> 0e0194d36c92f599c7d2f71c094e5ad1
\ No newline at end of file
Common subdirectories: Gateware/impl and Gateware2/impl
diff Gateware/rio.v Gateware2/rio.v
27,28c27,28

>     wire dummie_IF_TIMEOUT;
61a63
>     wire dummie_IF_SYNC = 1;
69a72,82
>     // make these 16 bigger to make room for the uart data
>     // need to have rio.c check the right size
>     //wire[167:0] rx_data;
>     //wire[167:0] tx_data;
> 
> 
>     wire[15:0] rx_data2;
>     wire[15:0] tx_data2;
> 
> 
> 
109c122,123
<         VARIN16_QUADENCODERZ26_REVS[7:0], VARIN16_QUADENCODERZ26_REVS[15:8],
---
>         //VARIN16_QUADENCODERZ26_REVS[7:0], VARIN16_QUADENCODERZ26_REVS[15:8],
>   rx_data[7:0],rx_data[15:8],
114a129
>   //rx_data[7:0],rx_data[15:8],
198c213
<         .BUFFER_SIZE(152),
---
>         .BUFFER_SIZE(16),
207,210c222,225
<         .rx_data(rx_data),
<         .tx_data(tx_data),
<         .sync(INTERFACE_SYNC),
<         .pkg_timeout(INTERFACE_TIMEOUT)
---
>         .rx_data(rx_data2),
>         .tx_data(tx_data2)
>         //.sync(dummie_IF_SYNC),
>         //.pkg_timeout(dummie_IF_TIMEOUT)

config:

{
    "name": "uart_bridge_test",
    "description": "Tangoboard with TangNano9K over UDP ",
    "boardcfg": "TangNano9K",
    "protocol": "UDP",
    "plugins": [
        {
            "type": "w5500",
            "port": "2390",
            "transport": "UDP",
            "protocol": "UDP",
            "pins": {
                "mosi": {
                    "pin": "75"
                },
                "miso": {
                    "pin": "74"
                },
                "sclk": {
                    "pin": "76"
                },
                "sel": {
                    "pin": "77"
                }
            },
            "name": "my_udp"
        },
        {
            "type": "blink",
            "pins": {
                "led": {
                    "pin": "10",
                    "modifier": [
                        {
                            "type": "invert"
                        }
                    ]
                }
            }
        },
        {
            "type": "bitout",
            "pins": {
                "bit": {
                    "pin": "11"
                }
            },
            "signals": {
                "bit": {
                    "display": {
                        "title": "led out",
                        "type": "button"
                    },
                    "net": ""
                }
            }
        },
        {
            "type": "stepdir",
            "pins": {
                "step": {
                    "pin": "54"
                },
                "dir": {
                    "pin": "53"
                },
                "en": {
                    "pin": "14"
                }
            },
            "is_joint": true,
            "name": "JOINT0",
            "axis": "X",
            "joint": {
                "scale": 4000.0,
                "max_acceleration": 70.0
            }
        },
        {
            "type": "stepdir",
            "pins": {
                "step": {
                    "pin": "41"
                },
                "dir": {
                    "pin": "35"
                },
                "en": {
                    "pin": "13"
                }
            },
            "name": "JOINT1",
            "axis": "Z",
            "is_joint": true,
            "joint": {
                "max_acceleration": 70.0
            }
        },
        {
            "type": "bitin",
            "pins": {
                "bit": {
                    "pin": "4",
                    "pullup": true
                }
            },
            "name": "btn_2"
        },
        {
            "type": "quadencoderz2",
            "pins": {
                "a": {
                    "pin": "33"
                },
                "b": {
                    "pin": "30"
                },
                "z": {
                    "pin": "29"
                }
            },
            "signals": {
                "indexenable": {
                    "net": "spindle.0.index-enable"
                },
                "position": {
                    "net": "spindle.0.revs"
                },
                "rps": {
                    "net": "spindle.0.speed-in"
                }
            }
        },
        {
            "type": "uart",
            "pins": {
                "rx": {
                    "pin": "38"
                },
                "tx": {
                    "pin": "37"
                }
            },
            "baud": 115200,
            "name": "uart_j2_csRx_clkTx"
        }
    ],
    "machinetype": "lathe",
    "axis": 2
}
multigcs commented 4 months ago

sorry, have no time at the moment, but: w5500 and uart plugins are interfaces and you can only use one of this, have to add a warning or try to get it work on the same time.

INTERFACE_SYNC is not used at the moment

INTERFACE_TIMEOUT is not implemented on the uart plugin, only on the network and spi plugin, because the uart was for testing and sometimes i run to low interval's

the modbus and uartbridge plugins are for controlling devices,

the modbus allready works (but need improvements), the vfd part is not generic, because its not a real modbus protocol, but works in combination with other modbus devices on the same bus

jschoch commented 4 months ago

Are you open to system verilog? The reason I was asking is that having structs seems like a great feature for things like these intefaces...

Also, wondering what your thoughts on testing and verilator are? Are you just using it for linting or are you doing any testing with it? If not verilator, wondering what you are using for testing? It seems like an integrated logic analyzer would be handy for this project.

multigcs commented 4 months ago

system-verilog: yes and no :) i don't know if this is supported by all toolchains and we need to change some parts

we would have to make a few changes, especially in the makefiles for some toolchains. I've done this before, but not everywhere.

The better way for me would be to convert the system-verilog at the end into normal verilog, which works very well and doesn't cause any problems in the build system

verilator: in the 'old' repository, i used iverilog to build test-benches for some plugins for better understanding the protocols or to find errors. https://github.com/multigcs/LinuxCNC-RIO/blob/main/plugins/vout_spipoti/Makefile

but most problems are on the real hardware, not in the simulation.

Normaly i use minimal configs on the Icebreaker-board (ice40), so i can really fast build new bitstreams und test direct on hardware, if needed with an hardware-logic-analyzer.

jschoch commented 4 months ago

Not sure if this adds too many deps but: https://github.com/zachjs/sv2v

I was watching this, and got a bit inspired. https://www.youtube.com/watch?v=3PVM07ei08U Being able to do struct literals, and to have automatic padding seemed pretty handy.

This morning I also played with this: https://github.com/kaspernyhus/esp_tinyusb_test, it required a bit of fiddling to get working. Pings are around 2.1ms so it may not be viable. I only tested NCM. It is possible the other usb networking modes have better latency.

multigcs commented 4 months ago

sv2v works fine, i already used it.

i have some esp32s2 and s3 boards, but can't find any UDP examples, i think if it works for the other project, then it's worth a try

jschoch commented 4 months ago

here's a fork with a working udp server ( mostly via Gemini)

https://github.com/jschoch/esp_tinyusb_test

multigcs commented 4 months ago

will try it, thanks

jschoch commented 4 months ago

apparently RNDIS/ECM is 10 faster than the NCM driver, but it isn't obvious how to get that working.... they have a dongle thing that has a ECM driver in it but the docs are in Chinese

multigcs commented 4 months ago

your tinyusb_test on esp32s3 works :)

netcat -u 192.168.11.160 8080

Hello from ESP32 S3! Hello from ESP32 S3!

multigcs commented 4 months ago

Uhhhh, very sloooooowwwww :)

# PYTHONPATH=. ../riogui/bin/rio-test -d riocore/configs/Tangoboard/config-5axis.json 192.168.11.160:2390
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-root'
loading: riocore/configs/Tangoboard/config-5axis.json
loading board setup: TangNano9K
connection via: UDP
IP: 192.168.11.160
PORT: 2390
WARNING: can not set timeouts: timed out
tx (400): [116, 105, 114, 119, 1, 8, 11, 2, 0, 0, 0, 4, 121, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
rx: [97, 116, 97, 100, 1, 8, 11, 2, 0, 0, 0, 4, 121, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
2.6412010192871094
ERROR: modbus CSUM failed [150, 101] != [0, 2]
#define UDP_SERVER_PORT 2390

static const char* TAG = "ESP32_SOCKET";

void udp_server_task(void *pvParameters)
{
    int sockfd;
    struct sockaddr_in server_addr, remote_addr;
    socklen_t addr_len = sizeof(remote_addr);

    // Create a UDP socket
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0) {
        ESP_LOGE(TAG, "Failed to create socket");
        vTaskDelete(NULL);
        return;
    }

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(UDP_SERVER_PORT);

    // Bind the socket to any available port
    if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        ESP_LOGE(TAG, "Failed to bind socket");
        close(sockfd);
        vTaskDelete(NULL);
        return;
    }

    while (1) {
        // Receive data (waits for a packet)

        uint8_t data[1024];

        int recv_bytes = recvfrom(sockfd, data, 50, MSG_WAITALL, 
                                 (struct sockaddr*)&remote_addr, &addr_len);

        data[0] = 97;
        data[1] = 116;
        data[2] = 97;
        data[3] = 100;

        if (recv_bytes < 0) {
            ESP_LOGE(TAG, "Failed to receive data");
            continue;
        }

        // Send data if a connection is established (remote address is valid)
        if (remote_addr.sin_addr.s_addr != INADDR_ANY) {
            int sent_bytes = sendto(sockfd, data, recv_bytes, 0, (struct sockaddr*)&remote_addr, addr_len);

            if (sent_bytes < 0) {
                ESP_LOGE(TAG, "Failed to send data");
                continue;
            }
        } 

        vTaskDelay(pdMS_TO_TICKS(1000));
    }

    close(sockfd);
    vTaskDelete(NULL);
}
multigcs commented 4 months ago

use deepl.com for Chinese doc's

jschoch commented 4 months ago

vTaskDelay(pdMS_TO_TICKS(1000));

set that to 1

multigcs commented 4 months ago

to slow for linuxcnc, but cooooool, thx !!!

tx (400): [116, 105, 114, 119, 30, 10, 32, 15, 0, 0, 0, 4, 1, 0, 253, 66, 0, 0, 0, 0, 0, 0, 0, 0, 70, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
rx: [97, 116, 97, 100, 30, 10, 32, 15, 0, 0, 0, 4, 1, 0, 253, 66, 0, 0, 0, 0, 0, 0, 0, 0, 70, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
2.6187896728515625
jschoch commented 4 months ago

Like i said, the ECM driver is 10x faster so that should be .2ms round trip times.... I think wez got that working in his project but he hasn't published that branch yet.

jschoch commented 4 months ago

also, per the above comment about performance, there is someone rewriting the NCM tinyusb driver and that performance may also get on par with the other driver.

multigcs commented 4 months ago

i think that means 1ms: vTaskDelay(pdMS_TO_TICKS(1);

how i can get 0.5ms or faster ?

multigcs commented 4 months ago

makes no difference :( : vTaskDelay(pdMS_TO_TICKS(1) / 5);

multigcs commented 4 months ago

ok, let's wait until wiz has committed it

jschoch commented 4 months ago

I believe that 1ms is the minimum task interval with the default IDF config, or that it is a RTOS limitation. You could setup a timer interrupt to go faster. Agree that @wezhunter likely has already figure out how to get the best performance.

wezhunter commented 4 months ago

Jessie is correct. If using Arduino the default RTOS tick is 1khz and if faster is required then use a HW timer. If using ESP-IDF the default RTOS tick is 100hz.

It's possible to compile Arduino as a component in IDF which I use for USB custom net driver.

It's also possible to change the RTOS tick that way however it's inadvisable since it wrecks havoc with any Arduino libs that use 1khz as timing, which is a surprising amount...

wezhunter commented 4 months ago

iDF sdkconfig: CONFIG_FREERTOSHZ There's an Arduino one if using Arduino as a component. I'm on mobile and search isn't working but it's under IDF menuconfig Arduino component. It's similar to the above but prefixed with ARDUINO

Don't advise you go that route anyway, HW timer and ensure it's ISR safe in IRAM is better for most use-cases. Useful to know that it's possible anyway...