Skip to content

Commit c21b6d9

Browse files
lucien-nxpjhedberg
authored andcommitted
boards: nxp: add frdm_mcxe247 board support
- support XIP way to boot - add board doc and picture - enable cases below: hello_world/blinky/button/ philosophers/synchronization/ gpio_basic_api/uart_async_api Signed-off-by: Lucien Zhao <[email protected]>
1 parent ae0725b commit c21b6d9

File tree

15 files changed

+727
-1
lines changed

15 files changed

+727
-1
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#
2+
# Copyright 2025 NXP
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
7+
zephyr_library()
8+
zephyr_library_sources(board.c)

boards/nxp/frdm_mcxe247/Kconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Copyright 2025 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config BOARD_FRDM_MCXE247
5+
select BOARD_EARLY_INIT_HOOK
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copyright 2025 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config BOARD_FRDM_MCXE247
5+
select SOC_MCXE247
6+
select SOC_PART_NUMBER_MCXE247VLQ

boards/nxp/frdm_mcxe247/board.c

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
/*
2+
* Copyright 2025 NXP
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
#include <zephyr/init.h>
6+
#include <zephyr/device.h>
7+
#include <zephyr/dt-bindings/clock/mcux_lpc_syscon_clock.h>
8+
#include <fsl_clock.h>
9+
#include <soc.h>
10+
11+
/*******************************************************************************
12+
* Definitions
13+
******************************************************************************/
14+
#define ASSERT_WITHIN_RANGE(val, min, max, str) \
15+
BUILD_ASSERT(val >= min && val <= max, str)
16+
17+
#define ASSERT_ASYNC_CLK_DIV_VALID(val, str) \
18+
BUILD_ASSERT(val == 0 || val == 1 || val == 2 || val == 4 || \
19+
val == 8 || val == 16 || val == 2 || val == 64, str)
20+
21+
#define kSCG_AsyncClkDivBy0 kSCG_AsyncClkDisable
22+
23+
#define TO_SYS_CLK_DIV(val) _DO_CONCAT(kSCG_SysClkDivBy, val)
24+
#define TO_ASYNC_CLK_DIV(val) _DO_CONCAT(kSCG_AsyncClkDivBy, val)
25+
26+
#define SCG_CLOCK_NODE(name) DT_CHILD(DT_INST(0, nxp_kinetis_scg), name)
27+
#define SCG_CLOCK_DIV(name) DT_PROP(SCG_CLOCK_NODE(name), clock_div)
28+
#define SCG_CLOCK_MULT(name) DT_PROP(SCG_CLOCK_NODE(name), clock_mult)
29+
30+
/* System Clock configuration */
31+
ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(slow_clk), 2, 8,
32+
"Invalid SCG slow clock divider value");
33+
ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(bus_clk), 1, 16,
34+
"Invalid SCG bus clock divider value");
35+
ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(core_clk), 1, 16,
36+
"Invalid SCG core clock divider value");
37+
38+
/*******************************************************************************
39+
* Variables
40+
******************************************************************************/
41+
42+
static const scg_sys_clk_config_t scg_sys_clk_config = {
43+
.divSlow = TO_SYS_CLK_DIV(SCG_CLOCK_DIV(slow_clk)),
44+
.divBus = TO_SYS_CLK_DIV(SCG_CLOCK_DIV(bus_clk)),
45+
.divCore = TO_SYS_CLK_DIV(SCG_CLOCK_DIV(core_clk)),
46+
#if DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(core_clk)), SCG_CLOCK_NODE(sosc_clk))
47+
.src = kSCG_SysClkSrcSysOsc,
48+
#elif DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(core_clk)), SCG_CLOCK_NODE(sirc_clk))
49+
.src = kSCG_SysClkSrcSirc,
50+
#elif DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(core_clk)), SCG_CLOCK_NODE(firc_clk))
51+
.src = kSCG_SysClkSrcFirc,
52+
#elif DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(core_clk)), SCG_CLOCK_NODE(spll_clk))
53+
.src = kSCG_SysClkSrcSysPll,
54+
#else
55+
#error Invalid SCG core clock source
56+
#endif
57+
};
58+
59+
#if DT_NODE_HAS_STATUS_OKAY(SCG_CLOCK_NODE(sosc_clk))
60+
/* System Oscillator (SOSC) configuration */
61+
ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(soscdiv1_clk),
62+
"Invalid SCG SOSC divider 1 value");
63+
ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(soscdiv2_clk),
64+
"Invalid SCG SOSC divider 2 value");
65+
static const scg_sosc_config_t scg_sosc_config = {
66+
.freq = DT_PROP(SCG_CLOCK_NODE(sosc_clk), clock_frequency),
67+
.monitorMode = kSCG_SysOscMonitorDisable,
68+
.enableMode = kSCG_SysOscEnable,
69+
.div1 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(soscdiv1_clk)),
70+
.div2 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(soscdiv2_clk)),
71+
.workMode = DT_PROP(DT_INST(0, nxp_kinetis_scg), sosc_mode)
72+
};
73+
#endif /* DT_NODE_HAS_STATUS_OKAY(SCG_CLOCK_NODE(sosc_clk)) */
74+
75+
/* Slow Internal Reference Clock (SIRC) configuration */
76+
ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(sircdiv1_clk),
77+
"Invalid SCG SIRC divider 1 value");
78+
ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(sircdiv2_clk),
79+
"Invalid SCG SIRC divider 2 value");
80+
static const scg_sirc_config_t scg_sirc_config = {
81+
.enableMode = kSCG_SircEnable | kSCG_SircEnableInLowPower,
82+
.div1 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(sircdiv1_clk)),
83+
.div2 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(sircdiv2_clk)),
84+
#if MHZ(8) == DT_PROP(SCG_CLOCK_NODE(sirc_clk), clock_frequency)
85+
.range = kSCG_SircRangeHigh
86+
#else
87+
#error Invalid SCG SIRC clock frequency
88+
#endif
89+
};
90+
91+
/* Fast Internal Reference Clock (FIRC) configuration */
92+
ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(fircdiv1_clk),
93+
"Invalid SCG FIRC divider 1 value");
94+
ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(fircdiv2_clk),
95+
"Invalid SCG FIRC divider 2 value");
96+
static const scg_firc_config_t scg_firc_config = {
97+
.enableMode = kSCG_FircEnable,
98+
.div1 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(fircdiv1_clk)),
99+
.div2 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(fircdiv2_clk)),
100+
#if MHZ(48) == DT_PROP(SCG_CLOCK_NODE(firc_clk), clock_frequency)
101+
.range = kSCG_FircRange48M,
102+
#else
103+
#error Invalid SCG FIRC clock frequency
104+
#endif
105+
.trimConfig = NULL
106+
};
107+
108+
/* System Phase-Locked Loop (SPLL) configuration */
109+
ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(spll_clk), 2, 2,
110+
"Invalid SCG SPLL fixed divider value");
111+
ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(splldiv1_clk),
112+
"Invalid SCG SPLL divider 1 value");
113+
ASSERT_ASYNC_CLK_DIV_VALID(SCG_CLOCK_DIV(splldiv2_clk),
114+
"Invalid SCG SPLL divider 2 value");
115+
ASSERT_WITHIN_RANGE(SCG_CLOCK_DIV(pll), 1, 8,
116+
"Invalid SCG PLL pre divider value");
117+
ASSERT_WITHIN_RANGE(SCG_CLOCK_MULT(pll), 16, 47,
118+
"Invalid SCG PLL multiplier value");
119+
#if (DT_NODE_HAS_STATUS_OKAY(SCG_CLOCK_NODE(sosc_clk)) && \
120+
DT_NODE_HAS_STATUS_OKAY(SCG_CLOCK_NODE(spll_clk)))
121+
static const scg_spll_config_t scg_spll_config = {
122+
.enableMode = kSCG_SysPllEnable,
123+
.monitorMode = kSCG_SysPllMonitorDisable,
124+
.div1 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(splldiv1_clk)),
125+
.div2 = TO_ASYNC_CLK_DIV(SCG_CLOCK_DIV(splldiv2_clk)),
126+
#if !DT_SAME_NODE(DT_CLOCKS_CTLR(SCG_CLOCK_NODE(pll)), SCG_CLOCK_NODE(sosc_clk))
127+
#error Invalid SCG PLL clock source
128+
#endif
129+
.prediv = (SCG_CLOCK_DIV(pll) - 1U),
130+
.mult = (SCG_CLOCK_MULT(pll) - 16U)
131+
};
132+
#endif
133+
134+
__weak void clock_init(void)
135+
{
136+
scg_sys_clk_config_t current;
137+
138+
const scg_sys_clk_config_t scg_sys_clk_config_safe = {
139+
.divSlow = kSCG_SysClkDivBy4,
140+
.divBus = kSCG_SysClkDivBy1,
141+
.divCore = kSCG_SysClkDivBy1,
142+
.src = kSCG_SysClkSrcSirc
143+
};
144+
145+
#if DT_NODE_HAS_STATUS_OKAY(SCG_CLOCK_NODE(sosc_clk))
146+
/* Optionally initialize system oscillator */
147+
CLOCK_InitSysOsc(&scg_sosc_config);
148+
CLOCK_SetXtal0Freq(scg_sosc_config.freq);
149+
#endif
150+
151+
/* Configure SIRC */
152+
CLOCK_InitSirc(&scg_sirc_config);
153+
154+
/* Temporary switch to safe SIRC in order to configure FIRC */
155+
CLOCK_SetRunModeSysClkConfig(&scg_sys_clk_config_safe);
156+
do {
157+
CLOCK_GetCurSysClkConfig(&current);
158+
} while (current.src != scg_sys_clk_config_safe.src);
159+
CLOCK_InitFirc(&scg_firc_config);
160+
161+
#if (DT_NODE_HAS_STATUS_OKAY(SCG_CLOCK_NODE(sosc_clk)) && \
162+
DT_NODE_HAS_STATUS_OKAY(SCG_CLOCK_NODE(spll_clk)))
163+
/* Configure System PLL only if system oscilator is initialized */
164+
/* as the oscillator is the only SPLL clock source.*/
165+
CLOCK_InitSysPll(&scg_spll_config);
166+
#endif
167+
168+
/* Only RUN mode supported for now */
169+
CLOCK_SetRunModeSysClkConfig(&scg_sys_clk_config);
170+
do {
171+
CLOCK_GetCurSysClkConfig(&current);
172+
} while (current.src != scg_sys_clk_config.src);
173+
174+
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpuart0))
175+
CLOCK_SetIpSrc(kCLOCK_Lpuart0,
176+
DT_CLOCKS_CELL(DT_NODELABEL(lpuart0), ip_source));
177+
#endif
178+
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpuart1))
179+
CLOCK_SetIpSrc(kCLOCK_Lpuart1,
180+
DT_CLOCKS_CELL(DT_NODELABEL(lpuart1), ip_source));
181+
#endif
182+
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpuart2))
183+
CLOCK_SetIpSrc(kCLOCK_Lpuart2,
184+
DT_CLOCKS_CELL(DT_NODELABEL(lpuart2), ip_source));
185+
#endif
186+
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpi2c0))
187+
CLOCK_SetIpSrc(kCLOCK_Lpi2c0,
188+
DT_CLOCKS_CELL(DT_NODELABEL(lpi2c0), ip_source));
189+
#endif
190+
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpi2c1))
191+
CLOCK_SetIpSrc(kCLOCK_Lpi2c1,
192+
DT_CLOCKS_CELL(DT_NODELABEL(lpi2c1), ip_source));
193+
#endif
194+
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpspi0))
195+
CLOCK_SetIpSrc(kCLOCK_Lpspi0,
196+
DT_CLOCKS_CELL(DT_NODELABEL(lpspi0), ip_source));
197+
#endif
198+
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpspi1))
199+
CLOCK_SetIpSrc(kCLOCK_Lpspi1,
200+
DT_CLOCKS_CELL(DT_NODELABEL(lpspi1), ip_source));
201+
#endif
202+
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(lpspi2))
203+
CLOCK_SetIpSrc(kCLOCK_Lpspi2,
204+
DT_CLOCKS_CELL(DT_NODELABEL(lpspi2), ip_source));
205+
#endif
206+
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(adc0))
207+
CLOCK_SetIpSrc(kCLOCK_Adc0
208+
DT_CLOCKS_CELL(DT_NODELABEL(adc0), ip_source));
209+
#endif
210+
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(adc1))
211+
CLOCK_SetIpSrc(kCLOCK_Adc1,
212+
DT_CLOCKS_CELL(DT_NODELABEL(adc1), ip_source));
213+
#endif
214+
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm0))
215+
CLOCK_SetIpSrc(kCLOCK_Ftm0,
216+
DT_CLOCKS_CELL(DT_NODELABEL(ftm0), ip_source));
217+
#endif
218+
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm1))
219+
CLOCK_SetIpSrc(kCLOCK_Ftm1,
220+
DT_CLOCKS_CELL(DT_NODELABEL(ftm1), ip_source));
221+
#endif
222+
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm2))
223+
CLOCK_SetIpSrc(kCLOCK_Ftm2,
224+
DT_CLOCKS_CELL(DT_NODELABEL(ftm2), ip_source));
225+
#endif
226+
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm3))
227+
CLOCK_SetIpSrc(kCLOCK_Ftm3,
228+
DT_CLOCKS_CELL(DT_NODELABEL(ftm3), ip_source));
229+
#endif
230+
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm4))
231+
CLOCK_SetIpSrc(kCLOCK_Ftm4,
232+
DT_CLOCKS_CELL(DT_NODELABEL(ftm4), ip_source));
233+
#endif
234+
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm5))
235+
CLOCK_SetIpSrc(kCLOCK_Ftm5,
236+
DT_CLOCKS_CELL(DT_NODELABEL(ftm5), ip_source));
237+
#endif
238+
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm6))
239+
CLOCK_SetIpSrc(kCLOCK_Ftm6,
240+
DT_CLOCKS_CELL(DT_NODELABEL(ftm6), ip_source));
241+
#endif
242+
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ftm7))
243+
CLOCK_SetIpSrc(kCLOCK_Ftm7,
244+
DT_CLOCKS_CELL(DT_NODELABEL(ftm7), ip_source));
245+
#endif
246+
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ewm0))
247+
CLOCK_SetIpSrc(kCLOCK_Ewm0,
248+
DT_CLOCKS_CELL(DT_NODELABEL(ewm0), ip_source));
249+
#endif
250+
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(flexio0))
251+
CLOCK_SetIpSrc(kCLOCK_Flexio0,
252+
DT_CLOCKS_CELL(DT_NODELABEL(flexio0), ip_source));
253+
#endif
254+
#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(enet_ptp_clock))
255+
CLOCK_SetIpSrc(kCLOCK_Enet,
256+
DT_CLOCKS_CELL(DT_NODELABEL(enet_ptp_clock), ip_source));
257+
#endif
258+
}
259+
260+
void board_early_init_hook(void)
261+
{
262+
#if !defined(CONFIG_ARM_MPU)
263+
uint32_t temp_reg;
264+
#endif /* !CONFIG_ARM_MPU */
265+
266+
#if !defined(CONFIG_ARM_MPU)
267+
/*
268+
* Disable memory protection and clear slave port errors.
269+
* MCXE24x does not implement the optional ARMv7-M memory
270+
* protection unit (MPU), specified by the architecture (PMSAv7), in the
271+
* Cortex-M4 core. Instead, the processor includes its own MPU module.
272+
*/
273+
temp_reg = SYSMPU->CESR;
274+
temp_reg &= ~SYSMPU_CESR_VLD_MASK;
275+
temp_reg |= SYSMPU_CESR_SPERR_MASK;
276+
SYSMPU->CESR = temp_reg;
277+
#endif /* !CONFIG_ARM_MPU */
278+
279+
clock_init();
280+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#
2+
# Copyright 2025 NXP
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
7+
board_runner_args(linkserver "--device=MCXE247:FRDM-MCXE247")
8+
board_runner_args(jlink "--device=MCXE247")
9+
10+
include(${ZEPHYR_BASE}/boards/common/linkserver.board.cmake)
11+
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)

boards/nxp/frdm_mcxe247/board.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
board:
2+
name: frdm_mcxe247
3+
full_name: FRDM-MCXE247
4+
vendor: nxp
5+
socs:
6+
- name: mcxe247
47.3 KB
Loading

0 commit comments

Comments
 (0)