From 7d94f9f61b23cbec209cbef9b5fa54dde00b25a3 Mon Sep 17 00:00:00 2001 From: "Sergio R. Caprile" Date: Mon, 24 Mar 2025 16:15:32 -0300 Subject: [PATCH] Add Pico + RM2 Wi-Fi example --- .../CMakeLists.txt | 24 +++ .../Makefile | 20 +++ .../rm2-pico-picosdk-baremetal-builtin/hal.h | 155 ++++++++++++++++++ .../rm2-pico-picosdk-baremetal-builtin/main.c | 151 +++++++++++++++++ .../mongoose.c | 1 + .../mongoose.h | 1 + .../mongoose_config.h | 6 + .../pico_sdk_import.cmake | 84 ++++++++++ 8 files changed, 442 insertions(+) create mode 100644 tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/CMakeLists.txt create mode 100644 tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/Makefile create mode 100644 tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/hal.h create mode 100644 tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/main.c create mode 120000 tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/mongoose.c create mode 120000 tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/mongoose.h create mode 100644 tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/mongoose_config.h create mode 100644 tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/pico_sdk_import.cmake diff --git a/tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/CMakeLists.txt b/tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/CMakeLists.txt new file mode 100644 index 00000000..e1c3597d --- /dev/null +++ b/tutorials/pico-sdk/rm2-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/rm2-pico-picosdk-baremetal-builtin/Makefile b/tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/Makefile new file mode 100644 index 00000000..369ccdef --- /dev/null +++ b/tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/Makefile @@ -0,0 +1,20 @@ +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 diff --git a/tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/hal.h b/tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/hal.h new file mode 100644 index 00000000..06dac6a6 --- /dev/null +++ b/tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/hal.h @@ -0,0 +1,155 @@ +// Copyright (c) 2025 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 DATAPIN 2 +#define CLKPIN 3 +#define CSPIN 1 +#define PWRPIN 0 + +#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 + 0xe080, // 7: set pindirs, 0 side 0 + 0x6020, // 8: out x, 32 side 0 + 0x4001, // 9: in pins, 1 side 0 + 0x1049, // 10: jmp x--, 9 side 1 + 0xe000, // 11: set pins, 0 side 0 + 0xe081, // 12: set pindirs, 1 side 0 + 0xc020, // 13: irq wait 0 side 0 + 0x0000, // 14: jmp 0 side 0 +}; + +static const struct pio_program piospi_program = { + .instructions = piospi_program_instructions, + .length = 15, + .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 data, uint clk) { + pio_gpio_init(pio, data); + pio_gpio_init(pio, clk); + pio_sm_set_pins_with_mask(pio, sm, 0, (1 << data) | (1 << clk)); + pio_sm_config c = piospi_program_get_default_config(addr); + sm_config_set_out_pins(&c, data, 1); + sm_config_set_in_pins(&c, data); + sm_config_set_set_pins(&c, data, 1); + sm_config_set_sideset_pins(&c, clk); + pio_sm_set_consecutive_pindirs(pio, sm, data, 1, true); + pio_sm_set_consecutive_pindirs(pio, sm, clk, 1, true); + pio_sm_set_pindirs_with_mask(pio, sm, (1 << data) | (1 << clk), (1 << data) | (1 << clk)); + 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 = <50MHz (2x data rate) +#else + sm_config_set_clkdiv(&c, 20); // Run at 150/1 = <50MHz (2x data rate) +#endif + return c; +} +static inline void piospi_tx(PIO pio, uint sm, pio_sm_config *c, uint addr, uint data) { + 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 inline void piospi_rx(PIO pio, uint sm, pio_sm_config *c, uint addr, uint data) { + 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 inline 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); +} + +static pio_sm_config s_piospi_sm_config; +static uint s_piospi_sm_addr; + +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, DATAPIN); + __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 +void piospi_read(uint8_t *data, size_t len) { + piospi_rx(SPIPIO, SPISM, &s_piospi_sm_config, s_piospi_sm_addr, DATAPIN); + __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 hwspecific_spi_init(void) { + gpio_init(PWRPIN); + gpio_set_dir(PWRPIN, GPIO_OUT); + gpio_put(PWRPIN, 0); + gpio_init(CSPIN); + gpio_set_dir(CSPIN, GPIO_OUT); + gpio_put(CSPIN, 0); + // init SPI pins so they are idle and stable during power up + gpio_init(DATAPIN); + gpio_set_dir(DATAPIN, GPIO_OUT); + gpio_put(DATAPIN, 0); + gpio_init(CLKPIN); + gpio_set_dir(CLKPIN, GPIO_OUT); + gpio_put(CLKPIN, 0); + mg_delayms(100); + gpio_put(CSPIN, 1); + gpio_put(PWRPIN, 1); + s_piospi_sm_addr = pio_add_program(SPIPIO, &piospi_program); + s_piospi_sm_config = piospi_init(SPIPIO, SPISM, s_piospi_sm_addr, DATAPIN, CLKPIN); + mg_delayms(50); +} + +void hwspecific_spi_begin(void *arg) { + gpio_put(CSPIN, 0); + (void) arg; +} + +// either write or read, not both +void hwspecific_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; +} + +void hwspecific_spi_end(void *arg) { + gpio_put(CSPIN, 1); + (void) arg; +} diff --git a/tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/main.c b/tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/main.c new file mode 100644 index 00000000..fefdf17d --- /dev/null +++ b/tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/main.c @@ -0,0 +1,151 @@ +// Copyright (c) 2025 Cesanta Software Limited +// All rights reserved + +#include "mongoose.h" +#include "hal.h" + + +#define WIFI_SSID "YOUR_WIFI_NETWORK_NAME" // SET THIS! +#define WIFI_PASS "YOUR_WIFI_PASSWORD" // SET THIS! + + +static const struct mg_tcpip_spi_ spi = {NULL, hwspecific_spi_begin, hwspecific_spi_end, hwspecific_spi_txn}; + +#ifndef CYW43_RESOURCE_ATTRIBUTE +#define CYW43_RESOURCE_ATTRIBUTE +#endif +#include "pico-sdk/lib/cyw43-driver/firmware/w43439A0_7_95_49_00_combined.h" +#include "pico-sdk/lib/cyw43-driver/firmware/wifi_nvram_43439.h" +static const struct mg_tcpip_driver_cyw_firmware fw = { + (const uint8_t *)w43439A0_7_95_49_00_combined, (size_t)CYW43_WIFI_FW_LEN, + (const uint8_t *)wifi_nvram_4343, (size_t)sizeof(wifi_nvram_4343), + (const uint8_t *)(w43439A0_7_95_49_00_combined + sizeof(w43439A0_7_95_49_00_combined) - CYW43_CLM_LEN), (size_t)CYW43_CLM_LEN}; + +// mif user states +enum {AP, SCANNING, STOPPING_AP, CONNECTING, READY}; +static unsigned int state; +static uint32_t s_ip, s_mask; + + +static void mif_fn(struct mg_tcpip_if *ifp, int ev, void *ev_data) { + // TODO(): should we include this inside ifp ? add an fn_data ? + if (ev == MG_TCPIP_EV_ST_CHG) { + MG_INFO(("State change: %u", *(uint8_t *) ev_data)); + } + switch(state) { + case AP: // we are in AP mode, wait for a user connection to trigger a scan or a connection to a network + if (ev == MG_TCPIP_EV_ST_CHG && *(uint8_t *) ev_data == MG_TCPIP_STATE_UP) { + MG_INFO(("Access Point started")); + s_ip = ifp->ip, ifp->ip = MG_IPV4(192, 168, 169, 1); + s_mask = ifp->mask, ifp->mask = MG_IPV4(255, 255, 255, 0); + ifp->enable_dhcp_client = false; + ifp->enable_dhcp_server = true; + } else if (ev == MG_TCPIP_EV_ST_CHG && *(uint8_t *) ev_data == MG_TCPIP_STATE_READY) { + MG_INFO(("Access Point READY !")); + + // simulate user request to scan for networks + bool res = mg_wifi_scan(); + MG_INFO(("Starting scan: %s", res ? "OK":"FAIL")); + if (res) state = SCANNING; + } + break; + case SCANNING: + if (ev == MG_TCPIP_EV_WIFI_SCAN_RESULT) { + struct mg_wifi_scan_bss_data *bss = (struct mg_wifi_scan_bss_data *) ev_data; + MG_INFO(("BSS: %.*s (%u) (%M) %d dBm %u", bss->SSID.len, bss->SSID.buf, bss->channel, mg_print_mac, bss->BSSID, (int) bss->RSSI, bss->security)); + } else if (ev == MG_TCPIP_EV_WIFI_SCAN_END) { + struct mg_tcpip_driver_cyw_data *d = (struct mg_tcpip_driver_cyw_data *) ifp->driver_data; + MG_INFO(("Wi-Fi scan finished")); + + // simulate user selection of a network (1/2: stop AP) + bool res = mg_wifi_ap_stop(); + MG_INFO(("Manually stopping AP: %s", res ? "OK":"FAIL")); + if (res) state = STOPPING_AP; + // else we have a hw/fw problem + } + break; + case STOPPING_AP: + if (ev == MG_TCPIP_EV_ST_CHG && *(uint8_t *) ev_data == MG_TCPIP_STATE_DOWN) { + struct mg_tcpip_driver_cyw_data *d = (struct mg_tcpip_driver_cyw_data *) ifp->driver_data; + d->apmode = false; + + // simulate user selection of a network (2/2: actual connect) + bool res = mg_wifi_connect(d->ssid, d->pass); + MG_INFO(("Manually connecting: %s", res ? "OK":"FAIL")); + if (res) { + state = CONNECTING; + ifp->ip = s_ip; + ifp->mask = s_mask; + if (ifp->ip == 0) ifp->enable_dhcp_client = true; + ifp->enable_dhcp_server = false; + } // else manually start AP as below + } + break; + case CONNECTING: + if (ev == MG_TCPIP_EV_ST_CHG && *(uint8_t *) ev_data == MG_TCPIP_STATE_READY) { + MG_INFO(("READY!")); + state = READY; + + // simulate user code disconnection and go back to AP mode (1/2: disconnect) + bool res = mg_wifi_disconnect(); + MG_INFO(("Manually disconnecting: %s", res ? "OK":"FAIL")); + } else if (ev == MG_TCPIP_EV_WIFI_CONNECT_ERR) { + MG_ERROR(("Wi-Fi connect failed")); + // manually start AP as below + } + break; + case READY: + // go back to AP mode after a disconnection (simulation 2/2), you could retry + if (ev == MG_TCPIP_EV_ST_CHG && *(uint8_t *) ev_data == MG_TCPIP_STATE_DOWN) { + struct mg_tcpip_driver_cyw_data *d = (struct mg_tcpip_driver_cyw_data *) ifp->driver_data; + bool res = mg_wifi_ap_start(d->apssid, d->appass, d->apchannel); + MG_INFO(("Disconnected")); + MG_INFO(("Manually starting AP: %s", res ? "OK":"FAIL")); + if (res) { + state = AP; + d->apmode = true; + } + } + break; + } +} + + +static struct mg_tcpip_driver_cyw_data d = { + (struct mg_tcpip_spi_ *)&spi, (struct mg_tcpip_driver_cyw_firmware *)&fw, WIFI_SSID, WIFI_PASS, "mongoose", "mongoose", 0, 0, 10, true}; + +int main(void) { + // initialize stdio + stdio_init_all(); + + hwspecific_spi_init(); + + state = d.apmode ? AP : CONNECTING; + + 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 = (struct mg_tcpip_driver *)&mg_tcpip_driver_cyw, + .driver_data = (struct mg_tcpip_driver_cyw_data*)&d, + .fn = mif_fn, +// .recv_queue.size = 8192 + }; + + 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/rm2-pico-picosdk-baremetal-builtin/mongoose.c b/tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/mongoose.c new file mode 120000 index 00000000..5e522bbc --- /dev/null +++ b/tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/mongoose.c @@ -0,0 +1 @@ +../../../mongoose.c \ No newline at end of file diff --git a/tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/mongoose.h b/tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/mongoose.h new file mode 120000 index 00000000..ee4ac823 --- /dev/null +++ b/tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/mongoose.h @@ -0,0 +1 @@ +../../../mongoose.h \ No newline at end of file diff --git a/tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/mongoose_config.h b/tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/mongoose_config.h new file mode 100644 index 00000000..fafc6aa2 --- /dev/null +++ b/tutorials/pico-sdk/rm2-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_CYW 1 +#define MG_ENABLE_TCPIP_DRIVER_INIT 0 +#define MG_ENABLE_PACKED_FS 1 diff --git a/tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/pico_sdk_import.cmake b/tutorials/pico-sdk/rm2-pico-picosdk-baremetal-builtin/pico_sdk_import.cmake new file mode 100644 index 00000000..a0721d0d --- /dev/null +++ b/tutorials/pico-sdk/rm2-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})