ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_sci_dma_isr.c
Go to the documentation of this file.
1
26
27#include <stdint.h>
28
29#include "ra8_attributes.h"
30#include "ra8_check.h"
31#include "ra8_dma.h"
32#include "ra8_dmac.h"
33#include "ra8_err.h"
34#include "ra8_sci.h"
35#include "ra8_sci_internal.h"
36#include "ra8_sci_regs.h"
37
38static const char* s_tag = "SCI";
39
65RA8_INTERNAL static ra8_err_t internal_dma_args_ok(const volatile r_sci_regs_t* reg, uint16_t len)
66{
67 ra8_err_t err = k_ra8_ok;
68 if (reg == nullptr) {
70 }
71 if (len == 0U) {
73 }
74 return err;
75}
76
77/* ---- DMA TX / RX ----------------------------------------- */
78
79/* Build a DMA request descriptor for byte-stream to/from SCI TDR/RDR -- see surrounding code and HUM citations. */
81 uintptr_t dst,
82 uint16_t len,
83 bool src_inc,
84 bool dst_inc,
85 ra8_dma_complete_fn_t on_complete,
86 void* ctx)
87{
88 ra8_dma_request_t req = {};
89 req.src_addr = src;
90 req.dst_addr = dst;
91 req.count = len;
93 req.src_inc = src_inc;
94 req.dst_inc = dst_inc;
95 /* HUM Ch 19 "Event Link Controller (ELC)" p 817 -- trigger routing is a
96 * task; until then use software-start and drive the first
97 * element from the polling path or rely on ra8_fake_dma for host tests. */
98 req.trigger = (ra8_elc_event_t)0;
99 req.on_complete = on_complete;
100 req.ctx = ctx;
101 return req;
102}
103
105 const uint8_t* data,
106 uint16_t len,
107 ra8_dma_complete_fn_t on_complete,
108 void* ctx,
109 uint8_t* out_dma_channel)
110{
111 RA8_CHECK_NULL_PTR(data, s_tag, "write_dma: data");
112 RA8_CHECK_NULL_PTR(out_dma_channel, s_tag, "write_dma: out_dma_channel");
113 volatile r_sci_regs_t* reg = ra8_sci(channel);
114 const ra8_err_t args_ok = internal_dma_args_ok(reg, len);
115 if (args_ok != k_ra8_ok) {
116 return args_ok;
117 }
118 /* HUM Ch 38.2.3 "TDR : Transmit Data Register", p 2181 -- DMA writes
119 * land in TDR; the engine streams one byte per element while the
120 * source increments across data[]. */
121 const ra8_dma_request_t req = internal_make_dma_request((uintptr_t)data,
122 (uintptr_t)&reg->TDR,
123 len,
124 /*src_inc=*/true,
125 /*dst_inc=*/false,
126 on_complete,
127 ctx);
128 return ra8_dma_request(&req, out_dma_channel);
129}
130
131/* out_buf is written by the DMAC engine via the dst_addr path, not
132 * through the pointer directly, so clang-tidy would otherwise flag
133 * it as a const candidate. */
135 uint8_t* out_buf,
136 uint16_t len,
137 ra8_dma_complete_fn_t on_complete,
138 void* ctx,
139 uint8_t* out_dma_channel)
140{
141 RA8_CHECK_NULL_PTR(out_buf, s_tag, "read_dma: out_buf");
142 RA8_CHECK_NULL_PTR(out_dma_channel, s_tag, "read_dma: out_dma_channel");
143 volatile r_sci_regs_t* reg = ra8_sci(channel);
144 const ra8_err_t args_ok = internal_dma_args_ok(reg, len);
145 if (args_ok != k_ra8_ok) {
146 return args_ok;
147 }
148 /* HUM Ch 38.2.2 "RDR : Receive Data Register", p 2180 -- RDR is
149 * read-once per element; destination increments across out_buf[]. */
150 const ra8_dma_request_t req = internal_make_dma_request((uintptr_t)&reg->RDR,
151 (uintptr_t)out_buf,
152 len,
153 /*src_inc=*/false,
154 /*dst_inc=*/true,
155 on_complete,
156 ctx);
157 return ra8_dma_request(&req, out_dma_channel);
158}
159
160/* ---- ISR dispatch ----------------------------------------------------- */
161
163void ra8_sci_dispatch_txi(uint8_t channel)
164{
165 if (channel > k_ra8_sci_channel_max_index) {
166 return;
167 }
168 volatile r_sci_regs_t* reg = ra8_sci(channel);
169 if (reg == nullptr) { /* GCOVR_EXCL_BR_LINE -- bounds already validated */
170 return;
171 }
172 const ra8_sci_tx_fn_t cb = s_sci_state[channel].tx_fn;
173 void* const ctx = s_sci_state[channel].tx_ctx;
174 const uint32_t tie = (1U << k_ra8_sci_ccr0_bit_tie);
175
176 /* Async byte-stream path (ra8_sci_write). Mirrors FSP r_sci_b_uart
177 * `txi_isr` (r_sci_b_uart.c) which decrements `tx_src_bytes`
178 * each TXI and clears TIE when the count hits zero. */
179 if (s_sci_state[channel].tx_len > 0U) {
180 if (s_sci_state[channel].tx_idx < s_sci_state[channel].tx_len) {
181 const uint8_t byte = s_sci_state[channel].tx_buf[s_sci_state[channel].tx_idx];
182 s_sci_state[channel].tx_idx += 1U;
183 /* HUM Ch 38.2.3 "TDR : Transmit Data Register", p 2181 */
184 reg->TDR = (uint32_t)byte;
185 /* Fire user-attached TX visibility callback per byte; its
186 * boolean return is ignored here because the async path owns
187 * the byte-stream now. */
188 if (cb != nullptr) {
189 uint8_t echo = byte;
190 (void)cb(ctx, &echo);
191 }
192 }
193 if (s_sci_state[channel].tx_idx >= s_sci_state[channel].tx_len) {
194 /* HUM Ch 38.2.5 "CCR0 : Common Control Register 0", p 2182 */
195 reg->CCR0 = reg->CCR0 & ~tie;
196 s_sci_state[channel].tx_buf = nullptr;
197 s_sci_state[channel].tx_len = 0U;
198 s_sci_state[channel].tx_idx = 0U;
199 }
200 return;
201 }
202
203 /* Legacy callback-only path (ra8_sci_attach_tx_handler). */
204 if (cb == nullptr) {
205 /* HUM Ch 38.2.5 "CCR0 : Common Control Register 0", p 2182 */
206 reg->CCR0 = reg->CCR0 & ~tie;
207 return;
208 }
209 uint8_t byte = 0U;
210 if (cb(ctx, &byte)) {
211 /* HUM Ch 38.2.3 "TDR : Transmit Data Register", p 2181 */
212 reg->TDR = (uint32_t)byte;
213 } else {
214 reg->CCR0 = reg->CCR0 & ~tie;
215 }
216}
217
219void ra8_sci_dispatch_rxi(uint8_t channel)
220{
221 if (channel > k_ra8_sci_channel_max_index) {
222 return;
223 }
224 volatile r_sci_regs_t* reg = ra8_sci(channel);
225 if (reg == nullptr) { /* GCOVR_EXCL_BR_LINE -- bounds already validated */
226 return;
227 }
228 const ra8_sci_rx_fn_t cb = s_sci_state[channel].rx_fn;
229 void* const ctx = s_sci_state[channel].rx_ctx;
230 /* HUM Ch 38.2.2 "RDR : Receive Data Register", p 2180 */
231 const uint8_t b = (uint8_t)(reg->RDR & k_ra8_sci_rdr_mask_data8);
232
233 /* Async byte-stream path (ra8_sci_read). Mirrors FSP r_sci_b_uart
234 * `rxi_isr` which appends each byte into `p_rx_dest` until
235 * `rx_dest_bytes` is satisfied, then signals UART_EVENT_RX_COMPLETE. */
236 if (s_sci_state[channel].rx_len > 0U) {
237 if (s_sci_state[channel].rx_idx < s_sci_state[channel].rx_len) {
238 s_sci_state[channel].rx_buf[s_sci_state[channel].rx_idx] = b;
239 s_sci_state[channel].rx_idx += 1U;
240 }
241 if (s_sci_state[channel].rx_idx >= s_sci_state[channel].rx_len) {
242 const uint32_t rie = (1U << k_ra8_sci_ccr0_bit_rie);
243 /* HUM Ch 38.2.5 "CCR0 : Common Control Register 0", p 2182 */
244 reg->CCR0 = reg->CCR0 & ~rie;
245 s_sci_state[channel].rx_buf = nullptr;
246 s_sci_state[channel].rx_len = 0U;
247 s_sci_state[channel].rx_idx = 0U;
248 }
249 }
250
251 /* Legacy attach path: still fires per byte even when an async RX is
252 * in flight, so existing flow-control hooks keep working. */
253 if (cb != nullptr) {
254 cb(ctx, b);
255 }
256}
257
259void ra8_sci_dispatch_eri(uint8_t channel)
260{
261 if (channel > k_ra8_sci_channel_max_index) {
262 return;
263 }
264 (void)ra8_sci_clear_errors(channel);
265}
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_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Generic DMA transfer substrate (DMAC engine).
ra8_err_t ra8_dma_request(const ra8_dma_request_t *req, uint8_t *out_channel)
Allocate a DMAC channel, programme it, and start the trigger wiring.
Definition ra8_dma.c:308
void(* ra8_dma_complete_fn_t)(void *ctx)
Caller-supplied completion callback.
Definition ra8_dma.h:88
8-channel DMA controller (DMAC0) driver
@ k_ra8_dmac_width_byte
8-bit transfers (DMTMD.SZ = 00b).
Definition ra8_dmac.h:51
ra8_elc_event_t
Partial list of ELC events (populate as drivers need them).
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
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
ra8_sci_state_t s_sci_state[k_ra8_sci_channel_count_val]
Per-channel allocation + dispatch table.
Definition ra8_sci.c:94
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
ra8_err_t ra8_sci_clear_errors(uint8_t channel)
Clear the SSR error flags via write-zero.
Definition ra8_sci.c:633
void(* ra8_sci_rx_fn_t)(void *ctx, uint8_t byte)
RX interrupt callback signature.
Definition ra8_sci.h:130
ra8_err_t ra8_sci_write_dma(uint8_t channel, const uint8_t *data, uint16_t len, ra8_dma_complete_fn_t on_complete, void *ctx, uint8_t *out_dma_channel)
Kick off a DMA-backed TX transfer.
static ra8_dma_request_t internal_make_dma_request(uintptr_t src, uintptr_t dst, uint16_t len, bool src_inc, bool dst_inc, ra8_dma_complete_fn_t on_complete, void *ctx)
void ra8_sci_dispatch_eri(uint8_t channel)
ERI dispatch – clear SSR error flags, invoke optional error callback (none in reserved for 3....
ra8_err_t ra8_sci_read_dma(uint8_t channel, uint8_t *out_buf, uint16_t len, ra8_dma_complete_fn_t on_complete, void *ctx, uint8_t *out_dma_channel)
Kick off a DMA-backed RX transfer.
static ra8_err_t internal_dma_args_ok(const volatile r_sci_regs_t *reg, uint16_t len)
Report whether a DMA entry point's channel register and length are usable.
void ra8_sci_dispatch_rxi(uint8_t channel)
RXI dispatch – hand a received byte to the RX callback.
void ra8_sci_dispatch_txi(uint8_t channel)
TXI dispatch – advance the TX callback.
src/-local shared surface for the ra8_sci driver TUs.
@ 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_tie
Transmit Interrupt Enable.
@ k_ra8_sci_ccr0_bit_rie
Receive Interrupt Enable.
@ k_ra8_sci_rdr_mask_data8
RDAT[7:0] for 8-bit reception.
Per-channel SCI_B register window.
volatile uint32_t RDR
+0x00 Receive Data.
volatile uint32_t TDR
+0x04 Transmit Data.
volatile uint32_t CCR0
+0x08 Common Control 0.
Descriptor for a single DMA transfer.
Definition ra8_dma.h:115
ra8_dma_complete_fn_t on_complete
On complete.
Definition ra8_dma.h:123
uintptr_t dst_addr
Dst address.
Definition ra8_dma.h:117
bool dst_inc
Dst inc.
Definition ra8_dma.h:121
ra8_dmac_width_t width
Width.
Definition ra8_dma.h:119
bool src_inc
Src inc.
Definition ra8_dma.h:120
uint16_t count
Count.
Definition ra8_dma.h:118
uintptr_t src_addr
Src address.
Definition ra8_dma.h:116
void * ctx
Ctx.
Definition ra8_dma.h:124
ra8_elc_event_t trigger
Trigger.
Definition ra8_dma.h:122