From ccd3514da33ae690e19e88b916d6473d2e6b7f79 Mon Sep 17 00:00:00 2001 From: cpq Date: Wed, 20 May 2026 10:30:23 +0100 Subject: [PATCH] RP boards --- tutorials/pico-sdk/pico2_w/Makefile | 2 +- tutorials/pico-sdk/pico2_w/README.md | 12 + tutorials/pico-sdk/pico2_w/main.c | 24 +- .../pico-sdk/w5500_evb_pico/CMakeLists.txt | 16 ++ tutorials/pico-sdk/w5500_evb_pico/Makefile | 53 +++++ tutorials/pico-sdk/w5500_evb_pico/main.c | 92 ++++++++ .../pico-sdk/w5500_evb_pico/mongoose_config.h | 48 ++++ .../pico-sdk/w5500_evb_pico2/CMakeLists.txt | 19 ++ tutorials/pico-sdk/w5500_evb_pico2/Makefile | 40 ++++ .../pico-sdk/w55rp20_evb_pico/CMakeLists.txt | 16 ++ tutorials/pico-sdk/w55rp20_evb_pico/Makefile | 53 +++++ tutorials/pico-sdk/w55rp20_evb_pico/main.c | 205 ++++++++++++++++++ .../w55rp20_evb_pico/mongoose_config.h | 48 ++++ 13 files changed, 618 insertions(+), 10 deletions(-) create mode 100644 tutorials/pico-sdk/pico2_w/README.md create mode 100644 tutorials/pico-sdk/w5500_evb_pico/CMakeLists.txt create mode 100644 tutorials/pico-sdk/w5500_evb_pico/Makefile create mode 100644 tutorials/pico-sdk/w5500_evb_pico/main.c create mode 100644 tutorials/pico-sdk/w5500_evb_pico/mongoose_config.h create mode 100644 tutorials/pico-sdk/w5500_evb_pico2/CMakeLists.txt create mode 100644 tutorials/pico-sdk/w5500_evb_pico2/Makefile create mode 100644 tutorials/pico-sdk/w55rp20_evb_pico/CMakeLists.txt create mode 100644 tutorials/pico-sdk/w55rp20_evb_pico/Makefile create mode 100644 tutorials/pico-sdk/w55rp20_evb_pico/main.c create mode 100644 tutorials/pico-sdk/w55rp20_evb_pico/mongoose_config.h diff --git a/tutorials/pico-sdk/pico2_w/Makefile b/tutorials/pico-sdk/pico2_w/Makefile index 02a29b1e..02e34bf4 100644 --- a/tutorials/pico-sdk/pico2_w/Makefile +++ b/tutorials/pico-sdk/pico2_w/Makefile @@ -1,6 +1,6 @@ # Environment setup: https://mongoose.ws/docs/getting-started/build-environment/ -CWD = $(realpath $(PWD)) +CWD ?= $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) SDK_PATH ?= $(CWD)/pico-sdk RM = rm -rf MKBUILD = test -d build || mkdir build diff --git a/tutorials/pico-sdk/pico2_w/README.md b/tutorials/pico-sdk/pico2_w/README.md new file mode 100644 index 00000000..fb055469 --- /dev/null +++ b/tutorials/pico-sdk/pico2_w/README.md @@ -0,0 +1,12 @@ +# Pico2-W Mongoose example + +To build and run, + +1. Edit main.c and change WIFI credentials +2. Execute the following + +```sh +make build flash +``` + +3. Run serial console to see the debug output diff --git a/tutorials/pico-sdk/pico2_w/main.c b/tutorials/pico-sdk/pico2_w/main.c index 34121b46..e5294c55 100644 --- a/tutorials/pico-sdk/pico2_w/main.c +++ b/tutorials/pico-sdk/pico2_w/main.c @@ -25,10 +25,12 @@ void wifi_setconfig(void *data) { wifi->apmode = ENABLE_AP; } -static void blink_timer(void *arg) { - (void) arg; - cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, - !cyw43_arch_gpio_get(CYW43_WL_GPIO_LED_PIN)); +static void blink_task(void) { + static uint64_t timer; + if (mg_timer_expired(&timer, 500, mg_now())) { + cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, + !cyw43_arch_gpio_get(CYW43_WL_GPIO_LED_PIN)); + } } static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { @@ -43,18 +45,22 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { } } -int main(void) { - stdio_init_all(); - // do not access the CYW43 LED before Mongoose initializes ! - MG_INFO(("Hardware initialised, starting firmware...")); - +// In an RTOS environment, give this task 8 KB of stack space. +static void run_mongoose(void) { struct mg_mgr mgr; mg_mgr_init(&mgr); mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL); for (;;) { mg_mgr_poll(&mgr, 1); + blink_task(); } +} +int main(void) { + stdio_init_all(); + // do not access the CYW43 LED before Mongoose initializes ! + MG_INFO(("Hardware initialised, starting firmware...")); + run_mongoose(); return 0; } diff --git a/tutorials/pico-sdk/w5500_evb_pico/CMakeLists.txt b/tutorials/pico-sdk/w5500_evb_pico/CMakeLists.txt new file mode 100644 index 00000000..af2a2e21 --- /dev/null +++ b/tutorials/pico-sdk/w5500_evb_pico/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.13) + +# If you will set board type here, do it BEFORE including the SDK +# set(PICO_BOARD pico2_w) +include(pico_sdk_import.cmake) + +project(firmware) +pico_sdk_init() +add_executable(firmware main.c mongoose.c) + +target_link_libraries(firmware pico_stdlib hardware_spi pico_rand hardware_flash pico_bootrom) +pico_add_extra_outputs(firmware) # create map/bin/hex file etc. +pico_enable_stdio_usb(firmware 1) # Route stdio + +# Prevent extreme optimization from breaking OTA +target_compile_options(firmware PRIVATE -fno-tree-loop-distribute-patterns) diff --git a/tutorials/pico-sdk/w5500_evb_pico/Makefile b/tutorials/pico-sdk/w5500_evb_pico/Makefile new file mode 100644 index 00000000..986d5704 --- /dev/null +++ b/tutorials/pico-sdk/w5500_evb_pico/Makefile @@ -0,0 +1,53 @@ +# Environment setup: https://mongoose.ws/docs/getting-started/build-environment/ + +CWD ?= $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) +SDK_PATH ?= $(CWD)/pico-sdk +RM = rm -rf +MKBUILD = test -d build || mkdir build + +ifeq ($(OS),Windows_NT) + RM = cmd /C del /Q /F /S + MKBUILD = if not exist build mkdir build +endif + +.PHONY: build + +all build: build/firmware.uf2 + +build/firmware.uf2: pico_sdk_import.cmake mongoose.c mongoose.h + +pico_sdk_import.cmake: $(SDK_PATH) + cp $(SDK_PATH)/external/$@ $@ + +mongoose.c mongoose.h: + cp ../../../$@ . + +build/firmware.uf2: $(SDK_PATH) $(wildcard *.[ch]) CMakeLists.txt Makefile + $(MKBUILD) + cd build && PICO_SDK_PATH=$(SDK_PATH) cmake -G "Unix Makefiles" .. && make + +flash: build/firmware.uf2 + picotool load $< -f + +clean: + $(RM) build pico_sdk_import.cmake mongoose.c mongoose.h + +fullclean: clean + $(RM) $(SDK_PATH) + +$(SDK_PATH): + git clone -c advice.detachedHead=false --quiet --depth 1 -b 2.1.1 https://github.com/raspberrypi/pico-sdk $@ + cd $@ && git submodule update --quiet --init + +# Automated remote test. Requires env variable VCON_API_KEY set. See https://vcon.io/automated-firmware-tests/ +DEVICE_URL ?= https://dash.vcon.io/api/v3/devices/3 +# stdio has to be changed from USB to UART in CMakeLists.txt +update: + perl -pi -e 's/pico_enable_stdio_usb(firmware 1)/pico_enable_stdio_usb(firmware 0)/' CMakeLists.txt + $(MAKE) build + perl -pi -e 's/pico_enable_stdio_usb(firmware 0)/pico_enable_stdio_usb(firmware 1)/' CMakeLists.txt + curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/ota?uf2=1 --data-binary @build/firmware.uf2 + +test: update + curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=15 | tee /tmp/output.txt + grep 'READY, IP:' /tmp/output.txt # Check for network init diff --git a/tutorials/pico-sdk/w5500_evb_pico/main.c b/tutorials/pico-sdk/w5500_evb_pico/main.c new file mode 100644 index 00000000..267ce3fb --- /dev/null +++ b/tutorials/pico-sdk/w5500_evb_pico/main.c @@ -0,0 +1,92 @@ +// SPDX-FileCopyrightText: 2026 Cesanta Software Limited +// SPDX-License-Identifier: GPL-2.0-only or commercial + +#include "hardware/spi.h" +#include "pico/stdlib.h" +#include "pico/unique_id.h" + +#include "mongoose.h" + +enum { SPI_CS = 17, SPI_CLK = 18, SPI_TX = 19, SPI_RX = 16 }; // Pins +// enum { SPI_CS = 5, SPI_CLK = 2, SPI_TX = 3, SPI_RX = 4 }; // Pins + +void spi_begin(void *spi) { + gpio_put(SPI_CS, 0); +} + +void spi_end(void *spi) { + gpio_put(SPI_CS, 1); +} + +void spi_txn(void *spi, uint8_t *tx, uint8_t *rx, size_t len) { + if (tx != NULL && rx != NULL) { + spi_write_read_blocking(spi0, tx, rx, len); + } else if (tx != NULL) { + spi_write_blocking(spi0, tx, len); + } else { + spi_read_blocking(spi0, 0xFF, rx, len); + } +} + +static void ethernet_init(void) { + // Init SPI pins + spi_init(spi0, 500 * 1000); + gpio_set_function(SPI_RX, GPIO_FUNC_SPI); // MISO + gpio_set_function(SPI_TX, GPIO_FUNC_SPI); // MOSI + gpio_set_function(SPI_CLK, GPIO_FUNC_SPI); // CLK + gpio_init(SPI_CS); // CS + gpio_set_dir(SPI_CS, GPIO_OUT); // Set CS to output + gpio_put(SPI_CS, 1); // And drive CS high (inactive) +} + +// Construct MAC address from the unique board ID +void genmac(unsigned char *mac) { + pico_unique_board_id_t board_id; + pico_get_unique_board_id(&board_id); + mac[0] = 2; + memcpy(&mac[1], &board_id.id[3], 5); +} + +static void blink_task(void) { + static uint64_t timer; + if (mg_timer_expired(&timer, 500, mg_now())) { + gpio_put(PICO_DEFAULT_LED_PIN, !gpio_get(PICO_DEFAULT_LED_PIN)); + } +} + +static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { + if (ev == MG_EV_HTTP_MSG) { // New HTTP request received + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + uint64_t tick = to_ms_since_boot(get_absolute_time()); + if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { + mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), tick); + } else { + mg_http_reply(c, 200, "", "Hi from Mongoose, tick %llu\n", tick); + } + } +} + +// In an RTOS environment, give this task 8 KB of stack space. +static void run_mongoose(void) { + struct mg_mgr mgr; + + mg_mgr_init(&mgr); + mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL); + + for (;;) { + mg_mgr_poll(&mgr, 1); + blink_task(); + } +} + +int main(void) { + stdio_init_all(); + gpio_init(PICO_DEFAULT_LED_PIN); // Initialise GPIO + gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); // Set as output + gpio_put(PICO_DEFAULT_LED_PIN, 1); + ethernet_init(); + MG_INFO(("Hardware initialised, starting firmware...")); + + run_mongoose(); + return 0; +} diff --git a/tutorials/pico-sdk/w5500_evb_pico/mongoose_config.h b/tutorials/pico-sdk/w5500_evb_pico/mongoose_config.h new file mode 100644 index 00000000..ed9a9fea --- /dev/null +++ b/tutorials/pico-sdk/w5500_evb_pico/mongoose_config.h @@ -0,0 +1,48 @@ +#pragma once + +// See https://mongoose.ws/documentation/#build-options +#define MG_ARCH MG_ARCH_PICOSDK +#define MG_OTA MG_OTA_PICOSDK +#define MG_TLS MG_TLS_BUILTIN +#define MG_IO_SIZE 2048 + +#define MG_ENABLE_TCPIP 1 +#define MG_ENABLE_DRIVER_W5500 1 + +// For static IP configuration, define MG_TCPIP_{IP,MASK,GW} +// By default, those are set to zero, meaning that DHCP is used +// +// #define MG_TCPIP_IP MG_IPV4(192, 168, 1, 10) +// #define MG_TCPIP_GW MG_IPV4(192, 168, 1, 1) +// #define MG_TCPIP_MASK MG_IPV4(255, 255, 255, 0) + +// Set custom MAC address. By default, it is randomly generated +// Using a build-time constant: +// #define MG_SET_MAC_ADDRESS(mac) do { uint8_t buf_[6] = {2,3,4,5,6,7}; +// memmove(mac, buf_, sizeof(buf_)); } while (0) +// +// Using custom function: +extern void genmac(unsigned char *mac); +#define MG_SET_MAC_ADDRESS(mac) genmac(mac) + +// Hardware specific SPI support +#include +#include + +extern void spi_begin(void *); +extern void spi_end(void *); +extern void spi_txn(void *spi, uint8_t *tx, uint8_t *rx, size_t len); + +#define MG_TCPIP_DRIVER_INIT(mgr) \ + do { \ + static struct mg_tcpip_spi spi_ = {NULL, spi_begin, spi_end, spi_txn}; \ + static struct mg_tcpip_if mif_; \ + mif_.ip = MG_TCPIP_IP; \ + mif_.mask = MG_TCPIP_MASK; \ + mif_.gw = MG_TCPIP_GW; \ + mif_.driver = &mg_tcpip_driver_w5500; \ + mif_.driver_data = &spi_; \ + MG_SET_MAC_ADDRESS(mif_.mac); \ + mg_tcpip_init(mgr, &mif_); \ + MG_INFO(("Driver: W5500, MAC: %M", mg_print_mac, mif_.mac)); \ + } while (0) diff --git a/tutorials/pico-sdk/w5500_evb_pico2/CMakeLists.txt b/tutorials/pico-sdk/w5500_evb_pico2/CMakeLists.txt new file mode 100644 index 00000000..2177a81f --- /dev/null +++ b/tutorials/pico-sdk/w5500_evb_pico2/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.13) + +# If you will set board type here, do it BEFORE including the SDK +set(PICO_BOARD pico2) +include(pico_sdk_import.cmake) + +project(firmware) +pico_sdk_init() + +# Sources are identical to ../w5500_evb_pico, we're just setting pico2 board +add_executable(firmware ../w5500_evb_pico/main.c mongoose.c) +target_include_directories(firmware PRIVATE . ../w5500_evb_pico) + +target_link_libraries(firmware pico_stdlib hardware_spi pico_rand hardware_flash pico_bootrom) +pico_add_extra_outputs(firmware) # create map/bin/hex file etc. +pico_enable_stdio_usb(firmware 1) # Route stdio + +# Prevent extreme optimization from breaking OTA +target_compile_options(firmware PRIVATE -fno-tree-loop-distribute-patterns) diff --git a/tutorials/pico-sdk/w5500_evb_pico2/Makefile b/tutorials/pico-sdk/w5500_evb_pico2/Makefile new file mode 100644 index 00000000..02e34bf4 --- /dev/null +++ b/tutorials/pico-sdk/w5500_evb_pico2/Makefile @@ -0,0 +1,40 @@ +# Environment setup: https://mongoose.ws/docs/getting-started/build-environment/ + +CWD ?= $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) +SDK_PATH ?= $(CWD)/pico-sdk +RM = rm -rf +MKBUILD = test -d build || mkdir build + +ifeq ($(OS),Windows_NT) + RM = cmd /C del /Q /F /S + MKBUILD = if not exist build mkdir build +endif + +.PHONY: build + +all build: build/firmware.uf2 + +build/firmware.uf2: pico_sdk_import.cmake mongoose.c mongoose.h + +pico_sdk_import.cmake: $(SDK_PATH) + cp $(SDK_PATH)/external/$@ $@ + +mongoose.c mongoose.h: + cp ../../../$@ . + +build/firmware.uf2: $(SDK_PATH) $(wildcard *.[ch]) CMakeLists.txt Makefile + $(MKBUILD) + cd build && PICO_SDK_PATH=$(SDK_PATH) cmake -G "Unix Makefiles" .. && make + +flash: build/firmware.uf2 + picotool load $< -f + +clean: + $(RM) build pico_sdk_import.cmake mongoose.c mongoose.h + +fullclean: clean + $(RM) $(SDK_PATH) + +$(SDK_PATH): + git clone -c advice.detachedHead=false --quiet --depth 1 -b 2.1.1 https://github.com/raspberrypi/pico-sdk $@ + cd $@ && git submodule update --quiet --init diff --git a/tutorials/pico-sdk/w55rp20_evb_pico/CMakeLists.txt b/tutorials/pico-sdk/w55rp20_evb_pico/CMakeLists.txt new file mode 100644 index 00000000..cce12837 --- /dev/null +++ b/tutorials/pico-sdk/w55rp20_evb_pico/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.13) + +# If you will set board type here, do it BEFORE including the SDK +# set(PICO_BOARD pico2_w) +include(pico_sdk_import.cmake) + +project(firmware) +pico_sdk_init() +add_executable(firmware main.c mongoose.c) + +target_link_libraries(firmware pico_stdlib hardware_pio pico_rand hardware_flash pico_bootrom) +pico_add_extra_outputs(firmware) # create map/bin/hex file etc. +pico_enable_stdio_usb(firmware 1) # Route stdio + +# Prevent extreme optimization from breaking OTA +target_compile_options(firmware PRIVATE -fno-tree-loop-distribute-patterns) diff --git a/tutorials/pico-sdk/w55rp20_evb_pico/Makefile b/tutorials/pico-sdk/w55rp20_evb_pico/Makefile new file mode 100644 index 00000000..986d5704 --- /dev/null +++ b/tutorials/pico-sdk/w55rp20_evb_pico/Makefile @@ -0,0 +1,53 @@ +# Environment setup: https://mongoose.ws/docs/getting-started/build-environment/ + +CWD ?= $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) +SDK_PATH ?= $(CWD)/pico-sdk +RM = rm -rf +MKBUILD = test -d build || mkdir build + +ifeq ($(OS),Windows_NT) + RM = cmd /C del /Q /F /S + MKBUILD = if not exist build mkdir build +endif + +.PHONY: build + +all build: build/firmware.uf2 + +build/firmware.uf2: pico_sdk_import.cmake mongoose.c mongoose.h + +pico_sdk_import.cmake: $(SDK_PATH) + cp $(SDK_PATH)/external/$@ $@ + +mongoose.c mongoose.h: + cp ../../../$@ . + +build/firmware.uf2: $(SDK_PATH) $(wildcard *.[ch]) CMakeLists.txt Makefile + $(MKBUILD) + cd build && PICO_SDK_PATH=$(SDK_PATH) cmake -G "Unix Makefiles" .. && make + +flash: build/firmware.uf2 + picotool load $< -f + +clean: + $(RM) build pico_sdk_import.cmake mongoose.c mongoose.h + +fullclean: clean + $(RM) $(SDK_PATH) + +$(SDK_PATH): + git clone -c advice.detachedHead=false --quiet --depth 1 -b 2.1.1 https://github.com/raspberrypi/pico-sdk $@ + cd $@ && git submodule update --quiet --init + +# Automated remote test. Requires env variable VCON_API_KEY set. See https://vcon.io/automated-firmware-tests/ +DEVICE_URL ?= https://dash.vcon.io/api/v3/devices/3 +# stdio has to be changed from USB to UART in CMakeLists.txt +update: + perl -pi -e 's/pico_enable_stdio_usb(firmware 1)/pico_enable_stdio_usb(firmware 0)/' CMakeLists.txt + $(MAKE) build + perl -pi -e 's/pico_enable_stdio_usb(firmware 0)/pico_enable_stdio_usb(firmware 1)/' CMakeLists.txt + curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/ota?uf2=1 --data-binary @build/firmware.uf2 + +test: update + curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=15 | tee /tmp/output.txt + grep 'READY, IP:' /tmp/output.txt # Check for network init diff --git a/tutorials/pico-sdk/w55rp20_evb_pico/main.c b/tutorials/pico-sdk/w55rp20_evb_pico/main.c new file mode 100644 index 00000000..f3773a8e --- /dev/null +++ b/tutorials/pico-sdk/w55rp20_evb_pico/main.c @@ -0,0 +1,205 @@ +// SPDX-FileCopyrightText: 2026 Cesanta Software Limited +// SPDX-License-Identifier: GPL-2.0-only or commercial + +#include "pico/stdlib.h" +#include "pico/unique_id.h" +#include "hardware/pio.h" + +#include "mongoose.h" + +#define SPIPIO pio0 +#define SPISM 0 +#define MOSIPIN 23 +#define MISOPIN 22 +#define CLKPIN 21 +#define CSPIN 20 +#define RSTPIN 25 + +#define USER_LED 19 + +#define piospi_wrap_target 0 +#define piospi_wrap 6 +#define piospi_pio_version 0 +#define piospi_offset_rx_ 7u + +static const uint16_t piospi_program_instructions[] = { + // .wrap_target + 0x80a0, // 0: pull block side 0 + 0xa027, // 1: mov x, osr side 0 + 0x6068, // 2: out null, 8 side 0 + 0x6001, // 3: out pins, 1 side 0 + 0x1043, // 4: jmp x--, 3 side 1 + 0xe000, // 5: set pins, 0 side 0 + 0xc020, // 6: irq wait 0 side 0 + // .wrap + 0x6020, // 7: out x, 32 side 0 + 0x5001, // 8: in pins, 1 side 1 + 0x0048, // 9: jmp x--, 8 side 0 + 0xc020, // 10: irq wait 0 side 0 + 0x0000, // 11: jmp 0 side 0 +}; + +static const struct pio_program piospi_program = { + .instructions = piospi_program_instructions, + .length = 12, + .origin = -1, + .pio_version = 0, +#if PICO_PIO_VERSION > 0 + .used_gpio_ranges = 0x0 +#endif +}; + +static pio_sm_config piospi_program_get_default_config(uint offset) { + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, offset + piospi_wrap_target, offset + piospi_wrap); + sm_config_set_sideset(&c, 1, false, false); + return c; +} + +static pio_sm_config piospi_init(PIO pio, uint sm, uint addr, uint mosi, uint miso, uint clk) { + pio_gpio_init(pio, mosi); + pio_gpio_init(pio, miso); + pio_gpio_init(pio, clk); + pio_sm_set_pins_with_mask(pio, sm, 0, (1 << mosi) | (1 << clk)); + pio_sm_config c = piospi_program_get_default_config(addr); + sm_config_set_out_pins(&c, mosi, 1); + sm_config_set_in_pins(&c, miso); + sm_config_set_set_pins(&c, mosi, 1); + sm_config_set_sideset_pins(&c, clk); + pio_sm_set_consecutive_pindirs(pio, sm, mosi, 1, true); + pio_sm_set_consecutive_pindirs(pio, sm, clk, 1, true); + pio_sm_set_pindirs_with_mask(pio, sm, (1 << mosi) | (1 << clk), (1 << mosi) | (1 << clk)); + sm_config_set_out_shift(&c, false, true, 8); // pull bytes, MSB first, auto + sm_config_set_in_shift(&c, false, true, 8); // push bytes, MSB first, auto +#if PICO_RP2040 + sm_config_set_clkdiv(&c, 10); // Run at <33.3MHz (2x data rate) +#else + sm_config_set_clkdiv(&c, 3); // Run at <33.3MHz (2x data rate) +#endif + return c; +} + +static void piospi_tx(PIO pio, uint sm, pio_sm_config *c, uint addr) { + sm_config_set_fifo_join(c, PIO_FIFO_JOIN_TX); + sm_config_set_out_shift(c, false, true, 8); // pull bytes, MSB first, auto + pio_sm_init(pio, sm, addr, c); +} + +static void piospi_rx(PIO pio, uint sm, pio_sm_config *c, uint addr) { + sm_config_set_fifo_join(c, PIO_FIFO_JOIN_NONE); + sm_config_set_out_shift(c, false, true, 32); // pull words, MSB first, auto + pio_sm_init(pio, sm, addr + piospi_offset_rx_, c); +} + +static void piospi_done(PIO pio, uint sm) { + while(!pio_interrupt_get(pio, 0)); + pio_sm_set_enabled(pio, sm, false); + pio_interrupt_clear(pio, 0); +} + +// Construct MAC address from the unique board ID +void genmac(unsigned char *mac) { + pico_unique_board_id_t board_id; + pico_get_unique_board_id(&board_id); + mac[0] = 2; + memcpy(&mac[1], &board_id.id[3], 5); +} + +static pio_sm_config s_piospi_sm_config; +static uint s_piospi_sm_addr; + +void ethernet_init(void) { + gpio_init(RSTPIN); + gpio_set_dir(RSTPIN, GPIO_OUT); + gpio_put(RSTPIN, 0); + gpio_init(CSPIN); + gpio_set_dir(CSPIN, GPIO_OUT); + gpio_put(CSPIN, 1); + s_piospi_sm_addr = pio_add_program(SPIPIO, &piospi_program); + s_piospi_sm_config = piospi_init(SPIPIO, SPISM, s_piospi_sm_addr, MOSIPIN, MISOPIN, CLKPIN); + mg_delayms(2); + gpio_put(RSTPIN, 1); +} + +// Hardware specific SPI support +static void piospi_write(uint8_t *data, size_t len) { + size_t initial_len = len; + piospi_tx(SPIPIO, SPISM, &s_piospi_sm_config, s_piospi_sm_addr); + __compiler_memory_barrier(); + pio_sm_put(SPIPIO, SPISM, (len * 8) - 1); // bits to transmit + pio_sm_set_enabled(SPIPIO, SPISM, true); + while (len--) pio_sm_put_blocking(SPIPIO, SPISM, (*data++) << 24); + piospi_done(SPIPIO, SPISM); +} + +// Read data block from SPI interface +static void piospi_read(uint8_t *data, size_t len) { + piospi_rx(SPIPIO, SPISM, &s_piospi_sm_config, s_piospi_sm_addr); + __compiler_memory_barrier(); + pio_sm_put(SPIPIO, SPISM, (len * 8) - 1); // bits to receive + pio_sm_set_enabled(SPIPIO, SPISM, true); + while (len--) *data++ = pio_sm_get_blocking(SPIPIO, SPISM); + piospi_done(SPIPIO, SPISM); +} + +void spi_begin(void *spi) { + (void) spi; + gpio_put(CSPIN, 0); +} + +void spi_end(void *spi) { + (void) spi; + gpio_put(CSPIN, 1); +} + +// either write or read, not both +void spi_txn(void *arg, uint8_t *txdata, uint8_t *rxdata, size_t len) { + if (txdata != NULL) piospi_write(txdata, len); + if (rxdata != NULL) piospi_read(rxdata, len); + (void) arg; +} + + +static void blink_task(void) { + static uint64_t timer; + if (mg_timer_expired(&timer, 500, mg_now())) { + gpio_put(USER_LED, !gpio_get(USER_LED)); + } +} + +static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { + if (ev == MG_EV_HTTP_MSG) { // New HTTP request received + struct mg_http_message *hm = (struct mg_http_message *) ev_data; + uint64_t tick = to_ms_since_boot(get_absolute_time()); + if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { + mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), tick); + } else { + mg_http_reply(c, 200, "", "Hi from Mongoose, tick %llu\n", tick); + } + } +} + +// In an RTOS environment, give this task 8 KB of stack space. +static void run_mongoose(void) { + struct mg_mgr mgr; + + mg_mgr_init(&mgr); + mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL); + + for (;;) { + mg_mgr_poll(&mgr, 1); + blink_task(); + } +} + +int main(void) { + stdio_init_all(); + gpio_init(USER_LED); // Initialise GPIO + gpio_set_dir(USER_LED, GPIO_OUT); // Set as output + gpio_put(USER_LED, 1); + ethernet_init(); + MG_INFO(("Hardware initialised, starting firmware...")); + + run_mongoose(); + return 0; +} diff --git a/tutorials/pico-sdk/w55rp20_evb_pico/mongoose_config.h b/tutorials/pico-sdk/w55rp20_evb_pico/mongoose_config.h new file mode 100644 index 00000000..ed9a9fea --- /dev/null +++ b/tutorials/pico-sdk/w55rp20_evb_pico/mongoose_config.h @@ -0,0 +1,48 @@ +#pragma once + +// See https://mongoose.ws/documentation/#build-options +#define MG_ARCH MG_ARCH_PICOSDK +#define MG_OTA MG_OTA_PICOSDK +#define MG_TLS MG_TLS_BUILTIN +#define MG_IO_SIZE 2048 + +#define MG_ENABLE_TCPIP 1 +#define MG_ENABLE_DRIVER_W5500 1 + +// For static IP configuration, define MG_TCPIP_{IP,MASK,GW} +// By default, those are set to zero, meaning that DHCP is used +// +// #define MG_TCPIP_IP MG_IPV4(192, 168, 1, 10) +// #define MG_TCPIP_GW MG_IPV4(192, 168, 1, 1) +// #define MG_TCPIP_MASK MG_IPV4(255, 255, 255, 0) + +// Set custom MAC address. By default, it is randomly generated +// Using a build-time constant: +// #define MG_SET_MAC_ADDRESS(mac) do { uint8_t buf_[6] = {2,3,4,5,6,7}; +// memmove(mac, buf_, sizeof(buf_)); } while (0) +// +// Using custom function: +extern void genmac(unsigned char *mac); +#define MG_SET_MAC_ADDRESS(mac) genmac(mac) + +// Hardware specific SPI support +#include +#include + +extern void spi_begin(void *); +extern void spi_end(void *); +extern void spi_txn(void *spi, uint8_t *tx, uint8_t *rx, size_t len); + +#define MG_TCPIP_DRIVER_INIT(mgr) \ + do { \ + static struct mg_tcpip_spi spi_ = {NULL, spi_begin, spi_end, spi_txn}; \ + static struct mg_tcpip_if mif_; \ + mif_.ip = MG_TCPIP_IP; \ + mif_.mask = MG_TCPIP_MASK; \ + mif_.gw = MG_TCPIP_GW; \ + mif_.driver = &mg_tcpip_driver_w5500; \ + mif_.driver_data = &spi_; \ + MG_SET_MAC_ADDRESS(mif_.mac); \ + mg_tcpip_init(mgr, &mif_); \ + MG_INFO(("Driver: W5500, MAC: %M", mg_print_mac, mif_.mac)); \ + } while (0)