From 6db0a502bfa313faac7fd9f409deabfbd6c8bbde Mon Sep 17 00:00:00 2001 From: "Sergio R. Caprile" Date: Tue, 3 Jan 2023 14:14:54 -0300 Subject: [PATCH] Add RMII example --- examples/rp2040/pico-rmii/CMakeLists.txt | 28 ++ examples/rp2040/pico-rmii/Makefile | 16 + examples/rp2040/pico-rmii/README.md | 63 +++ .../rp2040/pico-rmii/driver_rp2040_rmii.c | 366 ++++++++++++++++++ .../rp2040/pico-rmii/driver_rp2040_rmii.h | 10 + examples/rp2040/pico-rmii/main.c | 55 +++ examples/rp2040/pico-rmii/mongoose.c | 1 + examples/rp2040/pico-rmii/mongoose.h | 1 + 8 files changed, 540 insertions(+) create mode 100644 examples/rp2040/pico-rmii/CMakeLists.txt create mode 100644 examples/rp2040/pico-rmii/Makefile create mode 100644 examples/rp2040/pico-rmii/README.md create mode 100644 examples/rp2040/pico-rmii/driver_rp2040_rmii.c create mode 100644 examples/rp2040/pico-rmii/driver_rp2040_rmii.h create mode 100644 examples/rp2040/pico-rmii/main.c create mode 120000 examples/rp2040/pico-rmii/mongoose.c create mode 120000 examples/rp2040/pico-rmii/mongoose.h diff --git a/examples/rp2040/pico-rmii/CMakeLists.txt b/examples/rp2040/pico-rmii/CMakeLists.txt new file mode 100644 index 00000000..e99174d7 --- /dev/null +++ b/examples/rp2040/pico-rmii/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.13) +include(pico-sdk/pico_sdk_init.cmake) + +project(pico_rmii_ethernet) + +# initialize the Pico SDK +pico_sdk_init() + +add_compile_definitions( + MIP_DEBUG=1 + MG_ENABLE_PACKED_FS=1 + MG_ENABLE_MIP=1 +) + +add_executable(firmware + driver_rp2040_rmii.c + main.c + mongoose.c + ) + +# enable usb output, disable uart output +pico_enable_stdio_usb(firmware 1) +pico_enable_stdio_uart(firmware 0) + +target_link_libraries(firmware hardware_pio hardware_dma pico_stdlib) + +# create map/bin/hex file etc. +pico_add_extra_outputs(firmware) diff --git a/examples/rp2040/pico-rmii/Makefile b/examples/rp2040/pico-rmii/Makefile new file mode 100644 index 00000000..584371e2 --- /dev/null +++ b/examples/rp2040/pico-rmii/Makefile @@ -0,0 +1,16 @@ +SDK_VERSION ?= 1.4.0 +SDK_REPO ?= https://github.com/raspberrypi/pico-sdk + +all example: + true + +build: pico-sdk + test -d build || mkdir build + cd build && cmake .. && make + +pico-sdk: + git clone --depth 1 -b $(SDK_VERSION) $(SDK_REPO) $@ + cd $@ && git submodule update --init + +clean: + rm -rf pico-sdk build diff --git a/examples/rp2040/pico-rmii/README.md b/examples/rp2040/pico-rmii/README.md new file mode 100644 index 00000000..89a79a63 --- /dev/null +++ b/examples/rp2040/pico-rmii/README.md @@ -0,0 +1,63 @@ + +# RMII with the PIO in an RP2040 for 10Mbps Ethernet + +- Full-duplex 10Mbps +- RMII Tx implemented with a PIO state machine and single-buffer DMA transfers + - Once the DMA starts sending to the PIO, subsequent attempts to tx will block +- RMII Rx implemented with a PIO state machine and ping-pong buffer DMA transfers + - PIO code handles the CSR_DV signal, stops and raises an IRQ on frame ending. CRC is calculated later for minimum dead time between frames +- SMI implemented with a PIO state machine +- The RP2040 is clocked from the LAN8720 and works at 50MHz +- CRC calculation uses a fast table-based algorithm that doesn't require much storage (nibble calculation) + +## Hardware connections + +You can change most pins at will, bear in mind that each function requires consecutive pins, see main.c +The RETCLK (should be REFCLK...) pin can go to either GPIO20 or GPIO22 + +| LAN8720 | | Raspberry Pi Pico | | +| ----------- | ----------- |----------------- | -- | +| 1,2 | VCC | 3V3 | 36 | +| 3,4 | GND | GND | 38 | +| 5 | MDC | GPIO15 | 20 | +| 6 | MDIO | GPIO14 | 19 | +| 7 | CRS | GPIO8 | 11 | +| 8 | nINT / RETCLK | GPIO20 | 26 | +| 9 | RX1 | GPIO7 | 10 | +| 10 | RX0 | GPIO6 | 9 | +| 11 | TX0 | GPIO10 | 14 | +| 12 | TX-EN | GPIO12 | 16 | +| 13 | +| 14| TX1 | GPIO11 | 15 | + + +## Build and run + +Clone Mongoose repo, go to this example, and build it: + +```sh +git clone https://github.com/cesanta/mongoose +cd mongoose/examples/rp2040/pico-rmii +make build +``` + +This will generate a firmware file: `build/firmware.uf2`. Reboot your Pico board in bootloader mode, and copy it to the RPI disk. + +Attach to the serial console, wait a couple of seconds, then plug in your Ethernet cable: + +``` +$ picocom /dev/ttyACM0 -i -b 115200 --imap=lfcrlf +6213 1 mongoose.c:6757:onstatechange Link up +6217 3 mongoose.c:6840:tx_dhcp_discover DHCP discover sent +621b 3 mongoose.c:6723:arp_cache_add ARP cache: added 192.168.69.2 @ 52:54:... +6222 2 mongoose.c:6749:onstatechange READY, IP: 192.168.69.243 +6227 2 mongoose.c:6750:onstatechange GW: 192.168.69.1 +622b 2 mongoose.c:6752:onstatechange Lease: 21600 sec +``` + +Note the acquired IP address printed (you can also check your DHCP server). Point your browser to that address, or run curl, you should see an "ok" message: + +``` +$ curl 192.168.69.243 +ok +``` diff --git a/examples/rp2040/pico-rmii/driver_rp2040_rmii.c b/examples/rp2040/pico-rmii/driver_rp2040_rmii.c new file mode 100644 index 00000000..f0329119 --- /dev/null +++ b/examples/rp2040/pico-rmii/driver_rp2040_rmii.c @@ -0,0 +1,366 @@ +// Copyright (c) 2022 Cesanta Software Limited +// All rights reserved + +#include +#include +#include + +#include "hardware/dma.h" +#include "hardware/pio.h" +#include "pico/stdlib.h" + +#include "driver_rp2040_rmii.h" +#include "mongoose.h" + +#define RXSM 0 +#define TXSM 1 +#define SMITXSM 2 +#define SMIRXSM 0 // pio1 + +static uint smi_wr_addr, smi_rd_addr; +static int dma_rx; +static int dma_tx; + +static dma_channel_config dmacfg_rx; +static dma_channel_config dmacfg_tx; + +// Max frame size with VLAN tag + CRC and excluding preamble +#define ETH_PKT_SIZE 1522 + +static uint8_t s_rxbuf[2][ETH_PKT_SIZE]; // ping-pong buffer +static uint8_t s_txbuf[ETH_PKT_SIZE]; +static struct mip_if *s_ifp; // MIP interface + +#define rmii_tx_wrap_target 0 +#define rmii_tx_wrap 8 + +static const uint16_t rmii_tx_program_instructions[] = { + // .wrap_target + 0xe000, // 0: set pins, 0 side 0 + 0x80a0, // 1: pull block side 0 + 0xe03d, // 2: set x, 29 side 0 + 0xf101, // 3: set pins, 1 side 1 [1] + 0x1144, // 4: jmp x--, 4 side 1 [1] + 0xf103, // 5: set pins, 3 side 1 [1] + 0x7002, // 6: out pins, 2 side 1 + 0x10e6, // 7: jmp !osre, 6 side 1 + // .wrap +}; + +static const struct pio_program rmii_tx_program = { + .instructions = rmii_tx_program_instructions, + .length = 9, + .origin = -1, +}; + +static inline pio_sm_config rmii_tx_program_get_default_config(uint addr) { + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, addr + rmii_tx_wrap_target, addr + rmii_tx_wrap); + sm_config_set_sideset(&c, 1, false, false); + return c; +} + +static inline void rmii_tx_init(PIO pio, uint sm, uint addr, uint gpio) { + pio_sm_config c = rmii_tx_program_get_default_config(addr); + pio_gpio_init(pio, gpio); + pio_gpio_init(pio, gpio + 1); + pio_gpio_init(pio, gpio + 2); + sm_config_set_out_pins(&c, gpio, 2); + sm_config_set_set_pins(&c, gpio, 2); + sm_config_set_sideset_pins(&c, gpio + 2); + pio_sm_set_consecutive_pindirs(pio, sm, gpio, 3, true); + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); + sm_config_set_out_shift(&c, true, true, 8); // pull bytes, LSB first, auto + sm_config_set_clkdiv(&c, + 5); // Run at 50/5 = 10MHz (2x 2-bit nibble data rate) + pio_sm_init(pio, sm, addr, &c); + pio_sm_set_enabled(pio, sm, true); +} + +#define rmii_rx_wrap_target 0 +#define rmii_rx_wrap 10 + +static const uint16_t rmii_rx_program_instructions[] = { + // .wrap_target + 0x2122, // 0: wait 0 pin, 2 [1] + 0x21a2, // 1: wait 1 pin, 2 [1] + 0x21a0, // 2: wait 1 pin, 0 [1] + 0x2121, // 3: wait 0 pin, 1 [1] + 0x21a1, // 4: wait 1 pin, 1 [1] + 0x4002, // 5: in pins, 2 + 0x00c5, // 6: jmp pin, 5 + 0x4002, // 7: in pins, 2 + 0x00c5, // 8: jmp pin, 5 + 0xa0c3, // 9: mov isr, null + 0xc020, // 10: irq wait 0 + // .wrap +}; + +static const struct pio_program rmii_rx_program = { + .instructions = rmii_rx_program_instructions, + .length = 11, + .origin = -1, +}; + +static inline pio_sm_config rmii_rx_program_get_default_config(uint addr) { + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, addr + rmii_rx_wrap_target, addr + rmii_rx_wrap); + return c; +} + +static inline void rmii_rx_init(PIO pio, uint sm, uint addr, uint gpio) { + pio_sm_config c = rmii_rx_program_get_default_config(addr); + pio_gpio_init(pio, gpio); + pio_gpio_init(pio, gpio + 1); + pio_gpio_init(pio, gpio + 2); + sm_config_set_in_pins(&c, gpio); + pio_sm_set_consecutive_pindirs(pio, sm, gpio, 3, false); + sm_config_set_jmp_pin(&c, gpio + 2); + sm_config_set_in_shift(&c, true, true, 8); // push bytes, LSB first, auto + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX); + sm_config_set_clkdiv(&c, + 5); // Run at 50/5 = 10MHz (2x 2-bit nibble data rate) + pio_sm_init(pio, sm, addr, &c); + pio_sm_set_enabled(pio, sm, true); +} + +#define smi_wr_wrap_target 0 +#define smi_wr_wrap 4 + +static const uint16_t smi_wr_program_instructions[] = { + // .wrap_target + 0xe03f, // 0: set x, 31 side 0 + 0xe101, // 1: set pins, 1 side 0 [1] + 0x1141, // 2: jmp x--, 1 side 1 [1] + 0x6101, // 3: out pins, 1 side 0 [1] + 0x1103, // 4: jmp 3 side 1 [1] + // .wrap +}; + +static const struct pio_program smi_wr_program = { + .instructions = smi_wr_program_instructions, + .length = 5, + .origin = -1, +}; + +static inline pio_sm_config smi_wr_program_get_default_config(uint addr) { + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, addr + smi_wr_wrap_target, addr + smi_wr_wrap); + sm_config_set_sideset(&c, 1, false, false); + return c; +} + +#define smi_rd_wrap_target 13 +#define smi_rd_wrap 13 + +static const uint16_t smi_rd_program_instructions[] = { + 0xe03f, // 0: set x, 31 side 0 + 0xe101, // 1: set pins, 1 side 0 [1] + 0x1141, // 2: jmp x--, 1 side 1 [1] + 0xf02d, // 3: set x, 13 side 1 + 0x6101, // 4: out pins, 1 side 0 [1] + 0x1144, // 5: jmp x--, 4 side 1 [1] + 0xe180, // 6: set pindirs, 0 side 0 [1] + 0xf101, // 7: set pins, 1 side 1 [1] + 0xa142, // 8: nop side 0 [1] + 0xf12f, // 9: set x, 15 side 1 [1] + 0xa042, // 10: nop side 0 + 0x4001, // 11: in pins, 1 side 0 + 0x114a, // 12: jmp x--, 10 side 1 [1] + // .wrap_target + 0xf081, // 13: set pindirs, 1 side 1 + // .wrap +}; + +static const struct pio_program smi_rd_program = { + .instructions = smi_rd_program_instructions, + .length = 14, + .origin = -1, +}; + +static inline pio_sm_config smi_rd_program_get_default_config(uint addr) { + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, addr + smi_rd_wrap_target, addr + smi_rd_wrap); + sm_config_set_sideset(&c, 1, false, false); + return c; +} + +static inline void smi_wr_init(PIO pio, uint sm, uint addr, uint gpio) { + pio_gpio_init(pio, gpio); + pio_gpio_init(pio, gpio + 1); + pio_sm_config c = smi_wr_program_get_default_config(addr); + sm_config_set_out_pins(&c, gpio, 1); + sm_config_set_set_pins(&c, gpio, 1); + sm_config_set_sideset_pins(&c, gpio + 1); + pio_sm_set_consecutive_pindirs(pio, sm, gpio, 2, true); + sm_config_set_out_shift(&c, false, true, + 16); // pull half-words, MSB first, auto + sm_config_set_clkdiv(&c, 6); // Run at 50/6 = <10MHz (4x data rate) + pio_sm_init(pio, sm, addr, &c); +} + +static inline void smi_rd_init(PIO pio, uint sm, uint addr, uint gpio) { + pio_gpio_init(pio, gpio); + pio_gpio_init(pio, gpio + 1); + pio_sm_config c = smi_rd_program_get_default_config(addr); + sm_config_set_in_pins(&c, gpio); + sm_config_set_out_pins(&c, gpio, 1); + sm_config_set_set_pins(&c, gpio, 1); + sm_config_set_sideset_pins(&c, gpio + 1); + pio_sm_set_consecutive_pindirs(pio, sm, gpio, 2, true); + sm_config_set_out_shift(&c, false, true, + 16); // pull half-words, MSB first, auto + sm_config_set_in_shift(&c, false, true, + 16); // push half-words, MSB first, auto + sm_config_set_clkdiv(&c, 6); // Run at 50/6 = <10MHz (4x data rate) + pio_sm_init(pio, sm, addr, &c); +} + +static inline uint32_t crc_calc(const uint8_t *data, int length) { + static const uint32_t crclut[16] = { + // table for polynomial 0xEDB88320 (reflected) + 0x00000000, 0x1DB71064, 0x3B6E20C8, 0x26D930AC, 0x76DC4190, 0x6B6B51F4, + 0x4DB26158, 0x5005713C, 0xEDB88320, 0xF00F9344, 0xD6D6A3E8, 0xCB61B38C, + 0x9B64C2B0, 0x86D3D2D4, 0xA00AE278, 0xBDBDF21C}; + uint32_t crc = 0xFFFFFFFF; + while (--length >= 0) { + uint8_t byte = *data++; + crc = crclut[(crc ^ byte) & 0x0F] ^ (crc >> 4); + crc = crclut[(crc ^ (byte >> 4)) & 0x0F] ^ (crc >> 4); + } + return ~crc; +} + +static void eth_write_phy(int addr, int reg, int val, uint8_t gpio) { + uint16_t op = 0x5002 | (addr << 7) | (reg << 2); // b0101aaaaarrrrr10 + smi_wr_init(pio0, SMITXSM, smi_wr_addr, gpio); + pio_sm_put(pio0, SMITXSM, op << 16); + pio_sm_put(pio0, SMITXSM, (uint16_t) val << 16); + pio_sm_set_enabled(pio0, SMITXSM, true); +} + +static uint16_t eth_read_phy(uint addr, uint reg, uint8_t gpio) { + uint16_t op = 0x6000 | (addr << 7) | (reg << 2); // b0110aaaaarrrrr00 + smi_rd_init(pio1, SMIRXSM, smi_rd_addr, gpio); + pio_sm_put(pio1, SMIRXSM, op << 16); + pio_sm_set_enabled(pio1, SMIRXSM, true); + uint16_t val = (uint16_t) pio_sm_get_blocking(pio1, SMIRXSM); + pio_sm_set_enabled(pio1, SMIRXSM, false); + return val; +} + +static void rx_irq(void); + +static bool mip_driver_rp2040_rmii_init(struct mip_if *ifp) { + struct mip_driver_rp2040_rmii_data *d = + (struct mip_driver_rp2040_rmii_data *) ifp->driver_data; + uint rx_sm_addr, tx_sm_addr; + s_ifp = ifp; + if (ifp->queue.len == 0) ifp->queue.len = 8192; + rx_sm_addr = pio_add_program(pio0, &rmii_rx_program); + tx_sm_addr = pio_add_program(pio0, &rmii_tx_program); + smi_wr_addr = pio_add_program(pio0, &smi_wr_program); + smi_rd_addr = pio_add_program(pio1, &smi_rd_program); + + dma_tx = dma_claim_unused_channel(true); + dmacfg_tx = dma_channel_get_default_config(dma_tx); + channel_config_set_read_increment(&dmacfg_tx, true); // read from memory + channel_config_set_write_increment(&dmacfg_tx, false); // write to FIFO + channel_config_set_dreq(&dmacfg_tx, pio_get_dreq(pio0, TXSM, true)); + channel_config_set_transfer_data_size(&dmacfg_tx, + DMA_SIZE_8); // transfer bytes + rmii_tx_init(pio0, TXSM, tx_sm_addr, d->tx0); + + eth_write_phy(d->phy_addr, 4, 0x61, + d->mdio); // Auto Negotiation Advertisement Register: enable + // only 10BASE-T full and half duplex (two-pair), use + // IEEE 802.3 format + sleep_us(31); // give some time for PIO to work (64 bits @2.5MHz = 25.6 us) + eth_write_phy(d->phy_addr, 0, 0x1000, + d->mdio); // Basic Control Register: enable Auto-Negotiation + sleep_us(31); + + dma_rx = dma_claim_unused_channel(true); + dmacfg_rx = dma_channel_get_default_config(dma_rx); + channel_config_set_read_increment(&dmacfg_rx, false); // read from FIFO + channel_config_set_write_increment(&dmacfg_rx, + true); // write to memory, increment + channel_config_set_dreq(&dmacfg_rx, pio_get_dreq(pio0, RXSM, false)); + channel_config_set_transfer_data_size(&dmacfg_rx, + DMA_SIZE_8); // transfer bytes + dma_channel_configure(dma_rx, &dmacfg_rx, s_rxbuf[0], + ((uint8_t *) &pio0->rxf[RXSM]) + 3, ETH_PKT_SIZE, true); + pio_set_irq0_source_enabled(pio0, pis_interrupt0, + true); // enable SM0 on PIO0_IRQ_0 + irq_set_exclusive_handler(7, rx_irq); // set handler for PIO0_IRQ_0 + irq_set_enabled(7, true); // enable it + rmii_rx_init(pio0, RXSM, rx_sm_addr, d->rx0); + + return true; +} + +static size_t mip_driver_rp2040_rmii_tx(const void *buf, size_t len, + struct mip_if *ifp) { + dma_channel_wait_for_finish_blocking(dma_tx); + memset(s_txbuf, 0, 60); // pre-pad + memcpy(s_txbuf, buf, len); + if (len < 60) len = 60; // pad + uint32_t crc = crc_calc(s_txbuf, len); // host is little-endian + memcpy(s_txbuf + len, (uint8_t *) &crc, 4); + len += 4; + sleep_us(10); // enforce IFG in case software has been lightning fast... + dma_channel_configure(dma_tx, &dmacfg_tx, ((uint8_t *) &pio0->txf[TXSM]) + 3, + s_txbuf, len, true); + return len; +} + +static uint32_t s_rxno; + +// The max amount of time we should keep the PIO state machine stopped is the +// IFG time (10us) and that includes irq latency +static void rx_irq(void) { + dma_channel_hw_t *hw = dma_channel_hw_addr(dma_rx); + uint32_t rxno = + (s_rxno + 1) & + 1; // 2 buffers, switch to the available one as fast as possible + size_t len = ETH_PKT_SIZE - hw->transfer_count; + dma_channel_abort(dma_rx); + dma_channel_set_write_addr(dma_rx, s_rxbuf[rxno], true); // restart DMA + pio_interrupt_clear(pio0, + 0); // ACK PIO IRQ so the state machine resumes receiving + // NOTE(scaprile) Here we could check addressing to avoid queuing frames not + // for us, or we can defer that for later as we do with CRC The max amount of + // time we can linger here is what it takes for the other buffer to fill + // (<8us) and that includes irq chaining + if (len >= 64 && len <= ETH_PKT_SIZE) + mip_qwrite(s_rxbuf[s_rxno], len, s_ifp); + s_rxno = rxno; +} + +static size_t mip_driver_rp2040_rmii_rx(void *buf, size_t buflen, struct mip_if *ifp) { + size_t len = mip_qread(buf, ifp); + if (len == 0) return 0; + len -= 4; // exclude CRC from frame length + uint32_t crc = crc_calc(buf, len); // calculate CRC and compare + // NOTE(scaprile) Here we could check addressing to avoid delivering frames + // not for us, though MIP already does that (now ?) + if (memcmp(&((uint8_t *) buf)[len], &crc, + sizeof(crc))) // host is little-endian + return 0; + return len; +} + +static bool mip_driver_rp2040_rmii_up(struct mip_if *ifp) { + struct mip_driver_rp2040_rmii_data *d = + (struct mip_driver_rp2040_rmii_data *) ifp->driver_data; + uint32_t bsr = + eth_read_phy(d->phy_addr, 1, d->mdio); // Basic Status Register + return (bsr & (1 << 2)) ? 1 : 0; // check Link Status flag +} + +struct mip_driver mip_driver_rp2040_rmii = { + mip_driver_rp2040_rmii_init, + mip_driver_rp2040_rmii_tx, + mip_driver_rp2040_rmii_rx, + mip_driver_rp2040_rmii_up, +}; diff --git a/examples/rp2040/pico-rmii/driver_rp2040_rmii.h b/examples/rp2040/pico-rmii/driver_rp2040_rmii.h new file mode 100644 index 00000000..1ad696d1 --- /dev/null +++ b/examples/rp2040/pico-rmii/driver_rp2040_rmii.h @@ -0,0 +1,10 @@ +#pragma once + +struct mip_driver_rp2040_rmii_data { + uint8_t rx0; // RX0, RX1, CRS_DV; consecutive GPIO pins + uint8_t tx0; // TX0, TX1, TX-EN; consecutive GPIO pins + uint8_t mdio; // MDIO, MDC; consecutive GPIO pins + uint8_t phy_addr; // PHY address +}; + +extern struct mip_driver mip_driver_rp2040_rmii; diff --git a/examples/rp2040/pico-rmii/main.c b/examples/rp2040/pico-rmii/main.c new file mode 100644 index 00000000..e9183a11 --- /dev/null +++ b/examples/rp2040/pico-rmii/main.c @@ -0,0 +1,55 @@ +// Copyright (c) 2022 Cesanta Software Limited +// All rights reserved + +#include "pico/stdlib.h" +#include "hardware/clocks.h" + +#include "mongoose.h" + +#include "driver_rp2040_rmii.h" + +#define CLKREFPIN 20 // either 20 or 22 + +static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { + if (ev == MG_EV_HTTP_MSG) { + mg_http_reply(c, 200, "", "ok\n"); + } +} + + +int main(void) { + // use the RMII reference clock (50MHz) as our system clock + clock_configure_gpin(clk_sys, CLKREFPIN, 50 * MHZ, 50 * MHZ); + sleep_ms(100); + stdio_init_all(); + + struct mg_mgr mgr; // Initialise Mongoose event manager + mg_mgr_init(&mgr); // and attach it to the MIP interface + mg_log_set(MG_LL_DEBUG); // Set log level + + MG_INFO(("Init MIP")); + // Initialise Mongoose network stack and specific driver + // Set consecutive GPIOs for RMII (tx and rx) and SMI function groups + struct mip_driver_rp2040_rmii_data driver_data = { + // see driver_rp2040_rmii.h + .rx0 = 6, // 6, 7, 8 : RX0, RX1, CRS_DV + .tx0 = 10, // 10, 11, 12 : TX0, TX1, TX-EN + .mdio = 14, // 14, 15 : MDIO, MDC + .phy_addr = 1 // check your hardware, LAN8722 is 0 or 1 + }; + // Specify MAC address, either set use_dhcp or enter a static config. + // For static configuration, specify IP/mask/GW in network byte order + struct mip_if mif = { + .mac = {2, 0, 1, 2, 3, 5}, + .ip = 0, + .driver = &mip_driver_rp2040_rmii, + .driver_data = &driver_data, + }; + mip_init(&mgr, &mif); + mg_http_listen(&mgr, "http://0.0.0.0", fn, NULL); // HTTP listener + MG_INFO(("Init done, starting main loop")); + + for (;;) mg_mgr_poll(&mgr, 0); // Infinite event loop + + return 0; +} diff --git a/examples/rp2040/pico-rmii/mongoose.c b/examples/rp2040/pico-rmii/mongoose.c new file mode 120000 index 00000000..5e522bbc --- /dev/null +++ b/examples/rp2040/pico-rmii/mongoose.c @@ -0,0 +1 @@ +../../../mongoose.c \ No newline at end of file diff --git a/examples/rp2040/pico-rmii/mongoose.h b/examples/rp2040/pico-rmii/mongoose.h new file mode 120000 index 00000000..ee4ac823 --- /dev/null +++ b/examples/rp2040/pico-rmii/mongoose.h @@ -0,0 +1 @@ +../../../mongoose.h \ No newline at end of file