mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-21 11:30:01 +00:00
Add frdm-mcxw71 support
This commit is contained in:
1 parent
38c326644f
commit
a6b6a0d779
6 files changed
+343
No files matched your search
@@ -0,0 +1,43 @@
|
||||
# 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 += -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 -lgcc -Wl,--gc-sections
|
||||
|
||||
SOURCES = main.c hal.c $(MGDIR)/mongoose.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_*
|
||||
@@ -0,0 +1,109 @@
|
||||
// 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;
|
||||
|
||||
// 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) {
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
// 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>
|
||||
|
||||
#define BIT(x) (1UL << (x))
|
||||
#define CLRSET(reg, clear, set) ((reg) = ((reg) & ~(clear)) | (set))
|
||||
|
||||
#define SIRC_FREQUENCY 6000000UL // Slow IRC (FRO6M), Hz
|
||||
|
||||
extern uint32_t SystemCoreClock; // CPU clock, Hz. Set by hal_clock_init()
|
||||
|
||||
// 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];
|
||||
}
|
||||
|
||||
// Work out the CPU clock from the SCG clock source and core divider. The
|
||||
// clock is left as configured at reset
|
||||
static inline void hal_clock_init(void) {
|
||||
uint32_t csr = SCG0->CSR, freq = 0;
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -0,0 +1,37 @@
|
||||
/* MCXW716C memory map, see MCUXpresso SDK gcc/mcxw716_flash.ld */
|
||||
ENTRY(Reset_Handler);
|
||||
MEMORY {
|
||||
flash(rx) : ORIGIN = 0x00000000, LENGTH = 1024k
|
||||
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)
|
||||
*(.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 */
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) 2026 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
#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();
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
hal_clock_init();
|
||||
hal_uart_init(UART_DEBUG, 115200);
|
||||
mg_log_set_fn(log_fn, UART_DEBUG);
|
||||
|
||||
MG_INFO(("Initialised. CPU clock: %lu MHz", SystemCoreClock / 1000000));
|
||||
MG_INFO(("RAM used: %zu, free: %zu", hal_ram_used(), hal_ram_free()));
|
||||
|
||||
for (;;) {
|
||||
static uint64_t timer;
|
||||
if (hal_timer_expired(&timer, 1000, hal_get_tick())) {
|
||||
MG_INFO(("Hi from Mongoose, tick %llu", hal_get_tick()));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
// See https://mongoose.ws/documentation/#build-options
|
||||
#define MG_ARCH MG_ARCH_ARMGCC
|
||||
|
||||
#define MG_ENABLE_TCPIP 1 // Built-in TCP/IP stack. No network driver yet
|
||||
#define MG_ENABLE_CUSTOM_MILLIS 1
|
||||
Reference in new issue
Block a user