diff --git a/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/CMakeLists.txt b/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/CMakeLists.txt new file mode 100644 index 00000000..e1c3597d --- /dev/null +++ b/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.13) +include(pico-sdk/pico_sdk_init.cmake) + +project(firmware) +pico_sdk_init() + +add_executable(firmware + main.c + mongoose.c +) + +target_include_directories(firmware PUBLIC + . +) + +target_link_libraries(firmware hardware_pio pico_stdlib pico_rand) +pico_add_extra_outputs(firmware) # create map/bin/hex file etc. + +pico_enable_stdio_usb(firmware 1) # Route stdio +pico_enable_stdio_uart(firmware 0) # to USB + +# Mongoose build flags in mongoose_config.h + +# Example build options diff --git a/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/Makefile b/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/Makefile new file mode 100644 index 00000000..ac6991c0 --- /dev/null +++ b/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/Makefile @@ -0,0 +1,23 @@ +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 + +all example: + true + +build build/firmware.uf2: pico-sdk main.c + $(MKBUILD) + cd build && cmake -G "Unix Makefiles" .. && make + +pico-sdk: + git clone --depth 1 -b 2.1.0 https://github.com/raspberrypi/pico-sdk $@ + cd $@ && git submodule update --init + +clean: + $(RM) pico-sdk build + +.PHONY: build + diff --git a/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/hal.h b/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/hal.h new file mode 100644 index 00000000..b7aae9cb --- /dev/null +++ b/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/hal.h @@ -0,0 +1,118 @@ +// Copyright (c) 2026 Cesanta Software Limited +// All rights reserved + +#include "pico/stdlib.h" +#include "hardware/pio.h" + +extern void mg_delayms(unsigned int ms); + +#define SPIPIO pio0 +#define SPISM 0 +#define MOSIPIN 23 +#define MISOPIN 22 +#define CLKPIN 21 +#define CSPIN 20 +#define RSTPIN 25 + +// Try it on a bare Pico ! +// #define MOSIPIN 3 +// #define MISOPIN 4 +// #define CLKPIN 2 +// #define CSPIN 5 + +#define piospi_wrap_target 0 +#define piospi_wrap 3 +#define piospi_pio_version 0 + +static const uint16_t piospi_program_instructions[] = { + // .wrap_target + 0xe027, // 0: set x, 7 side 0 + 0x6101, // 1: out pins, 1 side 0 [1] + 0x5001, // 2: in pins, 1 side 1 + 0x1041, // 3: jmp x--, 1 side 1 + // .wrap +}; + +static const struct pio_program piospi_program = { + .instructions = piospi_program_instructions, + .length = 4, + .origin = -1, + .pio_version = 0, +#if PICO_PIO_VERSION > 0 + .used_gpio_ranges = 0x0 +#endif +}; + +static inline 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 inline 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_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, 18); // Run at 133/1 = <33MHz (4x data rate) +#else + sm_config_set_clkdiv(&c, 20); // Run at 150/2 = <19MHz (4x data rate) +#endif + return c; +} + + +static pio_sm_config s_piospi_sm_config; +static uint s_piospi_sm_addr; + +uint8_t hwspecific_spi_txn(void *arg, uint8_t data) { + (void) arg; + pio_sm_put(SPIPIO, SPISM, data << 24); + return pio_sm_get_blocking(SPIPIO, SPISM); +} + +void hwspecific_spi_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); +} + +void hwspecific_spi_begin(void *arg) { + pio_sm_init(SPIPIO, SPISM, s_piospi_sm_addr, &s_piospi_sm_config); + pio_sm_set_enabled(SPIPIO, SPISM, true); + gpio_put(CSPIN, 0); + (void) arg; +} + +void hwspecific_spi_end(void *arg) { + gpio_put(CSPIN, 1); + pio_sm_set_enabled(SPIPIO, SPISM, false); + (void) arg; +} + + +// Construct MAC address from the unique board ID +#include "pico/unique_id.h" +static inline void hal_ethernet_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); +} diff --git a/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/main.c b/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/main.c new file mode 100644 index 00000000..eb1d03e4 --- /dev/null +++ b/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/main.c @@ -0,0 +1,43 @@ +// Copyright (c) 2025 Cesanta Software Limited +// All rights reserved + +#include "mongoose.h" +#include "hal.h" + + +static const struct mg_tcpip_spi spi = {NULL, hwspecific_spi_begin, hwspecific_spi_end, hwspecific_spi_txn}; + + +int main(void) { + // initialize stdio + stdio_init_all(); + + hwspecific_spi_init(); + + struct mg_mgr mgr; // Initialise Mongoose event manager + mg_mgr_init(&mgr); // and attach it to the interface + mg_log_set(MG_LL_DEBUG); // Set log level + + // Initialise Mongoose network stack + // Either set use_dhcp or enter a static config. + // For static configuration, specify IP/mask/GW in network byte order + struct mg_tcpip_if mif = { + .ip = 0, + .driver = &mg_tcpip_driver_w5500, + .driver_data = (void *) &spi + }; + + hal_ethernet_genmac(mif.mac); + mg_tcpip_init(&mgr, &mif); + MG_INFO(("Init done, starting main loop")); + + MG_INFO(("Initialising application...")); + + MG_INFO(("Starting event loop")); + for (;;) { + mg_mgr_poll(&mgr, 0); + } + + return 0; +} + diff --git a/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/mongoose.c b/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/mongoose.c new file mode 120000 index 00000000..5e522bbc --- /dev/null +++ b/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/mongoose.c @@ -0,0 +1 @@ +../../../mongoose.c \ No newline at end of file diff --git a/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/mongoose.h b/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/mongoose.h new file mode 120000 index 00000000..ee4ac823 --- /dev/null +++ b/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/mongoose.h @@ -0,0 +1 @@ +../../../mongoose.h \ No newline at end of file diff --git a/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/mongoose_config.h b/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/mongoose_config.h new file mode 100644 index 00000000..c8750e1d --- /dev/null +++ b/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/mongoose_config.h @@ -0,0 +1,6 @@ +#define MG_ARCH MG_ARCH_PICOSDK + +#define MG_ENABLE_TCPIP 1 +#define MG_ENABLE_DRIVER_W5500 1 +#define MG_ENABLE_TCPIP_DRIVER_INIT 0 +#define MG_ENABLE_PACKED_FS 1 diff --git a/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/pico_sdk_import.cmake b/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/pico_sdk_import.cmake new file mode 100644 index 00000000..a0721d0d --- /dev/null +++ b/tutorials/pico-sdk/w55rp20-evb-pico-picosdk-baremetal-builtin/pico_sdk_import.cmake @@ -0,0 +1,84 @@ +# This is a copy of /external/pico_sdk_import.cmake + +# This can be dropped into an external project to help locate this SDK +# It should be include()ed prior to project() + +if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH)) + set(PICO_SDK_PATH $ENV{PICO_SDK_PATH}) + message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT)) + set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT}) + message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH)) + set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH}) + message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')") +endif () + +if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG)) + set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG}) + message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')") +endif () + +if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG) + set(PICO_SDK_FETCH_FROM_GIT_TAG "master") + message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG") +endif() + +set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK") +set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable") +set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK") +set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK") + +if (NOT PICO_SDK_PATH) + if (PICO_SDK_FETCH_FROM_GIT) + include(FetchContent) + set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR}) + if (PICO_SDK_FETCH_FROM_GIT_PATH) + get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}") + endif () + # GIT_SUBMODULES_RECURSE was added in 3.17 + if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0") + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + GIT_SUBMODULES_RECURSE FALSE + ) + else () + FetchContent_Declare( + pico_sdk + GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk + GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG} + ) + endif () + + if (NOT pico_sdk) + message("Downloading Raspberry Pi Pico SDK") + FetchContent_Populate(pico_sdk) + set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) + endif () + set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE}) + else () + message(FATAL_ERROR + "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git." + ) + endif () +endif () + +get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") +if (NOT EXISTS ${PICO_SDK_PATH}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found") +endif () + +set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake) +if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE}) + message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK") +endif () + +set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE) + +include(${PICO_SDK_INIT_CMAKE_FILE})