ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
usb_selftest_dfu_steps.c
Go to the documentation of this file.
1
26
28
29#include <stdint.h>
30#include <string.h>
31
32#include "ra8_board_ek_ra8d2.h"
33#include "ra8_err.h"
34#include "ra8_time.h"
35#include "ra8_usb.h"
36
37#ifndef RA8_OFF_TARGET
38
39/* -------------------------------------------------------------------------- */
40/* J-Link probes (host ladder) */
41/* -------------------------------------------------------------------------- */
42
44static volatile uint32_t s_dbg_phase;
46static volatile uint32_t s_dbg_pid;
48static volatile uint32_t s_dbg_blocks_ok;
50static volatile uint32_t s_dbg_mismatch = (uint32_t)k_dfu_no_mismatch;
52static volatile uint32_t s_dbg_pass_count;
53
54/* -------------------------------------------------------------------------- */
55/* Shared per-block pattern */
56/* -------------------------------------------------------------------------- */
57
73static void dfu_pattern_fill(uint32_t block, uint8_t* out, uint32_t len)
74{
75 for (uint32_t i = 0U; i < len; i++) {
76 const uint32_t v = (block * (uint32_t)k_dfu_pat_blk_mul) + (i * (uint32_t)k_dfu_pat_idx_mul) +
77 (uint32_t)k_dfu_pat_bias;
78 out[i] = (uint8_t)(v & (uint32_t)k_dfu_byte_mask);
79 }
80}
81
82/* -------------------------------------------------------------------------- */
83/* Console helpers (SCI8 -> J-Link OB CDC) */
84/* -------------------------------------------------------------------------- */
85
98static uint8_t dfu_nibble_to_hex(uint32_t nibble)
99{
100 if (nibble < k_dfu_hex_digit_split) {
101 return (uint8_t)((uint8_t)'0' + (uint8_t)nibble);
102 }
103 return (uint8_t)((uint8_t)'A' + (uint8_t)nibble - (uint8_t)k_dfu_hex_digit_split);
104}
105
118static uint32_t dfu_str_len(const char* text)
119{
120 uint32_t len = 0U;
121 while (len < (uint32_t)k_dfu_print_cap) {
122 if (text[len] == '\0') {
123 break;
124 }
125 len++;
126 }
127 return len;
128}
129
143[[nodiscard]] static ra8_err_t dfu_sci_write(const uint8_t* data, uint32_t len)
144{
145 return ra8_board_uart_console_write(data, (size_t)len);
146}
147
160[[nodiscard]] static ra8_err_t dfu_print(const char* text)
161{
162 return dfu_sci_write((const uint8_t*)text, dfu_str_len(text));
163}
164
178[[nodiscard]] static ra8_err_t dfu_print_hex(uint32_t value, uint8_t digits)
179{
180 uint8_t out[k_dfu_hex_chars_u32] = {};
181 uint8_t width = digits;
182 if (width > (uint8_t)k_dfu_hex_chars_u32) {
183 width = (uint8_t)k_dfu_hex_chars_u32;
184 }
185 for (uint8_t i = 0U; i < width; i++) {
186 const uint8_t shift = (uint8_t)((width - 1U - i) * k_dfu_nibble_bits);
187 out[i] = dfu_nibble_to_hex((value >> shift) & k_dfu_nibble_mask);
188 }
189 return dfu_sci_write(out, (uint32_t)width);
190}
191
204[[nodiscard]] static ra8_err_t dfu_print_dec(uint32_t value)
205{
206 uint8_t scratch[k_dfu_dec_chars_u32] = {};
207 uint8_t out[k_dfu_dec_chars_u32] = {};
208 uint8_t count = 0U;
209 uint32_t v = value;
210 if (v == 0U) {
211 out[0] = (uint8_t)'0';
212 return dfu_sci_write(out, 1U);
213 }
214 while (v != 0U) {
215 if (count >= (uint8_t)k_dfu_dec_chars_u32) {
216 break;
217 }
218 scratch[count] = (uint8_t)((uint8_t)'0' + (uint8_t)(v % k_dfu_dec_radix));
219 v = v / k_dfu_dec_radix;
220 count++;
221 }
222 for (uint8_t i = 0U; i < count; i++) {
223 out[i] = scratch[count - 1U - i];
224 }
225 return dfu_sci_write(out, (uint32_t)count);
226}
227
241[[nodiscard]] static ra8_err_t dfu_print_fail(const char* what, ra8_err_t err)
242{
243 ra8_err_t e = dfu_print("ra8d2 dfu: FAIL ");
244 if (e != k_ra8_ok) {
245 return e;
246 }
247 e = dfu_print(what);
248 if (e != k_ra8_ok) {
249 return e;
250 }
251 e = dfu_print(" err=0x");
252 if (e != k_ra8_ok) {
253 return e;
254 }
255 e = dfu_print_hex((uint32_t)err, (uint8_t)k_dfu_hex_chars_u32);
256 if (e != k_ra8_ok) {
257 return e;
258 }
259 return dfu_print("\r\n");
260}
261
262/* -------------------------------------------------------------------------- */
263/* Host side: enumerate, then DFU download + upload-verify */
264/* -------------------------------------------------------------------------- */
265
279[[nodiscard]] static ra8_err_t dfu_ctrl_get_dev_desc(uint8_t* desc)
280{
281 const ra8_usb_setup_t setup = {
282 .bm_request_type = (uint8_t)k_dfu_bm_std_dev_in,
283 .b_request = (uint8_t)k_dfu_breq_get_desc,
284 .w_value = (uint16_t)((uint16_t)k_dfu_desc_device << (uint16_t)k_dfu_byte_bits),
285 .w_index = 0U,
286 .w_length = (uint16_t)k_dfu_dev_desc_len,
287 };
288 uint16_t rx = 0U;
289 const ra8_err_t err =
291 if (err != k_ra8_ok) {
292 return err;
293 }
294 return (rx == (uint16_t)k_dfu_dev_desc_len) ? k_ra8_ok : k_ra8_err_hw_error;
295}
296
310[[nodiscard]] static ra8_err_t dfu_enum_hunt(uint8_t* desc)
311{
313 const uint32_t t0 = ra8_time_ms();
314 for (uint32_t spin = 0U; spin < (uint32_t)k_dfu_attach_spin; spin++) {
316 break;
317 }
318 if ((ra8_time_ms() - t0) > (uint32_t)k_dfu_attach_to_ms) {
319 break;
320 }
321 }
324 for (uint8_t attempt = 0U; attempt < (uint8_t)k_dfu_enum_tries; attempt++) {
331 err = dfu_ctrl_get_dev_desc(desc);
332 if (err == k_ra8_ok) {
333 return k_ra8_ok;
334 }
335 }
336 return err;
337}
338
350[[nodiscard]] static ra8_err_t dfu_enum_set_address(void)
351{
352 const ra8_usb_setup_t setup = {
353 .bm_request_type = (uint8_t)k_dfu_bm_std_dev_out,
354 .b_request = (uint8_t)k_dfu_breq_set_addr,
355 .w_value = (uint16_t)k_dfu_dev_addr,
356 .w_index = 0U,
357 .w_length = 0U,
358 };
359 const ra8_err_t err = ra8_usb_host_control_xfer(k_ra8_usb_speed_hs, &setup, nullptr, 0U, nullptr);
360 if (err != k_ra8_ok) {
361 return err;
362 }
365}
366
378[[nodiscard]] static ra8_err_t dfu_enum_set_config(void)
379{
380 const ra8_usb_setup_t setup = {
381 .bm_request_type = (uint8_t)k_dfu_bm_std_dev_out,
382 .b_request = (uint8_t)k_dfu_breq_set_config,
383 .w_value = (uint16_t)k_dfu_config_val,
384 .w_index = 0U,
385 .w_length = 0U,
386 };
387 return ra8_usb_host_control_xfer(k_ra8_usb_speed_hs, &setup, nullptr, 0U, nullptr);
388}
389
403[[nodiscard]] static ra8_err_t dfu_getstatus(uint8_t* out_state)
404{
405 uint8_t status[k_dfu_getstatus_len] = {};
406 const ra8_usb_setup_t setup = {
407 .bm_request_type = (uint8_t)k_dfu_bm_class_if_in,
408 .b_request = (uint8_t)k_dfu_breq_getstatus,
409 .w_value = 0U,
410 .w_index = (uint16_t)k_dfu_intf,
411 .w_length = (uint16_t)k_dfu_getstatus_len,
412 };
413 uint16_t rx = 0U;
415 &setup,
416 status,
417 (uint16_t)k_dfu_getstatus_len,
418 &rx);
419 if (err != k_ra8_ok) {
420 return err;
421 }
422 if (rx != (uint16_t)k_dfu_getstatus_len) {
423 return k_ra8_err_hw_error;
424 }
425 *out_state = status[k_dfu_off_status_state];
426 return k_ra8_ok;
427}
428
442[[nodiscard]] static ra8_err_t dfu_wait_state(uint8_t want_state)
443{
444 for (uint32_t i = 0U; i < (uint32_t)k_dfu_status_tries; i++) {
445 uint8_t state = 0U;
446 const ra8_err_t err = dfu_getstatus(&state);
447 if (err != k_ra8_ok) {
448 return err;
449 }
450 if (state == want_state) {
451 return k_ra8_ok;
452 }
454 }
456}
457
472[[nodiscard]] static ra8_err_t dfu_dnload_block(uint16_t block, uint8_t* data, uint16_t len)
473{
474 const ra8_usb_setup_t setup = {
475 .bm_request_type = (uint8_t)k_dfu_bm_class_if_out,
476 .b_request = (uint8_t)k_dfu_breq_dnload,
477 .w_value = block,
478 .w_index = (uint16_t)k_dfu_intf,
479 .w_length = len,
480 };
481 const ra8_err_t err = ra8_usb_host_control_xfer(k_ra8_usb_speed_hs, &setup, data, len, nullptr);
482 if (err != k_ra8_ok) {
483 return err;
484 }
486}
487
505[[nodiscard]] static ra8_err_t dfu_download_all(void)
506{
507 for (uint16_t b = 0U; b < (uint16_t)k_dfu_blocks; b++) {
508 uint8_t block[k_dfu_xfer_size] = {};
509 dfu_pattern_fill((uint32_t)b, block, (uint32_t)k_dfu_xfer_size);
510 const ra8_err_t err = dfu_dnload_block(b, block, (uint16_t)k_dfu_xfer_size);
511 if (err != k_ra8_ok) {
512 return err;
513 }
514 }
515 /* DFU_ABORT closes the download (dfuDNLOAD-IDLE -> dfuIDLE) without the
516 * manifest's wait-for-reset, so the UPLOAD phase runs on the same device. */
517 const ra8_usb_setup_t setup = {
518 .bm_request_type = (uint8_t)k_dfu_bm_class_if_out,
519 .b_request = (uint8_t)k_dfu_breq_abort,
520 .w_value = 0U,
521 .w_index = (uint16_t)k_dfu_intf,
522 .w_length = 0U,
523 };
524 const ra8_err_t err = ra8_usb_host_control_xfer(k_ra8_usb_speed_hs, &setup, nullptr, 0U, nullptr);
525 if (err != k_ra8_ok) {
526 return err;
527 }
528 return dfu_wait_state((uint8_t)k_dfu_state_idle);
529}
530
545[[nodiscard]] static ra8_err_t dfu_upload_verify(void)
546{
547 s_dbg_blocks_ok = 0U;
548 for (uint16_t b = 0U; b < (uint16_t)k_dfu_blocks; b++) {
549 uint8_t got[k_dfu_xfer_size] = {};
550 const ra8_usb_setup_t setup = {
551 .bm_request_type = (uint8_t)k_dfu_bm_class_if_in,
552 .b_request = (uint8_t)k_dfu_breq_upload,
553 .w_value = b,
554 .w_index = (uint16_t)k_dfu_intf,
555 .w_length = (uint16_t)k_dfu_xfer_size,
556 };
557 uint16_t rx = 0U;
558 const ra8_err_t err =
560 if (err != k_ra8_ok) {
561 return err;
562 }
563 if (rx != (uint16_t)k_dfu_xfer_size) {
564 s_dbg_mismatch = (uint32_t)b;
566 }
567 uint8_t want[k_dfu_xfer_size] = {};
568 dfu_pattern_fill((uint32_t)b, want, (uint32_t)k_dfu_xfer_size);
569 if (memcmp(got, want, (size_t)k_dfu_xfer_size) != 0) {
570 s_dbg_mismatch = (uint32_t)b;
572 }
574 }
575 return k_ra8_ok;
576}
577
595[[nodiscard]] static ra8_err_t dfu_host_enumerate(void)
596{
597 s_dbg_phase = (uint32_t)k_dfu_phase_enum;
598 uint8_t desc[k_dfu_dev_desc_len] = {};
599 ra8_err_t err = dfu_enum_hunt(desc);
600 if (err != k_ra8_ok) {
601 (void)dfu_print_fail("enumerate", err);
603 return err;
604 }
605 s_dbg_pid = (uint32_t)desc[k_dfu_off_dev_pid] |
606 ((uint32_t)desc[(uint32_t)k_dfu_off_dev_pid + 1U] << (uint32_t)k_dfu_byte_bits);
607 err = dfu_enum_set_address();
608 if (err != k_ra8_ok) {
609 (void)dfu_print_fail("set_address", err);
611 return err;
612 }
613 err = dfu_enum_set_config();
614 if (err != k_ra8_ok) {
615 (void)dfu_print_fail("set_config", err);
617 return err;
618 }
619 err = dfu_print("ra8d2 dfu: enumerated pid=0x");
620 if (err == k_ra8_ok) {
622 }
623 if (err == k_ra8_ok) {
624 err = dfu_print("\r\n");
625 }
626 return err;
627}
628
629[[nodiscard]] ra8_err_t dfu_host_pass(void)
630{
631 s_dbg_phase = (uint32_t)k_dfu_phase_init;
632 ra8_err_t err = dfu_print("ra8d2 dfu: host up on USB-HS, probing the loop...\r\n");
633 if (err != k_ra8_ok) {
634 return err;
635 }
637 if (err != k_ra8_ok) {
638 (void)dfu_print_fail("host init", err);
639 return err;
640 }
641
642 err = dfu_host_enumerate();
643 if (err != k_ra8_ok) {
644 return err;
645 }
646
648 err = dfu_download_all();
649 if (err != k_ra8_ok) {
650 (void)dfu_print_fail("dnload", err);
652 return err;
653 }
654
656 err = dfu_upload_verify();
657 if (err != k_ra8_ok) {
658 (void)dfu_print_fail("upload verify", err);
660 return err;
661 }
662
663 s_dbg_phase = (uint32_t)k_dfu_phase_pass;
665 err = dfu_print("ra8d2 dfu: ");
666 if (err == k_ra8_ok) {
667 err = dfu_print_dec((uint32_t)k_dfu_blocks);
668 }
669 if (err == k_ra8_ok) {
670 err = dfu_print(" blocks downloaded + verified -- USB SELFTEST DFU PASS\r\n");
671 }
672 if (err != k_ra8_ok) {
673 return err;
674 }
676 return k_ra8_ok;
677}
678
679#endif /* !RA8_OFF_TARGET */
@ k_dfu_print_cap
Bound for console-string scans.
Definition main.c:128
@ k_dfu_breq_dnload
DFU_DNLOAD.
Definition main.c:553
@ k_dfu_breq_getstatus
DFU_GETSTATUS.
Definition main.c:555
@ k_dfu_breq_get_desc
GET_DESCRIPTOR.
Definition main.c:550
@ k_dfu_byte_bits
Bits per byte.
Definition main.c:560
@ k_dfu_bm_std_dev_in
bmRequestType: Std | Device | In.
Definition main.c:546
@ k_dfu_getstatus_len
DFU_GETSTATUS payload len.
Definition main.c:561
@ k_dfu_breq_set_config
SET_CONFIGURATION.
Definition main.c:552
@ k_dfu_breq_set_addr
SET_ADDRESS.
Definition main.c:551
@ k_dfu_desc_device
DEVICE descriptor type.
Definition main.c:557
@ k_dfu_off_dev_pid
idProduct LSB byte offset.
Definition main.c:559
@ k_dfu_state_dnload_idle
dfuDNLOAD-IDLE.
Definition main.c:563
@ k_dfu_bm_class_if_in
bmRequestType: Class | Interface | In.
Definition main.c:549
@ k_dfu_breq_abort
DFU_ABORT (-> dfuIDLE).
Definition main.c:556
@ k_dfu_dev_desc_len
DEVICE descriptor length.
Definition main.c:558
@ k_dfu_breq_upload
DFU_UPLOAD.
Definition main.c:554
@ k_dfu_bm_class_if_out
bmRequestType: Class | Interface | Out.
Definition main.c:548
@ k_dfu_state_idle
dfuIDLE.
Definition main.c:564
@ k_dfu_bm_std_dev_out
bmRequestType: Std | Device | Out.
Definition main.c:547
@ k_dfu_off_status_state
bState offset in GETSTATUS.
Definition main.c:562
@ k_dfu_reset_hold_ms
USB bus-reset hold (>=10 ms).
Definition main.c:575
@ k_dfu_attach_to_ms
Wait for the D+ pull-up.
Definition main.c:573
@ k_dfu_enum_tries
Reset+probe attempts.
Definition main.c:580
@ k_dfu_attach_spin
Attach spin cap (frozen-tick guard).
Definition main.c:581
@ k_dfu_recovery_ms
Post-reset recovery (TRSTRCY).
Definition main.c:576
@ k_dfu_status_poll_ms
Pause between GETSTATUS polls.
Definition main.c:578
@ k_dfu_addr_settle_ms
Post-SET_ADDRESS recovery.
Definition main.c:577
@ k_dfu_vbus_settle_ms
VBUS settle before probing.
Definition main.c:572
@ k_dfu_debounce_ms
Post-attach debounce (>=100 ms).
Definition main.c:574
@ k_dfu_status_tries
GETSTATUS polls before giving up.
Definition main.c:579
static volatile uint32_t s_dbg_pid
Device-reported product id captured at enumeration.
Definition main.c:208
@ k_dfu_phase_init
Host controller init.
Definition main.c:158
@ k_dfu_phase_pass
Image verified byte-equal.
Definition main.c:162
@ k_dfu_phase_upload
Running DFU_UPLOAD.
Definition main.c:161
@ k_dfu_phase_download
Running DFU_DNLOAD.
Definition main.c:160
@ k_dfu_phase_enum
Enumerating.
Definition main.c:159
@ k_dfu_hex_chars_u32
32-bit value -> "ABCDEF01".
Definition main.c:139
@ k_dfu_hex_digit_split
Threshold between '0-9'/'A-F'.
Definition main.c:141
@ k_dfu_nibble_bits
Bits per hex nibble.
Definition main.c:140
@ k_dfu_nibble_mask
4-bit nibble mask.
Definition main.c:149
static volatile uint32_t s_dbg_blocks_ok
Blocks the host confirmed byte-equal on upload (expect k_dfu_blocks).
Definition main.c:230
@ k_dfu_xfer_size
wTransferSize: bytes per DFU block.
Definition main.c:162
@ k_dfu_byte_mask
Byte mask.
Definition main.c:169
@ k_dfu_dev_addr
Address the host assigns.
Definition main.c:170
@ k_dfu_pat_idx_mul
Per-index pattern multiplier.
Definition main.c:167
@ k_dfu_no_mismatch
Probe: no mismatch.
Definition main.c:165
@ k_dfu_pat_blk_mul
Per-block pattern multiplier.
Definition main.c:166
@ k_dfu_intf
DFU interface number.
Definition main.c:171
@ k_dfu_config_val
bConfigurationValue.
Definition main.c:172
@ k_dfu_pat_bias
Pattern constant bias.
Definition main.c:168
@ k_dfu_blocks
Blocks in the rehearsal image.
Definition main.c:163
@ k_dfu_dec_chars_u32
Max digits for a 32-bit count.
Definition main.c:143
@ k_dfu_hex_chars_u16
16-bit value -> "ABCD".
Definition main.c:141
@ k_dfu_dec_radix
Base for decimal conversion.
Definition main.c:154
Board-support layer for the Renesas EK-RA8D2 v1 evaluation kit.
ra8_err_t ra8_board_led_on(ra8_board_led_id_t led)
Drive led HIGH (light it).
@ k_ra8_board_led2
LED2, GREEN, P303 (jumper E26).
ra8_err_t ra8_board_uart_console_write(const uint8_t *data, size_t len)
Polled blocking write to the J-Link OB VCOM console.
Error Code Definitions for ra8-firmware.
@ k_ra8_err_invalid_state
Module in wrong state for requested operation.
Definition ra8_err.h:161
@ k_ra8_err_hw_timeout
Hardware timed out waiting for a flag or handshake.
Definition ra8_err.h:304
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_hw_error
Generic hardware fault detected (error flag set, fault interrupt).
Definition ra8_err.h:310
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
int memcmp(const void *a, const void *b, size_t n)
Compare bytes in two memory areas.
SysTick-based tick counter, delay and timestamp helpers.
void ra8_delay_ms(uint32_t ms)
Busy-wait for at least ms milliseconds.
Definition ra8_time.c:129
uint32_t ra8_time_ms(void)
Get the current 1 kHz tick count.
Definition ra8_time.c:108
Native USB controller driver public API (device + host modes).
@ k_ra8_usb_speed_hs
High-Speed controller (USBHS @ 0x40351000).
ra8_err_t ra8_usb_host_bus_reset(ra8_usb_speed_t speed, bool assert_reset)
Drive (or release) the bus reset line.
uint16_t ra8_usb_host_line_state(ra8_usb_speed_t speed)
Read the host port's D+/D- line state (SYSSTS0.LNST).
ra8_err_t ra8_usb_host_init(ra8_usb_speed_t speed)
Bring up a USB controller in HOST mode.
ra8_err_t ra8_usb_host_deinit(ra8_usb_speed_t speed)
Tear down a host-mode controller and drop its MSTP reference.
ra8_err_t ra8_usb_host_control_xfer(ra8_usb_speed_t speed, const ra8_usb_setup_t *setup, uint8_t *data, uint16_t data_len, uint16_t *out_received)
Run a complete host control transfer (SETUP, optional DATA, STATUS).
ra8_err_t ra8_usb_host_set_uact(ra8_usb_speed_t speed, bool enable)
Enable / disable SOF (Start-of-Frame) generation on the bus.
ra8_err_t ra8_usb_host_set_target(ra8_usb_speed_t speed, uint8_t dev_addr)
Retarget the host's default control pipe at a device address.
Decoded 8-byte USB SETUP packet.
static void dfu_pattern_fill(uint32_t block, uint8_t *out, uint32_t len)
Fill a firmware block with this block's deterministic bytes.
static ra8_err_t dfu_print_fail(const char *what, ra8_err_t err)
Print "FAIL <what> err=0xNNNNNNNN" on its own line.
static ra8_err_t dfu_wait_state(uint8_t want_state)
Poll DFU_GETSTATUS until the device reports want_state.
static ra8_err_t dfu_host_enumerate(void)
Enumerate the looped-back device: descriptor hunt, address, config.
static ra8_err_t dfu_download_all(void)
Download the whole rehearsal image, then DFU_ABORT back to dfuIDLE.
static ra8_err_t dfu_sci_write(const uint8_t *data, uint32_t len)
Push a literal block over the J-Link OB CDC console (SCI8) polled.
static ra8_err_t dfu_getstatus(uint8_t *out_state)
DFU_GETSTATUS: read the 6-byte status and return the bState field.
static ra8_err_t dfu_dnload_block(uint16_t block, uint8_t *data, uint16_t len)
DFU_DNLOAD one block, then poll to dfuDNLOAD-IDLE.
static ra8_err_t dfu_enum_set_config(void)
SET_CONFIGURATION(::k_dfu_config_val) on the addressed device.
static ra8_err_t dfu_ctrl_get_dev_desc(uint8_t *desc)
GET_DESCRIPTOR(DEVICE) over the polled control engine.
ra8_err_t dfu_host_pass(void)
Run the full host pass: enumerate, download, upload-verify.
static ra8_err_t dfu_enum_set_address(void)
SET_ADDRESS to k_dfu_dev_addr, then retarget the DCP.
static uint8_t dfu_nibble_to_hex(uint32_t nibble)
Format one nibble (0..15) into an uppercase hex character.
static ra8_err_t dfu_enum_hunt(uint8_t *desc)
Wait for attach, then bus-reset + read the device descriptor.
static ra8_err_t dfu_print_hex(uint32_t value, uint8_t digits)
Print a value as fixed-width uppercase hex.
static uint32_t dfu_str_len(const char *text)
Bounded ASCII string length (cap k_dfu_print_cap).
static ra8_err_t dfu_print_dec(uint32_t value)
Print a uint32_t as ASCII decimal.
static ra8_err_t dfu_print(const char *text)
Print a NUL-terminated ASCII string over the console.
static ra8_err_t dfu_upload_verify(void)
DFU_UPLOAD the image back block by block and byte-check each.
Shared constants + host-side DFU ladder interface for usb_selftest_dfu.
static volatile uint32_t s_dbg_phase
Host-ladder phase marker (wlun_phase_t).
static volatile uint32_t s_dbg_pass_count
Completed full passes (sticky success counter).
static volatile uint32_t s_dbg_mismatch
First mismatching sector, or k_wlun_no_mismatch.