ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_pdg.c
Go to the documentation of this file.
1
50
51#include "ra8_pdg.h"
52
53#include <stdint.h>
54
55#include "ra8_attributes.h"
56#include "ra8_check.h"
57#include "ra8_err.h"
58#include "ra8_gpt_regs.h"
59#include "ra8_hw_intrinsics.h"
60#include "ra8_log.h"
61#include "ra8_mstp.h"
62#include "ra8_pdg_regs.h"
63
64static const char* s_tag = "PDG";
65
87
96/* HUM Ch 23.2.1 "Write protection via GPT320.GTWP.WP" p 1154 */
97typedef enum : uint32_t {
101
106/* HUM Ch 23.4.2 "Notes on Delay Settings for PWM Delay Generation Circuit" p 1162 */
111
116/* HUM Ch 23.4.3 "Register Write Interval" p 1163 */
121
126typedef enum : uint32_t {
127 k_ra8_pdg_ns_per_sec = 1000000000UL,
129
154{
155 /* HUM Ch 23.2.1 "GTDLYCR : PWM Output Delay Control Register" p 1154 */
156 const uint16_t cr = ra8_pdg()->GTDLYCR;
157 if ((cr & k_ra8_pdg_gtdlycr_mask_dllen) == 0U) {
158 return false;
159 }
160 if ((cr & k_ra8_pdg_gtdlycr_mask_dlyrst) != 0U) {
161 return false;
162 }
163 return true;
164}
165
174
179static void* s_pdg_event_ctx;
180
201RA8_INTERNAL static void internal_busy_wait_us(uint16_t usec)
202{
203 for (uint16_t u = 0U; u < usec; ++u) {
204 for (uint16_t i = 0U; i < k_ra8_pdg_busy_loops_per_us; ++i) {
205 ra8_hw_nop();
206 }
207 }
208}
209
223{
224 /* HUM Ch 23.3.1 "Adjustments to the Timing of Rising and Falling Edges" p 1159
225 * The fastest GTCLK is 300 MHz, so 5 cycles ~= 17 ns; this loop
226 * absorbs more than that on any reasonable build. */
227 for (uint16_t i = 0U; i < k_ra8_pdg_post_reset_loops; ++i) {
228 ra8_hw_nop();
229 }
230}
231
248{
250 return true;
251 }
253 return true;
254 }
255 return false;
256}
257
278{
279 if (((uint16_t)cfg->channel_mask & ~k_ra8_pdg_channel_mask_all) != 0U) {
281 }
282 if (cfg->auto_tune != 0U) {
283 if (cfg->gptclk_hz == 0U) {
285 }
289 }
290 return k_ra8_ok;
291 }
292 if (!internal_frange_ok(cfg->frange)) {
294 }
295 return k_ra8_ok;
296}
297
307RA8_INTERNAL static inline volatile uint16_t*
309{
310 /* HUM Ch 23.2.3 "GTDLYRnA: GTIOCnA Rising Output Delay Register" p 1156 */
311 /* HUM Ch 23.2.6 "GTDLYFnB: GTIOCnB Falling Output Delay Register" p 1158 */
312 volatile r_pdg_regs_t* reg = ra8_pdg();
313 volatile r_pdg_dly_pair_t* base =
314 (edge == k_ra8_pdg_edge_rising) ? &reg->GTDLYR[channel] : &reg->GTDLYF[channel];
315 return (pin == k_ra8_pdg_pin_a) ? &base->A : &base->B;
316}
317
336internal_validate_slot(uint8_t channel, ra8_pdg_pin_t pin, ra8_pdg_edge_t edge, uint8_t code)
337{
338 if ((uint16_t)channel >= (uint16_t)k_ra8_pdg_channel_count) {
340 }
341 if ((pin != k_ra8_pdg_pin_a) && (pin != k_ra8_pdg_pin_b)) {
343 }
344 if ((edge != k_ra8_pdg_edge_rising) && (edge != k_ra8_pdg_edge_falling)) {
346 }
347 if ((uint16_t)code > k_ra8_pdg_dly_max) {
349 }
350 return k_ra8_ok;
351}
352
368RA8_INTERNAL static uint32_t internal_freq_to_period_ns(uint32_t hz)
369{
370 /* hz > 0 guaranteed by callers. */
371 return k_ra8_pdg_ns_per_sec / hz;
372}
373
374/* =============================================================================
375 * Lifecycle
376 * =============================================================================
377 */
378
401 ra8_pdg_frange_t frange_use)
402{
403 volatile r_pdg_regs_t* reg = ra8_pdg();
404
405 /* Step 1 of Figure 23.2 (p 1160): DLLEN=0, DLYRST=1, DLYBSn=0,
406 * FRANGE=user-supplied band. Performed in one 16-bit write so the
407 * intermediate state is never visible. */
408 /* HUM Ch 23.2.1 "GTDLYCR: PWM Output Delay Control Register" p 1154 */
409 const uint16_t frange_bits =
410 (uint16_t)((uint16_t)frange_use << (uint16_t)k_ra8_pdg_gtdlycr_shift_frange);
411 reg->GTDLYCR = (uint16_t)(k_ra8_pdg_gtdlycr_mask_dlyrst | frange_bits);
412 /* HUM Ch 23.2.2 "GTDLYCR2: PWM Output Delay Control Register 2" p 1155 */
413 reg->GTDLYCR2 = 0U;
414
415 /* Step 2: enable the DLL. */
416 /* HUM Ch 23.2.1 "GTDLYCR" p 1154 */
417 reg->GTDLYCR =
419
420 /* Step 3: wait >= 20 us for the DLL to lock. */
421 /* HUM Ch 23.3.1 "Adjustments to the Timing of Rising and Falling Edges" p 1159 */
423
424 /* Step 4: release the PDG from reset. */
425 /* HUM Ch 23.2.1 "GTDLYCR" p 1154 */
426 reg->GTDLYCR = (uint16_t)(k_ra8_pdg_gtdlycr_mask_dllen | frange_bits);
427
428 /* Step 5: wait >= 5 GTCLK cycles. */
430
431 /* Step 6: turn off bypass for the channels actually in use. */
432 /* HUM Ch 23.2.2 "GTDLYCR2" p 1155 */
433 const uint16_t bypass_off =
434 (uint16_t)((uint16_t)cfg->channel_mask << (uint16_t)k_ra8_pdg_gtdlycr2_shift_dlybs);
435 reg->GTDLYCR2 = bypass_off;
436}
437
439{
440 RA8_CHECK_NULL_PTR(cfg, s_tag, "cfg must not be nullptr");
441 const ra8_err_t cfg_err = internal_validate_cfg(cfg);
442 RA8_RETURN_ON_ERROR(cfg_err, s_tag, "pdg_init: cfg invalid");
443
444 ra8_pdg_frange_t frange_use = cfg->frange;
445 if (cfg->auto_tune != 0U) {
446 const ra8_err_t band_err = ra8_pdg_pick_frange(cfg->gptclk_hz, &frange_use);
447 /* GCOVR_EXCL_BR_START -- ra8_pdg_pick_frange() error edge; the auto-tune inputs are in range */
448 RA8_RETURN_ON_ERROR(band_err, s_tag, "pdg_init: auto-tune failed");
449 /* GCOVR_EXCL_BR_STOP */
450 }
451
452 /* HUM Ch 11.2.9 "MSTPCRD: Module Stop Control Register D" p 449 */
454 /* GCOVR_EXCL_BR_START -- MSTP HW readback */
455 RA8_RETURN_ON_ERROR(mst_err, s_tag, "pdg_init: mstp enable");
456 /* GCOVR_EXCL_BR_STOP */
457
458 internal_program_dll(cfg, frange_use);
459
460 ra8_log_info(s_tag, "pdg_init");
461 return k_ra8_ok;
462}
463
465{
466 volatile r_pdg_regs_t* reg = ra8_pdg();
467 /* Park the block: DLLEN=0, DLYRST=1, FRANGE=0. */
468 /* HUM Ch 23.2.1 "GTDLYCR" p 1154 */
470 /* HUM Ch 23.2.2 "GTDLYCR2" p 1155 */
471 reg->GTDLYCR2 = 0U;
472
473 /* Wipe every per-edge delay cell back to the post-reset value of 0. */
474 /* HUM Ch 23.2.3 "GTDLYRnA" p 1156 */
475 for (uint8_t ch = 0U; ch < k_ra8_pdg_channel_count; ++ch) {
476 reg->GTDLYR[ch].A = 0U;
477 reg->GTDLYR[ch].B = 0U;
478 /* HUM Ch 23.2.4 "GTDLYFnA" p 1156 */
479 reg->GTDLYF[ch].A = 0U;
480 reg->GTDLYF[ch].B = 0U;
481 }
482
483 /* PDG bit MSTPD6, see HUM Ch 23.4.1 p 1162. */
484 /* HUM Ch 11.2.9 "MSTPCRD: Module Stop Control Register D" p 449 */
486 return k_ra8_ok;
487}
488
489/* =============================================================================
490 * Per-edge delay programming
491 * =============================================================================
492 */
493
494ra8_err_t ra8_pdg_set_delay(uint8_t channel, ra8_pdg_pin_t pin, ra8_pdg_edge_t edge, uint8_t code)
495{
498 }
499 const ra8_err_t v = internal_validate_slot(channel, pin, edge, code);
500 RA8_RETURN_ON_ERROR(v, s_tag, "set_delay: bad input");
501
502 /* HUM Ch 23.2.3 "GTDLYRnA: GTIOCnA Rising Output Delay Register" p 1156 */
503 /* HUM Ch 23.2.4 "GTDLYFnA: GTIOCnA Falling Output Delay Register" p 1156 */
504 /* HUM Ch 23.2.5 "GTDLYRnB: GTIOCnB Rising Output Delay Register" p 1157 */
505 /* HUM Ch 23.2.6 "GTDLYFnB: GTIOCnB Falling Output Delay Register" p 1158 */
506 volatile uint16_t* cell = internal_dly_cell(channel, pin, edge);
507 *cell = (uint16_t)((uint16_t)code & k_ra8_pdg_dly_mask);
508 return k_ra8_ok;
509}
510
512ra8_pdg_get_delay(uint8_t channel, ra8_pdg_pin_t pin, ra8_pdg_edge_t edge, uint8_t* out_code)
513{
514 RA8_CHECK_NULL_PTR(out_code, s_tag, "out_code must not be nullptr");
515 const ra8_err_t v = internal_validate_slot(channel, pin, edge, 0U);
516 RA8_RETURN_ON_ERROR(v, s_tag, "get_delay: bad input");
517
518 /* HUM Ch 23.2.3 "GTDLYRnA" p 1156 */
519 /* HUM Ch 23.2.5 "GTDLYRnB" p 1157 */
520 volatile const uint16_t* cell = internal_dly_cell(channel, pin, edge);
521 *out_code = (uint8_t)(*cell & k_ra8_pdg_dly_mask);
522 return k_ra8_ok;
523}
524
526{
527 RA8_CHECK_NULL_PTR(entries, s_tag, "entries must not be nullptr");
530 }
531 if ((count == 0U) || (count > k_ra8_pdg_slot_count)) {
533 }
534 /* Pre-validate every entry so a partial batch is impossible. */
535 for (uint8_t i = 0U; i < count; ++i) {
536 const ra8_err_t v =
537 internal_validate_slot(entries[i].channel, entries[i].pin, entries[i].edge, entries[i].code);
538 if (v != k_ra8_ok) {
539 return v;
540 }
541 }
542 /* HUM Ch 23.3.2 "Timing for Transfer of GTDLYRnA, GTDLYRnB, GTDLYFnA, GTDLYFnB
543 * Register Settings" p 1161 -- temp-register transfer happens at next
544 * overflow / underflow / trough; writing all entries back-to-back keeps the
545 * batch coherent. */
546 for (uint8_t i = 0U; i < count; ++i) {
547 volatile uint16_t* cell =
548 internal_dly_cell(entries[i].channel, entries[i].pin, entries[i].edge);
549 *cell = (uint16_t)((uint16_t)entries[i].code & k_ra8_pdg_dly_mask);
550 }
551 return k_ra8_ok;
552}
553
555 uint32_t gptclk_hz,
556 ra8_pdg_frange_t frange,
557 uint8_t* out_code)
558{
559 RA8_CHECK_NULL_PTR(out_code, s_tag, "out_code must not be nullptr");
560 if (gptclk_hz == 0U) {
562 }
563 if (!internal_frange_ok(frange)) {
565 }
566 /* HUM Ch 23.2.3 "GTDLYRnA: GTIOCnA Rising Output Delay Register" p 1156
567 * code = round(delay_ns / (period_ns / divider))
568 * = round(delay_ns * divider / period_ns)
569 * = round(delay_ns * divider * gptclk_hz / 1e9) */
570 const uint32_t divider = (frange == k_ra8_pdg_frange_80_160_mhz)
571 ? (uint32_t)k_ra8_pdg_dly_div_low
572 : (uint32_t)k_ra8_pdg_dly_div_high;
573 /* Use 64-bit arithmetic to avoid overflow. */
574 const uint64_t numer = (uint64_t)delay_ns * (uint64_t)divider * (uint64_t)gptclk_hz;
575 const uint64_t half = (uint64_t)k_ra8_pdg_ns_per_sec / 2U;
576 uint64_t code = (numer + half) / (uint64_t)k_ra8_pdg_ns_per_sec;
577 if (code > (uint64_t)k_ra8_pdg_dly_max) {
578 code = (uint64_t)k_ra8_pdg_dly_max;
579 }
580 *out_code = (uint8_t)code;
581 return k_ra8_ok;
582}
583
584/* =============================================================================
585 * Per-channel and per-pin power transition
586 * =============================================================================
587 */
588
590{
591 if ((uint16_t)channel >= (uint16_t)k_ra8_pdg_channel_count) {
593 }
594 /* HUM Ch 23.2.2 "GTDLYCR2: PWM Output Delay Control Register 2" p 1155
595 * (DLYENn polarity is inverted: 0 = enabled, 1 = disabled). */
596 volatile r_pdg_regs_t* reg = ra8_pdg();
597 const uint16_t bit =
598 (uint16_t)(1U << ((uint16_t)k_ra8_pdg_gtdlycr2_shift_dlyen + (uint16_t)channel));
599 reg->GTDLYCR2 = (uint16_t)(reg->GTDLYCR2 & (uint16_t)~bit);
600 return k_ra8_ok;
601}
602
604{
605 if ((uint16_t)channel >= (uint16_t)k_ra8_pdg_channel_count) {
607 }
608 /* HUM Ch 23.2.2 "GTDLYCR2" p 1155 */
609 volatile r_pdg_regs_t* reg = ra8_pdg();
610 const uint16_t bit =
611 (uint16_t)(1U << ((uint16_t)k_ra8_pdg_gtdlycr2_shift_dlyen + (uint16_t)channel));
612 reg->GTDLYCR2 = (uint16_t)(reg->GTDLYCR2 | bit);
613 return k_ra8_ok;
614}
615
616ra8_err_t ra8_pdg_channel_bypass_set(uint8_t channel, uint8_t bypass)
617{
620 }
621 if ((uint16_t)channel >= (uint16_t)k_ra8_pdg_channel_count) {
623 }
624 /* DLYBSn = 1 means delay applied (bypass off). */
625 /* HUM Ch 23.2.2 "GTDLYCR2: PWM Output Delay Control Register 2" p 1155 */
626 volatile r_pdg_regs_t* reg = ra8_pdg();
627 const uint16_t bit =
628 (uint16_t)(1U << ((uint16_t)k_ra8_pdg_gtdlycr2_shift_dlybs + (uint16_t)channel));
629 if (bypass != 0U) {
630 reg->GTDLYCR2 = (uint16_t)(reg->GTDLYCR2 | bit);
631 } else {
632 reg->GTDLYCR2 = (uint16_t)(reg->GTDLYCR2 & (uint16_t)~bit);
633 }
634 return k_ra8_ok;
635}
636
638{
641 }
642 if ((uint16_t)channel >= (uint16_t)k_ra8_pdg_channel_count) {
644 }
645 if ((pin != k_ra8_pdg_pin_a) && (pin != k_ra8_pdg_pin_b)) {
647 }
648 /* HUM Ch 23.2.3 "GTDLYRnA" p 1156 + HUM Ch 23.2.4 "GTDLYFnA" p 1156 --
649 * code 0x00 means "delay not applied" so writing 0 to both
650 * rising and falling cells effectively disables the pin. */
651 volatile uint16_t* cell_rise = internal_dly_cell(channel, pin, k_ra8_pdg_edge_rising);
652 volatile uint16_t* cell_fall = internal_dly_cell(channel, pin, k_ra8_pdg_edge_falling);
653 *cell_rise = 0U;
654 *cell_fall = 0U;
655 return k_ra8_ok;
656}
657
658/* =============================================================================
659 * Status / IRQ
660 * =============================================================================
661 */
662
664{
665 RA8_CHECK_NULL_PTR(out, s_tag, "out must not be nullptr");
666 /* HUM Ch 23.2.1 "GTDLYCR" p 1154 */
667 volatile const r_pdg_regs_t* reg = ra8_pdg();
668 *out = reg->GTDLYCR;
669 return k_ra8_ok;
670}
671
673{
674 RA8_CHECK_NULL_PTR(out, s_tag, "out must not be nullptr");
675 /* HUM Ch 23.2.1 "GTDLYCR" p 1154 */
676 volatile const r_pdg_regs_t* reg = ra8_pdg();
677 const uint16_t cr = reg->GTDLYCR;
678 /* HUM Ch 23.2.2 "GTDLYCR2" p 1155 */
679 const uint16_t cr2 = reg->GTDLYCR2;
680 out->raw_gtdlycr = cr;
681 out->raw_gtdlycr2 = cr2;
682 out->dll_enabled = (uint8_t)((cr & k_ra8_pdg_gtdlycr_mask_dllen) != 0U);
683 out->in_reset = (uint8_t)((cr & k_ra8_pdg_gtdlycr_mask_dlyrst) != 0U);
686 for (uint8_t ch = 0U; ch < k_ra8_pdg_channel_count; ++ch) {
687 const uint16_t bs_bit = (uint16_t)(1U << ((uint16_t)k_ra8_pdg_gtdlycr2_shift_dlybs + ch));
688 const uint16_t en_bit = (uint16_t)(1U << ((uint16_t)k_ra8_pdg_gtdlycr2_shift_dlyen + ch));
689 out->per_channel_bypass_off[ch] = (uint8_t)((cr2 & bs_bit) != 0U);
690 /* DLYENn is inverted: 0 = powered, 1 = power-off. */
691 out->per_channel_powered[ch] = (uint8_t)((cr2 & en_bit) == 0U);
692 }
693 return k_ra8_ok;
694}
695
697{
698 /* Clearing DLYRST releases the block. */
699 /* HUM Ch 23.2.1 "GTDLYCR: PWM Output Delay Control Register" p 1154 */
700 volatile r_pdg_regs_t* reg = ra8_pdg();
701 if ((mask & k_ra8_pdg_status_in_reset) != 0U) {
702 reg->GTDLYCR = (uint16_t)(reg->GTDLYCR & (uint16_t)~k_ra8_pdg_gtdlycr_mask_dlyrst);
703 }
704 return k_ra8_ok;
705}
706
708{
709 s_pdg_event_fn = fn;
710 s_pdg_event_ctx = ctx;
711 return k_ra8_ok;
712}
713
716{
718 void* const ctx = s_pdg_event_ctx;
719 if (fn != nullptr) {
720 fn(ctx);
721 }
722}
723
724/* =============================================================================
725 * Sweep 17: capture-style buffered delay-code apply + completion callback
726 * =============================================================================
727 */
728
737
739{
740 RA8_CHECK_NULL_PTR(buf, s_tag, "buf must not be nullptr");
741 if (len == 0U) {
743 }
744 const ra8_err_t batch_err = ra8_pdg_set_delay_batch(buf, len);
745 if (batch_err != k_ra8_ok) {
746 return batch_err;
747 }
751 return k_ra8_ok;
752}
753
755{
757 return k_ra8_ok;
758}
759
760/* =============================================================================
761 * Runtime FRANGE switch + auto-tune calibration
762 * =============================================================================
763 */
764
766{
767 RA8_CHECK_NULL_PTR(out, s_tag, "out must not be nullptr");
768 if (gptclk_hz == 0U) {
770 }
771 if (gptclk_hz < k_ra8_pdg_freq_low_min_hz) {
773 }
774 if (gptclk_hz > k_ra8_pdg_freq_high_max_hz) {
776 }
777 /* HUM Ch 23.2.1 "GTDLYCR" p 1154 -- prefer the low band in the
778 * 155..160 MHz overlap because it gives 1/128 (finer) resolution. */
779 if (gptclk_hz <= k_ra8_pdg_freq_overlap_top) {
781 } else {
783 }
784 return k_ra8_ok;
785}
786
788{
791 }
792 if (!internal_frange_ok(new_frange)) {
794 }
795
796 volatile r_pdg_regs_t* reg = ra8_pdg();
797 /* Preserve the per-channel state across the FRANGE switch. */
798 /* HUM Ch 23.2.2 "GTDLYCR2: PWM Output Delay Control Register 2" p 1155 */
799 const uint16_t saved_cr2 = reg->GTDLYCR2;
800
801 /* "Set the FRANGE[1:0] bits only when the DLLEN bit is 0." So drop
802 * DLLEN and assert DLYRST first. */
803 /* HUM Ch 23.2.1 "GTDLYCR: PWM Output Delay Control Register" p 1154 */
805
806 /* Park GTDLYCR2 (Step 1 of Figure 23.2 also sets DLYBSn = 0). */
807 /* HUM Ch 23.2.2 "GTDLYCR2" p 1155 */
808 reg->GTDLYCR2 = 0U;
809
810 const uint16_t frange_bits =
811 (uint16_t)((uint16_t)new_frange << (uint16_t)k_ra8_pdg_gtdlycr_shift_frange);
812 /* Write FRANGE while DLLEN is still 0. */
813 /* HUM Ch 23.2.1 "GTDLYCR" p 1154 */
814 reg->GTDLYCR = (uint16_t)(k_ra8_pdg_gtdlycr_mask_dlyrst | frange_bits);
815
816 /* Re-run Steps 2..5 of HUM Figure 23.2 (p 1160). Enable DLL: */
817 /* HUM Ch 23.2.1 "GTDLYCR" p 1154 */
818 reg->GTDLYCR =
820 /* 20 us DLL lock wait per HUM Figure 23.2. */
821 /* HUM Ch 23.3.1 "Adjustments to the Timing of Rising and Falling Edges" p 1159 */
823 /* Release reset. */
824 /* HUM Ch 23.2.1 "GTDLYCR" p 1154 */
825 reg->GTDLYCR = (uint16_t)(k_ra8_pdg_gtdlycr_mask_dllen | frange_bits);
827
828 /* Restore the per-channel state. */
829 /* HUM Ch 23.2.2 "GTDLYCR2" p 1155 */
830 reg->GTDLYCR2 = saved_cr2;
831 return k_ra8_ok;
832}
833
834/* =============================================================================
835 * GPT0/1/2/3 binding helpers
836 * =============================================================================
837 */
838
840{
843 }
844 if ((uint16_t)channel >= (uint16_t)k_ra8_pdg_channel_count) {
846 }
847 /* HUM Ch 23.2.3 "GTDLYRnA" p 1156 -- "GTDLYRnA can be written when
848 * register write protection is disabled (GPT32n.GTWP.WP = 0)." */
849 volatile r_gpt_channel_regs_t* gpt = ra8_gpt(channel);
850 if (gpt == nullptr) {
852 }
854 /* HUM Ch 23.2.1 "GTDLYCR" p 1154 -- "be sure to read back the value of GTWP
855 * before changing GTDLYCR". The dummy read enforces ordering. */
856 (void)gpt->GTWP;
857 return k_ra8_ok;
858}
859
861{
862 if ((uint16_t)channel >= (uint16_t)k_ra8_pdg_channel_count) {
864 }
865 /* Restore write-protect on the host GPT channel. */
866 /* HUM Ch 23.2.3 "GTDLYRnA: GTIOCnA Rising Output Delay Register" p 1156 */
867 volatile r_gpt_channel_regs_t* gpt = ra8_gpt(channel);
868 if (gpt == nullptr) {
870 }
872 (void)gpt->GTWP;
873 return k_ra8_ok;
874}
875
876/* =============================================================================
877 * Constraint validation (HUM Ch 23.4.2 / 23.4.3)
878 * =============================================================================
879 */
880
883 uint32_t compare_match,
884 uint32_t gtpr)
885{
886 if ((mode != k_ra8_pdg_wave_saw) && (mode != k_ra8_pdg_wave_triangle)) {
888 }
889 if ((dir != k_ra8_pdg_dir_up) && (dir != k_ra8_pdg_dir_down)) {
891 }
892 /* HUM Ch 23.4.2 "Notes on Delay Settings for PWM Delay Generation Circuit" p 1162 */
893 if (mode == k_ra8_pdg_wave_saw) {
894 if (dir == k_ra8_pdg_dir_up) {
895 /* "Saw-wave Up: GTPR - 2 or above" -- compare_match must be < gtpr - 2. */
897 /* gtpr is too small to even compute the boundary safely. */
899 }
900 const uint32_t boundary = gtpr - k_ra8_pdg_constraint_high_pad;
901 if (compare_match >= boundary) {
903 }
904 } else {
905 /* "Saw-wave Down: <= 2". */
906 if (compare_match <= k_ra8_pdg_constraint_low_thresh) {
908 }
909 }
910 } else {
911 /* "Triangle-wave Down: <= 2". Up direction has no constraint per Table 23.4. */
912 if (dir == k_ra8_pdg_dir_down) {
913 if (compare_match <= k_ra8_pdg_constraint_low_thresh) {
915 }
916 }
917 }
918 return k_ra8_ok;
919}
920
921ra8_err_t ra8_pdg_required_write_ns(uint32_t pclka_hz, uint32_t gptclk_hz, uint32_t* out_ns)
922{
923 RA8_CHECK_NULL_PTR(out_ns, s_tag, "out_ns must not be nullptr");
924 if ((pclka_hz == 0U) || (gptclk_hz == 0U)) {
926 }
927 /* HUM Ch 23.4.3 "Register Write Interval" p 1163:
928 * Write_Interval = Period_of_PCLKA x 6 + Period_of_GPTCLK x 4 */
929 const uint32_t per_pclka = internal_freq_to_period_ns(pclka_hz);
930 const uint32_t per_gptclk = internal_freq_to_period_ns(gptclk_hz);
931 *out_ns = (per_pclka * k_ra8_pdg_pclka_mult) + (per_gptclk * k_ra8_pdg_gptclk_mult);
932 return k_ra8_ok;
933}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_HW_REGISTER_ACCESS
Mark an MMIO accessor function (returns volatile register pointer).
#define RA8_ISR_SAFE
The function is callable from interrupt context.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
ra8_board_eth_pin_t pin
Pin.
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_RETURN_ON_ERROR(err, tag, message)
Early return on error, propagating the code upward.
Definition ra8_check.h:184
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_hw_unmapped
Peripheral register block is not mapped in this MCU variant.
Definition ra8_err.h:345
@ k_ra8_err_out_of_range
Sensor or peripheral output out of valid range.
Definition ra8_err.h:337
@ 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_not_initialized
Module not initialized – _init() not yet called successfully.
Definition ra8_err.h:235
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
General PWM Timer (GPT) register layout for the Renesas RA8D2.
static volatile r_gpt_channel_regs_t * ra8_gpt(uint8_t channel)
Get pointer to GPT channel N.
Shared CPU-intrinsic seam for the HAL drivers (host/target split).
static void ra8_hw_nop(void)
No-operation used to pad a calibrated busy-wait.
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_info(tag, message)
RA8 log info.
Definition ra8_log.h:364
Ref-counted Module Stop Control wrapper for the RA8D2.
ra8_err_t ra8_mstp_enable(ra8_mstp_t id)
Reference-counted "ungate this peripheral" request.
Definition ra8_mstp.c:343
ra8_err_t ra8_mstp_disable(ra8_mstp_t id)
Reference-counted "gate this peripheral" request.
Definition ra8_mstp.c:382
@ k_ra8_mstp_pdg
MSTPD6 PDG.
static void * s_pdg_event_ctx
Opaque pointer forwarded to s_pdg_event_fn.
Definition ra8_pdg.c:179
ra8_pdg_unit_t
Units used by internal_freq_to_period_ns.
Definition ra8_pdg.c:126
@ k_ra8_pdg_ns_per_sec
1 second in ns.
Definition ra8_pdg.c:127
ra8_err_t ra8_pdg_delay_ns_to_code(uint32_t delay_ns, uint32_t gptclk_hz, ra8_pdg_frange_t frange, uint8_t *out_code)
Convert a desired pin-to-pin delay (in nanoseconds) to a DLY[6:0] code given a measured GPTCLK freque...
Definition ra8_pdg.c:554
ra8_err_t ra8_pdg_pin_disable(uint8_t channel, ra8_pdg_pin_t pin)
Force a single A or B pin's delay to zero (per-pin disable) without touching the channel-level bypass...
Definition ra8_pdg.c:637
static bool s_pdg_capture_in_flight
Set true between ra8_pdg_capture_start and the callback fire.
Definition ra8_pdg.c:736
ra8_err_t ra8_pdg_set_frange(ra8_pdg_frange_t new_frange)
Switch FRANGE at runtime, re-running the DLL re-lock sequence with the new band.
Definition ra8_pdg.c:787
static volatile uint16_t * internal_dly_cell(uint8_t channel, ra8_pdg_pin_t pin, ra8_pdg_edge_t edge)
Compute a pointer to the right delay register cell.
Definition ra8_pdg.c:308
ra8_err_t ra8_pdg_exit_stop(uint8_t channel)
Power up one PDG channel (clear the GTDLYCR2.DLYENn bit).
Definition ra8_pdg.c:589
ra8_err_t ra8_pdg_clear_status(uint16_t mask)
Clear the soft-reset bit (DLYRST -> 0) and re-enable the DLL.
Definition ra8_pdg.c:696
ra8_err_t ra8_pdg_attach_handler(ra8_pdg_event_fn_t fn, void *ctx)
Attach an asynchronous PDG event callback.
Definition ra8_pdg.c:707
ra8_err_t ra8_pdg_channel_bypass_set(uint8_t channel, uint8_t bypass)
Set or clear the bypass bit for a channel.
Definition ra8_pdg.c:616
ra8_err_t ra8_pdg_bind_gpt_channel(uint8_t channel)
Bind PDG channel n to its host GPT32n channel.
Definition ra8_pdg.c:839
ra8_err_t ra8_pdg_set_delay(uint8_t channel, ra8_pdg_pin_t pin, ra8_pdg_edge_t edge, uint8_t code)
Set the per-edge fine delay for one PDG channel/pin/edge.
Definition ra8_pdg.c:494
ra8_err_t ra8_pdg_capture_start(const ra8_pdg_delay_entry_t *buf, uint8_t len)
Stage a buffer of ra8_pdg_delay_entry_t records and arm them.
Definition ra8_pdg.c:738
static ra8_err_t internal_validate_cfg(const ra8_pdg_config_t *cfg)
Validate a user-supplied PDG configuration.
Definition ra8_pdg.c:277
ra8_err_t ra8_pdg_set_delay_batch(const ra8_pdg_delay_entry_t *entries, uint8_t count)
Atomically program a batch of (channel, pin, edge, code) delay updates.
Definition ra8_pdg.c:525
static void internal_busy_wait_us(uint16_t usec)
Coarse software busy-wait used during init.
Definition ra8_pdg.c:201
ra8_err_t ra8_pdg_get_delay(uint8_t channel, ra8_pdg_pin_t pin, ra8_pdg_edge_t edge, uint8_t *out_code)
Read back the last-programmed delay code.
Definition ra8_pdg.c:512
static void internal_wait_5_gtclk(void)
Spin >= 5 GTCLK cycles after releasing DLYRST (HUM Fig 23.2).
Definition ra8_pdg.c:222
ra8_err_t ra8_pdg_pick_frange(uint32_t gptclk_hz, ra8_pdg_frange_t *out)
Auto-pick a FRANGE value from a measured GPTCLK frequency.
Definition ra8_pdg.c:765
static uint32_t internal_freq_to_period_ns(uint32_t hz)
Convert a frequency in Hz to a period in nanoseconds.
Definition ra8_pdg.c:368
ra8_err_t ra8_pdg_get_status(uint16_t *out)
Read GTDLYCR packed into a status mask.
Definition ra8_pdg.c:663
ra8_err_t ra8_pdg_required_write_ns(uint32_t pclka_hz, uint32_t gptclk_hz, uint32_t *out_ns)
Compute the minimum register-write interval (HUM 23.4.3 p 1163).
Definition ra8_pdg.c:921
static ra8_err_t internal_validate_slot(uint8_t channel, ra8_pdg_pin_t pin, ra8_pdg_edge_t edge, uint8_t code)
Validate a (channel, pin, edge, code) tuple.
Definition ra8_pdg.c:336
ra8_err_t ra8_pdg_capture_stop(void)
Cancel any pending buffered apply and clear the completion latch.
Definition ra8_pdg.c:754
ra8_err_t ra8_pdg_enter_stop(uint8_t channel)
Power down one PDG channel (set GTDLYCR2.DLYENn).
Definition ra8_pdg.c:603
ra8_err_t ra8_pdg_get_status_full(ra8_pdg_status_full_t *out)
Read a fully-decoded snapshot of GTDLYCR + GTDLYCR2.
Definition ra8_pdg.c:672
ra8_pdg_internal_t
Driver-internal magic values (no magic numbers in functions).
Definition ra8_pdg.c:80
@ k_ra8_pdg_channel_mask_all
Bits 0..3 – 4 channels.
Definition ra8_pdg.c:81
@ k_ra8_pdg_dll_lock_us
HUM Fig 23.2 wait.
Definition ra8_pdg.c:82
@ k_ra8_pdg_busy_loops_per_us
Conservative spin floor.
Definition ra8_pdg.c:83
@ k_ra8_pdg_ns_per_sec_kilo
Used in MHz->ns math.
Definition ra8_pdg.c:85
@ k_ra8_pdg_post_reset_loops
>= 5 GTCLK cycles.
Definition ra8_pdg.c:84
ra8_pdg_write_interval_t
Multipliers in the HUM Ch 23.4.3 (p 1163) interval formula.
Definition ra8_pdg.c:117
@ k_ra8_pdg_pclka_mult
Period_of_PCLKA x 6.
Definition ra8_pdg.c:118
@ k_ra8_pdg_gptclk_mult
Period_of_GPTCLK x 4.
Definition ra8_pdg.c:119
ra8_err_t ra8_pdg_deinit(void)
Tear down the PDG block (reset + module-stop).
Definition ra8_pdg.c:464
ra8_pdg_gtwp_key_t
GPT GTWP write-protect key values (mirrors FSP).
Definition ra8_pdg.c:97
@ k_ra8_pdg_gtwp_unlock
Unlock GTWP (WP = 0).
Definition ra8_pdg.c:98
@ k_ra8_pdg_gtwp_lock
Re-lock GTWP (WP = 1).
Definition ra8_pdg.c:99
static bool internal_pdg_is_initialized(void)
Probe live PDG registers to decide whether ra8_pdg_init has run successfully.
Definition ra8_pdg.c:153
ra8_err_t ra8_pdg_init(const ra8_pdg_config_t *cfg)
Initialise the PDG block per HUM Figure 23.2 (p 1160).
Definition ra8_pdg.c:438
ra8_err_t ra8_pdg_unbind_gpt_channel(uint8_t channel)
Reverse ra8_pdg_bind_gpt_channel, restoring write-protect.
Definition ra8_pdg.c:860
void ra8_pdg_dispatch(void)
Fire the registered handler.
Definition ra8_pdg.c:715
static void internal_program_dll(const ra8_pdg_config_t *cfg, ra8_pdg_frange_t frange_use)
Run the six-step DLL bring-up sequence from HUM Fig 23.2.
Definition ra8_pdg.c:400
static bool internal_frange_ok(ra8_pdg_frange_t f)
Validate the FRANGE encoding.
Definition ra8_pdg.c:247
ra8_err_t ra8_pdg_check_constraints(ra8_pdg_wave_mode_t mode, ra8_pdg_count_dir_t dir, uint32_t compare_match, uint32_t gtpr)
Check Table 23.4 constraints before writing a delay register.
Definition ra8_pdg.c:881
static ra8_pdg_event_fn_t s_pdg_event_fn
Most recent callback registered by ra8_pdg_attach_handler.
Definition ra8_pdg.c:173
ra8_pdg_constraint_t
Numeric thresholds in HUM Ch 23.4.2 Table 23.4.
Definition ra8_pdg.c:107
@ k_ra8_pdg_constraint_high_pad
"GTPR - 2" boundary pad.
Definition ra8_pdg.c:109
@ k_ra8_pdg_constraint_low_thresh
"<= 2" boundary.
Definition ra8_pdg.c:108
PWM Delay Generation Circuit (PDG) driver public API.
ra8_pdg_wave_mode_t
PWM waveform shape – selects which Table 23.4 row applies.
Definition ra8_pdg.h:144
@ k_ra8_pdg_wave_saw
Saw-wave PWM (count up or down).
Definition ra8_pdg.h:145
@ k_ra8_pdg_wave_triangle
Triangle-wave PWM.
Definition ra8_pdg.h:146
ra8_pdg_edge_t
Selects which delay register family is targeted.
Definition ra8_pdg.h:86
@ k_ra8_pdg_edge_rising
GTDLYRnA / GTDLYRnB.
Definition ra8_pdg.h:87
@ k_ra8_pdg_edge_falling
GTDLYFnA / GTDLYFnB.
Definition ra8_pdg.h:88
void(* ra8_pdg_event_fn_t)(void *ctx)
PDG event callback (DLL lock event, etc.).
Definition ra8_pdg.h:231
@ k_ra8_pdg_status_in_reset
DLYRST = 1 (held in reset).
Definition ra8_pdg.h:116
ra8_pdg_pin_t
Picks the A or B pin within a PDG channel.
Definition ra8_pdg.h:99
@ k_ra8_pdg_pin_a
GTIOCnA – "A" output of GPT32n.
Definition ra8_pdg.h:100
@ k_ra8_pdg_pin_b
GTIOCnB – "B" output of GPT32n.
Definition ra8_pdg.h:101
ra8_pdg_count_dir_t
Counter direction passed to ra8_pdg_check_constraints.
Definition ra8_pdg.h:130
@ k_ra8_pdg_dir_up
Counter is up-counting (TUCF == 0).
Definition ra8_pdg.h:131
@ k_ra8_pdg_dir_down
Counter is down-counting (TUCF == 1).
Definition ra8_pdg.h:132
PWM Delay Generation Circuit (PDG) register layout for the Renesas RA8D2.
@ k_ra8_pdg_gtdlycr_shift_frange
FRANGE[1:0] starts at bit 8.
@ k_ra8_pdg_channel_count
4 GPT channels mapped to PDG (0..3).
@ k_ra8_pdg_slot_count
4 ch * 2 pin * 2 edge = 16 delay slots.
@ k_ra8_pdg_dly_div_high
Divider in the 155..300 MHz band.
@ k_ra8_pdg_dly_max
Maximum legal delay code.
@ k_ra8_pdg_dly_div_low
Divider in the 80..160 MHz band.
@ k_ra8_pdg_dly_mask
DLY[6:0] occupies the low 7 bits.
ra8_pdg_frange_t
GTDLYCR.FRANGE encoding (HUM Ch 23.2.1 p 1154).
@ k_ra8_pdg_frange_80_160_mhz
80..160 MHz, 1/128 step.
@ k_ra8_pdg_frange_155_300_mhz
155..300 MHz, 1/64 step.
@ k_ra8_pdg_gtdlycr_mask_dllen
RA8 pdg gtdlycr mask dllen.
@ k_ra8_pdg_gtdlycr_mask_dlyrst
RA8 pdg gtdlycr mask dlyrst.
@ k_ra8_pdg_gtdlycr_mask_frange
RA8 pdg gtdlycr mask frange.
@ k_ra8_pdg_gtdlycr2_shift_dlyen
DLYEN field starts at bit 8.
@ k_ra8_pdg_gtdlycr2_shift_dlybs
DLYBS field starts at bit 0.
@ k_ra8_pdg_freq_high_max_hz
300 MHz.
@ k_ra8_pdg_freq_low_min_hz
80 MHz.
@ k_ra8_pdg_freq_overlap_top
Top of the overlap zone.
static volatile r_pdg_regs_t * ra8_pdg(void)
Pointer to the PDG block.
Per-channel GPT register window.
volatile uint32_t GTWP
+0x00 Write-Protection.
Two consecutive 16-bit delay cells that match the PDG layout.
volatile uint16_t B
+2 GTIOCnB delay code (DLY[6:0]).
volatile uint16_t A
+0 GTIOCnA delay code (DLY[6:0]).
PDG block register window mapped at k_ra8_pdg_base_addr.
volatile uint16_t GTDLYCR
+0x000 HUM 23.2.1 p 1154
r_pdg_dly_pair_t GTDLYR[k_ra8_pdg_channel_count]
+0x018..0x027 rise.
r_pdg_dly_pair_t GTDLYF[k_ra8_pdg_channel_count]
+0x028..0x037 fall.
volatile uint16_t GTDLYCR2
+0x002 HUM 23.2.2 p 1155
Driver configuration descriptor for ra8_pdg_init.
Definition ra8_pdg.h:173
uint32_t gptclk_hz
Measured GTCLK frequency (Hz).
Definition ra8_pdg.h:177
ra8_pdg_frange_t frange
GPT core clock band (HUM 23.2.1).
Definition ra8_pdg.h:174
uint8_t channel_mask
Bit n = enable PDG channel n.
Definition ra8_pdg.h:175
uint8_t auto_tune
1 = ignore frange, derive from gptclk_hz.
Definition ra8_pdg.h:176
Single-edge descriptor for the batch update API.
Definition ra8_pdg.h:211
Decoded snapshot of GTDLYCR / GTDLYCR2 returned by ra8_pdg_get_status_full.
Definition ra8_pdg.h:191
uint16_t raw_gtdlycr2
Raw GTDLYCR2 contents.
Definition ra8_pdg.h:198
uint8_t per_channel_powered[k_ra8_pdg_channel_count]
!DLYENn.
Definition ra8_pdg.h:196
uint8_t in_reset
GTDLYCR.DLYRST.
Definition ra8_pdg.h:193
ra8_pdg_frange_t frange
GTDLYCR.FRANGE[1:0].
Definition ra8_pdg.h:194
uint8_t per_channel_bypass_off[k_ra8_pdg_channel_count]
DLYBSn.
Definition ra8_pdg.h:195
uint8_t dll_enabled
GTDLYCR.DLLEN.
Definition ra8_pdg.h:192
uint16_t raw_gtdlycr
Raw GTDLYCR contents.
Definition ra8_pdg.h:197