ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_spi_b_target.c
Go to the documentation of this file.
1
56
57#include <stdint.h>
58
59#include "ra8_attributes.h"
60#include "ra8_check.h"
61#include "ra8_err.h"
62#include "ra8_hw_err.h"
63#include "ra8_log.h"
64#include "ra8_mstp.h"
65#include "ra8_spi.h"
66#include "ra8_spi_regs.h"
67
68static const char* s_tag = "SPI_B_TGT";
69
70/* =============================================================================
71 * Constants
72 * =============================================================================
73 */
74
89
100typedef enum : uint32_t {
103
104/* =============================================================================
105 * Internal helpers
106 * =============================================================================
107 */
108
141 uint32_t flag_mask)
142{
143 /* Bounded busy-poll of SPSR. On the host test build the ra8_hw_err MMIO fault
144 * seam (ra8_fake_mmio_*) drives this real loop to succeed-after-N or to time out,
145 * so both the success and timeout legs are exercised on host (T1-01) rather
146 * than compiled out behind an RA8_OFF_TARGET short-circuit. On target it is
147 * a plain register spin with a fixed iteration bound. */
148 /* HUM Ch 43.2.9 "SPSR : SPI Status Register" p 2898 */
149 return ra8_hw_wait_flag_set32(&reg->SPSR, flag_mask, (uint32_t)k_spi_b_target_poll_limit);
150}
151
176{
177 uint32_t v = 0U;
178 /* SPCR.MSTR (bit 30) is NOT set -- Peripheral (Target) mode. */
179 /* SPCR.SCKASE (bit 12) is NOT set -- valid in controller mode only. */
180 v |= (uint32_t)k_ra8_spcr_mask_spe; /* SPI Function Enable. */
181 v |= (uint32_t)k_ra8_spcr_mask_modfen; /* Mode Fault Error Detection. */
182 return v;
183}
184
216{
217 uint32_t v = 0U;
218 switch (cfg->mode) {
219 case k_ra8_spi_mode_1:
220 v |= (uint32_t)k_ra8_spcmd_mask_cpha;
221 break;
222 case k_ra8_spi_mode_2:
223 v |= (uint32_t)k_ra8_spcmd_mask_cpol;
224 break;
225 case k_ra8_spi_mode_3:
226 v |= (uint32_t)k_ra8_spcmd_mask_cpha;
227 v |= (uint32_t)k_ra8_spcmd_mask_cpol;
228 break;
229 case k_ra8_spi_mode_0:
230 default:
231 break;
232 }
233 if (cfg->lsb_first) {
234 v |= (uint32_t)k_ra8_spcmd_mask_lsbf;
235 }
236 /* 8-bit frame. */
238 return v;
239}
240
265 const ra8_spi_cfg_t* cfg)
266{
267 /* HUM Ch 43.2.13 "SPSRC : SPI Status Clear Register" p 2905 */
268 reg->SPSRC = (uint32_t)k_ra8_spsrc_mask_all;
269
270 /* SPBR=0 in target mode: clock is external; field ignored by HW. */
271 /* HUM Ch 43.2.6 "SPCR3 : SPI Control Register 3" p 2891 */
272 reg->SPCR3 = 0U;
273
274 /* HUM Ch 43.2.3 "SPDECR : SPI Delay Control Register" p 2883 */
275 reg->SPDECR = 0U;
276
277 /* No loopback in target mode. SPCR2 must be written while SPE=0. */
278 /* HUM Ch 43.2.4 "SPCR2 : SPI Control Register 2" p 2889 */
279 reg->SPCR2 = 0U;
280
281 /* HUM Ch 43.2.7 "SPCMDm : SPI Command Register" p 2893 */
282 reg->SPCMD[0] = internal_spcmd_target(cfg);
283
284 /* HUM Ch 43.2.10 "SPDCR : SPI Data Control Register" p 2896 */
285 reg->SPDCR = 0U;
286 reg->SPDCR2 = 0U;
287
288 /* HUM Ch 43.2.14 "SPFCR : SPI FIFO Clear Register" p 2906 */
289 reg->SPFCR = (uint32_t)k_ra8_spfcr_mask_spfrst;
290
291 /* Re-clear status after FIFO reset in case SPRF was set by flush. */
292 /* HUM Ch 43.2.13 "SPSRC : SPI Status Clear Register" p 2905 */
293 reg->SPSRC = (uint32_t)k_ra8_spsrc_mask_all;
294}
295
296/* =============================================================================
297 * Public API -- definitions (declarations + Doxygen live in ra8_spi.h)
298 * =============================================================================
299 */
300
302{
303 RA8_CHECK_NULL_PTR(cfg, s_tag, "target_init: cfg");
304 if (channel >= (uint8_t)k_ra8_spi_b_channel_count) {
306 }
307 volatile r_spi_regs_t* reg = ra8_spi(channel);
308 if (reg == nullptr) { /* GCOVR_EXCL_BR_LINE -- bounded channel yields non-null reg */
309 return k_ra8_err_invalid_arg; /* GCOVR_EXCL_LINE -- bounded channel yields non-null reg */
310 }
311 /* HUM Ch 11.2.7 "MSTPCRB : Module Stop Control Register B" p 444 */
312 const ra8_err_t mst_err = ra8_mstp_enable(s_spi_mstp_table[channel]);
313 /* GCOVR_EXCL_BR_START -- MSTP HW readback */
314 RA8_RETURN_ON_ERROR(mst_err, s_tag, "target_init: mstp");
315 /* GCOVR_EXCL_BR_STOP */
316
317 /* Disable (SPE=0) before reprogramming. */
318 /* HUM Ch 43.2.4 "SPCR : SPI Control Register" p 2884 */
319 reg->SPCR = 0U;
320
322
323 /* Enable SPI in target/peripheral mode: MSTR=0, MODFEN=1, SPE=1. */
324 /* HUM Ch 43.2.4 "SPCR : SPI Control Register" p 2884 */
325 /* HUM Ch 43.3.14 "SPI peripheral-mode operation" p 2912 */
326 reg->SPCR = internal_target_spcr();
327
328 ra8_log_info_val(s_tag, "target_init channel", (uint32_t)channel);
329 return k_ra8_ok;
330}
331
332ra8_err_t ra8_spi_b_target_xfer(uint8_t channel, uint8_t tx, uint8_t* rx)
333{
334 volatile r_spi_regs_t* reg = ra8_spi(channel);
335 RA8_CHECK_NULL_PTR(reg, s_tag, "target_xfer: channel out of range");
336
337 /* Wait until the TX buffer is empty (safe to pre-load response). */
338 /* HUM Ch 43.2.9 "SPSR : SPI Status Register" p 2898 */
340 if (err != k_ra8_ok) {
341 return err;
342 }
343
344 /* Pre-load the response byte -- shifted out on CIPO when the external */
345 /* controller asserts CS and provides RSPCK. */
346 /* HUM Ch 43.2.2 "SPDR : SPI Data Register" p 2881 */
347 reg->SPDR = (uint32_t)tx;
348
349 /* Clear TX-empty flag (write-1-to-clear). */
350 /* HUM Ch 43.2.13 "SPSRC : SPI Status Clear Register" p 2905 */
351 reg->SPSRC = (uint32_t)k_ra8_spsrc_mask_sptefc;
352
353 /* Wait for the external controller to complete a full frame (SPRF). */
354 /* HUM Ch 43.2.9 "SPSR : SPI Status Register" p 2898 */
356 if (err != k_ra8_ok) {
357 return err;
358 }
359
360 /* Drain the byte received on COPI from the RX FIFO front-end. */
361 /* HUM Ch 43.2.2 "SPDR : SPI Data Register" p 2881 */
362 const uint8_t received = (uint8_t)reg->SPDR;
363
364 /* Clear RX-full flag. */
365 /* HUM Ch 43.2.13 "SPSRC : SPI Status Clear Register" p 2905 */
366 reg->SPSRC = (uint32_t)k_ra8_spsrc_mask_sprfc;
367
368 if (rx != nullptr) {
369 *rx = received;
370 }
371 return k_ra8_ok;
372}
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
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_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).
@ 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
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 uint32_t internal_target_spcr(void)
Build the SPCR value for target (peripheral) mode.
ra8_err_t ra8_spi_b_target_xfer(uint8_t channel, uint8_t tx, uint8_t *rx)
Exchange one byte as the SPI target in a polled blocking call.
ra8_spi_b_target_poll_t
Polling-loop budget for SPSR flag waits in target mode.
@ k_spi_b_target_poll_limit
Max iterations per flag wait.
static void internal_target_program_regs(volatile r_spi_regs_t *reg, const ra8_spi_cfg_t *cfg)
Write all control registers while SPCR.SPE=0.
ra8_err_t ra8_spi_b_target_init(uint8_t channel, const ra8_spi_cfg_t *cfg)
Initialise an SPI_B channel in target (peripheral) mode.
static uint32_t internal_spcmd_target(const ra8_spi_cfg_t *cfg)
Build SPCMD0 value from a caller-supplied configuration.
static ra8_err_t internal_target_wait_spsr(volatile r_spi_regs_t *reg, uint32_t flag_mask)
Wait for a single SPSR flag to assert, with a bounded poll.
SPI_B register layout for the Renesas RA8D2.
@ k_ra8_spcmd_bit_spb_lo
Data Length [20:16] low.
@ 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_spe
RA8 spcr mask spe.
@ k_ra8_spcr_mask_modfen
RA8 spcr mask modfen.
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_spsr_mask_sprf
RA8 spsr mask sprf.
@ k_ra8_spsr_mask_sptef
RA8 spsr mask sptef.
@ k_ra8_spi_b_channel_count
SPI0 + SPI1.
@ k_ra8_spcmd_spb_8bit
0b00111 -> 8-bit frame.
@ 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
ra8_spi_mode_t mode
CPOL / CPHA combination.
Definition ra8_spi.h:102