ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_i2c_peripheral.c File Reference

I2C Bus Interface (IIC) target (peripheral) role – polling mode. More...

#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_err.h"
#include "ra8_i2c.h"
#include "ra8_i2c_internal.h"
#include "ra8_i2c_regs.h"
Include dependency graph for ra8_i2c_peripheral.c:

Go to the source code of this file.

Enumerations

enum  ra8_i2c_peripheral_limits_t : uint32_t { k_ra8_i2c_peripheral_poll_limit = 200000U }
 Spin budgets and validation bounds for the target plane. More...
enum  ra8_i2c_peripheral_const_t : uint8_t {
  k_ra8_i2c_peripheral_addr_7b_max = 0x7FU ,
  k_ra8_i2c_peripheral_slot_max = 2U ,
  k_ra8_i2c_peripheral_addr_shift = (uint8_t)k_ra8_i2c_sarl_sva_pos ,
  k_ra8_i2c_peripheral_saru_7bit = 0U ,
  k_ra8_i2c_peripheral_icier_arm
}
 Addressing constants for the target plane. More...

Functions

bool priv_ra8_i2c_internal_peripheral_poll_done (uint8_t icsr1, uint8_t icsr2)
 Poll-exit predicate: an own-address match or a STOP was observed.
bool priv_ra8_i2c_internal_peripheral_rx_continue (uint8_t icsr2, uint32_t received, uint32_t capacity)
 Receive-loop predicate: keep draining while no STOP and room remains.
bool priv_ra8_i2c_internal_peripheral_tx_done (uint8_t icsr2)
 Transmit-completion predicate: the controller ended the read.
bool priv_ra8_i2c_internal_peripheral_tx_continue (uint8_t icsr2, uint32_t sent, uint32_t len)
 Transmit-loop predicate: keep sending while no NACK and data remains.
static ra8_i2c_peripheral_event_t internal_i2c_target_classify (uint8_t icsr1, uint8_t iccr2)
 Classify a latched address-match snapshot into a poll event.
static ra8_err_t internal_i2c_target_wait (volatile const r_i2c_regs_t *reg, uint8_t mask)
 Wait (bounded) for a flag in ICSR2 to set.
static void internal_i2c_target_set_addr (volatile r_i2c_regs_t *reg, uint8_t slot, uint8_t addr_7b)
 Programme a 7-bit own address into the SARLy/SARUy pair for a slot.
static uint8_t internal_i2c_target_icser_mask (uint8_t slot, bool general_call)
 Build the ICSER enable mask for one own-address slot.
ra8_err_t priv_ra8_i2c_internal_target_drain_rx (volatile r_i2c_regs_t *reg, uint8_t *buf, uint32_t capacity, uint32_t *out_count)
 Implementation of priv_ra8_i2c_internal_target_drain_rx() – trailing-byte ICDRR drain.
static void internal_i2c_target_fill_tx (volatile r_i2c_regs_t *reg, const uint8_t *data, uint32_t len, uint32_t *out_sent)
 Push controller-read data bytes from data into ICDRT.
static bool internal_i2c_target_finish_tx (volatile r_i2c_regs_t *reg)
 Close a target-transmit frame: wait for end, release SCL, clear flags.
ra8_err_t ra8_i2c_peripheral_init (uint8_t channel, const ra8_i2c_peripheral_cfg_t *cfg)
 Arm an IIC channel to answer as an I2C target (peripheral).
ra8_err_t ra8_i2c_peripheral_deinit (uint8_t channel)
 Disarm own-address matching, returning the channel to controller use.
ra8_err_t ra8_i2c_peripheral_poll (uint8_t channel, ra8_i2c_peripheral_event_t *out_event)
 Wait (bounded) for a controller to address this target.
ra8_err_t ra8_i2c_peripheral_receive (uint8_t channel, uint8_t *buf, uint32_t capacity, uint32_t *out_received)
 Drain a controller-write transaction into buf (target receive).
ra8_err_t ra8_i2c_peripheral_transmit (uint8_t channel, const uint8_t *data, uint32_t len, uint32_t *out_sent)
 Answer a controller-read transaction from data (target transmit).
static ra8_i2c_peripheral_event_t internal_i2c_dispatch_event (uint8_t icsr1, uint8_t icsr2, uint8_t iccr2)
 Classify an own-address / STOP status snapshot into a dispatch event.
ra8_err_t ra8_i2c_peripheral_attach_handler (uint8_t channel, ra8_i2c_peripheral_event_fn_t fn, void *ctx)
 Attach (or detach) the address-match callback for a channel.
void ra8_i2c_peripheral_dispatch (uint8_t channel)
 Snapshot the latched target status and fire the attached callback.

Detailed Description

I2C Bus Interface (IIC) target (peripheral) role – polling mode.

Tag
[Ring 3 / HAL] {World: NS}

Target-role plane of the RA8D2 RIIC polling driver, split out of ra8_i2c.c so the controller transfer plane stays under the file-size cap. Lets the RA8D2 answer a remote controller once one of its own-address slots matches. This driver uses the inclusive "target / peripheral" terminology for that role while keeping the HUM's register names (SARLy, AASy, ...) verbatim so cross-referencing the manual stays easy.

Mirrors FSP r_iic_slave collapsed into synchronous helpers – no DTC fast path and no interrupt path. Own-address matching, clock stretching and both transfer directions are implemented; the controller transfer plane in ra8_i2c.c and the bring-up plane in ra8_i2c_config.c are unchanged. Both planes share s_i2c_state and the log tag via ra8_i2c_internal.h.

Target-role state machine (synchronous reduction of HUM Ch 39.3.5 / 39.3.6):

*                +-----------------------------------------------+
*                |                  TARGET_IDLE                  |
*                |  (peripheral mode, ICCR2.MST = 0, own-address |
*                |   match armed in ICSER, AASy flags clear)     |
*                +-----------------------------------------------+
*                   | poll: AASy/GCA set            | poll: AASy/GCA set
*                   | and ICCR2.TRS = 0             | and ICCR2.TRS = 1
*                   v  (controller WRITE)           v  (controller READ)
*          +------------------+            +-------------------+
*          |    RX_ACTIVE     |            |     TX_ACTIVE     |
*          | dummy-read addr, |            | push ICDRT while  |
*          | read ICDRR while |            | TDRE set and no   |
*          | RDRF set and room|            | NACK, until len   |
*          +------------------+            +-------------------+
*                   | STOP or buffer full           | NACK (controller end)
*                   | (clear ICSR2.STOP)            | or sent == len; wait
*                   |                               | TEND, dummy-read ICDRR,
*                   v                               v clear NACKF/STOP
*                +-----------------------------------------------+
*                |                  TARGET_IDLE                  |
*                +-----------------------------------------------+
* 

Owns every write to the RIIC own-address and target-transfer registers. See HUM Ch 39 "I2C Bus Interface (IIC)", p 2367-2444.

Since
0.1.0

Definition in file ra8_i2c_peripheral.c.

Enumeration Type Documentation

◆ ra8_i2c_peripheral_const_t

Addressing constants for the target plane.

Enumerator
k_ra8_i2c_peripheral_addr_7b_max 

Largest valid 7-bit own address.

k_ra8_i2c_peripheral_slot_max 

Highest own-address comparator slot.

k_ra8_i2c_peripheral_addr_shift 

Shift to place a 7-bit own address into SARLy.SVA[6:0] (bits [7:1]).

k_ra8_i2c_peripheral_saru_7bit 

SARUy value for the 7-bit address format (FS = 0, SVA[1:0] = 0).

k_ra8_i2c_peripheral_icier_arm 

ICIER target-interrupt arm mask: RIE (RXI, bit 5) | TIE (TXI, bit 7) | SPIE (STOP, bit 3) – the own-address-match data + STOP interrupts.

Definition at line 80 of file ra8_i2c_peripheral.c.

◆ ra8_i2c_peripheral_limits_t

enum ra8_i2c_peripheral_limits_t : uint32_t

Spin budgets and validation bounds for the target plane.

Enumerator
k_ra8_i2c_peripheral_poll_limit 

Generic spin budget for status-flag polls, matching the controller plane: ~200k iterations keeps the worst-case stall under a few ms.

Definition at line 70 of file ra8_i2c_peripheral.c.

Function Documentation

◆ internal_i2c_dispatch_event()

ra8_i2c_peripheral_event_t internal_i2c_dispatch_event ( uint8_t icsr1,
uint8_t icsr2,
uint8_t iccr2 )
static

Classify an own-address / STOP status snapshot into a dispatch event.

Reduces the latched snapshot to a single ra8_i2c_peripheral_event_t. An own-address (or general-call) match decodes via ICCR2.TRS to read (controller reads -> target transmits) or write (controller writes -> target receives) through internal_i2c_target_classify. With no match a latched ICSR2.STOP decodes to stop; otherwise none. Match and STOP are mutually exclusive in hardware – the AASy flags clear on the STOP – so a match is tested first.

Parameters
[in]icsr1Snapshot of ICSR1 (own-address detection flags).
[in]icsr2Snapshot of ICSR2 (STOP detection flag).
[in]iccr2Snapshot of ICCR2 (transmit/receive mode bit TRS).
Returns
The decoded ra8_i2c_peripheral_event_t.
Return values
k_ra8_i2c_peripheral_event_writeMatch, controller writes.
k_ra8_i2c_peripheral_event_readMatch, controller reads.
k_ra8_i2c_peripheral_event_stopNo match but a STOP is latched.
k_ra8_i2c_peripheral_event_noneNeither a match nor a STOP.
Precondition
None.
None.
Postcondition
No state mutated.
Return depends solely on the three input snapshots.
Note
Thread safety: pure; thread-safe.
Since
0.1.0

Definition at line 581 of file ra8_i2c_peripheral.c.

References internal_i2c_target_classify(), k_ra8_i2c_msk_icsr2_stop, k_ra8_i2c_peripheral_event_none, and k_ra8_i2c_peripheral_event_stop.

Referenced by ra8_i2c_peripheral_dispatch().

◆ internal_i2c_target_classify()

ra8_i2c_peripheral_event_t internal_i2c_target_classify ( uint8_t icsr1,
uint8_t iccr2 )
static

Classify a latched address-match snapshot into a poll event.

Returns none when no own-address / general-call flag is set; otherwise decodes ICCR2.TRS, which the hardware sets to 1 when the controller's R/W# bit was 1 (controller read -> target transmit) and leaves 0 for a write.

Parameters
[in]icsr1Snapshot of ICSR1 (own-address detection flags).
[in]iccr2Snapshot of ICCR2 (transmit/receive mode bit TRS).
Returns
The decoded ra8_i2c_peripheral_event_t.
Return values
k_ra8_i2c_peripheral_event_noneNo own-address match latched.
k_ra8_i2c_peripheral_event_readMatch and TRS = 1 (controller reads).
k_ra8_i2c_peripheral_event_writeMatch and TRS = 0 (controller writes).
Precondition
None.
None.
Postcondition
No state mutated.
Return depends solely on the two input snapshots.
Note
Thread safety: pure; thread-safe.
Since
0.1.0

Definition at line 151 of file ra8_i2c_peripheral.c.

References k_ra8_i2c_msk_iccr2_trs, k_ra8_i2c_msk_icsr1_match, k_ra8_i2c_peripheral_event_none, k_ra8_i2c_peripheral_event_read, k_ra8_i2c_peripheral_event_write, and RA8_INTERNAL.

Referenced by internal_i2c_dispatch_event(), and ra8_i2c_peripheral_poll().

◆ internal_i2c_target_fill_tx()

void internal_i2c_target_fill_tx ( volatile r_i2c_regs_t * reg,
const uint8_t * data,
uint32_t len,
uint32_t * out_sent )
static

Push controller-read data bytes from data into ICDRT.

The per-byte transmit loop extracted from ra8_i2c_peripheral_transmit. Each iteration waits for ICSR2.TDRE, then – while priv_ra8_i2c_internal_peripheral_tx_continue holds (no controller NACK and bytes remain) – writes one byte to ICDRT. Stops on NACK, on a TDRE timeout, or when every byte is queued. The loop is bounded by len + 1 (NASA P10 Rule 2). The completion status is left to internal_i2c_target_finish_tx.

Parameters
[in]regChannel register block.
[in]dataSource buffer.
[in]lenBytes available to send (non-zero).
[out]out_sentNumber of bytes accepted by the controller.
Precondition
reg, data and out_sent are non-NULL.
The channel was addressed for a controller read (TRS = 1).
Postcondition
*out_sent <= len.
Each accepted byte was written to ICDRT in order.
Note
Thread safety: not thread-safe (drives a single channel).
Since
0.1.0

Definition at line 332 of file ra8_i2c_peripheral.c.

References r_i2c_regs_t::ICDRT, r_i2c_regs_t::ICSR2, internal_i2c_target_wait(), k_ra8_i2c_msk_icsr2_tdre, k_ra8_ok, priv_ra8_i2c_internal_peripheral_tx_continue(), and RA8_INTERNAL.

Referenced by ra8_i2c_peripheral_transmit().

◆ internal_i2c_target_finish_tx()

bool internal_i2c_target_finish_tx ( volatile r_i2c_regs_t * reg)
static

Close a target-transmit frame: wait for end, release SCL, clear flags.

Implements steps 4-7 of HUM Ch 39.3.5 p 2405: wait for the controller's TEND or NACK, snapshot whether the frame ended cleanly via priv_ra8_i2c_internal_peripheral_tx_done, dummy-read ICDRR to release SCL, then clear NACKF and STOP (W0C) for the next transfer.

Parameters
[in]regChannel register block.
Returns
Whether the controller ended the read (TEND or NACK observed).
Return values
trueTEND or NACK was latched within the spin budget.
falseThe end-of-frame poll timed out.
Precondition
reg is non-NULL.
The transmit data phase has completed.
Postcondition
SCL is released and ICSR2.NACKF / STOP read back zero.
No data register other than the ICDRR release-read is touched.
Note
Thread safety: not thread-safe (drives a single channel).
Since
0.1.0

Definition at line 378 of file ra8_i2c_peripheral.c.

References r_i2c_regs_t::ICDRR, r_i2c_regs_t::ICSR2, internal_i2c_target_wait(), k_ra8_i2c_msk_icsr2_nackf, k_ra8_i2c_msk_icsr2_stop, k_ra8_i2c_msk_icsr2_tend, priv_ra8_i2c_internal_peripheral_tx_done(), and RA8_INTERNAL.

Referenced by ra8_i2c_peripheral_transmit().

◆ internal_i2c_target_icser_mask()

uint8_t internal_i2c_target_icser_mask ( uint8_t slot,
bool general_call )
static

Build the ICSER enable mask for one own-address slot.

SARyE for slot y is bit y of ICSER, so the slot enable is 1 << slot; GCAE is OR-ed in when the general-call address is also to be answered (HUM Ch 39.2.7 p 2380).

Parameters
[in]slotOwn-address comparator slot (0, 1 or 2).
[in]general_callTrue to also enable general-call matching.
Returns
The ICSER value to write.
Return values
0Never (at least one SARyE bit is always set).
Precondition
slot is 0, 1 or 2.
None.
Postcondition
Return has exactly the SARyE bit (and optionally GCAE) set.
No state is mutated.
Note
Thread safety: pure; thread-safe.
Since
0.1.0

Definition at line 264 of file ra8_i2c_peripheral.c.

References k_ra8_i2c_msk_icser_gcae, k_ra8_i2c_msk_icser_sar0e, and RA8_INTERNAL.

Referenced by ra8_i2c_peripheral_init().

◆ internal_i2c_target_set_addr()

void internal_i2c_target_set_addr ( volatile r_i2c_regs_t * reg,
uint8_t slot,
uint8_t addr_7b )
static

Programme a 7-bit own address into the SARLy/SARUy pair for a slot.

Writes addr_7b left-shifted into SARLy.SVA[6:0] and clears SARUy to select the 7-bit address format (HUM Ch 39.2.13 p 2390, Ch 39.2.14 p 2391). The three comparator slots are discrete registers, so a switch selects the pair rather than indexing.

Parameters
[in]regChannel register block.
[in]slotOwn-address comparator slot (0, 1 or 2).
[in]addr_7b7-bit own address (already range-checked).
Precondition
reg is non-NULL.
slot is 0, 1 or 2.
Postcondition
The selected SARLy holds addr_7b << 1 and SARUy reads 0.
No other register is modified.
Note
Thread safety: not thread-safe.
Since
0.1.0

Definition at line 218 of file ra8_i2c_peripheral.c.

References k_ra8_i2c_peripheral_addr_shift, k_ra8_i2c_peripheral_saru_7bit, k_ra8_i2c_peripheral_slot_0, k_ra8_i2c_peripheral_slot_1, r_i2c_regs_t::SARL0, r_i2c_regs_t::SARL1, r_i2c_regs_t::SARL2, r_i2c_regs_t::SARU0, r_i2c_regs_t::SARU1, and r_i2c_regs_t::SARU2.

Referenced by ra8_i2c_peripheral_init().

◆ internal_i2c_target_wait()

ra8_err_t internal_i2c_target_wait ( volatile const r_i2c_regs_t * reg,
uint8_t mask )
static

Wait (bounded) for a flag in ICSR2 to set.

Spins up to k_ra8_i2c_peripheral_poll_limit iterations reading ICSR2 and returning success the moment the masked flag is observed set. The fixed bound satisfies NASA P10 Rule 2.

Parameters
[in]regChannel register block.
[in]maskBit mask to test against ICSR2.
Returns
ra8_err_t outcome of the poll.
Return values
k_ra8_okMasked flag observed set.
k_ra8_err_hw_timeoutSpin budget exhausted before the flag set.
Precondition
reg is non-NULL.
mask is a non-zero mask.
Postcondition
On success the masked flag was observed set.
No register write occurs.
Note
Thread safety: not thread-safe (reads a single channel).
Since
0.1.0

Definition at line 185 of file ra8_i2c_peripheral.c.

References r_i2c_regs_t::ICSR2, k_ra8_err_hw_timeout, k_ra8_i2c_peripheral_poll_limit, k_ra8_ok, and RA8_INTERNAL.

Referenced by internal_i2c_target_fill_tx(), internal_i2c_target_finish_tx(), priv_ra8_i2c_internal_target_drain_rx(), and ra8_i2c_peripheral_receive().

◆ priv_ra8_i2c_internal_peripheral_poll_done()

bool priv_ra8_i2c_internal_peripheral_poll_done ( uint8_t icsr1,
uint8_t icsr2 )

Poll-exit predicate: an own-address match or a STOP was observed.

Drives the bounded wait in ra8_i2c_peripheral_poll. The match flags come from ICSR1 (AAS0/1/2, GCA); STOP comes from ICSR2. Promoted so the OR can be exercised with independent influence under MC/DC.

Parameters
[in]icsr1Snapshot of ICSR1 (own-address detection flags).
[in]icsr2Snapshot of ICSR2 (STOP detection flag).
Returns
Whether the poll loop should stop spinning.
Return values
trueAn own-address match or a STOP condition is latched.
falseNeither – keep spinning.
Precondition
None.
None.
Postcondition
No state mutated.
Return depends solely on the two inputs.
Note
Test-access only. Pure function.
MC/DC:
Decision: (icsr1 & match) != 0 || (icsr2 & stop) != 0 (2 conditions); N+1 = 3 vectors:
  • V1: match=0, stop=0 -> false (control: both false)
  • V2: match=1, stop=0 -> true (varies left)
  • V3: match=0, stop=1 -> true (varies right)
Since
0.1.0

Definition at line 99 of file ra8_i2c_peripheral.c.

References k_ra8_i2c_msk_icsr1_match, and k_ra8_i2c_msk_icsr2_stop.

Referenced by ra8_i2c_peripheral_poll().

◆ priv_ra8_i2c_internal_peripheral_rx_continue()

bool priv_ra8_i2c_internal_peripheral_rx_continue ( uint8_t icsr2,
uint32_t received,
uint32_t capacity )

Receive-loop predicate: keep draining while no STOP and room remains.

Drives the per-byte loop in ra8_i2c_peripheral_receive. Promoted so the AND can be exercised with independent influence under MC/DC.

Parameters
[in]icsr2Snapshot of ICSR2 (STOP detection flag).
[in]receivedBytes stored so far.
[in]capacityDestination buffer size.
Returns
Whether another byte may be received into the buffer.
Return values
trueNo STOP latched and received < capacity.
falseA STOP is latched or the buffer is full.
Precondition
None.
None.
Postcondition
No state mutated.
Return depends solely on the inputs.
Note
Test-access only. Pure function.
MC/DC:
Decision: (icsr2 & stop) == 0 && received < capacity (2 conditions); N+1 = 3 vectors:
  • V1: stop=0, received<capacity -> true (control: both true)
  • V2: stop=1, received<capacity -> false (varies left)
  • V3: stop=0, received==capacity -> false (varies right)
Since
0.1.0

Definition at line 105 of file ra8_i2c_peripheral.c.

References k_ra8_i2c_msk_icsr2_stop.

Referenced by priv_ra8_i2c_internal_target_drain_rx().

◆ priv_ra8_i2c_internal_peripheral_tx_continue()

bool priv_ra8_i2c_internal_peripheral_tx_continue ( uint8_t icsr2,
uint32_t sent,
uint32_t len )

Transmit-loop predicate: keep sending while no NACK and data remains.

Drives the per-byte loop in ra8_i2c_peripheral_transmit. Promoted so the AND can be exercised with independent influence under MC/DC.

Parameters
[in]icsr2Snapshot of ICSR2 (NACKF detection flag).
[in]sentBytes accepted by the controller so far.
[in]lenNumber of bytes available to send.
Returns
Whether another byte should be queued to ICDRT.
Return values
trueNo NACK latched and sent < len.
falseThe controller NACKed or all bytes are queued.
Precondition
None.
None.
Postcondition
No state mutated.
Return depends solely on the inputs.
Note
Test-access only. Pure function.
MC/DC:
Decision: (icsr2 & nackf) == 0 && sent < len (2 conditions); N+1 = 3 vectors:
  • V1: nackf=0, sent<len -> true (control: both true)
  • V2: nackf=1, sent<len -> false (varies left)
  • V3: nackf=0, sent==len -> false (varies right)
Since
0.1.0

Definition at line 118 of file ra8_i2c_peripheral.c.

References k_ra8_i2c_msk_icsr2_nackf.

Referenced by internal_i2c_target_fill_tx().

◆ priv_ra8_i2c_internal_peripheral_tx_done()

bool priv_ra8_i2c_internal_peripheral_tx_done ( uint8_t icsr2)

Transmit-completion predicate: the controller ended the read.

Used by ra8_i2c_peripheral_transmit after the data loop to confirm the frame closed cleanly. Promoted so the OR can be exercised under MC/DC.

Parameters
[in]icsr2Snapshot of ICSR2 (NACKF and TEND flags).
Returns
Whether the controller has ended the read transaction.
Return values
trueNACKF or TEND is latched.
falseNeither – transmission is still in progress.
Precondition
None.
None.
Postcondition
No state mutated.
Return depends solely on the input snapshot.
Note
Test-access only. Pure function.
MC/DC:
Decision: (icsr2 & nackf) != 0 || (icsr2 & tend) != 0 (2 conditions); N+1 = 3 vectors:
  • V1: nackf=0, tend=0 -> false (control: both false)
  • V2: nackf=1, tend=0 -> true (varies left)
  • V3: nackf=0, tend=1 -> true (varies right)
Since
0.1.0

Definition at line 112 of file ra8_i2c_peripheral.c.

References k_ra8_i2c_msk_icsr2_nackf, and k_ra8_i2c_msk_icsr2_tend.

Referenced by internal_i2c_target_finish_tx().

◆ priv_ra8_i2c_internal_target_drain_rx()

ra8_err_t priv_ra8_i2c_internal_target_drain_rx ( volatile r_i2c_regs_t * reg,
uint8_t * buf,
uint32_t capacity,
uint32_t * out_count )

Implementation of priv_ra8_i2c_internal_target_drain_rx() – trailing-byte ICDRR drain.

Drain controller-write data bytes from ICDRR into buf.

Definition at line 274 of file ra8_i2c_peripheral.c.

References r_i2c_regs_t::ICDRR, r_i2c_regs_t::ICSR2, internal_i2c_target_wait(), k_ra8_i2c_msk_icsr2_rdrf, k_ra8_i2c_msk_icsr2_stop, k_ra8_ok, and priv_ra8_i2c_internal_peripheral_rx_continue().

Referenced by ra8_i2c_peripheral_receive().

◆ ra8_i2c_peripheral_attach_handler()

ra8_err_t ra8_i2c_peripheral_attach_handler ( uint8_t channel,
ra8_i2c_peripheral_event_fn_t fn,
void * ctx )
nodiscard

Attach (or detach) the address-match callback for a channel.

Stores fn and ctx in the channel's driver state so a later ra8_i2c_peripheral_dispatch can fire the callback when a controller addresses this target or a STOP ends a transaction. Pass fn == NULL to detach; dispatch then becomes a no-op for the channel. The handler is independent of ra8_i2c_peripheral_poll, which never consults it.

Parameters
[in]channelChannel index (0, 1 or 2).
[in]fnCallback to fire on a decoded event, or NULL to detach.
[in]ctxOpaque context passed back to fn (may be NULL).
Returns
ra8_err_t.
Return values
k_ra8_okHandler stored for the channel.
k_ra8_err_invalid_argchannel out of range.
Precondition
IRQs masked or single-threaded with respect to dispatch.
The channel index is one this driver owns.
Postcondition
The channel's handler equals fn and its context equals ctx.
No hardware register is touched.
Note
Thread safety: not thread-safe.
See also
ra8_i2c_peripheral_dispatch
Since
0.1.0

Definition at line 594 of file ra8_i2c_peripheral.c.

References k_ra8_err_invalid_arg, k_ra8_i2c_channel_count, k_ra8_ok, and s_i2c_state.

Referenced by riic_target_arm().

◆ ra8_i2c_peripheral_deinit()

ra8_err_t ra8_i2c_peripheral_deinit ( uint8_t channel)
nodiscard

Disarm own-address matching, returning the channel to controller use.

Parameters
[in]channelChannel index.
Returns
ra8_err_t.
Return values
k_ra8_okICSER cleared, WAIT released.
k_ra8_err_invalid_argchannel out of range.
k_ra8_err_not_initializedTarget role was not armed for this channel.
Precondition
Channel previously armed with ra8_i2c_peripheral_init.
IRQs masked or single-threaded context.
Postcondition
ICSER reads 0 and ICMR3.WAIT is clear.
The channel answers no own address; controller-role transfers resume.
Note
Thread safety: not thread-safe.
Since
0.1.0

Definition at line 435 of file ra8_i2c_peripheral.c.

References r_i2c_regs_t::ICIER, r_i2c_regs_t::ICMR3, r_i2c_regs_t::ICSER, k_ra8_err_invalid_arg, k_ra8_err_not_initialized, k_ra8_i2c_msk_icmr3_wait, k_ra8_i2c_peripheral_icier_arm, k_ra8_ok, ra8_i2c_regs(), and s_i2c_state.

◆ ra8_i2c_peripheral_dispatch()

void ra8_i2c_peripheral_dispatch ( uint8_t channel)

Snapshot the latched target status and fire the attached callback.

Reads ICSR1 (own-address match flags), ICSR2 (STOP) and ICCR2 (TRS) once, classifies them into an ra8_i2c_peripheral_event_t (an own-address match decodes to write / read from TRS; otherwise a latched STOP decodes to stop), and – when the event is not none and a handler is attached – invokes the handler with the registered context. Read-only with respect to the bus: it clears no flags and queues no data, leaving the data-phase flag handling to ra8_i2c_peripheral_receive / ra8_i2c_peripheral_transmit the handler calls. Safe to call from the RIIC RXI / TXI / STPI ISR or a poll loop; a no-op when the channel is invalid, not armed, or has no handler.

Parameters
[in]channelChannel index (0, 1 or 2).
Precondition
The channel was armed with ra8_i2c_peripheral_init.
A handler may or may not be attached.
Postcondition
At most one handler invocation occurs per call.
No RIIC register is written (read-only snapshot).
Note
Thread safety: runs in the caller's context (ISR or poll); not re-entrant on one channel.
See also
ra8_i2c_peripheral_attach_handler
Since
0.1.0

Definition at line 605 of file ra8_i2c_peripheral.c.

References r_i2c_regs_t::ICCR2, r_i2c_regs_t::ICSR1, r_i2c_regs_t::ICSR2, internal_i2c_dispatch_event(), k_ra8_i2c_peripheral_event_none, ra8_i2c_regs(), and s_i2c_state.

Referenced by main().

◆ ra8_i2c_peripheral_init()

ra8_err_t ra8_i2c_peripheral_init ( uint8_t channel,
const ra8_i2c_peripheral_cfg_t * cfg )
nodiscard

Arm an IIC channel to answer as an I2C target (peripheral).

Programmes one own-address slot (SARLy = own_addr_7b << 1 in 7-bit format, SARUy = 0) and enables the matching ICSER.SARyE bit, plus ICSER.GCAE when general_call is set, so the hardware raises ICSR1.AASy / ICSR1.GCA on a matching address (HUM Ch 39.2.7 p 2380, Ch 39.2.9 p 2382, Ch 39.2.13 p 2390). When clock_stretch is set, ICMR3.WAIT is armed so SCL is held low between the ninth and first clocks until the byte is serviced. When irq_enable is set, ICIER's RIE / TIE / SPIE bits are armed so the RIIC RXI / TXI / STPI interrupts fire on an own-address match and a STOP; wire those vectors to ra8_i2c_peripheral_dispatch. The channel stays in peripheral mode (ICCR2.MST = 0) until a matching address arrives.

Parameters
[in]channelChannel index (0, 1 or 2).
[in]cfgConfiguration descriptor (non-NULL).
Returns
ra8_err_t.
Return values
k_ra8_okOwn-address slot armed.
k_ra8_err_null_ptrcfg is NULL or channel invalid.
k_ra8_err_invalid_argown_addr_7b > 0x7F or slot out of range.
Precondition
ra8_i2c_init has already brought the channel up (ICE = 1).
IRQs masked or single-threaded init context.
Postcondition
On success the channel answers cfg->own_addr_7b and is ready for ra8_i2c_peripheral_poll / ra8_i2c_peripheral_dispatch.
ICSER reflects the armed own-address / general-call enables.
Note
Thread safety: not thread-safe.
See also
ra8_i2c_peripheral_dispatch
Since
0.1.0

Definition at line 403 of file ra8_i2c_peripheral.c.

References ra8_i2c_peripheral_cfg_t::clock_stretch, g_i2c_tag, ra8_i2c_peripheral_cfg_t::general_call, r_i2c_regs_t::ICIER, r_i2c_regs_t::ICMR3, r_i2c_regs_t::ICSER, internal_i2c_target_icser_mask(), internal_i2c_target_set_addr(), ra8_i2c_peripheral_cfg_t::irq_enable, k_ra8_err_invalid_arg, k_ra8_i2c_msk_icmr3_wait, k_ra8_i2c_peripheral_addr_7b_max, k_ra8_i2c_peripheral_icier_arm, k_ra8_i2c_peripheral_slot_max, k_ra8_ok, ra8_i2c_peripheral_cfg_t::own_addr_7b, RA8_CHECK_NULL_PTR, ra8_i2c_regs(), s_i2c_state, and ra8_i2c_peripheral_cfg_t::slot.

Referenced by riic_target_arm().

◆ ra8_i2c_peripheral_poll()

ra8_err_t ra8_i2c_peripheral_poll ( uint8_t channel,
ra8_i2c_peripheral_event_t * out_event )
nodiscard

Wait (bounded) for a controller to address this target.

Spins on ICSR1 / ICSR2 until an own-address match or a STOP is observed, then classifies the transaction from ICSR1 (match flags) and ICCR2.TRS: write when the controller will send data (target receives), read when the controller will clock data out (target transmits). Returns none if the bounded spin elapses without a match.

State machine: IDLE --match,R/W=0--> (write) --match,R/W=1--> (read).

Parameters
[in]channelChannel index.
[out]out_eventDecoded event (non-NULL).
Returns
ra8_err_t.
Return values
k_ra8_ok*out_event populated (may be none).
k_ra8_err_null_ptrout_event NULL or channel invalid.
k_ra8_err_not_initializedTarget role not armed for this channel.
Precondition
Channel armed with ra8_i2c_peripheral_init.
out_event points to writable storage.
Postcondition
*out_event reflects the latched ICSR1 / ICCR2 state.
No bus state is mutated (read-only poll).
Note
Thread safety: not thread-safe.
Since
0.1.0

Definition at line 454 of file ra8_i2c_peripheral.c.

References g_i2c_tag, r_i2c_regs_t::ICCR2, r_i2c_regs_t::ICSR1, r_i2c_regs_t::ICSR2, internal_i2c_target_classify(), k_ra8_err_not_initialized, k_ra8_i2c_peripheral_event_none, k_ra8_i2c_peripheral_poll_limit, k_ra8_ok, priv_ra8_i2c_internal_peripheral_poll_done(), RA8_CHECK_NULL_PTR, ra8_i2c_regs(), and s_i2c_state.

◆ ra8_i2c_peripheral_receive()

ra8_err_t ra8_i2c_peripheral_receive ( uint8_t channel,
uint8_t * buf,
uint32_t capacity,
uint32_t * out_received )
nodiscard

Drain a controller-write transaction into buf (target receive).

Mirrors HUM Ch 39.3.6 "Peripheral Receive Operation" p 2408: dummy-read ICDRR to discard the matched address byte, then read each data byte from ICDRR as ICSR2.RDRF sets, stopping when ICSR2.STOP is detected or buf fills. Clears ICSR2.STOP before returning. Clock stretching (if armed) gives the loop time to read each byte before the controller clocks the next.

State machine: RX_ACTIVE --RDRF--> store byte ... --STOP|full--> IDLE.

Parameters
[in]channelChannel index.
[out]bufDestination buffer (non-NULL).
[in]capacityBuffer size in bytes (non-zero).
[out]out_receivedNumber of bytes stored (non-NULL).
Returns
ra8_err_t.
Return values
k_ra8_okBytes received (possibly zero) up to STOP.
k_ra8_err_null_ptrbuf / out_received NULL or channel invalid.
k_ra8_err_invalid_argcapacity is zero.
k_ra8_err_not_initializedTarget role not armed.
k_ra8_err_hw_timeoutNo byte arrived within the spin budget.
Precondition
Channel armed and ra8_i2c_peripheral_poll returned write.
buf has room for capacity bytes and out_received is writable.
Postcondition
*out_received <= capacity and ICSR2.STOP is cleared.
Bytes [0, *out_received) of buf hold the received payload.
Note
Thread safety: not thread-safe.
Since
0.1.0

Definition at line 483 of file ra8_i2c_peripheral.c.

References g_i2c_tag, r_i2c_regs_t::ICDRR, r_i2c_regs_t::ICSR2, internal_i2c_target_wait(), k_ra8_err_invalid_arg, k_ra8_err_not_initialized, k_ra8_i2c_msk_icsr2_rdrf, k_ra8_i2c_msk_icsr2_stop, k_ra8_ok, priv_ra8_i2c_internal_target_drain_rx(), RA8_CHECK_NULL_PTR, ra8_i2c_regs(), and s_i2c_state.

Referenced by riic_target_on_event().

◆ ra8_i2c_peripheral_transmit()

ra8_err_t ra8_i2c_peripheral_transmit ( uint8_t channel,
const uint8_t * data,
uint32_t len,
uint32_t * out_sent )
nodiscard

Answer a controller-read transaction from data (target transmit).

Mirrors HUM Ch 39.3.5 "Peripheral Transmit Operation" p 2405: push each byte to ICDRT as ICSR2.TDRE sets, stopping when the controller NACKs the last byte it wants (ICSR2.NACKF) or the buffer is exhausted, then waits for TEND / NACKF, dummy-reads ICDRR to release SCL, and clears NACKF / STOP.

State machine: TX_ACTIVE --TDRE--> push byte ... --NACK|sent==len--> IDLE.

Parameters
[in]channelChannel index.
[in]dataSource buffer (non-NULL).
[in]lenBytes available to send (non-zero).
[out]out_sentNumber of bytes the controller accepted (non-NULL).
Returns
ra8_err_t.
Return values
k_ra8_okTransmit completed (controller NACK is a normal end-of-read, not an error).
k_ra8_err_null_ptrdata / out_sent NULL or channel invalid.
k_ra8_err_invalid_arglen is zero.
k_ra8_err_not_initializedTarget role not armed.
k_ra8_err_hw_timeoutTDRE never armed before any byte was sent.
Precondition
Channel armed and ra8_i2c_peripheral_poll returned read.
data holds len bytes and out_sent is writable.
Postcondition
*out_sent <= len and ICSR2.NACKF / STOP are cleared.
SCL is released (ICDRR dummy-read) so the bus is free for the next transaction.
Note
Thread safety: not thread-safe.
Since
0.1.0

Definition at line 519 of file ra8_i2c_peripheral.c.

References g_i2c_tag, internal_i2c_target_fill_tx(), internal_i2c_target_finish_tx(), k_ra8_err_hw_timeout, k_ra8_err_invalid_arg, k_ra8_err_not_initialized, k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_i2c_regs(), and s_i2c_state.

Referenced by riic_target_on_event().