mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-01 05:52:32 +07:00
RP boards
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
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)
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
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)
|
||||
Reference in New Issue
Block a user