Compare commits

..
18 Commits
Author SHA1 Message Date
Sergio R. Caprile b766c65615 avoid 802.15.4 using a standard BSD function name, enable BSD test after mg_error() fix 2026-10-23 14:00:24 -03:00
cpq 8296b88fb6 Update readme 2026-10-23 15:21:10 +01:00
Sergio R. Caprile a5efbf0592 misc cleanups and standardizations 2026-10-22 16:53:56 -03:00
Sergio R. Caprile 37c98dd893 mg_delay_ms() survives mg_millis() restarting on some 32-bit platforms 2026-10-22 13:49:21 -03:00
cpq 770a4ff27e Sync description 2026-10-22 17:21:05 +01:00
Sergio R. Caprile b6560306ba avoid reconnect timer being disrupted by possible SNTP updates 2026-10-22 12:12:27 -03:00
Sergio R. Caprile 5b39c93478 Merge pull request #3746 from cesanta/ota
Make mg_http_ota_cb public, add /ota endpoints to MCU examples
2026-10-22 11:30:35 -03:00
cpq 086008b716 Nit 2026-10-22 14:55:19 +01:00
cpq 35eb50a1e6 Nit 2026-10-22 14:46:19 +01:00
cpq 431e35ae8c Update README 2026-10-22 14:44:50 +01:00
cpq 25e2a99d8e Make mg_http_ota_cb public, add /ota endpoints to MCU examples 2026-10-22 14:30:10 +01:00
cpq 88b01ef6f0 Add security.md 2026-10-21 11:48:41 +01:00
cpq bd8ee86f9e Cube pack 7.23.3 2026-10-21 11:33:05 +01:00
Sergey Lyubka ef96f7a28c Merge pull request #3741 from cesanta/w71_2
Ethernet + IPv4 over 802.15.4 + bridge, mcxw71 and rw612
2026-10-21 10:22:43 +01:00
Sergey Lyubka 03f240a244 Merge pull request #3743 from cesanta/c5
Add nucleo-c5a3zg
2026-10-21 10:21:25 +01:00
cpq c775f31ca7 Add nucleo-c5a3zg 2026-10-21 10:16:02 +01:00
cpq 1ca4fd1fef Add frdm-mcxw71 support 2026-10-20 21:48:34 +01:00
cpq a6b6a0d779 Add frdm-mcxw71 support 2026-10-19 14:10:48 +01:00
267 changed files with 9387 additions and 248078 deletions

No files matched your search

+8 -4
View File
@@ -1,8 +1,12 @@
# Mongoose - Embedded Network Library # Mongoose: a full-stack embedded networking library
Mongoose is a full-stack embedded networking library for C/C++: a TCP/IP stack
with drivers, TLS 1.3, an embedded web server (HTTP, WebSocket), MQTT and
firmware OTA updates in two files, `mongoose.c` and `mongoose.h`. Mongoose runs on
STM32, NXP and other microcontrollers, on bare metal or with an RTOS, with no
external dependencies. Use it for cloud connectivity, device web dashboards,
secure firmware updates and remote control.
Mongoose is an open source, two-file C networking library and embedded web server for
microcontrollers that combines TCP/IP stack, HTTP, WebSocket, MQTT, TLS 1.3
stack, built-in firmware OTA updates, and device-dashboard infrastructure.
License: GPLv2 or commercial. License: GPLv2 or commercial.
Website: https://mongoose.ws/ Website: https://mongoose.ws/
GitHub repo: https://github.com/cesanta/mongoose GitHub repo: https://github.com/cesanta/mongoose
+51 -27
View File
@@ -1,4 +1,4 @@
# Mongoose - Embedded Web Server / Embedded Network Library # Mongoose: a full-stack embedded networking library
[![License: GPLv2/Commercial](https://img.shields.io/badge/License-GPLv2%20or%20Commercial-green.svg)](https://opensource.org/licenses/gpl-2.0.php) [![License: GPLv2/Commercial](https://img.shields.io/badge/License-GPLv2%20or%20Commercial-green.svg)](https://opensource.org/licenses/gpl-2.0.php)
[![Build Status]( https://github.com/cesanta/mongoose/actions/workflows/quicktest.yml/badge.svg)](https://github.com/cesanta/mongoose/actions) [![Build Status]( https://github.com/cesanta/mongoose/actions/workflows/quicktest.yml/badge.svg)](https://github.com/cesanta/mongoose/actions)
@@ -7,11 +7,17 @@
<img src="https://mongoose.ws/images/logo.svg" width="48" height="48" <img src="https://mongoose.ws/images/logo.svg" width="48" height="48"
align="left" style="float:left;" /> align="left" style="float:left;" />
Two files. Drop `mongoose.c` and `mongoose.h` into any C/C++ project and get a Mongoose is a full-stack embedded networking library for C/C++: a TCP/IP stack
full network stack — HTTP, WebSocket, MQTT, TLS, firmware OTA with drivers, TLS 1.3, an embedded web server (HTTP, WebSocket), MQTT and
updates, device dashboard — on any microcontroller or desktop OS. firmware OTA updates in two files, `mongoose.c` and `mongoose.h`. Mongoose runs on
STM32, NXP and other microcontrollers, on bare metal or with an RTOS, with no
external dependencies. Use it for cloud connectivity, device web dashboards,
secure firmware updates and remote control.
On the market since 2004, used by vast number of open source and commercial Use it instead of lwIP + mbedTLS + httpd + an MQTT client + OTA glue code, or
run it on top of lwIP or Zephyr.
On the market since 2004, used by a vast number of open source and commercial
products - it even runs on the International Space Station! Features include: products - it even runs on the International Space Station! Features include:
- Cross-platform: - Cross-platform:
@@ -24,7 +30,7 @@ products - it even runs on the International Space Station! Features include:
- Source code is both ISO C and ISO C++ compliant - Source code is both ISO C and ISO C++ compliant
- Very easy to integrate - Very easy to integrate
- Own TCP/IP stack for bare metal / RTOS, or run on top of any existing one (lwIP, Zephyr, ...) - Own TCP/IP stack for bare metal / RTOS, or run on top of any existing one (lwIP, Zephyr, ...)
- Built-in TLS 1.3 ECC stack. Also can use external TLS libraries - mbedTLS, OpenSSL, or other - Built-in TLS 1.3 stack. Also can use external TLS libraries - mbedTLS, OpenSSL, or other
- Does not depend on any other software to implement networking - Does not depend on any other software to implement networking
- Built-in firmware updates for STM32 H5, STM32 H7, NXP IMXRT, RP2040/2350, ESP32 and more - Built-in firmware updates for STM32 H5, STM32 H7, NXP IMXRT, RP2040/2350, ESP32 and more
- Commercial support with proactive security updates; [CRA-compliant](https://mongoose.ws/security/cra-compliance/) - Commercial support with proactive security updates; [CRA-compliant](https://mongoose.ws/security/cra-compliance/)
@@ -35,8 +41,32 @@ See https://mongoose.ws/ for complete documentation, videos, case studies, etc.
## Supported platforms ## Supported platforms
Mongoose can work on top of any TCP/IP stack that supports BSD sockets API. Mongoose has its own built-in TCP/IP stack with drivers, so it needs no
Platforms supported by the 3rd party TCP/IP stacks: additional software to implement networking. The built-in stack runs on bare
metal and under any RTOS. Platforms supported by the Mongoose built-in TCP/IP
stack:
| MCU | Connectivity | Notes |
| :-- | :----------- | :---- |
| **STM32** | Built-in Ethernet | Ethernet-capable STM32F, STM32H5, STM32H7, STM32N6, STM32C5 variants |
| **NXP i.MX RT** | Built-in Ethernet | RT102x, RT104x, RT105x, RT106x, RT117x, RT118x (NETC) |
| **NXP MCX** | Built-in Ethernet | MCXN94x, MCXE247 |
| **NXP RW612** | Eth, WiFi, 802.15.4 | Separate Ethernet and radio drivers |
| **Microchip ATSAME54** | Built-in Ethernet | GMAC driver |
| **Renesas RA** | Built-in Ethernet | RA6M, RA8M |
| **Infineon XMC** | Built-in Ethernet | XMC4, XMC7 |
| **Texas Instruments** | Built-in Ethernet | TM4C, TMS570 |
| **RP2040, RP2350, STM32, others** | CYW43xx Wi-Fi chips | SPI or SDIO; Pico W, Pico 2 W, Pico RM2, Arduino Portenta H7 |
| **STM32, others** | ST67W6 Wi-Fi modules | SPI; for example, STM32U5 with the ST67W611M1 module |
| **MCUs with an NXP Wi-Fi SDK port** | NXP Wi-Fi | Requires the SDK's Wi-Fi port implementing the driver's network hooks |
| **NXP MCXW71** | Built-in 802.15.4 radio | IPv4 over IEEE 802.15.4 |
| **NXP RW612** | Built-in 802.15.4 radio | IPv4 over IEEE 802.15.4; requires NXP radio firmware |
| **Any MCU with SPI** | W5500 or W5100 Ethernet chips | External Wiznet MAC+PHY |
| **MCUs connected to a cellular modem** | Cellular | AT commands and PPP; for example, SIM800 |
| **MCUs with CMSIS Ethernet drivers** | Ethernet via CMSIS-Driver | Requires CMSIS Ethernet MAC and PHY drivers |
Mongoose can also run on top of any TCP/IP stack that supports the BSD
sockets API. Platforms supported via 3rd party TCP/IP stacks:
| TCP/IP stack | Notes | | TCP/IP stack | Notes |
| :-------------- | :------- | | :-------------- | :------- |
@@ -45,23 +75,6 @@ Platforms supported by the 3rd party TCP/IP stacks:
| **Other** | Any other TCP/IP stack that supports BSD socket API, for example Amazon FreeRTOS-TCP | | **Other** | Any other TCP/IP stack that supports BSD socket API, for example Amazon FreeRTOS-TCP |
| **Linux, Mac, Windows** | Workstations, server, single board computers, embedded Linux devices running on MPUs or FPGAs | | **Linux, Mac, Windows** | Workstations, server, single board computers, embedded Linux devices running on MPUs or FPGAs |
Optionally, Mongoose provides its own built-in TCP/IP stack, eliminating the
need for additional software to implement networking functionality. The
built-in stack supports operation in both bare-metal and RTOS environments.
Platforms supported by the Mongoose built-in TCP/IP stack:
| Hardware | Notes |
| :------------- | :------- |
| **STM32** | All STM32 MCUs with built-in Ethernet: STM32Fxx, STM32H5xx, STM32H7xx |
| **NXP** | All NXP MCUs with built-in Ethernet: IMXRT102x, IMXRT104x, IMXRT105x, IMXRT106x, IMXRT117x, RW612, MCXN94x |
| **Microchip** | ATSAME54 MCUs with built-int Ethernet |
| **Renesas** | RA5M, RA6M, RA8M MCUs with built-in Ethernet |
| **Infineon** | XMC4, XMC7 MCUs with built-in Ethernet |
| **Texas Instruments** | TM4C, TMS570 MCUs with built-in Ethernet |
| **Cypress WiFi** | Any MCU with CY43xx WiFi chips, like RP2040 Pico-W, RP2350 Pico2-W, Arduino Portenta |
| **Wiznet Ethernet** | Any MCU that use Wiznet W5500 or Wiznet 5100 MAC+PHY chips |
| **Cellular** | NRF9160, SIM800 |
## Usage Examples ## Usage Examples
Below are quick snippets that should give an idea how simple the API is and Below are quick snippets that should give an idea how simple the API is and
@@ -158,6 +171,17 @@ int main() {
} }
``` ```
## Licensing
Mongoose is dual-licensed:
- GPLv2: free for open source projects. Many popular open source projects use
Mongoose, for example
[SWUpdate](https://github.com/sbabic/swupdate/tree/master/mongoose), the
embedded Linux update framework
- Commercial: for closed-source products. Includes support directly from the
engineers who wrote the whole stack, and early security fixes.
See [licensing](https://mongoose.ws/licensing/)
## Commercial use ## Commercial use
- Mongoose is used by hundreds of businesses, from Fortune500 giants like - Mongoose is used by hundreds of businesses, from Fortune500 giants like
Siemens, Schneider Electric, Broadcom, Bosch, Google, Samsung, Qualcomm, Caterpillar to the small businesses Siemens, Schneider Electric, Broadcom, Bosch, Google, Samsung, Qualcomm, Caterpillar to the small businesses
@@ -222,12 +246,12 @@ Technical guides and deep dives into embedded web servers, WebUI integration and
- [lwIP vs Mongoose - TCP/IP Stack Integration Benchmark](https://mongoose.ws/articles/lwip-vs-mongoose-tcpip-stack-integration/) - [lwIP vs Mongoose - TCP/IP Stack Integration Benchmark](https://mongoose.ws/articles/lwip-vs-mongoose-tcpip-stack-integration/)
- [Embedded TCP/IP Stacks Comparison](https://mongoose.ws/embedded-tcpip-stack-comparison/) - [Embedded TCP/IP Stacks Comparison](https://mongoose.ws/embedded-tcpip-stack-comparison/)
- [STM32H5 File System on Internal Flash: LittleFS + Mongoose](https://mongoose.ws/articles/stm32h5-file-system-on-internal-flash/) - [STM32H5 File System on Internal Flash: LittleFS + Mongoose](https://mongoose.ws/articles/stm32h5-file-system-on-internal-flash/)
- [Firmware OTA and remote control on NXP FRDM-RW612](https://mongoose.ws/articles/mdash/) - [Firmware OTA and remote control on NXP FRDM-RW612](https://mongoose.ws/articles/rw612-mdash/)
- [25000 WebSocket messages per second on STM32 Nucleo-H723ZG](https://mongoose.ws/articles/stm32-websocket-benchmark/) - [25000 WebSocket messages per second on STM32 Nucleo-H723ZG](https://mongoose.ws/articles/stm32-websocket-benchmark/)
- [How to connect STM32 to AWS IoT Core](https://mongoose.ws/articles/stm32-aws-iot/) - [How to connect STM32 to AWS IoT Core](https://mongoose.ws/articles/stm32-aws-iot/)
- [How to connect STM32 to Azure IoT Hub](https://mongoose.ws/articles/stm32-azure-iot-hub/) - [How to connect STM32 to Azure IoT Hub](https://mongoose.ws/articles/stm32-azure-iot-hub/)
- [How to connect STM32 to EMQX](https://mongoose.ws/articles/stm32-emqx/) - [How to connect STM32 to EMQX](https://mongoose.ws/articles/stm32-emqx/)
- [STM32 Device Management deep dive: Secure OTA, Remote Control, health monitor](https://mongoose.ws/articles/stm32-mdash-deep-dive/") - [STM32 Device Management deep dive: Secure OTA, Remote Control, health monitor](https://mongoose.ws/articles/stm32-mdash-deep-dive/)
- [STM32 TCP/IP footprint: how much flash and RAM does Mongoose take?](https://mongoose.ws/articles/tcp-ip-footprint/) - [STM32 TCP/IP footprint: how much flash and RAM does Mongoose take?](https://mongoose.ws/articles/tcp-ip-footprint/)
+41
View File
@@ -0,0 +1,41 @@
# Security Policy
Mongoose is a full-stack embedded networking library by Cesanta Software Ltd,
<https://mongoose.ws>. This policy covers how to report vulnerabilities
and how Cesanta handles them.
## Supported versions
Security fixes go to the `master` branch and the latest release.
## Reporting a vulnerability
Do not report security issues in public GitHub issues. Report them
privately using GitHub Security Advisories:
<https://github.com/cesanta/mongoose/security/advisories/new>
Include the Mongoose version or commit, steps or a proof of concept to reproduce, and
the impact. Cesanta usually responds the same business day.
## Disclosure process
1. Cesanta reviews the report and coordinates a fix with the reporter.
2. Eligible commercial customers receive a notification and a private fix
one month before the CVE becomes public.
3. The fix and the CVE are then published. The reporter is credited in the
GitHub Security Advisory.
## Security testing
- CI on every push, unit tests built with ASAN and UBSan
- CodeQL static analysis on every commit
- Continuous fuzzing on OSS-Fuzz, plus nightly libFuzzer runs
- AI-assisted security review on every pull request
- Regular review by independent security research groups worldwide
## EU Cyber Resilience Act (CRA)
Mongoose supports CRA compliance for connected products: a documented
vulnerability handling process (this file), TLS 1.3, signed OTA firmware
updates, and an SBOM (`sbom.cdx.json`). Details:
<https://mongoose.ws/security/cra-compliance/>
+923 -71
View File
File diff suppressed because it is too large. Load diff
+136 -96
View File
@@ -165,6 +165,7 @@ extern "C" {
#if MG_ENABLE_TCPIP && !defined(MG_ENABLE_DRIVER_STM32F) && \ #if MG_ENABLE_TCPIP && !defined(MG_ENABLE_DRIVER_STM32F) && \
!defined(MG_ENABLE_DRIVER_STM32H) && !defined(MG_ENABLE_DRIVER_STM32N) && \ !defined(MG_ENABLE_DRIVER_STM32H) && !defined(MG_ENABLE_DRIVER_STM32N) && \
!defined(MG_ENABLE_DRIVER_STM32C) && \
!defined(MG_ENABLE_DRIVER_CYW) && !defined(MG_ENABLE_DRIVER_CYW_SDIO) && \ !defined(MG_ENABLE_DRIVER_CYW) && !defined(MG_ENABLE_DRIVER_CYW_SDIO) && \
!defined(MG_ENABLE_DRIVER_ST67W6) !defined(MG_ENABLE_DRIVER_ST67W6)
#if defined(STM32F1) || defined(STM32F2) || defined(STM32F4) || defined(STM32F7) #if defined(STM32F1) || defined(STM32F2) || defined(STM32F4) || defined(STM32F7)
@@ -173,6 +174,8 @@ extern "C" {
#define MG_ENABLE_DRIVER_STM32H 1 #define MG_ENABLE_DRIVER_STM32H 1
#elif defined(STM32N6) #elif defined(STM32N6)
#define MG_ENABLE_DRIVER_STM32N 1 #define MG_ENABLE_DRIVER_STM32N 1
#elif defined(STM32C5)
#define MG_ENABLE_DRIVER_STM32C 1
#else #else
#error Select a driver in mongoose_config.h #error Select a driver in mongoose_config.h
#endif #endif
@@ -189,70 +192,8 @@ extern "C" {
#define MG_OTA MG_OTA_STM32H5 #define MG_OTA MG_OTA_STM32H5
#elif !defined(MG_OTA) && defined(STM32H7) #elif !defined(MG_OTA) && defined(STM32H7)
#define MG_OTA MG_OTA_STM32H7 #define MG_OTA MG_OTA_STM32H7
#endif #elif !defined(MG_OTA) && defined(STM32C5)
#define MG_OTA MG_OTA_STM32C5
// OTA rollback timer via IWDG. Fixed 10 s hang-detection window (prescaler
// /1024, LSI ~32 kHz: reload = 10 * 32000 / 1024 = 312). mg_ota_poll() feeds
// the watchdog every 500 ms while in MG_OTA_TESTING state; if the event loop
// hangs for 10 s, the IWDG fires and the device rolls back.
// STM32H7 names the peripheral IWDG1; all others use IWDG.
// The total evaluation period is set by MG_OTA_ROLLBACK_TIMEOUT_SECONDS.
// STM32H7 names the watchdog peripheral IWDG1; all other families use IWDG.
#if defined(IWDG1) && !defined(IWDG)
#define MG_IWDG IWDG1
#else
#define MG_IWDG IWDG
#endif
// PR=6 → /256 prescaler, RLR=1250 → ~10 s at LSI 32 kHz.
// Works on F4/F7/H5/H7; uses direct register writes so it is safe before HAL_Init().
#ifndef MG_OTA_ROLLBACK_TIMER_START
#define MG_OTA_ROLLBACK_TIMER_START() \
do { \
MG_IWDG->KR = 0xCCCCU; /* start + LSI */ \
MG_IWDG->KR = 0x5555U; /* unlock PR/RLR */ \
MG_IWDG->PR = 6U; /* /256 */ \
MG_IWDG->RLR = 1250U; /* 10 s */ \
while (MG_IWDG->SR & (IWDG_SR_PVU | IWDG_SR_RVU)) (void) 0; \
MG_IWDG->KR = 0xAAAAU; /* reload */ \
} while (0)
#endif
// Feed (reload) the IWDG. Called from mg_ota_poll() every 500 ms.
#ifndef MG_OTA_ROLLBACK_TIMER_FEED
#define MG_OTA_ROLLBACK_TIMER_FEED() (MG_IWDG->KR = 0xAAAAU)
#endif
// OTA state in a backup register that survives warm resets but clears on POR.
// STATE_GET reads work without any setup. STATE_SET enables the RTC APB clock
// and unlocks backup domain write access via direct register writes, so it is
// safe to call from any context (before or after HAL_Init).
// H5 (TAMP->BKP0R), H7 (RTC->BKP0R), F4/F7 (RTC->BKP0R).
#ifndef MG_OTA_STATE_GET
#if defined(PWR_DBPCR_DBP)
#define MG_OTA_DBP_ENABLE() (PWR->DBPCR |= PWR_DBPCR_DBP)
#elif defined(PWR_CR1_DBP)
#define MG_OTA_DBP_ENABLE() (PWR->CR1 |= PWR_CR1_DBP)
#else
#define MG_OTA_DBP_ENABLE() (PWR->CR |= PWR_CR_DBP)
#endif
#if defined(TAMP)
#define MG_OTA_STATE_GET() \
(RCC->APB3ENR |= RCC_APB3ENR_RTCAPBEN, TAMP->BKP0R)
#define MG_OTA_STATE_SET(v) \
(RCC->APB3ENR |= RCC_APB3ENR_RTCAPBEN, MG_OTA_DBP_ENABLE(), \
(TAMP->BKP0R = (uint32_t) (v)), TAMP->BKP0R)
#elif defined(RCC_APB4ENR_RTCAPBEN)
#define MG_OTA_STATE_GET() (RTC->BKP0R)
#define MG_OTA_STATE_SET(v) \
(RCC->APB4ENR |= RCC_APB4ENR_RTCAPBEN, MG_OTA_DBP_ENABLE(), \
(RTC->BKP0R = (uint32_t) (v)))
#else
#define MG_OTA_STATE_GET() (RTC->BKP0R)
#define MG_OTA_STATE_SET(v) \
(RCC->APB1ENR |= RCC_APB1ENR_PWREN, MG_OTA_DBP_ENABLE(), \
(RTC->BKP0R = (uint32_t) (v)))
#endif
#endif #endif
// use HAL-defined execute-in-ram section // use HAL-defined execute-in-ram section
@@ -2783,29 +2724,32 @@ int mg_http_status(const struct mg_http_message *hm);
// Streams a POST/PUT body to a callback as it arrives, without buffering it. // Streams a POST/PUT body to a callback as it arrives, without buffering it.
// Call it from an MG_EV_HTTP_HDRS handler, after matching the request, e.g. // Call it from an MG_EV_HTTP_HDRS handler, after matching the request, e.g.
// with mg_match(). Returns true if it took over the connection, false if the // with mg_match(). Always takes over the connection. Invalid requests receive
// request is not POST/PUT, is chunked, or has no Content-Length. // an HTTP error; client-side failures call mg_error(). Replies and connection
// draining are handled internally, including callback failures.
// //
// Callback upload_fn(hm, data, user_data) is called: // Callback upload_fn(hm, data, user_data) is called:
// - at start: hm is set. Open the file, set *user_data. // - at start: hm is set. Open the file, set *user_data.
// - per chunk: data is set, 512 byte aligned except the last. Not called // - per chunk: data is set, 512 byte aligned except the last. Not called
// again after a failure. // again after a failure.
// - at end: both NULL. Always called once, also when the connection drops // - at end: both NULL. Always called exactly once, including validation
// early, so release resources here. A truncated body looks like a complete // failures before start and connections that drop early. Release resources
// one: validate before committing. // here. A truncated body looks like a complete one: validate before
// Return true on success, false on error. // committing.
// The callback returns true on success, false on error. A failure stops
// streaming immediately and calls the end callback before closing.
// Example: // Example:
// if (ev == MG_EV_HTTP_HDRS && mg_match(hm->uri, mg_str("/fs/*"), NULL) { // if (ev == MG_EV_HTTP_HDRS && mg_match(hm->uri, mg_str("/fs/*"), NULL)) {
// mg_http_stream_body(c, hm, upload, NULL)); // mg_http_stream_body(c, hm, upload, NULL);
// } // }
// Full example: // Full example:
// tutorials/http/file-upload-single-post // tutorials/http/file-upload-single-post
// Related APIs: // Related APIs:
// mg_http_listen(), mg_http_next_multipart() // mg_http_listen(), mg_http_next_multipart()
// Notes: // Notes:
// After it returns true, this function hijacks the connection. Existing event // The existing event handler is no longer called. hm is invalid after this
// handler not called, hm is invalid, c->data and c->fn_data are modified // call; c->data and c->fn_data are reserved for streaming state.
bool mg_http_stream_body(struct mg_connection *c, struct mg_http_message *hm, void mg_http_stream_body(struct mg_connection *c, struct mg_http_message *hm,
bool (*upload_fn)(struct mg_http_message *, bool (*upload_fn)(struct mg_http_message *,
struct mg_str *, void **user_data), struct mg_str *, void **user_data),
void *user_data); void *user_data);
@@ -4227,12 +4171,14 @@ extern void mg_mqtt_poll(struct mg_mgr *);
// Supported OTA targets // Supported OTA targets
#define MG_OTA_NONE 0 // No OTA support #define MG_OTA_NONE 0 // No OTA support
#define MG_OTA_STM32H5 1 // STM32 H5 #define MG_OTA_STM32H5 1 // STM32 H5
#define MG_OTA_STM32H7 2 // STM32 H7 #define MG_OTA_STM32H7 2 // STM32 H7
#define MG_OTA_STM32H7_DUAL_CORE 3 // STM32 H7 dual core #define MG_OTA_STM32H7_DUAL_CORE 3 // STM32 H7 dual core
#define MG_OTA_STM32F 4 // STM32 F7/F4/F2 #define MG_OTA_STM32F 4 // STM32 F7/F4/F2
#define MG_OTA_STM32C5 5 // STM32 C5, same flash controller as H5
#define MG_OTA_CH32V307 100 // WCH CH32V307 #define MG_OTA_CH32V307 100 // WCH CH32V307
#define MG_OTA_U2A 200 // Renesas U2A16, U2A8, U2A6 #define MG_OTA_U2A 200 // Renesas U2A16, U2A8, U2A6
#define MG_OTA_RT1020 300 // IMXRT1020 #define MG_OTA_RT1020 300 // IMXRT1020
@@ -4242,6 +4188,7 @@ extern void mg_mqtt_poll(struct mg_mgr *);
#define MG_OTA_RT1170 304 // IMXRT1170 #define MG_OTA_RT1170 304 // IMXRT1170
#define MG_OTA_RT1180 305 // IMXRT1180 #define MG_OTA_RT1180 305 // IMXRT1180
#define MG_OTA_MCXN 310 // MCXN947 #define MG_OTA_MCXN 310 // MCXN947
#define MG_OTA_MCXW71 311 // MCXW71
#define MG_OTA_RW612 320 // FRDM-RW612 #define MG_OTA_RW612 320 // FRDM-RW612
#define MG_OTA_FLASH 900 // OTA via internal flash #define MG_OTA_FLASH 900 // OTA via internal flash
#define MG_OTA_ESP32 910 // ESP32 OTA implementation #define MG_OTA_ESP32 910 // ESP32 OTA implementation
@@ -4271,6 +4218,18 @@ bool mg_ota_write(const void *buf, size_t len);
// Ends the OTA process and commits the written firmware. // Ends the OTA process and commits the written firmware.
bool mg_ota_end(void); bool mg_ota_end(void);
// Push-based OTA: mg_http_stream_body() callback that flashes the request
//
// ```c
// if (ev == MG_EV_HTTP_HDRS) {
// struct mg_http_message *hm = (struct mg_http_message *) ev_data;
// if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
// mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
// }
// }
// ```
bool mg_http_ota_cb(struct mg_http_message *hm, struct mg_str *data, void **p);
// MG_OTA_ROLLBACK: swap firmware banks and reset. On flash-based OTA, the // MG_OTA_ROLLBACK: swap firmware banks and reset. On flash-based OTA, the
// default calls swap_fn() (no-op on single-bank) then resets. Override in // default calls swap_fn() (no-op on single-bank) then resets. Override in
// mongoose_config.h for platforms without mg_flash (ESP32, PicoSDK, etc.). // mongoose_config.h for platforms without mg_flash (ESP32, PicoSDK, etc.).
@@ -4414,32 +4373,15 @@ void mg_ota_poll(struct mg_mgr *);
// Memory usage in bytes. Override in mongoose_config.h for the target.
#ifndef MG_HEALTH_STACK_USED
#define MG_HEALTH_STACK_USED 0
#endif
#ifndef MG_HEALTH_STACK_TOTAL
#define MG_HEALTH_STACK_TOTAL 0
#endif
#ifndef MG_HEALTH_HEAP_USED
#define MG_HEALTH_HEAP_USED 0
#endif
#ifndef MG_HEALTH_HEAP_TOTAL
#define MG_HEALTH_HEAP_TOTAL 0
#endif
#ifndef MG_HEALTH_MAGIC #ifndef MG_HEALTH_MAGIC
#define MG_HEALTH_MAGIC {'M', 'G', 'H', '3'} // '3' is the layout version #define MG_HEALTH_MAGIC {'M', 'G', 'H', '3'} // '3' is the layout version
#endif #endif
#if !defined(MG_HEALTH_RAM) && (defined(STM32H7_DEV_ID) || defined(STM32H5)) #if !defined(MG_HEALTH_RAM) && (defined(STM32H7_DEV_ID) || defined(STM32H5) || defined(STM32C5))
#define MG_HEALTH_RAM __attribute__((section(".mg_health"))) #define MG_HEALTH_RAM __attribute__((section(".mg_health")))
#endif #endif
#if !defined(MG_HEALTH_DATA_SIZE) && (defined(STM32H7_DEV_ID) || defined(STM32H5)) #if !defined(MG_HEALTH_DATA_SIZE) && (defined(STM32H7_DEV_ID) || defined(STM32H5) || defined(STM32C5))
#define MG_HEALTH_DATA_SIZE 250 #define MG_HEALTH_DATA_SIZE 250
#endif #endif
@@ -4806,6 +4748,41 @@ extern struct mg_tcpip_driver mg_tcpip_driver_nxp_wifi;
extern struct mg_tcpip_driver mg_tcpip_driver_st67w6; extern struct mg_tcpip_driver mg_tcpip_driver_st67w6;
extern struct mg_tcpip_driver mg_tcpip_driver_atcmd; extern struct mg_tcpip_driver mg_tcpip_driver_atcmd;
extern struct mg_tcpip_driver mg_tcpip_driver_netc; extern struct mg_tcpip_driver mg_tcpip_driver_netc;
extern struct mg_tcpip_driver mg_tcpip_driver_mcxw71;
extern struct mg_tcpip_driver mg_tcpip_driver_rw612_154;
// IEEE 802.15.4 radio channel and PAN ID. Settable in mongoose_config.h
#ifndef MG_L2_802154_CHANNEL
#define MG_L2_802154_CHANNEL 15 // 11..26
#endif
#ifndef MG_L2_802154_PAN_ID
#define MG_L2_802154_PAN_ID 0xabcd
#endif
// driver_data for IEEE 802.15.4 radio drivers. The interface is Ethernet:
// each Ethernet frame is split into broadcast radio frames, and reassembled
// on the other side, see mg_l2_802154_tx() and mg_l2_802154_rx()
struct mg_l2_802154_data {
uint8_t channel; // User-set channel, 11..26
uint16_t pan_id; // User-set PAN ID
uint8_t seq, tag; // MAC sequence number, tag of the last sent frame
uint8_t rxtag, rxnext; // Frame being reassembled: tag, next fragment
uint8_t rxsrc[8]; // Its sender
uint16_t rxlen; // Its bytes received so far
uint8_t rxbuf[1514]; // Reassembly buffer, one Ethernet frame
};
// Splits an Ethernet frame into radio frames, sends each by calling send().
// Called by radio drivers' tx(). Return len, or 0 on error
size_t mg_l2_802154_tx(struct mg_tcpip_if *ifp, const void *buf, size_t len,
size_t (*send)(const uint8_t *, size_t,
struct mg_tcpip_if *));
// Adds a received radio frame f of n bytes to the frame being reassembled.
// Called by radio drivers' rx(). Return the Ethernet frame length, copied to
// buf, when it is complete, otherwise 0
size_t mg_l2_802154_rx(struct mg_tcpip_if *ifp, const uint8_t *f, size_t n,
void *buf, size_t len);
// SPI bus abstraction for SPI-attached network chips (e.g. W5500). // SPI bus abstraction for SPI-attached network chips (e.g. W5500).
// Populate and assign to the driver's driver_data field. // Populate and assign to the driver's driver_data field.
@@ -5193,6 +5170,31 @@ struct mg_tcpip_driver_imxrt_data {
#endif #endif
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_MCXW71) && \
MG_ENABLE_DRIVER_MCXW71
// NXP MCXW71 IEEE 802.15.4 radio, ZLL link layer, as an Ethernet interface:
// Ethernet frames are split into radio frames, see mg_l2_802154_tx().
// The transceiver (XCVR) must be set up for 802.15.4 before mg_tcpip_init(),
// see hal_radio_init() in the FRDM-MCXW71 tutorial.
// driver_data: struct mg_l2_802154_data, channel and PAN ID set
#define MG_TCPIP_DRIVER_INIT(mgr) \
do { \
static struct mg_l2_802154_data driver_data_; \
static struct mg_tcpip_if mif_; \
driver_data_.channel = MG_L2_802154_CHANNEL; \
driver_data_.pan_id = MG_L2_802154_PAN_ID; \
mif_.driver = &mg_tcpip_driver_mcxw71; \
mif_.driver_data = &driver_data_; \
MG_SET_MAC_ADDRESS(mif_.mac); \
mg_tcpip_init(mgr, &mif_); \
MG_INFO(("Driver: mcxw71, channel %d", MG_L2_802154_CHANNEL)); \
} while (0)
#endif
#if defined(MG_ENABLE_TCPIP) && MG_ENABLE_TCPIP && \ #if defined(MG_ENABLE_TCPIP) && MG_ENABLE_TCPIP && \
defined(MG_ENABLE_DRIVER_NETC) && MG_ENABLE_DRIVER_NETC defined(MG_ENABLE_DRIVER_NETC) && MG_ENABLE_DRIVER_NETC
@@ -5411,6 +5413,35 @@ struct mg_tcpip_driver_rw612_data {
#endif #endif
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_RW612_154) && \
MG_ENABLE_DRIVER_RW612_154
// NXP RW612 IEEE 802.15.4 radio, as an Ethernet interface: Ethernet frames
// are split into radio frames, see mg_l2_802154_tx(). The radio runs on
// CPU2: NXP BLE/802.15.4 combo firmware, an OpenThread radio co-processor
// (RCP). The firmware must be loaded and running before mg_tcpip_init(), see
// the FRDM-RW612 eth_radio_bridge tutorial. The driver talks to it over the
// CPU2 <-> CPU3 IMU mailbox: IMUMC messages carrying HDLC framed Spinel.
// driver_data: struct mg_l2_802154_data, channel and PAN ID set
#ifndef MG_TCPIP_DRIVER_INIT
#define MG_TCPIP_DRIVER_INIT(mgr) \
do { \
static struct mg_l2_802154_data driver_data_; \
static struct mg_tcpip_if mif_; \
driver_data_.channel = MG_L2_802154_CHANNEL; \
driver_data_.pan_id = MG_L2_802154_PAN_ID; \
mif_.driver = &mg_tcpip_driver_rw612_154; \
mif_.driver_data = &driver_data_; \
MG_SET_MAC_ADDRESS(mif_.mac); \
mg_tcpip_init(mgr, &mif_); \
MG_INFO(("Driver: rw612_154, channel %d", MG_L2_802154_CHANNEL)); \
} while (0)
#endif
#endif
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && \ #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_SAME54) && \
MG_ENABLE_DRIVER_SAME54 MG_ENABLE_DRIVER_SAME54
@@ -5572,6 +5603,13 @@ struct mg_tcpip_driver_stm32f_data {
#if !defined(MG_ENABLE_DRIVER_STM32H) #if !defined(MG_ENABLE_DRIVER_STM32H)
#define MG_ENABLE_DRIVER_STM32H 0 #define MG_ENABLE_DRIVER_STM32H 0
#endif #endif
#if !defined(MG_ENABLE_DRIVER_STM32C)
#define MG_ENABLE_DRIVER_STM32C 0
#endif
#if MG_ENABLE_DRIVER_STM32C // STM32C5: STM32H5 MAC, the IRQ is ETH1
#undef MG_ENABLE_DRIVER_STM32H
#define MG_ENABLE_DRIVER_STM32H 1
#endif
#if !defined(MG_ENABLE_DRIVER_MCXN) #if !defined(MG_ENABLE_DRIVER_MCXN)
#define MG_ENABLE_DRIVER_MCXN 0 #define MG_ENABLE_DRIVER_MCXN 0
#endif #endif
@@ -5611,9 +5649,11 @@ struct mg_tcpip_driver_stm32h_data {
#define MG_DRIVER_MDC_CR 4 #define MG_DRIVER_MDC_CR 4
#endif #endif
#if MG_ENABLE_DRIVER_STM32H && MG_ARCH == MG_ARCH_CUBE && !defined(MG_ENABLE_ETH_IRQ) #if MG_ENABLE_DRIVER_STM32H && !MG_ENABLE_DRIVER_STM32C && \
MG_ARCH == MG_ARCH_CUBE && !defined(MG_ENABLE_ETH_IRQ)
#define MG_ENABLE_ETH_IRQ() NVIC_EnableIRQ(ETH_IRQn) #define MG_ENABLE_ETH_IRQ() NVIC_EnableIRQ(ETH_IRQn)
#elif MG_ENABLE_DRIVER_STM32N && MG_ARCH == MG_ARCH_CUBE && !defined(MG_ENABLE_ETH_IRQ) #elif (MG_ENABLE_DRIVER_STM32N || MG_ENABLE_DRIVER_STM32C) && \
MG_ARCH == MG_ARCH_CUBE && !defined(MG_ENABLE_ETH_IRQ)
#define MG_ENABLE_ETH_IRQ() NVIC_EnableIRQ(ETH1_IRQn) #define MG_ENABLE_ETH_IRQ() NVIC_EnableIRQ(ETH1_IRQn)
#elif !defined(MG_ENABLE_ETH_IRQ) #elif !defined(MG_ENABLE_ETH_IRQ)
#define MG_ENABLE_ETH_IRQ() #define MG_ENABLE_ETH_IRQ()
@@ -15,6 +15,7 @@
</environment> </environment>
</environments> </environments>
<releases> <releases>
<release date="2026-10-21" version="7.23.3">See https://github.com/cesanta/mongoose/releases/tag/7.23</release>
<release date="2026-10-19" version="7.23.2">See https://github.com/cesanta/mongoose/releases/tag/7.23</release> <release date="2026-10-19" version="7.23.2">See https://github.com/cesanta/mongoose/releases/tag/7.23</release>
<release date="2026-09-28" version="7.23.1">See https://github.com/cesanta/mongoose/releases/tag/7.23</release> <release date="2026-09-28" version="7.23.1">See https://github.com/cesanta/mongoose/releases/tag/7.23</release>
<release date="2026-05-11" version="7.21.7">See https://github.com/cesanta/mongoose/releases/tag/7.21</release> <release date="2026-05-11" version="7.21.7">See https://github.com/cesanta/mongoose/releases/tag/7.21</release>
@@ -28,7 +29,7 @@
<keyword>IMPLEMENTED_WITH_STM32CUBEMX</keyword> <keyword>IMPLEMENTED_WITH_STM32CUBEMX</keyword>
</keywords> </keywords>
<components> <components>
<component Cclass="Mongoose" Cgroup="Networking Core" Cversion="7.23.2" maxInstances="1"> <component Cclass="Mongoose" Cgroup="Networking Core" Cversion="7.23.3" maxInstances="1">
<description>Networking Core</description> <description>Networking Core</description>
<files> <files>
<file category="doc" name="README.md"/> <file category="doc" name="README.md"/>
+1 -1
View File
@@ -1,4 +1,4 @@
VERSION = 7.23.2 VERSION = 7.23.3
REPO_ROOT = ../.. REPO_ROOT = ../..
MX ?= /Applications/STMicroelectronics/STM32CubeMX.app/Contents/MacOs/STM32CubeMX MX ?= /Applications/STMicroelectronics/STM32CubeMX.app/Contents/MacOs/STM32CubeMX
FILES = Cesanta.I-CUBE-Mongoose.pdsc Release_Notes.html mongoose_config.h README.md .config/mongoose_parameters.json FILES = Cesanta.I-CUBE-Mongoose.pdsc Release_Notes.html mongoose_config.h README.md .config/mongoose_parameters.json
+5 -64
View File
@@ -32,6 +32,7 @@
#if MG_ENABLE_TCPIP && !defined(MG_ENABLE_DRIVER_STM32F) && \ #if MG_ENABLE_TCPIP && !defined(MG_ENABLE_DRIVER_STM32F) && \
!defined(MG_ENABLE_DRIVER_STM32H) && !defined(MG_ENABLE_DRIVER_STM32N) && \ !defined(MG_ENABLE_DRIVER_STM32H) && !defined(MG_ENABLE_DRIVER_STM32N) && \
!defined(MG_ENABLE_DRIVER_STM32C) && \
!defined(MG_ENABLE_DRIVER_CYW) && !defined(MG_ENABLE_DRIVER_CYW_SDIO) && \ !defined(MG_ENABLE_DRIVER_CYW) && !defined(MG_ENABLE_DRIVER_CYW_SDIO) && \
!defined(MG_ENABLE_DRIVER_ST67W6) !defined(MG_ENABLE_DRIVER_ST67W6)
#if defined(STM32F1) || defined(STM32F2) || defined(STM32F4) || defined(STM32F7) #if defined(STM32F1) || defined(STM32F2) || defined(STM32F4) || defined(STM32F7)
@@ -40,6 +41,8 @@
#define MG_ENABLE_DRIVER_STM32H 1 #define MG_ENABLE_DRIVER_STM32H 1
#elif defined(STM32N6) #elif defined(STM32N6)
#define MG_ENABLE_DRIVER_STM32N 1 #define MG_ENABLE_DRIVER_STM32N 1
#elif defined(STM32C5)
#define MG_ENABLE_DRIVER_STM32C 1
#else #else
#error Select a driver in mongoose_config.h #error Select a driver in mongoose_config.h
#endif #endif
@@ -56,70 +59,8 @@
#define MG_OTA MG_OTA_STM32H5 #define MG_OTA MG_OTA_STM32H5
#elif !defined(MG_OTA) && defined(STM32H7) #elif !defined(MG_OTA) && defined(STM32H7)
#define MG_OTA MG_OTA_STM32H7 #define MG_OTA MG_OTA_STM32H7
#endif #elif !defined(MG_OTA) && defined(STM32C5)
#define MG_OTA MG_OTA_STM32C5
// OTA rollback timer via IWDG. Fixed 10 s hang-detection window (prescaler
// /1024, LSI ~32 kHz: reload = 10 * 32000 / 1024 = 312). mg_ota_poll() feeds
// the watchdog every 500 ms while in MG_OTA_TESTING state; if the event loop
// hangs for 10 s, the IWDG fires and the device rolls back.
// STM32H7 names the peripheral IWDG1; all others use IWDG.
// The total evaluation period is set by MG_OTA_ROLLBACK_TIMEOUT_SECONDS.
// STM32H7 names the watchdog peripheral IWDG1; all other families use IWDG.
#if defined(IWDG1) && !defined(IWDG)
#define MG_IWDG IWDG1
#else
#define MG_IWDG IWDG
#endif
// PR=6 → /256 prescaler, RLR=1250 → ~10 s at LSI 32 kHz.
// Works on F4/F7/H5/H7; uses direct register writes so it is safe before HAL_Init().
#ifndef MG_OTA_ROLLBACK_TIMER_START
#define MG_OTA_ROLLBACK_TIMER_START() \
do { \
MG_IWDG->KR = 0xCCCCU; /* start + LSI */ \
MG_IWDG->KR = 0x5555U; /* unlock PR/RLR */ \
MG_IWDG->PR = 6U; /* /256 */ \
MG_IWDG->RLR = 1250U; /* 10 s */ \
while (MG_IWDG->SR & (IWDG_SR_PVU | IWDG_SR_RVU)) (void) 0; \
MG_IWDG->KR = 0xAAAAU; /* reload */ \
} while (0)
#endif
// Feed (reload) the IWDG. Called from mg_ota_poll() every 500 ms.
#ifndef MG_OTA_ROLLBACK_TIMER_FEED
#define MG_OTA_ROLLBACK_TIMER_FEED() (MG_IWDG->KR = 0xAAAAU)
#endif
// OTA state in a backup register that survives warm resets but clears on POR.
// STATE_GET reads work without any setup. STATE_SET enables the RTC APB clock
// and unlocks backup domain write access via direct register writes, so it is
// safe to call from any context (before or after HAL_Init).
// H5 (TAMP->BKP0R), H7 (RTC->BKP0R), F4/F7 (RTC->BKP0R).
#ifndef MG_OTA_STATE_GET
#if defined(PWR_DBPCR_DBP)
#define MG_OTA_DBP_ENABLE() (PWR->DBPCR |= PWR_DBPCR_DBP)
#elif defined(PWR_CR1_DBP)
#define MG_OTA_DBP_ENABLE() (PWR->CR1 |= PWR_CR1_DBP)
#else
#define MG_OTA_DBP_ENABLE() (PWR->CR |= PWR_CR_DBP)
#endif
#if defined(TAMP)
#define MG_OTA_STATE_GET() \
(RCC->APB3ENR |= RCC_APB3ENR_RTCAPBEN, TAMP->BKP0R)
#define MG_OTA_STATE_SET(v) \
(RCC->APB3ENR |= RCC_APB3ENR_RTCAPBEN, MG_OTA_DBP_ENABLE(), \
(TAMP->BKP0R = (uint32_t) (v)), TAMP->BKP0R)
#elif defined(RCC_APB4ENR_RTCAPBEN)
#define MG_OTA_STATE_GET() (RTC->BKP0R)
#define MG_OTA_STATE_SET(v) \
(RCC->APB4ENR |= RCC_APB4ENR_RTCAPBEN, MG_OTA_DBP_ENABLE(), \
(RTC->BKP0R = (uint32_t) (v)))
#else
#define MG_OTA_STATE_GET() (RTC->BKP0R)
#define MG_OTA_STATE_SET(v) \
(RCC->APB1ENR |= RCC_APB1ENR_PWREN, MG_OTA_DBP_ENABLE(), \
(RTC->BKP0R = (uint32_t) (v)))
#endif
#endif #endif
// use HAL-defined execute-in-ram section // use HAL-defined execute-in-ram section
+3 -18
View File
@@ -533,21 +533,6 @@ static void mg_dash_handle_add(struct mg_connection *c, struct mg_dash *dash,
} }
} }
// Firmware upload callback for mg_http_stream_body(). Uses *p as a flag:
// non-NULL means an OTA session is open and must be closed by mg_ota_end()
static bool otacb(struct mg_http_message *hm, struct mg_str *data, void **p) {
if (hm != NULL) { // Start
if (!mg_ota_begin(hm->body.len)) return false;
*p = (void *) (ptrdiff_t) 1;
return true;
} else if (data != NULL) { // Next chunk
return mg_ota_write(data->buf, data->len);
}
if (*p == NULL) return false; // End. Begin failed, nothing to finish
*p = NULL;
return mg_ota_end();
}
static void mg_serve_fs(struct mg_connection *c, struct mg_http_message *hm, static void mg_serve_fs(struct mg_connection *c, struct mg_http_message *hm,
struct mg_dash_user *u, bool stream) { struct mg_dash_user *u, bool stream) {
struct mg_dash *dash = (struct mg_dash *) c->fn_data; struct mg_dash *dash = (struct mg_dash *) c->fn_data;
@@ -594,9 +579,9 @@ void mg_dash_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
mg_serve_fs(c, hm, u, true); mg_serve_fs(c, hm, u, true);
return; // Important - the serve_fs() call can invalidate hm return; // Important - the serve_fs() call can invalidate hm
} else if (mg_match(hm->uri, mg_str("/api/ota"), NULL)) { } else if (mg_match(hm->uri, mg_str("/api/ota"), NULL)) {
// Authenticated above. If streaming started, the stream handler owns // Authenticated above. Streaming owns the connection and c->data.
// the connection and c->data, so skip the marker check below mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
if (mg_http_stream_body(c, hm, otacb, NULL)) return; return;
} }
if (d->marker != '\0') mg_log_http_req(c, hm); if (d->marker != '\0') mg_log_http_req(c, hm);
} else if (ev == MG_EV_HTTP_MSG && d->marker != '\0') { } else if (ev == MG_EV_HTTP_MSG && d->marker != '\0') {
+142
View File
@@ -0,0 +1,142 @@
#include "net_builtin.h"
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_MCXW71) && \
MG_ENABLE_DRIVER_MCXW71
// ZLL, 802.15.4 link layer. See MCXW71 reference manual and NXP
// ieee_802_15_4 PHY sources: PhyPacketProcessor.c, PhyPlmeData.c, PhyISR.c
struct mg_zll {
volatile uint32_t IRQSTS, PHY_CTRL, EVENT_TMR, TIMESTAMP, T1CMP, T2CMP,
T2PRIMECMP, T3CMP, T4CMP, PA_PWR, CHANNEL_NUM0, LQI_AND_RSSI,
MACSHORTADDRS0, MACLONGADDRS0_LSB, MACLONGADDRS0_MSB, RX_FRAME_FILTER,
CCA_LQI_CTRL, CCA2_CTRL, RESERVED_0, DSM_CTRL, RESERVED_1,
MACSHORTADDRS1, MACLONGADDRS1_LSB, MACLONGADDRS1_MSB, DUAL_PAN_CTRL,
CHANNEL_NUM1, SAM_CTRL, SAM_TABLE, SAM_MATCH, SAM_FREE_IDX,
SEQ_CTRL_STS, ACKDELAY, FILTERFAIL_CODE, RX_WTR_MARK, RESERVED_2,
SLOT_PRELOAD, SEQ_STATE, TMR_PRESCALE, LENIENCY_LSB, LENIENCY_MSB,
PART_ID, COEX_CTRL, COEX_PRIORITY, ENHACK_CTRL0;
};
// TrustZone: code built for the secure state (-mcmse) uses the secure alias
// of the radio registers, 0x5xxxxxxx. Otherwise, the non-secure alias
#if defined(__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE & 2)
#define MGI_ZLL ((struct mg_zll *) 0x58A01000)
#define MGI_PKT_RAM ((volatile uint8_t *) 0x58A08000)
#else
#define MGI_ZLL ((struct mg_zll *) 0x48A01000)
#define MGI_PKT_RAM ((volatile uint8_t *) 0x48A08000)
#endif
#define MGI_TX_PB MGI_PKT_RAM // Length byte (incl. FCS), then frame
#define MGI_RX_PB (MGI_PKT_RAM + 0x80) // Received frame, no length byte
#define MGI_IRQSTS_SEQIRQ MG_BIT(0)
#define MGI_IRQSTS_RXIRQ MG_BIT(2)
#define MGI_IRQSTS_RX_LEN(x) (((x) >> 24) & 0x7f) // Frame length incl. FCS
#define MGI_PHY_CTRL_XCVSEQ 7U
#define MGI_PHY_CTRL_ALL_IRQ_MASKS 0x8007ff00U // Bits 8..18, 31: mask all IRQs
#define MGI_SEQ_STATE_MASK 0x1fU
#define MGI_SEQ_STATE_RX_WU 0x10U // RX warm up
#define MGI_SEQ_CTRL_NO_RX_RECYCLE MG_BIT(5)
#define MGI_FRAME_FILTER 0x70bU // Beacon, data, command; versions 0..2
enum { MGI_SEQ_IDLE = 0, MGI_SEQ_RX = 1, MGI_SEQ_TX = 2 }; // PHY_CTRL[XCVSEQ]
#define MGI_TX_TIMEOUT 400U // Symbols, 16 us: 127 bytes
// Symbol timer, 16 us, 24 bits
static uint32_t mg_mcxw71_symbols(void) {
return MGI_ZLL->EVENT_TMR >> 8;
}
// Wait for the sequence to end, up to MGI_TX_TIMEOUT symbols
static bool mg_mcxw71_wait(void) {
uint32_t start = mg_mcxw71_symbols();
while (((mg_mcxw71_symbols() - start) & 0xffffffU) < MGI_TX_TIMEOUT) {
if (MGI_ZLL->IRQSTS & MGI_IRQSTS_SEQIRQ) return true;
}
return false;
}
// Stop the current sequence, wait for the sequencer to go idle. See PhyAbort()
static void mg_mcxw71_idle(void) {
if (MGI_ZLL->PHY_CTRL & MGI_PHY_CTRL_XCVSEQ) {
while ((MGI_ZLL->SEQ_STATE & MGI_SEQ_STATE_MASK) == MGI_SEQ_STATE_RX_WU)
(void) 0;
MGI_ZLL->PHY_CTRL &= ~MGI_PHY_CTRL_XCVSEQ;
while (MGI_ZLL->SEQ_STATE & MGI_SEQ_STATE_MASK) (void) 0;
}
MGI_ZLL->IRQSTS = MGI_ZLL->IRQSTS; // Clear all flags, write 1 to clear
}
// Start a new sequence: MGI_SEQ_RX or MGI_SEQ_TX
static void mg_mcxw71_start(uint32_t seq) {
MGI_ZLL->IRQSTS = MGI_ZLL->IRQSTS;
MGI_ZLL->PHY_CTRL |= seq;
}
static bool mg_mcxw71_init(struct mg_tcpip_if *ifp) {
struct mg_l2_802154_data *d =
(struct mg_l2_802154_data *) ifp->driver_data;
if (d == NULL || d->channel < 11 || d->channel > 26) {
MG_ERROR(("Set driver_data, channel 11..26"));
return false;
}
MGI_ZLL->SEQ_CTRL_STS |= MGI_SEQ_CTRL_NO_RX_RECYCLE;
MGI_ZLL->PHY_CTRL = MGI_PHY_CTRL_ALL_IRQ_MASKS; // Mask all IRQs, we poll
MGI_ZLL->IRQSTS = MGI_ZLL->IRQSTS;
MGI_ZLL->SAM_CTRL = 0;
MGI_ZLL->RX_FRAME_FILTER = MGI_FRAME_FILTER;
MGI_ZLL->TMR_PRESCALE = 5; // 16 us timebase, one symbol
MGI_ZLL->CHANNEL_NUM0 = d->channel;
MGI_ZLL->MACSHORTADDRS0 = (0xfffeU << 16) | d->pan_id; // Filter by PAN ID
MGI_ZLL->PA_PWR = 0x3f; // PA slices, max output power
mg_mcxw71_start(MGI_SEQ_RX);
return true;
}
// Send one radio frame: MAC header and payload, no FCS
static size_t mg_mcxw71_send(const uint8_t *p, size_t len,
struct mg_tcpip_if *ifp) {
size_t i;
bool ok;
mg_mcxw71_idle();
MGI_TX_PB[0] = (uint8_t) (len + 2); // FCS is added by hardware
for (i = 0; i < len; i++) MGI_TX_PB[i + 1] = p[i]; // 8-bit access only
mg_mcxw71_start(MGI_SEQ_TX);
ok = mg_mcxw71_wait();
mg_mcxw71_idle();
mg_mcxw71_start(MGI_SEQ_RX);
(void) ifp;
return ok ? len : 0;
}
static size_t mg_mcxw71_tx(const void *buf, size_t len,
struct mg_tcpip_if *ifp) {
return mg_l2_802154_tx(ifp, buf, len, mg_mcxw71_send);
}
static size_t mg_mcxw71_rx(void *buf, size_t len, struct mg_tcpip_if *ifp) {
uint32_t irqsts = MGI_ZLL->IRQSTS;
uint8_t f[125];
size_t i, n = 0;
if ((irqsts & MGI_IRQSTS_SEQIRQ) == 0) return 0; // Still receiving
if (irqsts & MGI_IRQSTS_RXIRQ) {
n = MGI_IRQSTS_RX_LEN(irqsts);
n = n >= 2 ? n - 2 : 0; // Strip FCS
if (n > sizeof(f)) n = sizeof(f);
for (i = 0; i < n; i++) f[i] = MGI_RX_PB[i];
}
mg_mcxw71_idle();
mg_mcxw71_start(MGI_SEQ_RX);
return mg_l2_802154_rx(ifp, f, n, buf, len);
}
static bool mg_mcxw71_poll(struct mg_tcpip_if *ifp, bool s1) {
(void) ifp, (void) s1;
return true; // Radio link is always up
}
struct mg_tcpip_driver mg_tcpip_driver_mcxw71 = {mg_mcxw71_init, mg_mcxw71_tx,
mg_mcxw71_rx, mg_mcxw71_poll};
#endif
+25
View File
@@ -0,0 +1,25 @@
#pragma once
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_MCXW71) && \
MG_ENABLE_DRIVER_MCXW71
// NXP MCXW71 IEEE 802.15.4 radio, ZLL link layer, as an Ethernet interface:
// Ethernet frames are split into radio frames, see mg_l2_802154_tx().
// The transceiver (XCVR) must be set up for 802.15.4 before mg_tcpip_init(),
// see hal_radio_init() in the FRDM-MCXW71 tutorial.
// driver_data: struct mg_l2_802154_data, channel and PAN ID set
#define MG_TCPIP_DRIVER_INIT(mgr) \
do { \
static struct mg_l2_802154_data driver_data_; \
static struct mg_tcpip_if mif_; \
driver_data_.channel = MG_L2_802154_CHANNEL; \
driver_data_.pan_id = MG_L2_802154_PAN_ID; \
mif_.driver = &mg_tcpip_driver_mcxw71; \
mif_.driver_data = &driver_data_; \
MG_SET_MAC_ADDRESS(mif_.mac); \
mg_tcpip_init(mgr, &mif_); \
MG_INFO(("Driver: mcxw71, channel %d", MG_L2_802154_CHANNEL)); \
} while (0)
#endif
+450
View File
@@ -0,0 +1,450 @@
#include "net_builtin.h"
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_RW612_154) && \
MG_ENABLE_DRIVER_RW612_154
// The 802.15.4 radio runs NXP combo firmware on CPU2, an OpenThread RCP. We
// are CPU3. Messages go through the IMU mailbox: IMU messages carry IMUMC
// messages, IMUMC messages carry HDLC framed Spinel. See NXP sources:
// mcuxsdk-core drivers/imu/fsl_imu.c, mcux-component
// imu_adapter/fsl_adapter_imu.c, connectivity framework
// platform/rw61x/fwk_platform_hdlc.c; OpenThread src/lib/spinel/spinel.h
// IMU message FIFO registers, one block per direction. See fsl_imu.h
struct mg_rw612_imu {
volatile uint32_t WR_MSG, RD_MSG, STATUS, CNTL, RD_MSG_DBG;
};
#define MGI_IMU ((struct mg_rw612_imu *) 0x443ff804) // CPU3 -> CPU2
#define MGI_IMU_PEER ((struct mg_rw612_imu *) 0x443ff818) // CPU2 -> CPU3
#define MGI_IMU_LOCKED MG_BIT(0) // STATUS: FIFO locked
#define MGI_IMU_ALMOST_FULL MG_BIT(1) // STATUS: FIFO almost full
#define MGI_IMU_EMPTY MG_BIT(3) // STATUS: FIFO empty
#define MGI_IMU_WR_PTR(s) (((s) >> 16) & 15U)
#define MGI_IMU_INT_CLR MG_BIT(0) // CNTL: clear message ready IRQ
#define MGI_IMU_FLUSH MG_BIT(16) // CNTL: flush send FIFO
#define MGI_IMU_WAIT_FOR_ACK MG_BIT(17) // CNTL: lock send FIFO
#define MGI_IMU_WATERMARK(x) ((uint32_t) (x) << 20)
#define MGI_IMU_WATERMARK_MASK (15U << 20)
// IMU message: header, then payload words. See IMU_Msg_t
struct mg_rw612_msg {
uint8_t type, subtype, seq, len; // len: number of payload words
uint32_t payload[8];
};
// Mailbox in SMU2 shared memory, at the address CPU2 firmware expects
struct mg_rw612_mbox {
uint32_t magic[2]; // Sync pattern: [0] CPU2, [1] us
struct mg_rw612_msg q[2][16]; // Message slots: [0] CPU2 -> us, [1] ours
};
#define MGI_MBOX ((volatile struct mg_rw612_mbox *) 0x443c0000)
#define MGI_TXBUF 0x443c1508U // Our IMUMC buffers: 16 x 264 bytes
#define MGI_TXBUF_CNT 16
#define MGI_TXBUF_LEN 264U
#define MGI_SLEEP_FLAG (*(volatile uint32_t *) 0x443c2588)
#define MGI_SYNC_MAGIC 0xabcdef89U
// IMUMC message, carried in IMU payload words. See imumc_std_msg
struct mg_rw612_imumc {
uint32_t src, dst; // Endpoint addresses
uint16_t rfu, idx; // Reserved
uint16_t len; // Payload length, bytes
uint16_t flags; // Message flags
uint32_t data; // Payload buffer address
};
#define MGI_EPT_LOCAL 10 // Our 802.15.4 endpoint
#define MGI_EPT_REMOTE 20 // Firmware 802.15.4 endpoint
enum { MGI_MSG_CONTROL = 0, MGI_MSG_IMUMC = 8 }; // IMU message types
enum { // Control message subtypes
MGI_CTL_SYNC = 1,
MGI_CTL_SYNC_ACK = 2,
MGI_CTL_ACK_FOR_UNLOCK = 3,
MGI_CTL_CMD_BUF_ADDR = 6,
MGI_CTL_EPT_QUERY = 11,
MGI_CTL_EPT_QUERY_RSP = 12,
MGI_CTL_BUF_FREE = 13
};
// Spinel commands, properties and statuses we use
enum { MGI_CMD_RESET = 1, MGI_CMD_GET = 2, MGI_CMD_SET = 3, MGI_CMD_IS = 6 };
enum {
MGI_PROP_LAST_STATUS = 0,
MGI_PROP_NCP_VERSION = 2,
MGI_PROP_PHY_ENABLED = 0x20,
MGI_PROP_PHY_CHAN = 0x21,
MGI_PROP_PANID = 0x36,
MGI_PROP_RAW_STREAM = 0x37,
MGI_PROP_STREAM_RAW = 0x71
};
#define MGI_RESET_STACK 2 // RESET argument: reset the RCP stack only
#define MGI_STATUS_RESET_MIN 112 // LAST_STATUS: RCP has reset
#define MGI_STATUS_RESET_MAX 127
#define MGI_TX_TIMEOUT_MS 200 // Wait for transmit done, incl. retries
#define MGI_RSP_TIMEOUT_MS 500
#define MGI_RXQ_CNT 16 // A whole Ethernet frame, 15 radio frames
// Driver state, one radio
struct mg_rw612 {
bool up; // IMU link synchronised
bool ept_ready; // IMUMC endpoints connected
bool reset; // RCP reported a reset
uint8_t seq; // IMU message sequence number
uint16_t free_bufs; // Free IMUMC buffers, bit per buffer
uint8_t hdlc[300]; // HDLC frame being received, unescaped
size_t hlen; // Bytes in hdlc
bool esc; // Previous byte was an escape
uint8_t tid; // Spinel transaction ID of the pending request
bool rsp; // Response to the pending request received
uint32_t rsp_status; // Its status, if LAST_STATUS, else 0
char version[64]; // RCP version string
uint8_t rxq[MGI_RXQ_CNT][127]; // Received frames, no FCS
uint8_t rxlen[MGI_RXQ_CNT]; // Their lengths
uint8_t rxhead, rxtail; // Queue indexes
};
static struct mg_rw612 s_rw612;
static void mg_rw612_imu_send(uint8_t type, uint8_t subtype,
const uint32_t *payload, uint8_t len) {
volatile struct mg_rw612_msg *m;
uint64_t expire = mg_millis() + 100;
uint8_t i;
while ((MGI_IMU->STATUS & (MGI_IMU_ALMOST_FULL | MGI_IMU_LOCKED)) &&
mg_millis() < expire) {
(void) 0;
}
m = &MGI_MBOX->q[1][MGI_IMU_WR_PTR(MGI_IMU->STATUS)];
m->type = type, m->subtype = subtype, m->seq = s_rw612.seq++, m->len = len;
for (i = 0; i < len; i++) m->payload[i] = payload[i];
MGI_IMU->WR_MSG = (uint32_t) (uintptr_t) m;
}
static void mg_rw612_control(uint8_t subtype, uint32_t a, uint32_t b,
uint8_t len) {
uint32_t payload[2] = {a, b};
mg_rw612_imu_send(MGI_MSG_CONTROL, subtype, payload, len);
}
static void mg_rw612_queue_rx(const uint8_t *frame, size_t len) {
struct mg_rw612 *s = &s_rw612;
uint8_t next = (uint8_t) ((s->rxhead + 1) % MGI_RXQ_CNT);
if (next == s->rxtail || len > sizeof(s->rxq[0])) return; // Full: drop
memcpy(s->rxq[s->rxhead], frame, len);
s->rxlen[s->rxhead] = (uint8_t) len;
s->rxhead = next;
}
// Spinel packed unsigned integer: 7 bits per byte, LSB first
static size_t mg_rw612_unpack(const uint8_t *p, size_t len, uint32_t *v) {
size_t i;
*v = 0;
for (i = 0; i < len && i < 4; i++) {
*v |= (uint32_t) (p[i] & 0x7f) << (7 * i);
if ((p[i] & 0x80) == 0) return i + 1;
}
return 0;
}
// Handle a received Spinel frame: header, command, property, value
static void mg_rw612_spinel(const uint8_t *f, size_t len) {
struct mg_rw612 *s = &s_rw612;
uint32_t cmd, prop, status = 0;
size_t n, ofs = 1;
uint8_t tid = f[0] & 15;
if (len < 3 || (n = mg_rw612_unpack(f + ofs, len - ofs, &cmd)) == 0) return;
ofs += n;
if ((n = mg_rw612_unpack(f + ofs, len - ofs, &prop)) == 0) return;
ofs += n;
if (cmd != MGI_CMD_IS) return;
if (prop == MGI_PROP_STREAM_RAW && tid == 0 && len - ofs >= 2) {
size_t flen = (size_t) (f[ofs] | (f[ofs + 1] << 8)); // Incl. FCS
if (flen >= 2 && ofs + 2 + flen <= len) {
mg_rw612_queue_rx(f + ofs + 2, flen - 2);
}
} else if (prop == MGI_PROP_LAST_STATUS) {
mg_rw612_unpack(f + ofs, len - ofs, &status);
if (tid == 0 && status >= MGI_STATUS_RESET_MIN &&
status <= MGI_STATUS_RESET_MAX) {
s->reset = true;
}
} else if (prop == MGI_PROP_NCP_VERSION) {
n = len - ofs < sizeof(s->version) - 1 ? len - ofs : sizeof(s->version) - 1;
memcpy(s->version, f + ofs, n);
s->version[n] = '\0';
}
if (tid != 0 && tid == s->tid) s->rsp = true, s->rsp_status = status;
}
// HDLC-lite: 0x7e delimits frames, 0x7d escapes, FCS-16 at the end
static uint16_t mg_rw612_fcs(uint16_t fcs, uint8_t c) {
int i;
fcs ^= c;
for (i = 0; i < 8; i++) fcs = (fcs & 1) ? (fcs >> 1) ^ 0x8408 : fcs >> 1;
return fcs;
}
static void mg_rw612_hdlc_rx(const uint8_t *p, size_t len) {
struct mg_rw612 *s = &s_rw612;
size_t i, j;
for (i = 0; i < len; i++) {
uint8_t c = p[i];
if (c == 0x7e) {
if (s->hlen >= 3) {
uint16_t fcs = 0xffff;
for (j = 0; j < s->hlen; j++) fcs = mg_rw612_fcs(fcs, s->hdlc[j]);
if (fcs == 0xf0b8) mg_rw612_spinel(s->hdlc, s->hlen - 2);
}
s->hlen = 0, s->esc = false;
} else if (c == 0x7d) {
s->esc = true;
} else if (s->hlen < sizeof(s->hdlc)) {
s->hdlc[s->hlen++] = s->esc ? c ^ 0x20 : c;
s->esc = false;
}
}
}
static void mg_rw612_control_rx(volatile struct mg_rw612_msg *m) {
struct mg_rw612 *s = &s_rw612;
switch (m->subtype) {
case MGI_CTL_ACK_FOR_UNLOCK:
MGI_IMU->CNTL &= ~MGI_IMU_WAIT_FOR_ACK;
break;
case MGI_CTL_SYNC: // As HAL_ImuCtrlHandler(): acknowledge twice
mg_rw612_control(MGI_CTL_SYNC_ACK, 0, 0, 0);
mg_rw612_control(MGI_CTL_SYNC_ACK, 0, 0, 0);
s->up = true;
break;
case MGI_CTL_SYNC_ACK:
case MGI_CTL_CMD_BUF_ADDR:
s->up = true;
break;
case MGI_CTL_EPT_QUERY: { // Firmware asks if our endpoint exists
bool ours = m->payload[0] == MGI_EPT_LOCAL;
mg_rw612_control(MGI_CTL_EPT_QUERY_RSP, m->payload[0], ours, 2);
if (ours) s->ept_ready = true;
break;
}
case MGI_CTL_EPT_QUERY_RSP:
if (m->payload[0] == MGI_EPT_REMOTE && m->payload[1] != 0) {
s->ept_ready = true;
}
break;
case MGI_CTL_BUF_FREE: { // Firmware is done with one of our buffers
uint32_t i = (m->payload[0] - MGI_TXBUF) / MGI_TXBUF_LEN;
if (i < MGI_TXBUF_CNT) s->free_bufs |= (uint16_t) MG_BIT(i);
break;
}
default:
break;
}
}
// Process all received IMU messages. See HAL_ImuReceive()
static void mg_rw612_poll_imu(void) {
bool unlock = false;
while ((MGI_IMU_PEER->STATUS & MGI_IMU_EMPTY) == 0) {
struct mg_rw612_msg m;
volatile struct mg_rw612_msg *p;
uint8_t i;
MGI_SLEEP_FLAG &= ~1U;
p = (volatile struct mg_rw612_msg *) (uintptr_t) MGI_IMU->RD_MSG;
if (MGI_IMU_PEER->STATUS & MGI_IMU_LOCKED) unlock = true;
if (p == NULL) continue;
m.type = p->type, m.subtype = p->subtype, m.len = p->len;
for (i = 0; i < 8; i++) m.payload[i] = p->payload[i];
if (m.type == MGI_MSG_CONTROL) {
mg_rw612_control_rx(&m);
} else if (m.type == MGI_MSG_IMUMC) {
struct mg_rw612_imumc im;
memcpy(&im, m.payload, sizeof(im));
if (im.dst == MGI_EPT_LOCAL) {
mg_rw612_hdlc_rx((const uint8_t *) (uintptr_t) im.data, im.len);
}
mg_rw612_control(MGI_CTL_BUF_FREE, im.data, 0, 1);
}
}
MGI_IMU->CNTL |= MGI_IMU_INT_CLR;
MGI_SLEEP_FLAG |= 1U;
if (unlock) mg_rw612_control(MGI_CTL_ACK_FOR_UNLOCK, 0, 0, 0);
}
// Send bytes to the firmware endpoint, in IMUMC buffer sized chunks
static bool mg_rw612_imumc_send(const uint8_t *p, size_t len) {
struct mg_rw612 *s = &s_rw612;
while (len > 0) {
size_t n = len < MGI_TXBUF_LEN ? len : MGI_TXBUF_LEN;
uint64_t expire = mg_millis() + 100;
struct mg_rw612_imumc im;
uint32_t i;
while (s->free_bufs == 0) {
mg_rw612_poll_imu();
if (mg_millis() > expire) return false;
}
for (i = 0; (s->free_bufs & MG_BIT(i)) == 0; i++) (void) 0;
s->free_bufs &= (uint16_t) ~MG_BIT(i);
memset(&im, 0, sizeof(im));
im.src = MGI_EPT_LOCAL, im.dst = MGI_EPT_REMOTE, im.len = (uint16_t) n;
im.data = MGI_TXBUF + i * MGI_TXBUF_LEN;
memcpy((void *) (uintptr_t) im.data, p, n);
mg_rw612_imu_send(MGI_MSG_IMUMC, 0, (uint32_t *) &im, sizeof(im) / 4);
p += n, len -= n;
}
return true;
}
// Send a Spinel frame, HDLC encoded, and wait for the response with the
// same transaction ID. Return false on timeout
static bool mg_rw612_request(uint8_t *f, size_t len, uint32_t timeout_ms) {
struct mg_rw612 *s = &s_rw612;
uint8_t buf[2 * 160 + 6];
uint16_t fcs = 0xffff;
size_t i, n = 0;
uint64_t expire = mg_millis() + timeout_ms;
s->tid = (uint8_t) (s->tid % 15 + 1);
f[0] = (uint8_t) (0x80 | s->tid); // Header: flag, interface 0, TID
s->rsp = false;
buf[n++] = 0x7e;
for (i = 0; i < len + 2 && n + 3 < sizeof(buf); i++) {
uint8_t c;
if (i < len) {
c = f[i], fcs = mg_rw612_fcs(fcs, c);
} else {
c = (uint8_t) (i == len ? ~fcs & 0xff : ~fcs >> 8);
}
if (c == 0x7e || c == 0x7d || c == 0x11 || c == 0x13 || c == 0xf8) {
buf[n++] = 0x7d, c ^= 0x20;
}
buf[n++] = c;
}
buf[n++] = 0x7e;
if (!mg_rw612_imumc_send(buf, n)) return false;
while (!s->rsp && mg_millis() < expire) mg_rw612_poll_imu();
return s->rsp;
}
static bool mg_rw612_set(uint32_t prop, const uint8_t *val, size_t len) {
uint8_t f[16];
if (len > sizeof(f) - 3) return false;
f[1] = MGI_CMD_SET, f[2] = (uint8_t) prop; // Properties used are < 0x80
memcpy(f + 3, val, len);
return mg_rw612_request(f, len + 3, MGI_RSP_TIMEOUT_MS) &&
s_rw612.rsp_status == 0;
}
// Log an init error, return false
static bool mg_rw612_fail(const char *msg) {
MG_ERROR(("%s", msg));
return false;
}
static bool mg_rw612_154_init(struct mg_tcpip_if *ifp) {
struct mg_rw612 *s = &s_rw612;
struct mg_l2_802154_data *d =
(struct mg_l2_802154_data *) ifp->driver_data;
uint8_t f[8], one = 1, pan[2];
uint64_t expire;
if (d == NULL || d->channel < 11 || d->channel > 26) {
MG_ERROR(("Set driver_data, channel 11..26"));
return false;
}
if (MGI_MBOX->magic[0] != MGI_SYNC_MAGIC) {
MG_ERROR(("Radio firmware is not running on CPU2"));
return false;
}
memset(s, 0, sizeof(*s));
s->free_bufs = 0xffff;
// Reset our send FIFO, drop stale messages. See IMU_Init()
MGI_IMU->CNTL |= MGI_IMU_FLUSH;
MGI_IMU->CNTL &= ~(MGI_IMU_FLUSH | MGI_IMU_WAIT_FOR_ACK);
MGI_IMU->CNTL = (MGI_IMU->CNTL & ~MGI_IMU_WATERMARK_MASK) |
MGI_IMU_WATERMARK(15);
while ((MGI_IMU_PEER->STATUS & MGI_IMU_EMPTY) == 0) (void) MGI_IMU->RD_MSG;
// Synchronise the IMU link, then connect the IMUMC endpoints
MGI_MBOX->magic[1] = MGI_SYNC_MAGIC;
mg_rw612_control(MGI_CTL_SYNC, 0, 0, 0);
expire = mg_millis() + 1000;
while (!s->up && mg_millis() < expire) mg_rw612_poll_imu();
if (!s->up) return mg_rw612_fail("IMU sync timeout");
expire = mg_millis() + 2000;
while (!s->ept_ready && mg_millis() < expire) {
uint64_t retry = mg_millis() + 100;
mg_rw612_control(MGI_CTL_EPT_QUERY, MGI_EPT_REMOTE, 0, 1);
while (!s->ept_ready && mg_millis() < retry) mg_rw612_poll_imu();
}
if (!s->ept_ready) return mg_rw612_fail("IMUMC endpoint timeout");
// Reset the RCP stack, wait for its reset status, read its version
f[1] = MGI_CMD_RESET, f[2] = MGI_RESET_STACK;
mg_rw612_request(f, 3, MGI_RSP_TIMEOUT_MS);
expire = mg_millis() + 1000;
while (!s->reset && mg_millis() < expire) mg_rw612_poll_imu();
if (!s->reset) return mg_rw612_fail("RCP reset timeout");
f[1] = MGI_CMD_GET, f[2] = MGI_PROP_NCP_VERSION;
mg_rw612_request(f, 3, MGI_RSP_TIMEOUT_MS);
MG_INFO(("RCP: %s", s->version));
if (!mg_rw612_set(MGI_PROP_PHY_ENABLED, &one, 1)) {
return mg_rw612_fail("PHY enable failed");
}
pan[0] = (uint8_t) d->pan_id, pan[1] = (uint8_t) (d->pan_id >> 8);
if (!mg_rw612_set(MGI_PROP_PHY_CHAN, &d->channel, 1) ||
!mg_rw612_set(MGI_PROP_PANID, pan, 2)) {
return mg_rw612_fail("Channel or PAN ID set failed");
}
if (!mg_rw612_set(MGI_PROP_RAW_STREAM, &one, 1)) {
return mg_rw612_fail("Raw stream enable failed");
}
return true;
}
// Send one radio frame: MAC header and payload, no FCS
static size_t mg_rw612_send(const uint8_t *p, size_t len,
struct mg_tcpip_if *ifp) {
struct mg_l2_802154_data *d =
(struct mg_l2_802154_data *) ifp->driver_data;
uint8_t f[3 + 2 + 127 + 4];
size_t n = 3;
f[1] = MGI_CMD_SET, f[2] = MGI_PROP_STREAM_RAW;
f[n++] = (uint8_t) (len + 2), f[n++] = 0; // PSDU length, incl. FCS
memcpy(f + n, p, len), n += len;
f[n++] = 0, f[n++] = 0; // FCS, filled in by the radio
f[n++] = d->channel;
f[n++] = 4; // Max CSMA backoffs
f[n++] = 0; // Max frame retries: broadcast frames are not acknowledged
f[n++] = 1; // CSMA-CA enabled
if (!mg_rw612_request(f, n, MGI_TX_TIMEOUT_MS)) {
MG_ERROR(("TX timeout"));
return 0;
}
if (s_rw612.rsp_status != 0) {
MG_VERBOSE(("TX failed, status %lu", (unsigned long) s_rw612.rsp_status));
return 0;
}
return len;
}
static size_t mg_rw612_154_tx(const void *buf, size_t len,
struct mg_tcpip_if *ifp) {
return mg_l2_802154_tx(ifp, buf, len, mg_rw612_send);
}
static size_t mg_rw612_154_rx(void *buf, size_t len, struct mg_tcpip_if *ifp) {
struct mg_rw612 *s = &s_rw612;
size_t res = 0;
mg_rw612_poll_imu();
while (s->rxtail != s->rxhead && res == 0) {
res = mg_l2_802154_rx(ifp, s->rxq[s->rxtail], s->rxlen[s->rxtail], buf,
len);
s->rxtail = (uint8_t) ((s->rxtail + 1) % MGI_RXQ_CNT);
}
return res;
}
static bool mg_rw612_154_poll(struct mg_tcpip_if *ifp, bool s1) {
(void) ifp, (void) s1;
return s_rw612.up;
}
struct mg_tcpip_driver mg_tcpip_driver_rw612_154 = {
mg_rw612_154_init, mg_rw612_154_tx, mg_rw612_154_rx, mg_rw612_154_poll};
#endif
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_RW612_154) && \
MG_ENABLE_DRIVER_RW612_154
// NXP RW612 IEEE 802.15.4 radio, as an Ethernet interface: Ethernet frames
// are split into radio frames, see mg_l2_802154_tx(). The radio runs on
// CPU2: NXP BLE/802.15.4 combo firmware, an OpenThread radio co-processor
// (RCP). The firmware must be loaded and running before mg_tcpip_init(), see
// the FRDM-RW612 eth_radio_bridge tutorial. The driver talks to it over the
// CPU2 <-> CPU3 IMU mailbox: IMUMC messages carrying HDLC framed Spinel.
// driver_data: struct mg_l2_802154_data, channel and PAN ID set
#ifndef MG_TCPIP_DRIVER_INIT
#define MG_TCPIP_DRIVER_INIT(mgr) \
do { \
static struct mg_l2_802154_data driver_data_; \
static struct mg_tcpip_if mif_; \
driver_data_.channel = MG_L2_802154_CHANNEL; \
driver_data_.pan_id = MG_L2_802154_PAN_ID; \
mif_.driver = &mg_tcpip_driver_rw612_154; \
mif_.driver_data = &driver_data_; \
MG_SET_MAC_ADDRESS(mif_.mac); \
mg_tcpip_init(mgr, &mif_); \
MG_INFO(("Driver: rw612_154, channel %d", MG_L2_802154_CHANNEL)); \
} while (0)
#endif
#endif
+1 -1
View File
@@ -365,7 +365,7 @@ static bool st67w6_init(uint8_t *mac) {
} }
// set clock, who cares ??? // set clock, who cares ???
if (!st67w6_at_cmd("AT+GET_CLOCK\r\n", 14)) return false; if (!st67w6_at_cmd("AT+GET_CLOCK\r\n", 14)) return false;
MG_DEBUG(("%.*s", s_at_resp_len, at_resp)); // TODO(scaprile): --> VERBOSE MG_VERBOSE(("%.*s", s_at_resp_len, at_resp));
// BT-ENABLED DEPENDENCY // BT-ENABLED DEPENDENCY
// MODULE DEPENDENCY // MODULE DEPENDENCY
+6 -3
View File
@@ -2,6 +2,7 @@
#if MG_ENABLE_TCPIP && (MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN || \ #if MG_ENABLE_TCPIP && (MG_ENABLE_DRIVER_STM32H || MG_ENABLE_DRIVER_MCXN || \
MG_ENABLE_DRIVER_STM32N) MG_ENABLE_DRIVER_STM32N)
// STM32C: vendor modded single-queue Synopsys v5.4, same settings as STM32H
// STM32H: vendor modded single-queue Synopsys v4.2 // STM32H: vendor modded single-queue Synopsys v4.2
// STM32N: dual-queue GbE Synopsys v5.2 with no hash table option, 64-bit AXI // STM32N: dual-queue GbE Synopsys v5.2 with no hash table option, 64-bit AXI
// MCXNx4x: dual-queue Synopsys v5.2 with no hash table option // MCXNx4x: dual-queue Synopsys v5.2 with no hash table option
@@ -310,7 +311,7 @@ static uint32_t s_rxno;
#if MG_ENABLE_DRIVER_MCXN #if MG_ENABLE_DRIVER_MCXN
void ETHERNET_IRQHandler(void); void ETHERNET_IRQHandler(void);
void ETHERNET_IRQHandler(void) { void ETHERNET_IRQHandler(void) {
#elif MG_ENABLE_DRIVER_STM32H #elif MG_ENABLE_DRIVER_STM32H && !MG_ENABLE_DRIVER_STM32C
void ETH_IRQHandler(void); void ETH_IRQHandler(void);
void ETH_IRQHandler(void) { void ETH_IRQHandler(void) {
#else #else
@@ -339,8 +340,10 @@ void ETH1_IRQHandler(void) {
} }
ETH->DMACSR = ETH->DMACSR =
MG_BIT(7) | MG_BIT(8); // Clear possible RBU RPS while processing MG_BIT(7) | MG_BIT(8); // Clear possible RBU RPS while processing
ETH->DMACRDTPR = // Resume RX: tail is the last descriptor given back to DMA. It must differ
(uint32_t) (uintptr_t) &s_rxdesc[ETH_DESC_CNT - 1]; // and resume RX // from the DMA current descriptor, or some DMAs, e.g. STM32C5, stay suspended
ETH->DMACRDTPR = (uint32_t) (uintptr_t) &s_rxdesc[(s_rxno + ETH_DESC_CNT - 1) %
ETH_DESC_CNT];
} }
struct mg_tcpip_driver mg_tcpip_driver_stm32h = { struct mg_tcpip_driver mg_tcpip_driver_stm32h = {
+11 -2
View File
@@ -4,6 +4,13 @@
#if !defined(MG_ENABLE_DRIVER_STM32H) #if !defined(MG_ENABLE_DRIVER_STM32H)
#define MG_ENABLE_DRIVER_STM32H 0 #define MG_ENABLE_DRIVER_STM32H 0
#endif #endif
#if !defined(MG_ENABLE_DRIVER_STM32C)
#define MG_ENABLE_DRIVER_STM32C 0
#endif
#if MG_ENABLE_DRIVER_STM32C // STM32C5: STM32H5 MAC, the IRQ is ETH1
#undef MG_ENABLE_DRIVER_STM32H
#define MG_ENABLE_DRIVER_STM32H 1
#endif
#if !defined(MG_ENABLE_DRIVER_MCXN) #if !defined(MG_ENABLE_DRIVER_MCXN)
#define MG_ENABLE_DRIVER_MCXN 0 #define MG_ENABLE_DRIVER_MCXN 0
#endif #endif
@@ -43,9 +50,11 @@ struct mg_tcpip_driver_stm32h_data {
#define MG_DRIVER_MDC_CR 4 #define MG_DRIVER_MDC_CR 4
#endif #endif
#if MG_ENABLE_DRIVER_STM32H && MG_ARCH == MG_ARCH_CUBE && !defined(MG_ENABLE_ETH_IRQ) #if MG_ENABLE_DRIVER_STM32H && !MG_ENABLE_DRIVER_STM32C && \
MG_ARCH == MG_ARCH_CUBE && !defined(MG_ENABLE_ETH_IRQ)
#define MG_ENABLE_ETH_IRQ() NVIC_EnableIRQ(ETH_IRQn) #define MG_ENABLE_ETH_IRQ() NVIC_EnableIRQ(ETH_IRQn)
#elif MG_ENABLE_DRIVER_STM32N && MG_ARCH == MG_ARCH_CUBE && !defined(MG_ENABLE_ETH_IRQ) #elif (MG_ENABLE_DRIVER_STM32N || MG_ENABLE_DRIVER_STM32C) && \
MG_ARCH == MG_ARCH_CUBE && !defined(MG_ENABLE_ETH_IRQ)
#define MG_ENABLE_ETH_IRQ() NVIC_EnableIRQ(ETH1_IRQn) #define MG_ENABLE_ETH_IRQ() NVIC_EnableIRQ(ETH1_IRQn)
#elif !defined(MG_ENABLE_ETH_IRQ) #elif !defined(MG_ENABLE_ETH_IRQ)
#define MG_ENABLE_ETH_IRQ() #define MG_ENABLE_ETH_IRQ()
+1 -1
View File
@@ -6,7 +6,7 @@
struct mg_health mg_health_record MG_HEALTH_RAM; struct mg_health mg_health_record MG_HEALTH_RAM;
// STM32 H723 support. Needs the _estack symbol from the linker script // STM32 H723 support. Needs the _estack symbol from the linker script
#if MG_ENABLE_HEALTH && (defined(STM32H7_DEV_ID) || defined(STM32H5)) #if MG_ENABLE_HEALTH && (defined(STM32H7_DEV_ID) || defined(STM32H5) || defined(STM32C5))
// Fault handler body. Runs in exception context: no printf, no malloc, no // Fault handler body. Runs in exception context: no printf, no malloc, no
// blocking calls. Copies the unwind registers and raw stack into the health // blocking calls. Copies the unwind registers and raw stack into the health
// record, then resets. // record, then resets.
+2 -19
View File
@@ -5,32 +5,15 @@
#include "arch.h" #include "arch.h"
#include "printf.h" #include "printf.h"
// Memory usage in bytes. Override in mongoose_config.h for the target.
#ifndef MG_HEALTH_STACK_USED
#define MG_HEALTH_STACK_USED 0
#endif
#ifndef MG_HEALTH_STACK_TOTAL
#define MG_HEALTH_STACK_TOTAL 0
#endif
#ifndef MG_HEALTH_HEAP_USED
#define MG_HEALTH_HEAP_USED 0
#endif
#ifndef MG_HEALTH_HEAP_TOTAL
#define MG_HEALTH_HEAP_TOTAL 0
#endif
#ifndef MG_HEALTH_MAGIC #ifndef MG_HEALTH_MAGIC
#define MG_HEALTH_MAGIC {'M', 'G', 'H', '3'} // '3' is the layout version #define MG_HEALTH_MAGIC {'M', 'G', 'H', '3'} // '3' is the layout version
#endif #endif
#if !defined(MG_HEALTH_RAM) && (defined(STM32H7_DEV_ID) || defined(STM32H5)) #if !defined(MG_HEALTH_RAM) && (defined(STM32H7_DEV_ID) || defined(STM32H5) || defined(STM32C5))
#define MG_HEALTH_RAM __attribute__((section(".mg_health"))) #define MG_HEALTH_RAM __attribute__((section(".mg_health")))
#endif #endif
#if !defined(MG_HEALTH_DATA_SIZE) && (defined(STM32H7_DEV_ID) || defined(STM32H5)) #if !defined(MG_HEALTH_DATA_SIZE) && (defined(STM32H7_DEV_ID) || defined(STM32H5) || defined(STM32C5))
#define MG_HEALTH_DATA_SIZE 250 #define MG_HEALTH_DATA_SIZE 250
#endif #endif
+43 -33
View File
@@ -879,8 +879,8 @@ void mg_http_serve_upload(struct mg_connection *c, struct mg_http_message *hm,
fs->rm(path); // MG_FS_WRITE appends, not truncates: drop any old file fs->rm(path); // MG_FS_WRITE appends, not truncates: drop any old file
if ((fd = mg_fs_open(fs, path, MG_FS_WRITE)) == NULL) { if ((fd = mg_fs_open(fs, path, MG_FS_WRITE)) == NULL) {
MG_ERROR(("Cannot open %s for upload", path)); MG_ERROR(("Cannot open %s for upload", path));
} else if (!mg_http_stream_body(c, hm, serve_upload_cb, fd)) { } else {
mg_fs_close(fd); mg_http_stream_body(c, hm, serve_upload_cb, fd);
} }
} }
} }
@@ -1014,6 +1014,7 @@ struct mg_upload_state {
size_t received; // Number of body bytes received so far size_t received; // Number of body bytes received so far
void *user_data; // Passed to cb, free for cb to use void *user_data; // Passed to cb, free for cb to use
bool failed; // Set when cb returned false bool failed; // Set when cb returned false
bool finished; // End callback has been called
}; };
// Event handler installed by mg_http_stream_body(). Feeds the body to the // Event handler installed by mg_http_stream_body(). Feeds the body to the
@@ -1021,18 +1022,18 @@ struct mg_upload_state {
// handler: the connection is closed after the reply. // handler: the connection is closed after the reply.
static void mg_stream_handler(struct mg_connection *c, int ev, void *ev_data) { static void mg_stream_handler(struct mg_connection *c, int ev, void *ev_data) {
struct mg_upload_state *us = (struct mg_upload_state *) c->data; struct mg_upload_state *us = (struct mg_upload_state *) c->data;
bool (*fn)(struct mg_http_message *, struct mg_str *, void **) = bool (*fn)(struct mg_http_message *, struct mg_str *, void **) =
(bool (*)(struct mg_http_message *, struct mg_str *, void **)) (bool (*)(struct mg_http_message *, struct mg_str *, void **))
(ptrdiff_t) c->fn_data; (ptrdiff_t) c->fn_data;
(void) ev_data; (void) ev_data;
if (ev == MG_EV_CLOSE || ev == MG_EV_ERROR) { if (ev == MG_EV_CLOSE || ev == MG_EV_ERROR) {
if (us->received < us->expected) { if (!us->finished) {
// Connection dropped mid-upload. Let cb clean up, e.g. call mg_ota_end() // Connection dropped mid-upload. Let cb clean up, e.g. call mg_ota_end()
us->received = us->expected; // MG_EV_ERROR is followed by MG_EV_CLOSE us->finished = true; // MG_EV_ERROR is followed by MG_EV_CLOSE
fn(NULL, NULL, &us->user_data); fn(NULL, NULL, &us->user_data);
} }
} else if (ev == MG_EV_READ && !c->is_draining) { } else if (ev == MG_EV_READ && !c->is_draining && !us->finished) {
if (c->recv.len > 0 && us->received < us->expected) { if (!us->failed && c->recv.len > 0 && us->received < us->expected) {
// Got some uploaded data. Feed by 512-byte aligned chunks, for OTA // Got some uploaded data. Feed by 512-byte aligned chunks, for OTA
size_t left = us->expected - us->received, r = c->recv.len; size_t left = us->expected - us->received, r = c->recv.len;
size_t aligned = r < left ? MG_ROUND_DOWN(r, 512) : left; size_t aligned = r < left ? MG_ROUND_DOWN(r, 512) : left;
@@ -1043,10 +1044,13 @@ static void mg_stream_handler(struct mg_connection *c, int ev, void *ev_data) {
us->received += aligned; us->received += aligned;
mg_iobuf_del(&c->recv, 0, aligned); // Shift the unprocessed tail mg_iobuf_del(&c->recv, 0, aligned); // Shift the unprocessed tail
} }
if (us->received >= us->expected) { if (!us->finished && (us->failed || us->received >= us->expected)) {
// Finished upload. Always call cb, even after error, so it can clean up // Finished upload. Always call cb, even after error, so it can clean up
us->finished = true;
us->failed |= !fn(NULL, NULL, &us->user_data); us->failed |= !fn(NULL, NULL, &us->user_data);
if (!c->is_client) { if (c->is_client && us->failed) {
mg_error(c, "Body streaming failed");
} else if (!c->is_client) {
mg_http_reply(c, us->failed ? 500 : 200, NULL, "%zu %s\n", mg_http_reply(c, us->failed ? 500 : 200, NULL, "%zu %s\n",
us->received, us->failed ? "fail" : "ok"); us->received, us->failed ? "fail" : "ok");
} }
@@ -1055,48 +1059,54 @@ static void mg_stream_handler(struct mg_connection *c, int ev, void *ev_data) {
} }
} }
bool mg_http_stream_body(struct mg_connection *c, struct mg_http_message *hm, void mg_http_stream_body(struct mg_connection *c, struct mg_http_message *hm,
bool (*cb)(struct mg_http_message *, struct mg_str *, bool (*cb)(struct mg_http_message *, struct mg_str *,
void **user_data), void **),
void *user_data) { void *user_data) {
struct mg_upload_state *us = (struct mg_upload_state *) c->data; struct mg_upload_state *us = (struct mg_upload_state *) c->data;
struct mg_str *te = mg_http_get_header(hm, "Transfer-Encoding"); int code = 0;
bool handled = false; size_t head_len = hm->head.len;
// Catch upload requests early, without buffering whole body. Called on the // Catch upload requests early, without buffering whole body. Called on the
// MG_EV_HTTP_HDRS event: we've received all HTTP headers but not necessarily // MG_EV_HTTP_HDRS event: we've received all HTTP headers but not necessarily
// the full HTTP body // the full HTTP body
if (hm->body.len == (size_t) ~0 || if (!c->is_client && mg_strcmp(hm->method, mg_str("POST")) != 0 &&
(te != NULL && mg_strcasecmp(*te, mg_str("chunked")) == 0)) { mg_strcmp(hm->method, mg_str("PUT")) != 0) {
// Unknown length or chunked, cannot stream. Leave it to the caller code = 405;
} else if (!c->is_client && } else if (mg_http_get_header(hm, "Transfer-Encoding") != NULL) {
mg_strcmp(hm->method, mg_str("POST")) != 0 && code = 400;
mg_strcmp(hm->method, mg_str("PUT")) != 0) { } else if (hm->body.len == (size_t) ~0 ||
// Not an upload request. Leave it to the caller (!c->is_client && mg_http_get_header(hm, "Content-Length") == NULL)) {
code = 411;
} else if (sizeof(*us) > sizeof(c->data)) { } else if (sizeof(*us) > sizeof(c->data)) {
if (!c->is_client) { // Nobody to reply to on a client connection code = 500;
c->pfn = NULL; }
mg_http_reply(c, 500, NULL, "data too small\n"); c->pfn = NULL; // Take ownership even when validation fails
c->is_draining = 1; if (code != 0) {
cb(NULL, NULL, &user_data); // Let cb release user_data, start skipped c->fn = NULL;
handled = true; c->fn_data = NULL;
mg_iobuf_del(&c->recv, 0, c->recv.len);
cb(NULL, NULL, &user_data); // Release resources even if start was skipped
if (c->is_client) {
mg_error(c, "%s", mg_http_status_code_str(code));
} else {
mg_http_reply(c, code, code == 405 ? "Allow: POST, PUT\r\n" : NULL, "");
} }
c->is_draining = 1;
} else { } else {
c->pfn = NULL; // Silence HTTP protocol handler
memset(us, 0, sizeof(*us)); memset(us, 0, sizeof(*us));
us->expected = hm->body.len; // Store number of bytes we expect us->expected = hm->body.len; // Store number of bytes we expect
us->user_data = user_data; us->user_data = user_data;
c->fn = mg_stream_handler;
c->fn_data = (void *) (ptrdiff_t) cb;
us->failed = !cb(hm, NULL, &us->user_data); // Call before deleting headers us->failed = !cb(hm, NULL, &us->user_data); // Call before deleting headers
if (mg_http_get_header(hm, "Expect") != NULL) { if (!c->is_client && !us->failed && !us->finished &&
mg_http_get_header(hm, "Expect") != NULL) {
mg_http_reply(c, 100, NULL, ""); // If curl expects, we continue mg_http_reply(c, 100, NULL, ""); // If curl expects, we continue
} }
mg_iobuf_del(&c->recv, 0, hm->head.len); // Delete HTTP headers mg_iobuf_del(&c->recv, 0, head_len); // Delete HTTP headers
c->fn = mg_stream_handler; // We own the connection from now
c->fn_data = (void *) (ptrdiff_t) cb;
mg_call(c, MG_EV_READ, &c->recv.len); // Process the body bytes we have mg_call(c, MG_EV_READ, &c->recv.len); // Process the body bytes we have
handled = true;
} }
return handled;
} }
static bool is_hex_digit(int c) { static bool is_hex_digit(int c) {
+14 -11
View File
@@ -205,29 +205,32 @@ int mg_http_status(const struct mg_http_message *hm);
// Streams a POST/PUT body to a callback as it arrives, without buffering it. // Streams a POST/PUT body to a callback as it arrives, without buffering it.
// Call it from an MG_EV_HTTP_HDRS handler, after matching the request, e.g. // Call it from an MG_EV_HTTP_HDRS handler, after matching the request, e.g.
// with mg_match(). Returns true if it took over the connection, false if the // with mg_match(). Always takes over the connection. Invalid requests receive
// request is not POST/PUT, is chunked, or has no Content-Length. // an HTTP error; client-side failures call mg_error(). Replies and connection
// draining are handled internally, including callback failures.
// //
// Callback upload_fn(hm, data, user_data) is called: // Callback upload_fn(hm, data, user_data) is called:
// - at start: hm is set. Open the file, set *user_data. // - at start: hm is set. Open the file, set *user_data.
// - per chunk: data is set, 512 byte aligned except the last. Not called // - per chunk: data is set, 512 byte aligned except the last. Not called
// again after a failure. // again after a failure.
// - at end: both NULL. Always called once, also when the connection drops // - at end: both NULL. Always called exactly once, including validation
// early, so release resources here. A truncated body looks like a complete // failures before start and connections that drop early. Release resources
// one: validate before committing. // here. A truncated body looks like a complete one: validate before
// Return true on success, false on error. // committing.
// The callback returns true on success, false on error. A failure stops
// streaming immediately and calls the end callback before closing.
// Example: // Example:
// if (ev == MG_EV_HTTP_HDRS && mg_match(hm->uri, mg_str("/fs/*"), NULL) { // if (ev == MG_EV_HTTP_HDRS && mg_match(hm->uri, mg_str("/fs/*"), NULL)) {
// mg_http_stream_body(c, hm, upload, NULL)); // mg_http_stream_body(c, hm, upload, NULL);
// } // }
// Full example: // Full example:
// tutorials/http/file-upload-single-post // tutorials/http/file-upload-single-post
// Related APIs: // Related APIs:
// mg_http_listen(), mg_http_next_multipart() // mg_http_listen(), mg_http_next_multipart()
// Notes: // Notes:
// After it returns true, this function hijacks the connection. Existing event // The existing event handler is no longer called. hm is invalid after this
// handler not called, hm is invalid, c->data and c->fn_data are modified // call; c->data and c->fn_data are reserved for streaming state.
bool mg_http_stream_body(struct mg_connection *c, struct mg_http_message *hm, void mg_http_stream_body(struct mg_connection *c, struct mg_http_message *hm,
bool (*upload_fn)(struct mg_http_message *, bool (*upload_fn)(struct mg_http_message *,
struct mg_str *, void **user_data), struct mg_str *, void **user_data),
void *user_data); void *user_data);
+60
View File
@@ -0,0 +1,60 @@
#include "l2.h"
#include "net_builtin.h"
#if MG_ENABLE_TCPIP
// Radio frame: 802.15.4 MAC header, 15 bytes: data frame, PAN ID compression,
// broadcast destination, our EUI-64 made from MAC as source. Then 2 bytes:
// tag, fragment index << 4 | last fragment index. Then data. 125 bytes max,
// 127 minus FCS
#define MGI_802154_HDR 17
#define MGI_802154_DATA (125 - MGI_802154_HDR)
size_t mg_l2_802154_tx(struct mg_tcpip_if *ifp, const void *buf, size_t len,
size_t (*send_fn)(const uint8_t *, size_t,
struct mg_tcpip_if *)) {
struct mg_l2_802154_data *d =
(struct mg_l2_802154_data *) ifp->driver_data;
const uint8_t *p = (const uint8_t *) buf, *m = ifp->mac;
uint8_t f[MGI_802154_HDR + MGI_802154_DATA];
size_t i, n, last = (len - 1) / MGI_802154_DATA;
if (len == 0 || last > 15) return 0;
d->tag++;
for (i = 0; i <= last; i++) {
n = i == last ? len - i * MGI_802154_DATA : MGI_802154_DATA;
f[0] = 0x41, f[1] = 0xd8, f[2] = d->seq++; // 2006 frame, see above
f[3] = (uint8_t) d->pan_id, f[4] = (uint8_t) (d->pan_id >> 8);
f[5] = f[6] = 0xff;
f[7] = m[5], f[8] = m[4], f[9] = m[3], f[10] = 0xfe, f[11] = 0xff;
f[12] = m[2], f[13] = m[1], f[14] = m[0]; // Little endian EUI-64
f[15] = d->tag, f[16] = (uint8_t) ((i << 4) | last);
memcpy(f + MGI_802154_HDR, p + i * MGI_802154_DATA, n);
if (send_fn(f, MGI_802154_HDR + n, ifp) == 0) return 0;
}
return len;
}
size_t mg_l2_802154_rx(struct mg_tcpip_if *ifp, const uint8_t *f, size_t n,
void *buf, size_t len) {
struct mg_l2_802154_data *d =
(struct mg_l2_802154_data *) ifp->driver_data;
size_t idx, last;
if (n <= MGI_802154_HDR || f[0] != 0x41 || f[1] != 0xd8 ||
f[3] != (uint8_t) d->pan_id || f[4] != (uint8_t) (d->pan_id >> 8))
return 0; // Not ours
idx = f[16] >> 4, last = f[16] & 15;
if (idx == 0) d->rxtag = f[15], d->rxnext = 0, d->rxlen = 0;
if (idx == 0) memcpy(d->rxsrc, f + 7, sizeof(d->rxsrc));
n -= MGI_802154_HDR;
if (idx != d->rxnext || idx > last || f[15] != d->rxtag ||
memcmp(d->rxsrc, f + 7, sizeof(d->rxsrc)) != 0 ||
d->rxlen + n > sizeof(d->rxbuf))
return 0; // Missed a fragment, or from another sender
memcpy(d->rxbuf + d->rxlen, f + MGI_802154_HDR, n);
d->rxlen = (uint16_t) (d->rxlen + n), d->rxnext++;
if (idx < last || d->rxlen > len) return 0;
memcpy(buf, d->rxbuf, d->rxlen);
return d->rxlen;
}
#endif
-9
View File
@@ -105,14 +105,6 @@ static void mg_mdash_rpc_get_info(struct mg_rpc_req *r) {
MG_ESC("crash"), mg_print_crash_record); MG_ESC("crash"), mg_print_crash_record);
} }
static void mg_mdash_rpc_mem_stats(struct mg_rpc_req *r) {
mg_rpc_ok(r, "{%m:%zu,%m:%zu,%m:%zu,%m:%zu}", //
MG_ESC("stack_used"), (size_t) MG_HEALTH_STACK_USED, //
MG_ESC("stack_total"), (size_t) MG_HEALTH_STACK_TOTAL, //
MG_ESC("heap_used"), (size_t) MG_HEALTH_HEAP_USED, //
MG_ESC("heap_total"), (size_t) MG_HEALTH_HEAP_TOTAL);
}
static void mg_mdash_rpc_ota_begin(struct mg_rpc_req *r) { static void mg_mdash_rpc_ota_begin(struct mg_rpc_req *r) {
size_t total = (size_t) mg_json_get_long(r->frame, "$.params.size", -1); size_t total = (size_t) mg_json_get_long(r->frame, "$.params.size", -1);
if (mg_ota_begin(total)) { if (mg_ota_begin(total)) {
@@ -158,7 +150,6 @@ void mg_mdash_init(struct mg_mgr *mgr) {
MG_INFO(("Initialising mdash agent, key [%s]", MG_MDASH_KEY)); MG_INFO(("Initialising mdash agent, key [%s]", MG_MDASH_KEY));
mg_rpc_add(&mgr->rpcs, mg_str("RPC.List"), mg_rpc_list, NULL); mg_rpc_add(&mgr->rpcs, mg_str("RPC.List"), mg_rpc_list, NULL);
mg_rpc_add(&mgr->rpcs, mg_str("Sys.GetInfo"), mg_mdash_rpc_get_info, NULL); mg_rpc_add(&mgr->rpcs, mg_str("Sys.GetInfo"), mg_mdash_rpc_get_info, NULL);
mg_rpc_add(&mgr->rpcs, mg_str("Sys.MemStats"), mg_mdash_rpc_mem_stats, NULL);
mg_rpc_add(&mgr->rpcs, mg_str("OTA.Begin"), mg_mdash_rpc_ota_begin, NULL); mg_rpc_add(&mgr->rpcs, mg_str("OTA.Begin"), mg_mdash_rpc_ota_begin, NULL);
mg_rpc_add(&mgr->rpcs, mg_str("OTA.Write"), mg_mdash_rpc_ota_write, NULL); mg_rpc_add(&mgr->rpcs, mg_str("OTA.Write"), mg_mdash_rpc_ota_write, NULL);
mg_rpc_add(&mgr->rpcs, mg_str("OTA.End"), mg_mdash_rpc_ota_end, NULL); mg_rpc_add(&mgr->rpcs, mg_str("OTA.End"), mg_mdash_rpc_ota_end, NULL);
+35
View File
@@ -154,6 +154,41 @@ extern struct mg_tcpip_driver mg_tcpip_driver_nxp_wifi;
extern struct mg_tcpip_driver mg_tcpip_driver_st67w6; extern struct mg_tcpip_driver mg_tcpip_driver_st67w6;
extern struct mg_tcpip_driver mg_tcpip_driver_atcmd; extern struct mg_tcpip_driver mg_tcpip_driver_atcmd;
extern struct mg_tcpip_driver mg_tcpip_driver_netc; extern struct mg_tcpip_driver mg_tcpip_driver_netc;
extern struct mg_tcpip_driver mg_tcpip_driver_mcxw71;
extern struct mg_tcpip_driver mg_tcpip_driver_rw612_154;
// IEEE 802.15.4 radio channel and PAN ID. Settable in mongoose_config.h
#ifndef MG_L2_802154_CHANNEL
#define MG_L2_802154_CHANNEL 15 // 11..26
#endif
#ifndef MG_L2_802154_PAN_ID
#define MG_L2_802154_PAN_ID 0xabcd
#endif
// driver_data for IEEE 802.15.4 radio drivers. The interface is Ethernet:
// each Ethernet frame is split into broadcast radio frames, and reassembled
// on the other side, see mg_l2_802154_tx() and mg_l2_802154_rx()
struct mg_l2_802154_data {
uint8_t channel; // User-set channel, 11..26
uint16_t pan_id; // User-set PAN ID
uint8_t seq, tag; // MAC sequence number, tag of the last sent frame
uint8_t rxtag, rxnext; // Frame being reassembled: tag, next fragment
uint8_t rxsrc[8]; // Its sender
uint16_t rxlen; // Its bytes received so far
uint8_t rxbuf[1514]; // Reassembly buffer, one Ethernet frame
};
// Splits an Ethernet frame into radio frames, sends each by calling send().
// Called by radio drivers' tx(). Return len, or 0 on error
size_t mg_l2_802154_tx(struct mg_tcpip_if *ifp, const void *buf, size_t len,
size_t (*send)(const uint8_t *, size_t,
struct mg_tcpip_if *));
// Adds a received radio frame f of n bytes to the frame being reassembled.
// Called by radio drivers' rx(). Return the Ethernet frame length, copied to
// buf, when it is complete, otherwise 0
size_t mg_l2_802154_rx(struct mg_tcpip_if *ifp, const uint8_t *f, size_t n,
void *buf, size_t len);
// SPI bus abstraction for SPI-attached network chips (e.g. W5500). // SPI bus abstraction for SPI-attached network chips (e.g. W5500).
// Populate and assign to the driver's driver_data field. // Populate and assign to the driver's driver_data field.
+16 -3
View File
@@ -208,9 +208,7 @@ static void s_firmware_fn(struct mg_connection *c, int ev, void *ev_data) {
(unsigned long) hm->body.len, (unsigned long) s_ota->size); (unsigned long) hm->body.len, (unsigned long) s_ota->size);
} else { } else {
MG_DEBUG(("Beginning OTA (%lu bytes)", (unsigned long) s_ota->size)); MG_DEBUG(("Beginning OTA (%lu bytes)", (unsigned long) s_ota->size));
if (!mg_http_stream_body(c, hm, s_firmware_cb, NULL)) { mg_http_stream_body(c, hm, s_firmware_cb, NULL);
mg_error(c, "Cannot stream firmware");
}
} }
} else if (ev == MG_EV_ERROR) { } else if (ev == MG_EV_ERROR) {
s_ota->fn((char *) ev_data); s_ota->fn((char *) ev_data);
@@ -243,6 +241,21 @@ void mg_ota_url_check(struct mg_mgr *mgr, const char *json_url,
} }
} }
// Uses *p as a flag: non-NULL means an OTA session is open and must be
// closed by mg_ota_end()
bool mg_http_ota_cb(struct mg_http_message *hm, struct mg_str *data, void **p) {
if (hm != NULL) { // Start
if (!mg_ota_begin(hm->body.len)) return false;
*p = (void *) (ptrdiff_t) 1;
return true;
} else if (data != NULL) { // Next chunk
return mg_ota_write(data->buf, data->len);
}
if (*p == NULL) return false; // End. Begin failed, nothing to finish
*p = NULL;
return mg_ota_end();
}
void mg_ota_poll(struct mg_mgr *mgr) { void mg_ota_poll(struct mg_mgr *mgr) {
static uint64_t t = 5000; // Fire first time 5 sec after boot static uint64_t t = 5000; // Fire first time 5 sec after boot
+15
View File
@@ -26,6 +26,7 @@
#pragma once #pragma once
#include "arch.h" #include "arch.h"
#include "http.h"
#include "net.h" #include "net.h"
// Supported OTA targets // Supported OTA targets
@@ -34,6 +35,7 @@
#define MG_OTA_STM32H7 2 // STM32 H7 #define MG_OTA_STM32H7 2 // STM32 H7
#define MG_OTA_STM32H7_DUAL_CORE 3 // STM32 H7 dual core #define MG_OTA_STM32H7_DUAL_CORE 3 // STM32 H7 dual core
#define MG_OTA_STM32F 4 // STM32 F7/F4/F2 #define MG_OTA_STM32F 4 // STM32 F7/F4/F2
#define MG_OTA_STM32C5 5 // STM32 C5, same flash controller as H5
#define MG_OTA_CH32V307 100 // WCH CH32V307 #define MG_OTA_CH32V307 100 // WCH CH32V307
#define MG_OTA_U2A 200 // Renesas U2A16, U2A8, U2A6 #define MG_OTA_U2A 200 // Renesas U2A16, U2A8, U2A6
#define MG_OTA_RT1020 300 // IMXRT1020 #define MG_OTA_RT1020 300 // IMXRT1020
@@ -43,6 +45,7 @@
#define MG_OTA_RT1170 304 // IMXRT1170 #define MG_OTA_RT1170 304 // IMXRT1170
#define MG_OTA_RT1180 305 // IMXRT1180 #define MG_OTA_RT1180 305 // IMXRT1180
#define MG_OTA_MCXN 310 // MCXN947 #define MG_OTA_MCXN 310 // MCXN947
#define MG_OTA_MCXW71 311 // MCXW71
#define MG_OTA_RW612 320 // FRDM-RW612 #define MG_OTA_RW612 320 // FRDM-RW612
#define MG_OTA_FLASH 900 // OTA via internal flash #define MG_OTA_FLASH 900 // OTA via internal flash
#define MG_OTA_ESP32 910 // ESP32 OTA implementation #define MG_OTA_ESP32 910 // ESP32 OTA implementation
@@ -72,6 +75,18 @@ bool mg_ota_write(const void *buf, size_t len);
// Ends the OTA process and commits the written firmware. // Ends the OTA process and commits the written firmware.
bool mg_ota_end(void); bool mg_ota_end(void);
// Push-based OTA: mg_http_stream_body() callback that flashes the request
//
// ```c
// if (ev == MG_EV_HTTP_HDRS) {
// struct mg_http_message *hm = (struct mg_http_message *) ev_data;
// if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
// mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
// }
// }
// ```
bool mg_http_ota_cb(struct mg_http_message *hm, struct mg_str *data, void **p);
// MG_OTA_ROLLBACK: swap firmware banks and reset. On flash-based OTA, the // MG_OTA_ROLLBACK: swap firmware banks and reset. On flash-based OTA, the
// default calls swap_fn() (no-op on single-bank) then resets. Override in // default calls swap_fn() (no-op on single-bank) then resets. Override in
// mongoose_config.h for platforms without mg_flash (ESP32, PicoSDK, etc.). // mongoose_config.h for platforms without mg_flash (ESP32, PicoSDK, etc.).
+181
View File
@@ -0,0 +1,181 @@
#include "flash.h"
#include "log.h"
#include "ota.h"
#if MG_OTA == MG_OTA_MCXW71
// MCXW71SRM, section 11.2: ROM flash API, 8 KB sectors, 16-byte phrases,
// 128-byte pages. Only the CM33 application flash is used; RF flash and IFR
// (including the write-once ROM configuration) are left alone.
struct mg_mcxw71_flash_config {
struct {
uint32_t base, size, blocks;
uint32_t ifr_base, ifr_size;
} mem[2];
};
struct mg_mcxw71_flash_api {
uint32_t (*init)(struct mg_mcxw71_flash_config *);
uint32_t (*erase)(struct mg_mcxw71_flash_config *, void *, uint32_t, uint32_t,
uint32_t);
uint32_t (*phrase)(struct mg_mcxw71_flash_config *, void *, uint32_t,
uint32_t *, uint32_t);
uint32_t (*page)(struct mg_mcxw71_flash_config *, void *, uint32_t,
uint32_t *, uint32_t);
};
// The flash API pointer is the second entry in the ROM API table.
#define MG_MCXW71_FLASH_API \
(*(const struct mg_mcxw71_flash_api *const *) 0x14816fe4U)
#define MG_MCXW71_ERASE_KEY 0x6b65666cU // FOUR_CHAR_CODE('l', 'f', 'e', 'k')
static struct mg_mcxw71_flash_config s_mcxw71_config;
static size_t s_mcxw71_size, s_mcxw71_received, s_mcxw71_pending;
static uint32_t s_mcxw71_buf[4];
static bool s_mcxw71_failed;
static bool mg_mcxw71_write(void *, const void *, size_t);
static bool mg_mcxw71_swap(void);
static struct mg_flash s_mg_flash_mcxw71 = {
(void *) 0, 0x100000, 8192, 16, mg_mcxw71_write, mg_mcxw71_swap};
struct mg_flash *mg_flash = &s_mg_flash_mcxw71;
// Everything called while flash is busy, or after the application has been
// erased, must execute from RAM or ROM. Do not log or call libc here.
MG_IRAM static bool mg_mcxw71_write(void *addr, const void *buf, size_t len) {
uintptr_t dst = (uintptr_t) addr;
const volatile uint8_t *src = (const volatile uint8_t *) buf;
uint32_t irq, status = 0;
if (dst >= s_mg_flash_mcxw71.size || len > s_mg_flash_mcxw71.size - dst ||
(dst % 16) != 0 || (len % 16) != 0)
return false;
irq = __get_PRIMASK();
__disable_irq();
while (len > 0 && status == 0) {
uint32_t words[32]; // ROM needs a word-aligned source in RAM
volatile uint8_t *p = (volatile uint8_t *) words;
size_t i, n = (dst % 128) == 0 && len >= 128 ? 128 : 16;
for (i = 0; i < n; i++) p[i] = src[i];
// Match the MCUXpresso ROM wrappers' cache maintenance. Interrupts stay
// masked until the flash command completes and stale cache data is gone.
MCM->CPCR2 |= MCM_CPCR2_CCBC_MASK;
__DSB();
__ISB();
if ((dst % 8192) == 0) {
status = MG_MCXW71_FLASH_API->erase(
&s_mcxw71_config, FMU0, (uint32_t) dst, 8192, MG_MCXW71_ERASE_KEY);
}
if (status == 0) {
if (n == 128) {
status = MG_MCXW71_FLASH_API->page(&s_mcxw71_config, FMU0,
(uint32_t) dst, words, 128);
} else {
status = MG_MCXW71_FLASH_API->phrase(&s_mcxw71_config, FMU0,
(uint32_t) dst, words, 16);
}
}
MCM->CPCR2 |= MCM_CPCR2_CCBC_MASK;
__DSB();
__ISB();
dst += n, src += n, len -= n;
}
__set_PRIMASK(irq);
return status == 0;
}
static bool mg_mcxw71_swap(void) {
// The common helper verifies the staged image before the RAM copy below.
// A failed write must never commit, even if all expected bytes arrived.
return !s_mcxw71_failed;
}
MG_IRAM static void mg_mcxw71_apply(size_t size) {
size_t ofs, half = s_mg_flash_mcxw71.size / 2;
__disable_irq();
SysTick->CTRL = 0;
for (ofs = 0; ofs < size; ofs += 8192) {
if (!mg_mcxw71_write((void *) (uintptr_t) ofs,
(const void *) (uintptr_t) (half + ofs), 8192)) {
// The application may already be erased. Stay in RAM for debugger
// recovery rather than return to partially overwritten flash.
for (;;) __NOP();
}
}
__DSB();
SCB->AIRCR = 0x05fa0004U;
__DSB();
for (;;) __NOP();
}
bool mg_ota_begin(size_t new_firmware_size) {
uint32_t status;
if (s_mcxw71_size != 0 || new_firmware_size == 0) return false;
status = MG_MCXW71_FLASH_API->init(&s_mcxw71_config);
if (status != 0 || s_mcxw71_config.mem[0].base != 0 ||
s_mcxw71_config.mem[0].size < 16384 ||
(s_mcxw71_config.mem[0].size % 16384) != 0) {
MG_ERROR(("Flash init failed: %lu", (unsigned long) status));
return false;
}
s_mg_flash_mcxw71.size = s_mcxw71_config.mem[0].size;
if (!mg_ota_flash_begin(new_firmware_size, &s_mg_flash_mcxw71)) return false;
s_mcxw71_size = new_firmware_size;
s_mcxw71_received = s_mcxw71_pending = 0;
s_mcxw71_failed = false;
return true;
}
bool mg_ota_write(const void *buf, size_t len) {
const uint8_t *p = (const uint8_t *) buf;
uint8_t *pending = (uint8_t *) s_mcxw71_buf;
if (s_mcxw71_size == 0 || s_mcxw71_failed) return false;
if (len > s_mcxw71_size - s_mcxw71_received || (len > 0 && buf == NULL)) {
s_mcxw71_failed = true;
return false;
}
s_mcxw71_received += len;
if (s_mcxw71_pending > 0) {
size_t n = 16 - s_mcxw71_pending;
if (n > len) n = len;
if (n > 0) memcpy(pending + s_mcxw71_pending, p, n);
s_mcxw71_pending += n;
if (n > 0) p += n;
len -= n;
if (s_mcxw71_pending == 16) {
s_mcxw71_failed = !mg_ota_flash_write(pending, 16, &s_mg_flash_mcxw71);
s_mcxw71_pending = 0;
}
}
if (!s_mcxw71_failed && len >= 16) {
size_t n = MG_ROUND_DOWN(len, 16);
s_mcxw71_failed = !mg_ota_flash_write(p, n, &s_mg_flash_mcxw71);
p += n, len -= n;
}
if (!s_mcxw71_failed && len > 0) {
memcpy(pending + s_mcxw71_pending, p, len);
s_mcxw71_pending += len;
}
return !s_mcxw71_failed;
}
bool mg_ota_end(void) {
bool ok;
size_t size = s_mcxw71_size;
if (size == 0) return false;
if (s_mcxw71_received != size) s_mcxw71_failed = true;
if (!s_mcxw71_failed && s_mcxw71_pending > 0) {
s_mcxw71_failed =
!mg_ota_flash_write(s_mcxw71_buf, s_mcxw71_pending, &s_mg_flash_mcxw71);
}
ok = mg_ota_flash_end(&s_mg_flash_mcxw71);
s_mcxw71_size = s_mcxw71_pending = 0;
if (ok) {
MG_INFO(("Applying %lu bytes from staging flash", (unsigned long) size));
mg_mcxw71_apply(size);
}
return false;
}
#endif
+1 -1
View File
@@ -2,7 +2,7 @@
#include "log.h" #include "log.h"
#include "ota.h" #include "ota.h"
#if MG_OTA == MG_OTA_STM32H5 #if MG_OTA == MG_OTA_STM32H5 || MG_OTA == MG_OTA_STM32C5
static bool mg_stm32h5_write(void *, const void *, size_t); static bool mg_stm32h5_write(void *, const void *, size_t);
static bool mg_stm32h5_swap(void); static bool mg_stm32h5_swap(void);
+3 -2
View File
@@ -261,8 +261,9 @@ uint64_t mg_ntohll(uint64_t net) {
} }
void mg_delayms(unsigned int ms) { void mg_delayms(unsigned int ms) {
uint64_t to = mg_millis() + ms + 1; uint64_t now, to = mg_millis() + ms + 1;
while (mg_millis() < to) (void) 0; while ((now = mg_millis()) < to)
if (now + ms + 1 < to) to = now + ms + 1;
} }
#if MG_ENABLE_CUSTOM_CALLOC #if MG_ENABLE_CUSTOM_CALLOC
-7
View File
@@ -555,7 +555,6 @@ static void task2(void *args) {
DASHBOARD("select_child_write"); DASHBOARD("select_child_write");
DASHBOARD("poll_child_write"); DASHBOARD("poll_child_write");
#if 0
s_error = false; s_error = false;
s_backlog_ready = s_backlog_full = s_backlog_accept = false; s_backlog_ready = s_backlog_full = s_backlog_accept = false;
ASSERT(xTaskCreate(backlog_task, "backlog", 512, NULL, ASSERT(xTaskCreate(backlog_task, "backlog", 512, NULL,
@@ -570,12 +569,6 @@ static void task2(void *args) {
while (!client_done(first, &status)) vTaskDelay(1); while (!client_done(first, &status)) vTaskDelay(1);
check_client(status); check_client(status);
DASHBOARD("listen_backlog"); DASHBOARD("listen_backlog");
#else
(void) first;
(void) second;
(void) status;
(void) backlog_task;
#endif
s_error = false; s_error = false;
// atask at higher priority than task1 // atask at higher priority than task1
+108 -6
View File
@@ -3158,8 +3158,6 @@ static bool su_cb(struct mg_http_message *hm, struct mg_str *data, void **p) {
static void su(struct mg_connection *c, int ev, void *ev_data) { static void su(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_HDRS) { if (ev == MG_EV_HTTP_HDRS) {
mg_http_stream_body(c, (struct mg_http_message *) ev_data, su_cb, NULL); mg_http_stream_body(c, (struct mg_http_message *) ev_data, su_cb, NULL);
} else if (ev == MG_EV_HTTP_MSG) { // Only for requests that were not streamed
mg_http_reply(c, 400, "", "not streamed\n");
} }
} }
@@ -3194,8 +3192,7 @@ static void cr(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_CONNECT) { if (ev == MG_EV_CONNECT) {
mg_printf(c, "GET / HTTP/1.0\r\n\r\n"); mg_printf(c, "GET / HTTP/1.0\r\n\r\n");
} else if (ev == MG_EV_HTTP_HDRS) { } else if (ev == MG_EV_HTTP_HDRS) {
ASSERT(mg_http_stream_body(c, (struct mg_http_message *) ev_data, cr_cb, mg_http_stream_body(c, (struct mg_http_message *) ev_data, cr_cb, NULL);
NULL));
} }
} }
@@ -3208,12 +3205,103 @@ static void cs(struct mg_connection *c, int ev, void *ev_data) {
(void) ev_data; (void) ev_data;
} }
struct stream_test_state {
int fail_at, starts, chunks, ends;
};
static bool stream_test_cb(struct mg_http_message *hm, struct mg_str *data,
void **p) {
struct stream_test_state *s = (struct stream_test_state *) *p;
ASSERT(s != NULL);
if (hm != NULL) {
s->starts++;
return s->fail_at != 1;
} else if (data != NULL) {
s->chunks++;
return s->fail_at != 2;
}
s->ends++;
*p = NULL;
return s->fail_at != 3;
}
static void stream_test_original(struct mg_connection *c, int ev, void *data) {
(void) c, (void) ev, (void) data;
ASSERT(false); // Streaming must take ownership even when validation fails
}
static void test_http_stream_errors(void) {
static const struct {
const char *request;
int client, fail_at, body_size, code, starts, chunks;
} cases[] = {
{"GET / HTTP/1.1\r\nContent-Length: 0\r\n\r\n", 0, 0, 0, 405, 0, 0},
{"POST / HTTP/1.1\r\n\r\n", 0, 0, 0, 411, 0, 0},
{"POST / HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n",
0, 0, 0, 400, 0, 0},
{"POST / HTTP/1.1\r\nContent-Length: 3\r\n\r\nabc", 0, 0, 0, 200, 1, 1},
{"PUT / HTTP/1.1\r\nContent-Length: 0\r\n\r\n", 0, 0, 0, 200, 1, 0},
// Start failure must reply without waiting for the body or sending 100.
{"POST / HTTP/1.1\r\nContent-Length: 1000000\r\nExpect: 100-continue\r\n\r\n",
0, 1, 0, 500, 1, 0},
// Write failure must also reply before the announced body is complete.
{"POST / HTTP/1.1\r\nContent-Length: 1000000\r\n\r\n",
0, 2, 512, 500, 1, 1},
{"POST / HTTP/1.1\r\nContent-Length: 3\r\n\r\nabc", 0, 3, 0, 500, 1, 1},
// Clients close on errors and never send an HTTP error response.
{"HTTP/1.1 200 OK\r\n\r\n", 1, 0, 0, 411, 0, 0},
{"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n",
1, 0, 0, 400, 0, 0},
{"HTTP/1.1 200 OK\r\nContent-Length: 1000000\r\n\r\n",
1, 1, 0, 500, 1, 0},
{"HTTP/1.1 200 OK\r\nContent-Length: 1000000\r\n\r\n",
1, 2, 512, 500, 1, 1},
{"HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nabc", 1, 3, 0, 500, 1, 1},
{"HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nabc", 1, 0, 0, 200, 1, 1},
{"HTTP/1.1 204 No Content\r\n\r\n", 1, 0, 0, 200, 1, 0},
};
size_t i;
for (i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
struct mg_connection c;
struct mg_http_message hm;
struct stream_test_state state = {0, 0, 0, 0};
char body[512];
memset(&c, 0, sizeof(c));
memset(body, 'x', sizeof(body));
state.fail_at = cases[i].fail_at;
c.is_client = cases[i].client != 0;
c.fn = c.pfn = stream_test_original;
mg_iobuf_add(&c.recv, 0, cases[i].request, strlen(cases[i].request));
mg_iobuf_add(&c.recv, c.recv.len, body, (size_t) cases[i].body_size);
ASSERT(mg_http_parse((char *) c.recv.buf, c.recv.len, &hm) > 0);
mg_http_stream_body(&c, &hm, stream_test_cb, &state);
ASSERT(c.pfn == NULL && c.is_draining);
ASSERT(state.starts == cases[i].starts && state.chunks == cases[i].chunks);
ASSERT(state.ends == 1);
if (c.is_client) {
ASSERT(c.send.len == 0);
ASSERT(c.is_closing == (cases[i].code != 200));
} else {
ASSERT(mg_http_parse((char *) c.send.buf, c.send.len, &hm) > 0);
ASSERT(mg_http_status(&hm) == cases[i].code);
ASSERT(hm.message.len == c.send.len); // Exactly one response
}
mg_call(&c, MG_EV_READ, NULL);
mg_error(&c, "stream cleanup test");
mg_call(&c, MG_EV_CLOSE, NULL);
ASSERT(state.ends == 1); // Error followed by close must not clean up twice
mg_iobuf_free(&c.recv);
mg_iobuf_free(&c.send);
}
}
static void test_http_upload(void) { static void test_http_upload(void) {
struct mg_mgr mgr; struct mg_mgr mgr;
const char *url = "http://127.0.0.1:12352"; const char *url = "http://127.0.0.1:12352";
int i; int i;
const char *s = "ok (8 foo\nbar\n)\n"; const char *s = "ok (8 foo\nbar\n)\n";
test_http_stream_errors();
mg_mgr_init(&mgr); mg_mgr_init(&mgr);
mg_http_listen(&mgr, url, us, NULL); mg_http_listen(&mgr, url, us, NULL);
mg_http_connect(&mgr, url, uc, (void *) &s); mg_http_connect(&mgr, url, uc, (void *) &s);
@@ -3257,7 +3345,7 @@ static void test_http_upload(void) {
ASSERT(mgr.conns == NULL); ASSERT(mgr.conns == NULL);
} }
// mg_http_stream_body: chunked request is not streamed, caller replies "400" // mg_http_stream_body: chunked request rejected with "400", cleanup still runs
{ {
char buf[FETCH_BUF_SIZE]; char buf[FETCH_BUF_SIZE];
s_su_done = s_su_end = 0; s_su_done = s_su_end = 0;
@@ -3268,7 +3356,7 @@ static void test_http_upload(void) {
"POST /su_chunked.txt HTTP/1.1\r\n" "POST /su_chunked.txt HTTP/1.1\r\n"
"Transfer-Encoding: chunked\r\n\r\n" "Transfer-Encoding: chunked\r\n\r\n"
"3\r\nfoo\r\n0\r\n\r\n") == 400); "3\r\nfoo\r\n0\r\n\r\n") == 400);
ASSERT(s_su_done == 0 && s_su_end == 0); // The callback was never called ASSERT(s_su_done == 1 && s_su_end == 1); // End called without start
ASSERT(fopen("su_chunked.txt", "r") == NULL); ASSERT(fopen("su_chunked.txt", "r") == NULL);
mg_mgr_free(&mgr); mg_mgr_free(&mgr);
ASSERT(mgr.conns == NULL); ASSERT(mgr.conns == NULL);
@@ -5010,6 +5098,20 @@ static void test_dash(void) {
"Authorization: Basic YWRtaW46YWRtaW4=\n\n") == 200); "Authorization: Basic YWRtaW46YWRtaW4=\n\n") == 200);
ASSERT(cmpbody(buf, login_admin_expected) == 0); ASSERT(cmpbody(buf, login_admin_expected) == 0);
// OTA uses streaming and enforces the dashboard's authentication.
ASSERT(fetch(&mgr, buf, url,
"POST /api/ota HTTP/1.0\nContent-Length: 1\n\nx") == 403);
ASSERT(fetch(&mgr, buf, url,
"GET /api/ota HTTP/1.0\nContent-Length: 0\n"
"Authorization: Basic YWRtaW46YWRtaW4=\n\n") == 405);
ASSERT(fetch(&mgr, buf, url,
"POST /ota HTTP/1.0\nContent-Length: 1\n"
"Authorization: Basic YWRtaW46YWRtaW4=\n\nx") == 404);
ASSERT(fetch(&mgr, buf, url,
"POST /api/ota HTTP/1.0\nContent-Length: 1\n"
"Authorization: Basic YWRtaW46YWRtaW4=\n\nx") == 200);
ASSERT(cmpbody(buf, "1 ok\n") == 0);
// set3 is admin-only // set3 is admin-only
ASSERT(fetch(&mgr, buf, url, ASSERT(fetch(&mgr, buf, url,
"GET /api/get/set3 HTTP/1.0\n" "GET /api/get/set3 HTTP/1.0\n"
+3 -1
View File
@@ -1,9 +1,11 @@
THISDIR = $(realpath $(CURDIR)) THISDIR = $(realpath $(CURDIR))
ROOTDIR = $(realpath $(CURDIR)/../../..) ROOTDIR = $(realpath $(CURDIR)/../../..)
DOCKER ?= docker run --rm $(DA) -v $(ROOTDIR):$(ROOTDIR) -w $(THISDIR) espressif/idf DOCKER ?= docker run --rm $(DA) -v $(ROOTDIR):$(ROOTDIR) -w $(THISDIR) espressif/idf
CMD ?= idf.py build CMD ?= idf.py -DCFLAGS_EXTRA="$(CFLAGS_EXTRA)" build
PORT ?= /dev/ttyUSB0 PORT ?= /dev/ttyUSB0
CFLAGS_EXTRA ?= -DMG_TLS=MG_TLS_BUILTIN
all: example all: example
example: example:
@@ -12,3 +12,5 @@ idf_component_register(SRCS "main.c"
espcoredump espcoredump
nvs_flash nvs_flash
app_update) app_update)
separate_arguments(CFLAGS_EXTRA)
component_compile_options(${CFLAGS_EXTRA})
+5
View File
@@ -44,6 +44,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
.key = mg_str(TLS_KEY)}; .key = mg_str(TLS_KEY)};
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} else if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) { } else if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
size_t total = heap_caps_get_total_size(MALLOC_CAP_DEFAULT); size_t total = heap_caps_get_total_size(MALLOC_CAP_DEFAULT);
@@ -1,4 +1 @@
#define MG_ARCH MG_ARCH_ESP32 #define MG_ARCH MG_ARCH_ESP32
#define MG_TLS MG_TLS_BUILTIN
//#define MG_TLS MG_TLS_MBED
+6 -1
View File
@@ -9,7 +9,12 @@ static void t_fn(void *arg) { // Tick periodically
} }
static void fn(struct mg_connection *c, int ev, void *ev_data) { static void fn(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) mg_http_reply(c, 200, "", "hi\n"); if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) mg_http_reply(c, 200, "", "hi\n");
(void) ev_data; (void) ev_data;
} }
+6 -1
View File
@@ -9,7 +9,12 @@ static void t_fn(void *arg) { // Tick periodically
} }
static void fn(struct mg_connection *c, int ev, void *ev_data) { static void fn(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) mg_http_reply(c, 200, "", "hi\n"); if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) mg_http_reply(c, 200, "", "hi\n");
(void) ev_data; (void) ev_data;
} }
+6 -6
View File
@@ -3,24 +3,24 @@
extern void mgmp_init(void); extern void mgmp_init(void);
extern void mgmp_poll(int); extern void mgmp_poll(int);
STATIC mp_obj_t mongoose_init(void) { static mp_obj_t mongoose_init(void) {
mgmp_init(); mgmp_init();
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mongoose_init_obj, mongoose_init); static MP_DEFINE_CONST_FUN_OBJ_0(mongoose_init_obj, mongoose_init);
STATIC mp_obj_t mongoose_poll(mp_obj_t t_obj) { static mp_obj_t mongoose_poll(mp_obj_t t_obj) {
mgmp_poll(mp_obj_get_int(t_obj)); mgmp_poll(mp_obj_get_int(t_obj));
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mongoose_poll_obj, mongoose_poll); static MP_DEFINE_CONST_FUN_OBJ_1(mongoose_poll_obj, mongoose_poll);
STATIC const mp_rom_map_elem_t mongoose_module_globals_table[] = { static const mp_rom_map_elem_t mongoose_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_mongoose) }, { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_mongoose) },
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&mongoose_init_obj) }, { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&mongoose_init_obj) },
{ MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&mongoose_poll_obj) }, { MP_ROM_QSTR(MP_QSTR_poll), MP_ROM_PTR(&mongoose_poll_obj) },
}; };
STATIC MP_DEFINE_CONST_DICT(mongoose_module_globals, mongoose_module_globals_table); static MP_DEFINE_CONST_DICT(mongoose_module_globals, mongoose_module_globals_table);
const mp_obj_module_t mongoose_module = { const mp_obj_module_t mongoose_module = {
.base = { &mp_type_module }, .base = { &mp_type_module },
+1 -1
View File
@@ -120,7 +120,7 @@ void mg_mqtt_poll(struct mg_mgr *mgr) {
// Reconnect if connection is closed, and send MQTT PINGs to keep // Reconnect if connection is closed, and send MQTT PINGs to keep
// the connection alive or to detect connection loss // the connection alive or to detect connection loss
if (mg_timer_expired(&timer, MQTT_RECONNECT_PERIOD_MS, mg_now())) { if (mg_timer_expired(&timer, MQTT_RECONNECT_PERIOD_MS, mg_millis())) {
if (s_mqtt_conn == NULL) { if (s_mqtt_conn == NULL) {
struct mg_mqtt_opts opts = { struct mg_mqtt_opts opts = {
.clean = true, .clean = true,
@@ -65,6 +65,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
.key = mg_str(TLS_KEY)}; .key = mg_str(TLS_KEY)};
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} else if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
@@ -89,6 +89,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
.key = mg_str(TLS_KEY)}; .key = mg_str(TLS_KEY)};
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} else if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
@@ -97,6 +97,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
.key = mg_str(TLS_KEY)}; .key = mg_str(TLS_KEY)};
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} else if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
@@ -0,0 +1,45 @@
# Environment setup: https://mongoose.ws/documentation/tutorials/tools/
MGDIR = ../../../..
CFLAGS = -W -Wall -Wextra -Werror -Wundef -Wshadow
CFLAGS += -Wformat-truncation -fno-common -Wno-conversion -Wno-sign-conversion
CFLAGS += -g3 -Os -ffunction-sections -fdata-sections
CFLAGS += -I. -I$(MGDIR) -Icmsis_core/CMSIS/Core/Include
CFLAGS += -Icmsis_mcxw71/MCXW/MCXW716C -Icmsis_mcxw71/MCXW/periph2
CFLAGS += -DCPU_MCXW716CMFTA
CFLAGS += -D__START=main -D__STARTUP_CLEAR_BSS # For startup_MCXW716C.S
CFLAGS += -mcpu=cortex-m33 -mthumb -mfloat-abi=hard -mfpu=fpv5-sp-d16 $(CFLAGS_EXTRA)
LDFLAGS ?= -Tlink.ld -nostdlib -nostartfiles --specs=nano.specs -lc -lm -lgcc -Wl,--gc-sections
SOURCES = main.c hal.c $(MGDIR)/mongoose.c
SOURCES += $(MGDIR)/tutorials/mqtt/mqtt-client/mongoose_mqtt.c
SOURCES += cmsis_mcxw71/MCXW/MCXW716C/gcc/startup_MCXW716C.S
all build: firmware.bin
firmware.bin: firmware.elf
arm-none-eabi-objcopy -O binary $< $@
arm-none-eabi-size --format=berkeley $<
firmware.elf: cmsis_core cmsis_mcxw71 $(SOURCES) $(wildcard *.h) link.ld Makefile
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(LDFLAGS) -o $@
cmsis_core:
git clone -q -c advice.detachedHead=false --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@
# Device headers and startup code from MCUXpresso SDK, only MCXW716C files
cmsis_mcxw71:
git clone -q --depth 1 --filter=blob:none --sparse https://github.com/nxp-mcuxpresso/mcux-devices-mcx $@
cd $@ && git sparse-checkout set MCXW/MCXW716C MCXW/periph2
# Show all symbols sorted by size
show_symbols_sorted_by_size: firmware.bin
arm-none-eabi-readelf -sW firmware.elf | sed 1,3d | sed 's,^.*: ,,' | tr -s ' ' | cut -d ' ' -f 2,7 | sort -nk1 | grep -v '^0 '
flash: firmware.bin
LinkServer flash MCXW716C:FRDM-MCXW71 load firmware.elf
clean:
rm -rf firmware.* cmsis_*
+164
View File
@@ -0,0 +1,164 @@
// Copyright (c) 2026 Cesanta Software Limited
// All rights reserved
#include "hal.h"
#include "mongoose.h"
// Initialise the transceiver the way NXP XCVR_Init() does it: start the RF
// oscillator, wait for the radio to wake up, enable its clocks and load the
// 802.15.4 register setup. Then select the legacy 802.15.4 demodulator and
// CCA from RX digital. See PhyHwInit() in NXP ieee_802_15_4 PHY sources,
// PhyPacketProcessor.c
bool hal_radio_init(void) {
uint32_t stat = RFMC_RF2P4GHZ_STAT_RST_STAT_MASK |
RFMC_RF2P4GHZ_STAT_LP_ACK_STAT_MASK;
size_t i, n = 1000000;
RFMC->CTRL &= ~RFMC_CTRL_RFMC_RST_MASK; // RFMC out of reset
RFMC->RF2P4GHZ_CTRL |= RFMC_RF2P4GHZ_CTRL_XO_EN_MASK; // Start RF oscillator
RFMC->RF2P4GHZ_CTRL &=
~(RFMC_RF2P4GHZ_CTRL_LP_ENTER_MASK | RFMC_RF2P4GHZ_CTRL_RF_POR_MASK |
RFMC_RF2P4GHZ_CTRL_RST_MASK); // Release radio reset, no low power
while ((RFMC->RF2P4GHZ_STAT & stat) != 0 ||
(RFMC->XO_STAT & RFMC_XO_STAT_XTAL_RDY_MASK) == 0) {
if (--n == 0) return false; // Radio did not wake up
}
RADIO_CTRL->LL_CTRL = RADIO_CTRL_LL_CTRL_ACTIVE_LL_MASK;
RFMC->RF2P4GHZ_CTRL |=
RFMC_RF2P4GHZ_CTRL_BLE_LP_EN_MASK | RFMC_RF2P4GHZ_CTRL_BLE_WKUP_MASK;
for (i = 0; i < sizeof(s_radio_regs) / sizeof(s_radio_regs[0]); i++) {
*s_radio_regs[i].reg = s_radio_regs[i].val;
}
XCVR_MISC->XCVR_CTRL &= ~XCVR_MISC_XCVR_CTRL_DEMOD_SEL_MASK;
XCVR_MISC->XCVR_CTRL |= XCVR_MISC_XCVR_CTRL_DEMOD_SEL(2);
XCVR_ZBDEMOD->CCA_LQI_SRC |= XCVR_ZBDEMOD_CCA_LQI_SRC_CCA1_FROM_RX_DIG(1);
return true;
}
// Random bytes for Mongoose, MG_ENABLE_CUSTOM_RANDOM. Entropy is radio noise:
// receiver RSSI, sampled while the radio receives, mixed with SysTick by
// SHA-256. Good enough for random addresses and nonces, not a certified TRNG
bool mg_random(void *buf, size_t len) {
static uint32_t counter;
uint8_t digest[32], *p = (uint8_t *) buf;
size_t i, n;
while (len > 0) {
mg_sha256_ctx ctx;
mg_sha256_init(&ctx);
counter++;
mg_sha256_update(&ctx, (uint8_t *) &counter, sizeof(counter));
for (i = 0; i < 64; i++) {
uint32_t sample[2] = {XCVR_RX_DIG->NB_RSSI_RES0, SysTick->VAL};
mg_sha256_update(&ctx, (uint8_t *) sample, sizeof(sample));
for (n = 0; n < 50; n++) __NOP(); // Let the RSSI update
}
mg_sha256_final(digest, &ctx);
n = len < sizeof(digest) ? len : sizeof(digest);
memcpy(p, digest, n), p += n, len -= n;
}
return true;
}
// Added to minimise the bin size: avoid pulling printf and friends
void __assert_func(const char *s, int line, const char *fn, const char *expr) {
(void) s, (void) line, (void) fn, (void) expr;
for (;;) (void) 0; // or trigger the fault handler
}
bool hal_timer_expired(volatile uint64_t *t, uint64_t period, uint64_t now) {
uint64_t diff = now - *t; // Wrap-safe elapsed time since last expiry
if (period == 0) return false; // Avoid division by zero
if (diff < period) return false; // Period has not elapsed yet
*t += (diff / period) * period; // Preserve cadence, skip missed periods
return true;
}
static volatile uint64_t s_ticks; // Milliseconds since boot
void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms
s_ticks++;
}
uint64_t hal_get_tick(void) {
return s_ticks;
}
uint32_t SystemCoreClock;
// Called by the startup code before .data and .bss are initialised, so it
// must not write any variables. Clock and SysTick setup is in main()
void SystemInit(void) {
hal_sys_init();
}
struct stat;
__attribute__((weak)) int _fstat(int fd, struct stat *st) {
(void) fd, (void) st;
return -1;
}
extern unsigned char _end[]; // End of data section, start of heap. See link.ld
static unsigned char *s_current_heap_end = _end;
size_t hal_ram_used(void) {
return (size_t) (s_current_heap_end - _end);
}
size_t hal_ram_free(void) {
unsigned char endofstack;
return (size_t) (&endofstack - s_current_heap_end);
}
void *_sbrk(int incr) {
unsigned char *prev_heap;
unsigned char *heap_end = (unsigned char *) ((size_t) &heap_end - 256);
prev_heap = s_current_heap_end;
// Check how much space we got from the heap end to the stack end
if (s_current_heap_end + incr > heap_end) return (void *) -1;
s_current_heap_end += incr;
return prev_heap;
}
__attribute__((weak)) int _open(const char *path) {
(void) path;
return -1;
}
__attribute__((weak)) int _close(int fd) {
(void) fd;
return -1;
}
__attribute__((weak)) int _isatty(int fd) {
(void) fd;
return 1;
}
__attribute__((weak)) int _lseek(int fd, int ptr, int dir) {
(void) fd, (void) ptr, (void) dir;
return 0;
}
__attribute__((weak)) void _exit(int status) {
(void) status;
for (;;) asm volatile("BKPT #0");
}
__attribute__((weak)) void _kill(int pid, int sig) {
(void) pid, (void) sig;
}
__attribute__((weak)) int _getpid(void) {
return -1;
}
__attribute__((weak)) int _write(int fd, char *ptr, int len) {
(void) fd, (void) ptr, (void) len;
return -1;
}
__attribute__((weak)) int _read(int fd, char *ptr, int len) {
(void) fd, (void) ptr, (void) len;
return -1;
}
__attribute__((weak)) void _init(void) {
}
+418
View File
@@ -0,0 +1,418 @@
// Copyright (c) 2026 Cesanta Software Limited
// All rights reserved
//
// FRDM-MCXW71 hardware abstraction layer. MCXW716C reference: MCUXpresso SDK,
// https://github.com/nxp-mcuxpresso/mcux-devices-mcx, MCXW/MCXW716C
#pragma once
#include "MCXW716C.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
uint64_t hal_get_tick(void);
bool hal_timer_expired(volatile uint64_t *t, uint64_t period, uint64_t now);
size_t hal_ram_used(void);
size_t hal_ram_free(void);
bool hal_radio_init(void); // Set up the 2.4 GHz transceiver for 802.15.4
extern uint32_t SystemCoreClock; // CPU clock, Hz. Set by hal_clock_init()
#define BIT(x) (1UL << (x))
#define CLRSET(reg, clear, set) ((reg) = ((reg) & ~(clear)) | (set))
#define SIRC_FREQUENCY 6000000UL // Slow IRC (FRO6M), Hz
// MRCC peripheral clock source, MRCC_xx[MUX], see fsl_clock.h
enum { MRCC_SRC_FRO6M = 2, MRCC_SRC_FRO192M = 3 };
// Fast IRC frequency, Hz, or 0 if FIRC is not running. See CLOCK_GetFircFreq()
static inline uint32_t hal_firc_freq(void) {
static const uint32_t freqs[] = {48000000, 64000000, 96000000, 192000000};
if ((SCG0->FIRCCSR & SCG_FIRCCSR_FIRCVLD_MASK) == 0) return 0;
return freqs[SCG0->FIRCCFG & SCG_FIRCCFG_RANGE_MASK];
}
// Switch the system clock: source (2 SIRC, 3 FIRC), core and slow dividers
// as divider - 1. Wait until the switch is done. See CLOCK_SetRunModeSysClkConfig
static inline void hal_set_sysclk(uint32_t src, uint32_t divcore,
uint32_t divslow) {
SCG0->RCCR = SCG_RCCR_SCS(src) | SCG_RCCR_DIVCORE(divcore) |
SCG_RCCR_DIVSLOW(divslow);
while (((SCG0->CSR & SCG_CSR_SCS_MASK) >> SCG_CSR_SCS_SHIFT) != src) (void) 0;
}
// Run the core at 96 MHz from FIRC, slow clock 24 MHz. Order as in NXP
// BOARD_BootClockRUN(), clock_config.c: raise the core voltage and memory
// timing first, then the clock. FIRC can only be changed when not in use
static inline void hal_clock_96mhz(void) {
while (SPC0->SC & SPC_SC_BUSY_MASK) (void) 0;
CLRSET(SPC0->ACTIVE_CFG, SPC_ACTIVE_CFG_CORELDO_VDD_LVL_MASK,
SPC_ACTIVE_CFG_CORELDO_VDD_LVL(2)); // Normal voltage
while (SPC0->SC & SPC_SC_BUSY_MASK) (void) 0;
CLRSET(FMU0->FCTRL, FMU_FCTRL_RWSC_MASK, FMU_FCTRL_RWSC(2)); // Wait states
CLRSET(SPC0->SRAMCTL, SPC_SRAMCTL_VSM_MASK, SPC_SRAMCTL_VSM(2)); // 1.1 V
SPC0->SRAMCTL |= SPC_SRAMCTL_REQ_MASK;
while ((SPC0->SRAMCTL & SPC_SRAMCTL_ACK_MASK) == 0) (void) 0;
SPC0->SRAMCTL &= ~SPC_SRAMCTL_REQ_MASK;
hal_set_sysclk(2, 0, 3); // Run from SIRC meanwhile
SCG0->FIRCCSR &= ~SCG_FIRCCSR_LK_MASK; // Unlock
SCG0->FIRCCSR = SCG_FIRCCSR_FIRCERR_MASK; // Disable, clear error
SCG0->FIRCCFG = SCG_FIRCCFG_RANGE(2); // 96 MHz
SCG0->FIRCCSR |= SCG_FIRCCSR_FIRCEN_MASK;
while ((SCG0->FIRCCSR & SCG_FIRCCSR_FIRCVLD_MASK) == 0) (void) 0;
hal_set_sysclk(3, 0, 3); // FIRC, core / 1, slow / 4
}
// Set the CPU clock to 96 MHz, then work out SystemCoreClock from the SCG
// clock source and core divider
static inline void hal_clock_init(void) {
uint32_t csr, freq = 0;
hal_clock_96mhz();
csr = SCG0->CSR;
uint32_t src = (csr & SCG_CSR_SCS_MASK) >> SCG_CSR_SCS_SHIFT;
uint32_t div = ((csr & SCG_CSR_DIVCORE_MASK) >> SCG_CSR_DIVCORE_SHIFT) + 1;
if (src == 2) freq = SIRC_FREQUENCY; // Slow IRC
if (src == 3) freq = hal_firc_freq(); // Fast IRC
if (freq == 0) freq = SIRC_FREQUENCY; // Unknown source, assume reset value
SystemCoreClock = freq / div;
SysTick_Config(SystemCoreClock / 1000); // Sys tick every 1ms
}
// Enable peripheral clock and take it out of reset, from given clock source.
// See CLOCK_SetIpSrc() and CLOCK_EnableClock() in fsl_clock.h
static inline void hal_periph_clock(volatile uint32_t *mrcc, uint32_t src) {
uint32_t v = (*mrcc & ~(MRCC_CC_MASK | MRCC_MUX_MASK | MRCC_DIV_MASK)) |
MRCC_MUX(src);
*mrcc = v; // Source, clock still off
*mrcc = v | 1U; // CC = 1: clock on
if (*mrcc & MRCC_PR_MASK) *mrcc |= MRCC_RSTB_MASK; // Release reset
__DSB();
}
// LPUART1 is wired to the MCU-Link debug probe USB serial port.
// TX = PTC3, RX = PTC2, both pin mux alternative 3. See board.h, pin_mux.c
static inline void hal_uart_init(LPUART_Type *uart, unsigned long baud) {
uint32_t src = MRCC_SRC_FRO192M, freq = hal_firc_freq();
uint32_t best_osr = 16, best_sbr = 1, best_err = UINT32_MAX, osr;
if (freq == 0) src = MRCC_SRC_FRO6M, freq = SIRC_FREQUENCY; // FIRC off
hal_periph_clock(&MRCC->MRCC_PORTC, 0);
PORTC->PCR[2] = PORT_PCR_MUX(3); // RX
PORTC->PCR[3] = PORT_PCR_MUX(3); // TX
hal_periph_clock(&MRCC->MRCC_LPUART1, src);
// Find the oversampling ratio (4..32) that gives the lowest baud rate error
for (osr = 4; osr <= 32; osr++) {
uint32_t sbr = (freq + osr * baud / 2) / (osr * baud), actual, err;
if (sbr == 0 || sbr > 0x1fff) continue;
actual = freq / (osr * sbr);
err = actual > baud ? actual - baud : baud - actual;
if (err < best_err) best_err = err, best_osr = osr, best_sbr = sbr;
}
uart->CTRL = 0; // Disable while configuring
uart->BAUD = LPUART_BAUD_OSR(best_osr - 1) | LPUART_BAUD_SBR(best_sbr) |
(best_osr < 8 ? LPUART_BAUD_BOTHEDGE_MASK : 0);
uart->CTRL = LPUART_CTRL_TE_MASK | LPUART_CTRL_RE_MASK;
}
static inline void hal_uart_write_byte(LPUART_Type *uart, uint8_t byte) {
while ((uart->STAT & LPUART_STAT_TDRE_MASK) == 0) (void) 0;
uart->DATA = byte;
}
static inline void hal_uart_write_buf(LPUART_Type *uart, const char *buf,
size_t len) {
while (len-- > 0) hal_uart_write_byte(uart, *(const uint8_t *) buf++);
}
// WDOG0 runs after reset: disable it, as SystemInit() in system_MCXW716C.c
static inline void hal_wdog_disable(void) {
while ((WDOG0->CS & WDOG_CS_RCS_MASK) == 0) (void) 0;
if (WDOG0->CS & WDOG_CS_CMD32EN_MASK) {
WDOG0->CNT = 0xD928C520U; // Unlock sequence
} else {
WDOG0->CNT = 0xC520U;
WDOG0->CNT = 0xD928U;
}
while ((WDOG0->CS & WDOG_CS_ULK_MASK) == 0) (void) 0;
WDOG0->TOVAL = 0xFFFF;
WDOG0->CS = (WDOG0->CS & ~WDOG_CS_EN_MASK) | WDOG_CS_UPDATE_MASK;
while ((WDOG0->CS & WDOG_CS_RCS_MASK) == 0) (void) 0;
}
static inline void hal_sys_init(void) {
SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); // Enable FPU
hal_wdog_disable();
}
// 802.15.4 (O-QPSK 250 kbps) radio register setup for the MCXW71 transceiver.
// Values are taken from the NXP XCVR driver, release/25.06.00, configs/gen45:
// XCVR_RadioGenRegSetup() and XCVR_RadioGenRBMESetup() with
// xcvr_oqpsk_802p15p4_250kbps_full_config and xcvr_ble_uncoded_config.
// https://github.com/nxp-mcuxpresso/mcuxsdk-middleware-xcvr
// Copyright 2016 Freescale Semiconductor, Inc.
// Copyright 2018-2023 NXP
// SPDX-License-Identifier: BSD-3-Clause
// One radio register write
struct w71_radio_reg {
volatile uint32_t *reg; // Register address
uint32_t val; // Value to write
};
// Register writes, in the order the NXP driver performs them
static const struct w71_radio_reg s_radio_regs[] = {
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[0].DMD_WAVE_REG0, 0x0420b3d3},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[0].DMD_WAVE_REG1, 0x31d78f00},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[0].DMD_WAVE_REG2, 0x00025a6d},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[1].DMD_WAVE_REG0, 0x0420b3d3},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[1].DMD_WAVE_REG1, 0x38d78f00},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[1].DMD_WAVE_REG2, 0x0000403c},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[2].DMD_WAVE_REG0, 0x3c00420b},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[2].DMD_WAVE_REG1, 0x082c8100},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[2].DMD_WAVE_REG2, 0x0003c004},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[3].DMD_WAVE_REG0, 0x3c00420b},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[3].DMD_WAVE_REG1, 0x0f2c8100},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[3].DMD_WAVE_REG2, 0x0001b5d3},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[4].DMD_WAVE_REG0, 0x0403ce35},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[4].DMD_WAVE_REG1, 0x31d78f00},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[4].DMD_WAVE_REG2, 0x00025a6d},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[5].DMD_WAVE_REG0, 0x0403ce35},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[5].DMD_WAVE_REG1, 0x38d78f00},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[5].DMD_WAVE_REG2, 0x0000403c},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[6].DMD_WAVE_REG0, 0x3ce35c6d},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[6].DMD_WAVE_REG1, 0x082c8100},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[6].DMD_WAVE_REG2, 0x0003c004},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[7].DMD_WAVE_REG0, 0x3ce35c6d},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[7].DMD_WAVE_REG1, 0x0f2c8100},
{&XCVR_2P4GHZ_PHY->DEMOD_WAVE[7].DMD_WAVE_REG2, 0x0001b5d3},
{&XCVR_2P4GHZ_PHY->DMD_CTRL0, 0x6d940101},
{&XCVR_2P4GHZ_PHY->DMD_CTRL1, 0xa8049008},
{&XCVR_2P4GHZ_PHY->FSK_CFG0, 0x15001502},
{&XCVR_2P4GHZ_PHY->FSK_CFG1, 0x0f080020},
{&XCVR_2P4GHZ_PHY->FSK_CFG2, 0x40000000},
{&XCVR_2P4GHZ_PHY->FSK_FAD_CFG, 0x00000000},
{&XCVR_2P4GHZ_PHY->FSK_FAD_CTRL, 0x00000000},
{&XCVR_2P4GHZ_PHY->FSK_PD_CFG0, 0x0000ff0c},
{&XCVR_2P4GHZ_PHY->FSK_PD_CFG1, 0x00000055},
{&XCVR_2P4GHZ_PHY->FSK_PD_CFG2, 0x00f600f6},
{&XCVR_2P4GHZ_PHY->FSK_PD_PH[0], 0x00030503},
{&XCVR_2P4GHZ_PHY->FSK_PD_PH[1], 0x003d3b3d},
{&XCVR_2P4GHZ_PHY->FSK_PT, 0x00000048},
{&XCVR_2P4GHZ_PHY->LR_AA_CFG, 0x06020696},
{&XCVR_2P4GHZ_PHY->LR_PD_CFG, 0x0001019a},
{&XCVR_2P4GHZ_PHY->LR_PD_PH[0], 0x3d383028},
{&XCVR_2P4GHZ_PHY->LR_PD_PH[1], 0x20283038},
{&XCVR_2P4GHZ_PHY->LR_PD_PH[2], 0x03081018},
{&XCVR_2P4GHZ_PHY->LR_PD_PH[3], 0x20181008},
{&XCVR_2P4GHZ_PHY->MISC, 0x03ff00a0},
{&XCVR_2P4GHZ_PHY->PREPHY_MISC, 0x00000c10},
{&XCVR_2P4GHZ_PHY->RTT_CTRL, 0x00004166},
{&XCVR_2P4GHZ_PHY->RTT_REF, 0x00806348},
{&XCVR_2P4GHZ_PHY->SM_CFG, 0x00a02432},
{&RADIO_CTRL->LL_CTRL, 0x00000001},
{&XCVR_ANALOG->LDO_0, 0x04440400},
{&XCVR_ANALOG->LDO_1, 0x00000005},
{&XCVR_ANALOG->PLL, 0x00000040},
{&XCVR_ANALOG->RX_0, 0x01000002},
{&XCVR_ANALOG->RX_1, 0x00022008},
{&XCVR_ANALOG->TX_DAC_PA, 0x01000000},
{&XCVR_ANALOG->XO_DIST, 0x00000000},
{&XCVR_MISC->IPS_FO_ADDR[0], 0x00000370},
{&XCVR_MISC->IPS_FO_ADDR[1], 0x0000002c},
{&XCVR_MISC->IPS_FO_DRS0_DATA[0], 0x00000000},
{&XCVR_MISC->IPS_FO_DRS0_DATA[1], 0x00000000},
{&XCVR_MISC->IPS_FO_DRS1_DATA[0], 0x00000000},
{&XCVR_MISC->IPS_FO_DRS1_DATA[1], 0x00000000},
{&XCVR_MISC->LDO_TRIM_0, 0x00020000},
{&XCVR_MISC->LDO_TRIM_1, 0x00000000},
{&XCVR_MISC->XCVR_CTRL, 0x00130180},
{&XCVR_PLL_DIG->CHAN_MAP, 0x00040000},
{&XCVR_PLL_DIG->CHAN_MAP_EXT, 0x00100000},
{&XCVR_PLL_DIG->DATA_RATE_OVRD_CTRL1, 0x00000089},
{&XCVR_PLL_DIG->DATA_RATE_OVRD_CTRL2, 0x00180000},
{&XCVR_PLL_DIG->DELAY_MATCH, 0x00050102},
{&XCVR_PLL_DIG->HPMCAL_CTRL, 0x00002000},
{&XCVR_PLL_DIG->HPM_BUMP, 0x00440144},
{&XCVR_PLL_DIG->HPM_CAL_TIMING, 0x00000000},
{&XCVR_PLL_DIG->HPM_CTRL, 0x00840000},
{&XCVR_PLL_DIG->HPM_SDM_RES, 0x00ff0000},
{&XCVR_PLL_DIG->LOCK_DETECT, 0x0e1a1800},
{&XCVR_PLL_DIG->LPM_CTRL, 0x88880a00},
{&XCVR_PLL_DIG->LPM_SDM_CTRL1, 0x00260000},
{&XCVR_PLL_DIG->MOD_CTRL, 0x80000000},
{&XCVR_PLL_DIG->PLL_DATARATE_CTRL, 0x04126644},
{&XCVR_PLL_DIG->TUNING_CAP_RX_CTRL, 0x00000000},
{&XCVR_PLL_DIG->TUNING_CAP_TX_CTRL, 0x00ffffa3},
{&XCVR_RX_DIG->ACQ_FILT_0_3, 0x737f0502},
{&XCVR_RX_DIG->ACQ_FILT_0_3_DRS, 0x0f7f3a01},
{&XCVR_RX_DIG->ACQ_FILT_10_11, 0x00ef0061},
{&XCVR_RX_DIG->ACQ_FILT_10_11_DRS, 0x012b0021},
{&XCVR_RX_DIG->ACQ_FILT_4_7, 0xf8221478},
{&XCVR_RX_DIG->ACQ_FILT_4_7_DRS, 0x3c06617f},
{&XCVR_RX_DIG->ACQ_FILT_8_9, 0x01d501bc},
{&XCVR_RX_DIG->ACQ_FILT_8_9_DRS, 0x019401f3},
{&XCVR_RX_DIG->AGC_CTRL, 0x587c8d19},
{&XCVR_RX_DIG->AGC_CTRL_STAT, 0x0000872c},
{&XCVR_RX_DIG->AGC_IDX0_GAIN_CFG, 0x000000f2},
{&XCVR_RX_DIG->AGC_IDX0_GAIN_VAL, 0x000003fd},
{&XCVR_RX_DIG->AGC_IDX0_THR, 0x0000001e},
{&XCVR_RX_DIG->AGC_IDX10_GAIN_CFG, 0x00004a03},
{&XCVR_RX_DIG->AGC_IDX10_GAIN_VAL, 0x000000eb},
{&XCVR_RX_DIG->AGC_IDX10_THR, 0x0096001e},
{&XCVR_RX_DIG->AGC_IDX11_GAIN_CFG, 0x00007e03},
{&XCVR_RX_DIG->AGC_IDX11_GAIN_VAL, 0x000000fa},
{&XCVR_RX_DIG->AGC_IDX11_THR, 0x00780000},
{&XCVR_RX_DIG->AGC_IDX1_GAIN_CFG, 0x000001b2},
{&XCVR_RX_DIG->AGC_IDX1_GAIN_VAL, 0x0000000b},
{&XCVR_RX_DIG->AGC_IDX1_THR, 0x015e001e},
{&XCVR_RX_DIG->AGC_IDX2_GAIN_CFG, 0x00000123},
{&XCVR_RX_DIG->AGC_IDX2_GAIN_VAL, 0x00000026},
{&XCVR_RX_DIG->AGC_IDX2_THR, 0x00c8001e},
{&XCVR_RX_DIG->AGC_IDX3_GAIN_CFG, 0x00000113},
{&XCVR_RX_DIG->AGC_IDX3_GAIN_VAL, 0x0000003c},
{&XCVR_RX_DIG->AGC_IDX3_THR, 0x00c8001e},
{&XCVR_RX_DIG->AGC_IDX4_GAIN_CFG, 0x00000083},
{&XCVR_RX_DIG->AGC_IDX4_GAIN_VAL, 0x00000057},
{&XCVR_RX_DIG->AGC_IDX4_THR, 0x00c8001e},
{&XCVR_RX_DIG->AGC_IDX5_GAIN_CFG, 0x00000183},
{&XCVR_RX_DIG->AGC_IDX5_GAIN_VAL, 0x0000006d},
{&XCVR_RX_DIG->AGC_IDX5_THR, 0x00fa001e},
{&XCVR_RX_DIG->AGC_IDX6_GAIN_CFG, 0x00000203},
{&XCVR_RX_DIG->AGC_IDX6_GAIN_VAL, 0x00000087},
{&XCVR_RX_DIG->AGC_IDX6_THR, 0x012c001e},
{&XCVR_RX_DIG->AGC_IDX7_GAIN_CFG, 0x00000603},
{&XCVR_RX_DIG->AGC_IDX7_GAIN_VAL, 0x000000a0},
{&XCVR_RX_DIG->AGC_IDX7_THR, 0x012c001e},
{&XCVR_RX_DIG->AGC_IDX8_GAIN_CFG, 0x00000e03},
{&XCVR_RX_DIG->AGC_IDX8_GAIN_VAL, 0x000000b7},
{&XCVR_RX_DIG->AGC_IDX8_THR, 0x012c001e},
{&XCVR_RX_DIG->AGC_IDX9_GAIN_CFG, 0x00002203},
{&XCVR_RX_DIG->AGC_IDX9_GAIN_VAL, 0x000000d2},
{&XCVR_RX_DIG->AGC_IDX9_THR, 0x0096001e},
{&XCVR_RX_DIG->AGC_MIS_GAIN_CFG, 0x00000001},
{&XCVR_RX_DIG->AGC_THR_FAST, 0x0190000f},
{&XCVR_RX_DIG->AGC_THR_FAST_DRS, 0x0190001e},
{&XCVR_RX_DIG->AGC_THR_MIS, 0x00960028},
{&XCVR_RX_DIG->AGC_TIMING0, 0x04102398},
{&XCVR_RX_DIG->AGC_TIMING0_DRS, 0x40002000},
{&XCVR_RX_DIG->AGC_TIMING1, 0x190242a7},
{&XCVR_RX_DIG->AGC_TIMING1_DRS, 0x000002a7},
{&XCVR_RX_DIG->AGC_TIMING2, 0xe000007f},
{&XCVR_RX_DIG->AGC_TIMING2_DRS, 0x0000007f},
{&XCVR_RX_DIG->CTRL0, 0x68063083},
{&XCVR_RX_DIG->CTRL0_DRS, 0x000030c0},
{&XCVR_RX_DIG->CTRL1, 0x00000180},
{&XCVR_RX_DIG->DCOC_CTRL0, 0x04332d28},
{&XCVR_RX_DIG->DCOC_CTRL0_DRS, 0x00000114},
{&XCVR_RX_DIG->DCOC_CTRL1, 0x00000000},
{&XCVR_RX_DIG->DEMOD_FILT_0_1, 0x01fe01fd},
{&XCVR_RX_DIG->DEMOD_FILT_0_1_DRS, 0x00ff0003},
{&XCVR_RX_DIG->DEMOD_FILT_2_4, 0x0ba20824},
{&XCVR_RX_DIG->DEMOD_FILT_2_4_DRS, 0x124221ff},
{&XCVR_RX_DIG->NB_RSSI_CTRL0, 0xed472234},
{&XCVR_RX_DIG->NB_RSSI_CTRL1, 0x00000000},
{&XCVR_RX_DIG->RCCAL_CTRL0, 0x0000003a},
{&XCVR_RX_DIG->RSSI_GLOBAL_CTRL, 0x80008330},
{&XCVR_RX_DIG->WB_RSSI_CTRL, 0x00223342},
{&XCVR_TSM->CTRL, 0xff000000},
{&XCVR_TSM->END_OF_SEQ, 0x5c5a7270},
{&XCVR_TSM->FAST_CTRL1, 0x24006f00},
{&XCVR_TSM->FAST_CTRL2, 0x66284208},
{&XCVR_TSM->FAST_CTRL3, 0x18001800},
{&XCVR_TSM->RECYCLE_COUNT, 0x00001258},
{&XCVR_TSM->TIMING00, 0xffffffff},
{&XCVR_TSM->TIMING01, 0xffffffff},
{&XCVR_TSM->TIMING02, 0xffffffff},
{&XCVR_TSM->TIMING03, 0xffffffff},
{&XCVR_TSM->TIMING04, 0xffffffff},
{&XCVR_TSM->TIMING05, 0xffffffff},
{&XCVR_TSM->TIMING06, 0xffffffff},
{&XCVR_TSM->TIMING07, 0xffffffff},
{&XCVR_TSM->TIMING08, 0xffffffff},
{&XCVR_TSM->TIMING09, 0x5700ffff},
{&XCVR_TSM->TIMING10, 0x11081108},
{&XCVR_TSM->TIMING11, 0x5b137113},
{&XCVR_TSM->TIMING12, 0x5b19714f},
{&XCVR_TSM->TIMING13, 0x572dffff},
{&XCVR_TSM->TIMING14, 0x0000716f},
{&XCVR_TSM->TIMING15, 0x5b58716f},
{&XCVR_TSM->TIMING16, 0x59580000},
{&XCVR_TSM->TIMING17, 0x5b580000},
{&XCVR_TSM->TIMING18, 0x5b580000},
{&XCVR_TSM->TIMING19, 0x11061106},
{&XCVR_TSM->TIMING20, 0x11001100},
{&XCVR_TSM->TIMING21, 0x19001100},
{&XCVR_TSM->TIMING22, 0x58006f00},
{&XCVR_TSM->TIMING23, 0x58006f00},
{&XCVR_TSM->TIMING24, 0x5b007100},
{&XCVR_TSM->TIMING25, 0x5c007200},
{&XCVR_TSM->TIMING26, 0x5c007200},
{&XCVR_TSM->TIMING27, 0x5c007200},
{&XCVR_TSM->TIMING28, 0x5c007200},
{&XCVR_TSM->TIMING29, 0xffff7200},
{&XCVR_TSM->TIMING30, 0x5c00ffff},
{&XCVR_TSM->TIMING31, 0x5b087108},
{&XCVR_TSM->TIMING32, 0x1911ffff},
{&XCVR_TSM->TIMING33, 0x23115a11},
{&XCVR_TSM->TIMING34, 0x5b117111},
{&XCVR_TSM->TIMING35, 0x5b117111},
{&XCVR_TSM->TIMING36, 0x5b117111},
{&XCVR_TSM->TIMING37, 0x5b117111},
{&XCVR_TSM->TIMING38, 0x5b117111},
{&XCVR_TSM->TIMING39, 0x5b2b7111},
{&XCVR_TSM->TIMING40, 0xffff7111},
{&XCVR_TSM->TIMING41, 0xffff7111},
{&XCVR_TSM->TIMING42, 0x5b127112},
{&XCVR_TSM->TIMING43, 0x5b12ffff},
{&XCVR_TSM->TIMING44, 0x5b12ffff},
{&XCVR_TSM->TIMING45, 0xffff7112},
{&XCVR_TSM->TIMING46, 0xffff716f},
{&XCVR_TSM->TIMING47, 0x5b137157},
{&XCVR_TSM->TIMING48, 0x5b23715a},
{&XCVR_TSM->TIMING49, 0x5b23715a},
{&XCVR_TSM->TIMING50, 0x5b2bffff},
{&XCVR_TSM->TIMING51, 0x5b2bffff},
{&XCVR_TSM->TIMING52, 0xffffffff},
{&XCVR_TSM->WU_LATENCY, 0x00060006},
{&XCVR_TX_DIG->DATARATE_CONFIG_FILTER_CTRL, 0x00010000},
{&XCVR_TX_DIG->DATARATE_CONFIG_FSK_CTRL, 0x08001800},
{&XCVR_TX_DIG->DATARATE_CONFIG_GFSK_CTRL, 0x00000804},
{&XCVR_TX_DIG->DATA_PADDING_CTRL, 0x00001012},
{&XCVR_TX_DIG->DATA_PADDING_CTRL_1, 0x00001600},
{&XCVR_TX_DIG->DATA_PADDING_CTRL_2, 0x08001800},
{&XCVR_TX_DIG->FSK_CTRL, 0x04001c00},
{&XCVR_TX_DIG->GFSK_COEFF_0_1, 0x00040001},
{&XCVR_TX_DIG->GFSK_COEFF_2_3, 0x0028000d},
{&XCVR_TX_DIG->GFSK_COEFF_4_5, 0x00c00063},
{&XCVR_TX_DIG->GFSK_COEFF_6_7, 0x0176012c},
{&XCVR_TX_DIG->GFSK_CTRL, 0x000003fd},
{&XCVR_TX_DIG->IMAGE_FILTER_CTRL, 0x00000000},
{&XCVR_TX_DIG->PA_CTRL, 0x00020126},
{&XCVR_TX_DIG->PA_RAMP_TBL0, 0x06040201},
{&XCVR_TX_DIG->PA_RAMP_TBL1, 0x14100c09},
{&XCVR_TX_DIG->PA_RAMP_TBL2, 0x26211c18},
{&XCVR_TX_DIG->PA_RAMP_TBL3, 0x3c38322c},
{&XCVR_TX_DIG->SWITCH_TX_CTRL, 0x00000000},
{&XCVR_TX_DIG->TXDIG_CTRL, 0x00000007},
{&XCVR_2P4GHZ_PHY->DMD_CTRL1, 0x8c049008},
{&RBME->CRCW_CFG, 0x00000001},
{&RBME->CRCW_CFG2, 0x00000000},
{&RBME->CRCW_CFG3, 0x00000403},
{&RBME->CRC_INIT, 0x55555500},
{&RBME->CRC_PHR_SZ, 0x00000002},
{&RBME->CRC_POLY, 0x00065b00},
{&RBME->CRC_XOR_OUT, 0x00000000},
{&RBME->FCP_CFG, 0x00000000},
{&RBME->FEC_BSZ_OV_B4SP, 0x00000000},
{&RBME->FEC_CFG1, 0x00000000},
{&RBME->FEC_CFG2, 0x00000000},
{&RBME->FRAME_OVER_SZ, 0x00000000},
{&RBME->NPAYL_OVER_SZ, 0x00000000},
{&RBME->PKT_SZ, 0x00244000},
{&RBME->SPREAD_CFG, 0x00000000},
{&RBME->WHITEN_CFG, 0x00410705},
{&RBME->WHITEN_POLY, 0x00000004},
{&RBME->WHITEN_SZ_THR, 0x00000000},
};
+38
View File
@@ -0,0 +1,38 @@
/* MCXW716C memory map, see MCUXpresso SDK gcc/mcxw716_flash.ld */
ENTRY(Reset_Handler);
MEMORY {
flash(rx) : ORIGIN = 0x00000000, LENGTH = 512k /* Upper half: OTA staging */
sram(rwx) : ORIGIN = 0x20000000, LENGTH = 112k
}
__StackTop = ORIGIN(sram) + LENGTH(sram); /* Stack points here */
__StackLimit = __StackTop - 8192; /* MSPLIM, see startup */
SECTIONS {
.vectors : { KEEP(*(.isr_vector)) . = ALIGN(4); } > flash
.text : { *(.text* .text.*) } > flash
.rodata : { *(.rodata*) . = ALIGN(4); } > flash
.data : {
__data_start__ = .;
_sdata = .;
*(.first_data)
*(.iram .iram.*) /* OTA flash operations, copied to RAM by startup */
*(.data SORT(.data.*))
. = ALIGN(4);
__data_end__ = .;
_edata = .;
} > sram AT > flash
__etext = LOADADDR(.data); /* Startup copies .data from here */
.bss : {
__bss_start__ = .;
_sbss = .;
*(.bss SORT(.bss.*) COMMON)
. = ALIGN(4);
__bss_end__ = .;
_ebss = .;
} > sram
. = ALIGN(8);
_end = .; /* Start of heap, see _sbrk() in hal.c */
}
+95
View File
@@ -0,0 +1,95 @@
// Copyright (c) 2026 Cesanta Software Limited
// All rights reserved
//
// IPv4 over IEEE 802.15.4 on FRDM-MCXW71, Mongoose built-in TCP/IP stack.
// The radio carries Ethernet frames, channel 15, PAN ID 0xabcd. With the
// FRDM-RW612 eth_radio_bridge tutorial, gets an address from the LAN's DHCP
// server and is reachable from the LAN. Serves pages on ports 80 and 443
#include "hal.h"
#include "mongoose.h"
#define UART_DEBUG LPUART1 // MCU-Link USB serial port
static void log_fn(char ch, void *param) {
hal_uart_write_buf(param, &ch, 1);
}
uint64_t mg_millis(void) {
return hal_get_tick();
}
// Self-signed P-256 certificate and key for the HTTPS listener. Created by:
// openssl ecparam -genkey -name prime256v1 -noout -out key.pem
// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg
#define TLS_CERT \
"-----BEGIN CERTIFICATE-----\n" \
"MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \
"FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \
"MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \
"SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \
"uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \
"MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \
"lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \
"BCjX++LI\n" \
"-----END CERTIFICATE-----\n"
#define TLS_KEY \
"-----BEGIN EC PRIVATE KEY-----\n" \
"MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \
"AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \
"LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \
"-----END EC PRIVATE KEY-----\n"
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
.key = mg_str(TLS_KEY)};
mg_tls_init(c, &opts);
} else if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick());
} else if (mg_match(hm->uri, mg_str("/api/crash"), NULL)) {
__asm volatile("udf #0"); // Trigger HardFault
} else {
mg_http_reply(c, 200, "",
"Hi from Mongoose!\n"
"tick: %llu\n"
"ram used: %zu\n"
"ram free: %zu\n",
hal_get_tick(), hal_ram_used(), hal_ram_free());
}
}
}
int main(void) {
hal_clock_init();
hal_uart_init(UART_DEBUG, 115200);
mg_log_set_fn(log_fn, UART_DEBUG);
if (!hal_radio_init()) MG_ERROR(("Radio init failed"));
struct mg_mgr mgr;
mg_mgr_init(&mgr);
mg_http_listen(&mgr, "http://0.0.0.0:80", http_ev_handler, NULL);
mg_http_listen(&mgr, "https://0.0.0.0:443", http_ev_handler, NULL);
mg_mqtt_init(&mgr);
MG_INFO(("Initialised. CPU clock: %lu MHz", SystemCoreClock / 1000000));
MG_INFO(("RAM used: %zu, free: %zu", hal_ram_used(), hal_ram_free()));
MG_INFO(("Crash record: %M", mg_print_crash_record));
for (;;) {
mg_mgr_poll(&mgr, 0);
mg_mqtt_poll(&mgr);
}
return 0;
}
@@ -0,0 +1,23 @@
#pragma once
#include "MCXW716C.h"
// See https://mongoose.ws/docs/getting-started/build-environment/
#define MG_ARCH MG_ARCH_ARMGCC
#define MG_TLS MG_TLS_BUILTIN
#define MG_OTA MG_OTA_MCXW71
#define MG_ENABLE_TCPIP 1
#define MG_ENABLE_DRIVER_MCXW71 1
#define MG_ENABLE_CUSTOM_MILLIS 1
#define MG_ENABLE_CUSTOM_RANDOM 1
#define MG_ENABLE_TCPIP_TCPRTX 1 // Link can be lossy, enable retransmit
// Stable MAC, so the DHCP address stays the same across reboots: a hash of
// the 128-bit chip unique ID, MSCM UID, locally administered
#define MG_SET_MAC_ADDRESS(mac) \
do { \
uint8_t b_[32]; \
mg_sha256(b_, (uint8_t *) MSCM->UID, sizeof(MSCM->UID)); \
(mac)[0] = 2, (mac)[1] = b_[1], (mac)[2] = b_[2], (mac)[3] = b_[3]; \
(mac)[4] = b_[4], (mac)[5] = b_[5]; \
} while (0)
@@ -0,0 +1,63 @@
# Environment setup: https://mongoose.ws/documentation/tutorials/tools/
MGDIR = ../../../..
CFLAGS = -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion
CFLAGS += -Wformat-truncation -fno-common -Wno-conversion -Wno-sign-conversion
CFLAGS += -g3 -Os -ffunction-sections -fdata-sections
CFLAGS += -Wno-cast-function-type -Wno-old-style-declaration
CFLAGS += -Wno-unused-parameter
CFLAGS += -I. -I$(MGDIR) -Imongoose -Icmsis_core/CMSIS/Core/Include/
CFLAGS += $(addprefix -Icmsis_rw612/devices/RW612/drivers/romapi/,bootloader nboot otp iap flexspi)
CFLAGS += -Icmsis_rw612/devices/RW612/ -Icmsis_rw612/devices/RW612/periph/ -Icmsis_rw612/devices/RW612/drivers/
CFLAGS += -DCPU_RW612ETA2I -DCPU_RW612ETA2I_cm33_no_dsp
CFLAGS += -DBOOT_HEADER_ENABLE=1
CFLAGS += -DRADIO_FW='"$(RADIO_FW)"'
CFLAGS += -mcpu=cortex-m33+nodsp -mthumb -mfloat-abi=hard -mfpu=fpv5-sp-d16 $(CFLAGS_EXTRA)
LDFLAGS ?= -Tlink.ld -nostdlib -nostartfiles --specs=nano.specs -lc -lgcc -Wl,--gc-sections
SOURCES = main.c hal.c radio.c startup.c flexspi.c flash_config.c $(MGDIR)/mongoose.c
SOURCES += cmsis_rw612/devices/RW612/drivers/fsl_clock.c
SOURCES += cmsis_rw612/devices/RW612/drivers/fsl_trng.c
SOURCES += cmsis_rw612/devices/RW612/drivers/fsl_reset.c
SOURCES += $(addprefix cmsis_rw612/devices/RW612/drivers/,fsl_power.c fsl_ocotp.c \
romapi/bootloader/fsl_romapi.c romapi/nboot/fsl_romapi_nboot.c romapi/otp/fsl_romapi_otp.c)
# NXP BLE/802.15.4 combo firmware for CPU2, linked into our image. NXP license:
# https://github.com/NXP/wifi_nb_fw/blob/nxp-v4.4.3/LICENSE.txt
RADIO_FW = rw61x_sb_ble_15d4_combo_a2.bin
RADIO_FW_URL = https://github.com/NXP/wifi_nb_fw/raw/nxp-v4.4.3/rw61x/$(RADIO_FW)
RADIO_FW_SHA256 = 2efac0d771e371377d57159c40f0909c7ecc6f6b950ce69ed2a3e02ac7eb686a
all build: firmware.bin
firmware.bin: firmware.elf
arm-none-eabi-objcopy -O binary $< $@
arm-none-eabi-size --format=berkeley $<
firmware.elf: cmsis_core cmsis_rw612 $(RADIO_FW) $(SOURCES) $(wildcard *.h) link.ld Makefile mongoose_config.h
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(LDFLAGS) -o $@
cmsis_core:
git clone -q -c advice.detachedHead=false --depth 1 -b 5.9.0 https://github.com/ARM-software/CMSIS_5 $@
$(RADIO_FW):
curl -sL $(RADIO_FW_URL) -o $@.tmp
echo "$(RADIO_FW_SHA256) $@.tmp" | shasum -a 256 -c - >/dev/null
mv $@.tmp $@
cmsis_rw612:
curl -sL https://mcuxpresso.nxp.com/cmsis_pack/repo/NXP.RW612_DFP.25.12.00.pack -o NXP.RW612_DFP.25.12.00.pack
unzip -q NXP.RW612_DFP.25.12.00.pack -d $@
rm NXP.RW612_DFP.25.12.00.pack
# Show all symbols sorted by size
show_symbols_sorted_by_size: firmware.bin
arm-none-eabi-readelf -sW firmware.elf | sed 1,3d | sed 's,^.*: ,,' | tr -s ' ' | cut -d ' ' -f 2,7 | sort -nk1 | grep -v '^0 '
flash: firmware.bin
(echo 'loadfile firmware.elf'; echo 'reset'; echo 'exit';) | JLinkExe -device RW612 -if SWD -speed 4000 -autoconnect 1 -NoGui 1 -ExitOnError 1
# JRun --nogui --device RW612 --if SWD firmware.elf
clean:
rm -rf firmware.* cmsis_* mongoose/mongoose.* $(RADIO_FW)
@@ -0,0 +1,86 @@
/*
* Copyright 2021-2024 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "flash_config.h"
/* Component ID definition, used by tools. */
#ifndef FSL_COMPONENT_ID
#define FSL_COMPONENT_ID "platform.drivers.flash_config"
#endif
/*******************************************************************************
* Code
******************************************************************************/
#if defined(BOOT_HEADER_ENABLE) && (BOOT_HEADER_ENABLE == 1)
#if defined(__ARMCC_VERSION) || defined(__GNUC__)
__attribute__((section(".flash_conf"), used))
#elif defined(__ICCARM__)
#pragma location = ".flash_conf"
#endif
const fc_flexspi_nor_config_t flexspi_config = {
.memConfig =
{
.tag = FC_BLOCK_TAG,
.version = FC_BLOCK_VERSION,
.readSampleClkSrc = 1,
.csHoldTime = 3,
.csSetupTime = 3,
.deviceModeCfgEnable = 1,
.deviceModeSeq = {.seqNum = 1, .seqId = 2},
.deviceModeArg = 0x02,
.configCmdEnable = 0,
.deviceType = 0x1,
.sflashPadType = kSerialFlash_4Pads,
.serialClkFreq = 5,
.sflashA1Size = 0x4000000U,
.sflashA2Size = 0,
.sflashB1Size = 0,
.sflashB2Size = 0,
.lookupTable =
{
/* Read */
[0] = FC_FLEXSPI_LUT_SEQ(FC_CMD_SDR, FC_FLEXSPI_1PAD, 0xEC, FC_RADDR_SDR, FC_FLEXSPI_4PAD, 0x20),
[1] = FC_FLEXSPI_LUT_SEQ(FC_MODE8_SDR, FC_FLEXSPI_4PAD, 0xF0, FC_DUMMY_SDR, FC_FLEXSPI_4PAD, 0x04),
[2] = FC_FLEXSPI_LUT_SEQ(FC_READ_SDR, FC_FLEXSPI_4PAD, 0x04, FC_STOP_EXE, FC_FLEXSPI_1PAD, 0x00),
/* Read Status */
[4 * 1 + 0] =
FC_FLEXSPI_LUT_SEQ(FC_CMD_SDR, FC_FLEXSPI_1PAD, 0x05, FC_READ_SDR, FC_FLEXSPI_1PAD, 0x04),
/* Write Status */
[4 * 2 + 0] =
FC_FLEXSPI_LUT_SEQ(FC_CMD_SDR, FC_FLEXSPI_1PAD, 0x31, FC_WRITE_SDR, FC_FLEXSPI_1PAD, 0x01),
/* Write Enable */
[4 * 3 + 0] =
FC_FLEXSPI_LUT_SEQ(FC_CMD_SDR, FC_FLEXSPI_1PAD, 0x06, FC_STOP_EXE, FC_FLEXSPI_1PAD, 0x00),
/* Sector erase */
[4 * 5 + 0] =
FC_FLEXSPI_LUT_SEQ(FC_CMD_SDR, FC_FLEXSPI_1PAD, 0x21, FC_RADDR_SDR, FC_FLEXSPI_1PAD, 0x20),
/* Block erase */
[4 * 8 + 0] =
FC_FLEXSPI_LUT_SEQ(FC_CMD_SDR, FC_FLEXSPI_1PAD, 0xDC, FC_RADDR_SDR, FC_FLEXSPI_1PAD, 0x20),
/* Page program */
[4 * 9 + 0] =
FC_FLEXSPI_LUT_SEQ(FC_CMD_SDR, FC_FLEXSPI_1PAD, 0x34, FC_RADDR_SDR, FC_FLEXSPI_1PAD, 0x20),
[4 * 9 + 1] =
FC_FLEXSPI_LUT_SEQ(FC_WRITE_SDR, FC_FLEXSPI_4PAD, 0x00, FC_STOP_EXE, FC_FLEXSPI_1PAD, 0x00),
/* chip erase */
[4 * 11 + 0] =
FC_FLEXSPI_LUT_SEQ(FC_CMD_SDR, FC_FLEXSPI_1PAD, 0xC7, FC_STOP_EXE, FC_FLEXSPI_1PAD, 0x00),
},
},
.pageSize = 0x100,
.sectorSize = 0x1000,
.ipcmdSerialClkFreq = 0,
.blockSize = 0x10000,
.fcb_fill[0] = 0xFFFFFFFF,
};
#endif /* BOOT_HEADER_ENABLE */
@@ -0,0 +1,221 @@
/*
* Copyright 2021-2023 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __FLASH_CONFIG__
#define __FLASH_CONFIG__
#include <stdint.h>
#include <stdbool.h>
#include "fsl_common.h"
/*! @name Driver version */
/*@{*/
/*! @brief FLASH_CONFIG driver version 2.0.0. */
#define FSL_FLASH_CONFIG_DRIVER_VERSION (MAKE_VERSION(2, 0, 0))
/*@}*/
/*******************************************************************************
* Definition
******************************************************************************/
/* FLEXSPI memory config block related defintions */
#define FC_BLOCK_TAG (0x42464346)
#define FC_BLOCK_VERSION (0x00000000)
#define FC_CMD_SDR 0x01
#define FC_CMD_DDR 0x21
#define FC_RADDR_SDR 0x02
#define FC_RADDR_DDR 0x22
#define FC_CADDR_SDR 0x03
#define FC_CADDR_DDR 0x23
#define FC_MODE1_SDR 0x04
#define FC_MODE1_DDR 0x24
#define FC_MODE2_SDR 0x05
#define FC_MODE2_DDR 0x25
#define FC_MODE4_SDR 0x06
#define FC_MODE4_DDR 0x26
#define FC_MODE8_SDR 0x07
#define FC_MODE8_DDR 0x27
#define FC_WRITE_SDR 0x08
#define FC_WRITE_DDR 0x28
#define FC_READ_SDR 0x09
#define FC_READ_DDR 0x29
#define FC_LEARN_SDR 0x0A
#define FC_LEARN_DDR 0x2A
#define FC_DATSZ_SDR 0x0B
#define FC_DATSZ_DDR 0x2B
#define FC_DUMMY_SDR 0x0C
#define FC_DUMMY_DDR 0x2C
#define FC_DUMMY_RWDS_SDR 0x0D
#define FC_DUMMY_RWDS_DDR 0x2D
#define FC_JMP_ON_CS 0x1F
#define FC_STOP_EXE 0
#define FC_FLEXSPI_1PAD 0
#define FC_FLEXSPI_2PAD 1
#define FC_FLEXSPI_4PAD 2
#define FC_FLEXSPI_8PAD 3
#define FC_FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1) \
(FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \
FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1))
/* !@brief Data pad used in Read command */
enum
{
kSerialFlash_1Pads = 1,
kSerialFlash_2Pads = 2,
kSerialFlash_4Pads = 4,
kSerialFlash_8Pads = 8,
};
/* !@brief FLEXSPI clock configuration - In High speed boot mode mode */
enum
{
kFlexSpiSerialClk_30MHz = 1,
kFlexSpiSerialClk_50MHz = 2,
kFlexSpiSerialClk_60MHz = 3,
kFlexSpiSerialClk_80MHz = 4,
kFlexSpiSerialClk_100MHz = 5,
kFlexSpiSerialClk_120MHz = 6,
kFlexSpiSerialClk_133MHz = 7,
kFlexSpiSerialClk_166MHz = 8,
kFlexSpiSerialClk_200MHz = 9,
};
/* !@brief FLEXSPI clock configuration - In Normal boot SDR mode */
enum
{
kFlexSpiSerialClk_SDR_24MHz = 1,
kFlexSpiSerialClk_SDR_48MHz = 2,
};
/* !@brief FLEXSPI clock configuration - In Normal boot DDR mode */
enum
{
kFlexSpiSerialClk_DDR_48MHz = 1,
};
/* !@brief Misc feature bit definitions */
enum
{
kFlexSpiMiscOffset_DiffClkEnable = 0, /* !< Bit for Differential clock enable */
kFlexSpiMiscOffset_WordAddressableEnable = 3, /* !< Bit for Word Addressable enable */
kFlexSpiMiscOffset_SafeConfigFreqEnable = 4, /* !< Bit for Safe Configuration Frequency enable */
kFlexSpiMiscOffset_DdrModeEnable = 6, /* !< Bit for DDR clock confiuration indication. */
};
/* !@brief Flash Configuration Command Type */
enum
{
kDeviceConfigCmdType_Generic, /* !< Generic command, for example: configure dummy cycles, drive strength, etc */
kDeviceConfigCmdType_QuadEnable, /* !< Quad Enable command */
kDeviceConfigCmdType_Spi2Xpi, /* !< Switch from SPI to DPI/QPI/OPI mode */
kDeviceConfigCmdType_Xpi2Spi, /* !< Switch from DPI/QPI/OPI to SPI mode */
kDeviceConfigCmdType_Spi2NoCmd, /* !< Switch to 0-4-4/0-8-8 mode */
kDeviceConfigCmdType_Reset, /* !< Reset device command */
};
typedef struct _fc_flexspi_dll_time
{
uint8_t time_100ps; /* !< Data valid time, in terms of 100ps */
uint8_t delay_cells; /* !< Data valid time, in terms of delay cells */
} fc_flexspi_dll_time_t;
/* !@brief FlexSPI LUT Sequence structure */
typedef struct _fc_flexspi_lut_seq
{
uint8_t seqNum; /* !< Sequence Number, valid number: 1-16 */
uint8_t seqId; /* !< Sequence Index, valid number: 0-15 */
uint16_t reserved;
} fc_flexspi_lut_seq_t;
/* !@brief FlexSPI Memory Configuration Block */
typedef struct _fc_flexspi_mem_config
{
uint32_t tag; /* !< [0x000-0x003] Tag, fixed value 0x42464346UL */
uint32_t version; /* !< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix */
uint32_t reserved0; /* !< [0x008-0x00b] Reserved for future use */
uint8_t readSampleClkSrc; /* !< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3 */
uint8_t csHoldTime; /* !< [0x00d-0x00d] CS hold time, default value: 3 */
uint8_t csSetupTime; /* !< [0x00e-0x00e] CS setup time, default value: 3 */
uint8_t columnAddressWidth; /* !< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For
Serial NAND, need to refer to datasheet */
uint8_t deviceModeCfgEnable; /* !< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable */
uint8_t deviceModeType; /* !< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch,
Generic configuration, etc. */
uint16_t waitTimeCfgCommands; /* !< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for
DPI/QPI/OPI switch or reset command */
fc_flexspi_lut_seq_t deviceModeSeq; /* !< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] -
LUt sequence number, [31:16] Reserved */
uint32_t deviceModeArg; /* !< [0x018-0x01b] Argument/Parameter for device configuration */
uint8_t configCmdEnable; /* !< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable */
uint8_t configModeType[3]; /* !< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe */
fc_flexspi_lut_seq_t configCmdSeqs[3]; /* !< [0x020-0x02b] Sequence info for Device Configuration command, similar
as deviceModeSeq */
uint32_t reserved1; /* !< [0x02c-0x02f] Reserved for future use */
uint32_t configCmdArgs[3]; /* !< [0x030-0x03b] Arguments/Parameters for device Configuration commands */
uint32_t reserved2; /* !< [0x03c-0x03f] Reserved for future use */
uint32_t controllerMiscOption; /* !< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for
more details */
uint8_t deviceType; /* !< [0x044-0x044] Device Type: See Flash Type Definition for more details */
uint8_t sflashPadType; /* !< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal */
uint8_t serialClkFreq; /* !< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot
Chapter for more details */
uint8_t lutCustomSeqEnable; /* !< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot
be done using 1 LUT sequence, currently, only applicable to HyperFLASH */
uint32_t reserved3[2]; /* !< [0x048-0x04f] Reserved for future use */
uint32_t sflashA1Size; /* !< [0x050-0x053] Size of Flash connected to A1 */
uint32_t sflashA2Size; /* !< [0x054-0x057] Size of Flash connected to A2 */
uint32_t sflashB1Size; /* !< [0x058-0x05b] Size of Flash connected to B1 */
uint32_t sflashB2Size; /* !< [0x05c-0x05f] Size of Flash connected to B2 */
uint32_t csPadSettingOverride; /* !< [0x060-0x063] CS pad setting override value */
uint32_t sclkPadSettingOverride; /* !< [0x064-0x067] SCK pad setting override value */
uint32_t dataPadSettingOverride; /* !< [0x068-0x06b] data pad setting override value */
uint32_t dqsPadSettingOverride; /* !< [0x06c-0x06f] DQS pad setting override value */
uint32_t timeoutInMs; /* !< [0x070-0x073] Timeout threshold for read status command */
uint32_t commandInterval; /* !< [0x074-0x077] CS deselect interval between two commands */
fc_flexspi_dll_time_t dataValidTime[2]; /* !< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B */
uint16_t busyOffset; /* !< [0x07c-0x07d] Busy offset, valid value: 0-31 */
uint16_t busyBitPolarity; /* !< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 -
busy flag is 0 when flash device is busy */
uint32_t lookupTable[64]; /* !< [0x080-0x17f] Lookup table holds Flash command sequences */
fc_flexspi_lut_seq_t lutCustomSeq[12]; /* !< [0x180-0x1af] Customizable LUT Sequences */
uint32_t reserved4[4]; /* !< [0x1b0-0x1bf] Reserved for future use */
} fc_flexspi_mem_config_t;
/*
* Serial NOR configuration block
*/
typedef struct _fc_flexspi_nor_config
{
#if defined(__ARMCC_VERSION) || defined(__ICCARM__)
uint8_t padding[0x400]; /* !< Padding for MDK and IAR */
#endif
fc_flexspi_mem_config_t memConfig; /* !< Common memory configuration info via FlexSPI */
uint32_t pageSize; /* !< Page size of Serial NOR */
uint32_t sectorSize; /* !< Sector size of Serial NOR */
uint8_t ipcmdSerialClkFreq; /* !< Clock frequency for IP command */
uint8_t isUniformBlockSize; /* !< Sector/Block size is the same */
uint8_t isDataOrderSwapped; /* !< Data order (D0, D1, D2, D3) is swapped (D1,D0, D3, D2) */
uint8_t reserved0[1]; /* !< Reserved for future use */
uint8_t serialNorType; /* !< Serial NOR Flash type: 0/1/2/3 */
uint8_t needExitNoCmdMode; /* !< Need to exit NoCmd mode before other IP command */
uint8_t halfClkForNonReadCmd; /* !< Half the Serial Clock for non-read command: true/false */
uint8_t needRestoreNoCmdMode; /* !< Need to Restore NoCmd mode after IP commmand execution */
uint32_t blockSize; /* !< Block size */
uint32_t flashStateCtx; /* !< Flash State Context */
uint32_t reserve2[10]; /* !< Reserved for future use */
uint32_t fcb_fill[0x280]; /* !< Fill */
} fc_flexspi_nor_config_t;
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif /* __FLASH_CONFIG__ */
@@ -0,0 +1,82 @@
#include "RW612.h"
#include "fsl_flexspi.h" // peripheral structures
__attribute__((section(".iram"))) static void deinit_flash(FLEXSPI_Type *base) {
CLKCTL0->PSCCTL0_SET =
CLKCTL0_PSCCTL0_SET_FLEXSPI0_MASK; // Enable FLEXSPI clock again
base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK; // Enable FLEXSPI module
// Wait until FLEXSPI is not busy
while (!((base->STS0 & FLEXSPI_STS0_ARBIDLE_MASK) &&
(base->STS0 & FLEXSPI_STS0_SEQIDLE_MASK)))
(void)0;
base->MCR0 |=
FLEXSPI_MCR0_MDIS_MASK; // Disable module during the reset procedure
}
__attribute__((section(".iram"))) static void init_flash(FLEXSPI_Type *base) {
uint32_t status;
uint32_t lastStatus;
uint32_t retry;
// Loopback from DQS pad can maximize RD board flash speed.
if ((base->MCR0 & FLEXSPI_MCR0_RXCLKSRC_MASK) != FLEXSPI_MCR0_RXCLKSRC(1)) {
base->MCR0 =
(base->MCR0 & ~FLEXSPI_MCR0_RXCLKSRC_MASK) | FLEXSPI_MCR0_RXCLKSRC(1);
}
base->DLLCR[0] = 0x1U;
base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK; // Enable FLEXSPI module
base->MCR0 |= FLEXSPI_MCR0_SWRESET_MASK;
while (base->MCR0 & FLEXSPI_MCR0_SWRESET_MASK)
(void)0;
// Need to wait DLL locked if DLL enabled
if (0U != (base->DLLCR[0] & FLEXSPI_DLLCR_DLLEN_MASK)) {
lastStatus = base->STS2;
retry = 10;
// Wait slave delay line locked and slave reference delay line locked.
do {
status = base->STS2;
if ((status &
(FLEXSPI_STS2_AREFLOCK_MASK | FLEXSPI_STS2_ASLVLOCK_MASK)) ==
(FLEXSPI_STS2_AREFLOCK_MASK | FLEXSPI_STS2_ASLVLOCK_MASK)) {
// Locked
retry = 100;
break;
} else if (status == lastStatus) {
retry--;
} else {
retry = 10;
lastStatus = status;
}
} while (retry > 0);
// According to ERR011377, need to delay at least 100 NOPs to ensure the DLL
// is locked
for (; retry > 0U; retry--)
(void)0;
}
}
__attribute__((section(".iram"))) void
set_flexspi_clock(FLEXSPI_Type *base, uint32_t src, uint32_t divider) {
if ((CLKCTL0->FLEXSPIFCLKSEL != CLKCTL0_FLEXSPIFCLKSEL_SEL(src)) ||
((CLKCTL0->FLEXSPIFCLKDIV & CLKCTL0_FLEXSPIFCLKDIV_DIV_MASK) !=
(divider - 1))) {
// Always deinit FLEXSPI and init FLEXSPI for the flash to make sure the
// flash works correctly after the FLEXSPI root clock changed as the default
// FLEXSPI configuration may does not work for the new root clock frequency.
deinit_flash(base);
// Disable clock before changing clock source
CLKCTL0->PSCCTL0_CLR = CLKCTL0_PSCCTL0_CLR_FLEXSPI0_MASK;
// Update flexspi clock.
CLKCTL0->FLEXSPIFCLKSEL = CLKCTL0_FLEXSPIFCLKSEL_SEL(src);
CLKCTL0->FLEXSPIFCLKDIV |=
CLKCTL0_FLEXSPIFCLKDIV_RESET_MASK; // Reset the divider counter
CLKCTL0->FLEXSPIFCLKDIV = CLKCTL0_FLEXSPIFCLKDIV_DIV(divider - 1);
while ((CLKCTL0->FLEXSPIFCLKDIV) & CLKCTL0_FLEXSPIFCLKDIV_REQFLAG_MASK)
(void)0;
// Enable FLEXSPI clock again
CLKCTL0->PSCCTL0_SET = CLKCTL0_PSCCTL0_SET_FLEXSPI0_MASK;
init_flash(base);
}
}
@@ -0,0 +1,133 @@
// Copyright (c) 2026 Cesanta Software Limited
// All rights reserved
#include "hal.h"
// Added to minimise the bin size: avoid pulling printf and friends
void __assert_func(const char *s, int line, const char *fn, const char *expr) {
(void) s, (void) line, (void) fn, (void) expr;
for (;;) (void) 0; // or trigger the fault handler
}
bool hal_timer_expired(volatile uint64_t *t, uint64_t period, uint64_t now) {
uint64_t diff = now - *t; // Wrap-safe elapsed time since last expiry
if (period == 0) return false; // Avoid division by zero
if (diff < period) return false; // Period has not elapsed yet
*t += (diff / period) * period; // Preserve cadence, skip missed periods
return true;
}
static volatile uint64_t s_ticks; // Milliseconds since boot
void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms
s_ticks++;
}
uint64_t hal_get_tick(void) {
return s_ticks;
};
uint32_t SystemCoreClock = SYS_FREQUENCY;
int hal_radio_err; // Result of hal_radio_init()
void SystemInit(void) { // Called automatically by startup code
hal_system_init(); // Enable FPU
hal_radio_err = hal_radio_init(); // At the boot clock, see radio.c
hal_clock_init();
SysTick_Config(SystemCoreClock / 1000); // Sys tick every 1ms
}
void ExitRun0Mode(void) {
}
struct stat;
__attribute__((weak)) int _fstat(int fd, struct stat *st) {
(void) fd, (void) st;
return -1;
}
extern unsigned char _end[]; // End of data section, start of heap. See link.ld
static unsigned char *s_current_heap_end = _end;
size_t hal_ram_used(void) {
return (size_t) (s_current_heap_end - _end);
}
size_t hal_ram_free(void) {
unsigned char endofstack;
return (size_t) (&endofstack - s_current_heap_end);
}
void *_sbrk(int incr) {
unsigned char *prev_heap;
unsigned char *heap_end = (unsigned char *) ((size_t) &heap_end - 256);
prev_heap = s_current_heap_end;
// Check how much space we got from the heap end to the stack end
if (s_current_heap_end + incr > heap_end) return (void *) -1;
s_current_heap_end += incr;
return prev_heap;
}
__attribute__((weak)) int _open(const char *path) {
(void) path;
return -1;
}
__attribute__((weak)) int _close(int fd) {
(void) fd;
return -1;
}
__attribute__((weak)) int _isatty(int fd) {
(void) fd;
return 1;
}
__attribute__((weak)) int _lseek(int fd, int ptr, int dir) {
(void) fd, (void) ptr, (void) dir;
return 0;
}
__attribute__((weak)) void _exit(int status) {
(void) status;
for (;;) asm volatile("BKPT #0");
}
__attribute__((weak)) void _kill(int pid, int sig) {
(void) pid, (void) sig;
}
__attribute__((weak)) int _getpid(void) {
return -1;
}
__attribute__((weak)) int _write(int fd, char *ptr, int len) {
(void) fd, (void) ptr, (void) len;
return -1;
}
__attribute__((weak)) int _read(int fd, char *ptr, int len) {
(void) fd, (void) ptr, (void) len;
return -1;
}
__attribute__((weak)) int _link(const char *a, const char *b) {
(void) a, (void) b;
return -1;
}
__attribute__((weak)) int _unlink(const char *a) {
(void) a;
return -1;
}
__attribute__((weak)) int _stat(const char *path, struct stat *st) {
(void) path, (void) st;
return -1;
}
__attribute__((weak)) int mkdir(const char *path, int mode) {
(void) path, (void) mode;
return -1;
}
__attribute__((weak)) void _init(void) {
}
@@ -0,0 +1,366 @@
// Copyright (c) 2023 Cesanta Software Limited
// All rights reserved
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "RW612.h"
#include "fsl_clock.h"
#include "fsl_ocotp.h"
#include "fsl_power.h"
#include "fsl_io_mux.h"
#include "fsl_reset.h"
#include "fsl_trng.h"
int hal_radio_init(void); // Start the 802.15.4 radio firmware. 0: success
extern int hal_radio_err; // hal_radio_init() result, called by SystemInit()
#define BIT(x) (1UL << (x))
#define CLRSET(reg, clear, set) ((reg) = ((reg) & ~(clear)) | (set))
#define PIN(bank, num) ((bank << 8) | (num))
#define PINNO(pin) (pin & 255)
#define PINBANK(pin) (pin >> 8)
void hal_init(void);
size_t hal_ram_free(void);
size_t hal_ram_used(void);
bool hal_timer_expired(volatile uint64_t *t, uint64_t period, uint64_t now);
uint64_t hal_get_tick(void);
static inline void spin(volatile uint32_t count) {
while (count--)
(void)0;
}
#define SYS_FREQUENCY 260000000UL
#define FRG_PLL_CLKDIV 13
enum { HAL_GPIO_MODE_INPUT, HAL_GPIO_MODE_OUTPUT };
enum {
HAL_GPIO_TYPE_NOPULL_WEAKEST = 0x0,
HAL_GPIO_TYPE_NOPULL_WEAK = 0x4,
HAL_GPIO_TYPE_NOPULL_STRONG = 0x8,
HAL_GPIO_TYPE_NOPULL_STRONGEST = 0xC,
HAL_GPIO_TYPE_PULLUP_WEAKEST = 0x1,
HAL_GPIO_TYPE_PULLUP_WEAK = 0x5,
HAL_GPIO_TYPE_PULLUP_STRONG = 0x9,
HAL_GPIO_TYPE_PULLUP_STRONGEST = 0xD,
HAL_GPIO_TYPE_PULLDOWN_WEAKEST = 0x2,
HAL_GPIO_TYPE_PULLDOWN_WEAK = 0x6,
HAL_GPIO_TYPE_PULLDOWN_STRONG = 0xA,
HAL_GPIO_TYPE_PULLDOWN_STRONGEST = 0xE,
HAL_GPIO_TYPE_NOPULL = HAL_GPIO_TYPE_NOPULL_STRONGEST,
HAL_GPIO_TYPE_PULLUP = HAL_GPIO_TYPE_PULLUP_STRONGEST,
HAL_GPIO_TYPE_PULLDOWN = HAL_GPIO_TYPE_PULLDOWN_STRONGEST,
};
// Wrapper structure over the IO_MUX_* macros in fsl_io_mux.h
// To use those macros with our gpio functions,
// wrap them inside this structure as shown in the example from the
// ethernet_init function.
typedef struct
{
uint32_t pinLowMask, pinHighMask, gpioFcSetMask,
gpioFcClrMask, fselSetMask, fselClrMask, ctimerSetMask,
ctimerClrMask, sctimerSetMask, sctimerClrMask;
} io_mux_config_t;
static inline void hal_gpio_init(uint16_t pin, uint8_t mode, uint8_t type,
io_mux_config_t *mux_config) {
uint8_t bank = PINBANK(pin);
uint8_t pin_no = PINNO(pin);
if (mode == HAL_GPIO_MODE_INPUT) {
GPIO->DIR[bank] &= ~(1 << pin_no);
} else {
GPIO->DIR[bank] |= (1 << pin_no);
}
// configure pull
pin_no += bank * 32;
uint32_t shift = (pin_no % 16) * 2;
uint32_t pull_val = (uint32_t)type & 3;
uint32_t drive_val = ((uint32_t)type >> 2) & 3;
volatile uint32_t *pull_reg, *drive_reg;
if (pin_no < 22 || pin_no > 27) {
pull_reg = &SOCCTRL->PAD_PU_PD_EN0 + pin_no / 16;
drive_reg = &SOCCTRL->SR_CONFIG0 + pin_no / 16;
} else {
pull_reg = &AON_SOC_CIU->PAD_PU_PD_EN1;
drive_reg = &AON_SOC_CIU->SR_CONFIG1;
}
*pull_reg = (*pull_reg & ~(3 << shift)) | (pull_val << shift);
*drive_reg = (*drive_reg & ~(3 << shift)) | (drive_val << shift);
if (mux_config) {
IO_MUX_SetPinMux(mux_config->pinLowMask, mux_config->pinHighMask,
mux_config->gpioFcSetMask, mux_config->gpioFcClrMask,
mux_config->fselSetMask, mux_config->fselClrMask,
mux_config->ctimerSetMask, mux_config->ctimerClrMask,
mux_config->sctimerSetMask, mux_config->sctimerClrMask
);
} else {
// if no mux config is specified, assume default gpio settings and
// no special function and just enable the IO
IO_MUX_SetPinMux(bank ? 0 : BIT(PINNO(pin)), !bank ? 0 : BIT(PINNO(pin)),
1 << 16, 0, 0, 0, 0, 0, 0, 0);
}
}
static inline void hal_gpio_input(uint16_t pin) {
hal_gpio_init(pin, HAL_GPIO_MODE_INPUT, HAL_GPIO_TYPE_PULLUP_STRONGEST, NULL);
}
static inline void hal_gpio_output(uint16_t pin) {
hal_gpio_init(pin, HAL_GPIO_MODE_OUTPUT, HAL_GPIO_TYPE_NOPULL_STRONGEST, NULL);
}
static inline bool hal_gpio_read(uint16_t pin) {
return GPIO->PIN[PINBANK(pin)] & (1 << PINNO(pin));
}
static inline void hal_gpio_write(uint16_t pin, bool value) {
if (value) {
GPIO->SET[PINBANK(pin)] |= (1 << PINNO(pin));
} else {
GPIO->CLR[PINBANK(pin)] |= (1 << PINNO(pin));
}
}
static inline void hal_gpio_toggle(uint16_t pin) {
hal_gpio_read(pin) ? hal_gpio_write(pin, false) : hal_gpio_write(pin, true);
}
#if defined(__ZEPHYR__)
#undef MG_HAL_DISABLE_SYSTEM_INIT
#define MG_HAL_DISABLE_SYSTEM_INIT 1
#undef MG_HAL_DISABLE_NEWLIB
#define MG_HAL_DISABLE_NEWLIB 1
#undef MG_HAL_DISABLE_CLOCK
#define MG_HAL_DISABLE_CLOCK 1
#undef MG_HAL_DISABLE_RANDOM
#define MG_HAL_DISABLE_RANDOM 1
#undef MG_HAL_DISABLE_MILLIS
#define MG_HAL_DISABLE_MILLIS 1
#undef MG_HAL_DISABLE_UART
#define MG_HAL_DISABLE_UART 1
#undef MG_HAL_DISABLE_ETHERNET
#define MG_HAL_DISABLE_ETHERNET 1
#undef MG_HAL_SYSTICK
#define MG_HAL_SYSTICK MG_HAL_SYSTICK_NONE
#endif
static inline void hal_uart_init(USART_Type *uart, unsigned long baud) {
if (uart == USART0) {
IO_MUX_SetPinMux(IO_MUX_FC0_USART_DATA);
} else if (uart == USART1) {
IO_MUX_SetPinMux(IO_MUX_FC1_USART_DATA);
} else if (uart == USART2) {
IO_MUX_SetPinMux(IO_MUX_FC2_USART_DATA);
} else if (uart == USART3) {
IO_MUX_SetPinMux(IO_MUX_FC3_USART_DATA);
} else if (uart == USART14) {
IO_MUX_SetPinMux(IO_MUX_FC14_USART_DATA);
} else {
return;
}
uint32_t uart_index = ((uint32_t)uart - USART0_BASE) / 0x1000;
// set FRG clk
CLKCTL1->FLEXCOMM[uart_index].FRGCLKSEL = kCLOCK_FrgPllDiv;
CLKCTL1->FLEXCOMM[uart_index].FRGCTL =
(CLKCTL1_FRGCTL_MULT(0) | CLKCTL1_FRGCTL_DIV(255));
CLOCK_AttachClk(CLKCTL1_TUPLE_MUXA(0x508 + uart_index * 0x20, 4));
// set FLEXCOMM to USART mode
CLOCK_EnableClock(CLK_GATE_DEFINE(CLK_CTL1_PSCCTL0, uart_index + 8));
uint32_t mask = BIT(uart_index + 8);
RSTCTL1->PRSTCTL0_SET = mask;
while ((RSTCTL1->PRSTCTL0 & mask) == 0)
spin(1);
RSTCTL1->PRSTCTL0_CLR = mask;
while ((RSTCTL1->PRSTCTL0 & mask) == mask)
spin(1);
((FLEXCOMM_Type *)uart)->PSELID = 1;
uart->FIFOCFG |= USART_FIFOCFG_EMPTYTX_MASK |
USART_FIFOCFG_ENABLETX_MASK; // empty and enable txFIFO
uart->CFG = BIT(2) | BIT(0); // 8 bit data length and enable
// compute baud
uint32_t uart_freq = SYS_FREQUENCY / FRG_PLL_CLKDIV;
uint32_t best_diff = (uint32_t)-1, best_osr = 0xF, best_brg = (uint32_t)-1;
uint32_t osr, brg, diff, current_baud;
for (osr = 15; osr >= 4; osr--) {
brg = (((uart_freq * 10) / ((osr + 1) * baud)) - 5) / 10;
if (brg > 0xFFFF)
continue;
current_baud = uart_freq / ((osr + 1) * (brg + 1));
diff =
(baud < current_baud) ? (current_baud - baud) : (baud - current_baud);
if (diff < best_diff) {
best_diff = diff;
best_osr = osr;
best_brg = brg;
}
}
uart->OSR = best_osr;
uart->BRG = best_brg;
}
static inline void hal_uart_write_byte(USART_Type *uart, uint8_t byte) {
while ((uart->FIFOSTAT & USART_FIFOSTAT_TXNOTFULL_MASK) == 0)
spin(1);
uart->FIFOWR = byte;
}
static inline void hal_uart_write_buf(USART_Type *uart, char *buf, size_t len) {
while (len-- > 0)
hal_uart_write_byte(uart, *(uint8_t *)buf++);
}
static inline void hal_rng_init(void) {
trng_config_t config;
TRNG_GetDefaultConfig(&config);
TRNG_Init(TRNG, &config);
}
static inline uint32_t hal_rng_read(void) {
uint32_t value;
TRNG_GetRandomData(TRNG, &value, sizeof(value));
return value;
}
static inline void hal_ethernet_init(void) {
CLOCK_EnableClock(kCLOCK_TddrMciEnetClk);
hal_gpio_init(PIN(0, 25), HAL_GPIO_MODE_OUTPUT, IO_MUX_PinConfigPullUpDriveWeak,
&(io_mux_config_t){ IO_MUX_ENET_CLK }); // ENET_CLK on GPIO_25
IO_MUX_SetPinMux(
IO_MUX_ENET_RX); // ENET_RX on pin GPIO_62, GPIO_63, GPIO_22, GPIO_23
IO_MUX_SetPinMux(IO_MUX_ENET_TX); // ENET_TX on pin GPIO_58, GPIO_59, GPIO_60
IO_MUX_SetPinMux(IO_MUX_ENET_MDIO); // ENET_MDIO on pin GPIO_56, GPIO_57
// reset ENET peripheral
RSTCTL0->PRSTCTL1_SET = BIT(25);
while ((RSTCTL0->PRSTCTL1 & BIT(25)) == 0)
spin(1);
RSTCTL0->PRSTCTL1_CLR = BIT(25);
while ((RSTCTL0->PRSTCTL1 & BIT(25)) == BIT(25))
spin(1);
RSTCTL0->PRSTCTL1_SET = BIT(26);
while ((RSTCTL0->PRSTCTL1 & BIT(26)) == 0)
spin(1);
RSTCTL0->PRSTCTL1_CLR = BIT(26);
while ((RSTCTL0->PRSTCTL1 & BIT(26)) == BIT(26))
spin(1);
// Enable clocks
CLOCK_EnableClock(kCLOCK_EnetIpg);
CLOCK_EnableClock(kCLOCK_EnetIpgS);
NVIC_EnableIRQ(ENET_IRQn);
}
extern void set_flexspi_clock(FLEXSPI_Type *base, uint32_t src,
uint32_t divider);
static inline void hal_clock_init(void) {
const clock_avpll_config_t avpllConfig_BOARD_BootClockRUN = {
.ch1Freq =
kCLOCK_AvPllChFreq12p288m, // AVPLL channel frequency 12.288 MHz
.ch2Freq = kCLOCK_AvPllChFreq64m, // AVPLL channel frequency 64 MHz
.enableCali = true, // AVPLL calibration is enabled
};
// As NXP BOARD_BootClockRUN(): the ROM leaves the ELS glitch detector and
// voltage sensors armed, trimmed for the boot clock. Disable them before
// changing the clock, or the ROM resets the chip when it next uses ELS
POWER_DisableGDetVSensors();
if ((PMU->CAU_SLP_CTRL & PMU_CAU_SLP_CTRL_SOC_SLP_RDY_MASK) == 0) {
CLOCK_EnableClock(
kCLOCK_RefClkCauSlp); // Enable the CAU sleep clock for PMU
}
if ((SYSCTL2->SOURCE_CLK_GATE & SYSCTL2_SOURCE_CLK_GATE_REFCLK_SYS_CG_MASK) !=
0) {
CLOCK_EnableClock(kCLOCK_RefClkSys); // Enable the REFCLK_SYS clock
}
CLOCK_InitT3RefClk(kCLOCK_T3MciIrc48m); // Initialize T3 PLL and enable
// outputs that are not clock gated
CLOCK_EnableClock(
kCLOCK_T3PllMciIrcClk); // Enable FFRO - T3 PLL 48/60 MHz IRC clock output
CLOCK_EnableClock(
kCLOCK_T3PllMci256mClk); // Enable T3 PLL 256 MHz clock output
// Move FLEXSPI clock source to T3 256M / 4 to avoid instruction/data fetch
// issue in XIP when updating PLL and main clock.
set_flexspi_clock(FLEXSPI, 6, 4);
CLOCK_AttachClk(kSYSOSC_to_MAIN_CLK); // Set core clock to safe system
// oscillator for initialization
CLOCK_SetClkDiv(kCLOCK_DivSysCpuAhbClk,
1); // Set system CPU AHB clock divider to 1
CLOCK_InitTcpuRefClk(
3120000000UL,
kCLOCK_TcpuFlexspiDiv10); // Initialize TCPU PLL and enable outputs
CLOCK_EnableClock(kCLOCK_TcpuMciClk); // Enable TCPU PLL MCI clock output
CLOCK_InitTddrRefClk(
kCLOCK_TddrFlexspiDiv10); // Initialize TDDR PLL and enable outputs
CLOCK_EnableClock(
kCLOCK_TddrMciFlexspiClk); // Enable TDDR PLL FlexSPI clock output
CLOCK_InitAvPll(&avpllConfig_BOARD_BootClockRUN); // Initialize AVPLL and
// enable both channels
CLOCK_AttachClk(kRC32K_to_CLK32K); // Switch CLK32K to RC32K
CLOCK_AttachClk(
kSYSTICK_DIV_to_SYSTICK_CLK); // Switch SYSTICK_CLK to SYSTICK_DIV
CLOCK_SetClkDiv(kCLOCK_DivAudioPllClk, 1U); // Set AUDIOPLLCLKDIV divider to 1
CLOCK_SetClkDiv(kCLOCK_DivPllFrgClk,
FRG_PLL_CLKDIV); // Set FRGPLLCLKDIV divider
CLOCK_SetClkDiv(kCLOCK_DivMainPllClk, 1U); // Set MAINPLLCLKDIV divider to 1
CLOCK_SetClkDiv(kCLOCK_DivAux0PllClk, 1U); // Set AUX0PLLCLKDIV divider to 1
CLOCK_SetClkDiv(kCLOCK_DivSystickClk, 1U); // Set SYSTICKFCLKDIV divider to 1
CLOCK_SetClkDiv(kCLOCK_DivPmuFclk, 5U); // Set PMUFCLKDIV divider to 5
CLOCK_AttachClk(
kMAIN_PLL_to_MAIN_CLK); // Select the main clock source for system clock
set_flexspi_clock(FLEXSPI, 2U, 2U); // set_flexspi_clock
CLOCK_EnableClock(kCLOCK_HsGpio0);
RSTCTL1->PRSTCTL1_SET = BIT(0); // Reset GPIO_0
while ((RSTCTL1->PRSTCTL1 & BIT(0)) == 0)
spin(1);
RSTCTL1->PRSTCTL1_CLR = BIT(0);
while ((RSTCTL1->PRSTCTL1 & BIT(0)) == BIT(0))
spin(1);
CLOCK_EnableClock(kCLOCK_HsGpio1);
RSTCTL1->PRSTCTL1_SET = BIT(1); // Reset GPIO_1
while ((RSTCTL1->PRSTCTL1 & BIT(1)) == 0)
spin(1);
RSTCTL1->PRSTCTL1_CLR = BIT(1);
while ((RSTCTL1->PRSTCTL1 & BIT(1)) == BIT(1))
spin(1);
}
#if defined(__MCUXPRESSO)
#undef MG_HAL_DISABLE_SYSTEM_INIT
#define MG_HAL_DISABLE_SYSTEM_INIT 1
#undef MG_HAL_SBRK_NONE
#define MG_HAL_SBRK_NONE 1
#endif
static inline void hal_system_init(void) {
SCB->CPACR |=
(3UL << 0 * 2) | (3UL << 1 * 2) | // Enable PowerQuad (CPO/CP1)
(3UL << 10 * 2) | (3UL << 11 * 2); // Enable FPU
SCB->NSACR |= ((3UL << 0) | (3UL << 10));
CACHE64_CTRL0->CCR = CACHE64_CTRL_CCR_INVW1_MASK | CACHE64_CTRL_CCR_INVW0_MASK;
CACHE64_CTRL0->CCR |= CACHE64_CTRL_CCR_GO_MASK;
while ((CACHE64_CTRL0->CCR & CACHE64_CTRL_CCR_GO_MASK) != 0) spin(1);
// Enable cache, enable write buffer
CACHE64_CTRL0->CCR = (CACHE64_CTRL_CCR_ENWRBUF_MASK | CACHE64_CTRL_CCR_ENCACHE_MASK);
// Set whole FlexSPI0 space to write through
CACHE64_POLSEL0->REG0_TOP = 0x07FFFC00U;
CACHE64_POLSEL0->REG1_TOP = 0x0U;
CACHE64_POLSEL0->POLSEL = 0x1U;
__DSB();
__ISB();
}
@@ -0,0 +1,38 @@
ENTRY(Reset_Handler);
MEMORY {
flash(rx) : ORIGIN = 0x08000000, LENGTH = 0x4000000
sram(rwx) : ORIGIN = 0x20000000, LENGTH = 0x123000 /* Top is reserved, as in NXP wireless linker scripts */
}
__StackTop = ORIGIN(sram) + LENGTH(sram);
SECTIONS {
.boot_hdr : ALIGN(4) { FILL(0xFF); . = 0x400; __FLASH_BASE = .; KEEP(*(.flash_conf)) . = 0x1000; } > flash
.vectors : { FILL(256) KEEP(*(.isr_vector)) } > flash
.text : { *(.text.* *.text.*) } > flash
.rodata : { *(.rodata*) } > flash
.iram : {
_siram = .;
*(.iram)
*(CodeQuickAccess) /* NXP SDK drivers, e.g. fsl_power.c */
*(DataQuickAccess)
_eiram = .;
} > sram AT > flash
_siiram = LOADADDR(.iram);
.data : {
_sdata = .;
*(.first_data)
*(.data SORT(.data.*))
_edata = .;
} > sram AT > flash
_sidata = LOADADDR(.data);
.bss : { _sbss = .; *(.bss SORT(.bss.*) COMMON) _ebss = .; } > sram
. = ALIGN(8);
_end = .;
_image_start = LOADADDR(.text);
_image_end = LOADADDR(.data) + SIZEOF(.data);
_image_size = _image_end - _image_start;
}
@@ -0,0 +1,101 @@
// Copyright (c) 2026 Cesanta Software Limited
// All rights reserved
//
// Ethernet <-> IEEE 802.15.4 radio bridge. Radio frames carry Ethernet frames
// split into pieces, see mg_l2_802154_tx(). Radio nodes, e.g. the
// FRDM-MCXW71 minimal tutorial, are on the Ethernet LAN: they get IPv4
// addresses from its DHCP server. The bridge itself has no IP address.
// Everything from the radio goes to Ethernet. From Ethernet, only broadcasts
// and frames to radio nodes go to the radio, it is much slower
#include "hal.h"
#include "mongoose.h"
#define UART_DEBUG USART3
static void log_fn(char ch, void *param) {
hal_uart_write_buf(param, &ch, 1);
}
uint64_t mg_millis(void) {
return hal_get_tick();
}
// MAC addresses of radio nodes, learned from frames they send
static uint8_t s_nodes[8][6];
static size_t s_next;
// Remember a radio node's MAC address, if new
static void learn(const uint8_t *mac) {
size_t i, n = sizeof(s_nodes) / sizeof(s_nodes[0]);
for (i = 0; i < n && memcmp(s_nodes[i], mac, 6) != 0; i++) (void) 0;
if (i < n) return;
memcpy(s_nodes[s_next], mac, 6);
s_next = (s_next + 1) % n;
MG_INFO(("Radio node %M", mg_print_mac, mac));
}
// Is an Ethernet frame for the radio: broadcast, or to a radio node
static bool for_radio(const uint8_t *dst) {
size_t i, n = sizeof(s_nodes) / sizeof(s_nodes[0]);
if (memcmp(dst, "\xff\xff\xff\xff\xff\xff", 6) == 0) return true;
for (i = 0; i < n && memcmp(s_nodes[i], dst, 6) != 0; i++) (void) 0;
return i < n;
}
int main(void) {
static struct mg_tcpip_driver_rw612_data eth_data = {
.mdc_cr = MG_DRIVER_MDC_CR, .phy_addr = MG_TCPIP_PHY_ADDR};
static struct mg_l2_802154_data radio_data = {
.channel = MG_L2_802154_CHANNEL, .pan_id = MG_L2_802154_PAN_ID};
static struct mg_tcpip_if eth = {.driver = &mg_tcpip_driver_rw612,
.driver_data = &eth_data};
static struct mg_tcpip_if radio = {.driver = &mg_tcpip_driver_rw612_154,
.driver_data = &radio_data};
static char eth_queue[8192]; // Filled by the Ethernet IRQ handler
static uint8_t frame[1540];
uint8_t uid[FSL_OCOTP_UID_LENGTH], digest[32];
uint32_t uid_len = sizeof(uid);
uint64_t timer = 0;
char *p;
size_t n;
hal_clock_init();
hal_uart_init(UART_DEBUG, 115200);
mg_log_set_fn(log_fn, UART_DEBUG);
if (hal_radio_err) {
MG_ERROR(("Radio firmware failed to start, step %d", hal_radio_err));
}
// MAC addresses made from the chip unique ID
memset(uid, 0, sizeof(uid));
OCOTP_ReadUniqueID(uid, &uid_len);
mg_sha256(digest, uid, sizeof(uid));
memcpy(eth.mac, digest, 6);
memcpy(radio.mac, digest + 6, 6);
eth.mac[0] = radio.mac[0] = 0x02; // Locally administered, unicast
hal_ethernet_init();
mg_queue_init(&eth.recv_queue, eth_queue, sizeof(eth_queue));
if (!eth.driver->init(&eth)) MG_ERROR(("Ethernet init failed"));
if (!radio.driver->init(&radio)) MG_ERROR(("Radio init failed"));
ENET->RCR |= ENET_RCR_PROM_MASK; // Receive frames for radio nodes, too
MG_INFO(("Bridge started, radio channel %d", radio_data.channel));
for (;;) {
if ((n = mg_queue_next(&eth.recv_queue, &p)) > 0) { // Ethernet -> radio
if (n >= 14 && for_radio((uint8_t *) p)) radio.driver->tx(p, n, &radio);
mg_queue_del(&eth.recv_queue, n);
}
if ((n = radio.driver->rx(frame, sizeof(frame), &radio)) >= 14) {
learn(frame + 6); // Radio -> Ethernet
eth.driver->tx(frame, n, &eth);
}
if (mg_timer_expired(&timer, 1000, mg_millis())) { // Ethernet link
bool up = eth.driver->poll(&eth, true);
eth.state = up ? MG_TCPIP_STATE_UP : MG_TCPIP_STATE_DOWN;
}
}
return 0;
}
@@ -0,0 +1,10 @@
#pragma once
// See https://mongoose.ws/docs/getting-started/build-environment/
#define MG_ARCH MG_ARCH_ARMGCC
#define MG_ENABLE_TCPIP 1
#define MG_ENABLE_DRIVER_RW612 1 // Ethernet
#define MG_ENABLE_DRIVER_RW612_154 1 // 802.15.4 radio
#define MG_ENABLE_TCPIP_DRIVER_INIT 0 // main.c drives both, no TCP/IP stack
#define MG_ENABLE_CUSTOM_MILLIS 1
@@ -0,0 +1,236 @@
// Load NXP BLE/802.15.4 combo firmware to CPU2 and start it.
// Port of NXP mcux-component conn_fwloader: fsl_loader_utils.c (SB3 loader,
// load_service_monolithic) and nboot_hal.c (manifest parameters).
// Copyright 2024 NXP
// SPDX-License-Identifier: BSD-3-Clause
#include "hal.h"
#include "fsl_ocotp.h"
#include "fsl_power.h"
#include "fsl_romapi_nboot.h"
#include "fsl_romapi_otp.h"
#include "fsl_kb_api.h"
#include "fsl_sbloader_v3.h"
// The firmware image, linked into our flash. Signed SB3 container, see
// https://github.com/NXP/wifi_nb_fw, rw61x/rw61x_sb_ble_15d4_combo_a2.bin
__asm__(
".section .rodata.radio_fw,\"a\"\n"
".balign 16\n"
"radio_fw:\n"
".incbin \"" RADIO_FW "\"\n"
".balign 4\n"
"radio_fw_end:\n"
".previous\n");
extern const uint8_t radio_fw[], radio_fw_end[];
#define CIU2_RST_SW3 (*(volatile uint32_t *) 0x4424011cU)
#define CIU2_RST_SW3_CPU2_RST BIT(4)
#define CPU2_MAGIC (*(volatile uint32_t *) 0x443c0000U) // Set by firmware
#define CPU2_MAGIC_VALUE 0xabcdef89U
#define OTP_LCS_FUSE_IDX 45U // Life cycle state, and its redundant copy
#define OTP_PCK_BLOB_FUSE_IDX 116U // Part common key blob, 48 bytes
// SB3 loader state. See fsl_ldr_Context_v3_t
struct sb3 {
nboot_context_t nboot; // ROM nboot context
uint8_t buf[MAX(NBOOT_SB3_MANIFEST_MAX_SIZE_IN_BYTES,
NBOOT_SB3_BLOCK_MAX_SIZE_IN_BYTES)]; // Block being read
uint32_t buf_size; // Bytes needed for the current block
uint32_t buf_pos; // Bytes in buf so far
bool header_done; // Manifest (block 0) processed
uint32_t data_offset; // Data offset within a block
uint32_t blocks; // Data blocks processed
uint8_t *data; // Data of the current block
uint32_t pos; // Position in data
bool in_section; // Inside a data section
uint32_t section_done; // Bytes of the section handled
sb3_section_header_t section;
bool in_range; // Inside a data range
uint32_t range_gap; // Padding after the range, 16 byte alignment
sb3_data_range_header_t range;
bool has_expansion; // Range expansion read
bool executed; // Execute command seen: firmware loaded
};
static struct sb3 s_sb3;
static uint32_t antipole(uint32_t v) {
return (v & 0xffffU) | (~(v & 0xffffU) << 16);
}
// Manifest parameters: root of trust for NXP signed images, rev A2 chips.
// See nboot_hal_get_sb3_manifest_params(), nboot_hal.c
static bool manifest_params(nboot_sb3_load_manifest_parms_t *p) {
static const uint32_t rkh_a2[8] = {0xE7C7E9BB, 0x12C8C535, 0x37E61148,
0x2BE7F18C, 0x8F0E3094, 0xB2BA7F32,
0xEC9B4ECB, 0xAD9FC941};
uint32_t i, lcs = OCOTP->OTP_SHADOW[OTP_LCS_FUSE_IDX];
memset(p, 0, sizeof(*p));
if ((lcs & 0xff) != ((lcs >> 8) & 0xff)) return false; // Corrupt LCS
for (i = 0; i < NBOOT_ROOT_CERT_COUNT; i++) {
p->soc_RoTNVM.soc_rootKeyRevocation[i] = kNBOOT_RootKey_Enabled;
}
memcpy(p->soc_RoTNVM.soc_rkh, rkh_a2, sizeof(rkh_a2));
p->soc_RoTNVM.soc_numberOfRootKeys = 1;
for (i = 1; i < NBOOT_ROOT_CERT_COUNT; i++) {
p->soc_RoTNVM.soc_rootKeyUsage[i] = kNBOOT_RootKeyUsage_Unused;
}
p->soc_RoTNVM.soc_rootKeyTypeAndLength = kNBOOT_RootKey_Ecdsa_P256;
p->soc_RoTNVM.soc_lifecycle = (nboot_soc_lifecycle_t) antipole(lcs & 0xff);
for (i = 0; i < sizeof(p->pckBlob) / 4; i++) {
if (OCOTP_OtpFuseRead(OTP_PCK_BLOB_FUSE_IDX + i,
(uint32_t *) &p->pckBlob[4 * i]) != kStatus_Success) {
return false;
}
}
return true;
}
// Manifest (block 0): verify, learn the block layout. See ldr_DoHeader_v3()
static bool sb3_header(struct sb3 *s) {
nboot_sb3_header_t *h = (nboot_sb3_header_t *) s->buf;
nboot_sb3_load_manifest_parms_t parms;
if (s->buf_size == sizeof(nboot_sb3_header_t)) { // Header only so far
s->buf_size = h->imageTotalLength;
s->buf_pos = sizeof(nboot_sb3_header_t);
return s->buf_size <= sizeof(s->buf);
}
if (!manifest_params(&parms)) return false;
// Protected status: the status code is in the low 32 bits
if ((nboot_status_t) nboot_sb3_load_manifest(&s->nboot, (uint32_t *) h,
&parms) != kStatus_NBOOT_Success) {
return false;
}
s->data_offset = 4 + h->certificateBlockOffset - sizeof(nboot_sb3_header_t);
s->buf_size = s->data_offset + NBOOT_SB3_CHUNK_SIZE_IN_BYTES;
s->header_done = true;
return true;
}
// Copy (part of) the current load range to its destination
static void sb3_load(struct sb3 *s) {
uint32_t avail = NBOOT_SB3_CHUNK_SIZE_IN_BYTES - s->pos;
uint32_t n = s->range.length < avail ? s->range.length : avail;
memcpy((void *) s->range.startAddress, &s->data[s->pos], n);
s->pos += n, s->section_done += n;
s->range.startAddress += n, s->range.length -= n;
if (s->range.length == 0) { // Range done, skip alignment padding
s->in_range = false;
s->pos += s->range_gap, s->section_done += s->range_gap;
}
}
// Process one decrypted data block. See ldr_DoBlock()
static bool sb3_block(struct sb3 *s) {
while (s->pos < NBOOT_SB3_CHUNK_SIZE_IN_BYTES) {
if (!s->in_section) { // New section
memcpy(&s->section, &s->data[s->pos], sizeof(s->section));
if (s->section.sectionType == kSectionNone) break; // Rest is unused
if (s->section.sectionType != kSectionDataRange) return false;
s->in_section = true, s->section_done = 0, s->in_range = false;
s->pos += sizeof(sb3_section_header_t);
}
if (!s->in_range) { // New range
memcpy(&s->range, &s->data[s->pos], sizeof(s->range));
if (s->range.tag != SB3_DATA_RANGE_HEADER_TAG) return false;
s->in_range = true, s->has_expansion = false, s->range_gap = 0;
s->pos += sizeof(sb3_data_range_header_t);
s->section_done += sizeof(sb3_data_range_header_t);
if (s->range.cmd == kSB3_CmdLoad) {
s->range_gap = (SB3_DATA_ALIGNMENT_SIZE_IN_BYTE -
(s->range.length & 15U)) & 15U;
}
}
if (s->range.cmd == kSB3_CmdLoad) {
if (!s->has_expansion) {
if (s->pos == NBOOT_SB3_CHUNK_SIZE_IN_BYTES) break; // Next block
s->has_expansion = true;
s->pos += sizeof(sb3_data_range_expansion_t);
s->section_done += sizeof(sb3_data_range_expansion_t);
}
if (s->pos < NBOOT_SB3_CHUNK_SIZE_IN_BYTES) sb3_load(s);
} else if (s->range.cmd == kSB3_CmdExecute) {
s->executed = true;
return true;
} else {
s->in_range = false; // Other commands: nothing to do
}
if (s->section_done == s->section.length) s->in_section = false;
if (s->section_done > s->section.length) return false;
}
s->pos = 0;
return true;
}
// Feed image bytes, process complete blocks. See fsl_sbloader_pump()
static bool sb3_pump(struct sb3 *s, const uint8_t *p, uint32_t len) {
while (len > 0 && !s->executed) {
uint32_t n = s->buf_size - s->buf_pos;
if (n > len) n = len;
memcpy(&s->buf[s->buf_pos], p, n);
s->buf_pos += n, p += n, len -= n;
if (s->buf_pos < s->buf_size) break;
s->buf_pos = 0;
if (!s->header_done) {
if (!sb3_header(s)) return false;
} else {
if (s->blocks >= s->nboot.totalBlocks) return false;
if ((nboot_status_t) nboot_sb3_load_block(
&s->nboot, (uint32_t *) s->buf) != kStatus_NBOOT_Success) {
return false;
}
s->blocks++;
s->data = &s->buf[s->data_offset];
if (!sb3_block(s)) return false;
}
}
return true;
}
// Authenticate the image with the ROM, copy it to CPU2 memory.
// See loader_process_sb_file()
static bool sb3_process(const uint8_t *img, size_t len) {
struct sb3 *s = &s_sb3;
bool ok = false;
memset(s, 0, sizeof(*s));
s->buf_size = sizeof(nboot_sb3_header_t);
// Start ELS only if it is off: the ROM keeps keys in it after boot
if ((CLKCTL0->PSCCTL0 & CLKCTL0_PSCCTL0_ELS_MASK) == 0 ||
(CLKCTL0->PSCCTL1 & CLKCTL0_PSCCTL1_ELS_APB_MASK) == 0 ||
(RSTCTL0->PRSTCTL0 & RSTCTL0_PRSTCTL0_ELS_MASK) != 0) {
CLOCK_EnableClock(kCLOCK_Els);
CLOCK_EnableClock(kCLOCK_ElsApb);
RESET_PeripheralReset(kELS_RST_SHIFT_RSTn);
}
if (nboot_context_init(&s->nboot) == kStatus_NBOOT_Success) {
ok = sb3_pump(s, img, (uint32_t) len) && s->executed;
(void) nboot_context_deinit(&s->nboot);
}
return ok;
}
// Load the radio firmware to CPU2 and start it. See sb3_fw_reset() and
// load_service_monolithic(), fsl_loader_utils.c. Call before changing the
// boot clock: the ROM trims the ELS glitch detector for it, and after the
// clock change ELS reports glitch events. Interrupts may be off.
// Return 0 on success, or the failed step: 1 chip revision, 2 OTP, 3 image
// load, 4 firmware start
int hal_radio_init(void) {
uint32_t n = 100000000; // Firmware start timeout, loop iterations
bool ok;
if ((SOCCTRL->CHIP_INFO & 15U) != 2U) return 1; // Image is for rev A2
POWER_PowerOffBle();
spin(100000);
if (otp_init(0) != kStatus_Success) return 2;
POWER_PowerOnBle();
spin(100000);
CPU2_MAGIC = 0;
ok = sb3_process(radio_fw, (size_t) (radio_fw_end - radio_fw));
(void) otp_deinit();
if (!ok) return 3;
CIU2_RST_SW3 |= CIU2_RST_SW3_CPU2_RST;
while (CPU2_MAGIC != CPU2_MAGIC_VALUE) {
if (--n == 0) return 4; // Firmware did not start
}
return 0;
}
@@ -0,0 +1,338 @@
#include "RW612.h"
void Reset_Handler(void); // Defined below
void Dummy_Handler(void); // Defined below
void SysTick_Handler(void); // Defined in main.c
void SystemInit(void); // Defined in main.c, called by reset handler
void __StackTop(void); // Defined in link.ld
void _image_size(void);
#define WEAK __attribute__((weak, alias("Default_Handler")))
void Default_Handler(void);
WEAK void NMI_Handler(void);
WEAK void HardFault_Handler(void);
WEAK void MemManage_Handler(void);
WEAK void BusFault_Handler(void);
WEAK void UsageFault_Handler(void);
WEAK void SecureFault_Handler(void);
WEAK void SVC_Handler(void);
WEAK void DebugMon_Handler(void);
WEAK void PendSV_Handler(void);
WEAK void SysTick_Handler(void);
WEAK void IntDefaultHandler(void);
WEAK void WDT0_IRQHandler(void);
WEAK void DMA0_IRQHandler(void);
WEAK void GPIO_INTA_IRQHandler(void);
WEAK void GPIO_INTB_IRQHandler(void);
WEAK void PIN_INT0_IRQHandler(void);
WEAK void PIN_INT1_IRQHandler(void);
WEAK void PIN_INT2_IRQHandler(void);
WEAK void PIN_INT3_IRQHandler(void);
WEAK void UTICK_IRQHandler(void);
WEAK void MRT_IRQHandler(void);
WEAK void CTIMER0_IRQHandler(void);
WEAK void CTIMER1_IRQHandler(void);
WEAK void SCT0_IRQHandler(void);
WEAK void CTIMER3_IRQHandler(void);
WEAK void FLEXCOMM0_IRQHandler(void);
WEAK void FLEXCOMM1_IRQHandler(void);
WEAK void FLEXCOMM2_IRQHandler(void);
WEAK void FLEXCOMM3_IRQHandler(void);
WEAK void Reserved34_IRQHandler(void);
WEAK void Reserved35_IRQHandler(void);
WEAK void FLEXCOMM14_IRQHandler(void);
WEAK void Reserved37_IRQHandler(void);
WEAK void Reserved38_IRQHandler(void);
WEAK void GFMRT_IRQHandler(void);
WEAK void Reserved40_IRQHandler(void);
WEAK void DMIC_IRQHandler(void);
WEAK void WKDEEPSLEEP_IRQHandler(void);
WEAK void HYPERVISOR_IRQHandler(void);
WEAK void SECUREVIOLATION_IRQHandler(void);
WEAK void HWVAD_IRQHandler(void);
WEAK void Reserved46_IRQHandler(void);
WEAK void Reserved47_IRQHandler(void);
WEAK void RTC_IRQHandler(void);
WEAK void Reserved49_IRQHandler(void);
WEAK void Reserved50_IRQHandler(void);
WEAK void PIN_INT4_IRQHandler(void);
WEAK void PIN_INT5_IRQHandler(void);
WEAK void PIN_INT6_IRQHandler(void);
WEAK void PIN_INT7_IRQHandler(void);
WEAK void CTIMER2_IRQHandler(void);
WEAK void CTIMER4_IRQHandler(void);
WEAK void OS_EVENT_TIMER_IRQHandler(void);
WEAK void FLEXSPI_IRQHandler(void);
WEAK void Reserved59_IRQHandler(void);
WEAK void Reserved60_IRQHandler(void);
WEAK void Reserved61_IRQHandler(void);
WEAK void SDIO_IRQHandler(void);
WEAK void SGPIO_INTA_IRQHandler(void);
WEAK void SGPIO_INTB_IRQHandler(void);
WEAK void Reserved65_IRQHandler(void);
WEAK void USB_IRQHandler(void);
WEAK void Reserved67_IRQHandler(void);
WEAK void Reserved68_IRQHandler(void);
WEAK void Reserved69_IRQHandler(void);
WEAK void DMA1_IRQHandler(void);
WEAK void PUF_IRQHandler(void);
WEAK void POWERQUAD_IRQHandler(void);
WEAK void Reserved73_IRQHandler(void);
WEAK void Reserved74_IRQHandler(void);
WEAK void Reserved75_IRQHandler(void);
WEAK void Reserved76_IRQHandler(void);
WEAK void LCD_IRQHandler(void);
WEAK void CAPTIMER_IRQHandler(void);
WEAK void Reserved79_IRQHandler(void);
WEAK void W2MWKUP_DONE0_IRQHandler(void);
WEAK void W2MWKUP_DONE1_IRQHandler(void);
WEAK void W2MWKUP_DONE2_IRQHandler(void);
WEAK void W2MWKUP_DONE3_IRQHandler(void);
WEAK void W2MWKUP_DONE4_IRQHandler(void);
WEAK void W2MWKUP_DONE5_IRQHandler(void);
WEAK void W2MWKUP_DONE6_IRQHandler(void);
WEAK void W2MWKUP_DONE7_IRQHandler(void);
WEAK void W2MWKUP0_IRQHandler(void);
WEAK void W2MWKUP1_IRQHandler(void);
WEAK void WL_MCI_INT0_IRQHandler(void);
WEAK void WL_MCI_INT1_IRQHandler(void);
WEAK void WL_MCI_INT2_IRQHandler(void);
WEAK void WL_MCI_INT3_IRQHandler(void);
WEAK void WL_MCI_INT4_IRQHandler(void);
WEAK void WL_MCI_INT5_IRQHandler(void);
WEAK void WL_MCI_INT6_IRQHandler(void);
WEAK void WL_MCI_INT7_IRQHandler(void);
WEAK void B2MWKUP_DONE0_IRQHandler(void);
WEAK void B2MWKUP_DONE1_IRQHandler(void);
WEAK void B2MWKUP_DONE2_IRQHandler(void);
WEAK void B2MWKUP_DONE3_IRQHandler(void);
WEAK void B2MWKUP_DONE4_IRQHandler(void);
WEAK void B2MWKUP_DONE5_IRQHandler(void);
WEAK void B2MWKUP_DONE6_IRQHandler(void);
WEAK void B2MWKUP_DONE7_IRQHandler(void);
WEAK void B2MWKUP0_IRQHandler(void);
WEAK void B2MWKUP1_IRQHandler(void);
WEAK void BLE_MCI_INT0_IRQHandler(void);
WEAK void BLE_MCI_INT1_IRQHandler(void);
WEAK void BLE_MCI_INT2_IRQHandler(void);
WEAK void BLE_MCI_INT3_IRQHandler(void);
WEAK void BLE_MCI_INT4_IRQHandler(void);
WEAK void BLE_MCI_INT5_IRQHandler(void);
WEAK void BLE_MCI_INT6_IRQHandler(void);
WEAK void BLE_MCI_INT7_IRQHandler(void);
WEAK void PIN0_INT_IRQHandler(void);
WEAK void PIN1_INT_IRQHandler(void);
WEAK void ELS_IRQHandler(void);
WEAK void ELS_GDET_IRQHandler(void);
WEAK void ELS_GDET_UM_IRQHandler(void);
WEAK void PKC_INT_IRQHandler(void);
WEAK void PKC_ERR_IRQHandler(void);
WEAK void CDOG_INT_IRQHandler(void);
WEAK void GAU_DAC_IRQHandler(void);
WEAK void GAU_ACOMP_WKUP_IRQHandler(void);
WEAK void GAU_ACOMP_IRQHandler(void);
WEAK void GAU_ADC1_IRQHandler(void);
WEAK void GAU_ADC0_IRQHandler(void);
WEAK void USIM_IRQHandler(void);
WEAK void OTP_IRQHandler(void);
WEAK void ENET_IRQHandler(void);
WEAK void ENET_TIMER_IRQHandler(void);
WEAK void PMIP_IRQHandler(void);
WEAK void PMIP_CHANGE_IRQHandler(void);
WEAK void ITRC_IRQHandler(void);
WEAK void Reserved136_IRQHandler(void);
WEAK void Reserved137_IRQHandler(void);
WEAK void Reserved138_IRQHandler(void);
WEAK void TRNG_IRQHandler(void);
WEAK void ACC_C_INT_IRQHandler(void);
WEAK void ACC_S_INT_IRQHandler(void);
WEAK void WACC_IRQHandler(void);
WEAK void BACC_IRQHandler(void);
WEAK void GDMA_IRQHandler(void);
#define WEAK_ALIAS __attribute__((weak, alias("Default_Handler")))
__attribute__((section(".vectors"))) void (*const tab[16 + 156])(void) = {
&__StackTop, // The initial stack pointer
Reset_Handler, // The reset handler
NMI_Handler, // NMI Handler
HardFault_Handler, // Hard Fault Handler
MemManage_Handler, // MPU Fault Handler
BusFault_Handler, // Bus Fault Handler
UsageFault_Handler, // Usage Fault Handler
SecureFault_Handler, // Secure Fault Handler
&_image_size, // Image size
0, // Image type
0, // Reserved
SVC_Handler, // SVCall Handler
DebugMon_Handler, // Debug Monitor Handler
(void (*)())tab, // Image load address
PendSV_Handler, // PendSV Handler
SysTick_Handler, // SysTick Handler
// Chip Level - RW612
WDT0_IRQHandler, // 16 : Windowed watchdog timer 0 (WDT0)(Cortex-M33 watchdog)
DMA0_IRQHandler, // 17 : Direct memory access (DMA) controller 0 (secure or Cortex-M33 DMA)
GPIO_INTA_IRQHandler, // 18 : GPIO interrupt A
GPIO_INTB_IRQHandler, // 19 : GPIO interrupt B
PIN_INT0_IRQHandler, // 20 : Pin interrupt 0 or pattern match engine slice 0
PIN_INT1_IRQHandler, // 21 : Pin interrupt 1 or pattern match engine slice 1
PIN_INT2_IRQHandler, // 22 : Pin interrupt 2 or pattern match engine slice 2
PIN_INT3_IRQHandler, // 23 : Pin interrupt 3 or pattern match engine slice 3
UTICK_IRQHandler, // 24 : Micro-tick Timer (UTICK)
MRT_IRQHandler, // 25 : Multi-Rate Timer (MRT). Global MRT interrupts
CTIMER0_IRQHandler, // 26 : Standard counter/timer CTIMER0
CTIMER1_IRQHandler, // 27 : Standard counter/timer CTIMER1
SCT0_IRQHandler, // 28 : SCTimer/PWM
CTIMER3_IRQHandler, // 29 : Standard counter/timer CTIMER3
FLEXCOMM0_IRQHandler, // 30 : Flexcomm Interface 0 (USART, SPI, I2C, I2S)
FLEXCOMM1_IRQHandler, // 31 : Flexcomm Interface 1 (USART, SPI, I2C, I2S)
FLEXCOMM2_IRQHandler, // 32 : Flexcomm Interface 2 (USART, SPI, I2C, I2S)
FLEXCOMM3_IRQHandler, // 33 : Flexcomm Interface 3 (USART, SPI, I2C, I2S)
Reserved34_IRQHandler, // 34 : Reserved interrupt
Reserved35_IRQHandler, // 35 : Reserved interrupt
FLEXCOMM14_IRQHandler, // 36 : Flexcomm Interface 14 (USART, SPI, I2C, I2S)
Reserved37_IRQHandler, // 37 : Reserved interrupt
Reserved38_IRQHandler, // 38 : Reserved interrupt
GFMRT_IRQHandler, // 39 : Free Multi-rate timer (GFMRT). Global MRT interrupts
Reserved40_IRQHandler, // 40 : Reserved interrupt
DMIC_IRQHandler, // 41 : Digital microphone (DMIC) and DMIC subsystem
WKDEEPSLEEP_IRQHandler, // 42 : Wake-up from deep sleep
HYPERVISOR_IRQHandler, // 43 : Hypervisor service software interrupt
SECUREVIOLATION_IRQHandler, // 44 : Secure violation
HWVAD_IRQHandler, // 45 : Hardware Voice Activity Detector
Reserved46_IRQHandler, // 46 : Reserved interrupt
Reserved47_IRQHandler, // 47 : Reserved interrupt
RTC_IRQHandler, // 48 : RTC alarm and wake-up
Reserved49_IRQHandler, // 49 : Reserved interrupt
Reserved50_IRQHandler, // 50 : Reserved interrupt
PIN_INT4_IRQHandler, // 51 : Pin interrupt 4 or pattern match engine slice 4
PIN_INT5_IRQHandler, // 52 : Pin interrupt 5 or pattern match engine slice 5
PIN_INT6_IRQHandler, // 53 : Pin interrupt 6 or pattern match engine slice 6
PIN_INT7_IRQHandler, // 54 : Pin interrupt 7 or pattern match engine slice 7
CTIMER2_IRQHandler, // 55 : Standard counter/timer CTIMER2
CTIMER4_IRQHandler, // 56 : Standard counter/timer CTIMER4
OS_EVENT_TIMER_IRQHandler, // 57 : OS event timer 0
FLEXSPI_IRQHandler, // 58 : FLEXSPI interface
Reserved59_IRQHandler, // 59 : Reserved interrupt
Reserved60_IRQHandler, // 60 : Reserved interrupt
Reserved61_IRQHandler, // 61 : Reserved interrupt
SDIO_IRQHandler, // 62 : The secure digital interface
SGPIO_INTA_IRQHandler, // 63 : Secure GPIO interrupt A
SGPIO_INTB_IRQHandler, // 64 : Secure GPIO interrupt B
Reserved65_IRQHandler, // 65 : Reserved interrupt
USB_IRQHandler, // 66 : High-speed USB device/host
Reserved67_IRQHandler, // 67 : Reserved interrupt
Reserved68_IRQHandler, // 68 : Reserved interrupt
Reserved69_IRQHandler, // 69 : Reserved interrupt
DMA1_IRQHandler, // 70 : DMA controller 1 (non-secure or HiFi 4 DMA)
PUF_IRQHandler, // 71 : Physical Unclonable Function
POWERQUAD_IRQHandler, // 72 : PowerQuad math coprocessor
Reserved73_IRQHandler, // 73 : Reserved interrupt
Reserved74_IRQHandler, // 74 : Reserved interrupt
Reserved75_IRQHandler, // 75 : Reserved interrupt
Reserved76_IRQHandler, // 76 : Reserved interrupt
LCD_IRQHandler, // 77 : LCDIC
CAPTIMER_IRQHandler, // 78 : Capture timer
Reserved79_IRQHandler, // 79 : Reserved interrupt
W2MWKUP_DONE0_IRQHandler, // 80 : Wi-Fi to MCU, wakeup done 0
W2MWKUP_DONE1_IRQHandler, // 81 : Wi-Fi to MCU, wakeup done 1
W2MWKUP_DONE2_IRQHandler, // 82 : Wi-Fi to MCU, wakeup done 2
W2MWKUP_DONE3_IRQHandler, // 83 : Wi-Fi to MCU, wakeup done 3
W2MWKUP_DONE4_IRQHandler, // 84 : Wi-Fi to MCU, wakeup done 4
W2MWKUP_DONE5_IRQHandler, // 85 : Wi-Fi to MCU, wakeup done 5
W2MWKUP_DONE6_IRQHandler, // 86 : Wi-Fi to MCU, wakeup done 6
W2MWKUP_DONE7_IRQHandler, // 87 : Wi-Fi to MCU, wakeup done 7
W2MWKUP0_IRQHandler, // 88 : Wi-Fi to MCU, wakeup signal 0
W2MWKUP1_IRQHandler, // 89 : Wi-Fi to MCU, wakueup signal 1
WL_MCI_INT0_IRQHandler, // 90 : Wi-Fi to MCU interrupt 0
WL_MCI_INT1_IRQHandler, // 91 : Reserved for Wi-Fi to MCU
WL_MCI_INT2_IRQHandler, // 92 : Reserved for Wi-Fi to MCU
WL_MCI_INT3_IRQHandler, // 93 : Reserved for Wi-Fi to MCU
WL_MCI_INT4_IRQHandler, // 94 : Reserved for Wi-Fi to MCU
WL_MCI_INT5_IRQHandler, // 95 : Reserved for Wi-Fi to MCU
WL_MCI_INT6_IRQHandler, // 96 : Reserved for Wi-Fi to MCU
WL_MCI_INT7_IRQHandler, // 97 : Reserved for Wi-Fi to MCU
B2MWKUP_DONE0_IRQHandler, // 98 : Bluetooth LE/802.15.4 radio to MCU, wakeup done 0
B2MWKUP_DONE1_IRQHandler, // 99 : Bluetooth LE/802.15.4 radio to MCU, wakeup done 1
B2MWKUP_DONE2_IRQHandler, // 100: Bluetooth LE/802.15.4 radio to MCU, wakeup done 2
B2MWKUP_DONE3_IRQHandler, // 101: Bluetooth LE/802.15.4 radio to MCU, wakeup done 3
B2MWKUP_DONE4_IRQHandler, // 102: Bluetooth LE/802.15.4 radio to MCU, wakeup done 4
B2MWKUP_DONE5_IRQHandler, // 103: Bluetooth LE/802.15.4 radio to MCU, wakeup done 5
B2MWKUP_DONE6_IRQHandler, // 104: Bluetooth LE/802.15.4 radio to MCU, wakeup done 6
B2MWKUP_DONE7_IRQHandler, // 105: Bluetooth LE/802.15.4 radio to MCU, wakeup done 7
B2MWKUP0_IRQHandler, // 106: Bluetooth LE/802.15.4 radio to MCU, wakeup signal 0
B2MWKUP1_IRQHandler, // 107: Bluetooth LE/802.15.4 radio to MCU, wakeup signal 1
BLE_MCI_INT0_IRQHandler, // 108: Bluetooth LE/802.15.4 radio to MCU interrupt 0
BLE_MCI_INT1_IRQHandler, // 109: Reserved for Bluetooth LE/802.15.4 radio to MCU
BLE_MCI_INT2_IRQHandler, // 110: Reserved for Bluetooth LE/802.15.4 radio to MCU
BLE_MCI_INT3_IRQHandler, // 111: Reserved for Bluetooth LE/802.15.4 radio to MCU
BLE_MCI_INT4_IRQHandler, // 112: Reserved for Bluetooth LE/802.15.4 radio to MCU
BLE_MCI_INT5_IRQHandler, // 113: Reserved for Bluetooth LE/802.15.4 radio to MCU
BLE_MCI_INT6_IRQHandler, // 114: Reserved for Bluetooth LE/802.15.4 radio to MCU
BLE_MCI_INT7_IRQHandler, // 115: Reserved for Bluetooth LE/802.15.4 radio to MCU
PIN0_INT_IRQHandler, // 116: From AON GPIO
PIN1_INT_IRQHandler, // 117: From AON GPIO
ELS_IRQHandler, // 118: EdgeLock subsystem (ELS)
ELS_GDET_IRQHandler, // 119: ELS IRQ line for GDET error
ELS_GDET_UM_IRQHandler, // 120: ELS un-gated latched error
PKC_INT_IRQHandler, // 121: Public key crypto-processor (PKC) interrupt
PKC_ERR_IRQHandler, // 122: PKC error
CDOG_INT_IRQHandler, // 123: Code watch dog timmer interrupt
GAU_DAC_IRQHandler, // 124: General analog unit (GAU) digital to analog converter (DAC)
GAU_ACOMP_WKUP_IRQHandler, // 125: GAU analog comparator (ACOMP) wake-up
GAU_ACOMP_IRQHandler, // 126: GAU analog comparator
GAU_ADC1_IRQHandler, // 127: GAU analog to digital converter 1 (ADC1)
GAU_ADC0_IRQHandler, // 128: GAU analog to digital converter 0 (ADC0)
USIM_IRQHandler, // 129: Universal subscriber identity module (USIM) interface
OTP_IRQHandler, // 130: One time programmable (OTP) memory interrupt
ENET_IRQHandler, // 131: Etheret interrupt
ENET_TIMER_IRQHandler, // 132: Ethernet timer interrupt
PMIP_IRQHandler, // 133: Power management IP (PMIP)
PMIP_CHANGE_IRQHandler, // 134: PMIP change from 1 to 0
ITRC_IRQHandler, // 135: Intrusion and tamper response controller (ITRC) interrupt request
Reserved136_IRQHandler, // 136: Reserved interrupt
Reserved137_IRQHandler, // 137: Reserved interrupt
Reserved138_IRQHandler, // 138: Reserved interrupt
TRNG_IRQHandler, // 139: TRNG interrupt request
ACC_C_INT_IRQHandler, // 140: AHB memory access checker - Cortex-M33 code bus
ACC_S_INT_IRQHandler, // 141: AHB memory access checker - Cortex-M33 sys bus
WACC_IRQHandler, // 142: Wi-Fi accessed during power off
BACC_IRQHandler, // 143: Bluetooth LE/802.15.4 radio accessed during power off
GDMA_IRQHandler, // 144: General purpose direct memory access (GDMA) interrupt
};
extern unsigned char _end[]; // End of data section, start of heap. See link.ld
__attribute__((naked, noreturn)) void Reset_Handler(void) {
__asm("cpsid i"); // Disable interrupts
// Config VTOR & MSPLIM register
__asm("LDR R0, =0xE000ED08 \n"
"STR %0, [R0] \n"
"LDR R1, [%0] \n"
"MSR MSP, R1 \n"
"MSR MSPLIM, %1 \n"
:
: "r"(tab), "r"(_end)
: "r0", "r1");
extern long _sbss, _ebss, _sdata, _edata, _sidata, _siram, _siiram, _eiram;
for (long *dst = &_sbss; dst < &_ebss; dst++) *dst = 0;
for (long *dst = &_sdata, *src = &_sidata; dst < &_edata;) *dst++ = *src++;
for (long *dst = &_siram, *src = &_siiram; dst < &_eiram;) *dst++ = *src++;
SystemInit();
__asm("cpsie i"); // Reenable interrupts
// Call main()
extern void main(void);
main();
for (;;) (void) 0; // Infinite loop
}
void SystemCoreClockUpdate (void) {
}
void Default_Handler(void) {
for (;;) (void) 0;
}
+5
View File
@@ -65,6 +65,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
.key = mg_str(TLS_KEY)}; .key = mg_str(TLS_KEY)};
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} else if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
+5
View File
@@ -61,6 +61,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
.key = mg_str(TLS_KEY)}; .key = mg_str(TLS_KEY)};
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} else if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
+5
View File
@@ -65,6 +65,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
.key = mg_str(TLS_KEY)}; .key = mg_str(TLS_KEY)};
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} else if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
+6 -1
View File
@@ -5,7 +5,12 @@
#include "mongoose.h" #include "mongoose.h"
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
uint64_t tick = to_ms_since_boot(get_absolute_time()); uint64_t tick = to_ms_since_boot(get_absolute_time());
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
+6 -1
View File
@@ -33,7 +33,12 @@ static void driver_init(struct mg_mgr *mgr) {
} }
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
uint64_t tick = to_ms_since_boot(get_absolute_time()); uint64_t tick = to_ms_since_boot(get_absolute_time());
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
+6 -1
View File
@@ -58,7 +58,12 @@ static void driver_init(struct mg_mgr *mgr) {
} }
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
uint64_t tick = to_ms_since_boot(get_absolute_time()); uint64_t tick = to_ms_since_boot(get_absolute_time());
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
+5
View File
@@ -39,6 +39,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
.key = mg_str(TLS_KEY)}; .key = mg_str(TLS_KEY)};
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} else if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
uint64_t tick = to_ms_since_boot(get_absolute_time()); uint64_t tick = to_ms_since_boot(get_absolute_time());
+5
View File
@@ -82,6 +82,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
.key = mg_str(TLS_KEY)}; .key = mg_str(TLS_KEY)};
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} else if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
uint64_t tick = to_ms_since_boot(get_absolute_time()); uint64_t tick = to_ms_since_boot(get_absolute_time());
+5
View File
@@ -195,6 +195,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
.key = mg_str(TLS_KEY)}; .key = mg_str(TLS_KEY)};
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} else if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
uint64_t tick = to_ms_since_boot(get_absolute_time()); uint64_t tick = to_ms_since_boot(get_absolute_time());
@@ -0,0 +1,9 @@
# Nucleo-C5A3ZI Mongoose Integration
The `.ioc2` file in this directory is pre-configured. Note that after the
project generation, you should do the following to complete integraion:
1. Edit the linker script `.ld` file and increase heap and stack sizes to
0x20000 and 0x4000 respectively
2. Add Mongoose to the `main.c`, see https://mongoose.ws/docs/guides/stm32-tcpip-stack/#modify-mainc
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,46 @@
# Copyright (c) 2026 Cesanta Software Limited
# Environment setup: https://mongoose.ws/docs/getting-started/build-environment/
MGDIR = ../../../..
CFLAGS = -W -Wall -Wextra -Wundef -Wshadow -Wdouble-promotion
CFLAGS += -Wformat-truncation -fno-common -Wconversion -Wno-sign-conversion
CFLAGS += -g3 -Os -ffunction-sections -fdata-sections
CFLAGS += -I. -I$(MGDIR) -Icmsis_core/CMSIS/Core/Include -Icmsis_c5/Include -DSTM32C5A3xx
CFLAGS += -mcpu=cortex-m33 -mthumb -mfpu=fpv5-sp-d16 -mfloat-abi=hard $(CFLAGS_EXTRA)
LDFLAGS ?= -Tlink.ld -nostdlib -nostartfiles --specs nano.specs -lc -lgcc -Wl,--gc-sections
SOURCES = main.c hal.c
SOURCES += cmsis_c5/Source/startup_stm32c5a3xx.c
SOURCES += $(MGDIR)/mongoose.c
all build example: firmware.bin
firmware.elf: cmsis_core cmsis_c5 hal.h link.ld Makefile $(SOURCES) $(MGDIR)/mongoose.h mongoose_config.h
arm-none-eabi-gcc $(SOURCES) $(CFLAGS) $(CFLAGS_EXTRA) $(LDFLAGS) -o $@
firmware.bin: firmware.elf
arm-none-eabi-objcopy -O binary $< $@
@echo
@echo "To flash, run 'make flash', or use STM32CubeProgrammer"
firmware.signed.bin: firmware.bin
test -f private.pem || node $(MGDIR)/resources/sign.js keygen
node $(MGDIR)/resources/sign.js sign firmware.bin
# Show all symbols sorted by size
show_symbols_sorted_by_size: firmware.bin
arm-none-eabi-readelf -sW firmware.elf | sed 1,3d | sed 's,^.*: ,,' | tr -s ' ' | cut -d ' ' -f 2,7 | sort -nk1 | grep -v '^0 '
# If the board gets stuck: STM32_Programmer_CLI -c port=swd -e all mode=UR
flash: firmware.bin
STM32_Programmer_CLI -c port=swd -w firmware.elf mode=UR -rst
cmsis_core:
git clone -q -c advice.detachedHead=false --depth 1 -b v6.4.0 https://github.com/ARM-software/CMSIS_6 $@
cmsis_c5:
git clone -q -c advice.detachedHead=false --depth 1 -b 2.1.0 https://github.com/STMicroelectronics/stm32c5xx-dfp $@
clean:
rm -rf firmware.* cmsis_*
+141
View File
@@ -0,0 +1,141 @@
// Copyright (c) 2026 Cesanta Software Limited
// All rights reserved
#include "hal.h"
// Added to minimise the bin size: avoid pulling printf and friends
void __assert_func(const char *s, int line, const char *fn, const char *expr) {
(void) s, (void) line, (void) fn, (void) expr;
for (;;) (void) 0; // or trigger the fault handler
}
bool hal_timer_expired(volatile uint64_t *t, uint64_t period, uint64_t now) {
uint64_t diff = now - *t; // Wrap-safe elapsed time since last expiry
if (period == 0) return false; // Avoid division by zero
if (diff < period) return false; // Period has not elapsed yet
*t += (diff / period) * period; // Preserve cadence, skip missed periods
return true;
}
static volatile uint64_t s_ticks; // Milliseconds since boot
void SysTick_Handler(void) { // SyStick IRQ handler, triggered every 1ms
s_ticks++;
}
uint64_t hal_get_tick(void) {
return s_ticks;
};
uint32_t SystemCoreClock = 160000000;
void SystemInit(void) { // Called automatically by startup code
hal_system_init(); // Enable FPU
hal_clock_init();
SysTick_Config(SystemCoreClock / 1000); // Sys tick every 1ms
}
void ExitRun0Mode(void) {
}
// C library entry, called by the CMSIS startup code after it copies .data
// and clears .bss. See __cmsis_start() in cmsis_gcc_m.h
extern int main(void);
extern void __libc_init_array(void);
__attribute__((noreturn)) void _start(void) {
__libc_init_array();
main();
for (;;) (void) 0;
}
struct stat;
__attribute__((weak)) int _fstat(int fd, struct stat *st) {
(void) fd, (void) st;
return -1;
}
extern unsigned char _end[]; // End of data section, start of heap. See link.ld
static unsigned char *s_current_heap_end = _end;
size_t hal_ram_used(void) {
return (size_t) (s_current_heap_end - _end);
}
size_t hal_ram_free(void) {
unsigned char endofstack;
return (size_t) (&endofstack - s_current_heap_end);
}
void *_sbrk(int incr) {
unsigned char *prev_heap;
unsigned char *heap_end = (unsigned char *) ((size_t) &heap_end - 256);
prev_heap = s_current_heap_end;
// Check how much space we got from the heap end to the stack end
if (s_current_heap_end + incr > heap_end) return (void *) -1;
s_current_heap_end += incr;
return prev_heap;
}
__attribute__((weak)) int _open(const char *path) {
(void) path;
return -1;
}
__attribute__((weak)) int _close(int fd) {
(void) fd;
return -1;
}
__attribute__((weak)) int _isatty(int fd) {
(void) fd;
return 1;
}
__attribute__((weak)) int _lseek(int fd, int ptr, int dir) {
(void) fd, (void) ptr, (void) dir;
return 0;
}
__attribute__((weak)) void _exit(int status) {
(void) status;
for (;;) asm volatile("BKPT #0");
}
__attribute__((weak)) void _kill(int pid, int sig) {
(void) pid, (void) sig;
}
__attribute__((weak)) int _getpid(void) {
return -1;
}
__attribute__((weak)) int _write(int fd, char *ptr, int len) {
(void) fd, (void) ptr, (void) len;
return -1;
}
__attribute__((weak)) int _read(int fd, char *ptr, int len) {
(void) fd, (void) ptr, (void) len;
return -1;
}
__attribute__((weak)) int _link(const char *a, const char *b) {
(void) a, (void) b;
return -1;
}
__attribute__((weak)) int _unlink(const char *a) {
(void) a;
return -1;
}
__attribute__((weak)) int _stat(const char *path, struct stat *st) {
(void) path, (void) st;
return -1;
}
__attribute__((weak)) int mkdir(const char *path, int mode) {
(void) path, (void) mode;
return -1;
}
__attribute__((weak)) void _init(void) {
}
+165
View File
@@ -0,0 +1,165 @@
// Copyright (c) 2013-2026 Cesanta Software Limited
// Datasheet: RM0522, devboard manual: UM3616
// https://www.st.com/resource/en/reference_manual/rm0522-stm32c5-series-armbased-32bit-mcus-stmicroelectronics.pdf
// https://www.st.com/resource/en/user_manual/um3616-stm32c5-nucleo144-board-mb2310-stmicroelectronics.pdf
#pragma once
#include <stm32c5xx.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
extern bool hal_timer_expired(volatile uint64_t *t, uint64_t prd, uint64_t now);
extern uint64_t hal_get_tick(void);
extern size_t hal_ram_free(void);
extern size_t hal_ram_used(void);
extern uint32_t SystemCoreClock;
#define BIT(x) (1UL << (x))
#define CLRSET(reg, clear, set) ((reg) = ((reg) & ~(clear)) | (set))
#define PIN(bank, num) ((((bank) - 'A') << 8) | (num))
#define PINNO(pin) (pin & 255)
#define PINBANK(pin) (pin >> 8)
// Ethernet RMII pins and their alternate functions. UM3616 7.11, Table 9
#define HAL_ETH_PINS \
{PIN('A', 1), 10}, /* REF_CLK */ \
{PIN('C', 1), 10}, /* MDC */ \
{PIN('E', 12), 10}, /* MDIO */ \
{PIN('D', 1), 10}, /* CRS_DV */ \
{PIN('C', 4), 12}, /* RXD0 */ \
{PIN('C', 5), 13}, /* RXD1 */ \
{PIN('G', 11), 10}, /* TX_EN */ \
{PIN('G', 13), 10}, /* TXD0 */ \
{PIN('G', 12), 10} /* TXD1 */
// System clock (9.4.2, 9.4.8). HSI runs at 144 MHz, the maximum system clock:
// SYSCLK = HSIS, no PLL. hclk = SYSCLK, APB clocks = hclk. After reset, the
// system runs on HSIDIV3, 48 MHz. Flash latency for 144 MHz: 6.3.6, Table 20
#define SYS_FREQUENCY 144000000
#define AHB_FREQUENCY SYS_FREQUENCY
#define APB2_FREQUENCY AHB_FREQUENCY
#define APB1_FREQUENCY AHB_FREQUENCY
#define HAL_FLASH_LATENCY (4 | FLASH_ACR_WRHIGHFREQ_1) // 4 WS, WRHIGHFREQ 2
enum { HAL_GPIO_MODE_INPUT, HAL_GPIO_MODE_OUTPUT, HAL_GPIO_MODE_AF, HAL_GPIO_MODE_ANALOG };
enum { HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_OTYPE_OPEN_DRAIN };
enum { HAL_GPIO_SPEED_LOW, HAL_GPIO_SPEED_MEDIUM, HAL_GPIO_SPEED_HIGH, HAL_GPIO_SPEED_INSANE };
enum { HAL_GPIO_PULL_NONE, HAL_GPIO_PULL_UP, HAL_GPIO_PULL_DOWN };
#define HAL_GPIO(N) ((GPIO_TypeDef *) (GPIOA_BASE + 0x400 * (N)))
static GPIO_TypeDef *hal_gpio_bank(uint16_t pin) {
return HAL_GPIO(PINBANK(pin));
}
static inline void hal_gpio_toggle(uint16_t pin) {
GPIO_TypeDef *gpio = hal_gpio_bank(pin);
uint32_t mask = BIT(PINNO(pin));
gpio->BSRR = mask << (gpio->ODR & mask ? 16 : 0);
}
static inline int hal_gpio_read(uint16_t pin) {
return hal_gpio_bank(pin)->IDR & BIT(PINNO(pin)) ? 1 : 0;
}
static inline void hal_gpio_write(uint16_t pin, bool val) {
GPIO_TypeDef *gpio = hal_gpio_bank(pin);
gpio->BSRR = BIT(PINNO(pin)) << (val ? 0 : 16);
}
static inline void hal_gpio_init(uint16_t pin, uint8_t mode, uint8_t type,
uint8_t speed, uint8_t pull, uint8_t af) {
GPIO_TypeDef *gpio = hal_gpio_bank(pin);
uint8_t n = (uint8_t) (PINNO(pin));
RCC->AHB2ENR |= BIT(PINBANK(pin)); // Enable GPIO clock
CLRSET(gpio->OTYPER, 1UL << n, ((uint32_t) type) << n);
CLRSET(gpio->OSPEEDR, 3UL << (n * 2), ((uint32_t) speed) << (n * 2));
CLRSET(gpio->PUPDR, 3UL << (n * 2), ((uint32_t) pull) << (n * 2));
CLRSET(gpio->AFR[n >> 3], 15UL << ((n & 7) * 4),
((uint32_t) af) << ((n & 7) * 4));
CLRSET(gpio->MODER, 3UL << (n * 2), ((uint32_t) mode) << (n * 2));
}
static inline void hal_gpio_input(uint16_t pin) {
hal_gpio_init(pin, HAL_GPIO_MODE_INPUT, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_HIGH,
HAL_GPIO_PULL_NONE, 0);
}
static inline void hal_gpio_output(uint16_t pin) {
hal_gpio_init(pin, HAL_GPIO_MODE_OUTPUT, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_HIGH,
HAL_GPIO_PULL_NONE, 0);
}
// USART1 kernel clock defaults to pclk2 (APB2), USART2,3 default to pclk1
// (APB1), see RCC_CCIPR1
static inline void hal_uart_init(USART_TypeDef *uart, uint16_t tx,
uint16_t rx, unsigned long baud) {
uint8_t af = 7; // Alternate function
uint32_t freq = 0; // Bus frequency. UART1 is on APB2, rest on APB1
if (uart == USART1) freq = APB2_FREQUENCY, RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
if (uart == USART2) freq = APB1_FREQUENCY, RCC->APB1LENR |= RCC_APB1LENR_USART2EN;
if (uart == USART3) freq = APB1_FREQUENCY, RCC->APB1LENR |= RCC_APB1LENR_USART3EN;
hal_gpio_init(tx, HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_HIGH, 0, af);
hal_gpio_init(rx, HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_HIGH, 0, af);
uart->CR1 = 0; // Disable this UART
uart->BRR = freq / baud; // Set baud rate
uart->CR1 = BIT(0) | BIT(2) | BIT(3); // Set UE, RE, TE
}
static inline void hal_uart_write_byte(USART_TypeDef *uart, uint8_t byte) {
uart->TDR = byte;
while ((uart->ISR & USART_ISR_TXE_TXFNF) == 0) (void) 0;
}
static inline void hal_uart_write_buf(USART_TypeDef *uart, char *buf, size_t len) {
while (len-- > 0) hal_uart_write_byte(uart, *(uint8_t *) buf++);
}
static inline int hal_uart_read_ready(USART_TypeDef *uart) {
return uart->ISR & BIT(5); // If RXNE bit is set, data is ready
}
static inline uint8_t hal_uart_read_byte(USART_TypeDef *uart) {
return (uint8_t) (uart->RDR & 255);
}
// RNG clock (rng_clk) is CK48, which is disabled after reset. Use HSIDIV3,
// 48 MHz. It stays enabled after the system clock switches to HSIS
static inline void hal_rng_init(void) {
CLRSET(RCC->CCIPR2, RCC_CCIPR2_CK48SEL_Msk, RCC_CCIPR2_CK48SEL_1);
RCC->AHB2ENR |= RCC_AHB2ENR_RNGEN; // Enable RNG AHB clock
RNG->CR |= RNG_CR_RNGEN; // Enable RNG
}
static inline uint32_t hal_rng_read(void) {
while ((RNG->SR & RNG_SR_DRDY) == 0) (void) 0;
return RNG->DR;
}
static inline void hal_ethernet_init(void) {
// Initialise Ethernet. Enable MAC GPIO pins, see UM3616 Table 9
uint16_t pins[][2] = {HAL_ETH_PINS};
for (size_t i = 0; i < sizeof(pins) / sizeof(pins[0]); i++) {
hal_gpio_init(pins[i][0], HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_INSANE,
HAL_GPIO_PULL_NONE, (uint8_t) pins[i][1]);
}
NVIC_EnableIRQ(ETH1_IRQn); // Setup Ethernet IRQ handler
RCC->APB3ENR |= RCC_APB3ENR_SBSEN; // Enable SBS clock
CLRSET(SBS->PMCR, SBS_PMCR_ETH1_SEL_PHY_Msk, SBS_PMCR_ETH1_SEL_PHY_2); // RMII
RCC->AHB1ENR |= RCC_AHB1ENR_ETH1CKEN | RCC_AHB1ENR_ETH1EN |
RCC_AHB1ENR_ETH1TXEN | RCC_AHB1ENR_ETH1RXEN;
}
static inline void hal_clock_init(void) {
CLRSET(FLASH->ACR, FLASH_ACR_LATENCY_Msk | FLASH_ACR_WRHIGHFREQ_Msk,
HAL_FLASH_LATENCY);
while ((FLASH->ACR & FLASH_ACR_LATENCY_Msk) != (HAL_FLASH_LATENCY & 15)) (void) 0;
RCC->CR1 |= RCC_CR1_HSISON; // Enable HSIS, 144 MHz
while ((RCC->CR1 & RCC_CR1_HSISRDY) == 0) (void) 0; // Wait until ready
CLRSET(RCC->CFGR1, RCC_CFGR1_SW_Msk, RCC_CFGR1_SW_0); // SYSCLK = HSIS
while ((RCC->CFGR1 & RCC_CFGR1_SWS_Msk) != RCC_CFGR1_SWS_0) (void) 0;
SystemCoreClock = SYS_FREQUENCY; // Update SystemCoreClock global var
SysTick_Config(SystemCoreClock / 1000); // Sys tick every 1ms
}
static inline void hal_system_init(void) {
SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); // Enable FPU
__DSB();
__ISB();
}
@@ -0,0 +1,37 @@
ENTRY(Reset_Handler);
MEMORY {
flash(rx) : ORIGIN = 0x08000000, LENGTH = 1024k
sram(rwx) : ORIGIN = 0x20000000, LENGTH = 256k - 1k
health(rw) : ORIGIN = 0x2003fc00, LENGTH = 1k /* Retained health record */
}
__StackTop = ORIGIN(sram) + LENGTH(sram); /* End of RAM. stack points here */
_estack = __StackTop; /* Used by the health fault handler */
__StackLimit = __StackTop - 16384; /* Stack limit, MSPLIM. TLS needs > 4 KB */
SECTIONS {
.vectors : { KEEP(*(.vectors)) } > flash
.text : { *(.text* .text.*) } > flash
.rodata : { *(.rodata*) } > flash
/* Copy and zero tables for the CMSIS startup code, see __cmsis_start() */
.copy.table : {
__copy_table_start__ = .;
LONG(LOADADDR(.data)) LONG(ADDR(.data)) LONG(SIZEOF(.data) / 4)
__copy_table_end__ = .;
} > flash
.zero.table : {
__zero_table_start__ = .;
LONG(ADDR(.bss)) LONG(SIZEOF(.bss) / 4)
__zero_table_end__ = .;
} > flash
/* Note the .iram section, for functions copied to RAM. Required for MG_IRAM OTA support */
.data : { _sdata = .; *(.first_data) *(.iram .iram* .iram.*) *(.data SORT(.data.*)) . = ALIGN(4); _edata = .; } > sram AT > flash
_sidata = LOADADDR(.data);
.bss : { _sbss = .; *(.bss SORT(.bss.*) COMMON) . = ALIGN(4); _ebss = .; } > sram
_end = ALIGN(_ebss, 8); /* Heap starts after .bss */
/* Retained health record. Startup code must neither copy nor clear it. */
.mg_health (NOLOAD) : { KEEP(*(.mg_health .mg_health*)) } > health
}
@@ -0,0 +1,115 @@
// Copyright (c) 2026 Cesanta Software Limited
// All rights reserved
#include "hal.h"
#include "mongoose.h"
#define UART_DEBUG USART2 // ST-LINK virtual COM port, UM3616 7.12
#define UART_DEBUG_TX_PIN PIN('A', 2)
#define UART_DEBUG_RX_PIN PIN('A', 3)
#define LED1 PIN('A', 5) // Green, on when high. UM3616 7.8
#define LED2 PIN('G', 1) // Red, on when low
#define LED3 PIN('G', 2) // Blue, on when low
static void log_fn(char ch, void *param) {
hal_uart_write_buf(param, &ch, 1);
}
static void blink_task(void) {
static uint64_t blink_timer = 0;
if (hal_timer_expired(&blink_timer, 500, hal_get_tick())) {
hal_gpio_toggle(LED2);
}
}
uint64_t mg_millis(void) {
return hal_get_tick();
}
bool mg_random(void *buf, size_t len) {
for (size_t n = 0; n < len; n += sizeof(uint32_t)) {
uint32_t r = hal_rng_read();
memcpy((char *) buf + n, &r, n + sizeof(r) > len ? len - n : sizeof(r));
}
return true;
}
// Self-signed P-256 certificate and key for the HTTPS listener. Created by:
// openssl ecparam -genkey -name prime256v1 -noout -out key.pem
// openssl req -x509 -key key.pem -out cert.pem -days 3650 -subj /CN=mg
#define TLS_CERT \
"-----BEGIN CERTIFICATE-----\n" \
"MIIBgjCCASegAwIBAgIUIJOq77Qn7lHbH6WseMemeqorR50wCgYIKoZIzj0EAwIw\n" \
"FjEUMBIGA1UEAwwLbnVjbGVvLWg3MjMwHhcNMjYxMDEyMTUwMjE5WhcNMzYxMDA5\n" \
"MTUwMjE5WjAWMRQwEgYDVQQDDAtudWNsZW8taDcyMzBZMBMGByqGSM49AgEGCCqG\n" \
"SM49AwEHA0IABB6IQJNmzrsdQL+2BnZYS7GYOaj7sz8f6cjBmz3n8D9Em19XodlU\n" \
"uy4ybIvyhr766lL0ERoTmMUivb/lGmzx9C+jUzBRMB0GA1UdDgQWBBQqxMuc4gj7\n" \
"MTMzreWlRMNI3QMqTzAfBgNVHSMEGDAWgBQqxMuc4gj7MTMzreWlRMNI3QMqTzAP\n" \
"BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDY4xaJpuxq6b3rHK3b\n" \
"lOIQyfkQX+orCRqQUkseplqpqwIhAKswZFNn+2zUNRRNY8+cHmdIwmdpsmxtoWYP\n" \
"BCjX++LI\n" \
"-----END CERTIFICATE-----\n"
#define TLS_KEY \
"-----BEGIN EC PRIVATE KEY-----\n" \
"MHcCAQEEIJ/GBl0TlD52q9PMg1KWaNIdXqp8b/HyIsABmBpqC+O1oAoGCCqGSM49\n" \
"AwEHoUQDQgAEHohAk2bOux1Av7YGdlhLsZg5qPuzPx/pyMGbPefwP0SbX1eh2VS7\n" \
"LjJsi/KGvvrqUvQRGhOYxSK9v+UabPH0Lw==\n" \
"-----END EC PRIVATE KEY-----\n"
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_ACCEPT && c->is_tls) { // Accepted on the https:// listener
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
.key = mg_str(TLS_KEY)};
mg_tls_init(c, &opts);
} else if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
mg_http_reply(c, 200, "", "{%m:%llu}\n", MG_ESC("tick"), hal_get_tick());
} else if (mg_match(hm->uri, mg_str("/api/crash"), NULL)) {
__asm volatile("udf #0"); // Trigger HardFault
} else {
mg_http_reply(c, 200, "",
"Hi from Mongoose!\n"
"tick: %llu\n"
"ram used: %zu\n"
"ram free: %zu\n",
hal_get_tick(), hal_ram_used(), hal_ram_free());
}
}
}
int main(void) {
MG_HEALTH_INIT();
hal_clock_init();
hal_uart_init(UART_DEBUG, UART_DEBUG_TX_PIN, UART_DEBUG_RX_PIN, 115200);
mg_log_set_fn(log_fn, UART_DEBUG);
hal_rng_init();
hal_ethernet_init();
hal_gpio_output(LED1);
hal_gpio_output(LED2);
hal_gpio_output(LED3);
struct mg_mgr mgr;
mg_mgr_init(&mgr);
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
mg_http_listen(&mgr, "https://0.0.0.0", http_ev_handler, NULL);
MG_INFO(("Initialised. CPU clock: %lu MHz", SystemCoreClock / 1000000));
MG_INFO(("RAM used: %zu, free: %zu", hal_ram_used(), hal_ram_free()));
MG_INFO(("Crash record: %M", mg_print_crash_record));
for (;;) {
mg_mgr_poll(&mgr, 0);
blink_task();
}
return 0;
}
@@ -0,0 +1,32 @@
#pragma once
#include "hal.h"
// See https://mongoose.ws/docs/getting-started/build-environment/
#define MG_ARCH MG_ARCH_ARMGCC
#define MG_TLS MG_TLS_BUILTIN
#define MG_OTA MG_OTA_STM32C5
#define MG_ENABLE_TCPIP 1
#define MG_ENABLE_CUSTOM_MILLIS 1
#define MG_ENABLE_CUSTOM_RANDOM 1
#define MG_ENABLE_DRIVER_STM32C 1
// Construct MAC address from the MCU unique ID
#define MGUID ((uint32_t *) UID_BASE)
#define MG_SET_MAC_ADDRESS(mac) \
do { \
mac[0] = 2; \
mac[1] = MGUID[0] & 255; \
mac[2] = (MGUID[0] >> 10) & 255; \
mac[3] = (MGUID[0] >> 19) & 255; \
mac[4] = MGUID[1] & 255; \
mac[5] = MGUID[2] & 255; \
} while (0)
// Crash report support. Health record lives in the .mg_health region, see link.ld
#define MG_ENABLE_HEALTH 1
// mdash.net device management service support
#define MG_ENABLE_MDASH 0
#define MG_MDASH_KEY "..." // Set this - mDash device token
#define MG_FIRMWARE_VERSION "c5a3.1.0.0"
@@ -66,7 +66,12 @@ static bool usb_poll(struct mg_tcpip_if *ifp, bool s1) {
} }
static void fn(struct mg_connection *c, int ev, void *ev_data) { static void fn(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) { if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/api/debug"), NULL)) { if (mg_match(hm->uri, mg_str("/api/debug"), NULL)) {
int level = mg_json_get_long(hm->body, "$.level", MG_LL_DEBUG); int level = mg_json_get_long(hm->body, "$.level", MG_LL_DEBUG);
@@ -68,6 +68,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
.key = mg_str(TLS_KEY)}; .key = mg_str(TLS_KEY)};
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} else if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
@@ -28,7 +28,12 @@ bool mg_random(void *buf, size_t len) { // Use on-board RNG
static void fn(struct mg_connection *c, int ev, void *ev_data) { static void fn(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) { if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
(void) hm; (void) hm;
mg_http_reply(c, 200, "", "hi\n"); mg_http_reply(c, 200, "", "hi\n");
@@ -66,7 +66,12 @@ static bool usb_poll(struct mg_tcpip_if *ifp, bool s1) {
} }
static void fn(struct mg_connection *c, int ev, void *ev_data) { static void fn(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) { if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/api/debug"), NULL)) { if (mg_match(hm->uri, mg_str("/api/debug"), NULL)) {
int level = mg_json_get_long(hm->body, "$.level", MG_LL_DEBUG); int level = mg_json_get_long(hm->body, "$.level", MG_LL_DEBUG);
@@ -68,6 +68,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
.key = mg_str(TLS_KEY)}; .key = mg_str(TLS_KEY)};
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} else if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
@@ -68,6 +68,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
.key = mg_str(TLS_KEY)}; .key = mg_str(TLS_KEY)};
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} else if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received } else if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
@@ -47,7 +47,12 @@ static void timer_fn(void *arg) {
static void fn(struct mg_connection *c, int ev, void *ev_data) { static void fn(struct mg_connection *c, int ev, void *ev_data) {
struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->fn_data; struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->fn_data;
if (ev == MG_EV_HTTP_MSG) { if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/api/hello"), if (mg_match(hm->uri, mg_str("/api/hello"),
NULL)) { // Request to /api/hello NULL)) { // Request to /api/hello
@@ -68,6 +68,11 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT), struct mg_tls_opts opts = {.cert = mg_str(TLS_CERT),
.key = mg_str(TLS_KEY)}; .key = mg_str(TLS_KEY)};
mg_tls_init(c, &opts); mg_tls_init(c, &opts);
} else if (ev == MG_EV_HTTP_HDRS) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/ota"), NULL)) {
mg_http_stream_body(c, hm, mg_http_ota_cb, NULL);
}
} else if (ev == MG_EV_HTTP_MSG) { } else if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data; struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) { if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
@@ -1,28 +0,0 @@
[PreviousGenFiles]
AdvancedFolderStructure=true
HeaderFileListSize=4
HeaderFiles#0=..\Core\Inc\FreeRTOSConfig.h
HeaderFiles#1=..\Core\Inc\stm32h7xx_it.h
HeaderFiles#2=..\Core\Inc\stm32h7xx_hal_conf.h
HeaderFiles#3=..\Core\Inc\main.h
HeaderFolderListSize=1
HeaderPath#0=..\Core\Inc
HeaderFiles=;
SourceFileListSize=5
SourceFiles#0=..\Core\Src\freertos.c
SourceFiles#1=..\Core\Src\stm32h7xx_it.c
SourceFiles#2=..\Core\Src\stm32h7xx_hal_msp.c
SourceFiles#3=..\Core\Src\stm32h7xx_hal_timebase_tim.c
SourceFiles#4=..\Core\Src\main.c
SourceFolderListSize=1
SourcePath#0=..\Core\Src
SourceFiles=;
[PreviousLibFiles]
LibFiles=Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_tim.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_tim_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_cortex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_cortex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_eth.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_eth_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_rcc.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_rcc_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_bus.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_rcc.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_crs.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_system.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_utils.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_flash.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_flash_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_gpio.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_gpio_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_gpio.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_hsem.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_hsem.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_dma.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_dma_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_dma.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_dmamux.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_mdma.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_pwr.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_pwr_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_pwr.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_def.h;Drivers\STM32H7xx_HAL_Driver\Inc\Legacy\stm32_hal_legacy.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_i2c.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_i2c_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_exti.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_exti.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_rng.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_rng_ex.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_rng.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_uart.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_usart.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_ll_lpuart.h;Drivers\STM32H7xx_HAL_Driver\Inc\stm32h7xx_hal_uart_ex.h;Middlewares\Third_Party\FreeRTOS\Source\include\croutine.h;Middlewares\Third_Party\FreeRTOS\Source\include\deprecated_definitions.h;Middlewares\Third_Party\FreeRTOS\Source\include\event_groups.h;Middlewares\Third_Party\FreeRTOS\Source\include\FreeRTOS.h;Middlewares\Third_Party\FreeRTOS\Source\include\list.h;Middlewares\Third_Party\FreeRTOS\Source\include\message_buffer.h;Middlewares\Third_Party\FreeRTOS\Source\include\mpu_prototypes.h;Middlewares\Third_Party\FreeRTOS\Source\include\mpu_wrappers.h;Middlewares\Third_Party\FreeRTOS\Source\include\mpu_syscall_numbers.h;Middlewares\Third_Party\FreeRTOS\Source\include\portable.h;Middlewares\Third_Party\FreeRTOS\Source\include\projdefs.h;Middlewares\Third_Party\FreeRTOS\Source\include\queue.h;Middlewares\Third_Party\FreeRTOS\Source\include\semphr.h;Middlewares\Third_Party\FreeRTOS\Source\include\stack_macros.h;Middlewares\Third_Party\FreeRTOS\Source\include\StackMacros.h;Middlewares\Third_Party\FreeRTOS\Source\include\stream_buffer.h;Middlewares\Third_Party\FreeRTOS\Source\include\task.h;Middlewares\Third_Party\FreeRTOS\Source\include\timers.h;Middlewares\Third_Party\FreeRTOS\Source\include\newlib-freertos.h;Middlewares\Third_Party\FreeRTOS\Source\include\picolibc-freertos.h;Middlewares\Third_Party\FreeRTOS\Source\include\atomic.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\freertos_mpool.h;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\freertos_os2.h;Middlewares\Third_Party\FreeRTOS\Source\portable\GCC\ARM_CM4F\portmacro.h;Drivers\CMSIS\RTOS2\Include\cmsis_os2.h;Drivers\CMSIS\RTOS2\Include\os_tick.h;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_tim.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_tim_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_cortex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_eth.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_eth_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rcc.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rcc_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_flash.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_flash_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_gpio.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_hsem.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_dma.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_dma_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_mdma.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pwr.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pwr_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_i2c.c;Drivers\STM32H7xx_Line truncated
[PreviousUsedCMakes]
SourceFiles=Core\Src\main.c;Core\Src\freertos.c;Core\Src\stm32h7xx_it.c;Core\Src\stm32h7xx_hal_msp.c;Core\Src\stm32h7xx_hal_timebase_tim.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_tim.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_tim_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_cortex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_eth.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_eth_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rcc.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rcc_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_flash.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_flash_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_gpio.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_hsem.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_dma.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_dma_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_mdma.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pwr.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pwr_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_i2c.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_i2c_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_exti.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rng.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rng_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_uart.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_uart_ex.c;Middlewares\Third_Party\FreeRTOS\Source\portable\Common\mpu_wrappers_v2.c;Middlewares\Third_Party\FreeRTOS\Source\croutine.c;Middlewares\Third_Party\FreeRTOS\Source\event_groups.c;Middlewares\Third_Party\FreeRTOS\Source\list.c;Middlewares\Third_Party\FreeRTOS\Source\queue.c;Middlewares\Third_Party\FreeRTOS\Source\stream_buffer.c;Middlewares\Third_Party\FreeRTOS\Source\tasks.c;Middlewares\Third_Party\FreeRTOS\Source\timers.c;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.c;Middlewares\Third_Party\FreeRTOS\Source\portable\MemMang\heap_4.c;Middlewares\Third_Party\FreeRTOS\Source\portable\GCC\ARM_CM4F\port.c;Drivers\CMSIS\Device\ST\STM32H7xx\Source\Templates\system_stm32h7xx.c;Core\Src\system_stm32h7xx.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_tim.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_tim_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_cortex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_eth.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_eth_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rcc.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rcc_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_flash.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_flash_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_gpio.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_hsem.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_dma.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_dma_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_mdma.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pwr.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_pwr_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_i2c.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_i2c_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_exti.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rng.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_rng_ex.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_uart.c;Drivers\STM32H7xx_HAL_Driver\Src\stm32h7xx_hal_uart_ex.c;Middlewares\Third_Party\FreeRTOS\Source\portable\Common\mpu_wrappers_v2.c;Middlewares\Third_Party\FreeRTOS\Source\croutine.c;Middlewares\Third_Party\FreeRTOS\Source\event_groups.c;Middlewares\Third_Party\FreeRTOS\Source\list.c;Middlewares\Third_Party\FreeRTOS\Source\queue.c;Middlewares\Third_Party\FreeRTOS\Source\stream_buffer.c;Middlewares\Third_Party\FreeRTOS\Source\tasks.c;Middlewares\Third_Party\FreeRTOS\Source\timers.c;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.c;Middlewares\Third_Party\FreeRTOS\Source\portable\MemMang\heap_4.c;Middlewares\Third_Party\FreeRTOS\Source\portable\GCC\ARM_CM4F\port.c;Drivers\CMSIS\Device\ST\STM32H7xx\Source\Templates\system_stm32h7xx.c;Core\Src\system_stm32h7xx.c;;;Middlewares\Third_Party\FreeRTOS\Source\portable\Common\mpu_wrappers_v2.c;Middlewares\Third_Party\FreeRTOS\Source\croutine.c;Middlewares\Third_Party\FreeRTOS\Source\event_groups.c;Middlewares\Third_Party\FreeRTOS\Source\list.c;Middlewares\Third_Party\FreeRTOS\Source\queue.c;Middlewares\Third_Party\FreeRTOS\Source\stream_buffer.c;Middlewares\Third_Party\FreeRTOS\Source\tasks.c;Middlewares\Third_Party\FreeRTOS\Source\timers.c;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2\cmsis_os2.c;Middlewares\Third_Party\FreeRTOS\Source\portable\MemMang\heap_4.c;Middlewares\Third_Party\FreeRTOS\Source\portable\GCC\ARM_CM4F\port.c;
HeaderPath=Drivers\STM32H7xx_HAL_Driver\Inc;Drivers\STM32H7xx_HAL_Driver\Inc\Legacy;Middlewares\Third_Party\FreeRTOS\Source\include;Middlewares\Third_Party\FreeRTOS\Source\CMSIS_RTOS_V2;Middlewares\Third_Party\FreeRTOS\Source\portable\GCC\ARM_CM4F;Drivers\CMSIS\RTOS2\Include;Drivers\CMSIS\Device\ST\STM32H7xx\Include;Drivers\CMSIS\Include;Core\Inc;
CDefines=USE_PWR_LDO_SUPPLY;USE_HAL_DRIVER;STM32H723xx;USE_HAL_DRIVER;USE_HAL_DRIVER;
@@ -1,78 +0,0 @@
cmake_minimum_required(VERSION 3.22)
#
# This file is generated only once,
# and is not re-generated if converter is called multiple times.
#
# User is free to modify the file as much as necessary
#
# Setup compiler settings
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS ON)
# Define the build type
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug")
endif()
# Set the project name
set(CMAKE_PROJECT_NAME nucleo-h723zg)
# Enable compile command to ease indexing with e.g. clangd
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
# Core project settings
project(${CMAKE_PROJECT_NAME})
message("Build type: " ${CMAKE_BUILD_TYPE})
# Enable CMake support for ASM and C languages
enable_language(C ASM)
# Create an executable object type
add_executable(${CMAKE_PROJECT_NAME})
# Add STM32CubeMX generated sources
add_subdirectory(cmake/stm32cubemx)
# Link directories setup
target_link_directories(${CMAKE_PROJECT_NAME} PRIVATE
# Add user defined library search paths
)
# Add sources to executable
target_sources(${CMAKE_PROJECT_NAME} PRIVATE
# Add user sources here
#${CMAKE_SOURCE_DIR}/../../../../mongoose.c
${CMAKE_SOURCE_DIR}/mongoose/mongoose.c
)
# Add include paths
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE
# Add user defined include paths
${CMAKE_SOURCE_DIR}/mongoose/
#${CMAKE_SOURCE_DIR}/../../../../
)
# Add project symbols (macros)
target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE
# Add user defined symbols
)
# Remove wrong libob.a library dependency when using cpp files
list(REMOVE_ITEM CMAKE_C_IMPLICIT_LINK_LIBRARIES ob)
# Add linked libraries
target_link_libraries(${CMAKE_PROJECT_NAME}
stm32cubemx
# Add user defined libraries
)
# Generate .bin from .elf
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
COMMAND arm-none-eabi-objcopy -O binary $<TARGET_FILE:${CMAKE_PROJECT_NAME}> ${CMAKE_PROJECT_NAME}.bin
VERBATIM
)
@@ -1,38 +0,0 @@
{
"version": 3,
"configurePresets": [
{
"name": "default",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/${presetName}",
"toolchainFile": "${sourceDir}/cmake/gcc-arm-none-eabi.cmake",
"cacheVariables": {
}
},
{
"name": "Debug",
"inherits": "default",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "Release",
"inherits": "default",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
}
],
"buildPresets": [
{
"name": "Debug",
"configurePreset": "Debug"
},
{
"name": "Release",
"configurePreset": "Release"
}
]
}
@@ -1,171 +0,0 @@
/* USER CODE BEGIN Header */
/*
* FreeRTOS Kernel V10.6.2
* Portion Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Portion Copyright (C) 2019 StMicroelectronics, Inc. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE .
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/* USER CODE END Header */
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* These parameters and more are described within the 'configuration' section of the
* FreeRTOS API documentation available on the FreeRTOS.org web site.
*
* See http://www.freertos.org/a00110.html
*----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* Section where include file can be added */
/* USER CODE END Includes */
/* Ensure definitions are only used by the compiler, and not by the assembler. */
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
#include <stdint.h>
extern uint32_t SystemCoreClock;
#endif
#ifndef CMSIS_device_header
#define CMSIS_device_header "stm32h7xx.h"
#endif /* CMSIS_device_header */
#define configENABLE_FPU 0
#define configENABLE_MPU 0
#define configUSE_PREEMPTION 1
#define configSUPPORT_STATIC_ALLOCATION 1
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCPU_CLOCK_HZ ( SystemCoreClock )
#define configTICK_RATE_HZ ((TickType_t)1000)
#define configMAX_PRIORITIES ( 56 )
#define configUSE_SB_COMPLETED_CALLBACK ( 0 )
#define configUSE_MINI_LIST_ITEM ( 1 )
#define configMINIMAL_STACK_SIZE ((uint16_t)128)
#define configTOTAL_HEAP_SIZE ((size_t)65536)
#define configMAX_TASK_NAME_LEN ( 16 )
#define configHEAP_CLEAR_MEMORY_ON_FREE 0
#define configUSE_TRACE_FACILITY 1
#define configUSE_16_BIT_TICKS 0
#define configUSE_MUTEXES 1
#define configQUEUE_REGISTRY_SIZE 8
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_COUNTING_SEMAPHORES 1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
/* USER CODE BEGIN MESSAGE_BUFFER_LENGTH_TYPE */
/* Defaults to size_t for backward compatibility, but can be changed
if lengths will always be less than the number of bytes in a size_t. */
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t
/* USER CODE END MESSAGE_BUFFER_LENGTH_TYPE */
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
/* Software timer definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( 2 )
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH 256
/* CMSIS-RTOS V2 flags */
#define configUSE_OS2_THREAD_SUSPEND_RESUME 1
#define configUSE_OS2_THREAD_ENUMERATE 1
#define configUSE_OS2_EVENTFLAGS_FROM_ISR 1
#define configUSE_OS2_THREAD_FLAGS 1
#define configUSE_OS2_TIMER 1
#define configUSE_OS2_MUTEX 1
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskCleanUpResources 0
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_xTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_xQueueGetMutexHolder 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_eTaskGetState 1
/*
* The CMSIS-RTOS V2 FreeRTOS wrapper is dependent on the heap implementation used
* by the application thus the correct define need to be enabled below
*/
#define USE_FreeRTOS_HEAP_4
/* Cortex-M specific definitions. */
#ifdef __NVIC_PRIO_BITS
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
#define configPRIO_BITS __NVIC_PRIO_BITS
#else
#define configPRIO_BITS 4
#endif
/* The lowest interrupt priority that can be used in a call to a "set priority"
function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
/* Interrupt priorities used by the kernel port layer itself. These are generic
to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* Normal assert() semantics without relying on the provision of an assert.h
header file. */
/* USER CODE BEGIN 1 */
#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );}
/* USER CODE END 1 */
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
standard names. */
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
/* IMPORTANT: After 10.3.1 update, Systick_Handler comes from NVIC (if SYS timebase = systick), otherwise from cmsis_os2.c */
#define USE_CUSTOM_SYSTICK_HANDLER_IMPLEMENTATION 0
/* USER CODE BEGIN Defines */
/* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */
/* USER CODE END Defines */
#endif /* FREERTOS_CONFIG_H */
@@ -1,69 +0,0 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.h
* @brief : Header for main.c file.
* This file contains the common defines of the application.
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32h7xx_hal.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
/* USER CODE END ET */
/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
/* USER CODE END EC */
/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */
/* USER CODE END EM */
/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */
/* Private defines -----------------------------------------------------------*/
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */
@@ -1,514 +0,0 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file stm32h7xx_hal_conf.h
* @author MCD Application Team
* @brief HAL configuration file.
******************************************************************************
* @attention
*
* Copyright (c) 2017 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef STM32H7xx_HAL_CONF_H
#define STM32H7xx_HAL_CONF_H
#ifdef __cplusplus
extern "C" {
#endif
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* ########################## Module Selection ############################## */
/**
* @brief This is the list of modules to be used in the HAL driver
*/
#define HAL_MODULE_ENABLED
/* #define HAL_ADC_MODULE_ENABLED */
/* #define HAL_FDCAN_MODULE_ENABLED */
/* #define HAL_FMAC_MODULE_ENABLED */
/* #define HAL_CEC_MODULE_ENABLED */
/* #define HAL_COMP_MODULE_ENABLED */
/* #define HAL_CORDIC_MODULE_ENABLED */
/* #define HAL_CRC_MODULE_ENABLED */
/* #define HAL_CRYP_MODULE_ENABLED */
/* #define HAL_DAC_MODULE_ENABLED */
/* #define HAL_DCMI_MODULE_ENABLED */
/* #define HAL_DMA2D_MODULE_ENABLED */
#define HAL_ETH_MODULE_ENABLED
/* #define HAL_ETH_LEGACY_MODULE_ENABLED */
/* #define HAL_NAND_MODULE_ENABLED */
/* #define HAL_NOR_MODULE_ENABLED */
/* #define HAL_OTFDEC_MODULE_ENABLED */
/* #define HAL_SRAM_MODULE_ENABLED */
/* #define HAL_SDRAM_MODULE_ENABLED */
/* #define HAL_HASH_MODULE_ENABLED */
/* #define HAL_HRTIM_MODULE_ENABLED */
/* #define HAL_HSEM_MODULE_ENABLED */
/* #define HAL_GFXMMU_MODULE_ENABLED */
/* #define HAL_JPEG_MODULE_ENABLED */
/* #define HAL_OPAMP_MODULE_ENABLED */
/* #define HAL_OSPI_MODULE_ENABLED */
/* #define HAL_I2S_MODULE_ENABLED */
/* #define HAL_SMBUS_MODULE_ENABLED */
/* #define HAL_IWDG_MODULE_ENABLED */
/* #define HAL_LPTIM_MODULE_ENABLED */
/* #define HAL_LTDC_MODULE_ENABLED */
/* #define HAL_QSPI_MODULE_ENABLED */
/* #define HAL_RAMECC_MODULE_ENABLED */
#define HAL_RNG_MODULE_ENABLED
/* #define HAL_RTC_MODULE_ENABLED */
/* #define HAL_SAI_MODULE_ENABLED */
/* #define HAL_SD_MODULE_ENABLED */
/* #define HAL_MMC_MODULE_ENABLED */
/* #define HAL_SPDIFRX_MODULE_ENABLED */
/* #define HAL_SPI_MODULE_ENABLED */
/* #define HAL_SWPMI_MODULE_ENABLED */
#define HAL_TIM_MODULE_ENABLED
#define HAL_UART_MODULE_ENABLED
/* #define HAL_USART_MODULE_ENABLED */
/* #define HAL_IRDA_MODULE_ENABLED */
/* #define HAL_SMARTCARD_MODULE_ENABLED */
/* #define HAL_WWDG_MODULE_ENABLED */
/* #define HAL_PCD_MODULE_ENABLED */
/* #define HAL_HCD_MODULE_ENABLED */
/* #define HAL_DFSDM_MODULE_ENABLED */
/* #define HAL_DSI_MODULE_ENABLED */
/* #define HAL_JPEG_MODULE_ENABLED */
/* #define HAL_MDIOS_MODULE_ENABLED */
/* #define HAL_PSSI_MODULE_ENABLED */
/* #define HAL_DTS_MODULE_ENABLED */
#define HAL_GPIO_MODULE_ENABLED
#define HAL_DMA_MODULE_ENABLED
#define HAL_MDMA_MODULE_ENABLED
#define HAL_RCC_MODULE_ENABLED
#define HAL_FLASH_MODULE_ENABLED
#define HAL_EXTI_MODULE_ENABLED
#define HAL_PWR_MODULE_ENABLED
#define HAL_I2C_MODULE_ENABLED
#define HAL_CORTEX_MODULE_ENABLED
#define HAL_HSEM_MODULE_ENABLED
/* ########################## Oscillator Values adaptation ####################*/
/**
* @brief Adjust the value of External High Speed oscillator (HSE) used in your application.
* This value is used by the RCC HAL module to compute the system frequency
* (when HSE is used as system clock source, directly or through the PLL).
*/
#if !defined (HSE_VALUE)
#define HSE_VALUE (25000000UL) /*!< Value of the External oscillator in Hz : FPGA case fixed to 60MHZ */
#endif /* HSE_VALUE */
#if !defined (HSE_STARTUP_TIMEOUT)
#define HSE_STARTUP_TIMEOUT (100UL) /*!< Time out for HSE start up, in ms */
#endif /* HSE_STARTUP_TIMEOUT */
/**
* @brief Internal oscillator (CSI) default value.
* This value is the default CSI value after Reset.
*/
#if !defined (CSI_VALUE)
#define CSI_VALUE (4000000UL) /*!< Value of the Internal oscillator in Hz*/
#endif /* CSI_VALUE */
/**
* @brief Internal High Speed oscillator (HSI) value.
* This value is used by the RCC HAL module to compute the system frequency
* (when HSI is used as system clock source, directly or through the PLL).
*/
#if !defined (HSI_VALUE)
#define HSI_VALUE (64000000UL) /*!< Value of the Internal oscillator in Hz*/
#endif /* HSI_VALUE */
/**
* @brief External Low Speed oscillator (LSE) value.
* This value is used by the UART, RTC HAL module to compute the system frequency
*/
#if !defined (LSE_VALUE)
#define LSE_VALUE (32768UL) /*!< Value of the External oscillator in Hz*/
#endif /* LSE_VALUE */
#if !defined (LSE_STARTUP_TIMEOUT)
#define LSE_STARTUP_TIMEOUT (5000UL) /*!< Time out for LSE start up, in ms */
#endif /* LSE_STARTUP_TIMEOUT */
#if !defined (LSI_VALUE)
#define LSI_VALUE (32000UL) /*!< LSI Typical Value in Hz*/
#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz
The real value may vary depending on the variations
in voltage and temperature.*/
/**
* @brief External clock source for I2S peripheral
* This value is used by the I2S HAL module to compute the I2S clock source
* frequency, this source is inserted directly through I2S_CKIN pad.
*/
#if !defined (EXTERNAL_CLOCK_VALUE)
#define EXTERNAL_CLOCK_VALUE 12288000UL /*!< Value of the External clock in Hz*/
#endif /* EXTERNAL_CLOCK_VALUE */
/* Tip: To avoid modifying this file each time you need to use different HSE,
=== you can define the HSE value in your toolchain compiler preprocessor. */
/* ########################### System Configuration ######################### */
/**
* @brief This is the HAL system configuration section
*/
#define VDD_VALUE (3300UL) /*!< Value of VDD in mv */
#define TICK_INT_PRIORITY (15UL) /*!< tick interrupt priority */
#define USE_RTOS 0
#define USE_SD_TRANSCEIVER 0U /*!< use uSD Transceiver */
#define USE_SPI_CRC 0U /*!< use CRC in SPI */
#define USE_HAL_ADC_REGISTER_CALLBACKS 0U /* ADC register callback disabled */
#define USE_HAL_CEC_REGISTER_CALLBACKS 0U /* CEC register callback disabled */
#define USE_HAL_COMP_REGISTER_CALLBACKS 0U /* COMP register callback disabled */
#define USE_HAL_CORDIC_REGISTER_CALLBACKS 0U /* CORDIC register callback disabled */
#define USE_HAL_CRYP_REGISTER_CALLBACKS 0U /* CRYP register callback disabled */
#define USE_HAL_DAC_REGISTER_CALLBACKS 0U /* DAC register callback disabled */
#define USE_HAL_DCMI_REGISTER_CALLBACKS 0U /* DCMI register callback disabled */
#define USE_HAL_DFSDM_REGISTER_CALLBACKS 0U /* DFSDM register callback disabled */
#define USE_HAL_DMA2D_REGISTER_CALLBACKS 0U /* DMA2D register callback disabled */
#define USE_HAL_DSI_REGISTER_CALLBACKS 0U /* DSI register callback disabled */
#define USE_HAL_DTS_REGISTER_CALLBACKS 0U /* DTS register callback disabled */
#define USE_HAL_ETH_REGISTER_CALLBACKS 0U /* ETH register callback disabled */
#define USE_HAL_FDCAN_REGISTER_CALLBACKS 0U /* FDCAN register callback disabled */
#define USE_HAL_FMAC_REGISTER_CALLBACKS 0U /* FMAC register callback disabled */
#define USE_HAL_NAND_REGISTER_CALLBACKS 0U /* NAND register callback disabled */
#define USE_HAL_NOR_REGISTER_CALLBACKS 0U /* NOR register callback disabled */
#define USE_HAL_SDRAM_REGISTER_CALLBACKS 0U /* SDRAM register callback disabled */
#define USE_HAL_SRAM_REGISTER_CALLBACKS 0U /* SRAM register callback disabled */
#define USE_HAL_HASH_REGISTER_CALLBACKS 0U /* HASH register callback disabled */
#define USE_HAL_HCD_REGISTER_CALLBACKS 0U /* HCD register callback disabled */
#define USE_HAL_GFXMMU_REGISTER_CALLBACKS 0U /* GFXMMU register callback disabled */
#define USE_HAL_HRTIM_REGISTER_CALLBACKS 0U /* HRTIM register callback disabled */
#define USE_HAL_I2C_REGISTER_CALLBACKS 0U /* I2C register callback disabled */
#define USE_HAL_I2S_REGISTER_CALLBACKS 0U /* I2S register callback disabled */
#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U /* IRDA register callback disabled */
#define USE_HAL_JPEG_REGISTER_CALLBACKS 0U /* JPEG register callback disabled */
#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0U /* LPTIM register callback disabled */
#define USE_HAL_LTDC_REGISTER_CALLBACKS 0U /* LTDC register callback disabled */
#define USE_HAL_MDIOS_REGISTER_CALLBACKS 0U /* MDIO register callback disabled */
#define USE_HAL_MMC_REGISTER_CALLBACKS 0U /* MMC register callback disabled */
#define USE_HAL_OPAMP_REGISTER_CALLBACKS 0U /* MDIO register callback disabled */
#define USE_HAL_OSPI_REGISTER_CALLBACKS 0U /* OSPI register callback disabled */
#define USE_HAL_OTFDEC_REGISTER_CALLBACKS 0U /* OTFDEC register callback disabled */
#define USE_HAL_PCD_REGISTER_CALLBACKS 0U /* PCD register callback disabled */
#define USE_HAL_QSPI_REGISTER_CALLBACKS 0U /* QSPI register callback disabled */
#define USE_HAL_RNG_REGISTER_CALLBACKS 0U /* RNG register callback disabled */
#define USE_HAL_RTC_REGISTER_CALLBACKS 0U /* RTC register callback disabled */
#define USE_HAL_SAI_REGISTER_CALLBACKS 0U /* SAI register callback disabled */
#define USE_HAL_SD_REGISTER_CALLBACKS 0U /* SD register callback disabled */
#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U /* SMARTCARD register callback disabled */
#define USE_HAL_SPDIFRX_REGISTER_CALLBACKS 0U /* SPDIFRX register callback disabled */
#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0U /* SMBUS register callback disabled */
#define USE_HAL_SPI_REGISTER_CALLBACKS 0U /* SPI register callback disabled */
#define USE_HAL_SWPMI_REGISTER_CALLBACKS 0U /* SWPMI register callback disabled */
#define USE_HAL_TIM_REGISTER_CALLBACKS 0U /* TIM register callback disabled */
#define USE_HAL_UART_REGISTER_CALLBACKS 0U /* UART register callback disabled */
#define USE_HAL_USART_REGISTER_CALLBACKS 0U /* USART register callback disabled */
#define USE_HAL_WWDG_REGISTER_CALLBACKS 0U /* WWDG register callback disabled */
/* ########################### Ethernet Configuration ######################### */
#define ETH_TX_DESC_CNT 4U /* number of Ethernet Tx DMA descriptors */
#define ETH_RX_DESC_CNT 4U /* number of Ethernet Rx DMA descriptors */
#define ETH_MAC_ADDR0 (0x02UL)
#define ETH_MAC_ADDR1 (0x00UL)
#define ETH_MAC_ADDR2 (0x00UL)
#define ETH_MAC_ADDR3 (0x00UL)
#define ETH_MAC_ADDR4 (0x00UL)
#define ETH_MAC_ADDR5 (0x00UL)
/* ########################## Assert Selection ############################## */
/**
* @brief Uncomment the line below to expanse the "assert_param" macro in the
* HAL drivers code
*/
/* #define USE_FULL_ASSERT 1U */
/* Includes ------------------------------------------------------------------*/
/**
* @brief Include module's header file
*/
#ifdef HAL_RCC_MODULE_ENABLED
#include "stm32h7xx_hal_rcc.h"
#endif /* HAL_RCC_MODULE_ENABLED */
#ifdef HAL_GPIO_MODULE_ENABLED
#include "stm32h7xx_hal_gpio.h"
#endif /* HAL_GPIO_MODULE_ENABLED */
#ifdef HAL_DMA_MODULE_ENABLED
#include "stm32h7xx_hal_dma.h"
#endif /* HAL_DMA_MODULE_ENABLED */
#ifdef HAL_MDMA_MODULE_ENABLED
#include "stm32h7xx_hal_mdma.h"
#endif /* HAL_MDMA_MODULE_ENABLED */
#ifdef HAL_HASH_MODULE_ENABLED
#include "stm32h7xx_hal_hash.h"
#endif /* HAL_HASH_MODULE_ENABLED */
#ifdef HAL_DCMI_MODULE_ENABLED
#include "stm32h7xx_hal_dcmi.h"
#endif /* HAL_DCMI_MODULE_ENABLED */
#ifdef HAL_DMA2D_MODULE_ENABLED
#include "stm32h7xx_hal_dma2d.h"
#endif /* HAL_DMA2D_MODULE_ENABLED */
#ifdef HAL_DSI_MODULE_ENABLED
#include "stm32h7xx_hal_dsi.h"
#endif /* HAL_DSI_MODULE_ENABLED */
#ifdef HAL_DFSDM_MODULE_ENABLED
#include "stm32h7xx_hal_dfsdm.h"
#endif /* HAL_DFSDM_MODULE_ENABLED */
#ifdef HAL_DTS_MODULE_ENABLED
#include "stm32h7xx_hal_dts.h"
#endif /* HAL_DTS_MODULE_ENABLED */
#ifdef HAL_ETH_MODULE_ENABLED
#include "stm32h7xx_hal_eth.h"
#endif /* HAL_ETH_MODULE_ENABLED */
#ifdef HAL_ETH_LEGACY_MODULE_ENABLED
#include "stm32h7xx_hal_eth_legacy.h"
#endif /* HAL_ETH_LEGACY_MODULE_ENABLED */
#ifdef HAL_EXTI_MODULE_ENABLED
#include "stm32h7xx_hal_exti.h"
#endif /* HAL_EXTI_MODULE_ENABLED */
#ifdef HAL_CORTEX_MODULE_ENABLED
#include "stm32h7xx_hal_cortex.h"
#endif /* HAL_CORTEX_MODULE_ENABLED */
#ifdef HAL_ADC_MODULE_ENABLED
#include "stm32h7xx_hal_adc.h"
#endif /* HAL_ADC_MODULE_ENABLED */
#ifdef HAL_FDCAN_MODULE_ENABLED
#include "stm32h7xx_hal_fdcan.h"
#endif /* HAL_FDCAN_MODULE_ENABLED */
#ifdef HAL_CEC_MODULE_ENABLED
#include "stm32h7xx_hal_cec.h"
#endif /* HAL_CEC_MODULE_ENABLED */
#ifdef HAL_COMP_MODULE_ENABLED
#include "stm32h7xx_hal_comp.h"
#endif /* HAL_COMP_MODULE_ENABLED */
#ifdef HAL_CORDIC_MODULE_ENABLED
#include "stm32h7xx_hal_cordic.h"
#endif /* HAL_CORDIC_MODULE_ENABLED */
#ifdef HAL_CRC_MODULE_ENABLED
#include "stm32h7xx_hal_crc.h"
#endif /* HAL_CRC_MODULE_ENABLED */
#ifdef HAL_CRYP_MODULE_ENABLED
#include "stm32h7xx_hal_cryp.h"
#endif /* HAL_CRYP_MODULE_ENABLED */
#ifdef HAL_DAC_MODULE_ENABLED
#include "stm32h7xx_hal_dac.h"
#endif /* HAL_DAC_MODULE_ENABLED */
#ifdef HAL_FLASH_MODULE_ENABLED
#include "stm32h7xx_hal_flash.h"
#endif /* HAL_FLASH_MODULE_ENABLED */
#ifdef HAL_GFXMMU_MODULE_ENABLED
#include "stm32h7xx_hal_gfxmmu.h"
#endif /* HAL_GFXMMU_MODULE_ENABLED */
#ifdef HAL_FMAC_MODULE_ENABLED
#include "stm32h7xx_hal_fmac.h"
#endif /* HAL_FMAC_MODULE_ENABLED */
#ifdef HAL_HRTIM_MODULE_ENABLED
#include "stm32h7xx_hal_hrtim.h"
#endif /* HAL_HRTIM_MODULE_ENABLED */
#ifdef HAL_HSEM_MODULE_ENABLED
#include "stm32h7xx_hal_hsem.h"
#endif /* HAL_HSEM_MODULE_ENABLED */
#ifdef HAL_SRAM_MODULE_ENABLED
#include "stm32h7xx_hal_sram.h"
#endif /* HAL_SRAM_MODULE_ENABLED */
#ifdef HAL_NOR_MODULE_ENABLED
#include "stm32h7xx_hal_nor.h"
#endif /* HAL_NOR_MODULE_ENABLED */
#ifdef HAL_NAND_MODULE_ENABLED
#include "stm32h7xx_hal_nand.h"
#endif /* HAL_NAND_MODULE_ENABLED */
#ifdef HAL_I2C_MODULE_ENABLED
#include "stm32h7xx_hal_i2c.h"
#endif /* HAL_I2C_MODULE_ENABLED */
#ifdef HAL_I2S_MODULE_ENABLED
#include "stm32h7xx_hal_i2s.h"
#endif /* HAL_I2S_MODULE_ENABLED */
#ifdef HAL_IWDG_MODULE_ENABLED
#include "stm32h7xx_hal_iwdg.h"
#endif /* HAL_IWDG_MODULE_ENABLED */
#ifdef HAL_JPEG_MODULE_ENABLED
#include "stm32h7xx_hal_jpeg.h"
#endif /* HAL_JPEG_MODULE_ENABLED */
#ifdef HAL_MDIOS_MODULE_ENABLED
#include "stm32h7xx_hal_mdios.h"
#endif /* HAL_MDIOS_MODULE_ENABLED */
#ifdef HAL_MMC_MODULE_ENABLED
#include "stm32h7xx_hal_mmc.h"
#endif /* HAL_MMC_MODULE_ENABLED */
#ifdef HAL_LPTIM_MODULE_ENABLED
#include "stm32h7xx_hal_lptim.h"
#endif /* HAL_LPTIM_MODULE_ENABLED */
#ifdef HAL_LTDC_MODULE_ENABLED
#include "stm32h7xx_hal_ltdc.h"
#endif /* HAL_LTDC_MODULE_ENABLED */
#ifdef HAL_OPAMP_MODULE_ENABLED
#include "stm32h7xx_hal_opamp.h"
#endif /* HAL_OPAMP_MODULE_ENABLED */
#ifdef HAL_OSPI_MODULE_ENABLED
#include "stm32h7xx_hal_ospi.h"
#endif /* HAL_OSPI_MODULE_ENABLED */
#ifdef HAL_OTFDEC_MODULE_ENABLED
#include "stm32h7xx_hal_otfdec.h"
#endif /* HAL_OTFDEC_MODULE_ENABLED */
#ifdef HAL_PSSI_MODULE_ENABLED
#include "stm32h7xx_hal_pssi.h"
#endif /* HAL_PSSI_MODULE_ENABLED */
#ifdef HAL_PWR_MODULE_ENABLED
#include "stm32h7xx_hal_pwr.h"
#endif /* HAL_PWR_MODULE_ENABLED */
#ifdef HAL_QSPI_MODULE_ENABLED
#include "stm32h7xx_hal_qspi.h"
#endif /* HAL_QSPI_MODULE_ENABLED */
#ifdef HAL_RAMECC_MODULE_ENABLED
#include "stm32h7xx_hal_ramecc.h"
#endif /* HAL_RAMECC_MODULE_ENABLED */
#ifdef HAL_RNG_MODULE_ENABLED
#include "stm32h7xx_hal_rng.h"
#endif /* HAL_RNG_MODULE_ENABLED */
#ifdef HAL_RTC_MODULE_ENABLED
#include "stm32h7xx_hal_rtc.h"
#endif /* HAL_RTC_MODULE_ENABLED */
#ifdef HAL_SAI_MODULE_ENABLED
#include "stm32h7xx_hal_sai.h"
#endif /* HAL_SAI_MODULE_ENABLED */
#ifdef HAL_SD_MODULE_ENABLED
#include "stm32h7xx_hal_sd.h"
#endif /* HAL_SD_MODULE_ENABLED */
#ifdef HAL_SDRAM_MODULE_ENABLED
#include "stm32h7xx_hal_sdram.h"
#endif /* HAL_SDRAM_MODULE_ENABLED */
#ifdef HAL_SPI_MODULE_ENABLED
#include "stm32h7xx_hal_spi.h"
#endif /* HAL_SPI_MODULE_ENABLED */
#ifdef HAL_SPDIFRX_MODULE_ENABLED
#include "stm32h7xx_hal_spdifrx.h"
#endif /* HAL_SPDIFRX_MODULE_ENABLED */
#ifdef HAL_SWPMI_MODULE_ENABLED
#include "stm32h7xx_hal_swpmi.h"
#endif /* HAL_SWPMI_MODULE_ENABLED */
#ifdef HAL_TIM_MODULE_ENABLED
#include "stm32h7xx_hal_tim.h"
#endif /* HAL_TIM_MODULE_ENABLED */
#ifdef HAL_UART_MODULE_ENABLED
#include "stm32h7xx_hal_uart.h"
#endif /* HAL_UART_MODULE_ENABLED */
#ifdef HAL_USART_MODULE_ENABLED
#include "stm32h7xx_hal_usart.h"
#endif /* HAL_USART_MODULE_ENABLED */
#ifdef HAL_IRDA_MODULE_ENABLED
#include "stm32h7xx_hal_irda.h"
#endif /* HAL_IRDA_MODULE_ENABLED */
#ifdef HAL_SMARTCARD_MODULE_ENABLED
#include "stm32h7xx_hal_smartcard.h"
#endif /* HAL_SMARTCARD_MODULE_ENABLED */
#ifdef HAL_SMBUS_MODULE_ENABLED
#include "stm32h7xx_hal_smbus.h"
#endif /* HAL_SMBUS_MODULE_ENABLED */
#ifdef HAL_WWDG_MODULE_ENABLED
#include "stm32h7xx_hal_wwdg.h"
#endif /* HAL_WWDG_MODULE_ENABLED */
#ifdef HAL_PCD_MODULE_ENABLED
#include "stm32h7xx_hal_pcd.h"
#endif /* HAL_PCD_MODULE_ENABLED */
#ifdef HAL_HCD_MODULE_ENABLED
#include "stm32h7xx_hal_hcd.h"
#endif /* HAL_HCD_MODULE_ENABLED */
/* Exported macro ------------------------------------------------------------*/
#ifdef USE_FULL_ASSERT
/**
* @brief The assert_param macro is used for function's parameters check.
* @param expr: If expr is false, it calls assert_failed function
* which reports the name of the source file and the source
* line number of the call that failed.
* If expr is true, it returns no value.
* @retval None
*/
#define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */
void assert_failed(uint8_t *file, uint32_t line);
#else
#define assert_param(expr) ((void)0U)
#endif /* USE_FULL_ASSERT */
#ifdef __cplusplus
}
#endif
#endif /* STM32H7xx_HAL_CONF_H */
@@ -1,60 +0,0 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file stm32h7xx_it.h
* @brief This file contains the headers of the interrupt handlers.
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32H7xx_IT_H
#define __STM32H7xx_IT_H
#ifdef __cplusplus
extern "C" {
#endif
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
/* USER CODE END ET */
/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
/* USER CODE END EC */
/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */
/* USER CODE END EM */
/* Exported functions prototypes ---------------------------------------------*/
void NMI_Handler(void);
void DebugMon_Handler(void);
void TIM6_DAC_IRQHandler(void);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */
#ifdef __cplusplus
}
#endif
#endif /* __STM32H7xx_IT_H */
@@ -1,59 +0,0 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : freertos.c
* Description : Code for freertos applications
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
/* USER CODE END Variables */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */
/* USER CODE END FunctionPrototypes */
/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
/* USER CODE END Application */
@@ -1,541 +0,0 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "string.h"
#include "FreeRTOS.h"
#include "cmsis_os2.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "mongoose.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma location=0x30000000
ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT]; /* Ethernet Rx DMA Descriptors */
#pragma location=0x30000080
ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT]; /* Ethernet Tx DMA Descriptors */
#elif defined ( __CC_ARM ) /* MDK ARM Compiler */
__attribute__((at(0x30000000))) ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT]; /* Ethernet Rx DMA Descriptors */
__attribute__((at(0x30000080))) ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT]; /* Ethernet Tx DMA Descriptors */
#elif defined ( __GNUC__ ) /* GNU Compiler */
ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT] __attribute__((section(".RxDescripSection"))); /* Ethernet Rx DMA Descriptors */
ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT] __attribute__((section(".TxDescripSection"))); /* Ethernet Tx DMA Descriptors */
#endif
ETH_TxPacketConfig TxConfig;
ETH_HandleTypeDef heth;
RNG_HandleTypeDef hrng;
UART_HandleTypeDef huart3;
/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
.name = "defaultTask",
.stack_size = MG_HEALTH_STACK_TOTAL,
.priority = (osPriority_t) osPriorityNormal,
};
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MPU_Config(void);
static void MX_GPIO_Init(void);
static void MX_ETH_Init(void);
static void MX_RNG_Init(void);
static void MX_USART3_UART_Init(void);
void StartDefaultTask(void *argument);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
static void log_fn(char ch, void *param) {
HAL_UART_Transmit(param, (unsigned char *) &ch, 1, HAL_MAX_DELAY);
}
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
if (mg_match(hm->uri, mg_str("/api/tick"), NULL)) {
mg_http_reply(c, 200, "", "{%m:%lu}\n", MG_ESC("tick"), HAL_GetTick());
} else if (mg_match(hm->uri, mg_str("/api/kill"), NULL)) {
SCB->SHCSR &= ~SCB_SHCSR_USGFAULTENA_Msk;
__asm volatile("udf #0");
} else {
mg_http_reply(c, 200, "Content-Type: text/plain\r\n",
"Hi from Mongoose, tick %lu\n"
"stack %zu/%zu bytes, heap %zu/%zu bytes\n",
(unsigned long) HAL_GetTick(),
(size_t) MG_HEALTH_STACK_USED, (size_t) MG_HEALTH_STACK_TOTAL,
(size_t) MG_HEALTH_HEAP_USED, (size_t) MG_HEALTH_HEAP_TOTAL);
}
}
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
MG_HEALTH_INIT();
/* USER CODE END 1 */
/* MPU Configuration--------------------------------------------------------*/
MPU_Config();
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ETH_Init();
MX_RNG_Init();
MX_USART3_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Init scheduler */
osKernelInitialize();
/* USER CODE BEGIN RTOS_MUTEX */
/* add mutexes, ... */
/* USER CODE END RTOS_MUTEX */
/* USER CODE BEGIN RTOS_SEMAPHORES */
/* add semaphores, ... */
/* USER CODE END RTOS_SEMAPHORES */
/* USER CODE BEGIN RTOS_TIMERS */
/* start timers, add new ones, ... */
/* USER CODE END RTOS_TIMERS */
/* USER CODE BEGIN RTOS_QUEUES */
/* add queues, ... */
/* USER CODE END RTOS_QUEUES */
/* Create the thread(s) */
/* creation of defaultTask */
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
/* USER CODE END RTOS_THREADS */
/* USER CODE BEGIN RTOS_EVENTS */
/* add events, ... */
/* USER CODE END RTOS_EVENTS */
/* Start scheduler */
osKernelStart();
/* We should never get here as control is now taken by the scheduler */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Supply configuration update enable
*/
HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);
while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48|RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_DIV1;
RCC_OscInitStruct.HSICalibrationValue = 64;
RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = 4;
RCC_OscInitStruct.PLL.PLLN = 34;
RCC_OscInitStruct.PLL.PLLP = 1;
RCC_OscInitStruct.PLL.PLLQ = 2;
RCC_OscInitStruct.PLL.PLLR = 2;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLFRACN = 3072;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
|RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief ETH Initialization Function
* @param None
* @retval None
*/
static void MX_ETH_Init(void)
{
/* USER CODE BEGIN ETH_Init 0 */
/* USER CODE END ETH_Init 0 */
static uint8_t MACAddr[6];
/* USER CODE BEGIN ETH_Init 1 */
/* USER CODE END ETH_Init 1 */
heth.Instance = ETH;
MACAddr[0] = 0x00;
MACAddr[1] = 0x80;
MACAddr[2] = 0xE1;
MACAddr[3] = 0x00;
MACAddr[4] = 0x00;
MACAddr[5] = 0x00;
heth.Init.MACAddr = &MACAddr[0];
heth.Init.MediaInterface = HAL_ETH_RMII_MODE;
heth.Init.TxDesc = DMATxDscrTab;
heth.Init.RxDesc = DMARxDscrTab;
heth.Init.RxBuffLen = 1536;
/* USER CODE BEGIN MACADDRESS */
/* USER CODE END MACADDRESS */
if (HAL_ETH_Init(&heth) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ETH_Init 2 */
/* USER CODE END ETH_Init 2 */
}
/**
* @brief RNG Initialization Function
* @param None
* @retval None
*/
static void MX_RNG_Init(void)
{
/* USER CODE BEGIN RNG_Init 0 */
/* USER CODE END RNG_Init 0 */
/* USER CODE BEGIN RNG_Init 1 */
/* USER CODE END RNG_Init 1 */
hrng.Instance = RNG;
hrng.Init.ClockErrorDetection = RNG_CED_ENABLE;
if (HAL_RNG_Init(&hrng) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN RNG_Init 2 */
/* USER CODE END RNG_Init 2 */
}
/**
* @brief USART3 Initialization Function
* @param None
* @retval None
*/
static void MX_USART3_UART_Init(void)
{
/* USER CODE BEGIN USART3_Init 0 */
/* USER CODE END USART3_Init 0 */
/* USER CODE BEGIN USART3_Init 1 */
/* USER CODE END USART3_Init 1 */
huart3.Instance = USART3;
huart3.Init.BaudRate = 115200;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
huart3.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart3.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart3.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart3) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&huart3, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&huart3, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&huart3) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART3_Init 2 */
/* USER CODE END USART3_Init 2 */
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0|GPIO_PIN_14, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_1, GPIO_PIN_RESET);
/*Configure GPIO pins : PB0 PB14 */
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_14;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/*Configure GPIO pin : PE1 */
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/* USER CODE BEGIN Header_StartDefaultTask */
/**
* @brief Function implementing the defaultTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN 5 */
struct mg_mgr mgr;
(void) argument;
mg_log_set_fn(log_fn, &huart3);
mg_mgr_init(&mgr);
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
/* Infinite loop */
for(;;)
{
mg_mgr_poll(&mgr, 0);
osDelay(1);
}
/* USER CODE END 5 */
}
/* MPU Configuration */
void MPU_Config(void)
{
MPU_Region_InitTypeDef MPU_InitStruct = {0};
/* Disables the MPU */
HAL_MPU_Disable();
/** Initializes and configures the Region and the memory to be protected
*/
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.BaseAddress = 0x0;
MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;
MPU_InitStruct.SubRegionDisable = 0x87;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* Enables the MPU */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
/**
* @brief Period elapsed callback in non blocking mode
* @note This function is called when TIM6 interrupt took place, inside
* HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
* a global variable "uwTick" used as application time base.
* @param htim : TIM handle
* @retval None
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/* USER CODE BEGIN Callback 0 */
/* USER CODE END Callback 0 */
if (htim->Instance == TIM6)
{
HAL_IncTick();
}
/* USER CODE BEGIN Callback 1 */
/* USER CODE END Callback 1 */
}
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
@@ -1,329 +0,0 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file stm32h7xx_hal_msp.c
* @brief This file provides code for the MSP Initialization
* and de-Initialization codes.
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN TD */
/* USER CODE END TD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN Define */
/* USER CODE END Define */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN Macro */
/* USER CODE END Macro */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* External functions --------------------------------------------------------*/
/* USER CODE BEGIN ExternalFunctions */
/* USER CODE END ExternalFunctions */
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* Initializes the Global MSP.
*/
void HAL_MspInit(void)
{
/* USER CODE BEGIN MspInit 0 */
/* USER CODE END MspInit 0 */
__HAL_RCC_SYSCFG_CLK_ENABLE();
/* System interrupt init*/
/* PendSV_IRQn interrupt configuration */
HAL_NVIC_SetPriority(PendSV_IRQn, 15, 0);
/* USER CODE BEGIN MspInit 1 */
/* USER CODE END MspInit 1 */
}
/**
* @brief ETH MSP Initialization
* This function configures the hardware resources used in this example
* @param heth: ETH handle pointer
* @retval None
*/
void HAL_ETH_MspInit(ETH_HandleTypeDef* heth)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(heth->Instance==ETH)
{
/* USER CODE BEGIN ETH_MspInit 0 */
/* USER CODE END ETH_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_ETH1MAC_CLK_ENABLE();
__HAL_RCC_ETH1TX_CLK_ENABLE();
__HAL_RCC_ETH1RX_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
/**ETH GPIO Configuration
PC1 ------> ETH_MDC
PA1 ------> ETH_REF_CLK
PA2 ------> ETH_MDIO
PA7 ------> ETH_CRS_DV
PC4 ------> ETH_RXD0
PC5 ------> ETH_RXD1
PB13 ------> ETH_TXD1
PG11 ------> ETH_TX_EN
PG13 ------> ETH_TXD0
*/
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
/* USER CODE BEGIN ETH_MspInit 1 */
/* USER CODE END ETH_MspInit 1 */
}
}
/**
* @brief ETH MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param heth: ETH handle pointer
* @retval None
*/
void HAL_ETH_MspDeInit(ETH_HandleTypeDef* heth)
{
if(heth->Instance==ETH)
{
/* USER CODE BEGIN ETH_MspDeInit 0 */
/* USER CODE END ETH_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_ETH1MAC_CLK_DISABLE();
__HAL_RCC_ETH1TX_CLK_DISABLE();
__HAL_RCC_ETH1RX_CLK_DISABLE();
/**ETH GPIO Configuration
PC1 ------> ETH_MDC
PA1 ------> ETH_REF_CLK
PA2 ------> ETH_MDIO
PA7 ------> ETH_CRS_DV
PC4 ------> ETH_RXD0
PC5 ------> ETH_RXD1
PB13 ------> ETH_TXD1
PG11 ------> ETH_TX_EN
PG13 ------> ETH_TXD0
*/
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5);
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_7);
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_13);
HAL_GPIO_DeInit(GPIOG, GPIO_PIN_11|GPIO_PIN_13);
/* USER CODE BEGIN ETH_MspDeInit 1 */
/* USER CODE END ETH_MspDeInit 1 */
}
}
/**
* @brief RNG MSP Initialization
* This function configures the hardware resources used in this example
* @param hrng: RNG handle pointer
* @retval None
*/
void HAL_RNG_MspInit(RNG_HandleTypeDef* hrng)
{
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
if(hrng->Instance==RNG)
{
/* USER CODE BEGIN RNG_MspInit 0 */
/* USER CODE END RNG_MspInit 0 */
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RNG;
PeriphClkInitStruct.RngClockSelection = RCC_RNGCLKSOURCE_HSI48;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/* Peripheral clock enable */
__HAL_RCC_RNG_CLK_ENABLE();
/* USER CODE BEGIN RNG_MspInit 1 */
/* USER CODE END RNG_MspInit 1 */
}
}
/**
* @brief RNG MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param hrng: RNG handle pointer
* @retval None
*/
void HAL_RNG_MspDeInit(RNG_HandleTypeDef* hrng)
{
if(hrng->Instance==RNG)
{
/* USER CODE BEGIN RNG_MspDeInit 0 */
/* USER CODE END RNG_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_RNG_CLK_DISABLE();
/* USER CODE BEGIN RNG_MspDeInit 1 */
/* USER CODE END RNG_MspDeInit 1 */
}
}
/**
* @brief UART MSP Initialization
* This function configures the hardware resources used in this example
* @param huart: UART handle pointer
* @retval None
*/
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
if(huart->Instance==USART3)
{
/* USER CODE BEGIN USART3_MspInit 0 */
/* USER CODE END USART3_MspInit 0 */
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USART3;
PeriphClkInitStruct.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_D2PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/* Peripheral clock enable */
__HAL_RCC_USART3_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/**USART3 GPIO Configuration
PD8 ------> USART3_TX
PD9 ------> USART3_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/* USER CODE BEGIN USART3_MspInit 1 */
/* USER CODE END USART3_MspInit 1 */
}
}
/**
* @brief UART MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param huart: UART handle pointer
* @retval None
*/
void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
{
if(huart->Instance==USART3)
{
/* USER CODE BEGIN USART3_MspDeInit 0 */
/* USER CODE END USART3_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_USART3_CLK_DISABLE();
/**USART3 GPIO Configuration
PD8 ------> USART3_TX
PD9 ------> USART3_RX
*/
HAL_GPIO_DeInit(GPIOD, GPIO_PIN_8|GPIO_PIN_9);
/* USER CODE BEGIN USART3_MspDeInit 1 */
/* USER CODE END USART3_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
@@ -1,131 +0,0 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file stm32h7xx_hal_timebase_tim.c
* @brief HAL time base based on the hardware TIM.
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "stm32h7xx_hal.h"
#include "stm32h7xx_hal_tim.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim6;
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/**
* @brief This function configures the TIM6 as a time base source.
* The time source is configured to have 1ms time base with a dedicated
* Tick interrupt priority.
* @note This function is called automatically at the beginning of program after
* reset by HAL_Init() or at any time when clock is configured, by HAL_RCC_ClockConfig().
* @param TickPriority: Tick interrupt priority.
* @retval HAL status
*/
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
RCC_ClkInitTypeDef clkconfig;
uint32_t uwTimclock, uwAPB1Prescaler;
uint32_t uwPrescalerValue;
uint32_t pFLatency;
/*Configure the TIM6 IRQ priority */
if (TickPriority < (1UL << __NVIC_PRIO_BITS))
{
HAL_NVIC_SetPriority(TIM6_DAC_IRQn, TickPriority ,0);
/* Enable the TIM6 global Interrupt */
HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);
uwTickPrio = TickPriority;
}
else
{
return HAL_ERROR;
}
/* Enable TIM6 clock */
__HAL_RCC_TIM6_CLK_ENABLE();
/* Get clock configuration */
HAL_RCC_GetClockConfig(&clkconfig, &pFLatency);
/* Get APB1 prescaler */
uwAPB1Prescaler = clkconfig.APB1CLKDivider;
/* Compute TIM6 clock */
if (uwAPB1Prescaler == RCC_HCLK_DIV1)
{
uwTimclock = HAL_RCC_GetPCLK1Freq();
}
else
{
uwTimclock = 2UL * HAL_RCC_GetPCLK1Freq();
}
/* Compute the prescaler value to have TIM6 counter clock equal to 1MHz */
uwPrescalerValue = (uint32_t) ((uwTimclock / 1000000U) - 1U);
/* Initialize TIM6 */
htim6.Instance = TIM6;
/* Initialize TIMx peripheral as follow:
* Period = [(TIM6CLK/1000) - 1]. to have a (1/1000) s time base.
* Prescaler = (uwTimclock/1000000 - 1) to have a 1MHz counter clock.
* ClockDivision = 0
* Counter direction = Up
*/
htim6.Init.Period = (1000000U / 1000U) - 1U;
htim6.Init.Prescaler = uwPrescalerValue;
htim6.Init.ClockDivision = 0;
htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
if(HAL_TIM_Base_Init(&htim6) == HAL_OK)
{
/* Start the TIM time Base generation in interrupt mode */
return HAL_TIM_Base_Start_IT(&htim6);
}
/* Return function status */
return HAL_ERROR;
}
/**
* @brief Suspend Tick increment.
* @note Disable the tick increment by disabling TIM6 update interrupt.
* @param None
* @retval None
*/
void HAL_SuspendTick(void)
{
/* Disable TIM6 update Interrupt */
__HAL_TIM_DISABLE_IT(&htim6, TIM_IT_UPDATE);
}
/**
* @brief Resume Tick increment.
* @note Enable the tick increment by Enabling TIM6 update interrupt.
* @param None
* @retval None
*/
void HAL_ResumeTick(void)
{
/* Enable TIM6 Update interrupt */
__HAL_TIM_ENABLE_IT(&htim6, TIM_IT_UPDATE);
}
@@ -1,118 +0,0 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file stm32h7xx_it.c
* @brief Interrupt Service Routines.
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32h7xx_it.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN TD */
/* USER CODE END TD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/* External variables --------------------------------------------------------*/
extern TIM_HandleTypeDef htim6;
/* USER CODE BEGIN EV */
/* USER CODE END EV */
/******************************************************************************/
/* Cortex Processor Interruption and Exception Handlers */
/******************************************************************************/
/**
* @brief This function handles Non maskable interrupt.
*/
void NMI_Handler(void)
{
/* USER CODE BEGIN NonMaskableInt_IRQn 0 */
/* USER CODE END NonMaskableInt_IRQn 0 */
/* USER CODE BEGIN NonMaskableInt_IRQn 1 */
while (1)
{
}
/* USER CODE END NonMaskableInt_IRQn 1 */
}
/**
* @brief This function handles Debug monitor.
*/
void DebugMon_Handler(void)
{
/* USER CODE BEGIN DebugMonitor_IRQn 0 */
/* USER CODE END DebugMonitor_IRQn 0 */
/* USER CODE BEGIN DebugMonitor_IRQn 1 */
/* USER CODE END DebugMonitor_IRQn 1 */
}
/******************************************************************************/
/* STM32H7xx Peripheral Interrupt Handlers */
/* Add here the Interrupt Handlers for the used peripherals. */
/* For the available peripheral interrupt handler names, */
/* please refer to the startup file (startup_stm32h7xx.s). */
/******************************************************************************/
/**
* @brief This function handles TIM6 global interrupt, DAC1_CH1 and DAC1_CH2 underrun error interrupts.
*/
void TIM6_DAC_IRQHandler(void)
{
/* USER CODE BEGIN TIM6_DAC_IRQn 0 */
/* USER CODE END TIM6_DAC_IRQn 0 */
HAL_TIM_IRQHandler(&htim6);
/* USER CODE BEGIN TIM6_DAC_IRQn 1 */
/* USER CODE END TIM6_DAC_IRQn 1 */
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
@@ -1,244 +0,0 @@
/**
******************************************************************************
* @file syscalls.c
* @author Auto-generated by STM32CubeMX
* @brief Minimal System calls file
*
* For more information about which c-functions
* need which of these lowlevel functions
* please consult the Newlib or Picolibc libc-manual
******************************************************************************
* @attention
*
* Copyright (c) 2020-2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes */
#include <sys/stat.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>
/* Variables */
extern int __io_putchar(int ch) __attribute__((weak));
extern int __io_getchar(void) __attribute__((weak));
char *__env[1] = { 0 };
char **environ = __env;
/* Functions */
void initialise_monitor_handles()
{
}
int _getpid(void)
{
return 1;
}
int _kill(int pid, int sig)
{
(void)pid;
(void)sig;
errno = EINVAL;
return -1;
}
void _exit (int status)
{
_kill(status, -1);
while (1) {} /* Make sure we hang here */
}
__attribute__((weak)) int _read(int file, char *ptr, int len)
{
(void)file;
int DataIdx;
for (DataIdx = 0; DataIdx < len; DataIdx++)
{
*ptr++ = __io_getchar();
}
return len;
}
__attribute__((weak)) int _write(int file, char *ptr, int len)
{
(void)file;
int DataIdx;
for (DataIdx = 0; DataIdx < len; DataIdx++)
{
__io_putchar(*ptr++);
}
return len;
}
int _close(int file)
{
(void)file;
return -1;
}
int _fstat(int file, struct stat *st)
{
(void)file;
st->st_mode = S_IFCHR;
return 0;
}
int _isatty(int file)
{
(void)file;
return 1;
}
int _lseek(int file, int ptr, int dir)
{
(void)file;
(void)ptr;
(void)dir;
return 0;
}
int _open(char *path, int flags, ...)
{
(void)path;
(void)flags;
/* Pretend like we always fail */
return -1;
}
int _wait(int *status)
{
(void)status;
errno = ECHILD;
return -1;
}
int _unlink(char *name)
{
(void)name;
errno = ENOENT;
return -1;
}
clock_t _times(struct tms *buf)
{
(void)buf;
return -1;
}
int _stat(const char *file, struct stat *st)
{
(void)file;
st->st_mode = S_IFCHR;
return 0;
}
int _link(char *old, char *new)
{
(void)old;
(void)new;
errno = EMLINK;
return -1;
}
int _fork(void)
{
errno = EAGAIN;
return -1;
}
int _execve(char *name, char **argv, char **env)
{
(void)name;
(void)argv;
(void)env;
errno = ENOMEM;
return -1;
}
// --- Picolibc Specific Section ---
#if defined(__PICOLIBC__)
/**
* @brief Picolibc helper function to output a character to a FILE stream.
* This redirects the output to the low-level __io_putchar function.
* @param c Character to write.
* @param file FILE stream pointer (ignored).
* @retval int The character written.
*/
static int starm_putc(char c, FILE *file)
{
(void) file;
__io_putchar(c);
return c;
}
/**
* @brief Picolibc helper function to input a character from a FILE stream.
* This redirects the input from the low-level __io_getchar function.
* @param file FILE stream pointer (ignored).
* @retval int The character read, cast to an unsigned char then int.
*/
static int starm_getc(FILE *file)
{
unsigned char c;
(void) file;
c = __io_getchar();
return c;
}
// Define and initialize the standard I/O streams for Picolibc.
// FDEV_SETUP_STREAM connects the starm_putc and starm_getc helper functions to a FILE structure.
// _FDEV_SETUP_RW indicates the stream is for reading and writing.
static FILE __stdio = FDEV_SETUP_STREAM(starm_putc,
starm_getc,
NULL,
_FDEV_SETUP_RW);
// Assign the standard stream pointers (stdin, stdout, stderr) to the initialized stream.
// Picolibc uses these pointers for standard I/O operations (printf, scanf, etc.).
FILE *const stdin = &__stdio;
__strong_reference(stdin, stdout);
__strong_reference(stdin, stderr);
// Create strong aliases mapping standard C library function names (without underscore)
// to the implemented system call stubs (with underscore). Picolibc uses these
// standard names internally, so this linking is required.
__strong_reference(_read, read);
__strong_reference(_write, write);
__strong_reference(_times, times);
__strong_reference(_execve, execve);
__strong_reference(_fork, fork);
__strong_reference(_link, link);
__strong_reference(_unlink, unlink);
__strong_reference(_stat, stat);
__strong_reference(_wait, wait);
__strong_reference(_open, open);
__strong_reference(_close, close);
__strong_reference(_lseek, lseek);
__strong_reference(_isatty, isatty);
__strong_reference(_fstat, fstat);
__strong_reference(_exit, exit);
__strong_reference(_kill, kill);
__strong_reference(_getpid, getpid);
#endif //__PICOLIBC__
@@ -1,87 +0,0 @@
/**
******************************************************************************
* @file sysmem.c
* @author Generated by STM32CubeMX
* @brief System Memory calls file
*
* For more information about which C functions
* need which of these lowlevel functions
* please consult the Newlib or Picolibc libc manual
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes */
#include <errno.h>
#include <stdint.h>
#include <stddef.h>
/**
* Pointer to the current high watermark of the heap usage
*/
static uint8_t *__sbrk_heap_end = NULL;
/**
* @brief _sbrk() allocates memory to the newlib heap and is used by malloc
* and others from the C library
*
* @verbatim
* ############################################################################
* # .data # .bss # newlib heap # MSP stack #
* # # # # Reserved by _Min_Stack_Size #
* ############################################################################
* ^-- RAM start ^-- _end _estack, RAM end --^
* @endverbatim
*
* This implementation starts allocating at the '_end' linker symbol
* The '_Min_Stack_Size' linker symbol reserves a memory for the MSP stack
* The implementation considers '_estack' linker symbol to be RAM end
* NOTE: If the MSP stack, at any point during execution, grows larger than the
* reserved size, please increase the '_Min_Stack_Size'.
*
* @param incr Memory size
* @return Pointer to allocated memory
*/
void *_sbrk(ptrdiff_t incr)
{
extern uint8_t _end; /* Symbol defined in the linker script */
extern uint8_t _estack; /* Symbol defined in the linker script */
extern uint32_t _Min_Stack_Size; /* Symbol defined in the linker script */
const uint32_t stack_limit = (uint32_t)&_estack - (uint32_t)&_Min_Stack_Size;
const uint8_t *max_heap = (uint8_t *)stack_limit;
uint8_t *prev_heap_end;
/* Initialize heap end at first call */
if (NULL == __sbrk_heap_end)
{
__sbrk_heap_end = &_end;
}
/* Protect heap from growing into the reserved MSP stack */
if (__sbrk_heap_end + incr > max_heap)
{
errno = ENOMEM;
return (void *)-1;
}
prev_heap_end = __sbrk_heap_end;
__sbrk_heap_end += incr;
return (void *)prev_heap_end;
}
#if defined(__PICOLIBC__)
// Picolibc expects syscalls without the leading underscore.
// This creates a strong alias so that
// calls to `sbrk()` are resolved to our `_sbrk()` implementation.
__strong_reference(_sbrk, sbrk);
#endif
@@ -1,554 +0,0 @@
/**
******************************************************************************
* @file system_stm32h7xx.c
* @author MCD Application Team
* @brief CMSIS Cortex-Mx Device Peripheral Access Layer System Source File.
*
* This file provides two functions and one global variable to be called from
* user application:
* - ExitRun0Mode(): Specifies the Power Supply source. This function is
* called at startup just after reset and before the call
* of SystemInit(). This call is made inside
* the "startup_stm32h7xx.s" file.
*
* - SystemInit(): This function is called at startup just after reset and
* before branch to main program. This call is made inside
* the "startup_stm32h7xx.s" file.
*
* - SystemCoreClock variable: Contains the core clock, it can be used
* by the user application to setup the SysTick
* timer or configure other parameters.
*
* - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
* be called whenever the core clock is changed
* during program execution.
*
*
******************************************************************************
* @attention
*
* Copyright (c) 2017 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/** @addtogroup CMSIS
* @{
*/
/** @addtogroup stm32h7xx_system
* @{
*/
/** @addtogroup STM32H7xx_System_Private_Includes
* @{
*/
#include "stm32h7xx.h"
#include <math.h>
#if !defined (HSE_VALUE)
#define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */
#if !defined (CSI_VALUE)
#define CSI_VALUE ((uint32_t)4000000) /*!< Value of the Internal oscillator in Hz*/
#endif /* CSI_VALUE */
#if !defined (HSI_VALUE)
#define HSI_VALUE ((uint32_t)64000000) /*!< Value of the Internal oscillator in Hz*/
#endif /* HSI_VALUE */
/**
* @}
*/
/** @addtogroup STM32H7xx_System_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @addtogroup STM32H7xx_System_Private_Defines
* @{
*/
/************************* Miscellaneous Configuration ************************/
/*!< Uncomment the following line if you need to use initialized data in D2 domain SRAM (AHB SRAM) */
/* #define DATA_IN_D2_SRAM */
/* Note: Following vector table addresses must be defined in line with linker
configuration. */
/*!< Uncomment the following line if you need to relocate the vector table
anywhere in FLASH BANK1 or AXI SRAM, else the vector table is kept at the automatic
remap of boot address selected */
/* #define USER_VECT_TAB_ADDRESS */
#if defined(USER_VECT_TAB_ADDRESS)
#if defined(DUAL_CORE) && defined(CORE_CM4)
/*!< Uncomment the following line if you need to relocate your vector Table
in D2 AXI SRAM else user remap will be done in FLASH BANK2. */
/* #define VECT_TAB_SRAM */
#if defined(VECT_TAB_SRAM)
#define VECT_TAB_BASE_ADDRESS D2_AXISRAM_BASE /*!< Vector Table base address field.
This value must be a multiple of 0x400. */
#else
#define VECT_TAB_BASE_ADDRESS FLASH_BANK2_BASE /*!< Vector Table base address field.
This value must be a multiple of 0x400. */
#endif /* VECT_TAB_SRAM */
#else
/*!< Uncomment the following line if you need to relocate your vector Table
in D1 AXI SRAM else user remap will be done in FLASH BANK1. */
/* #define VECT_TAB_SRAM */
#if defined(VECT_TAB_SRAM)
#define VECT_TAB_BASE_ADDRESS D1_AXISRAM_BASE /*!< Vector Table base address field.
This value must be a multiple of 0x400. */
#else
#define VECT_TAB_BASE_ADDRESS FLASH_BANK1_BASE /*!< Vector Table base address field.
This value must be a multiple of 0x400. */
#endif /* VECT_TAB_SRAM */
#endif /* DUAL_CORE && CORE_CM4 */
#if !defined(VECT_TAB_OFFSET)
#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field.
This value must be a multiple of 0x400. */
#endif /* VECT_TAB_OFFSET */
#endif /* USER_VECT_TAB_ADDRESS */
/******************************************************************************/
/**
* @}
*/
/** @addtogroup STM32H7xx_System_Private_Macros
* @{
*/
/**
* @}
*/
/** @addtogroup STM32H7xx_System_Private_Variables
* @{
*/
/* This variable is updated in three ways:
1) by calling CMSIS function SystemCoreClockUpdate()
2) by calling HAL API function HAL_RCC_GetHCLKFreq()
3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
Note: If you use this function to configure the system clock; then there
is no need to call the 2 first functions listed above, since SystemCoreClock
variable is updated automatically.
*/
uint32_t SystemCoreClock = 64000000;
uint32_t SystemD2Clock = 64000000;
const uint8_t D1CorePrescTable[16] = {0, 0, 0, 0, 1, 2, 3, 4, 1, 2, 3, 4, 6, 7, 8, 9};
/**
* @}
*/
/** @addtogroup STM32H7xx_System_Private_FunctionPrototypes
* @{
*/
/**
* @}
*/
/** @addtogroup STM32H7xx_System_Private_Functions
* @{
*/
/**
* @brief Setup the microcontroller system
* Initialize the FPU setting and vector table location
* configuration.
* @param None
* @retval None
*/
void SystemInit (void)
{
#if defined (DATA_IN_D2_SRAM)
__IO uint32_t tmpreg;
#endif /* DATA_IN_D2_SRAM */
/* FPU settings ------------------------------------------------------------*/
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
SCB->CPACR |= ((3UL << (10*2))|(3UL << (11*2))); /* set CP10 and CP11 Full Access */
#endif
/* Reset the RCC clock configuration to the default reset state ------------*/
/* Increasing the CPU frequency */
if(FLASH_LATENCY_DEFAULT > (READ_BIT((FLASH->ACR), FLASH_ACR_LATENCY)))
{
/* Program the new number of wait states to the LATENCY bits in the FLASH_ACR register */
MODIFY_REG(FLASH->ACR, FLASH_ACR_LATENCY, (uint32_t)(FLASH_LATENCY_DEFAULT));
}
/* Set HSION bit */
RCC->CR |= RCC_CR_HSION;
/* Reset CFGR register */
RCC->CFGR = 0x00000000;
/* Reset HSEON, HSECSSON, CSION, HSI48ON, CSIKERON, PLL1ON, PLL2ON and PLL3ON bits */
RCC->CR &= 0xEAF6ED7FU;
/* Decreasing the number of wait states because of lower CPU frequency */
if(FLASH_LATENCY_DEFAULT < (READ_BIT((FLASH->ACR), FLASH_ACR_LATENCY)))
{
/* Program the new number of wait states to the LATENCY bits in the FLASH_ACR register */
MODIFY_REG(FLASH->ACR, FLASH_ACR_LATENCY, (uint32_t)(FLASH_LATENCY_DEFAULT));
}
#if defined(D3_SRAM_BASE)
/* Reset D1CFGR register */
RCC->D1CFGR = 0x00000000;
/* Reset D2CFGR register */
RCC->D2CFGR = 0x00000000;
/* Reset D3CFGR register */
RCC->D3CFGR = 0x00000000;
#else
/* Reset CDCFGR1 register */
RCC->CDCFGR1 = 0x00000000;
/* Reset CDCFGR2 register */
RCC->CDCFGR2 = 0x00000000;
/* Reset SRDCFGR register */
RCC->SRDCFGR = 0x00000000;
#endif
/* Reset PLLCKSELR register */
RCC->PLLCKSELR = 0x02020200;
/* Reset PLLCFGR register */
RCC->PLLCFGR = 0x01FF0000;
/* Reset PLL1DIVR register */
RCC->PLL1DIVR = 0x01010280;
/* Reset PLL1FRACR register */
RCC->PLL1FRACR = 0x00000000;
/* Reset PLL2DIVR register */
RCC->PLL2DIVR = 0x01010280;
/* Reset PLL2FRACR register */
RCC->PLL2FRACR = 0x00000000;
/* Reset PLL3DIVR register */
RCC->PLL3DIVR = 0x01010280;
/* Reset PLL3FRACR register */
RCC->PLL3FRACR = 0x00000000;
/* Reset HSEBYP bit */
RCC->CR &= 0xFFFBFFFFU;
/* Disable all interrupts */
RCC->CIER = 0x00000000;
#if (STM32H7_DEV_ID == 0x450UL)
/* dual core CM7 or single core line */
if((DBGMCU->IDCODE & 0xFFFF0000U) < 0x20000000U)
{
/* if stm32h7 revY*/
/* Change the switch matrix read issuing capability to 1 for the AXI SRAM target (Target 7) */
*((__IO uint32_t*)0x51008108) = 0x000000001U;
}
#endif /* STM32H7_DEV_ID */
#if defined(DATA_IN_D2_SRAM)
/* in case of initialized data in D2 SRAM (AHB SRAM), enable the D2 SRAM clock (AHB SRAM clock) */
#if defined(RCC_AHB2ENR_D2SRAM3EN)
RCC->AHB2ENR |= (RCC_AHB2ENR_D2SRAM1EN | RCC_AHB2ENR_D2SRAM2EN | RCC_AHB2ENR_D2SRAM3EN);
#elif defined(RCC_AHB2ENR_D2SRAM2EN)
RCC->AHB2ENR |= (RCC_AHB2ENR_D2SRAM1EN | RCC_AHB2ENR_D2SRAM2EN);
#else
RCC->AHB2ENR |= (RCC_AHB2ENR_AHBSRAM1EN | RCC_AHB2ENR_AHBSRAM2EN);
#endif /* RCC_AHB2ENR_D2SRAM3EN */
tmpreg = RCC->AHB2ENR;
(void) tmpreg;
#endif /* DATA_IN_D2_SRAM */
#if defined(DUAL_CORE) && defined(CORE_CM4)
/* Configure the Vector Table location add offset address for cortex-M4 ------------------*/
#if defined(USER_VECT_TAB_ADDRESS)
SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal D2 AXI-RAM or in Internal FLASH */
#endif /* USER_VECT_TAB_ADDRESS */
#else
if(READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN) == 0U)
{
/* Enable the FMC interface clock */
SET_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
/*
* Disable the FMC bank1 (enabled after reset).
* This, prevents CPU speculation access on this bank which blocks the use of FMC during
* 24us. During this time the others FMC master (such as LTDC) cannot use it!
*/
FMC_Bank1_R->BTCR[0] = 0x000030D2;
/* Disable the FMC interface clock */
CLEAR_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
}
/* Configure the Vector Table location -------------------------------------*/
#if defined(USER_VECT_TAB_ADDRESS)
SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal D1 AXI-RAM or in Internal FLASH */
#endif /* USER_VECT_TAB_ADDRESS */
#endif /*DUAL_CORE && CORE_CM4*/
}
/**
* @brief Update SystemCoreClock variable according to Clock Register Values.
* The SystemCoreClock variable contains the core clock , it can
* be used by the user application to setup the SysTick timer or configure
* other parameters.
*
* @note Each time the core clock changes, this function must be called
* to update SystemCoreClock variable value. Otherwise, any configuration
* based on this variable will be incorrect.
*
* @note - The system frequency computed by this function is not the real
* frequency in the chip. It is calculated based on the predefined
* constant and the selected clock source:
*
* - If SYSCLK source is CSI, SystemCoreClock will contain the CSI_VALUE(*)
* - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(**)
* - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(***)
* - If SYSCLK source is PLL, SystemCoreClock will contain the CSI_VALUE(*),
* HSI_VALUE(**) or HSE_VALUE(***) multiplied/divided by the PLL factors.
*
* (*) CSI_VALUE is a constant defined in stm32h7xx_hal.h file (default value
* 4 MHz) but the real value may vary depending on the variations
* in voltage and temperature.
* (**) HSI_VALUE is a constant defined in stm32h7xx_hal.h file (default value
* 64 MHz) but the real value may vary depending on the variations
* in voltage and temperature.
*
* (***)HSE_VALUE is a constant defined in stm32h7xx_hal.h file (default value
* 25 MHz), user has to ensure that HSE_VALUE is same as the real
* frequency of the crystal used. Otherwise, this function may
* have wrong result.
*
* - The result of this function could be not correct when using fractional
* value for HSE crystal.
* @param None
* @retval None
*/
void SystemCoreClockUpdate (void)
{
uint32_t pllp, pllsource, pllm, pllfracen, hsivalue, tmp;
uint32_t common_system_clock;
float_t fracn1, pllvco;
/* Get SYSCLK source -------------------------------------------------------*/
switch (RCC->CFGR & RCC_CFGR_SWS)
{
case RCC_CFGR_SWS_HSI: /* HSI used as system clock source */
common_system_clock = (uint32_t) (HSI_VALUE >> ((RCC->CR & RCC_CR_HSIDIV)>> 3));
break;
case RCC_CFGR_SWS_CSI: /* CSI used as system clock source */
common_system_clock = CSI_VALUE;
break;
case RCC_CFGR_SWS_HSE: /* HSE used as system clock source */
common_system_clock = HSE_VALUE;
break;
case RCC_CFGR_SWS_PLL1: /* PLL1 used as system clock source */
/* PLL_VCO = (HSE_VALUE or HSI_VALUE or CSI_VALUE/ PLLM) * PLLN
SYSCLK = PLL_VCO / PLLR
*/
pllsource = (RCC->PLLCKSELR & RCC_PLLCKSELR_PLLSRC);
pllm = ((RCC->PLLCKSELR & RCC_PLLCKSELR_DIVM1)>> 4) ;
pllfracen = ((RCC->PLLCFGR & RCC_PLLCFGR_PLL1FRACEN)>>RCC_PLLCFGR_PLL1FRACEN_Pos);
fracn1 = (float_t)(uint32_t)(pllfracen* ((RCC->PLL1FRACR & RCC_PLL1FRACR_FRACN1)>> 3));
if (pllm != 0U)
{
switch (pllsource)
{
case RCC_PLLCKSELR_PLLSRC_HSI: /* HSI used as PLL clock source */
hsivalue = (HSI_VALUE >> ((RCC->CR & RCC_CR_HSIDIV)>> 3)) ;
pllvco = ( (float_t)hsivalue / (float_t)pllm) * ((float_t)(uint32_t)(RCC->PLL1DIVR & RCC_PLL1DIVR_N1) + (fracn1/(float_t)0x2000) +(float_t)1 );
break;
case RCC_PLLCKSELR_PLLSRC_CSI: /* CSI used as PLL clock source */
pllvco = ((float_t)CSI_VALUE / (float_t)pllm) * ((float_t)(uint32_t)(RCC->PLL1DIVR & RCC_PLL1DIVR_N1) + (fracn1/(float_t)0x2000) +(float_t)1 );
break;
case RCC_PLLCKSELR_PLLSRC_HSE: /* HSE used as PLL clock source */
pllvco = ((float_t)HSE_VALUE / (float_t)pllm) * ((float_t)(uint32_t)(RCC->PLL1DIVR & RCC_PLL1DIVR_N1) + (fracn1/(float_t)0x2000) +(float_t)1 );
break;
default:
hsivalue = (HSI_VALUE >> ((RCC->CR & RCC_CR_HSIDIV)>> 3)) ;
pllvco = ((float_t)hsivalue / (float_t)pllm) * ((float_t)(uint32_t)(RCC->PLL1DIVR & RCC_PLL1DIVR_N1) + (fracn1/(float_t)0x2000) +(float_t)1 );
break;
}
pllp = (((RCC->PLL1DIVR & RCC_PLL1DIVR_P1) >>9) + 1U ) ;
common_system_clock = (uint32_t)(float_t)(pllvco/(float_t)pllp);
}
else
{
common_system_clock = 0U;
}
break;
default:
common_system_clock = (uint32_t) (HSI_VALUE >> ((RCC->CR & RCC_CR_HSIDIV)>> 3));
break;
}
/* Compute SystemClock frequency --------------------------------------------------*/
#if defined (RCC_D1CFGR_D1CPRE)
tmp = D1CorePrescTable[(RCC->D1CFGR & RCC_D1CFGR_D1CPRE)>> RCC_D1CFGR_D1CPRE_Pos];
/* common_system_clock frequency : CM7 CPU frequency */
common_system_clock >>= tmp;
/* SystemD2Clock frequency : CM4 CPU, AXI and AHBs Clock frequency */
SystemD2Clock = (common_system_clock >> ((D1CorePrescTable[(RCC->D1CFGR & RCC_D1CFGR_HPRE)>> RCC_D1CFGR_HPRE_Pos]) & 0x1FU));
#else
tmp = D1CorePrescTable[(RCC->CDCFGR1 & RCC_CDCFGR1_CDCPRE)>> RCC_CDCFGR1_CDCPRE_Pos];
/* common_system_clock frequency : CM7 CPU frequency */
common_system_clock >>= tmp;
/* SystemD2Clock frequency : AXI and AHBs Clock frequency */
SystemD2Clock = (common_system_clock >> ((D1CorePrescTable[(RCC->CDCFGR1 & RCC_CDCFGR1_HPRE)>> RCC_CDCFGR1_HPRE_Pos]) & 0x1FU));
#endif
#if defined(DUAL_CORE) && defined(CORE_CM4)
SystemCoreClock = SystemD2Clock;
#else
SystemCoreClock = common_system_clock;
#endif /* DUAL_CORE && CORE_CM4 */
}
/**
* @brief Exit Run* mode and Configure the system Power Supply
*
* @note This function exits the Run* mode and configures the system power supply
* according to the definition to be used at compilation preprocessing level.
* The application shall set one of the following configuration option:
* - PWR_LDO_SUPPLY
* - PWR_DIRECT_SMPS_SUPPLY
* - PWR_EXTERNAL_SOURCE_SUPPLY
* - PWR_SMPS_1V8_SUPPLIES_LDO
* - PWR_SMPS_2V5_SUPPLIES_LDO
* - PWR_SMPS_1V8_SUPPLIES_EXT_AND_LDO
* - PWR_SMPS_2V5_SUPPLIES_EXT_AND_LDO
* - PWR_SMPS_1V8_SUPPLIES_EXT
* - PWR_SMPS_2V5_SUPPLIES_EXT
*
* @note The function modifies the PWR->CR3 register to enable or disable specific
* power supply modes and waits until the voltage level flag is set, indicating
* that the power supply configuration is stable.
*
* @param None
* @retval None
*/
void ExitRun0Mode(void)
{
#if defined(USE_PWR_LDO_SUPPLY)
#if defined(SMPS)
/* Exit Run* mode by disabling SMPS and enabling LDO */
PWR->CR3 = (PWR->CR3 & ~PWR_CR3_SMPSEN) | PWR_CR3_LDOEN;
#else
/* Enable LDO mode */
PWR->CR3 |= PWR_CR3_LDOEN;
#endif /* SMPS */
/* Wait till voltage level flag is set */
while ((PWR->CSR1 & PWR_CSR1_ACTVOSRDY) == 0U)
{}
#elif defined(USE_PWR_EXTERNAL_SOURCE_SUPPLY)
#if defined(SMPS)
/* Exit Run* mode */
PWR->CR3 = (PWR->CR3 & ~(PWR_CR3_SMPSEN | PWR_CR3_LDOEN)) | PWR_CR3_BYPASS;
#else
PWR->CR3 = (PWR->CR3 & ~(PWR_CR3_LDOEN)) | PWR_CR3_BYPASS;
#endif /* SMPS */
/* Wait till voltage level flag is set */
while ((PWR->CSR1 & PWR_CSR1_ACTVOSRDY) == 0U)
{}
#elif defined(USE_PWR_DIRECT_SMPS_SUPPLY) && defined(SMPS)
/* Exit Run* mode */
PWR->CR3 &= ~(PWR_CR3_LDOEN);
/* Wait till voltage level flag is set */
while ((PWR->CSR1 & PWR_CSR1_ACTVOSRDY) == 0U)
{}
#elif defined(USE_PWR_SMPS_1V8_SUPPLIES_LDO) && defined(SMPS)
/* Exit Run* mode */
PWR->CR3 |= PWR_CR3_SMPSLEVEL_0 | PWR_CR3_SMPSEN | PWR_CR3_LDOEN;
/* Wait till voltage level flag is set */
while ((PWR->CSR1 & PWR_CSR1_ACTVOSRDY) == 0U)
{}
#elif defined(USE_PWR_SMPS_2V5_SUPPLIES_LDO) && defined(SMPS)
/* Exit Run* mode */
PWR->CR3 |= PWR_CR3_SMPSLEVEL_1 | PWR_CR3_SMPSEN | PWR_CR3_LDOEN;
/* Wait till voltage level flag is set */
while ((PWR->CSR1 & PWR_CSR1_ACTVOSRDY) == 0U)
{}
#elif defined(USE_PWR_SMPS_1V8_SUPPLIES_EXT_AND_LDO) && defined(SMPS)
/* Exit Run* mode */
PWR->CR3 |= PWR_CR3_SMPSLEVEL_0 | PWR_CR3_SMPSEXTHP | PWR_CR3_SMPSEN | PWR_CR3_LDOEN;
/* Wait till voltage level flag is set */
while ((PWR->CSR1 & PWR_CSR1_ACTVOSRDY) == 0U)
{}
#elif defined(USE_PWR_SMPS_2V5_SUPPLIES_EXT_AND_LDO) && defined(SMPS)
/* Exit Run* mode */
PWR->CR3 |= PWR_CR3_SMPSLEVEL_1 | PWR_CR3_SMPSEXTHP | PWR_CR3_SMPSEN | PWR_CR3_LDOEN;
/* Wait till voltage level flag is set */
while ((PWR->CSR1 & PWR_CSR1_ACTVOSRDY) == 0U)
{}
#elif defined(USE_PWR_SMPS_1V8_SUPPLIES_EXT) && defined(SMPS)
/* Exit Run* mode */
PWR->CR3 = (PWR->CR3 & ~(PWR_CR3_LDOEN)) | PWR_CR3_SMPSLEVEL_0 | PWR_CR3_SMPSEXTHP | PWR_CR3_SMPSEN | PWR_CR3_BYPASS;
/* Wait till voltage level flag is set */
while ((PWR->CSR1 & PWR_CSR1_ACTVOSRDY) == 0U)
{}
#elif defined(USE_PWR_SMPS_2V5_SUPPLIES_EXT) && defined(SMPS)
/* Exit Run* mode */
PWR->CR3 = (PWR->CR3 & ~(PWR_CR3_LDOEN)) | PWR_CR3_SMPSLEVEL_1 | PWR_CR3_SMPSEXTHP | PWR_CR3_SMPSEN | PWR_CR3_BYPASS;
/* Wait till voltage level flag is set */
while ((PWR->CSR1 & PWR_CSR1_ACTVOSRDY) == 0U)
{}
#else
/* No system power supply configuration is selected at exit Run* mode */
#endif /* USE_PWR_LDO_SUPPLY */
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
@@ -1,302 +0,0 @@
/**
******************************************************************************
* @file stm32h7xx.h
* @author MCD Application Team
* @brief CMSIS STM32H7xx Device Peripheral Access Layer Header File.
*
* The file is the unique include file that the application programmer
* is using in the C source code, usually in main.c. This file contains:
* - Configuration section that allows to select:
* - The STM32H7xx device used in the target application
* - To use or not the peripheral's drivers in application code(i.e.
* code will be based on direct access to peripheral's registers
* rather than drivers API), this option is controlled by
* "#define USE_HAL_DRIVER"
*
******************************************************************************
* @attention
*
* Copyright (c) 2017 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/** @addtogroup CMSIS
* @{
*/
/** @addtogroup stm32h7xx
* @{
*/
#ifndef STM32H7xx_H
#define STM32H7xx_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/** @addtogroup Library_configuration_section
* @{
*/
/**
* @brief STM32 Family
*/
#if !defined (STM32H7)
#define STM32H7
#endif /* STM32H7 */
/* Uncomment the line below according to the target STM32H7 device used in your
application
*/
#if !defined (STM32H743xx) && !defined (STM32H753xx) && !defined (STM32H750xx) && !defined (STM32H742xx) && \
!defined (STM32H745xx) && !defined (STM32H745xG) && !defined (STM32H755xx) && !defined (STM32H747xx) && !defined (STM32H747xG)&& !defined (STM32H757xx) && \
!defined (STM32H7A3xx) && !defined (STM32H7A3xxQ) && !defined (STM32H7B3xx) && !defined (STM32H7B3xxQ) && !defined (STM32H7B0xx) && !defined (STM32H7B0xxQ) && \
!defined (STM32H735xx) && !defined (STM32H733xx) && !defined (STM32H730xx) && !defined (STM32H730xxQ) && !defined (STM32H725xx) && !defined (STM32H723xx)
/* #define STM32H742xx */ /*!< STM32H742VI, STM32H742ZI, STM32H742AI, STM32H742II, STM32H742BI, STM32H742XI Devices */
/* #define STM32H743xx */ /*!< STM32H743VI, STM32H743ZI, STM32H743AI, STM32H743II, STM32H743BI, STM32H743XI Devices */
/* #define STM32H753xx */ /*!< STM32H753VI, STM32H753ZI, STM32H753AI, STM32H753II, STM32H753BI, STM32H753XI Devices */
/* #define STM32H750xx */ /*!< STM32H750V, STM32H750I, STM32H750X Devices */
/* #define STM32H747xx */ /*!< STM32H747ZI, STM32H747AI, STM32H747II, STM32H747BI, STM32H747XI Devices */
/* #define STM32H747xG */ /*!< STM32H747AG, STM32H747IG, STM32H747BG, STM32H747XG */
/* #define STM32H757xx */ /*!< STM32H757ZI, STM32H757AI, STM32H757II, STM32H757BI, STM32H757XI Devices */
/* #define STM32H745xx */ /*!< STM32H745ZI, STM32H745II, STM32H745BI, STM32H745XI Devices */
/* #define STM32H745xG */ /*!< STM32H745ZG, STM32H745IG, STM32H745BG, STM32H745XG Devices */
/* #define STM32H755xx */ /*!< STM32H755ZI, STM32H755II, STM32H755BI, STM32H755XI Devices */
/* #define STM32H7B0xx */ /*!< STM32H7B0IBTx, STM32H7B0RBTx, STM32H7B0VBTx, STM32H7B0ZBTx Devices */
/* #define STM32H7B0xxQ */ /*!< STM32H7B0ABIxQ, STM32H7B0IBKxQ Devices */
/* #define STM32H7A3xx */ /*!< STM32H7A3IIK6, STM32H7A3IIT6, STM32H7A3NIH6, STM32H7A3RIT6, STM32H7A3VIH6, STM32H7A3VIT6, STM32H7A3ZIT6 */
/* #define STM32H7A3xxQ */ /*!< STM32H7A3QIY6Q, STM32H7A3IIK6Q, STM32H7A3IIT6Q, STM32H7A3LIH6Q, STM32H7A3VIH6Q, STM32H7A3VIT6Q, STM32H7A3AII6Q, STM32H7A3ZIT6Q */
/* #define STM32H7B3xx */ /*!< STM32H7B3IIK6, STM32H7B3IIT6, STM32H7B3NIH6, STM32H7B3RIT6, STM32H7B3VIH6, STM32H7B3VIT6, STM32H7B3ZIT6 */
/* #define STM32H7B3xxQ */ /*!< STM32H7B3QIY6Q, STM32H7B3IIK6Q, STM32H7B3IIT6Q, STM32H7B3LIH6Q, STM32H7B3VIH6Q, STM32H7B3VIT6Q, STM32H7B3AII6Q, STM32H7B3ZIT6Q */
/* #define STM32H735xx */ /*!< STM32H735AGI6, STM32H735IGK6, STM32H735RGV6, STM32H735VGT6, STM32H735VGY6, STM32H735ZGT6 Devices */
/* #define STM32H733xx */ /*!< STM32H733VGH6, STM32H733VGT6, STM32H733ZGI6, STM32H733ZGT6, Devices */
/* #define STM32H730xx */ /*!< STM32H730VBH6, STM32H730VBT6, STM32H730ZBT6, STM32H730ZBI6 Devices */
/* #define STM32H730xxQ */ /*!< STM32H730IBT6Q, STM32H730ABI6Q, STM32H730IBK6Q Devices */
/* #define STM32H725xx */ /*!< STM32H725AGI6, STM32H725IGK6, STM32H725IGT6, STM32H725RGV6, STM32H725VGT6, STM32H725VGY6, STM32H725ZGT6, STM32H725REV6, SM32H725VET6, STM32H725ZET6, STM32H725AEI6, STM32H725IET6, STM32H725IEK6 Devices */
/* #define STM32H723xx */ /*!< STM32H723VGH6, STM32H723VGT6, STM32H723ZGI6, STM32H723ZGT6, STM32H723VET6, STM32H723VEH6, STM32H723ZET6, STM32H723ZEI6 Devices */
#endif
/* Tip: To avoid modifying this file each time you need to switch between these
devices, you can define the device in your toolchain compiler preprocessor.
*/
#if !defined (USE_HAL_DRIVER)
/**
* @brief Comment the line below if you will not use the peripherals drivers.
In this case, these drivers will not be included and the application code will
be based on direct access to peripherals registers
*/
/*#define USE_HAL_DRIVER */
#endif /* USE_HAL_DRIVER */
/**
* @brief CMSIS Device version number V1.10.7
*/
#define __STM32H7xx_CMSIS_DEVICE_VERSION_MAIN (0x01) /*!< [31:24] main version */
#define __STM32H7xx_CMSIS_DEVICE_VERSION_SUB1 (0x0A) /*!< [23:16] sub1 version */
#define __STM32H7xx_CMSIS_DEVICE_VERSION_SUB2 (0x07) /*!< [15:8] sub2 version */
#define __STM32H7xx_CMSIS_DEVICE_VERSION_RC (0x00) /*!< [7:0] release candidate */
#define __STM32H7xx_CMSIS_DEVICE_VERSION ((__STM32H7xx_CMSIS_DEVICE_VERSION_MAIN << 24)\
|(__STM32H7xx_CMSIS_DEVICE_VERSION_SUB1 << 16)\
|(__STM32H7xx_CMSIS_DEVICE_VERSION_SUB2 << 8 )\
|(__STM32H7xx_CMSIS_DEVICE_VERSION_RC))
/**
* @}
*/
/** @addtogroup Device_Included
* @{
*/
#if defined(STM32H743xx)
#include "stm32h743xx.h"
#elif defined(STM32H753xx)
#include "stm32h753xx.h"
#elif defined(STM32H750xx)
#include "stm32h750xx.h"
#elif defined(STM32H742xx)
#include "stm32h742xx.h"
#elif defined(STM32H745xx)
#include "stm32h745xx.h"
#elif defined(STM32H745xG)
#include "stm32h745xg.h"
#elif defined(STM32H755xx)
#include "stm32h755xx.h"
#elif defined(STM32H747xx)
#include "stm32h747xx.h"
#elif defined(STM32H747xG)
#include "stm32h747xg.h"
#elif defined(STM32H757xx)
#include "stm32h757xx.h"
#elif defined(STM32H7B0xx)
#include "stm32h7b0xx.h"
#elif defined(STM32H7B0xxQ)
#include "stm32h7b0xxq.h"
#elif defined(STM32H7A3xx)
#include "stm32h7a3xx.h"
#elif defined(STM32H7B3xx)
#include "stm32h7b3xx.h"
#elif defined(STM32H7A3xxQ)
#include "stm32h7a3xxq.h"
#elif defined(STM32H7B3xxQ)
#include "stm32h7b3xxq.h"
#elif defined(STM32H735xx)
#include "stm32h735xx.h"
#elif defined(STM32H733xx)
#include "stm32h733xx.h"
#elif defined(STM32H730xx)
#include "stm32h730xx.h"
#elif defined(STM32H730xxQ)
#include "stm32h730xxq.h"
#elif defined(STM32H725xx)
#include "stm32h725xx.h"
#elif defined(STM32H723xx)
#include "stm32h723xx.h"
#else
#error "Please select first the target STM32H7xx device used in your application (in stm32h7xx.h file)"
#endif
#if defined(DUAL_CORE) && !defined(CORE_CM4) && !defined(CORE_CM7)
#error "Dual core device, please select CORE_CM4 or CORE_CM7"
#endif
/**
* @}
*/
/** @addtogroup Exported_types
* @{
*/
typedef enum
{
RESET = 0,
SET = !RESET
} FlagStatus, ITStatus;
typedef enum
{
DISABLE = 0,
ENABLE = !DISABLE
} FunctionalState;
#define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE))
typedef enum
{
SUCCESS = 0,
ERROR = !SUCCESS
} ErrorStatus;
/**
* @}
*/
/** @addtogroup Exported_macros
* @{
*/
#define SET_BIT(REG, BIT) ((REG) |= (BIT))
#define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT))
#define READ_BIT(REG, BIT) ((REG) & (BIT))
#define CLEAR_REG(REG) ((REG) = (0x0))
#define WRITE_REG(REG, VAL) ((REG) = (VAL))
#define READ_REG(REG) ((REG))
#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))
#define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL)))
/* Use of CMSIS compiler intrinsics for register exclusive access */
/* Atomic 32-bit register access macro to set one or several bits */
#define ATOMIC_SET_BIT(REG, BIT) \
do { \
uint32_t val; \
do { \
val = __LDREXW((__IO uint32_t *)&(REG)) | (BIT); \
} while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \
} while(0)
/* Atomic 32-bit register access macro to clear one or several bits */
#define ATOMIC_CLEAR_BIT(REG, BIT) \
do { \
uint32_t val; \
do { \
val = __LDREXW((__IO uint32_t *)&(REG)) & ~(BIT); \
} while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \
} while(0)
/* Atomic 32-bit register access macro to clear and set one or several bits */
#define ATOMIC_MODIFY_REG(REG, CLEARMSK, SETMASK) \
do { \
uint32_t val; \
do { \
val = (__LDREXW((__IO uint32_t *)&(REG)) & ~(CLEARMSK)) | (SETMASK); \
} while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \
} while(0)
/* Atomic 16-bit register access macro to set one or several bits */
#define ATOMIC_SETH_BIT(REG, BIT) \
do { \
uint16_t val; \
do { \
val = __LDREXH((__IO uint16_t *)&(REG)) | (BIT); \
} while ((__STREXH(val,(__IO uint16_t *)&(REG))) != 0U); \
} while(0)
/* Atomic 16-bit register access macro to clear one or several bits */
#define ATOMIC_CLEARH_BIT(REG, BIT) \
do { \
uint16_t val; \
do { \
val = __LDREXH((__IO uint16_t *)&(REG)) & ~(BIT); \
} while ((__STREXH(val,(__IO uint16_t *)&(REG))) != 0U); \
} while(0)
/* Atomic 16-bit register access macro to clear and set one or several bits */
#define ATOMIC_MODIFYH_REG(REG, CLEARMSK, SETMASK) \
do { \
uint16_t val; \
do { \
val = (__LDREXH((__IO uint16_t *)&(REG)) & ~(CLEARMSK)) | (SETMASK); \
} while ((__STREXH(val,(__IO uint16_t *)&(REG))) != 0U); \
} while(0)
/**
* @}
*/
#if defined (USE_HAL_DRIVER)
#include "stm32h7xx_hal.h"
#endif /* USE_HAL_DRIVER */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* STM32H7xx_H */
/**
* @}
*/
/**
* @}
*/
Loaded 100 of 267 files, more files were not shown because too many files have changed in this diff. Show more