ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_dfu_host.c
Go to the documentation of this file.
1
17
18#include "ra8_dfu_host.h"
19
20#ifndef RA8_OFF_TARGET
21
22#include <string.h>
23
24#include "ra8_attributes.h"
25#include "ra8_time.h"
26#include "ra8_usb.h"
27
54
69
99{
100 const ra8_usb_setup_t setup = {
101 .bm_request_type = (uint8_t)k_rdh_bm_std_dev_in,
102 .b_request = (uint8_t)k_rdh_breq_get_desc,
103 .w_value = (uint16_t)((uint16_t)k_rdh_desc_device << (uint16_t)k_rdh_byte_bits),
104 .w_index = 0U,
105 .w_length = (uint16_t)k_rdh_dev_desc_len,
106 };
107 uint16_t rx = 0U;
108 const ra8_err_t err =
109 ra8_usb_host_control_xfer(speed, &setup, desc, (uint16_t)k_rdh_dev_desc_len, &rx);
110 if (err != k_ra8_ok) {
111 return err;
112 }
113 return (rx == (uint16_t)k_rdh_dev_desc_len) ? k_ra8_ok : k_ra8_err_hw_error;
114}
115
148{
150 const uint32_t t0 = ra8_time_ms();
151 for (uint32_t spin = 0U; spin < (uint32_t)k_rdh_attach_spin; spin++) {
152 if (ra8_usb_host_line_state(speed) != 0U) {
153 break;
154 }
155 if ((ra8_time_ms() - t0) > (uint32_t)k_rdh_attach_to_ms) {
156 break;
157 }
158 }
161 for (uint8_t attempt = 0U; attempt < (uint8_t)k_rdh_enum_tries; attempt++) {
162 (void)ra8_usb_host_bus_reset(speed, true);
164 (void)ra8_usb_host_bus_reset(speed, false);
165 (void)ra8_usb_host_set_uact(speed, true);
167 (void)ra8_usb_host_set_target(speed, 0U);
168 err = internal_get_dev_desc(speed, desc);
169 if (err == k_ra8_ok) {
170 return k_ra8_ok;
171 }
172 }
173 return err;
174}
175
201{
202 const ra8_usb_setup_t setup = {
203 .bm_request_type = (uint8_t)k_rdh_bm_std_dev_out,
204 .b_request = (uint8_t)k_rdh_breq_set_addr,
205 .w_value = (uint16_t)k_rdh_dev_addr,
206 .w_index = 0U,
207 .w_length = 0U,
208 };
209 const ra8_err_t err = ra8_usb_host_control_xfer(speed, &setup, nullptr, 0U, nullptr);
210 if (err != k_ra8_ok) {
211 return err;
212 }
214 return ra8_usb_host_set_target(speed, (uint8_t)k_rdh_dev_addr);
215}
216
242{
243 const ra8_usb_setup_t setup = {
244 .bm_request_type = (uint8_t)k_rdh_bm_std_dev_out,
245 .b_request = (uint8_t)k_rdh_breq_set_config,
246 .w_value = (uint16_t)k_rdh_config_val,
247 .w_index = 0U,
248 .w_length = 0U,
249 };
250 return ra8_usb_host_control_xfer(speed, &setup, nullptr, 0U, nullptr);
251}
252
281{
282 uint8_t status[k_rdh_getstatus_len] = {};
283 const ra8_usb_setup_t setup = {
284 .bm_request_type = (uint8_t)k_rdh_bm_class_if_in,
285 .b_request = (uint8_t)k_rdh_breq_getstatus,
286 .w_value = 0U,
287 .w_index = (uint16_t)k_rdh_intf,
288 .w_length = (uint16_t)k_rdh_getstatus_len,
289 };
290 uint16_t rx = 0U;
291 const ra8_err_t err =
292 ra8_usb_host_control_xfer(speed, &setup, status, (uint16_t)k_rdh_getstatus_len, &rx);
293 if (err != k_ra8_ok) {
294 return err;
295 }
296 if (rx != (uint16_t)k_rdh_getstatus_len) {
297 return k_ra8_err_hw_error;
298 }
299 *out_state = status[k_rdh_off_status_state];
300 return k_ra8_ok;
301}
302
334{
335 for (uint32_t i = 0U; i < (uint32_t)k_rdh_status_tries; i++) {
336 uint8_t state = 0U;
337 const ra8_err_t err = internal_getstatus(speed, &state);
338 if (err != k_ra8_ok) {
339 return err;
340 }
341 if (state == want_state) {
342 return k_ra8_ok;
343 }
345 }
347}
348
379internal_dnload_block(ra8_usb_speed_t speed, uint16_t block, uint8_t* data, uint16_t len)
380{
381 const ra8_usb_setup_t setup = {
382 .bm_request_type = (uint8_t)k_rdh_bm_class_if_out,
383 .b_request = (uint8_t)k_rdh_breq_dnload,
384 .w_value = block,
385 .w_index = (uint16_t)k_rdh_intf,
386 .w_length = len,
387 };
388 const ra8_err_t err = ra8_usb_host_control_xfer(speed, &setup, data, len, nullptr);
389 if (err != k_ra8_ok) {
390 return err;
391 }
392 return internal_wait_state(speed, (uint8_t)k_rdh_state_dnload_idle);
393}
394
426internal_download_all(ra8_usb_speed_t speed, const uint8_t* img, uint32_t img_len)
427{
428 const uint16_t blocks = (uint16_t)(img_len / (uint32_t)k_rdh_xfer_size);
429 for (uint16_t b = 0U; b < blocks; b++) {
430 uint8_t blk[k_rdh_xfer_size] = {};
431 (void)memcpy(blk, &img[(uint32_t)b * (uint32_t)k_rdh_xfer_size], (size_t)k_rdh_xfer_size);
432 const ra8_err_t err = internal_dnload_block(speed, b, blk, (uint16_t)k_rdh_xfer_size);
433 if (err != k_ra8_ok) {
434 return err;
435 }
436 }
437 /* DFU_ABORT closes the download (dfuDNLOAD-IDLE -> dfuIDLE) without the
438 * manifest's wait-for-reset, so the UPLOAD phase runs on the same device. */
439 const ra8_usb_setup_t setup = {
440 .bm_request_type = (uint8_t)k_rdh_bm_class_if_out,
441 .b_request = (uint8_t)k_rdh_breq_abort,
442 .w_value = 0U,
443 .w_index = (uint16_t)k_rdh_intf,
444 .w_length = 0U,
445 };
446 const ra8_err_t err = ra8_usb_host_control_xfer(speed, &setup, nullptr, 0U, nullptr);
447 if (err != k_ra8_ok) {
448 return err;
449 }
450 return internal_wait_state(speed, (uint8_t)k_rdh_state_idle);
451}
452
486internal_download_manifest(ra8_usb_speed_t speed, const uint8_t* img, uint32_t img_len)
487{
488 const uint16_t blocks = (uint16_t)(img_len / (uint32_t)k_rdh_xfer_size);
489 for (uint16_t b = 0U; b < blocks; b++) {
490 uint8_t blk[k_rdh_xfer_size] = {};
491 (void)memcpy(blk, &img[(uint32_t)b * (uint32_t)k_rdh_xfer_size], (size_t)k_rdh_xfer_size);
492 const ra8_err_t err = internal_dnload_block(speed, b, blk, (uint16_t)k_rdh_xfer_size);
493 if (err != k_ra8_ok) {
494 return err;
495 }
496 }
497 /* Zero-length DFU_DNLOAD = end-of-download: the device commits the slot header
498 * and enters dfuMANIFEST. This is the real flash flow (what dfu-util does),
499 * versus internal_download_all's DFU_ABORT that the self-test round-trip uses
500 * to keep the device enumerable for the UPLOAD comparison. The caller drives
501 * the device half on the same chip, so it polls ::ra8_dfu_device_committed
502 * rather than waiting on a manifest-state GETSTATUS here. */
503 const ra8_usb_setup_t setup = {
504 .bm_request_type = (uint8_t)k_rdh_bm_class_if_out,
505 .b_request = (uint8_t)k_rdh_breq_dnload,
506 .w_value = blocks,
507 .w_index = (uint16_t)k_rdh_intf,
508 .w_length = 0U,
509 };
510 return ra8_usb_host_control_xfer(speed, &setup, nullptr, 0U, nullptr);
511}
512
548 const uint8_t* img,
549 uint32_t img_len,
551{
552 const uint16_t blocks = (uint16_t)(img_len / (uint32_t)k_rdh_xfer_size);
553 out->blocks_ok = 0U;
554 for (uint16_t b = 0U; b < blocks; b++) {
555 uint8_t got[k_rdh_xfer_size] = {};
556 const ra8_usb_setup_t setup = {
557 .bm_request_type = (uint8_t)k_rdh_bm_class_if_in,
558 .b_request = (uint8_t)k_rdh_breq_upload,
559 .w_value = b,
560 .w_index = (uint16_t)k_rdh_intf,
561 .w_length = (uint16_t)k_rdh_xfer_size,
562 };
563 uint16_t rx = 0U;
564 const ra8_err_t err =
565 ra8_usb_host_control_xfer(speed, &setup, got, (uint16_t)k_rdh_xfer_size, &rx);
566 if (err != k_ra8_ok) {
567 return err;
568 }
569 if (rx != (uint16_t)k_rdh_xfer_size) {
570 out->mismatch = (uint32_t)b;
572 }
573 if (memcmp(got, &img[(uint32_t)b * (uint32_t)k_rdh_xfer_size], (size_t)k_rdh_xfer_size) != 0) {
574 out->mismatch = (uint32_t)b;
576 }
577 out->blocks_ok++;
578 }
579 return k_ra8_ok;
580}
581
615 const uint8_t* img,
616 uint32_t img_len,
618{
619 uint8_t desc[k_rdh_dev_desc_len] = {};
620 ra8_err_t err = internal_enum_hunt(speed, desc);
621 if (err != k_ra8_ok) {
622 return err;
623 }
624 out->pid = (uint32_t)desc[k_rdh_off_dev_pid] |
625 ((uint32_t)desc[(uint32_t)k_rdh_off_dev_pid + 1U] << (uint32_t)k_rdh_byte_bits);
626 err = internal_set_address(speed);
627 if (err != k_ra8_ok) {
628 return err;
629 }
630 err = internal_set_config(speed);
631 if (err != k_ra8_ok) {
632 return err;
633 }
634 err = internal_download_all(speed, img, img_len);
635 if (err != k_ra8_ok) {
636 return err;
637 }
638 return internal_upload_verify(speed, img, img_len, out);
639}
640
642 const uint8_t* img,
643 uint32_t img_len,
645{
646 if ((img == nullptr) || (out == nullptr)) {
647 return k_ra8_err_null_ptr;
648 }
649 out->pid = 0U;
650 out->blocks_ok = 0U;
651 out->mismatch = (uint32_t)k_rdh_mismatch_none;
652 out->last_err = k_ra8_ok;
653 if ((img_len == 0U) || ((img_len % (uint32_t)k_rdh_xfer_size) != 0U)) {
656 }
657 ra8_err_t err = ra8_usb_host_init(host_speed);
658 if (err != k_ra8_ok) {
659 out->last_err = err;
660 return err;
661 }
662 err = internal_run_seq(host_speed, img, img_len, out);
663 out->last_err = err;
664 if (err != k_ra8_ok) {
665 (void)ra8_usb_host_deinit(host_speed);
666 }
667 return err;
668}
669
705 const uint8_t* img,
706 uint32_t img_len,
708{
709 uint8_t desc[k_rdh_dev_desc_len] = {};
710 ra8_err_t err = internal_enum_hunt(speed, desc);
711 if (err != k_ra8_ok) {
712 return err;
713 }
714 out->pid = (uint32_t)desc[k_rdh_off_dev_pid] |
715 ((uint32_t)desc[(uint32_t)k_rdh_off_dev_pid + 1U] << (uint32_t)k_rdh_byte_bits);
716 err = internal_set_address(speed);
717 if (err != k_ra8_ok) {
718 return err;
719 }
720 err = internal_set_config(speed);
721 if (err != k_ra8_ok) {
722 return err;
723 }
724 return internal_download_manifest(speed, img, img_len);
725}
726
728 const uint8_t* img,
729 uint32_t img_len,
731{
732 if ((img == nullptr) || (out == nullptr)) {
733 return k_ra8_err_null_ptr;
734 }
735 out->pid = 0U;
736 out->blocks_ok = 0U;
737 out->mismatch = (uint32_t)k_rdh_mismatch_none;
738 out->last_err = k_ra8_ok;
739 if ((img_len == 0U) || ((img_len % (uint32_t)k_rdh_xfer_size) != 0U)) {
742 }
743 ra8_err_t err = ra8_usb_host_init(host_speed);
744 if (err != k_ra8_ok) {
745 out->last_err = err;
746 return err;
747 }
748 err = internal_program_seq(host_speed, img, img_len, out);
749 out->last_err = err;
750 if (err != k_ra8_ok) {
751 (void)ra8_usb_host_deinit(host_speed);
752 }
753 return err;
754}
755
756#endif /* !RA8_OFF_TARGET */
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
static ra8_err_t internal_enum_hunt(ra8_usb_speed_t speed, uint8_t *desc)
Wait for device attach, apply bus reset, and read the DEVICE descriptor.
rdh_tune_t
Timing / retry tunables for the polled enumeration + status polling.
@ k_rdh_mismatch_none
"no mismatch" sentinel.
@ k_rdh_reset_hold_ms
USB bus-reset hold (>=10 ms).
@ k_rdh_attach_spin
Attach spin cap.
@ k_rdh_debounce_ms
Post-attach debounce.
@ k_rdh_vbus_settle_ms
VBUS settle before probing.
@ k_rdh_enum_tries
Reset+probe attempts.
@ k_rdh_status_poll_ms
Pause between GETSTATUS polls.
@ k_rdh_addr_settle_ms
Post-SET_ADDRESS recovery.
@ k_rdh_recovery_ms
Post-reset recovery (TRSTRCY).
@ k_rdh_status_tries
GETSTATUS polls before giving up.
@ k_rdh_attach_to_ms
Wait for the D+ pull-up.
static ra8_err_t internal_upload_verify(ra8_usb_speed_t speed, const uint8_t *img, uint32_t img_len, ra8_dfu_host_result_t *out)
DFU_UPLOAD each block and byte-compare against img.
static ra8_err_t internal_get_dev_desc(ra8_usb_speed_t speed, uint8_t *desc)
Issue GET_DESCRIPTOR(DEVICE) over the polled control engine.
static ra8_err_t internal_set_config(ra8_usb_speed_t speed)
Issue SET_CONFIGURATION(1) on the addressed device.
static ra8_err_t internal_run_seq(ra8_usb_speed_t speed, const uint8_t *img, uint32_t img_len, ra8_dfu_host_result_t *out)
Run the full self-test sequence: enumerate, download, abort, upload-verify.
static ra8_err_t internal_wait_state(ra8_usb_speed_t speed, uint8_t want_state)
Poll DFU_GETSTATUS until the device reaches want_state or the retry cap.
ra8_err_t ra8_dfu_host_run(ra8_usb_speed_t host_speed, const uint8_t *img, uint32_t img_len, ra8_dfu_host_result_t *out)
Enumerate, DFU_DNLOAD img, DFU_ABORT, DFU_UPLOAD, and byte-verify.
static ra8_err_t internal_download_all(ra8_usb_speed_t speed, const uint8_t *img, uint32_t img_len)
Download the entire image in 64-byte blocks, then DFU_ABORT to dfuIDLE.
static ra8_err_t internal_set_address(ra8_usb_speed_t speed)
Issue SET_ADDRESS(1) and retarget the DCP to the new address.
static ra8_err_t internal_program_seq(ra8_usb_speed_t speed, const uint8_t *img, uint32_t img_len, ra8_dfu_host_result_t *out)
Run the real-flash sequence: enumerate, download, then send manifest.
static ra8_err_t internal_download_manifest(ra8_usb_speed_t speed, const uint8_t *img, uint32_t img_len)
Download the entire image in 64-byte blocks, then send a zero-length manifest.
ra8_err_t ra8_dfu_host_program(ra8_usb_speed_t host_speed, const uint8_t *img, uint32_t img_len, ra8_dfu_host_result_t *out)
Enumerate, DFU_DNLOAD img, then a zero-length DFU_DNLOAD (manifest).
static ra8_err_t internal_getstatus(ra8_usb_speed_t speed, uint8_t *out_state)
Issue DFU_GETSTATUS and return the bState byte.
rdh_proto_t
Chapter-9 + DFU class request / descriptor constants.
@ k_rdh_byte_bits
Bits per byte.
@ k_rdh_dev_desc_len
DEVICE descriptor length.
@ k_rdh_off_status_state
bState offset.
@ k_rdh_config_val
bConfigurationValue.
@ k_rdh_desc_device
DEVICE descriptor type.
@ k_rdh_intf
DFU interface number.
@ k_rdh_breq_dnload
DFU_DNLOAD.
@ k_rdh_breq_set_addr
SET_ADDRESS.
@ k_rdh_breq_set_config
SET_CONFIGURATION.
@ k_rdh_bm_class_if_out
Class | Interface | Out.
@ k_rdh_dev_addr
Operating device address.
@ k_rdh_state_idle
dfuIDLE.
@ k_rdh_off_dev_pid
idProduct LSB offset.
@ k_rdh_bm_std_dev_out
Std | Device | Out.
@ k_rdh_bm_std_dev_in
Std | Device | In.
@ k_rdh_getstatus_len
DFU_GETSTATUS payload.
@ k_rdh_breq_abort
DFU_ABORT (-> dfuIDLE).
@ k_rdh_breq_get_desc
GET_DESCRIPTOR.
@ k_rdh_breq_upload
DFU_UPLOAD.
@ k_rdh_xfer_size
wTransferSize per block.
@ k_rdh_breq_getstatus
DFU_GETSTATUS.
@ k_rdh_state_dnload_idle
dfuDNLOAD-IDLE.
@ k_rdh_bm_class_if_in
Class | Interface | In.
static ra8_err_t internal_dnload_block(ra8_usb_speed_t speed, uint16_t block, uint8_t *data, uint16_t len)
Issue DFU_DNLOAD for one block, then poll to dfuDNLOAD-IDLE.
Polled on-board USB-DFU host driver, bound to either controller.
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ 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_null_ptr
Pointer was NULL where a valid pointer was required.
Definition ra8_err.h:478
@ 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.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
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).
ra8_usb_speed_t
Selects which controller instance the call targets.
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.
Outcome of a DFU round-trip for diagnostics / banners.
uint32_t blocks_ok
Upload blocks that byte-matched.
uint32_t mismatch
First differing block, or 0xFFFFFFFF.
uint32_t pid
Enumerated idProduct.
ra8_err_t last_err
First failing step's error, or k_ra8_ok.
Decoded 8-byte USB SETUP packet.