ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_sci.c
Go to the documentation of this file.
1
62
63#include "ra8_sci.h"
64
65#include <stdint.h>
66
67#include "ra8_attributes.h"
68#include "ra8_check.h"
69#include "ra8_err.h"
70#include "ra8_hw_err.h"
71#include "ra8_log.h"
72#include "ra8_mstp.h"
73#include "ra8_mstp_regs.h"
74#include "ra8_register_guard.h"
75#include "ra8_sci_internal.h"
76#include "ra8_sci_regs.h"
77
78static const char* s_tag = "SCI";
79
80/* =============================================================================
81 * Per-channel state
82 * =============================================================================
83 */
84
95
112
113/* =============================================================================
114 * Internal helpers
115 * =============================================================================
116 */
117
122RA8_INTERNAL static inline volatile r_sci_regs_t* internal_reg(uint8_t channel)
123{
124 if (channel > k_ra8_sci_channel_max_index) {
125 return nullptr;
126 }
127 return ra8_sci(channel);
128}
129
155RA8_INTERNAL static uint8_t internal_brr(uint32_t pclk_hz, uint32_t baud)
156{
157 if ((baud == 0U) || (pclk_hz == 0U)) {
158 return 0U;
159 }
160 const uint32_t divisor = k_ra8_sci_brr_async_divisor * baud;
161 const uint32_t n = pclk_hz / divisor;
162 if (n == 0U) {
163 return 0U;
164 }
165 return (uint8_t)(n - 1U);
166}
167
189RA8_INTERNAL static uint32_t internal_ccr1(const ra8_sci_cfg_t* cfg)
190{
191 uint32_t ccr1 = (1U << k_ra8_sci_ccr1_bit_spb2dt) | (1U << k_ra8_sci_ccr1_bit_spb2io);
192 if (cfg->parity != k_ra8_sci_parity_none) {
193 ccr1 |= (1U << k_ra8_sci_ccr1_bit_pe);
194 if (cfg->parity == k_ra8_sci_parity_odd) {
195 ccr1 |= (1U << k_ra8_sci_ccr1_bit_pm);
196 }
197 }
198 return ccr1;
199}
200
219RA8_INTERNAL static uint32_t internal_ccr3(const ra8_sci_cfg_t* cfg)
220{
221 /* LSBF = 1 (LSB-first) is the UART standard wire order. SCI_B's
222 * reset state is MSB-first; without this bit the host receives
223 * each byte bit-reversed (e.g. 'h' = 0x68 transmits as 0x16). FSP
224 * r_sci_b_uart sets LSBF unconditionally for async configs.
225 *
226 * BPEN = 1 (Synchronizer Bypass Enable) is required when the bus
227 * clock (PCLK) is also used as the operation clock (TCLK) -- which
228 * is what we're doing in async mode with the on-chip baud-rate
229 * generator on the synchronized clock. Without BPEN the SCI's
230 * shift state machine waits forever for an independent SCICLK
231 * edge that never arrives, and the chip looks alive at the
232 * register level (TDR latches, CCR0.TE=1) but never advances --
233 * CSR.TDRE and CSR.TEND stay 0 indefinitely. HUM Ch 38.2.8 p 2207
234 * "BPEN bit" is the authoritative source. */
235 uint32_t ccr3 = (1U << k_ra8_sci_ccr3_bit_lsbf) | (1U << k_ra8_sci_ccr3_bit_bpen);
236
237 /* MOD = 000 (Asynchronous) -- already 0. */
238
239 /* CHR[1:0]. 8-bit -> 10b, 7-bit -> 11b. */
240 if (cfg->data_bits == k_ra8_sci_data_7) {
242 } else {
244 }
245
246 /* STP -- 1 = 2 stop bits. */
247 if (cfg->stop_bits == k_ra8_sci_stop_2) {
248 ccr3 |= (1U << k_ra8_sci_ccr3_bit_stp);
249 }
250
251 return ccr3;
252}
253
275{
276 /* HUM Ch 38.2.24 "CFCLR : Common Flag Clear Register", p 2238 --
277 * one write clears ERS / DCMF / DPER / DFER / ORER / MFF / PER /
278 * FER / TDRE / RDRF in CSR. */
280
281 /* HUM Ch 38.2.26 "FFCLR : FIFO Flag Clear Register", p 2239 --
282 * clears FRSR.DR (the only defined W1C bit). */
284}
285
313{
314 /* HUM Ch 38.2.17 "CSR : Common Status Register", p 2225 -- TEND (bit 30) goes
315 * high when both the data register and the shift register are empty. The
316 * ra8_fake_mmio host fault seam drives this real poll on the unit-test build, so
317 * the success and timeout legs run on host (T1-01) rather than short-circuit. */
318 const uint32_t mask = (1U << k_ra8_sci_csr_bit_tend);
320}
321
340RA8_INTERNAL static uint32_t internal_ccr2(const ra8_sci_cfg_t* cfg)
341{
342 const uint8_t brr = internal_brr(cfg->pclk_hz, cfg->baud);
343 uint32_t ccr2 = 0U;
344 ccr2 |= ((uint32_t)brr << k_ra8_sci_ccr2_shift_brr);
345 /* MDDR reset value -- keep modulation off. */
347 return ccr2;
348}
349
350/* =============================================================================
351 * Public API
352 * =============================================================================
353 */
354
377 const ra8_sci_cfg_t* cfg)
378{
379 /* HUM Ch 38.2.5 "CCR0 : Common Control Register 0", p 2182 -- disable
380 * TX/RX/IE bits before reconfiguring CCR1..CCR4 and FCR. */
381 reg->CCR0 = 0U;
382
383 /* HUM Ch 38.2.11 "FCR : FIFO Control Register", p 2215 -- non-FIFO
384 * polling mode for the bring-up demo: TFRST/RFRST cleared, all
385 * trigger numbers reset to 0. */
386 reg->FCR = 0U;
387
388 /* HUM Ch 38.2.6 "CCR1 : Common Control Register 1", p 2185 */
389 reg->CCR1 = internal_ccr1(cfg);
390
391 /* HUM Ch 38.2.8 "CCR3 : Common Control Register 3", p 2203 -- mode
392 * + framing must be programmed before TE/RE go high. */
393 reg->CCR3 = internal_ccr3(cfg);
394
395 /* HUM Ch 38.2.7 "CCR2 : Common Control Register 2", p 2189 -- BRR
396 * derived from cfg->pclk_hz and cfg->baud. */
397 reg->CCR2 = internal_ccr2(cfg);
398
399 /* HUM Ch 38.2.9 "CCR4 : Common Control Register 4", p 2210 -- no
400 * sample / transmit timing adjustment for async UART. */
401 reg->CCR4 = 0U;
402
403 /* HUM Ch 38.2.24 "CFCLR : Common Flag Clear Register", p 2238 +
404 * HUM Ch 38.2.26 "FFCLR : FIFO Flag Clear Register", p 2239 -- drop
405 * any latches inherited from a previous boot before TX/RX go live.
406 * Mirrors FSP r_sci_b_uart.c. */
408}
409
410ra8_err_t ra8_sci_init(uint8_t channel, const ra8_sci_cfg_t* cfg)
411{
412 RA8_CHECK_NULL_PTR(cfg, s_tag, "sci_init: cfg");
413 volatile r_sci_regs_t* reg = internal_reg(channel);
414 if (reg == nullptr) {
416 }
417
418 /* HUM Ch 11.2.7 "MSTPCRB : Module Stop Control Register B", p 445 */
419 const ra8_err_t mst_err = ra8_mstp_enable(s_mstp_table[channel]);
420 if (mst_err != k_ra8_ok) {
421 ra8_log_error_val(s_tag, "sci_init: mstp enable failed", (uint32_t)mst_err);
423 }
424
426
427 /* HUM Ch 38.2.5 "CCR0 : Common Control Register 0", p 2182 -- enable
428 * transmitter and receiver. Interrupt-enable bits are toggled
429 * separately by ra8_sci_attach_{rx,tx}_handler. */
430 reg->CCR0 = (1U << k_ra8_sci_ccr0_bit_te) | (1U << k_ra8_sci_ccr0_bit_re);
431
432 s_sci_state[channel].initialized = true;
433 s_sci_state[channel].tx_buf = nullptr;
434 s_sci_state[channel].tx_len = 0U;
435 s_sci_state[channel].tx_idx = 0U;
436 s_sci_state[channel].rx_buf = nullptr;
437 s_sci_state[channel].rx_len = 0U;
438 s_sci_state[channel].rx_idx = 0U;
439 ra8_log_info_val(s_tag, "sci_init channel", (uint32_t)channel);
440 return k_ra8_ok;
441}
442
443ra8_err_t ra8_sci_deinit(uint8_t channel)
444{
445 volatile r_sci_regs_t* reg = internal_reg(channel);
446 if (reg == nullptr) {
448 }
449
450 /* Drop CCR0 and tear the async descriptor down atomically w.r.t. the
451 * TXI/RXI ISR. Without the mask, a pending interrupt can still observe a
452 * non-zero tx_len/rx_len after CCR0 is cleared and then dereference the
453 * buffer pointer this path is nulling -- a NULL deref in interrupt
454 * context. Mirrors the ra8_sci_abort teardown. */
457 /* HUM Ch 38.2.5 "CCR0 : Common Control Register 0", p 2182 */
458 reg->CCR0 = 0U;
459 s_sci_state[channel].rx_fn = nullptr;
460 s_sci_state[channel].rx_ctx = nullptr;
461 s_sci_state[channel].tx_fn = nullptr;
462 s_sci_state[channel].tx_ctx = nullptr;
463 s_sci_state[channel].initialized = false;
464 s_sci_state[channel].tx_buf = nullptr;
465 s_sci_state[channel].tx_len = 0U;
466 s_sci_state[channel].tx_idx = 0U;
467 s_sci_state[channel].rx_buf = nullptr;
468 s_sci_state[channel].rx_len = 0U;
469 s_sci_state[channel].rx_idx = 0U;
471 return ra8_mstp_disable(s_mstp_table[channel]);
472}
473
474/* ---- Polling TX / RX -------------------------------------------------- */
475
476ra8_err_t ra8_sci_putc_polling(uint8_t channel, uint8_t byte)
477{
478 volatile r_sci_regs_t* reg = internal_reg(channel);
479 if (reg == nullptr) {
481 }
482 /* HUM Ch 38.2.17 "CSR : Common Status Register", p 2225 -- spin
483 * until TDRE = 1 (transmit data register empty). */
484 const uint32_t mask = (1U << k_ra8_sci_csr_bit_tdre);
486 if (werr != k_ra8_ok) {
487 return werr;
488 }
489 /* HUM Ch 38.2.3 "TDR : Transmit Data Register", p 2181 -- write to
490 * TDAT[7:0] (low 8 bits of TDR) launches one frame in non-FIFO
491 * 8-bit async mode. */
492 reg->TDR = (uint32_t)byte;
493 return k_ra8_ok;
494}
495
496ra8_err_t ra8_sci_getc_polling(uint8_t channel, uint8_t* out_byte)
497{
498 RA8_CHECK_NULL_PTR(out_byte, s_tag, "getc: out_byte");
499 volatile r_sci_regs_t* reg = internal_reg(channel);
500 if (reg == nullptr) {
502 }
503 /* HUM Ch 38.2.17 "CSR : Common Status Register", p 2225 -- spin
504 * until RDRF = 1 (receive data full). */
505 const uint32_t mask = (1U << k_ra8_sci_csr_bit_rdrf);
507 if (werr != k_ra8_ok) {
508 return werr;
509 }
510 /* HUM Ch 38.2.2 "RDR : Receive Data Register", p 2180 -- RDAT[7:0]
511 * holds the byte just received in 8-bit async mode. */
512 *out_byte = (uint8_t)(reg->RDR & k_ra8_sci_rdr_mask_data8);
513 return k_ra8_ok;
514}
515
516ra8_err_t ra8_sci_write_polling(uint8_t channel, const uint8_t* data, uint32_t len)
517{
518 if ((data == nullptr) && (len != 0U)) {
519 return k_ra8_err_null_ptr;
520 }
521 volatile r_sci_regs_t* reg = internal_reg(channel);
522 if (reg == nullptr) {
524 }
525 for (uint32_t i = 0U; i < len; ++i) {
526 const ra8_err_t err = ra8_sci_putc_polling(channel, data[i]);
527 if (err != k_ra8_ok) {
528 return err;
529 }
530 }
531 /* HUM Ch 38.2.17 "CSR : Common Status Register", p 2225 -- TDRE
532 * goes high as soon as TDR latches into the shifter, but the byte
533 * may still be on the wire. Wait for TEND so the call only returns
534 * after the last frame is fully transmitted. Mirrors FSP
535 * r_sci_b_uart.c (`R_SCI_B_UART_Close` blocks on TEND for the
536 * same reason before dropping TE). */
537 if (len != 0U) {
538 return internal_wait_tx_end(reg);
539 }
540 return k_ra8_ok;
541}
542
543ra8_err_t ra8_sci_flush(uint8_t channel)
544{
545 volatile r_sci_regs_t* reg = internal_reg(channel);
546 if (reg == nullptr) {
548 }
549 /* HUM Ch 38.2.17 "CSR : Common Status Register", p 2225 -- block on
550 * TEND so the shift register has fully drained before the caller
551 * proceeds (typically into a panic_halt / WFI that would gate the
552 * SCI clock and discard in-flight bytes). */
553 return internal_wait_tx_end(reg);
554}
555
556/* ---- Interrupt handler attach ---------------------------------------- */
557
559{
560 volatile r_sci_regs_t* reg = internal_reg(channel);
561 if (reg == nullptr) {
563 }
564 /* The RXI ISR reads rx_fn/rx_ctx and read-modify-writes CCR0; mask it
565 * while we publish the handler and toggle RIE so neither a torn callback
566 * pointer nor a lost CCR0 update is observable. */
567 const uint32_t rie = (1U << k_ra8_sci_ccr0_bit_rie);
570 s_sci_state[channel].rx_fn = fn;
571 s_sci_state[channel].rx_ctx = ctx;
572 /* HUM Ch 38.2.5 "CCR0 : Common Control Register 0", p 2182 -- toggle
573 * RIE (bit 16). */
574 if (fn != nullptr) {
575 reg->CCR0 = reg->CCR0 | rie;
576 } else {
577 reg->CCR0 = reg->CCR0 & ~rie;
578 }
580 return k_ra8_ok;
581}
582
584{
585 volatile r_sci_regs_t* reg = internal_reg(channel);
586 if (reg == nullptr) {
588 }
589 /* The TXI ISR reads tx_fn/tx_ctx and read-modify-writes CCR0; mask it
590 * while we publish the handler and toggle TIE. */
591 const uint32_t tie = (1U << k_ra8_sci_ccr0_bit_tie);
594 s_sci_state[channel].tx_fn = fn;
595 s_sci_state[channel].tx_ctx = ctx;
596 /* HUM Ch 38.2.5 "CCR0 : Common Control Register 0", p 2182 -- toggle
597 * TIE (bit 20). */
598 if (fn != nullptr) {
599 reg->CCR0 = reg->CCR0 | tie;
600 } else {
601 reg->CCR0 = reg->CCR0 & ~tie;
602 }
604 return k_ra8_ok;
605}
606
607/* ---- Error status ----------------------------------------------------- */
608
609ra8_err_t ra8_sci_get_errors(uint8_t channel, uint8_t* out_mask)
610{
611 RA8_CHECK_NULL_PTR(out_mask, s_tag, "get_errors: out");
612 volatile const r_sci_regs_t* reg = internal_reg(channel);
613 if (reg == nullptr) {
615 }
616 uint8_t mask = k_ra8_sci_err_none;
617 /* HUM Ch 38.2.17 "CSR : Common Status Register", p 2225 -- read the
618 * three error flags out of the 32-bit status word. */
619 const uint32_t csr = reg->CSR;
620 if ((csr & (1U << k_ra8_sci_csr_bit_orer)) != 0U) {
621 mask |= k_ra8_sci_err_overrun;
622 }
623 if ((csr & (1U << k_ra8_sci_csr_bit_fer)) != 0U) {
624 mask |= k_ra8_sci_err_framing;
625 }
626 if ((csr & (1U << k_ra8_sci_csr_bit_per)) != 0U) {
627 mask |= k_ra8_sci_err_parity;
628 }
629 *out_mask = mask;
630 return k_ra8_ok;
631}
632
634{
635 volatile r_sci_regs_t* reg = internal_reg(channel);
636 if (reg == nullptr) {
638 }
639 /* HUM Ch 38.2.24 "CFCLR : Common Flag Clear Register", p 2238 --
640 * write-1-to-clear lines for ORER / FER / PER. */
643 return k_ra8_ok;
644}
645
646/* ---- Runtime reconfigure --------------------------------------------- */
647
648ra8_err_t ra8_sci_set_baud(uint8_t channel, uint32_t baud, uint32_t pclk_hz)
649{
650 volatile r_sci_regs_t* reg = internal_reg(channel);
651 if (reg == nullptr) {
653 }
654 if (baud == 0U) {
656 }
657 const uint8_t brr = internal_brr(pclk_hz, baud);
658 /* Guard the CCR2 read-modify-write against any SCI ISR that stores to
659 * this channel's control registers: an interrupt landing between the
660 * CCR2 read and the write-back would otherwise drop the freshly merged
661 * BRR field (lost update). The mask is a no-op when uncontended, so the
662 * final CCR2 value is byte-identical to the unguarded path. */
665 /* HUM Ch 38.2.7 "CCR2 : Common Control Register 2", p 2189 -- BRR
666 * lives in CCR2[15:8]; preserve the rest of CCR2. */
667 uint32_t v = reg->CCR2;
669 v |= ((uint32_t)brr << k_ra8_sci_ccr2_shift_brr);
670 reg->CCR2 = v;
672 return k_ra8_ok;
673}
674
675/* ---- Power transition ------------------------------------------------- */
676
678{
679 volatile r_sci_regs_t* reg = internal_reg(channel);
680 if (reg == nullptr) {
682 }
683 /* HUM Ch 38.2.5 "CCR0 : Common Control Register 0", p 2182 */
684 reg->CCR0 = 0U;
685 return ra8_mstp_disable(s_mstp_table[channel]);
686}
687
689{
690 if (channel > k_ra8_sci_channel_max_index) {
692 }
693 return ra8_mstp_enable(s_mstp_table[channel]);
694}
695
696/* ---- Async byte-stream TX / RX (FSP Read/Write parity) --------------- */
697
715
717ra8_sci_baud_calculate(uint32_t baud, uint32_t pclk_hz, uint16_t* brr_out, uint8_t* clk_div_out)
718{
719 RA8_CHECK_NULL_PTR(brr_out, s_tag, "baud_calc: brr_out");
720 RA8_CHECK_NULL_PTR(clk_div_out, s_tag, "baud_calc: clk_div_out");
721 if ((baud == 0U) || (pclk_hz == 0U)) {
723 }
724
725 /* HUM Ch 38.2.7 "CCR2 : Common Control Register 2", p 2189 -- walk
726 * CKS = 0..3 and pick the smallest divider that yields a BRR <= 255.
727 * Mirrors the FSP `R_SCI_B_UART_BaudCalculate` outer loop
728 * (r_sci_b_uart.c) but without the bit-rate-modulation pass
729 * since the project always programs BRME=0. */
730 uint64_t divisor = (uint64_t)k_ra8_sci_baud_n0_divisor;
731 for (uint8_t n = 0U; n <= (uint8_t)k_ra8_sci_baud_cks_max; ++n) {
732 const uint64_t denom = divisor * (uint64_t)baud;
733 const uint64_t quotient = (uint64_t)pclk_hz / denom;
734 if (quotient > 0U) {
735 const uint64_t candidate = quotient - 1U;
736 if (candidate <= (uint64_t)k_ra8_sci_baud_brr_max) {
737 *brr_out = (uint16_t)candidate;
738 *clk_div_out = n;
739 return k_ra8_ok;
740 }
741 }
742 divisor *= (uint64_t)k_ra8_sci_baud_div_step;
743 }
745}
746
747ra8_err_t ra8_sci_write(uint8_t channel, const uint8_t* data, uint32_t len)
748{
749 if ((data == nullptr) && (len != 0U)) {
750 return k_ra8_err_null_ptr;
751 }
752 volatile r_sci_regs_t* reg = internal_reg(channel);
753 if (reg == nullptr) {
755 }
756 if (!s_sci_state[channel].initialized) {
758 }
759 if (s_sci_state[channel].tx_len != 0U) {
760 return k_ra8_err_busy;
761 }
762 if (len == 0U) {
763 return k_ra8_ok;
764 }
765 /* Publish the async TX descriptor and arm TIE atomically w.r.t. the
766 * TXI ISR: it tests tx_len then dereferences tx_buf, so a torn publish
767 * (or a CCR0 RMW racing the ISR's TIE clear) must not be observable. */
770 s_sci_state[channel].tx_buf = data;
771 s_sci_state[channel].tx_len = len;
772 s_sci_state[channel].tx_idx = 0U;
773 /* HUM Ch 38.2.5 "CCR0 : Common Control Register 0", p 2182 -- arm
774 * TIE so the next TDRE event fires the dispatcher. Mirrors FSP
775 * r_sci_b_uart.c which sets TE | TIE in a single store. */
776 reg->CCR0 = reg->CCR0 | (1U << k_ra8_sci_ccr0_bit_tie);
778 return k_ra8_ok;
779}
780
781ra8_err_t ra8_sci_read(uint8_t channel, uint8_t* buf, uint32_t len)
782{
783 if ((buf == nullptr) && (len != 0U)) {
784 return k_ra8_err_null_ptr;
785 }
786 volatile r_sci_regs_t* reg = internal_reg(channel);
787 if (reg == nullptr) {
789 }
790 if (!s_sci_state[channel].initialized) {
792 }
793 if (s_sci_state[channel].rx_len != 0U) {
794 return k_ra8_err_busy;
795 }
796 if (len == 0U) {
797 return k_ra8_ok;
798 }
799 /* Publish the async RX descriptor and arm RIE atomically w.r.t. the
800 * RXI ISR (it tests rx_len then writes through rx_buf). */
803 s_sci_state[channel].rx_buf = buf;
804 s_sci_state[channel].rx_len = len;
805 s_sci_state[channel].rx_idx = 0U;
806 /* HUM Ch 38.2.5 "CCR0 : Common Control Register 0", p 2182 -- arm
807 * RIE so the next RDRF event fires the dispatcher. Mirrors FSP
808 * r_sci_b_uart.c which stashes p_rx_dest / rx_dest_bytes for
809 * use by `rxi_isr`. */
810 reg->CCR0 = reg->CCR0 | (1U << k_ra8_sci_ccr0_bit_rie);
812 return k_ra8_ok;
813}
814
815ra8_err_t ra8_sci_abort(uint8_t channel, ra8_sci_dir_t direction)
816{
817 volatile r_sci_regs_t* reg = internal_reg(channel);
818 if (reg == nullptr) {
820 }
821 if ((direction != k_ra8_sci_dir_tx) && (direction != k_ra8_sci_dir_rx) &&
822 (direction != k_ra8_sci_dir_both)) {
824 }
825 /* Disarm and tear down the async descriptor atomically w.r.t. the
826 * TXI/RXI ISR. Without the mask, the ISR can latch tx_len > 0, take an
827 * interrupt while this path nulls tx_buf, then dereference the stale
828 * NULL -- a use-after-free / NULL deref in interrupt context.
829 * HUM Ch 38.2.5 "CCR0 : Common Control Register 0", p 2182 */
832 if ((direction & k_ra8_sci_dir_tx) != 0U) {
833 const uint32_t tie_teie = (1U << k_ra8_sci_ccr0_bit_tie) | (1U << k_ra8_sci_ccr0_bit_teie);
834 reg->CCR0 = reg->CCR0 & ~tie_teie;
835 s_sci_state[channel].tx_buf = nullptr;
836 s_sci_state[channel].tx_len = 0U;
837 s_sci_state[channel].tx_idx = 0U;
838 }
839 if ((direction & k_ra8_sci_dir_rx) != 0U) {
840 const uint32_t rie = (1U << k_ra8_sci_ccr0_bit_rie);
841 reg->CCR0 = reg->CCR0 & ~rie;
842 s_sci_state[channel].rx_buf = nullptr;
843 s_sci_state[channel].rx_len = 0U;
844 s_sci_state[channel].rx_idx = 0U;
845 }
847 return k_ra8_ok;
848}
849
850ra8_err_t ra8_sci_read_stop(uint8_t channel, uint32_t* remaining)
851{
852 RA8_CHECK_NULL_PTR(remaining, s_tag, "read_stop: remaining");
853 volatile r_sci_regs_t* reg = internal_reg(channel);
854 if (reg == nullptr) {
856 }
857 /* Mirror FSP `R_SCI_B_UART_ReadStop` r_sci_b_uart.c: stash the
858 * pre-stop count, zero state, then disarm RIE. */
859 /* Snapshot the residual count, null the descriptor, and disarm RIE
860 * atomically w.r.t. the RXI ISR so the reported remaining matches the
861 * state we tear down (and the ISR cannot deref a half-nulled rx_buf). */
862 const uint32_t rie = (1U << k_ra8_sci_ccr0_bit_rie);
865 const uint32_t pending = (s_sci_state[channel].rx_len > s_sci_state[channel].rx_idx)
866 ? (s_sci_state[channel].rx_len - s_sci_state[channel].rx_idx)
867 : 0U;
868 *remaining = pending;
869 s_sci_state[channel].rx_buf = nullptr;
870 s_sci_state[channel].rx_len = 0U;
871 s_sci_state[channel].rx_idx = 0U;
872 /* HUM Ch 38.2.5 "CCR0 : Common Control Register 0", p 2182 */
873 reg->CCR0 = reg->CCR0 & ~rie;
875 return k_ra8_ok;
876}
877
879{
880 volatile r_sci_regs_t* reg = internal_reg(channel);
881 if (reg == nullptr) {
883 }
884 /* HUM Ch 38.2.5 "CCR0 : Common Control Register 0", p 2182 -- drop
885 * RE to silence the RX shift register. FSP returns UNSUPPORTED here;
886 * we approximate the feature by toggling CCR0.RE so RXI stops firing
887 * and the FIFO/RDR stops accepting fresh frames. Guard the RMW against
888 * the RXI ISR's own CCR0 update. */
889 const uint32_t re = (1U << k_ra8_sci_ccr0_bit_re);
892 reg->CCR0 = reg->CCR0 & ~re;
894 return k_ra8_ok;
895}
896
898{
899 volatile r_sci_regs_t* reg = internal_reg(channel);
900 if (reg == nullptr) {
902 }
903 /* HUM Ch 38.2.5 "CCR0 : Common Control Register 0", p 2182 -- guard the
904 * RE RMW against the RXI ISR's concurrent CCR0 update. */
905 const uint32_t re = (1U << k_ra8_sci_ccr0_bit_re);
908 reg->CCR0 = reg->CCR0 | re;
910 return k_ra8_ok;
911}
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_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#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_init_failed
Hardware peripheral failed to initialise.
Definition ra8_err.h:290
@ k_ra8_err_busy
Resource busy – blocking operation cannot proceed.
Definition ra8_err.h:195
@ 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
@ k_ra8_hw_budget_medium
RA8 hw budget medium.
Definition ra8_hw_err.h:173
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_info_val(tag, message, value)
RA8 log info val.
Definition ra8_log.h:366
#define ra8_log_error_val(tag, message, value)
RA8 log error val.
Definition ra8_log.h:337
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
Module Stop Control (MSTP) register layout for the Renesas RA8D2.
ra8_mstp_t
Packed (reg << 8) | bit module-stop identifier.
@ k_ra8_mstp_sci2
MSTPB29 SCI2.
@ k_ra8_mstp_sci4
MSTPB27 SCI4.
@ k_ra8_mstp_sci7
MSTPB24 SCI7.
@ k_ra8_mstp_sci9
MSTPB22 SCI9.
@ k_ra8_mstp_sci0
MSTPB31 SCI0.
@ k_ra8_mstp_sci5
MSTPB26 SCI5.
@ k_ra8_mstp_sci1
MSTPB30 SCI1.
@ k_ra8_mstp_sci6
MSTPB25 SCI6.
@ k_ra8_mstp_sci8
MSTPB23 SCI8.
@ k_ra8_mstp_sci3
MSTPB28 SCI3.
IRQ-masked read-modify-write helper for shared registers.
static void ra8_register_guard_exit(const ra8_register_guard_t *guard)
Exit a critical section: restore PRIMASK.
static void ra8_register_guard_enter(ra8_register_guard_t *guard)
Enter a critical section: save PRIMASK, mask interrupts.
ra8_err_t ra8_sci_exit_stop(uint8_t channel)
Exit MSTP-gated stop state; the channel must be re-init'd.
Definition ra8_sci.c:688
ra8_err_t ra8_sci_write_polling(uint8_t channel, const uint8_t *data, uint32_t len)
Send len bytes by polling (convenience wrapper).
Definition ra8_sci.c:516
ra8_err_t ra8_sci_attach_rx_handler(uint8_t channel, ra8_sci_rx_fn_t fn, void *ctx)
Install the RX interrupt callback + context.
Definition ra8_sci.c:558
static volatile r_sci_regs_t * internal_reg(uint8_t channel)
Validate channel and return the register pointer.
Definition ra8_sci.c:122
ra8_err_t ra8_sci_set_baud(uint8_t channel, uint32_t baud, uint32_t pclk_hz)
Change the baud rate without tearing down the channel.
Definition ra8_sci.c:648
static uint32_t internal_ccr3(const ra8_sci_cfg_t *cfg)
Build the CCR3 value for an async-UART config descriptor.
Definition ra8_sci.c:219
ra8_err_t ra8_sci_baud_calculate(uint32_t baud, uint32_t pclk_hz, uint16_t *brr_out, uint8_t *clk_div_out)
Pure-math conversion from a target baud rate to BRR + clock divider settings.
Definition ra8_sci.c:717
ra8_err_t ra8_sci_abort(uint8_t channel, ra8_sci_dir_t direction)
Cancel an in-flight async TX or RX.
Definition ra8_sci.c:815
static void internal_clear_csr_flags(volatile r_sci_regs_t *reg)
Clear every stale CSR / FFCLR latch on a freshly-opened channel.
Definition ra8_sci.c:274
static uint8_t internal_brr(uint32_t pclk_hz, uint32_t baud)
Compute the 8-bit BRR value from a target baud and PCLKB.
Definition ra8_sci.c:155
ra8_err_t ra8_sci_clear_errors(uint8_t channel)
Clear the SSR error flags via write-zero.
Definition ra8_sci.c:633
ra8_err_t ra8_sci_read(uint8_t channel, uint8_t *buf, uint32_t len)
Arm an interrupt-driven RX of len bytes into buf.
Definition ra8_sci.c:781
ra8_err_t ra8_sci_init(uint8_t channel, const ra8_sci_cfg_t *cfg)
Initialise an SCI channel using the descriptor.
Definition ra8_sci.c:410
ra8_err_t ra8_sci_enter_stop(uint8_t channel)
Put the channel into MSTP-gated stop state.
Definition ra8_sci.c:677
static const ra8_mstp_t s_mstp_table[k_ra8_sci_channel_count_val]
Channel-index -> MSTP id lookup.
Definition ra8_sci.c:100
ra8_err_t ra8_sci_attach_tx_handler(uint8_t channel, ra8_sci_tx_fn_t fn, void *ctx)
Install the TX interrupt callback + context.
Definition ra8_sci.c:583
ra8_err_t ra8_sci_getc_polling(uint8_t channel, uint8_t *out_byte)
Poll-receive one byte (blocking, bounded spin).
Definition ra8_sci.c:496
static ra8_err_t internal_wait_tx_end(volatile r_sci_regs_t *reg)
Spin until CSR.TEND = 1 or the bounded budget runs out.
Definition ra8_sci.c:312
static uint32_t internal_ccr2(const ra8_sci_cfg_t *cfg)
Build the CCR2 value with BRR programmed.
Definition ra8_sci.c:340
ra8_err_t ra8_sci_receive_resume(uint8_t channel)
Resume reception by setting CCR0.RE.
Definition ra8_sci.c:897
ra8_err_t ra8_sci_receive_suspend(uint8_t channel)
Suspend reception by clearing CCR0.RE.
Definition ra8_sci.c:878
ra8_err_t ra8_sci_putc_polling(uint8_t channel, uint8_t byte)
Poll-send one byte (blocking, bounded by ra8_hw_err spin budget).
Definition ra8_sci.c:476
ra8_err_t ra8_sci_read_stop(uint8_t channel, uint32_t *remaining)
Stop an in-flight RX and report how many bytes were not yet consumed.
Definition ra8_sci.c:850
static void internal_program_ccr_bank(volatile r_sci_regs_t *reg, const ra8_sci_cfg_t *cfg)
Program CCR0..CCR4 + FCR for the requested UART config.
Definition ra8_sci.c:376
ra8_sci_state_t s_sci_state[k_ra8_sci_channel_count_val]
Per-channel allocation + dispatch table.
Definition ra8_sci.c:94
static uint32_t internal_ccr1(const ra8_sci_cfg_t *cfg)
Build the CCR1 value for an async-UART config descriptor.
Definition ra8_sci.c:189
ra8_err_t ra8_sci_write(uint8_t channel, const uint8_t *data, uint32_t len)
Arm an interrupt-driven TX of len bytes from data.
Definition ra8_sci.c:747
ra8_err_t ra8_sci_flush(uint8_t channel)
Block until the channel's transmit shift register is empty.
Definition ra8_sci.c:543
ra8_sci_baud_calc_const_t
Constants used by ra8_sci_baud_calculate.
Definition ra8_sci.c:709
@ k_ra8_sci_baud_cks_max
CKS field is 2 bits.
Definition ra8_sci.c:711
@ k_ra8_sci_baud_n0_divisor
32 * 2^(2*0).
Definition ra8_sci.c:713
@ k_ra8_sci_baud_div_step
Multiplier per CKS step.
Definition ra8_sci.c:712
@ k_ra8_sci_baud_brr_max
BRR is 8 bits wide.
Definition ra8_sci.c:710
ra8_err_t ra8_sci_deinit(uint8_t channel)
Tear down a channel – disable TX/RX, release MSTP.
Definition ra8_sci.c:443
ra8_err_t ra8_sci_get_errors(uint8_t channel, uint8_t *out_mask)
Read the SSR error bits (ORER, FER, PER).
Definition ra8_sci.c:609
Full-featured Serial Communications Interface driver.
bool(* ra8_sci_tx_fn_t)(void *ctx, uint8_t *byte)
TX-empty interrupt callback signature.
Definition ra8_sci.h:141
@ k_ra8_sci_stop_2
RA8 SCI stop 2.
Definition ra8_sci.h:82
@ k_ra8_sci_err_overrun
ORER set.
Definition ra8_sci.h:118
@ k_ra8_sci_err_parity
PER set.
Definition ra8_sci.h:120
@ k_ra8_sci_err_framing
FER set.
Definition ra8_sci.h:119
@ k_ra8_sci_err_none
RA8 SCI error none.
Definition ra8_sci.h:117
void(* ra8_sci_rx_fn_t)(void *ctx, uint8_t byte)
RX interrupt callback signature.
Definition ra8_sci.h:130
@ k_ra8_sci_parity_odd
RA8 SCI parity odd.
Definition ra8_sci.h:73
@ k_ra8_sci_parity_none
RA8 SCI parity none.
Definition ra8_sci.h:71
@ k_ra8_sci_data_7
RA8 SCI data 7.
Definition ra8_sci.h:90
ra8_sci_dir_t
Direction selector for ra8_sci_abort.
Definition ra8_sci.h:150
@ k_ra8_sci_dir_tx
Cancel an in-flight TX.
Definition ra8_sci.h:151
@ k_ra8_sci_dir_both
Cancel both directions.
Definition ra8_sci.h:153
@ k_ra8_sci_dir_rx
Cancel an in-flight RX.
Definition ra8_sci.h:152
src/-local shared surface for the ra8_sci driver TUs.
@ k_ra8_sci_channel_count_val
Total channels tracked.
@ k_ra8_sci_channel_max_index
SCI0..SCI9.
SCI_B (Serial Communication Interface, B variant) register layoutfor the RA8D2.
static volatile r_sci_regs_t * ra8_sci(uint8_t channel)
Get pointer to SCI_B channel N (0..9).
@ k_ra8_sci_ccr0_bit_re
Receive Enable.
@ k_ra8_sci_ccr0_bit_tie
Transmit Interrupt Enable.
@ k_ra8_sci_ccr0_bit_rie
Receive Interrupt Enable.
@ k_ra8_sci_ccr0_bit_teie
Transmit End Interrupt Enable.
@ k_ra8_sci_ccr0_bit_te
Transmit Enable.
@ k_ra8_sci_mddr_default
MDDR reset value (modulation disabled).
@ k_ra8_sci_cfclr_default
Clear every W1C bit at once.
@ k_ra8_sci_rdr_mask_data8
RDAT[7:0] for 8-bit reception.
@ k_ra8_sci_ccr3_bit_lsbf
LSB First.
@ k_ra8_sci_ccr3_bit_bpen
Synchronizer Bypass Enable.
@ k_ra8_sci_ccr3_bit_stp
Stop Bit Length (0=1, 1=2).
@ k_ra8_sci_ccr3_shift_chr
CHR[1:0] data-length field.
@ k_ra8_sci_ccr1_bit_pm
Parity Mode (0=even, 1=odd).
@ k_ra8_sci_ccr1_bit_pe
Parity Enable.
@ k_ra8_sci_ccr1_bit_spb2dt
Serial Port Break Data Select.
@ k_ra8_sci_ccr1_bit_spb2io
Serial Port Break I/O.
@ k_ra8_sci_ccr2_shift_mddr
MDDR[7:0] field shift.
@ k_ra8_sci_ccr2_shift_brr
BRR[7:0] field shift.
@ k_ra8_sci_csr_bit_tend
Transmit End.
@ k_ra8_sci_csr_bit_rdrf
Receive Data Full.
@ k_ra8_sci_csr_bit_tdre
Transmit Data Empty.
@ k_ra8_sci_csr_bit_fer
Framing Error.
@ k_ra8_sci_csr_bit_orer
Overrun Error.
@ k_ra8_sci_csr_bit_per
Parity Error.
@ k_ra8_sci_ffclr_default
Clear FRSR.DR latch.
@ k_ra8_sci_brr_async_divisor
64 * 2^(2*0 - 1) for n = 0.
@ k_ra8_sci_cfclr_bit_perc
Clear CSR.PER.
@ k_ra8_sci_cfclr_bit_ferc
Clear CSR.FER.
@ k_ra8_sci_cfclr_bit_orerc
Clear CSR.ORER.
@ k_ra8_sci_ccr3_chr_8bit
10 = 8-bit data (initial value).
@ k_ra8_sci_ccr3_chr_7bit
11 = 7-bit data.
@ k_ra8_sci_ccr2_mask_brr_field
BRR[15:8] in CCR2.
Per-channel SCI_B register window.
volatile uint32_t CCR4
+0x18 Common Control 4.
volatile uint32_t FCR
+0x24 FIFO Control.
volatile uint32_t FFCLR
+0x70 FIFO Flag Clear.
volatile uint32_t CSR
+0x48 Common Status.
volatile uint32_t RDR
+0x00 Receive Data.
volatile uint32_t CCR2
+0x10 Common Control 2.
volatile uint32_t TDR
+0x04 Transmit Data.
volatile uint32_t CCR1
+0x0C Common Control 1.
volatile uint32_t CCR3
+0x14 Common Control 3.
volatile uint32_t CCR0
+0x08 Common Control 0.
volatile uint32_t CFCLR
+0x68 Common Flag Clear.
Opaque save-restore handle for IRQ masking.
Configuration descriptor for ra8_sci_init.
Definition ra8_sci.h:103
uint32_t pclk_hz
PCLKB frequency in Hz (used for BRR calculation).
Definition ra8_sci.h:108
ra8_sci_parity_t parity
Parity mode.
Definition ra8_sci.h:106
ra8_sci_stop_bits_t stop_bits
1 or 2 stop bits.
Definition ra8_sci.h:107
uint32_t baud
Target baud rate in bps.
Definition ra8_sci.h:104
ra8_sci_data_bits_t data_bits
7 or 8 data bits.
Definition ra8_sci.h:105
Per-channel dispatch state.