Skip to content

Commit a39e9cd

Browse files
gab-khathach
authored andcommitted
Add initial board support for nRF54LM20 DK
1 parent 7c3f597 commit a39e9cd

12 files changed

Lines changed: 238 additions & 16 deletions

File tree

docs/reference/boards.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ nrf52840dk Nordic nRF52840DK nrf ht
221221
nrf52840dongle Nordic nRF52840 Dongle nrf https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-Dongle
222222
nrf5340dk Nordic nRF5340 DK nrf https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF5340-DK
223223
nrf54h20dk Nordic nRF54H20 DK nrf https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF5340-DK
224+
nrf54lm20dk Nordic nRF54LM20 DK nrf https://www.nordicsemi.com/Products/Development-hardware/nRF54LM20-DK
224225
=========================== ===================================== ======== ============================================================================== ======
225226

226227
Raspberry Pi

hw/bsp/BoardPresets.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,10 @@
470470
"name": "nrf54h20dk",
471471
"inherits": "default"
472472
},
473+
{
474+
"name": "nrf54lm20dk",
475+
"inherits": "default"
476+
},
473477
{
474478
"name": "nutiny_nuc126v",
475479
"inherits": "default"
@@ -1563,6 +1567,11 @@
15631567
"description": "Build preset for the nrf54h20dk board",
15641568
"configurePreset": "nrf54h20dk"
15651569
},
1570+
{
1571+
"name": "nrf54lm20dk",
1572+
"description": "Build preset for the nrf54lm20dk board",
1573+
"configurePreset": "nrf54lm20dk"
1574+
},
15661575
{
15671576
"name": "nutiny_nuc126v",
15681577
"description": "Build preset for the nutiny_nuc126v board",
@@ -3711,6 +3720,19 @@
37113720
}
37123721
]
37133722
},
3723+
{
3724+
"name": "nrf54lm20dk",
3725+
"steps": [
3726+
{
3727+
"type": "configure",
3728+
"name": "nrf54lm20dk"
3729+
},
3730+
{
3731+
"type": "build",
3732+
"name": "nrf54lm20dk"
3733+
}
3734+
]
3735+
},
37143736
{
37153737
"name": "nutiny_nuc126v",
37163738
"steps": [
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
set(MCU_VARIANT nrf54lm20a_enga)
2+
set(JLINK_DEVICE NRF54LM20A_M33)
3+
4+
function(update_board TARGET)
5+
target_compile_definitions(${TARGET} PUBLIC
6+
CFG_EXAMPLE_VIDEO_READONLY
7+
)
8+
target_sources(${TARGET} PRIVATE
9+
# ${NRFX_PATH}/drivers/src/nrfx_usbreg.c
10+
)
11+
endfunction()
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2020, Ha Thach (tinyusb.org)
5+
* Copyright (c) 2026, Gabriel Koppenstein
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy
8+
* of this software and associated documentation files (the "Software"), to deal
9+
* in the Software without restriction, including without limitation the rights
10+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the Software is
12+
* furnished to do so, subject to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be included in
15+
* all copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
* THE SOFTWARE.
24+
*
25+
* This file is part of the TinyUSB stack.
26+
*/
27+
28+
/* metadata:
29+
name: Nordic nRF54LM20 DK
30+
url: https://www.nordicsemi.com/Products/Development-hardware/nRF54LM20-DK
31+
*/
32+
33+
#ifndef BOARD_H_
34+
#define BOARD_H_
35+
36+
#ifdef __cplusplus
37+
extern "C" {
38+
#endif
39+
40+
#define _PINNUM(port, pin) ((port)*32 + (pin))
41+
42+
// LED0 active high (MOSFET-driven)
43+
#define LED_PIN _PINNUM(1, 22)
44+
#define LED_STATE_ON 1
45+
46+
// Button0 active low
47+
#define BUTTON_PIN _PINNUM(1, 26)
48+
#define BUTTON_STATE_ACTIVE 0
49+
50+
// UART20 (VCOM via debugger)
51+
#define UART_TX_PIN _PINNUM(1, 16)
52+
#define UART_RX_PIN _PINNUM(1, 17)
53+
54+
#ifdef __cplusplus
55+
}
56+
#endif
57+
58+
#endif /* BOARD_H_ */
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
MCU_VARIANT = nrf54lm20a_enga
2+
CFLAGS += -DNRF54LM20A_ENGA_XXAA
3+
4+
# flash using jlink
5+
JLINK_DEVICE = NRF54LM20A_M33
6+
flash: flash-jlink

hw/bsp/nrf/family.c

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* The MIT License (MIT)
33
*
44
* Copyright (c) 2019 Ha Thach (tinyusb.org)
5+
* Copyright (c) 2026, Gabriel Koppenstein
56
*
67
* Permission is hereby granted, free of charge, to any person obtaining a copy
78
* of this software and associated documentation files (the "Software"), to deal
@@ -45,7 +46,7 @@
4546
#include "nrfx.h"
4647
#include "hal/nrf_gpio.h"
4748
#include "nrfx_gpiote.h"
48-
#if !defined(NRF54H20_XXAA)
49+
#if !defined(NRF54H20_XXAA) && !defined(NRF54LM20A_ENGA_XXAA)
4950
#include "nrfx_power.h"
5051
#endif
5152
#include "nrfx_uarte.h"
@@ -79,13 +80,17 @@ enum {
7980
};
8081

8182
// Forward USB interrupt events to TinyUSB IRQ Handler
82-
#if defined(NRF54H20_XXAA)
83+
#if defined(NRF54H20_XXAA) || defined(NRF54LM20A_ENGA_XXAA)
8384
#define USBD_IRQn USBHS_IRQn
8485
void USBHS_IRQHandler(void) {
8586
tusb_int_handler(0, true);
8687
}
8788

89+
#if defined(NRF54LM20A_ENGA_XXAA)
90+
static nrfx_uarte_t _uart_id = NRFX_UARTE_INSTANCE(20);
91+
#else
8892
static nrfx_uarte_t _uart_id = NRFX_UARTE_INSTANCE(120);
93+
#endif
8994

9095
#else
9196

@@ -114,7 +119,7 @@ void USBD_IRQHandler(void) {
114119
// We must call it within SD's SOC event handler, or set it as power event handler if SD is not enabled.
115120
extern void tusb_hal_nrf_power_event(uint32_t event);
116121

117-
#if !defined(NRF54H20_XXAA)
122+
#if !defined(NRF54H20_XXAA) && !defined(NRF54LM20A_ENGA_XXAA)
118123
// nrf power callback, could be unused if SD is enabled or usb is disabled (board_test example)
119124
TU_ATTR_UNUSED static void power_event_handler(nrfx_power_usb_evt_t event) {
120125
tusb_hal_nrf_power_event((uint32_t) event);
@@ -133,7 +138,7 @@ static nrfx_gpiote_t _gpiote = NRFX_GPIOTE_INSTANCE(0);
133138
//--------------------------------------------------------------------+
134139

135140
void board_init(void) {
136-
#if !defined(NRF54H20_XXAA)
141+
#if !defined(NRF54H20_XXAA) && !defined(NRF54LM20A_ENGA_XXAA)
137142
// stop LF clock just in case we jump from application without reset
138143
NRF_CLOCK->TASKS_LFCLKSTOP = 1UL;
139144

@@ -186,11 +191,63 @@ void board_init(void) {
186191

187192
//------------- USB -------------//
188193
#if CFG_TUD_ENABLED
194+
195+
#if defined(NRF54LM20A_ENGA_XXAA)
196+
// Start the USB voltage regulator
197+
NRF_VREGUSB->TASKS_START = VREGUSB_TASKS_START_TASKS_START_Trigger;
198+
199+
// Request HFXO crystal clock for PCLK24M (required by USBHS core)
200+
NRF_CLOCK->TASKS_XO24MSTART = CLOCK_TASKS_XO24MSTART_TASKS_XO24MSTART_Trigger;
201+
while (!NRF_CLOCK->EVENTS_XO24MSTARTED) {}
202+
NRF_CLOCK->EVENTS_XO24MSTARTED = 0;
203+
#endif
204+
205+
#if defined(NRF54H20_XXAA)
206+
// Enable the USBHS wrapper (core + PHY) before any DWC2 register access
207+
NRF_USBHS->ENABLE = (USBHS_ENABLE_PHY_Enabled << USBHS_ENABLE_PHY_Pos) |
208+
(USBHS_ENABLE_CORE_Enabled << USBHS_ENABLE_CORE_Pos);
209+
NRF_USBHS->TASKS_START = USBHS_TASKS_START_TASKS_START_Trigger;
210+
// Brief delay for PHY PLL lock and core power-up
211+
for (volatile int i = 0; i < 1000; i++) {}
212+
#endif
213+
214+
#if defined(NRF54LM20A_ENGA_XXAA)
215+
// Based on Zephyr usbhs_enable_core() in drivers/usb/udc/udc_dwc2_vendor_quirks.h
216+
// Step 1: Power up core only (PHY not yet)
217+
NRF_USBHS->ENABLE = USBHS_ENABLE_CORE_Msk;
218+
219+
// Step 2: Override ID=Device (bit 31), and temporarily override VBUSVALID
220+
NRF_USBHS->PHY.OVERRIDEVALUES = (USBHS_PHY_OVERRIDEVALUES_ID_Device << USBHS_PHY_OVERRIDEVALUES_ID_Pos);
221+
NRF_USBHS->PHY.INPUTOVERRIDE = USBHS_PHY_INPUTOVERRIDE_ID_Msk | USBHS_PHY_INPUTOVERRIDE_VBUSVALID_Msk;
222+
223+
// Step 3: Release PHY power-on reset by enabling PHY
224+
NRF_USBHS->ENABLE = USBHS_ENABLE_PHY_Msk | USBHS_ENABLE_CORE_Msk;
225+
226+
// Step 4: Wait 45us for PHY clock to start
227+
NRFX_DELAY_US(45);
228+
229+
// Step 5: Release DWC2 reset
230+
NRF_USBHS->TASKS_START = USBHS_TASKS_START_TASKS_START_Trigger;
231+
232+
// Step 6: Wait for clock to start to avoid hang on too early register read
233+
NRFX_DELAY_US(2);
234+
235+
// Step 7: Clear VBUSVALID override (keep ID=Device override)
236+
// DWC2 is now in Non-Driving opmode; D+ pull-up will activate when DWC2 clears DCTL SftDiscon
237+
NRF_USBHS->PHY.INPUTOVERRIDE = USBHS_PHY_INPUTOVERRIDE_ID_Msk;
238+
239+
// Barrier: USBHS wrapper (0x5005A000) and USBHSCORE (0x50020000) are separate
240+
// peripheral blocks. Ensure the ENABLE/TASKS_START writes have propagated from
241+
// the Cortex-M33 write buffer to hardware before anyone reads DWC2 core regs.
242+
__DSB();
243+
244+
#endif
245+
189246
// Priorities 0, 1, 4 (nRF52) are reserved for SoftDevice
190247
// 2 is highest for application
191248
NVIC_SetPriority(USBD_IRQn, 2);
192249

193-
#if !defined(NRF54H20_XXAA)
250+
#if !defined(NRF54H20_XXAA) && !defined(NRF54LM20A_ENGA_XXAA)
194251
// USB power may already be ready at this time -> no event generated
195252
// We need to invoke the handler based on the status initially
196253
uint32_t usb_reg;
@@ -258,7 +315,7 @@ size_t board_get_unique_id(uint8_t id[], size_t max_len) {
258315

259316
#if defined(NRF54H20_XXAA)
260317
uintptr_t did_addr = (uintptr_t) NRF_FICR->BLE.ADDR;
261-
#elif defined(NRF5340_XXAA)
318+
#elif defined(NRF54LM20A_ENGA_XXAA) || defined(NRF5340_XXAA)
262319
uintptr_t did_addr = (uintptr_t) NRF_FICR->INFO.DEVICEID;
263320
#else
264321
uintptr_t did_addr = (uintptr_t) NRF_FICR->DEVICEID;

hw/bsp/nrf/family.cmake

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,19 @@ if (NOT board_cmake_included)
1010
endif ()
1111

1212
# toolchain set up
13-
if (MCU_VARIANT STREQUAL nrf5340 OR MCU_VARIANT STREQUAL nrf54h20)
13+
if (MCU_VARIANT STREQUAL nrf5340 OR MCU_VARIANT STREQUAL nrf54h20 OR MCU_VARIANT STREQUAL nrf54lm20a_enga)
1414
set(CMAKE_SYSTEM_CPU cortex-m33 CACHE INTERNAL "System Processor")
15-
set(JLINK_DEVICE ${MCU_VARIANT}_xxaa_app)
15+
if (NOT DEFINED JLINK_DEVICE)
16+
set(JLINK_DEVICE ${MCU_VARIANT}_xxaa_app)
17+
endif ()
1618
else ()
1719
set(CMAKE_SYSTEM_CPU cortex-m4 CACHE INTERNAL "System Processor")
18-
set(JLINK_DEVICE ${MCU_VARIANT}_xxaa)
20+
if (NOT DEFINED JLINK_DEVICE)
21+
set(JLINK_DEVICE ${MCU_VARIANT}_xxaa)
22+
endif ()
1923
endif ()
2024

21-
if (MCU_VARIANT STREQUAL "nrf54h20")
25+
if (MCU_VARIANT STREQUAL "nrf54h20" OR MCU_VARIANT STREQUAL "nrf54lm20a_enga")
2226
set(FAMILY_MCUS NRF54 CACHE INTERNAL "")
2327
else ()
2428
set(FAMILY_MCUS NRF5X CACHE INTERNAL "")
@@ -29,7 +33,10 @@ set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOL
2933
#------------------------------------
3034
# Startup & Linker script
3135
#------------------------------------
32-
if (MCU_VARIANT STREQUAL nrf54h20)
36+
if (MCU_VARIANT STREQUAL nrf54lm20a_enga)
37+
set(LD_FILE_GNU_DEFAULT ${CMAKE_CURRENT_LIST_DIR}/linker/${MCU_VARIANT}_xxaa_application.ld)
38+
set(STARTUP_FILE_GNU ${NRFX_PATH}/mdk/gcc_startup_${MCU_VARIANT}_application.S)
39+
elseif (MCU_VARIANT STREQUAL nrf54h20)
3340
set(LD_FILE_GNU_DEFAULT ${CMAKE_CURRENT_LIST_DIR}/linker/${MCU_VARIANT}_xxaa_application.ld)
3441
set(STARTUP_FILE_GNU ${NRFX_PATH}/mdk/gcc_startup_${MCU_VARIANT}_application.S)
3542
elseif (MCU_VARIANT STREQUAL nrf5340)
@@ -52,13 +59,20 @@ function(family_add_board BOARD_TARGET)
5259
add_library(${BOARD_TARGET} STATIC
5360
${NRFX_PATH}/helpers/nrfx_flag32_allocator.c
5461
${NRFX_PATH}/drivers/src/nrfx_gpiote.c
55-
${NRFX_PATH}/drivers/src/nrfx_power.c
5662
${NRFX_PATH}/drivers/src/nrfx_spim.c
5763
${NRFX_PATH}/drivers/src/nrfx_uarte.c
5864
${NRFX_PATH}/soc/nrfx_atomic.c
5965
)
6066

61-
if (MCU_VARIANT STREQUAL nrf54h20)
67+
if (NOT FAMILY_MCUS STREQUAL "NRF54")
68+
target_sources(${BOARD_TARGET} PRIVATE ${NRFX_PATH}/drivers/src/nrfx_power.c)
69+
endif ()
70+
71+
if (MCU_VARIANT STREQUAL nrf54lm20a_enga)
72+
target_sources(${BOARD_TARGET} PRIVATE
73+
${NRFX_PATH}/mdk/system_nrf54l.c
74+
)
75+
elseif (MCU_VARIANT STREQUAL nrf54h20)
6276
target_sources(${BOARD_TARGET} PRIVATE
6377
${NRFX_PATH}/mdk/system_nrf54h.c
6478
)

hw/bsp/nrf/family.mk

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ NRFX_PATH = hw/mcu/nordic/nrfx
44

55
include $(TOP)/$(BOARD_PATH)/board.mk
66

7+
ifeq (${MCU_VARIANT},nrf54lm20a_enga)
8+
CPU_CORE = cortex-m33
9+
CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_NRF54
10+
LD_FILE_DEFAULT = ${FAMILY_PATH}/linker/${MCU_VARIANT}_xxaa_application.ld
11+
SRC_C += ${NRFX_PATH}/mdk/system_nrf54l.c
12+
SRC_S += ${NRFX_PATH}/mdk/gcc_startup_$(MCU_VARIANT)_application.S
13+
JLINK_DEVICE ?= $(MCU_VARIANT)_xxaa_app
14+
15+
else
716
ifeq (${MCU_VARIANT},nrf54h20)
817
CPU_CORE = cortex-m33
918
CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_NRF54
@@ -32,6 +41,7 @@ else
3241
JLINK_DEVICE ?= $(MCU_VARIANT)_xxaa
3342
endif
3443
endif
44+
endif
3545

3646
CFLAGS += \
3747
-DNRF_APPLICATION \
@@ -70,11 +80,14 @@ SRC_C += \
7080
src/portable/synopsys/dwc2/hcd_dwc2.c \
7181
${NRFX_PATH}/helpers/nrfx_flag32_allocator.c \
7282
${NRFX_PATH}/drivers/src/nrfx_gpiote.c \
73-
${NRFX_PATH}/drivers/src/nrfx_power.c \
7483
${NRFX_PATH}/drivers/src/nrfx_spim.c \
7584
${NRFX_PATH}/drivers/src/nrfx_uarte.c \
7685
${NRFX_PATH}/soc/nrfx_atomic.c
7786

87+
ifeq (,$(findstring OPT_MCU_NRF54,$(CFLAGS)))
88+
SRC_C += ${NRFX_PATH}/drivers/src/nrfx_power.c
89+
endif
90+
7891
INC += \
7992
$(TOP)/$(BOARD_PATH) \
8093
$(TOP)/$(FAMILY_PATH)/nrfx_config \
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/* Linker script to configure memory regions. */
2+
3+
SEARCH_DIR(.)
4+
/*GROUP(-lgcc -lc) not compatible with clang*/
5+
6+
MEMORY
7+
{
8+
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x1FD000 /* Inside global RRAM0 */
9+
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x40000
10+
RAM1 (rwx) : ORIGIN = 0x20040000, LENGTH = 0x40000
11+
}
12+
13+
INCLUDE "nrf_common.ld"

hw/bsp/nrf/nrfx_config/nrfx_config_common.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@
6262
#if defined(NRF54H20_XXAA)
6363
#define NRFX_UARTE120_ENABLED 1
6464

65+
#elif defined(NRF54LM20A_ENGA_XXAA)
66+
#define NRFX_UARTE20_ENABLED 1
67+
6568
#else
6669

6770
#define NRFX_POWER_ENABLED 1

0 commit comments

Comments
 (0)