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
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
8485void 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
8892static 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
104108static nrfx_uarte_t _uart_id = NRFX_UARTE_INSTANCE (0 );
105- #endif
109+ #endif
106110
107111void 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.
115148extern 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)
119152TU_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-
135167void 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
274318int 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
282333int 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