mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-28 12:30:58 +00:00
115 lines
4.5 KiB
C
115 lines
4.5 KiB
C
// 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);
|