Skip to content

Commit 3cfe7a0

Browse files
authored
Merge pull request #3574 from gab-k/support-nrf54lm20a
Add initial board support for nRF54LM20 DK
2 parents 470715a + 5358b20 commit 3cfe7a0

27 files changed

Lines changed: 455 additions & 116 deletions

README.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,9 @@ Supported CPUs
182182
+--------------+-----+-----------------------+--------+------+-----------+------------------------+--------------------+
183183
| MindMotion | mm32 || || mm32f327x_otg | ci_fs variant |
184184
+--------------+-----+-----------------------+--------+------+-----------+------------------------+--------------------+
185-
| NordicSemi | nRF 52833, 52840, 5340 |||| nrf5x | only ep8 is ISO |
185+
| NordicSemi | nRF52, nRF53 |||| nrf5x | only ep8 is ISO |
186+
| +-----------------------------+--------+------+-----------+------------------------+--------------------+
187+
| | nRF54 |||| dwc2 | |
186188
+--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+
187189
| Nuvoton | NUC120 |||| nuc120 | |
188190
| +-----------------------------+--------+------+-----------+------------------------+--------------------+

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": [

hw/bsp/nrf/FreeRTOSConfig/FreeRTOSConfig.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@
5353
#define configENABLE_TRUSTZONE 0
5454
#define configMINIMAL_SECURE_STACK_SIZE (1024)
5555

56+
/* nRF54 runs entirely in Secure mode (SAU present but no SPE bootloader).
57+
* Tell FreeRTOS CM33 NTZ port to use Secure-compatible EXC_RETURN values. */
58+
#if defined(NRF54H20_XXAA) || defined(NRF54LM20A_ENGA_XXAA)
59+
#define configRUN_FREERTOS_SECURE_ONLY 1
60+
#endif
61+
5662
#define configUSE_PREEMPTION 1
5763
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
5864
#define configCPU_CLOCK_HZ SystemCoreClock
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
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+
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: 80 additions & 26 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,42 +80,74 @@ enum {
7980
};
8081

8182
// Forward USB interrupt events to TinyUSB IRQ Handler
82-
#if defined(NRF54H20_XXAA)
83-
#define USBD_IRQn USBHS_IRQn
83+
#if defined(NRF54H20_XXAA) || defined(NRF54LM20A_ENGA_XXAA)
84+
#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
96+
#ifdef NRF5340_XXAA
97+
#define LFCLK_SRC_RC CLOCK_LFCLKSRC_SRC_LFRC
98+
#define VBUSDETECT_Msk USBREG_USBREGSTATUS_VBUSDETECT_Msk
99+
#define OUTPUTRDY_Msk USBREG_USBREGSTATUS_OUTPUTRDY_Msk
100+
#define GPIOTE_IRQn GPIOTE1_IRQn
101+
#else
102+
#define LFCLK_SRC_RC CLOCK_LFCLKSRC_SRC_RC
103+
#define VBUSDETECT_Msk POWER_USBREGSTATUS_VBUSDETECT_Msk
104+
#define OUTPUTRDY_Msk POWER_USBREGSTATUS_OUTPUTRDY_Msk
105+
#endif
91106

92-
#ifdef NRF5340_XXAA
93-
#define LFCLK_SRC_RC CLOCK_LFCLKSRC_SRC_LFRC
94-
#define VBUSDETECT_Msk USBREG_USBREGSTATUS_VBUSDETECT_Msk
95-
#define OUTPUTRDY_Msk USBREG_USBREGSTATUS_OUTPUTRDY_Msk
96-
#define GPIOTE_IRQn GPIOTE1_IRQn
97-
#else
98-
#define LFCLK_SRC_RC CLOCK_LFCLKSRC_SRC_RC
99-
#define VBUSDETECT_Msk POWER_USBREGSTATUS_VBUSDETECT_Msk
100-
#define OUTPUTRDY_Msk POWER_USBREGSTATUS_OUTPUTRDY_Msk
101-
#endif
102-
103-
#if CFG_TUSB_OS != OPT_OS_ZEPHYR
107+
#if CFG_TUSB_OS != OPT_OS_ZEPHYR
104108
static nrfx_uarte_t _uart_id = NRFX_UARTE_INSTANCE(0);
105-
#endif
109+
#endif
106110

107111
void USBD_IRQHandler(void) {
108-
tud_int_handler(0);
112+
tusb_int_handler(0, true);
109113
}
110114
#endif
111115

116+
//--------------------------------------------------------------------+
117+
// UART RX ring buffer and event handler
118+
//--------------------------------------------------------------------+
119+
#if CFG_TUSB_OS != OPT_OS_ZEPHYR
120+
121+
#define UART_RX_BUFSIZE 64
122+
123+
static uint8_t rx_fifo[UART_RX_BUFSIZE];
124+
static volatile uint16_t rx_fifo_head = 0;
125+
static volatile uint16_t rx_fifo_tail = 0;
126+
127+
static uint8_t rx_dma_buf[1]; // 1-byte DMA target for continuous RX
128+
129+
static void uart_event_handler(nrfx_uarte_event_t const* p_event, void* p_context) {
130+
(void) p_context;
131+
if (p_event->type == NRFX_UARTE_EVT_RX_DONE) {
132+
for (size_t i = 0; i < p_event->data.rx.length; i++) {
133+
uint16_t next_head = (rx_fifo_head + 1) & (UART_RX_BUFSIZE - 1);
134+
if (next_head != rx_fifo_tail) {
135+
rx_fifo[rx_fifo_head] = p_event->data.rx.p_buffer[i];
136+
rx_fifo_head = next_head;
137+
}
138+
}
139+
// re-arm 1-byte RX
140+
nrfx_uarte_rx(&_uart_id, rx_dma_buf, sizeof(rx_dma_buf));
141+
}
142+
}
143+
144+
#endif
112145

113146
// tinyusb function that handles power event (detected, ready, removed)
114147
// We must call it within SD's SOC event handler, or set it as power event handler if SD is not enabled.
115148
extern void tusb_hal_nrf_power_event(uint32_t event);
116149

117-
#if !defined(NRF54H20_XXAA)
150+
#if !defined(NRF54H20_XXAA) && !defined(NRF54LM20A_ENGA_XXAA)
118151
// nrf power callback, could be unused if SD is enabled or usb is disabled (board_test example)
119152
TU_ATTR_UNUSED static void power_event_handler(nrfx_power_usb_evt_t event) {
120153
tusb_hal_nrf_power_event((uint32_t) event);
@@ -131,9 +164,8 @@ static nrfx_gpiote_t _gpiote = NRFX_GPIOTE_INSTANCE(0);
131164
//--------------------------------------------------------------------+
132165
//
133166
//--------------------------------------------------------------------+
134-
135167
void board_init(void) {
136-
#if !defined(NRF54H20_XXAA)
168+
#if !defined(NRF54H20_XXAA) && !defined(NRF54LM20A_ENGA_XXAA)
137169
// stop LF clock just in case we jump from application without reset
138170
NRF_CLOCK->TASKS_LFCLKSTOP = 1UL;
139171

@@ -167,12 +199,14 @@ void board_init(void) {
167199

168200
#if CFG_TUSB_OS != OPT_OS_ZEPHYR
169201
// UART
202+
static uint8_t uart_tx_cache[64];
170203
nrfx_uarte_config_t uart_cfg = {
171204
.txd_pin = UART_TX_PIN,
172205
.rxd_pin = UART_RX_PIN,
173206
.rts_pin = NRF_UARTE_PSEL_DISCONNECTED,
174207
.cts_pin = NRF_UARTE_PSEL_DISCONNECTED,
175208
.p_context = NULL,
209+
.tx_cache = { .p_buffer = uart_tx_cache, .length = sizeof(uart_tx_cache) },
176210
.baudrate = NRF_UARTE_BAUDRATE_115200, // CFG_BOARD_UART_BAUDRATE
177211
.interrupt_priority = 7,
178212
.config = {
@@ -181,16 +215,26 @@ void board_init(void) {
181215
}
182216
};
183217

184-
nrfx_uarte_init(&_uart_id, &uart_cfg, NULL);
218+
nrfx_uarte_init(&_uart_id, &uart_cfg, uart_event_handler);
219+
// start continuous 1-byte RX
220+
nrfx_uarte_rx(&_uart_id, rx_dma_buf, sizeof(rx_dma_buf));
185221
#endif
186222

187223
//------------- USB -------------//
188224
#if CFG_TUD_ENABLED
225+
226+
#if defined(NRF54LM20A_ENGA_XXAA)
227+
// Request HFXO crystal clock for PCLK24M (required by USBHS core)
228+
NRF_CLOCK->TASKS_XO24MSTART = CLOCK_TASKS_XO24MSTART_TASKS_XO24MSTART_Trigger;
229+
while (!NRF_CLOCK->EVENTS_XO24MSTARTED) {}
230+
NRF_CLOCK->EVENTS_XO24MSTARTED = 0;
231+
#endif
232+
189233
// Priorities 0, 1, 4 (nRF52) are reserved for SoftDevice
190234
// 2 is highest for application
191235
NVIC_SetPriority(USBD_IRQn, 2);
192236

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

259303
#if defined(NRF54H20_XXAA)
260304
uintptr_t did_addr = (uintptr_t) NRF_FICR->BLE.ADDR;
261-
#elif defined(NRF5340_XXAA)
305+
#elif defined(NRF54LM20A_ENGA_XXAA) || defined(NRF5340_XXAA)
262306
uintptr_t did_addr = (uintptr_t) NRF_FICR->INFO.DEVICEID;
263307
#else
264308
uintptr_t did_addr = (uintptr_t) NRF_FICR->DEVICEID;
@@ -272,19 +316,29 @@ size_t board_get_unique_id(uint8_t id[], size_t max_len) {
272316
}
273317

274318
int board_uart_read(uint8_t* buf, int len) {
319+
#if CFG_TUSB_OS == OPT_OS_ZEPHYR
275320
(void) buf;
276321
(void) len;
277322
return -1;
278-
// nrfx_err_t err = nrfx_uarte_rx(&_uart_id, buf, (size_t) len);
279-
// return NRFX_SUCCESS == err ? len : 0;
323+
#else
324+
int count = 0;
325+
while (count < len && rx_fifo_tail != rx_fifo_head) {
326+
buf[count++] = rx_fifo[rx_fifo_tail];
327+
rx_fifo_tail = (rx_fifo_tail + 1) & (UART_RX_BUFSIZE - 1);
328+
}
329+
return count;
330+
#endif
280331
}
281332

282333
int board_uart_write(void const* buf, int len) {
283334
#if CFG_TUSB_OS == OPT_OS_ZEPHYR
284335
(void) buf;
285336
return len;
286337
#else
287-
nrfx_err_t err = nrfx_uarte_tx(&_uart_id, (uint8_t const*) buf, (size_t) len ,0);
338+
if (nrfx_uarte_tx_in_progress(&_uart_id)) {
339+
return 0;
340+
}
341+
nrfx_err_t err = nrfx_uarte_tx(&_uart_id, (uint8_t const*) buf, (size_t) len, 0);
288342
return (NRFX_SUCCESS == err) ? len : 0;
289343
#endif
290344
}

0 commit comments

Comments
 (0)