ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_spi_b.c
Go to the documentation of this file.
1
36
37#include <stdint.h>
38
39#include "ra8_attributes.h"
40#include "ra8_check.h"
41#include "ra8_err.h"
42#include "ra8_hw_err.h"
43#include "ra8_log.h"
44#include "ra8_mstp.h"
45#include "ra8_spi.h"
46#include "ra8_spi_regs.h"
47
48static const char* s_tag = "SPI_B";
49
50/* =============================================================================
51 * Constants and lookup tables
52 * =============================================================================
53 */
54
63
68typedef enum : uint32_t {
71
82typedef enum : uint32_t {
86
101
110typedef enum : uint32_t {
111 k_ra8_spi_b_dummy_tx_8 = 0x000000FFUL,
112 k_ra8_spi_b_dummy_tx_16 = 0x0000FFFFUL,
113 k_ra8_spi_b_dummy_tx_32 = 0xFFFFFFFFUL,
115
116/* =============================================================================
117 * Per-channel runtime state
118 * =============================================================================
119 */
120
130
136
137/* =============================================================================
138 * Bit-rate helper
139 * =============================================================================
140 */
141
167RA8_INTERNAL static uint8_t internal_spbr(uint32_t baud_hz, uint32_t pclka_hz)
168{
169 if ((baud_hz == 0U) || (pclka_hz == 0U)) {
170 return 0U;
171 }
172 const uint32_t divisor = 2U * baud_hz;
173 const uint32_t n = pclka_hz / divisor;
174 if (n == 0U) {
175 return 0U;
176 }
177 const uint32_t result = n - 1U;
178 if (result > (uint32_t)k_ra8_spbr_max) {
179 return k_ra8_spbr_max;
180 }
181 return (uint8_t)result;
182}
183
206RA8_INTERNAL static uint32_t internal_spcmd(const ra8_spi_cfg_t* cfg)
207{
208 uint32_t v = 0U;
209 /* CPHA / CPOL match SPI mode 0..3. */
210 if ((cfg->mode == k_ra8_spi_mode_1) || (cfg->mode == k_ra8_spi_mode_3)) {
212 }
213 if ((cfg->mode == k_ra8_spi_mode_2) || (cfg->mode == k_ra8_spi_mode_3)) {
215 }
216 if (cfg->lsb_first) {
218 }
219 /* 8-bit frame. */
221 return v;
222}
223
243{
244 uint32_t v = 0U;
245 v |= k_ra8_spcr_mask_mstr; /* Controller mode. */
246 v |= k_ra8_spcr_mask_sckase; /* Auto-stop SCK. */
247 v |= k_ra8_spcr_mask_spe; /* SPI enable. */
248 return v;
249}
250
279RA8_INTERNAL static ra8_err_t internal_wait_spsr(volatile r_spi_regs_t* reg, uint32_t flag_mask)
280{
281 /* Bounded busy-poll of SPSR. On the host test build the ra8_hw_err MMIO fault
282 * seam (ra8_fake_mmio_*) drives this real loop to succeed-after-N or to time out,
283 * so both the success and timeout legs are exercised on host (T1-01) rather
284 * than compiled out behind an RA8_OFF_TARGET short-circuit. On target it is
285 * a plain register spin with a fixed iteration bound. */
286 return ra8_hw_wait_flag_set32(&reg->SPSR, flag_mask, (uint32_t)k_ra8_spi_b_poll_limit);
287}
288
289/* =============================================================================
290 * Lifecycle: init / deinit
291 * =============================================================================
292 */
293
314 const ra8_spi_cfg_t* cfg)
315{
316 /* HUM Ch 43.2.13 "SPSRC : SPI Status Clear Register" p 2905 */
318
319 /* HUM Ch 43.2.6 "SPCR3 : SPI Control Register 3" p 2891 */
320 const uint8_t spbr = internal_spbr(cfg->baud_hz, cfg->pclka_hz);
321 reg->SPCR3 = ((uint32_t)spbr << k_ra8_spcr3_bit_spbr) & k_ra8_spcr3_mask_spbr;
322
323 /* HUM Ch 43.2.3 "SPDECR : SPI Delay Control Register" p 2883 */
324 reg->SPDECR = 0U;
325
326 /* SPCR2 only honors writes while SPE=0; SPLP2 (bit 17) is the */
327 /* non-inverting loopback (rx = tx). */
328 /* HUM Ch 43.2.4 "SPCR2 : SPI Control Register 2" p 2889 */
329 reg->SPCR2 = (cfg->loopback ? (uint32_t)k_ra8_spcr2_mask_splp2 : 0U);
330
331 /* HUM Ch 43.2.7 "SPCMDm : SPI Command Register" p 2893 */
332 reg->SPCMD[0] = internal_spcmd(cfg);
333
334 /* HUM Ch 43.2.10 "SPDCR : SPI Data Control Register" p 2896 */
335 reg->SPDCR = 0U;
336 reg->SPDCR2 = 0U;
337
338 /* HUM Ch 43.2.14 "SPFCR : SPI FIFO Clear Register" p 2906 */
340
341 /* SPFRST drains residual FIFO contents through the shifter and */
342 /* can leave SPRF set with a stale 0x00, so the first xfer8 */
343 /* would race; re-clear SPSR right before the SPE assert. */
344 /* HUM Ch 43.2.13 "SPSRC : SPI Status Clear Register" p 2905 */
346}
347
348ra8_err_t ra8_spi_init(uint8_t channel, const ra8_spi_cfg_t* cfg)
349{
350 RA8_CHECK_NULL_PTR(cfg, s_tag, "spi_init: cfg");
351 if (channel >= k_ra8_spi_b_channel_count) {
353 }
354 volatile r_spi_regs_t* reg = ra8_spi(channel);
355 if (reg == nullptr) { /* GCOVR_EXCL_BR_LINE -- bounded channel yields non-null reg */
356 return k_ra8_err_invalid_arg; /* GCOVR_EXCL_LINE -- bounded channel yields non-null reg */
357 }
358
359 /* HUM Ch 11.2.7 "MSTPCRB : Module Stop Control Register B" p 444 */
360 const ra8_err_t mst_err = ra8_mstp_enable(s_spi_mstp_table[channel]);
361 /* GCOVR_EXCL_BR_START -- MSTP HW readback */
362 RA8_RETURN_ON_ERROR(mst_err, s_tag, "spi_init: mstp");
363 /* GCOVR_EXCL_BR_STOP */
364
365 /* Disable (SPE=0) before reprogramming. */
366 /* HUM Ch 43.2.4 "SPCR : SPI Control Register" p 2884 */
367 reg->SPCR = 0U;
368
370
371 /* Re-enable with SPE+MSTR set. */
372 /* HUM Ch 43.2.4 "SPCR : SPI Control Register" p 2884 */
374
375 s_spi_state[channel].cb = nullptr;
376 s_spi_state[channel].ctx = nullptr;
377 s_spi_state[channel].initialized = true;
378 ra8_log_info_val(s_tag, "spi_init channel", (uint32_t)channel);
379 return k_ra8_ok;
380}
381
382ra8_err_t ra8_spi_deinit(uint8_t channel)
383{
384 if (channel >= k_ra8_spi_b_channel_count) {
386 }
387 volatile r_spi_regs_t* reg = ra8_spi(channel);
388 if (reg == nullptr) { /* GCOVR_EXCL_BR_LINE -- bounded channel yields non-null reg */
389 return k_ra8_err_invalid_arg; /* GCOVR_EXCL_LINE -- bounded channel yields non-null reg */
390 }
391 /* Clear SPE. */
392 /* HUM Ch 43.2.4 "SPCR : SPI Control Register" p 2884 */
393 reg->SPCR = 0U;
394 s_spi_state[channel].cb = nullptr;
395 s_spi_state[channel].ctx = nullptr;
396 s_spi_state[channel].initialized = false;
397 return ra8_mstp_disable(s_spi_mstp_table[channel]);
398}
399
400/* =============================================================================
401 * Legacy polling shim
402 * =============================================================================
403 */
404
406{
407 const ra8_spi_cfg_t cfg = {
410 .mode = k_ra8_spi_mode_0,
411 .lsb_first = false,
412 };
413 /* The pre-existing test contract distinguishes "channel out of range"
414 * with k_ra8_err_null_ptr (because ra8_spi() returns nullptr). Preserve. */
415 if (ra8_spi(channel) == nullptr) {
416 return k_ra8_err_null_ptr;
417 }
418 return ra8_spi_init(channel, &cfg);
419}
420
421ra8_err_t ra8_spi_xfer8(uint8_t channel, uint8_t tx, uint8_t* rx)
422{
423 volatile r_spi_regs_t* reg = ra8_spi(channel);
424 RA8_CHECK_NULL_PTR(reg, s_tag, "channel out of range");
425
426 /* Wait for TX buffer empty. */
427 /* HUM Ch 43.2.9 "SPSR : SPI Status Register" p 2898 */
429 if (err != k_ra8_ok) {
430 return err;
431 }
432
433 /* Push TX byte. */
434 /* HUM Ch 43.2.2 "SPDR : SPI Data Register" p 2881 */
435 reg->SPDR = (uint32_t)tx;
436
437 /* Clear TX-empty flag (write-1). */
438 /* HUM Ch 43.2.13 "SPSRC : SPI Status Clear Register" p 2905 */
440
441 /* Wait for RX buffer full. */
442 /* HUM Ch 43.2.9 "SPSR : SPI Status Register" p 2898 */
444 if (err != k_ra8_ok) {
445 return err;
446 }
447
448 /* Drain RX byte. */
449 /* HUM Ch 43.2.2 "SPDR : SPI Data Register" p 2881 */
450 const uint8_t received = (uint8_t)reg->SPDR;
451
452 /* Clear RX-full flag. */
453 /* HUM Ch 43.2.13 "SPSRC : SPI Status Clear Register" p 2905 */
455
456 if (rx != nullptr) {
457 *rx = received;
458 }
459 return k_ra8_ok;
460}
461
462/* =============================================================================
463 * Multi-byte / multi-width polling transfers
464 * =============================================================================
465 */
466
486{
487 switch (bit_width) {
489 *out_bytes = k_ra8_spi_b_bytes_per_unit_8;
490 return k_ra8_ok;
493 return k_ra8_ok;
496 return k_ra8_ok;
497 default:
499 }
500}
501
523 ra8_spi_bit_width_t bit_width)
524{
525 /* HUM Ch 43.2.7 "SPCMDm : SPI Command Register" p 2893 */
526 uint32_t spcmd0 = reg->SPCMD[0] & ~k_ra8_spcmd_mask_spb;
527 spcmd0 |= ((uint32_t)bit_width << k_ra8_spcmd_bit_spb_lo) & k_ra8_spcmd_mask_spb;
528 reg->SPCMD[0] = spcmd0;
529}
530
554 const void* tx,
555 uint32_t idx,
556 ra8_spi_bit_width_t bit_width)
557{
558 uint32_t value = 0U;
559 if (tx == nullptr) {
560 if (bit_width == k_ra8_spi_width_32) {
562 } else if (bit_width == k_ra8_spi_width_16) {
564 } else {
566 }
567 } else if (bit_width == k_ra8_spi_width_32) {
568 value = ((const uint32_t*)tx)[idx];
569 } else if (bit_width == k_ra8_spi_width_16) {
570 value = (uint32_t)((const uint16_t*)tx)[idx];
571 } else {
572 value = (uint32_t)((const uint8_t*)tx)[idx];
573 }
574 /* HUM Ch 43.2.2 "SPDR : SPI Data Register" p 2881 */
575 reg->SPDR = value;
576}
577
598RA8_INTERNAL static void internal_pop_unit(volatile const r_spi_regs_t* reg,
599 void* rx,
600 uint32_t idx,
601 ra8_spi_bit_width_t bit_width)
602{
603 /* HUM Ch 43.2.2 "SPDR : SPI Data Register" p 2881 */
604 const uint32_t value = reg->SPDR;
605 if (rx == nullptr) {
606 return;
607 }
608 if (bit_width == k_ra8_spi_width_32) {
609 ((uint32_t*)rx)[idx] = value;
610 } else if (bit_width == k_ra8_spi_width_16) {
611 ((uint16_t*)rx)[idx] = (uint16_t)value;
612 } else {
613 ((uint8_t*)rx)[idx] = (uint8_t)value;
614 }
615}
616
651 const void* tx,
652 void* rx,
653 uint32_t len,
654 ra8_spi_bit_width_t bit_width)
655{
656 if (channel >= k_ra8_spi_b_channel_count) {
658 }
659 uint8_t bytes_per_unit = 0U;
660 const ra8_err_t bw_err = internal_unit_bytes(bit_width, &bytes_per_unit);
661 if (bw_err != k_ra8_ok) {
662 return bw_err;
663 }
664 if (len == 0U) {
665 return k_ra8_ok;
666 }
667 // mcdc-deactivated: TU-local helper internal_xfer_common null-pair guard; the public-API ra8_spi_b_transfer entry validates that at least one of (tx, rx) is non-NULL before calling this helper, so the AND's two conditions cannot both be true on any reachable path -- defensive depth guard only.
668 if ((tx == nullptr) && (rx == nullptr)) {
669 return k_ra8_err_null_ptr;
670 }
671 volatile r_spi_regs_t* reg = ra8_spi(channel);
672 if (reg == nullptr) { /* GCOVR_EXCL_BR_LINE -- bounded channel yields non-null reg */
673 return k_ra8_err_invalid_arg; /* GCOVR_EXCL_LINE -- bounded channel yields non-null reg */
674 }
675
676 /* Lock SPCMD0.SPB to the requested width before pushing data. */
677 internal_apply_bit_width(reg, bit_width);
678 /* Suppress unused warning when callers never pass a 32-bit frame. */
679 (void)bytes_per_unit;
680
681 for (uint32_t i = 0U; i < len; i++) {
682 /* HUM Ch 43.2.9 "SPSR : SPI Status Register" p 2898 */
684 if (err != k_ra8_ok) {
685 return err;
686 }
687 internal_push_unit(reg, tx, i, bit_width);
688 /* HUM Ch 43.2.13 "SPSRC : SPI Status Clear Register" p 2905 */
690
692 if (err != k_ra8_ok) {
693 return err;
694 }
695 internal_pop_unit(reg, rx, i, bit_width);
696 /* HUM Ch 43.2.13 "SPSRC : SPI Status Clear Register" p 2905 */
698 }
699 return k_ra8_ok;
700}
701
703ra8_spi_write(uint8_t channel, const void* tx, uint32_t len, ra8_spi_bit_width_t bit_width)
704{
705 if ((tx == nullptr) && (len > 0U)) {
706 return k_ra8_err_null_ptr;
707 }
708 return internal_xfer_common(channel, tx, nullptr, len, bit_width);
709}
710
711ra8_err_t ra8_spi_read(uint8_t channel, void* rx, uint32_t len, ra8_spi_bit_width_t bit_width)
712{
713 if ((rx == nullptr) && (len > 0U)) {
714 return k_ra8_err_null_ptr;
715 }
716 return internal_xfer_common(channel, nullptr, rx, len, bit_width);
717}
718
720 const void* tx,
721 void* rx,
722 uint32_t len,
723 ra8_spi_bit_width_t bit_width)
724{
725 if (len > 0U) {
726 if (tx == nullptr) {
727 return k_ra8_err_null_ptr;
728 }
729 if (rx == nullptr) {
730 return k_ra8_err_null_ptr;
731 }
732 }
733 return internal_xfer_common(channel, tx, rx, len, bit_width);
734}
735
736/* =============================================================================
737 * Runtime reconfigure
738 * =============================================================================
739 */
740
741ra8_err_t ra8_spi_set_clock(uint8_t channel, uint32_t baud_hz, uint32_t pclka_hz)
742{
743 if (channel >= k_ra8_spi_b_channel_count) {
745 }
746 volatile r_spi_regs_t* reg = ra8_spi(channel);
747 if (reg == nullptr) { /* GCOVR_EXCL_BR_LINE -- bounded channel yields non-null reg */
748 return k_ra8_err_invalid_arg; /* GCOVR_EXCL_LINE -- bounded channel yields non-null reg */
749 }
750 if (baud_hz == 0U) {
752 }
753 /* Update SPCR3.SPBR[15:8]. */
754 /* HUM Ch 43.2.6 "SPCR3 : SPI Control Register 3" p 2891 */
755 const uint8_t spbr = internal_spbr(baud_hz, pclka_hz);
756 const uint32_t spcr3_in = reg->SPCR3 & ~k_ra8_spcr3_mask_spbr;
757 reg->SPCR3 = spcr3_in | (((uint32_t)spbr << k_ra8_spcr3_bit_spbr) & k_ra8_spcr3_mask_spbr);
758 return k_ra8_ok;
759}
760
761/* =============================================================================
762 * Error status
763 * =============================================================================
764 */
765
766ra8_err_t ra8_spi_get_errors(uint8_t channel, uint8_t* out_mask)
767{
768 RA8_CHECK_NULL_PTR(out_mask, s_tag, "spi get_errors");
769 if (channel >= k_ra8_spi_b_channel_count) {
771 }
772 volatile const r_spi_regs_t* reg = ra8_spi(channel);
773 if (reg == nullptr) { /* GCOVR_EXCL_BR_LINE -- bounded channel yields non-null reg */
774 return k_ra8_err_invalid_arg; /* GCOVR_EXCL_LINE -- bounded channel yields non-null reg */
775 }
776 const uint32_t ss = reg->SPSR;
777 uint8_t m = k_ra8_spi_err_none;
778 if ((ss & k_ra8_spsr_mask_ovrf) != 0U) {
780 }
781 if ((ss & k_ra8_spsr_mask_modf) != 0U) {
783 }
784 if ((ss & k_ra8_spsr_mask_perf) != 0U) {
786 }
787 if ((ss & k_ra8_spsr_mask_udrf) != 0U) {
789 }
790 *out_mask = m;
791 return k_ra8_ok;
792}
793
795{
796 if (channel >= k_ra8_spi_b_channel_count) {
798 }
799 volatile r_spi_regs_t* reg = ra8_spi(channel);
800 if (reg == nullptr) { /* GCOVR_EXCL_BR_LINE -- bounded channel yields non-null reg */
801 return k_ra8_err_invalid_arg; /* GCOVR_EXCL_LINE -- bounded channel yields non-null reg */
802 }
803 /* SPI_B status flags clear via SPSRC (write-1). */
804 /* HUM Ch 43.2.13 "SPSRC : SPI Status Clear Register" p 2905 */
806 return k_ra8_ok;
807}
808
810{
811 if (channel >= k_ra8_spi_b_channel_count) {
813 }
814 s_spi_state[channel].cb = fn;
815 s_spi_state[channel].ctx = ctx;
816 return k_ra8_ok;
817}
818
819/* =============================================================================
820 * Power transition
821 * =============================================================================
822 */
823
825{
826 if (channel >= k_ra8_spi_b_channel_count) {
828 }
829 volatile r_spi_regs_t* reg = ra8_spi(channel);
830 if (reg == nullptr) { /* GCOVR_EXCL_BR_LINE -- bounded channel yields non-null reg */
831 return k_ra8_err_invalid_arg; /* GCOVR_EXCL_LINE -- bounded channel yields non-null reg */
832 }
833 /* Clear SPE. */
834 /* HUM Ch 43.2.4 "SPCR : SPI Control Register" p 2884 */
835 reg->SPCR = 0U;
836 return ra8_mstp_disable(s_spi_mstp_table[channel]);
837}
838
840{
841 if (channel >= k_ra8_spi_b_channel_count) {
843 }
844 return ra8_mstp_enable(s_spi_mstp_table[channel]);
845}
846
847/* =============================================================================
848 * ISR dispatch -- placeholder; real IRQ routing lands with NVIC wiring.
849 * =============================================================================
850 */
851
853void ra8_spi_dispatch_spti(uint8_t channel)
854{
855 if (channel >= k_ra8_spi_b_channel_count) {
856 return;
857 }
858 (void)s_spi_state[channel].cb;
859}
860
862void ra8_spi_dispatch_spri(uint8_t channel)
863{
864 if (channel >= k_ra8_spi_b_channel_count) {
865 return;
866 }
867 (void)s_spi_state[channel].cb;
868}
869
871void ra8_spi_dispatch_spei(uint8_t channel)
872{
873 if (channel >= k_ra8_spi_b_channel_count) {
874 return;
875 }
876 uint8_t mask = 0U;
877 (void)ra8_spi_get_errors(channel, &mask);
878 (void)ra8_spi_clear_errors(channel);
879 const ra8_spi_complete_fn_t cb = s_spi_state[channel].cb;
880 if ((mask != 0U) && (cb != nullptr)) {
881 cb(s_spi_state[channel].ctx, mask);
882 }
883}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#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).
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_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ 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
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
Bounded wait-flag primitives for RA8D2 HAL drivers.
static ra8_err_t ra8_hw_wait_flag_set32(volatile const uint32_t *reg, uint32_t mask, uint32_t budget)
Spin until (*reg & mask) != 0 or budget runs out.
Definition ra8_hw_err.h:309
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_info_val(tag, message, value)
RA8 log info val.
Definition ra8_log.h:366
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
ra8_mstp_t
Packed (reg << 8) | bit module-stop identifier.
@ k_ra8_mstp_spi0
MSTPB19 SPI0.
@ k_ra8_mstp_spi1
MSTPB18 SPI1.
SPI_B controller driver (RA8D2 Type-B SPI peripheral).
ra8_spi_bit_width_t
Per-frame bit width for multi-byte transfers.
Definition ra8_spi.h:84
@ k_ra8_spi_width_16
16-bit frame -> SPCMDn.SPB = 0b01111.
Definition ra8_spi.h:86
@ k_ra8_spi_width_32
32-bit frame -> SPCMDn.SPB = 0b11111.
Definition ra8_spi.h:87
@ k_ra8_spi_width_8
8-bit frame -> SPCMDn.SPB = 0b00111.
Definition ra8_spi.h:85
void(* ra8_spi_complete_fn_t)(void *ctx, uint8_t err_mask)
Transfer-complete callback signature.
Definition ra8_spi.h:126
@ k_ra8_spi_mode_0
CPOL=0, CPHA=0.
Definition ra8_spi.h:62
@ k_ra8_spi_mode_3
CPOL=1, CPHA=1.
Definition ra8_spi.h:65
@ k_ra8_spi_mode_1
CPOL=0, CPHA=1.
Definition ra8_spi.h:63
@ k_ra8_spi_mode_2
CPOL=1, CPHA=0.
Definition ra8_spi.h:64
@ k_ra8_spi_err_none
RA8 SPI error none.
Definition ra8_spi.h:112
@ k_ra8_spi_err_mode
SPSR.MODERF set.
Definition ra8_spi.h:114
@ k_ra8_spi_err_parity
SPSR.PERF set.
Definition ra8_spi.h:115
@ k_ra8_spi_err_underrun
SPSR.UDRF set.
Definition ra8_spi.h:116
@ k_ra8_spi_err_overrun
SPSR.OVRF set.
Definition ra8_spi.h:113
static void internal_apply_bit_width(volatile r_spi_regs_t *reg, ra8_spi_bit_width_t bit_width)
Programme SPCMD0.SPB to the requested bit-width.
Definition ra8_spi_b.c:522
ra8_err_t ra8_spi_write(uint8_t channel, const void *tx, uint32_t len, ra8_spi_bit_width_t bit_width)
Multi-frame TX-only polling transfer.
Definition ra8_spi_b.c:703
static void internal_pop_unit(volatile const r_spi_regs_t *reg, void *rx, uint32_t idx, ra8_spi_bit_width_t bit_width)
Read SPDR into rx at idx (or discard).
Definition ra8_spi_b.c:598
ra8_err_t ra8_spi_write_read(uint8_t channel, const void *tx, void *rx, uint32_t len, ra8_spi_bit_width_t bit_width)
Multi-frame full-duplex polling transfer.
Definition ra8_spi_b.c:719
static void internal_spi_program_regs(volatile r_spi_regs_t *reg, const ra8_spi_cfg_t *cfg)
Programme the polling-controller register set with SPE=0.
Definition ra8_spi_b.c:313
ra8_spi_b_dummy_t
Dummy TX values written when ra8_spi_read has no caller payload.
Definition ra8_spi_b.c:110
@ k_ra8_spi_b_dummy_tx_16
16-bit dummy.
Definition ra8_spi_b.c:112
@ k_ra8_spi_b_dummy_tx_8
8-bit dummy.
Definition ra8_spi_b.c:111
@ k_ra8_spi_b_dummy_tx_32
32-bit dummy.
Definition ra8_spi_b.c:113
ra8_err_t ra8_spi_attach_transfer_handler(uint8_t channel, ra8_spi_complete_fn_t fn, void *ctx)
Attach a transfer-complete callback for a channel.
Definition ra8_spi_b.c:809
ra8_spi_b_default_t
Default register values for the legacy ra8_spi_controller_init shim.
Definition ra8_spi_b.c:82
@ k_ra8_spi_b_default_baud_hz
RA8 SPI b default baud Hz.
Definition ra8_spi_b.c:83
@ k_ra8_spi_b_default_pclka_hz
RA8 SPI b default pclka Hz.
Definition ra8_spi_b.c:84
ra8_err_t ra8_spi_clear_errors(uint8_t channel)
Clear the SPSR error flags.
Definition ra8_spi_b.c:794
void ra8_spi_dispatch_spei(uint8_t channel)
Dispatch SPEI – collect + clear errors, fire callback.
Definition ra8_spi_b.c:871
ra8_spi_b_unit_bytes_t
Bytes-per-frame for each supported transfer width.
Definition ra8_spi_b.c:96
@ k_ra8_spi_b_bytes_per_unit_16
16-bit frame -> 2 bytes.
Definition ra8_spi_b.c:98
@ k_ra8_spi_b_bytes_per_unit_8
8-bit frame -> 1 byte.
Definition ra8_spi_b.c:97
@ k_ra8_spi_b_bytes_per_unit_32
32-bit frame -> 4 bytes.
Definition ra8_spi_b.c:99
ra8_err_t ra8_spi_enter_stop(uint8_t channel)
Put the channel into MSTP-gated stop state.
Definition ra8_spi_b.c:824
void ra8_spi_dispatch_spti(uint8_t channel)
Dispatch SPTI – advance TX state.
Definition ra8_spi_b.c:853
static const ra8_mstp_t s_spi_mstp_table[k_ra8_spi_b_channel_count]
Channel-index -> MSTP id (HUM Ch 11.2.7 "MSTPCRB", p 444).
Definition ra8_spi_b.c:59
static void internal_push_unit(volatile r_spi_regs_t *reg, const void *tx, uint32_t idx, ra8_spi_bit_width_t bit_width)
Pull one TX unit out of tx (or use a dummy) and write SPDR.
Definition ra8_spi_b.c:553
ra8_err_t ra8_spi_controller_init(uint8_t channel)
Legacy init (1.9 MHz at PCLKA = 125 MHz, mode 0).
Definition ra8_spi_b.c:405
ra8_spi_b_poll_t
Polling-loop budget.
Definition ra8_spi_b.c:68
@ k_ra8_spi_b_poll_limit
RA8 SPI b poll limit.
Definition ra8_spi_b.c:69
static ra8_spi_state_t s_spi_state[k_ra8_spi_b_channel_count]
Per-channel state table indexed by channel.
Definition ra8_spi_b.c:135
ra8_err_t ra8_spi_get_errors(uint8_t channel, uint8_t *out_mask)
Read the SPSR error bits (OVRF, MODERF, PERF, UDRF).
Definition ra8_spi_b.c:766
ra8_err_t ra8_spi_xfer8(uint8_t channel, uint8_t tx, uint8_t *rx)
Full-duplex 8-bit exchange.
Definition ra8_spi_b.c:421
ra8_err_t ra8_spi_read(uint8_t channel, void *rx, uint32_t len, ra8_spi_bit_width_t bit_width)
Multi-frame RX-only polling transfer.
Definition ra8_spi_b.c:711
ra8_err_t ra8_spi_exit_stop(uint8_t channel)
Exit MSTP-gated stop state.
Definition ra8_spi_b.c:839
void ra8_spi_dispatch_spri(uint8_t channel)
Dispatch SPRI – advance RX state.
Definition ra8_spi_b.c:862
static ra8_err_t internal_xfer_common(uint8_t channel, const void *tx, void *rx, uint32_t len, ra8_spi_bit_width_t bit_width)
Common engine for ra8_spi_write / ra8_spi_read / ra8_spi_write_read.
Definition ra8_spi_b.c:650
ra8_err_t ra8_spi_set_clock(uint8_t channel, uint32_t baud_hz, uint32_t pclka_hz)
Change the SPI clock without tearing down the channel.
Definition ra8_spi_b.c:741
static uint32_t internal_spcmd(const ra8_spi_cfg_t *cfg)
Build SPCMD0 from a ra8_spi_cfg_t.
Definition ra8_spi_b.c:206
static uint32_t internal_spcr_controller(void)
Build SPCR (control register 1) for controller polling mode.
Definition ra8_spi_b.c:242
ra8_err_t ra8_spi_init(uint8_t channel, const ra8_spi_cfg_t *cfg)
Initialise an SPI channel with a full config descriptor.
Definition ra8_spi_b.c:348
static ra8_err_t internal_wait_spsr(volatile r_spi_regs_t *reg, uint32_t flag_mask)
Wait for an SPSR flag to assert.
Definition ra8_spi_b.c:279
static ra8_err_t internal_unit_bytes(ra8_spi_bit_width_t bit_width, uint8_t *out_bytes)
Map a public ra8_spi_bit_width_t to its bytes-per-unit.
Definition ra8_spi_b.c:485
ra8_err_t ra8_spi_deinit(uint8_t channel)
Tear down a channel.
Definition ra8_spi_b.c:382
static uint8_t internal_spbr(uint32_t baud_hz, uint32_t pclka_hz)
Compute SPCR3.SPBR for a requested bit-rate.
Definition ra8_spi_b.c:167
SPI_B register layout for the Renesas RA8D2.
@ k_ra8_spcmd_bit_spb_lo
Data Length [20:16] low.
@ k_ra8_spcr3_bit_spbr
SPBR field [15:8] – bit-rate divider.
@ k_ra8_spcmd_mask_cpol
RA8 spcmd mask cpol.
@ k_ra8_spcmd_mask_lsbf
RA8 spcmd mask lsbf.
@ k_ra8_spcmd_mask_cpha
RA8 spcmd mask cpha.
@ k_ra8_spcmd_mask_spb
[20:16] data length
@ k_ra8_spcr_mask_mstr
RA8 spcr mask mstr.
@ k_ra8_spcr_mask_spe
RA8 spcr mask spe.
@ k_ra8_spcr_mask_sckase
RA8 spcr mask sckase.
static volatile r_spi_regs_t * ra8_spi(uint8_t channel)
Get pointer to SPI_B channel channel (0..1).
@ k_ra8_spfcr_mask_spfrst
Reset both FIFOs.
@ k_ra8_spcr2_mask_splp2
Non-inverting loopback (rx = tx).
@ k_ra8_spcr3_mask_spbr
[15:8] bit-rate divider.
@ k_ra8_spsr_mask_ovrf
RA8 spsr mask ovrf.
@ k_ra8_spsr_mask_sprf
RA8 spsr mask sprf.
@ k_ra8_spsr_mask_udrf
RA8 spsr mask udrf.
@ k_ra8_spsr_mask_perf
RA8 spsr mask perf.
@ k_ra8_spsr_mask_modf
RA8 spsr mask modf.
@ k_ra8_spsr_mask_sptef
RA8 spsr mask sptef.
@ k_ra8_spsr_mask_errs
OVRF | MODF | PERF | UDRF.
@ k_ra8_spi_b_channel_count
SPI0 + SPI1.
@ k_ra8_spcmd_spb_8bit
0b00111 -> 8-bit frame.
@ k_ra8_spbr_max
SPBR is 8-bit unsigned.
@ k_ra8_spsrc_mask_all
Clear every flag at once.
@ k_ra8_spsrc_mask_sprfc
RA8 spsrc mask sprfc.
@ k_ra8_spsrc_mask_sptefc
RA8 spsrc mask sptefc.
SPI_B register-window mirror (matches FSP R_SPI_B0_Type, 0x70 bytes).
volatile uint32_t SPDECR
+0x04 SPI Delay Control Register.
volatile uint32_t SPSRC
+0x68 SPI Status Clear Register.
volatile uint32_t SPDCR2
+0x44 SPI Data Control Register 2.
volatile uint32_t SPCR
+0x08 SPI Control Register 1.
volatile uint32_t SPCR3
+0x10 SPI Control Register 3.
volatile uint32_t SPCMD[8]
+0x14..0x30 Command Registers SPCMD0..7.
volatile uint32_t SPFCR
+0x6C SPI FIFO Clear Register.
volatile uint32_t SPSR
+0x50 SPI Status Register.
volatile uint32_t SPDCR
+0x40 SPI Data Control Register.
volatile uint32_t SPCR2
+0x0C SPI Control Register 2.
volatile uint32_t SPDR
+0x00 SPI Data Register.
Configuration descriptor for ra8_spi_init.
Definition ra8_spi.h:99
bool lsb_first
True for LSB-first transfers.
Definition ra8_spi.h:103
bool loopback
SPCR2.SPLP=1: internal COPI->CIPO tie (no pins).
Definition ra8_spi.h:104
uint32_t pclka_hz
Current PCLKA in Hz (for SPBR calc).
Definition ra8_spi.h:101
uint32_t baud_hz
Target SPI clock in Hz.
Definition ra8_spi.h:100
ra8_spi_mode_t mode
CPOL / CPHA combination.
Definition ra8_spi.h:102
Per-channel dispatch state owned by this driver.
Definition ra8_spi_b.c:125
ra8_spi_complete_fn_t cb
Transfer-complete callback.
Definition ra8_spi_b.c:126
void * ctx
Callback context.
Definition ra8_spi_b.c:127
bool initialized
True after ra8_spi_init.
Definition ra8_spi_b.c:128