mirror of
https://github.com/cesanta/mongoose.git
synced 2026-11-07 16:01:30 +00:00
Reorganized NXP examples
This commit is contained in:
1 parent
aae31aba9c
commit
201a81a315
1955 files changed
+5705
-1344015
No files matched your search
@@ -0,0 +1 @@
|
||||
See the example at https://github.com/mongoose-examples/frdm-mcxe247
|
||||
@@ -0,0 +1,42 @@
|
||||
# Environment setup: https://mongoose.ws/documentation/tutorials/tools/
|
||||
|
||||
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. -Imongoose -Icmsis_core/CMSIS/Core/Include/
|
||||
CFLAGS += -Icmsis_mcxe247/devices/MCXE247/ -Icmsis_mcxe247/devices/MCXE247/periph0/ -Icmsis_mcxe247/devices/MCXE247/drivers/
|
||||
CFLAGS += -DCPU_MCXE247VLQ -DCPU_MCXE247VLQ_cm4
|
||||
CFLAGS += -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard $(CFLAGS_EXTRA)
|
||||
LDFLAGS ?= -Tlink.ld -nostdlib -nostartfiles --specs=nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=$@.map
|
||||
|
||||
SOURCES = main.c hal.c mongoose/mongoose.c
|
||||
SOURCES += cmsis_mcxe247/devices/MCXE247/gcc/startup_MCXE247.S
|
||||
SOURCES += cmsis_mcxe247/devices/MCXE247/drivers/fsl_clock.c
|
||||
|
||||
CFLAGS += -D__ATOLLIC__ -D__STARTUP_CLEAR_BSS
|
||||
|
||||
all build: firmware.bin
|
||||
|
||||
mongoose/mongoose.c mongoose/mongoose.h:
|
||||
mkdir -p mongoose
|
||||
cp ../../../../mongoose.[ch] mongoose/
|
||||
|
||||
firmware.bin: firmware.elf
|
||||
arm-none-eabi-objcopy -O binary $< $@
|
||||
arm-none-eabi-size --format=berkeley $<
|
||||
|
||||
firmware.elf: cmsis_core cmsis_mcxe247 $(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 $@
|
||||
|
||||
cmsis_mcxe247:
|
||||
curl -sL https://mcuxpresso.nxp.com/cmsis_pack/repo/NXP.MCXE247_DFP.26.06.00.pack -o NXP.MCXE247_DFP.26.06.00.pack
|
||||
unzip -q NXP.MCXE247_DFP.26.06.00.pack -d $@
|
||||
rm NXP.MCXE247_DFP.26.06.00.pack
|
||||
|
||||
clean:
|
||||
rm -rf firmware.* cmsis_* mongoose/mongoose.*
|
||||
@@ -0,0 +1,125 @@
|
||||
// Copyright (c) 2026 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
#include "hal.h"
|
||||
|
||||
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;
|
||||
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) {
|
||||
}
|
||||
|
||||
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,289 @@
|
||||
// Copyright (c) 2023 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
// MCXE24x Series Reference Manual (MCXE24XRM)
|
||||
// FRDM-MCXE247 Board User Manual: UM12286
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "MCXE247.h"
|
||||
|
||||
#include <fsl_clock.h>
|
||||
|
||||
#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)
|
||||
|
||||
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 80000000UL
|
||||
|
||||
enum { HAL_GPIO_MODE_INPUT, HAL_GPIO_MODE_OUTPUT, HAL_GPIO_MODE_AF };
|
||||
enum { HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_OTYPE_OPEN_DRAIN };
|
||||
enum { HAL_GPIO_SPEED_LOW, HAL_GPIO_SPEED_HIGH };
|
||||
enum { HAL_GPIO_PULL_NONE, HAL_GPIO_PULL_DOWN, HAL_GPIO_PULL_UP };
|
||||
static inline GPIO_Type *hal_gpio_bank(uint16_t pin) {
|
||||
static GPIO_Type *const g[] = GPIO_BASE_PTRS;
|
||||
return g[PINBANK(pin)];
|
||||
}
|
||||
|
||||
static inline void hal_gpio_init(uint16_t pin, uint8_t mode, uint8_t type,
|
||||
uint8_t speed, uint8_t pull, uint8_t af) {
|
||||
static PORT_Type *const p[] = PORT_BASE_PTRS;
|
||||
PORT_Type *port = p[PINBANK(pin)];
|
||||
GPIO_Type *gpio = hal_gpio_bank(pin);
|
||||
uint32_t mask = (uint32_t)BIT(PINNO(pin));
|
||||
bool dopull = pull > 0;
|
||||
if (gpio == GPIOA) {
|
||||
CLOCK_EnableClock(kCLOCK_PortA);
|
||||
} else if (gpio == GPIOB) {
|
||||
CLOCK_EnableClock(kCLOCK_PortB);
|
||||
} else if (gpio == GPIOC) {
|
||||
CLOCK_EnableClock(kCLOCK_PortC);
|
||||
} else if (gpio == GPIOD) {
|
||||
CLOCK_EnableClock(kCLOCK_PortD);
|
||||
} else if (gpio == GPIOE) {
|
||||
CLOCK_EnableClock(kCLOCK_PortE);
|
||||
}
|
||||
if (dopull)
|
||||
--pull;
|
||||
port->PCR[PINNO(pin)] = PORT_PCR_MUX(af) | PORT_PCR_DSE(1) |
|
||||
PORT_PCR_PE(dopull) | PORT_PCR_PS(pull);
|
||||
if (mode == HAL_GPIO_MODE_INPUT) {
|
||||
gpio->PDDR &= ~mask;
|
||||
} else if (mode == HAL_GPIO_MODE_OUTPUT) {
|
||||
gpio->PDDR |= mask;
|
||||
}
|
||||
|
||||
(void) type, (void) speed;
|
||||
}
|
||||
|
||||
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_LOW,
|
||||
HAL_GPIO_PULL_NONE, 1);
|
||||
}
|
||||
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_LOW,
|
||||
HAL_GPIO_PULL_NONE, 1);
|
||||
}
|
||||
|
||||
static inline bool hal_gpio_read(uint16_t pin) {
|
||||
GPIO_Type *gpio = hal_gpio_bank(pin);
|
||||
return gpio->PDIR & PINNO(pin);
|
||||
}
|
||||
|
||||
static inline void hal_gpio_write(uint16_t pin, bool value) {
|
||||
GPIO_Type *gpio = hal_gpio_bank(pin);
|
||||
if (value) {
|
||||
gpio->PDOR |= (1 << PINNO(pin));
|
||||
} else {
|
||||
gpio->PDOR &= ~(1 << PINNO(pin));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void hal_gpio_toggle(uint16_t pin) {
|
||||
GPIO_Type *gpio = hal_gpio_bank(pin);
|
||||
uint32_t mask = (uint32_t)BIT(PINNO(pin));
|
||||
gpio->PTOR = mask;
|
||||
}
|
||||
|
||||
static inline void hal_uart_init(LPUART_Type *uart, unsigned long baud) {
|
||||
uint8_t af = 3; // Alternate function
|
||||
uint16_t pr = 0, pt = 0; // pins
|
||||
uint32_t freq = 8000000; // 8MHz (System Oscillator clock)
|
||||
uint32_t lpuart_clk;
|
||||
if (uart == LPUART2)
|
||||
lpuart_clk = kCLOCK_Lpuart2, pt = PIN('E', 12), pr = PIN('D', 17);
|
||||
if (uart == LPUART1)
|
||||
lpuart_clk = kCLOCK_Lpuart1, pt = PIN('C', 9), pr = PIN('C', 8);
|
||||
|
||||
CLOCK_SetIpSrc(lpuart_clk, kCLOCK_IpSrcSysOscAsync);
|
||||
hal_gpio_init(pt, HAL_GPIO_MODE_OUTPUT, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_LOW,
|
||||
HAL_GPIO_PULL_UP, af);
|
||||
hal_gpio_init(pr, HAL_GPIO_MODE_INPUT, HAL_GPIO_OTYPE_PUSH_PULL, HAL_GPIO_SPEED_LOW,
|
||||
HAL_GPIO_PULL_UP, af);
|
||||
CLOCK_EnableClock(lpuart_clk);
|
||||
uart->GLOBAL |= LPUART_GLOBAL_RST_MASK; // reset, CTRL = 0, defaults
|
||||
uart->GLOBAL &= ~LPUART_GLOBAL_RST_MASK;
|
||||
// use an oversample ratio of 23
|
||||
CLRSET(uart->BAUD,
|
||||
LPUART_BAUD_OSR_MASK | LPUART_BAUD_SBR_MASK | LPUART_BAUD_SBNS_MASK,
|
||||
LPUART_BAUD_OSR(23 - 1) | LPUART_BAUD_SBR(freq / (23 * baud)));
|
||||
CLRSET(uart->CTRL,
|
||||
LPUART_CTRL_PE_MASK | LPUART_CTRL_M_MASK | LPUART_CTRL_ILT_MASK |
|
||||
LPUART_CTRL_IDLECFG_MASK,
|
||||
LPUART_CTRL_IDLECFG(1) | LPUART_CTRL_ILT(1) |
|
||||
LPUART_BAUD_SBNS(0)); // no parity, idle 2 chars after 1 stop bit
|
||||
uart->CTRL |= LPUART_CTRL_TE_MASK | LPUART_CTRL_RE_MASK;
|
||||
}
|
||||
|
||||
static inline void hal_uart_write_byte(LPUART_Type *uart, uint8_t byte) {
|
||||
uart->DATA = byte;
|
||||
while ((uart->STAT & LPUART_STAT_TDRE_MASK) == 0)
|
||||
spin(1);
|
||||
}
|
||||
static inline void hal_uart_write_buf(LPUART_Type *uart, char *buf, size_t len) {
|
||||
while (len-- > 0)
|
||||
hal_uart_write_byte(uart, *(uint8_t *)buf++);
|
||||
}
|
||||
|
||||
static inline void hal_ethernet_init(void) {
|
||||
// enable peripheral clock
|
||||
uint32_t reg = (*(volatile uint32_t *)(uint32_t)kCLOCK_Enet);
|
||||
reg = (reg & ~(PCC_CLKCFG_PCS_MASK | PCC_CLKCFG_FRAC_MASK | PCC_CLKCFG_PCD_MASK)) | PCC_CLKCFG_PCS(6) |
|
||||
PCC_CLKCFG_PCD(1) | PCC_CLKCFG_FRAC(1);
|
||||
(*(volatile uint32_t *)(uint32_t)kCLOCK_Enet) = reg & ~PCC_CLKCFG_CGC_MASK;
|
||||
(*(volatile uint32_t *)(uint32_t)kCLOCK_Enet) = reg;
|
||||
CLOCK_EnableClock(kCLOCK_Enet);
|
||||
|
||||
// init pins
|
||||
hal_gpio_init(PIN('C', 3), HAL_GPIO_MODE_OUTPUT, 0, 0, HAL_GPIO_PULL_NONE, 1); // PHY_RST
|
||||
hal_gpio_write(PIN('C', 3), 1);
|
||||
|
||||
hal_gpio_init(PIN('B', 4), HAL_GPIO_MODE_AF, 0, 0, HAL_GPIO_PULL_NONE, 5); // MII_RMII_MDIO
|
||||
hal_gpio_init(PIN('C', 0), HAL_GPIO_MODE_AF, 0, 0, HAL_GPIO_PULL_NONE, 4); // MII_RMII_RXD1
|
||||
hal_gpio_init(PIN('C', 1), HAL_GPIO_MODE_AF, 0, 0, HAL_GPIO_PULL_NONE, 5); // MII_RMII_RXD0
|
||||
hal_gpio_init(PIN('C', 17), HAL_GPIO_MODE_AF, 0, 0, HAL_GPIO_PULL_NONE, 5); // MII_RMII_RX_DV
|
||||
hal_gpio_init(PIN('C', 2), HAL_GPIO_MODE_AF, 0, 0, HAL_GPIO_PULL_NONE, 5); // MII_RMII_TXD0
|
||||
hal_gpio_init(PIN('D', 11), HAL_GPIO_MODE_AF, 0, 0, HAL_GPIO_PULL_NONE, 5); // MII_RMII_TX_CLK
|
||||
hal_gpio_init(PIN('D', 12), HAL_GPIO_MODE_AF, 0, 0, HAL_GPIO_PULL_NONE, 5); // MII_RMII_TX_EN
|
||||
hal_gpio_init(PIN('D', 7), HAL_GPIO_MODE_AF, 0, 0, HAL_GPIO_PULL_NONE, 5); // MII_RMII_TXD1
|
||||
hal_gpio_init(PIN('E', 8), HAL_GPIO_MODE_AF, 0, 0, HAL_GPIO_PULL_NONE, 5); // MII_RMII_MDC
|
||||
|
||||
// reset PHY
|
||||
hal_gpio_write(PIN('C', 3), 0);
|
||||
spin(50000);
|
||||
hal_gpio_write(PIN('C', 3), 1);
|
||||
|
||||
NVIC_EnableIRQ(ENET_Receive_IRQn);
|
||||
}
|
||||
|
||||
static inline void hal_rtc_init(void) {
|
||||
// Configure RTC clock to generate seeds
|
||||
// Reconfigure it there as needed.
|
||||
SIM->LPOCLKS = 0x13; // LPO32K_CLK, LPO32KCLKEN, LPO1KCLKEN
|
||||
CLOCK_EnableClock(kCLOCK_Rtc0);
|
||||
// If Time Invalid Flag set, reset the RTC
|
||||
if (RTC->SR & RTC_SR_TIF_MASK) {
|
||||
RTC->CR |= RTC_CR_SWR_MASK;
|
||||
RTC->CR &= ~RTC_CR_SWR_MASK;
|
||||
}
|
||||
RTC->IER &= ~(RTC_IER_TSIC_MASK | RTC_IER_TSIE_MASK);
|
||||
RTC->SR |= RTC_SR_TCE_MASK; // Enable timer
|
||||
}
|
||||
|
||||
static inline void hal_clock_init(void) {
|
||||
// init SysOsc
|
||||
SCG->SOSCCSR = SCG_SOSCCSR_SOSCERR_MASK;
|
||||
SCG->SOSCDIV = SCG_SOSCDIV_SOSCDIV1(1) | SCG_SOSCDIV_SOSCDIV2(1);
|
||||
SCG->SOSCCFG = BIT(2) | SCG_SOSCCFG_RANGE(2); // work mode, range
|
||||
SCG->SOSCCSR |= SCG_SOSCCSR_SOSCEN_MASK;
|
||||
while ((SCG->SOSCCSR & SCG_SOSCCSR_SOSCVLD_MASK) == 0) spin(1);
|
||||
|
||||
// init FIRC
|
||||
SCG->SIRCCSR = 0U;
|
||||
SCG->SIRCDIV = SCG_SIRCDIV_SIRCDIV1(0) | SCG_SIRCDIV_SIRCDIV2(2);
|
||||
SCG->SIRCCFG = SCG_SIRCCFG_RANGE(1);
|
||||
SCG->SIRCCSR = SCG_SIRCCSR_SIRCEN_MASK | BIT(0);
|
||||
while ((SCG->SIRCCSR & SCG_SIRCCSR_SIRCVLD_MASK) == 0) spin(1);
|
||||
// Change to use SIRC as system clock source
|
||||
SCG->RCCR = SCG_RCCR_DIVSLOW(3) | SCG_RCCR_SCS(2);
|
||||
while (((SCG->CSR & SCG_CSR_SCS_MASK) >> SCG_CSR_SCS_SHIFT) != 2) spin(1);
|
||||
SCG->FIRCDIV = SCG_FIRCDIV_FIRCDIV1(1) | SCG_FIRCDIV_FIRCDIV2(1);
|
||||
SCG->FIRCCFG = SCG_FIRCCFG_RANGE(0);
|
||||
SCG->FIRCCSR |= SCG_FIRCCSR_FIRCEN_MASK;
|
||||
while ((SCG->FIRCCSR & SCG_FIRCCSR_FIRCVLD_MASK) == 0) spin(1);
|
||||
SCG->RCCR = SCG_RCCR_DIVSLOW(3) | SCG_RCCR_SCS(3); // Change to FIRC
|
||||
while (((SCG->CSR & SCG_CSR_SCS_MASK) >> SCG_CSR_SCS_SHIFT) != 3) spin(1);
|
||||
|
||||
// init SIRC
|
||||
SCG->SIRCCSR = 0U;
|
||||
SCG->SIRCDIV = SCG_SIRCDIV_SIRCDIV1(1) | SCG_SIRCDIV_SIRCDIV2(2);
|
||||
SCG->SIRCCFG = SCG_SIRCCFG_RANGE(1);
|
||||
SCG->SIRCCSR = SCG_SIRCCSR_SIRCEN_MASK | BIT(2);
|
||||
while ((SCG->SIRCCSR & SCG_SIRCCSR_SIRCVLD_MASK) == 0) spin(1);
|
||||
|
||||
// init SysPLL
|
||||
SCG->SPLLCSR = SCG_SPLLCSR_SPLLERR_MASK;
|
||||
SCG->SPLLDIV = SCG_SPLLDIV_SPLLDIV1(2) | SCG_SPLLDIV_SPLLDIV2(0);
|
||||
SCG->SPLLCFG = SCG_SPLLCFG_PREDIV(0) | SCG_SPLLCFG_MULT(24);
|
||||
SCG->SPLLCSR = (uint32_t)SCG_SPLLCSR_SPLLEN_MASK ;
|
||||
while ((SCG->SPLLCSR & SCG_SPLLCSR_SPLLVLD_MASK) == 0) spin(1);
|
||||
|
||||
// Set SCG to SPLL mode
|
||||
SCG->RCCR = SCG_RCCR_DIVSLOW(4) | SCG_RCCR_DIVBUS(1) | SCG_RCCR_DIVCORE(1) | SCG_RCCR_SCS(6);
|
||||
while (((SCG->CSR & SCG_CSR_SCS_MASK) >> SCG_CSR_SCS_SHIFT) != 6) spin(1);
|
||||
// Set SCG CLKOUT selection.
|
||||
SCG->CLKOUTCNFG = SCG_CLKOUTCNFG_CLKOUTSEL(3);
|
||||
}
|
||||
|
||||
// TRNG is part of ELS, which requires flash partitioning to work
|
||||
// Use our PRNG when the OS does not provide an alternative
|
||||
#define MG_HAL_ENABLE_PRNG 1
|
||||
static inline uint32_t hal_entropy_init(void) {
|
||||
hal_rtc_init(); // Initialize RTC
|
||||
spin(100000);
|
||||
uint32_t seed = RTC->TPR; // get seed
|
||||
spin(100000);
|
||||
seed |= (RTC->TPR << 16);
|
||||
return seed;
|
||||
}
|
||||
|
||||
static inline bool hal_entropy_get(uint32_t *ent) {
|
||||
*ent = RTC->TPR;
|
||||
return true;
|
||||
}
|
||||
|
||||
#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) {
|
||||
#if ((__FPU_PRESENT == 1) && (__FPU_USED == 1))
|
||||
SCB->CPACR |= (3 << 20) | (3 << 22); // Enable FPU access
|
||||
#endif
|
||||
__DSB();
|
||||
__ISB();
|
||||
|
||||
// Disable watchdog
|
||||
if ((WDOG->CS & WDOG_CS_CMD32EN_MASK) != 0) {
|
||||
WDOG->CNT = WDOG_UPDATE_KEY;
|
||||
} else {
|
||||
WDOG->CNT = WDOG_UPDATE_KEY & 0xFFFFU;
|
||||
WDOG->CNT = (WDOG_UPDATE_KEY >> 16U) & 0xFFFFU;
|
||||
}
|
||||
WDOG->TOVAL = 0xFFFFU;
|
||||
WDOG->CS = (uint32_t) ((WDOG->CS) & ~WDOG_CS_EN_MASK) | WDOG_CS_UPDATE_MASK;
|
||||
|
||||
LMEM->PCCCR |= LMEM_PCCCR_INVW1_MASK | LMEM_PCCCR_INVW0_MASK;
|
||||
LMEM->PCCCR |= LMEM_PCCCR_GO_MASK;
|
||||
// Wait until the command completes
|
||||
while (LMEM->PCCCR & LMEM_PCCCR_GO_MASK) spin(1);
|
||||
// Enable cache
|
||||
LMEM->PCCCR |= LMEM_PCCCR_ENCACHE_MASK;
|
||||
__ISB();
|
||||
|
||||
// Errata ERR050877 workaround. Enable FZ mode in the FPSCR
|
||||
__set_FPSCR(__get_FPSCR() | FPSCR_FZ_MASK);
|
||||
|
||||
SYSMPU->CESR &= ~SYSMPU_CESR_VLD(1); // disable MPU
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
OUTPUT_FORMAT("elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
ENTRY(Reset_Handler)
|
||||
|
||||
MEMORY
|
||||
{
|
||||
flash(RX) : ORIGIN = 0x0, LENGTH = 0x180000
|
||||
flash2(RX) : ORIGIN = 0x10000000, LENGTH = 0x80000
|
||||
sram(RWX) : ORIGIN = 0x1ffe0000, LENGTH = 0x3f000
|
||||
}
|
||||
|
||||
__StackTop = ORIGIN(sram) + LENGTH(sram);
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.vectors : { FILL(256) KEEP(*(.isr_vector)) } > flash
|
||||
. = 0x400 ;
|
||||
.FlashConfig : { KEEP(*(.FlashConfig)) } > flash
|
||||
.text : { *(.text.* *.text.*) } > flash
|
||||
.rodata : { *(.rodata*) } > flash
|
||||
|
||||
.data : {
|
||||
__data_start__ = .;
|
||||
*(.first_data)
|
||||
*(.data SORT(.data.*))
|
||||
__data_end__ = .;
|
||||
} > sram AT > flash
|
||||
__etext = LOADADDR(.data);
|
||||
|
||||
.bss : { __bss_start__ = .; *(.bss SORT(.bss.*) COMMON) __bss_end__ = .; } > sram
|
||||
|
||||
. = ALIGN(8);
|
||||
_end = .;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
// Copyright (c) 2026 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
|
||||
#include "mongoose.h"
|
||||
#include "hal.h"
|
||||
|
||||
#ifndef UART_DEBUG
|
||||
#define UART_DEBUG LPUART2
|
||||
#endif
|
||||
|
||||
#define LED1 PIN('C', 13) // Red
|
||||
#define LED2 PIN('B', 11) // Green
|
||||
#define LED3 PIN('C', 12) // Blue
|
||||
|
||||
static uint32_t s_rng_seed;
|
||||
|
||||
static void hal_rng_init(void) {
|
||||
s_rng_seed = hal_entropy_init();
|
||||
}
|
||||
|
||||
static uint32_t hal_rng_read(void) {
|
||||
uint32_t seed = s_rng_seed, entropy;
|
||||
if (hal_entropy_get(&entropy)) {
|
||||
entropy *= 0x85ebca6b;
|
||||
entropy ^= entropy << 16;
|
||||
entropy ^= entropy >> 5;
|
||||
seed ^= entropy;
|
||||
seed *= 0x5bd1e995;
|
||||
seed ^= seed << 13;
|
||||
seed ^= seed >> 17;
|
||||
seed ^= seed << 5;
|
||||
seed += entropy;
|
||||
seed ^= seed >> 16;
|
||||
}
|
||||
s_rng_seed = seed;
|
||||
return seed;
|
||||
}
|
||||
|
||||
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(LED1);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t mg_millis(void) {
|
||||
return hal_get_tick();
|
||||
}
|
||||
|
||||
#if MG_ENABLE_CUSTOM_RANDOM
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) { // New HTTP request received
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
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 {
|
||||
mg_http_reply(c, 200, "", "Hi from Mongoose, tick %llu\n",
|
||||
hal_get_tick());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
hal_clock_init();
|
||||
hal_rng_init();
|
||||
hal_gpio_output(LED1);
|
||||
hal_gpio_write(LED1, true);
|
||||
hal_gpio_output(LED2);
|
||||
hal_gpio_write(LED2, true);
|
||||
hal_gpio_output(LED3);
|
||||
hal_gpio_write(LED3, true);
|
||||
hal_uart_init(UART_DEBUG, 115200);
|
||||
mg_log_set_fn(log_fn, UART_DEBUG);
|
||||
|
||||
hal_ethernet_init();
|
||||
|
||||
// Start a minimal web server
|
||||
struct mg_mgr mgr;
|
||||
mg_mgr_init(&mgr);
|
||||
mg_http_listen(&mgr, "http://0.0.0.0", http_ev_handler, NULL);
|
||||
|
||||
for (;;) {
|
||||
mg_mgr_poll(&mgr, 0);
|
||||
blink_task();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
// See https://mongoose.ws/documentation/#build-options
|
||||
#define MG_ARCH MG_ARCH_ARMGCC
|
||||
|
||||
#define MG_ENABLE_TCPIP 1
|
||||
#define MG_ENABLE_DRIVER_MCXE 1
|
||||
#define MG_ENABLE_CUSTOM_MILLIS 1
|
||||
#define MG_ENABLE_CUSTOM_RANDOM 1
|
||||
|
||||
#define MG_DRIVER_MDC_CR 15 // RMII MDC clock divider, from 0 to 7
|
||||
#define MG_TCPIP_PHY_ADDR 0 // PHY address
|
||||
|
||||
// For static IP configuration, define MG_TCPIP_{IP,MASK,GW}
|
||||
// By default, those are set to zero, meaning that DHCP is used
|
||||
//
|
||||
//#define MG_TCPIP_IP MG_IPV4(192, 168, 1, 10)
|
||||
//#define MG_TCPIP_GW MG_IPV4(192, 168, 1, 1)
|
||||
//#define MG_TCPIP_MASK MG_IPV4(255, 255, 255, 0)
|
||||
|
||||
// Set custom MAC address. By default, it is randomly generated
|
||||
// Use the unique ID of the board
|
||||
#define MGUID ((uint32_t*)0x40048054UL)
|
||||
#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)
|
||||
//
|
||||
// Using custom function:
|
||||
// extern void my_function(unsigned char *mac);
|
||||
// #define MG_SET_MAC_ADDRESS(mac) my_function(mac)
|
||||
Reference in new issue
Block a user