ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_sci_spi.c
Go to the documentation of this file.
1
26
27#include "ra8_sci_spi.h"
28
29#include <stdint.h>
30
31#include "ra8_attributes.h"
32#include "ra8_check.h"
33#include "ra8_err.h"
34#include "ra8_hw_err.h"
35#include "ra8_mstp.h"
36#include "ra8_mstp_regs.h"
37#include "ra8_sci_regs.h"
38
39static const char* s_tag = "SCI_SPI";
40
52
69
70/* =============================================================================
71 * Bit-rate helper
72 * =============================================================================
73 */
74
96RA8_INTERNAL static void
97internal_resolve_rate(uint32_t baud_hz, uint32_t pclk_hz, uint32_t* out_cks, uint32_t* out_brr)
98{
99 for (uint32_t cks = 0U; cks <= (uint32_t)k_ra8_sci_spi_cks_max; cks++) {
100 const uint32_t divisor = (uint32_t)k_ra8_sci_spi_div_base << (2U * cks);
101 const uint32_t denom = divisor * baud_hz;
102 const uint32_t q = pclk_hz / denom;
103 if (q == 0U) {
104 /* Requested rate exceeds this CKS ceiling -> fastest (BRR = 0). */
105 *out_cks = cks;
106 *out_brr = 0U;
107 return;
108 }
109 if ((q - 1U) <= (uint32_t)k_ra8_sci_spi_brr_max) {
110 *out_cks = cks;
111 *out_brr = q - 1U;
112 return;
113 }
114 }
115 /* Unreachably slow: clamp to the slowest divider. */
116 *out_cks = (uint32_t)k_ra8_sci_spi_cks_max;
117 *out_brr = (uint32_t)k_ra8_sci_spi_brr_max;
118}
119
137RA8_INTERNAL static void
138internal_apply_rate(volatile r_sci_regs_t* reg, uint32_t baud_hz, uint32_t pclk_hz)
139{
140 uint32_t cks = 0U;
141 uint32_t brr = 0U;
142 internal_resolve_rate(baud_hz, pclk_hz, &cks, &brr);
143 /* HUM Ch 38.2.7 "CCR2 : Common Control Register 2" p 2189 */
144 uint32_t ccr2 =
145 (brr << (uint32_t)k_ra8_sci_ccr2_shift_brr) & (uint32_t)k_ra8_sci_ccr2_mask_brr_field;
146 ccr2 |= (cks << (uint32_t)k_ra8_sci_ccr2_shift_cks) & (uint32_t)k_ra8_sci_ccr2_mask_cks_field;
147 ccr2 |= ((uint32_t)k_ra8_sci_mddr_default << (uint32_t)k_ra8_sci_ccr2_shift_mddr);
148 reg->CCR2 = ccr2;
149}
150
169{
170 uint32_t ccr3 = ((uint32_t)k_ra8_sci_ccr3_mod_simple_spi << (uint32_t)k_ra8_sci_ccr3_shift_mod);
171 ccr3 |= ((uint32_t)k_ra8_sci_ccr3_chr_8bit << (uint32_t)k_ra8_sci_ccr3_shift_chr);
172 /* ra8_spi_mode_t is 0..3 where bit 1 = CPOL and bit 0 = CPHA. */
173 if (((uint32_t)cfg->mode & (uint32_t)k_ra8_spi_mode_2) != 0U) {
174 ccr3 |= (1U << (uint32_t)k_ra8_sci_ccr3_bit_cpol);
175 }
176 if (((uint32_t)cfg->mode & (uint32_t)k_ra8_spi_mode_1) != 0U) {
177 ccr3 |= (1U << (uint32_t)k_ra8_sci_ccr3_bit_cpha);
178 }
179 if (cfg->lsb_first) {
180 ccr3 |= (1U << (uint32_t)k_ra8_sci_ccr3_bit_lsbf);
181 }
182 return ccr3;
183}
184
185ra8_err_t ra8_sci_spi_init(uint8_t channel, const ra8_sci_spi_cfg_t* cfg)
186{
187 RA8_CHECK_NULL_PTR(cfg, s_tag, "spi_init: cfg");
188 if (channel >= (uint8_t)k_ra8_sci_spi_channel_count) {
190 }
191 if (cfg->baud_hz == 0U) {
193 }
194 volatile r_sci_regs_t* reg = ra8_sci(channel);
195 if (reg == nullptr) { /* GCOVR_EXCL_BR_LINE -- bounded channel yields non-null reg */
196 return k_ra8_err_invalid_arg; /* GCOVR_EXCL_LINE -- bounded channel yields non-null reg */
197 }
198 const ra8_err_t mst_err = ra8_mstp_enable(s_mstp_table[channel]);
199 /* GCOVR_EXCL_BR_START -- MSTP HW readback */
200 RA8_RETURN_ON_ERROR(mst_err, s_tag, "spi_init: mstp");
201 /* GCOVR_EXCL_BR_STOP */
202
203 /* HUM Ch 38.2.5 "CCR0 : Common Control Register 0" p 2182 */
204 reg->CCR0 = 0U;
205 reg->CCR1 = 0U;
206 reg->CCR3 = internal_ccr3(cfg);
207 internal_apply_rate(reg, cfg->baud_hz, cfg->pclk_hz);
208 reg->CCR4 = 0U;
209 /* HUM Ch 38.2.24 "CFCLR : Common Flag Clear Register" p 2238 */
210 reg->CFCLR = (uint32_t)k_ra8_sci_cfclr_default;
211 /* HUM Ch 38.2.5 "CCR0 : Common Control Register 0" p 2182 */
212 reg->CCR0 = (1U << (uint32_t)k_ra8_sci_ccr0_bit_te) | (1U << (uint32_t)k_ra8_sci_ccr0_bit_re);
213 return k_ra8_ok;
214}
215
217{
218 if (channel >= (uint8_t)k_ra8_sci_spi_channel_count) {
220 }
221 volatile r_sci_regs_t* reg = ra8_sci(channel);
222 if (reg == nullptr) { /* GCOVR_EXCL_BR_LINE -- bounded channel yields non-null reg */
223 return k_ra8_err_invalid_arg; /* GCOVR_EXCL_LINE -- bounded channel yields non-null reg */
224 }
225 /* HUM Ch 38.2.5 "CCR0 : Common Control Register 0" p 2182 */
226 reg->CCR0 = 0U;
227 return ra8_mstp_disable(s_mstp_table[channel]);
228}
229
230ra8_err_t ra8_sci_spi_set_clock(uint8_t channel, uint32_t baud_hz, uint32_t pclk_hz)
231{
232 if (channel >= (uint8_t)k_ra8_sci_spi_channel_count) {
234 }
235 if (baud_hz == 0U) {
237 }
238 volatile r_sci_regs_t* reg = ra8_sci(channel);
239 if (reg == nullptr) { /* GCOVR_EXCL_BR_LINE -- bounded channel yields non-null reg */
240 return k_ra8_err_invalid_arg; /* GCOVR_EXCL_LINE -- bounded channel yields non-null reg */
241 }
242 /* CCR2 (CKS/BRR) is writable while enabled; TE/RE stay set. */
243 const uint32_t saved_ccr0 = reg->CCR0;
244 reg->CCR0 = 0U;
245 internal_apply_rate(reg, baud_hz, pclk_hz);
246 reg->CCR0 = saved_ccr0;
247 return k_ra8_ok;
248}
249
250ra8_err_t ra8_sci_spi_xfer8(uint8_t channel, uint8_t tx, uint8_t* rx)
251{
252 volatile r_sci_regs_t* reg = ra8_sci(channel);
253 RA8_CHECK_NULL_PTR(reg, s_tag, "spi_xfer8: channel out of range");
254
255 /* HUM Ch 38.2.17 "CSR : Common Status Register" p 2225 */
256 const uint32_t tdre = (1U << (uint32_t)k_ra8_sci_csr_bit_tdre);
258 if (err != k_ra8_ok) {
259 return err;
260 }
261 /* HUM Ch 38.2.3 "TDR : Transmit Data Register" p 2181 */
262 reg->TDR = (uint32_t)tx;
263
264 /* HUM Ch 38.2.17 "CSR : Common Status Register" p 2225 */
265 const uint32_t rdrf = (1U << (uint32_t)k_ra8_sci_csr_bit_rdrf);
267 if (err != k_ra8_ok) {
268 return err;
269 }
270 /* HUM Ch 38.2.2 "RDR : Receive Data Register" p 2180 */
271 const uint8_t received = (uint8_t)(reg->RDR & (uint32_t)k_ra8_sci_rdr_mask_data8);
272 /* HUM Ch 38.2.24 "CFCLR : Common Flag Clear Register" p 2238 */
273 reg->CFCLR = (1U << (uint32_t)k_ra8_sci_cfclr_bit_rdrfc);
274
275 if (rx != nullptr) {
276 *rx = received;
277 }
278 return k_ra8_ok;
279}
280
281ra8_err_t ra8_sci_spi_xfer(uint8_t channel, const uint8_t* tx, uint8_t* rx, uint32_t len)
282{
283 if (channel >= (uint8_t)k_ra8_sci_spi_channel_count) {
285 }
286 for (uint32_t i = 0U; i < len; i++) {
287 const uint8_t out = (tx != nullptr) ? tx[i] : (uint8_t)k_ra8_sci_spi_idle_byte;
288 uint8_t in = 0U;
289 const ra8_err_t err = ra8_sci_spi_xfer8(channel, out, &in);
290 if (err != k_ra8_ok) {
291 return err;
292 }
293 if (rx != nullptr) {
294 rx[i] = in;
295 }
296 }
297 return k_ra8_ok;
298}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#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
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_long
RA8 hw budget long.
Definition ra8_hw_err.h:174
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.
static const ra8_mstp_t s_mstp_table[k_ra8_sci_channel_count_val]
Channel-index -> MSTP id lookup.
Definition ra8_sci.c:100
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_ccr3_mod_simple_spi
Simple SPI.
@ k_ra8_sci_ccr0_bit_re
Receive 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_cpha
Clock Phase (sync only).
@ k_ra8_sci_ccr3_bit_lsbf
LSB First.
@ k_ra8_sci_ccr3_shift_chr
CHR[1:0] data-length field.
@ k_ra8_sci_ccr3_shift_mod
MOD[2:0] mode select.
@ k_ra8_sci_ccr3_bit_cpol
Clock Polarity (sync only).
@ k_ra8_sci_ccr2_shift_mddr
MDDR[7:0] field shift.
@ k_ra8_sci_ccr2_shift_cks
CKS[1:0] field shift.
@ k_ra8_sci_ccr2_shift_brr
BRR[7:0] field shift.
@ k_ra8_sci_csr_bit_rdrf
Receive Data Full.
@ k_ra8_sci_csr_bit_tdre
Transmit Data Empty.
@ k_ra8_sci_cfclr_bit_rdrfc
Clear CSR.RDRF.
@ k_ra8_sci_ccr3_chr_8bit
10 = 8-bit data (initial value).
@ k_ra8_sci_ccr2_mask_cks_field
CKS[21:20] in CCR2.
@ k_ra8_sci_ccr2_mask_brr_field
BRR[15:8] in CCR2.
ra8_err_t ra8_sci_spi_set_clock(uint8_t channel, uint32_t baud_hz, uint32_t pclk_hz)
Re-program the bit-rate without otherwise reconfiguring.
static uint32_t internal_ccr3(const ra8_sci_spi_cfg_t *cfg)
Build CCR3 for Simple-SPI controller mode.
ra8_err_t ra8_sci_spi_xfer(uint8_t channel, const uint8_t *tx, uint8_t *rx, uint32_t len)
Full-duplex multi-byte transfer.
static void internal_resolve_rate(uint32_t baud_hz, uint32_t pclk_hz, uint32_t *out_cks, uint32_t *out_brr)
Resolve CCR2.CKS + BRR for a requested Simple-SPI bit-rate.
Definition ra8_sci_spi.c:97
ra8_err_t ra8_sci_spi_init(uint8_t channel, const ra8_sci_spi_cfg_t *cfg)
Bring an SCI channel up as a Simple-SPI controller.
ra8_err_t ra8_sci_spi_deinit(uint8_t channel)
Disable the channel and release its MSTP gate.
static void internal_apply_rate(volatile r_sci_regs_t *reg, uint32_t baud_hz, uint32_t pclk_hz)
Write CCR2 with the resolved CKS + BRR fields.
ra8_sci_spi_dim_t
Static dimensioning + bit-rate search constants.
Definition ra8_sci_spi.c:45
@ k_ra8_sci_spi_channel_count
SCI0..SCI9.
Definition ra8_sci_spi.c:46
@ k_ra8_sci_spi_brr_max
BRR is 8-bit.
Definition ra8_sci_spi.c:48
@ k_ra8_sci_spi_cks_max
CKS[1:0] max (clock /64).
Definition ra8_sci_spi.c:47
@ k_ra8_sci_spi_div_base
B = TCLK / (4 * 4^n * (N + 1)).
Definition ra8_sci_spi.c:49
@ k_ra8_sci_spi_idle_byte
Idle fill when tx is NULL.
Definition ra8_sci_spi.c:50
ra8_err_t ra8_sci_spi_xfer8(uint8_t channel, uint8_t tx, uint8_t *rx)
Full-duplex single-frame transfer.
SCI Simple-SPI controller-mode driver (polling, full-duplex).
@ 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
Per-channel SCI_B register window.
volatile uint32_t CCR4
+0x18 Common Control 4.
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.
Configuration descriptor for ra8_sci_spi_init.
Definition ra8_sci_spi.h:49
ra8_spi_mode_t mode
Clock polarity/phase (mode 0..3).
Definition ra8_sci_spi.h:52
uint32_t baud_hz
Desired SCK bit-rate (Hz).
Definition ra8_sci_spi.h:50
uint32_t pclk_hz
SCI baud-clock source (PCLKA, Hz).
Definition ra8_sci_spi.h:51
bool lsb_first
true shifts LSB first.
Definition ra8_sci_spi.h:53