diff --git a/mongoose.c b/mongoose.c index f02f10ae..de26d39f 100644 --- a/mongoose.c +++ b/mongoose.c @@ -11369,10 +11369,6 @@ MG_IRAM static bool mg_imxrt_erase(void *addr) { } #endif -MG_IRAM bool mg_imxrt_swap(void) { - return true; -} - MG_IRAM static bool mg_imxrt_write(void *addr, const void *buf, size_t len) { struct mg_flexspi_nor_config config, *config_ptr = &config; bool ok = false; @@ -11428,16 +11424,40 @@ fwxit: return ok; } -// just overwrite instead of swap MG_IRAM static void single_bank_swap(char *p1, char *p2, size_t s, size_t ss) { - // no stdlib calls here + char *scratch = p2 + s; for (size_t ofs = 0; ofs < s; ofs += ss) { + MG_OTA_ROLLBACK_TIMER_FEED(); + mg_imxrt_write(scratch, p1 + ofs, ss); + MG_OTA_ROLLBACK_TIMER_FEED(); mg_imxrt_write(p1 + ofs, p2 + ofs, ss); + MG_OTA_ROLLBACK_TIMER_FEED(); + mg_imxrt_write(p2 + ofs, scratch, ss); } *(volatile unsigned long *) 0xe000ed0c = 0x5fa0004; } +MG_IRAM static bool mg_imxrt_swap(void) { + size_t ss = s_mg_flash_imxrt.secsz; + char *p1 = (char *) s_mg_flash_imxrt.start; + char *p2 = p1 + s_mg_flash_imxrt.size / 2; + size_t s = s_mg_flash_imxrt.size / 2 - ss; + MG_INFO(("Swapping partitions, %u bytes", s)); + MG_INFO(("Do NOT power off...")); + MG_OTA_ROLLBACK_TIMER_FEED(); + mg_log_level = MG_LL_NONE; + s_flash_irq_disabled = true; + single_bank_swap(p1, p2, s, ss); + return true; // unreachable +} + bool mg_ota_begin(size_t new_firmware_size) { + size_t max = s_mg_flash_imxrt.size / 2 - s_mg_flash_imxrt.secsz; + if (new_firmware_size > max) { + MG_ERROR(("Firmware %lu too big for single-bank OTA, max %lu", + new_firmware_size, max)); + return false; + } return mg_ota_flash_begin(new_firmware_size, &s_mg_flash_imxrt); } @@ -11446,25 +11466,7 @@ bool mg_ota_write(const void *buf, size_t len) { } bool mg_ota_end(void) { - if (mg_ota_flash_end(&s_mg_flash_imxrt)) { - if (0) { // is_dualbank() - // TODO(): no devices so far - *(volatile unsigned long *) 0xe000ed0c = 0x5fa0004; - } else { - // Swap partitions. Pray power does not go away - MG_INFO(("Swapping partitions, size %u (%u sectors)", - s_mg_flash_imxrt.size, - s_mg_flash_imxrt.size / s_mg_flash_imxrt.secsz)); - MG_INFO(("Do NOT power off...")); - mg_log_level = MG_LL_NONE; - s_flash_irq_disabled = true; - // Runs in RAM, will reset when finished - single_bank_swap( - (char *) s_mg_flash_imxrt.start, - (char *) s_mg_flash_imxrt.start + s_mg_flash_imxrt.size / 2, - s_mg_flash_imxrt.size / 2, s_mg_flash_imxrt.secsz); - } - } + mg_ota_flash_end(&s_mg_flash_imxrt); return false; } struct mg_flash *mg_flash = &s_mg_flash_imxrt; diff --git a/mongoose.h b/mongoose.h index f70288e8..b646d881 100644 --- a/mongoose.h +++ b/mongoose.h @@ -46,6 +46,7 @@ extern "C" { #define MG_ARCH_RTTHREAD 14 // RT-Thread RTOS #define MG_ARCH_ARMCGT 15 // Texas Semi ARM-CGT #define MG_ARCH_CUBE 16 // STM32Cube environment +#define MG_ARCH_MCUXPRESSO 17 // MCUXpresso environment #define MG_ARCH_NEWLIB MG_ARCH_ARMGCC // Alias, deprecate in 2025 @@ -410,6 +411,158 @@ static inline uint32_t mg_ota_esp32_state_set(uint32_t state) { #endif +#if MG_ARCH == MG_ARCH_MCUXPRESSO +#define _POSIX_TIMERS + +#include +#if !defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// MCUXpresso-generated header, includes the SoC peripheral definitions. +// NOTE: use angle brackets to prevent amalgamator ditching it +#include + +#ifndef MG_PATH_MAX +#define MG_PATH_MAX 100 +#endif + +#ifndef MG_ENABLE_DIRLIST +#define MG_ENABLE_DIRLIST 0 +#endif + +#ifndef MG_ENABLE_TCPIP +#define MG_ENABLE_TCPIP 1 // Enable built-in TCP/IP stack +#endif + +#if MG_ENABLE_TCPIP && !defined(MG_ENABLE_DRIVER_IMXRT10) && \ + !defined(MG_ENABLE_DRIVER_IMXRT11) +#if defined(CPU_MIMXRT1021DAG5A) || defined(CPU_MIMXRT1024DAG5A) || \ + defined(CPU_MIMXRT1042XJM5B) || defined(CPU_MIMXRT1052DVL6B) || \ + defined(CPU_MIMXRT1062DVL6B) || defined(CPU_MIMXRT1064DVL6B) || \ + defined(CPU_MIMXRT1062DVL6A) || defined(CPU_MIMXRT1064DVL6A) || \ + defined(CPU_MIMXRT1062DVMAA_cm7) || defined(CPU_MIMXRT1062DVL6A_cm7) || \ + defined(CPU_MIMXRT1062DVL6B_cm7) || defined(_MIMXRT1021_H_) || \ + defined(_MIMXRT1024_H_) || defined(_MIMXRT1042_H_) || \ + defined(_MIMXRT1052_H_) || defined(_MIMXRT1062_H_) || \ + defined(_MIMXRT1064_H_) +#define MG_ENABLE_DRIVER_IMXRT10 1 +#elif defined(CPU_MIMXRT1176DVMAA_cm7) || defined(CPU_MIMXRT1176DVMAA_cm4) || \ + defined(_MIMXRT1176_cm7_H_) || defined(_MIMXRT1176_cm4_H_) || \ + defined(_MIMXRT1176_H_) +#define MG_ENABLE_DRIVER_IMXRT11 1 +#else +#error Select an Ethernet driver in mongoose_config.h +#endif +#endif + +#ifndef MG_TLS +#define MG_TLS MG_TLS_BUILTIN +#endif + +#if !defined(MG_OTA) && \ + (defined(CPU_MIMXRT1021DAG5A) || defined(CPU_MIMXRT1024DAG5A) || \ + defined(_MIMXRT1021_H_) || defined(_MIMXRT1024_H_)) +#define MG_OTA MG_OTA_RT1020 +#elif !defined(MG_OTA) && \ + (defined(CPU_MIMXRT1052DVL6B) || defined(_MIMXRT1052_H_)) +#define MG_OTA MG_OTA_RT1050 +#elif !defined(MG_OTA) && \ + (defined(CPU_MIMXRT1062DVL6B) || defined(CPU_MIMXRT1062DVL6A) || \ + defined(CPU_MIMXRT1042XJM5B) || defined(_MIMXRT1042_H_) || \ + defined(CPU_MIMXRT1062DVMAA_cm7) || defined(CPU_MIMXRT1062DVL6A_cm7) || \ + defined(CPU_MIMXRT1062DVL6B_cm7) || defined(_MIMXRT1062_H_)) +#define MG_OTA MG_OTA_RT1060 +#elif !defined(MG_OTA) && \ + (defined(CPU_MIMXRT1064DVL6B) || defined(CPU_MIMXRT1064DVL6A) || \ + defined(_MIMXRT1064_H_)) +#define MG_OTA MG_OTA_RT1064 +#elif !defined(MG_OTA) && \ + (defined(CPU_MIMXRT1176DVMAA_cm7) || defined(CPU_MIMXRT1176DVMAA_cm4) || \ + defined(_MIMXRT1176_cm7_H_) || defined(_MIMXRT1176_cm4_H_) || \ + defined(_MIMXRT1176_H_)) +#define MG_OTA MG_OTA_RT1170 +#endif + +#ifndef MG_IRAM +#define MG_IRAM __attribute__((noinline, section(".data_RAM2"))) +#endif + +#ifndef MG_SET_MAC_ADDRESS +#if defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11 +#define MG_OCOTP_FUSES ((volatile uint32_t *) 0x40cac900) +#else +#define MG_OCOTP_FUSES ((volatile uint32_t *) 0x401f4410) +#endif +#define MG_SET_MAC_ADDRESS(mac) \ + do { \ + mac[0] = 2; \ + mac[1] = (MG_OCOTP_FUSES[0] >> 0) & 255; \ + mac[2] = (MG_OCOTP_FUSES[0] >> 10) & 255; \ + mac[3] = ((MG_OCOTP_FUSES[0] >> 19) ^ (MG_OCOTP_FUSES[4] >> 19)) & 255; \ + mac[4] = (MG_OCOTP_FUSES[4] >> 10) & 255; \ + mac[5] = (MG_OCOTP_FUSES[4] >> 0) & 255; \ + } while (0) +#endif + +#ifndef MG_IMXRT_WDOG1_TIMEOUT_MS +#define MG_IMXRT_WDOG1_TIMEOUT_MS 10000 +#endif + +#define MG_IMXRT_WDOG1_FEED() \ + do { \ + WDOG1->WSR = 0x5555; \ + WDOG1->WSR = 0xaaaa; \ + } while (0) + +#ifndef MG_OTA_ROLLBACK_TIMER_START +#define MG_OTA_ROLLBACK_TIMER_START() \ + do { \ + uint16_t wt_ = (uint16_t) ((MG_IMXRT_WDOG1_TIMEOUT_MS / 500) - 1); \ + if ((WDOG1->WCR & WDOG_WCR_WDE_MASK) == 0) { \ + WDOG1->WMCR = 0; \ + WDOG1->WCR = (uint16_t) (WDOG_WCR_WDZST_MASK | WDOG_WCR_WDBG_MASK | \ + WDOG_WCR_WDE_MASK | WDOG_WCR_WDT_MASK | \ + WDOG_WCR_SRS_MASK | WDOG_WCR_WDW_MASK | \ + WDOG_WCR_WT(wt_)); \ + } \ + MG_IMXRT_WDOG1_FEED(); \ + } while (0) +#endif + +#ifndef MG_OTA_ROLLBACK_TIMER_FEED +#define MG_OTA_ROLLBACK_TIMER_FEED() MG_IMXRT_WDOG1_FEED() +#endif + +#ifndef MG_OTA_STATE_GET +#define MG_OTA_STATE_GET() SNVS->LPGPR[0] +#endif + +#ifndef MG_OTA_STATE_SET +#define MG_OTA_STATE_SET(v) \ + do { \ + if (SNVS->LPSR & (1u << 3)) { \ + SNVS->LPLVDR = 0x41736166u; \ + SNVS->LPSR = 1u << 3; \ + } \ + SNVS->LPGPR[0] = (uint32_t) (v); \ + } while (0) +#endif + +#endif + + #if MG_ARCH == MG_ARCH_PICOSDK #if !defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP #include diff --git a/src/arch.h b/src/arch.h index 5df1b76e..c6268658 100644 --- a/src/arch.h +++ b/src/arch.h @@ -19,6 +19,7 @@ #define MG_ARCH_RTTHREAD 14 // RT-Thread RTOS #define MG_ARCH_ARMCGT 15 // Texas Semi ARM-CGT #define MG_ARCH_CUBE 16 // STM32Cube environment +#define MG_ARCH_MCUXPRESSO 17 // MCUXpresso environment #define MG_ARCH_NEWLIB MG_ARCH_ARMGCC // Alias, deprecate in 2025 diff --git a/src/arch_mcuxpresso.h b/src/arch_mcuxpresso.h new file mode 100644 index 00000000..89f2252e --- /dev/null +++ b/src/arch_mcuxpresso.h @@ -0,0 +1,152 @@ +#pragma once + +#if MG_ARCH == MG_ARCH_MCUXPRESSO +#define _POSIX_TIMERS + +#include +#if !defined(MG_ENABLE_LWIP) || !MG_ENABLE_LWIP +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// MCUXpresso-generated header, includes the SoC peripheral definitions. +// NOTE: use angle brackets to prevent amalgamator ditching it +#include + +#ifndef MG_PATH_MAX +#define MG_PATH_MAX 100 +#endif + +#ifndef MG_ENABLE_DIRLIST +#define MG_ENABLE_DIRLIST 0 +#endif + +#ifndef MG_ENABLE_TCPIP +#define MG_ENABLE_TCPIP 1 // Enable built-in TCP/IP stack +#endif + +#if MG_ENABLE_TCPIP && !defined(MG_ENABLE_DRIVER_IMXRT10) && \ + !defined(MG_ENABLE_DRIVER_IMXRT11) +#if defined(CPU_MIMXRT1021DAG5A) || defined(CPU_MIMXRT1024DAG5A) || \ + defined(CPU_MIMXRT1042XJM5B) || defined(CPU_MIMXRT1052DVL6B) || \ + defined(CPU_MIMXRT1062DVL6B) || defined(CPU_MIMXRT1064DVL6B) || \ + defined(CPU_MIMXRT1062DVL6A) || defined(CPU_MIMXRT1064DVL6A) || \ + defined(CPU_MIMXRT1062DVMAA_cm7) || defined(CPU_MIMXRT1062DVL6A_cm7) || \ + defined(CPU_MIMXRT1062DVL6B_cm7) || defined(_MIMXRT1021_H_) || \ + defined(_MIMXRT1024_H_) || defined(_MIMXRT1042_H_) || \ + defined(_MIMXRT1052_H_) || defined(_MIMXRT1062_H_) || \ + defined(_MIMXRT1064_H_) +#define MG_ENABLE_DRIVER_IMXRT10 1 +#elif defined(CPU_MIMXRT1176DVMAA_cm7) || defined(CPU_MIMXRT1176DVMAA_cm4) || \ + defined(_MIMXRT1176_cm7_H_) || defined(_MIMXRT1176_cm4_H_) || \ + defined(_MIMXRT1176_H_) +#define MG_ENABLE_DRIVER_IMXRT11 1 +#else +#error Select an Ethernet driver in mongoose_config.h +#endif +#endif + +#ifndef MG_TLS +#define MG_TLS MG_TLS_BUILTIN +#endif + +#if !defined(MG_OTA) && \ + (defined(CPU_MIMXRT1021DAG5A) || defined(CPU_MIMXRT1024DAG5A) || \ + defined(_MIMXRT1021_H_) || defined(_MIMXRT1024_H_)) +#define MG_OTA MG_OTA_RT1020 +#elif !defined(MG_OTA) && \ + (defined(CPU_MIMXRT1052DVL6B) || defined(_MIMXRT1052_H_)) +#define MG_OTA MG_OTA_RT1050 +#elif !defined(MG_OTA) && \ + (defined(CPU_MIMXRT1062DVL6B) || defined(CPU_MIMXRT1062DVL6A) || \ + defined(CPU_MIMXRT1042XJM5B) || defined(_MIMXRT1042_H_) || \ + defined(CPU_MIMXRT1062DVMAA_cm7) || defined(CPU_MIMXRT1062DVL6A_cm7) || \ + defined(CPU_MIMXRT1062DVL6B_cm7) || defined(_MIMXRT1062_H_)) +#define MG_OTA MG_OTA_RT1060 +#elif !defined(MG_OTA) && \ + (defined(CPU_MIMXRT1064DVL6B) || defined(CPU_MIMXRT1064DVL6A) || \ + defined(_MIMXRT1064_H_)) +#define MG_OTA MG_OTA_RT1064 +#elif !defined(MG_OTA) && \ + (defined(CPU_MIMXRT1176DVMAA_cm7) || defined(CPU_MIMXRT1176DVMAA_cm4) || \ + defined(_MIMXRT1176_cm7_H_) || defined(_MIMXRT1176_cm4_H_) || \ + defined(_MIMXRT1176_H_)) +#define MG_OTA MG_OTA_RT1170 +#endif + +#ifndef MG_IRAM +#define MG_IRAM __attribute__((noinline, section(".data_RAM2"))) +#endif + +#ifndef MG_SET_MAC_ADDRESS +#if defined(MG_ENABLE_DRIVER_IMXRT11) && MG_ENABLE_DRIVER_IMXRT11 +#define MG_OCOTP_FUSES ((volatile uint32_t *) 0x40cac900) +#else +#define MG_OCOTP_FUSES ((volatile uint32_t *) 0x401f4410) +#endif +#define MG_SET_MAC_ADDRESS(mac) \ + do { \ + mac[0] = 2; \ + mac[1] = (MG_OCOTP_FUSES[0] >> 0) & 255; \ + mac[2] = (MG_OCOTP_FUSES[0] >> 10) & 255; \ + mac[3] = ((MG_OCOTP_FUSES[0] >> 19) ^ (MG_OCOTP_FUSES[4] >> 19)) & 255; \ + mac[4] = (MG_OCOTP_FUSES[4] >> 10) & 255; \ + mac[5] = (MG_OCOTP_FUSES[4] >> 0) & 255; \ + } while (0) +#endif + +#ifndef MG_IMXRT_WDOG1_TIMEOUT_MS +#define MG_IMXRT_WDOG1_TIMEOUT_MS 10000 +#endif + +#define MG_IMXRT_WDOG1_FEED() \ + do { \ + WDOG1->WSR = 0x5555; \ + WDOG1->WSR = 0xaaaa; \ + } while (0) + +#ifndef MG_OTA_ROLLBACK_TIMER_START +#define MG_OTA_ROLLBACK_TIMER_START() \ + do { \ + uint16_t wt_ = (uint16_t) ((MG_IMXRT_WDOG1_TIMEOUT_MS / 500) - 1); \ + if ((WDOG1->WCR & WDOG_WCR_WDE_MASK) == 0) { \ + WDOG1->WMCR = 0; \ + WDOG1->WCR = (uint16_t) (WDOG_WCR_WDZST_MASK | WDOG_WCR_WDBG_MASK | \ + WDOG_WCR_WDE_MASK | WDOG_WCR_WDT_MASK | \ + WDOG_WCR_SRS_MASK | WDOG_WCR_WDW_MASK | \ + WDOG_WCR_WT(wt_)); \ + } \ + MG_IMXRT_WDOG1_FEED(); \ + } while (0) +#endif + +#ifndef MG_OTA_ROLLBACK_TIMER_FEED +#define MG_OTA_ROLLBACK_TIMER_FEED() MG_IMXRT_WDOG1_FEED() +#endif + +#ifndef MG_OTA_STATE_GET +#define MG_OTA_STATE_GET() SNVS->LPGPR[0] +#endif + +#ifndef MG_OTA_STATE_SET +#define MG_OTA_STATE_SET(v) \ + do { \ + if (SNVS->LPSR & (1u << 3)) { \ + SNVS->LPLVDR = 0x41736166u; \ + SNVS->LPSR = 1u << 3; \ + } \ + SNVS->LPGPR[0] = (uint32_t) (v); \ + } while (0) +#endif + +#endif diff --git a/src/ota_imxrt.c b/src/ota_imxrt.c index 49db3e37..1c389de7 100644 --- a/src/ota_imxrt.c +++ b/src/ota_imxrt.c @@ -491,10 +491,6 @@ MG_IRAM static bool mg_imxrt_erase(void *addr) { } #endif -MG_IRAM bool mg_imxrt_swap(void) { - return true; -} - MG_IRAM static bool mg_imxrt_write(void *addr, const void *buf, size_t len) { struct mg_flexspi_nor_config config, *config_ptr = &config; bool ok = false; @@ -550,16 +546,40 @@ fwxit: return ok; } -// just overwrite instead of swap MG_IRAM static void single_bank_swap(char *p1, char *p2, size_t s, size_t ss) { - // no stdlib calls here + char *scratch = p2 + s; for (size_t ofs = 0; ofs < s; ofs += ss) { + MG_OTA_ROLLBACK_TIMER_FEED(); + mg_imxrt_write(scratch, p1 + ofs, ss); + MG_OTA_ROLLBACK_TIMER_FEED(); mg_imxrt_write(p1 + ofs, p2 + ofs, ss); + MG_OTA_ROLLBACK_TIMER_FEED(); + mg_imxrt_write(p2 + ofs, scratch, ss); } *(volatile unsigned long *) 0xe000ed0c = 0x5fa0004; } +MG_IRAM static bool mg_imxrt_swap(void) { + size_t ss = s_mg_flash_imxrt.secsz; + char *p1 = (char *) s_mg_flash_imxrt.start; + char *p2 = p1 + s_mg_flash_imxrt.size / 2; + size_t s = s_mg_flash_imxrt.size / 2 - ss; + MG_INFO(("Swapping partitions, %u bytes", s)); + MG_INFO(("Do NOT power off...")); + MG_OTA_ROLLBACK_TIMER_FEED(); + mg_log_level = MG_LL_NONE; + s_flash_irq_disabled = true; + single_bank_swap(p1, p2, s, ss); + return true; // unreachable +} + bool mg_ota_begin(size_t new_firmware_size) { + size_t max = s_mg_flash_imxrt.size / 2 - s_mg_flash_imxrt.secsz; + if (new_firmware_size > max) { + MG_ERROR(("Firmware %lu too big for single-bank OTA, max %lu", + new_firmware_size, max)); + return false; + } return mg_ota_flash_begin(new_firmware_size, &s_mg_flash_imxrt); } @@ -568,25 +588,7 @@ bool mg_ota_write(const void *buf, size_t len) { } bool mg_ota_end(void) { - if (mg_ota_flash_end(&s_mg_flash_imxrt)) { - if (0) { // is_dualbank() - // TODO(): no devices so far - *(volatile unsigned long *) 0xe000ed0c = 0x5fa0004; - } else { - // Swap partitions. Pray power does not go away - MG_INFO(("Swapping partitions, size %u (%u sectors)", - s_mg_flash_imxrt.size, - s_mg_flash_imxrt.size / s_mg_flash_imxrt.secsz)); - MG_INFO(("Do NOT power off...")); - mg_log_level = MG_LL_NONE; - s_flash_irq_disabled = true; - // Runs in RAM, will reset when finished - single_bank_swap( - (char *) s_mg_flash_imxrt.start, - (char *) s_mg_flash_imxrt.start + s_mg_flash_imxrt.size / 2, - s_mg_flash_imxrt.size / 2, s_mg_flash_imxrt.secsz); - } - } + mg_ota_flash_end(&s_mg_flash_imxrt); return false; } struct mg_flash *mg_flash = &s_mg_flash_imxrt;