This is a followup of my original post.

As I mentioned in the SPI-related post, I have added the SPI interface to my FPGA computer. Not one, but two: one for the SD card, and the other one for the Ethernet card. Today I am going to talk about the Ethernet.

First of all, I have used the ENC28J60 module, which I use for my Raspberry Pi Zero and Arduino/ESP32 ethernet connectivity This is rather simple module, which uses SPI as an interface to the host computer. Since I have already used this module with the Arduino and ESP32, I have decided to reuse the corresponding Arduino library for this module and to adjust it to work with my FPGA computer.

The library I used for the Arduino is: https://github.com/njh/EtherCard

This library is written in C++. Since I haven't finished porting GCC to my FPGA, I don't have the support for the C++. This means that I had to unwrap the code from C++ to pure C. When I finished that, the only thing that I had to do was to replace Arduino-based SPI code with my FPGA SPI code. For example, one of the original functions was:

static void writeOp (byte opbyte addressbyte data) {
    enableChip();
    SpiPtr->beginTransaction(SPISettings(spiClk, MSBFIRST, SPI_MODE0));
    SpiPtr->transfer(op | (address & ADDR_MASK));
    SpiPtr->transfer(data);
    SpiPtr->endTransaction();
    disableChip();
}

My code is:

void enc28j60WriteOp(uint8_t opuint8_t addressuint8_t data)
{
        chipSelectLowE();
        // issue write command
        spiSendE(op | (address & ADDR_MASK));
        // write data
        spiSendE(data);
        chipSelectHighE();
}

The support for the TCP/IP protocol is built in the EtherCard library. It also had to be modified from C++ to C. After that, I was able to use the library.

Besides simple TCP/IP examples, I have decided to make use of this network support. I have added network drive support in my BASIC interpreter - I have added the DRIVE command. DRIVE 0 selects the SD card. DRIVE 1 selects the UART-based drive which communicates with the Raspbootin application on the PC via UART, while DRIVE 2 sets the network drive which also communicates with the Raspbootin application on the PC, but this time over Ethernet.

Here is the snapshot of the FPGA screen:


In the example above, the drive was set to be the network drive and directory was listed on the PC. The C1.BAS program was loaded from the PC via network drive.

The C code for the DIR command is here:

// called when the client request is complete
void my_callback (uint8_t statusuint16_t offuint16_t len) {
    memcpy(to_print_buffeth_buffer+offlen);
    to_print_len = len;

...
// DRIVE 2 - ETHERNET NETWORK DRIVE
to_print_len = 0;
browseUrl("/dir""", server_ip, 0, my_callback);
for (i = 0; i < 1000; i++) { // approx. 1MB max file size
    packetLoop(enc28j60PacketReceive(4500, eth_buffer));
    if (to_print_len > 0) {
        to_print_buff[to_print_len] = 0;
        printf("%s\n", to_print_buff);
        to_print_len = 0;
        return;
    }
}
printf("NETWORK TIMEOUT\n");
...

The code on the PC side is here:

if (req.startsWith("/dir")) {
    File currFile = new File(Rest.path);
    File dir = currFile.getParentFile().getParentFile();
    System.out.println(dir.getCanonicalPath());
    File[] files = dir.listFiles();
    StringBuilder sb = new StringBuilder();
    for (File f : files) {
        if (f.isDirectory()) {
            sb.append("<" + f.getName() + ">");
            sb.append("\n");
        }
    }
    for (File f : files) {
        if (f.isFile()) {
            sb.append(f.getName());
            sb.append("\n");
        }
    }
    String str = sb.toString();
    int size = str.length();
    System.out.println("size: " + size);
    out.print(str);
}

Conclusion

Since I have implemented the SPI interface on the FPGA computer, it was possible to connect the ENC28J60 Ethernet module to it. I cannot stress enough how important for me was to be able to port the GCC to my platform. That allows me to use all sorts of C code instead of programming in assembly language.

Network drive also makes development easy since I do all the programming on my PC, I compile it using the GCC, and then I load that program on the FPGA computer over Ethernet. No need to transfer the program to the SD card (card dance), or to use slower UART. This time I use the Ethernet!