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

SMBus 3.2 protocol layer over an injected I2C bus seam – implementation. More...

#include "ra8_smbus.h"
#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_err.h"
#include "ra8_i2c_bus_ops.h"
#include "ra8_log.h"
Include dependency graph for ra8_smbus.c:

Go to the source code of this file.

Data Structures

struct  ra8_smbus_state_t
 Module state: latched at init time. More...

Enumerations

enum  smbus_buf_size_t : uint16_t {
  k_smbus_frame_bytes = 258U ,
  k_smbus_rx_bytes = 257U
}
 SMBus scratch buffer sizes (max 255-byte payload + overhead). More...
enum  ra8_smbus_internal_t : uint16_t {
  k_ra8_smbus_pec_poly = 0x07U ,
  k_ra8_smbus_pec_init = 0x00U ,
  k_ra8_smbus_addr_shift = 1U ,
  k_ra8_smbus_rw_write = 0U ,
  k_ra8_smbus_rw_read = 1U ,
  k_ra8_smbus_msb_for_byte = 8U ,
  k_ra8_smbus_pec_top_bit = 0x80U ,
  k_ra8_smbus_byte_mask = 0xFFU
}
 Implementation constants. More...

Functions

static uint8_t internal_pec_update (uint8_t crc, uint8_t b)
 Update one byte into a running CRC-8/SMBus accumulator.
uint8_t ra8_smbus_pec (const uint8_t *data, uint32_t len)
 Compute CRC-8/SMBus over a buffer.
static uint8_t internal_make_addr_byte (uint8_t target_7b, uint8_t rw_bit)
ra8_err_t ra8_smbus_init (const ra8_smbus_cfg_t *cfg)
 Initialise the SMBus layer over the injected bus seam.
ra8_err_t ra8_smbus_deinit (void)
 Tear the SMBus layer down and release the driver slot.
ra8_err_t ra8_smbus_send_byte (uint8_t target_7b, uint8_t data)
 Send Byte transaction (SMBus 3.2 section 6.5.2).
ra8_err_t ra8_smbus_receive_byte (uint8_t target_7b, uint8_t *out_data)
 Receive Byte transaction (SMBus 3.2 section 6.5.3).
ra8_err_t ra8_smbus_write_byte_data (uint8_t target_7b, uint8_t cmd, uint8_t data)
 Write Byte Data: register-indexed byte write (SMBus 3.2 sec 6.5.4).
ra8_err_t ra8_smbus_read_byte_data (uint8_t target_7b, uint8_t cmd, uint8_t *out_data)
 Read Byte Data: register-indexed byte read (SMBus 3.2 sec 6.5.5).
ra8_err_t ra8_smbus_block_write (uint8_t target_7b, uint8_t cmd, const uint8_t *data, uint8_t len)
 Block Write (SMBus 3.2 section 6.5.7).
static ra8_err_t internal_block_read_pec_check (uint8_t target_7b, uint8_t cmd, const uint8_t *buf, uint8_t count, uint8_t pec_rx)
 Verify the PEC byte of a completed Block Read transfer.
static ra8_err_t internal_block_read_finish (uint8_t target_7b, uint8_t cmd, const uint8_t *rx, uint8_t cap, uint8_t *buf, uint8_t *out_len)
 Unpack a completed Block Read transfer into the caller buffer.
ra8_err_t ra8_smbus_block_read (uint8_t target_7b, uint8_t cmd, uint8_t *buf, uint8_t cap, uint8_t *out_len)
 Block Read (SMBus 3.2 section 6.5.8).
ra8_err_t ra8_smbus_alert_register_callback (ra8_smbus_alert_fn_t fn, void *ctx)
 Register a callback fired when ra8_smbus_alert_dispatch successfully reads the Alert Response Address.
ra8_err_t ra8_smbus_alert_dispatch (void)
 Dispatch a single SMBALERT# event: read the ARA and fire the registered callback.

Variables

static const char * s_tag = "SMBUS"
 Log tag for this driver.
static ra8_smbus_state_t s_state
 Singleton driver state.

Detailed Description

SMBus 3.2 protocol layer over an injected I2C bus seam – implementation.

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

Builds the SMBus 3.2 wire frames into a small stack scratch buffer and hands them to the injected I2C bus seam (ra8_i2c_bus_ops_t) latched at init. PEC (Packet Error Code) is computed with the SMBus 3.2 section 5.4 CRC-8 (poly 0x07, init 0). The bus drivers are untouched – this file is pure protocol framing.

Section references in the comment headers below are to the SMBus 3.2 specification (SBS-IF, December 2018).

Definition in file ra8_smbus.c.

Enumeration Type Documentation

◆ ra8_smbus_internal_t

enum ra8_smbus_internal_t : uint16_t

Implementation constants.

Enumerator
k_ra8_smbus_pec_poly 

CRC-8 polynomial (SMBus 3.2 5.4).

k_ra8_smbus_pec_init 

CRC-8 initial value.

k_ra8_smbus_addr_shift 

7-bit -> 8-bit address shift.

k_ra8_smbus_rw_write 

R/W bit value for write.

k_ra8_smbus_rw_read 

R/W bit value for read.

k_ra8_smbus_msb_for_byte 

MSB index for byte-loop pec calc.

k_ra8_smbus_pec_top_bit 

Top bit mask used by pec loop.

k_ra8_smbus_byte_mask 

8-bit narrowing mask.

Definition at line 46 of file ra8_smbus.c.

◆ smbus_buf_size_t

enum smbus_buf_size_t : uint16_t

SMBus scratch buffer sizes (max 255-byte payload + overhead).

Enumerator
k_smbus_frame_bytes 

Smbus frame bytes.

k_smbus_rx_bytes 

Smbus RX bytes.

Definition at line 37 of file ra8_smbus.c.

Function Documentation

◆ internal_block_read_finish()

ra8_err_t internal_block_read_finish ( uint8_t target_7b,
uint8_t cmd,
const uint8_t * rx,
uint8_t cap,
uint8_t * buf,
uint8_t * out_len )
static

Unpack a completed Block Read transfer into the caller buffer.

The combined transfer left [count] [data...] [optional PEC] in rx. Publish the peripheral-reported count, bound it against the caller's capacity, copy the payload out, and (when PEC is enabled) verify the trailing PEC byte via internal_block_read_pec_check.

Parameters
[in]target_7b7-bit peripheral address (for the PEC frame).
[in]cmdCommand code that selected the block.
[in]rxRaw transfer buffer from the bus seam.
[in]capCaller buffer capacity in bytes.
[out]bufReceives the payload bytes.
[out]out_lenReceives the peripheral-reported byte count.
Returns
ra8_err_t error code.
Return values
k_ra8_okPayload copied (and PEC verified).
k_ra8_err_invalid_sizePeripheral count exceeds cap.
k_ra8_err_crc_mismatchPEC byte did not match the frame.
Precondition
rx holds a completed transfer of cap + 1 bytes (one more with PEC enabled), so every index this helper reads is in range.
buf and out_len are non-NULL (checked by the caller).
Postcondition
*out_len is set even when the count exceeds cap.
buf holds count payload bytes on success.
Note
Reads module PEC state; call from the block-read path only.
Since
0.1.0

Definition at line 406 of file ra8_smbus.c.

References internal_block_read_pec_check(), k_ra8_err_invalid_size, k_ra8_ok, and s_state.

Referenced by ra8_smbus_block_read().

◆ internal_block_read_pec_check()

ra8_err_t internal_block_read_pec_check ( uint8_t target_7b,
uint8_t cmd,
const uint8_t * buf,
uint8_t count,
uint8_t pec_rx )
static

Verify the PEC byte of a completed Block Read transfer.

Recomputes the SMBus 3.2 5.4 CRC-8 over the full wire frame of the combined transfer – write-address byte, command, read-address byte, byte count, then the count payload bytes – and compares it with the PEC byte the peripheral appended after the payload.

Parameters
[in]target_7b7-bit peripheral address.
[in]cmdCommand code that selected the block.
[in]bufPayload bytes copied out of the transfer.
[in]countPayload byte count reported by the peripheral.
[in]pec_rxPEC byte received after the payload.
Returns
ra8_err_t error code.
Return values
k_ra8_okPEC matches the received frame.
k_ra8_err_crc_mismatchComputed PEC differs from pec_rx.
Precondition
buf holds at least count bytes.
PEC was enabled at init time (caller checks pec_enabled).
Postcondition
No state is mutated.
Return value depends only on the inputs.
Note
Pure computation; safe from any context.
Since
0.1.0

Definition at line 353 of file ra8_smbus.c.

References internal_make_addr_byte(), internal_pec_update(), k_ra8_err_crc_mismatch, k_ra8_ok, k_ra8_smbus_pec_init, k_ra8_smbus_rw_read, k_ra8_smbus_rw_write, ra8_log_error, and s_tag.

Referenced by internal_block_read_finish().

◆ internal_make_addr_byte()

uint8_t internal_make_addr_byte ( uint8_t target_7b,
uint8_t rw_bit )
static

◆ internal_pec_update()

uint8_t internal_pec_update ( uint8_t crc,
uint8_t b )
static

Update one byte into a running CRC-8/SMBus accumulator.

Bitwise implementation – 8 shifts per byte. With the firmware's call frequency (a handful of SMBus transactions per second) a table lookup would be premature optimisation, and it would burn 256 bytes of MRAM. The poly and init values are mandated by SMBus 3.2 5.4.

Parameters
[in]crcCurrent CRC.
[in]bByte to fold in.
Returns
Updated CRC.
Return values
0Success or default value.
Precondition
Module has been initialized.
Caller has validated arguments.
Postcondition
Side effects bounded to documented state.
State reflects operation result.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 109 of file ra8_smbus.c.

References k_ra8_smbus_msb_for_byte, k_ra8_smbus_pec_poly, k_ra8_smbus_pec_top_bit, and RA8_INTERNAL.

Referenced by internal_block_read_pec_check(), ra8_smbus_block_write(), ra8_smbus_pec(), ra8_smbus_read_byte_data(), ra8_smbus_receive_byte(), ra8_smbus_send_byte(), and ra8_smbus_write_byte_data().

◆ ra8_smbus_alert_dispatch()

ra8_err_t ra8_smbus_alert_dispatch ( void )
nodiscard

Dispatch a single SMBALERT# event: read the ARA and fire the registered callback.

Reads one byte from address k_ra8_smbus_alert_addr_7b (0x0C). The returned byte's upper 7 bits are the 7-bit address of the peripheral that asserted ALERT (SMBus 3.2 section 6.5.13). The LSB is the device status. If no callback has been registered the read still happens (so the bus line is released) but no further action is taken.

Test-callable: unit tests invoke this directly to simulate an ALERT event.

Returns
ra8_err_t.
Return values
k_ra8_okDispatch completed (callback fired if registered).
k_ra8_err_not_initializedInit not run.
Forwardedcodes from the bus seam read.
Precondition
ra8_smbus_init previously succeeded.
Postcondition
Bus is released.
Since
0.1.0

Definition at line 472 of file ra8_smbus.c.

References k_ra8_err_not_initialized, k_ra8_ok, k_ra8_smbus_addr_shift, k_ra8_smbus_alert_addr_7b, and s_state.

◆ ra8_smbus_alert_register_callback()

ra8_err_t ra8_smbus_alert_register_callback ( ra8_smbus_alert_fn_t fn,
void * ctx )
nodiscard

Register a callback fired when ra8_smbus_alert_dispatch successfully reads the Alert Response Address.

SMBus 3.2 section 6.5.13 specifies that a peripheral asserts SMBALERT# (an open-drain side-band line, not SDA/SCL) and the controller responds by reading from address 0x0C (ARA). The peripheral that won arbitration writes its 7-bit address back into the LSBs of the response byte. Because SMBALERT# is a board-level GPIO interrupt, this driver does not own the IRQ wiring – the caller arms ra8_icu to call ra8_smbus_alert_dispatch() from the SMBALERT# ISR, and the dispatch helper performs the ARA read and fires the registered callback.

Parameters
[in]fnCallback to fire, or NULL to detach.
[in]ctxContext pointer passed back unchanged.
Returns
ra8_err_t.
Return values
k_ra8_okCallback registered or detached.
k_ra8_err_not_initializedInit not run.
Since
0.1.0

Definition at line 461 of file ra8_smbus.c.

References k_ra8_err_not_initialized, k_ra8_ok, and s_state.

◆ ra8_smbus_block_read()

ra8_err_t ra8_smbus_block_read ( uint8_t target_7b,
uint8_t cmd,
uint8_t * buf,
uint8_t cap,
uint8_t * out_len )
nodiscard

Block Read (SMBus 3.2 section 6.5.8).

Wire format with PEC disabled: S | addr_w | cmd | Sr | addr_r | count | data[0..count-1] | P With PEC enabled the PEC trails the data run.

Parameters
[in]target_7b7-bit peripheral address.
[in]cmdCommand / register index byte.
[out]bufDestination buffer (non-NULL, capacity cap).
[in]capCapacity of buf (1..255).
[out]out_lenBytes actually returned by the peripheral (the count field). Always populated on k_ra8_ok and on k_ra8_err_invalid_size.
Returns
ra8_err_t.
Return values
k_ra8_okBlock received and PEC matched if on.
k_ra8_err_null_ptrbuf / out_len NULL.
k_ra8_err_invalid_argcap is 0 or > 255.
k_ra8_err_invalid_sizeReturned count exceeds cap.
k_ra8_err_not_initializedInit not run.
k_ra8_err_crc_mismatchPEC verification failed.
Forwardedcodes from the bus seam write / read.
Precondition
ra8_smbus_init previously succeeded.
Postcondition
STOP is issued regardless of outcome.
Since
0.1.0

Definition at line 433 of file ra8_smbus.c.

References internal_block_read_finish(), k_ra8_err_invalid_arg, k_ra8_err_not_initialized, k_ra8_ok, k_smbus_rx_bytes, RA8_CHECK_NULL_PTR, s_state, and s_tag.

◆ ra8_smbus_block_write()

ra8_err_t ra8_smbus_block_write ( uint8_t target_7b,
uint8_t cmd,
const uint8_t * data,
uint8_t len )
nodiscard

Block Write (SMBus 3.2 section 6.5.7).

Wire format with PEC disabled: S | addr_w | cmd | count | data[0..count-1] | P With PEC enabled the PEC byte is inserted before the STOP. The count byte is mandatory and must equal len (1..255).

Parameters
[in]target_7b7-bit peripheral address.
[in]cmdCommand / register index byte.
[in]dataPayload buffer (non-NULL when len > 0).
[in]lenNumber of bytes (1..255).
Returns
ra8_err_t.
Return values
k_ra8_okBlock written.
k_ra8_err_null_ptrdata NULL with non-zero len.
k_ra8_err_invalid_arglen is 0 or > 255.
k_ra8_err_not_initializedInit not run.
Forwardedcodes from the bus seam write.
Precondition
ra8_smbus_init previously succeeded.
Postcondition
STOP is issued.
Since
0.1.0

Definition at line 294 of file ra8_smbus.c.

References internal_make_addr_byte(), internal_pec_update(), k_ra8_err_invalid_arg, k_ra8_err_not_initialized, k_ra8_smbus_pec_init, k_ra8_smbus_rw_write, k_smbus_frame_bytes, RA8_CHECK_NULL_PTR, s_state, and s_tag.

◆ ra8_smbus_deinit()

ra8_err_t ra8_smbus_deinit ( void )
nodiscard

Tear the SMBus layer down and release the driver slot.

Returns
ra8_err_t.
Return values
k_ra8_okLayer released.
k_ra8_err_not_initializedra8_smbus_init never ran.
Precondition
Caller is not in the middle of a transaction.
Postcondition
The layer rejects transactions until the next init; the app keeps owning the bus peripheral behind the injected seam.
Since
0.1.0

Definition at line 175 of file ra8_smbus.c.

References k_ra8_err_not_initialized, k_ra8_ok, and s_state.

◆ ra8_smbus_init()

ra8_err_t ra8_smbus_init ( const ra8_smbus_cfg_t * cfg)
nodiscard

Initialise the SMBus layer over the injected bus seam.

Latches cfg->bus and the policy bits (PEC enable) for later transfers. The bus peripheral behind the seam is initialised by the app before this call – this layer never brings hardware up or down.

Parameters
[in]cfgConfiguration descriptor.
Returns
ra8_err_t.
Return values
k_ra8_okSMBus layer ready.
k_ra8_err_null_ptrcfg is NULL.
k_ra8_err_invalid_argcfg->bus seam incomplete (a NULL op).
Precondition
IRQs masked or single-threaded init context.
The bus peripheral behind cfg->bus is initialised.
Postcondition
On success the layer accepts SMBus transactions.
Note
Thread safety: not thread-safe.
See also
ra8_i2c_bus_ops_t
Since
0.1.0

Definition at line 152 of file ra8_smbus.c.

References ra8_smbus_cfg_t::bus, k_ra8_err_invalid_arg, k_ra8_ok, ra8_smbus_cfg_t::pec_enabled, RA8_CHECK_NULL_PTR, ra8_log_error, ra8_i2c_bus_ops_t::read, s_state, s_tag, ra8_i2c_bus_ops_t::transfer, and ra8_i2c_bus_ops_t::write.

Referenced by main().

◆ ra8_smbus_pec()

uint8_t ra8_smbus_pec ( const uint8_t * data,
uint32_t len )

Compute CRC-8/SMBus over a buffer.

Polynomial 0x07, initial value 0x00, no reflection, no XOR-out (SMBus 3.2 section 5.4). Provided as a public symbol so tests can cross-check the framing; production code should not need to call this directly.

Parameters
[in]dataPointer to bytes (non-NULL when len > 0).
[in]lenByte count.
Returns
Computed CRC-8 value.
Return values
0x00Either len == 0 or the input bytes happen to hash to zero.
otherComputed CRC-8 over data[0..len-1] per SMBus 3.2 section 5.4.
Precondition
data != NULL when len > 0.
len reflects the true buffer size (no aliasing past len).
Postcondition
Function is pure – no firmware state mutated.
Result depends only on data and len.
Note
Thread-safe: pure function with no shared state.
Since
0.1.0

Definition at line 122 of file ra8_smbus.c.

References internal_pec_update(), and k_ra8_smbus_pec_init.

◆ ra8_smbus_read_byte_data()

ra8_err_t ra8_smbus_read_byte_data ( uint8_t target_7b,
uint8_t cmd,
uint8_t * out_data )
nodiscard

Read Byte Data: register-indexed byte read (SMBus 3.2 sec 6.5.5).

Wire format with PEC disabled: S | addr_w | cmd | Sr | addr_r | data | P With PEC enabled: S | addr_w | cmd | Sr | addr_r | data | PEC | P

The PEC is computed over addr_w | cmd | addr_r | data.

Parameters
[in]target_7b7-bit peripheral address.
[in]cmdCommand / register index byte.
[out]out_dataDestination byte (non-NULL).
Returns
ra8_err_t.
Return values
k_ra8_okByte read (and PEC matched if enabled).
k_ra8_err_null_ptrout_data NULL.
k_ra8_err_not_initializedInit not run.
k_ra8_err_crc_mismatchPEC verification failed.
Forwardedcodes from the bus seam write / read.
Precondition
ra8_smbus_init previously succeeded.
Postcondition
STOP is issued.
Since
0.1.0

Definition at line 259 of file ra8_smbus.c.

References internal_make_addr_byte(), internal_pec_update(), k_ra8_err_crc_mismatch, k_ra8_err_not_initialized, k_ra8_ok, k_ra8_smbus_pec_init, k_ra8_smbus_rw_read, k_ra8_smbus_rw_write, RA8_CHECK_NULL_PTR, ra8_log_error, s_state, and s_tag.

Referenced by bm_read_or_halt(), and sd_read_whoami_or_halt().

◆ ra8_smbus_receive_byte()

ra8_err_t ra8_smbus_receive_byte ( uint8_t target_7b,
uint8_t * out_data )
nodiscard

Receive Byte transaction (SMBus 3.2 section 6.5.3).

Wire format with PEC disabled: S | (addr<<1)|1 | data | P With PEC enabled: S | (addr<<1)|1 | data | PEC | P

Parameters
[in]target_7b7-bit peripheral address.
[out]out_dataDestination byte (non-NULL).
Returns
ra8_err_t.
Return values
k_ra8_okByte received (and PEC matched if enabled).
k_ra8_err_null_ptrout_data is NULL.
k_ra8_err_not_initializedInit not run.
k_ra8_err_crc_mismatchPEC verification failed.
Forwardedcodes from the bus seam read.
Precondition
ra8_smbus_init previously succeeded.
Postcondition
STOP is issued, bus is released.
Since
0.1.0

Definition at line 210 of file ra8_smbus.c.

References internal_make_addr_byte(), internal_pec_update(), k_ra8_err_crc_mismatch, k_ra8_err_not_initialized, k_ra8_ok, k_ra8_smbus_pec_init, k_ra8_smbus_rw_read, RA8_CHECK_NULL_PTR, ra8_log_error, s_state, and s_tag.

Referenced by sd_read_whoami_or_halt().

◆ ra8_smbus_send_byte()

ra8_err_t ra8_smbus_send_byte ( uint8_t target_7b,
uint8_t data )
nodiscard

Send Byte transaction (SMBus 3.2 section 6.5.2).

Wire format with PEC disabled: S | (addr<<1)|0 | data | P With PEC enabled: S | (addr<<1)|0 | data | PEC | P

The PEC is computed over the address byte and the data byte using CRC-8 polynomial 0x07, init 0 (SMBus 3.2 section 5.4).

Parameters
[in]target_7b7-bit peripheral address.
[in]dataSingle data byte to transmit.
Returns
ra8_err_t.
Return values
k_ra8_okByte delivered.
k_ra8_err_not_initializedInit not run.
Forwardedcodes from the bus seam write.
Precondition
ra8_smbus_init previously succeeded.
Postcondition
STOP is issued, bus is released.
Since
0.1.0

Definition at line 191 of file ra8_smbus.c.

References internal_make_addr_byte(), internal_pec_update(), k_ra8_err_not_initialized, k_ra8_smbus_pec_init, k_ra8_smbus_rw_write, and s_state.

Referenced by sd_read_whoami_or_halt().

◆ ra8_smbus_write_byte_data()

ra8_err_t ra8_smbus_write_byte_data ( uint8_t target_7b,
uint8_t cmd,
uint8_t data )
nodiscard

Write Byte Data: register-indexed byte write (SMBus 3.2 sec 6.5.4).

Wire format with PEC disabled: S | addr_w | cmd | data | P With PEC enabled the PEC is appended before the STOP.

Parameters
[in]target_7b7-bit peripheral address.
[in]cmdCommand / register index byte.
[in]dataData byte to write.
Returns
ra8_err_t.
Return values
k_ra8_okByte written.
k_ra8_err_not_initializedInit not run.
Forwardedcodes from the bus seam write.
Precondition
ra8_smbus_init previously succeeded.
Postcondition
STOP is issued.
Since
0.1.0

Definition at line 240 of file ra8_smbus.c.

References internal_make_addr_byte(), internal_pec_update(), k_ra8_err_not_initialized, k_ra8_smbus_pec_init, k_ra8_smbus_rw_write, and s_state.

Variable Documentation

◆ s_state

ra8_smbus_state_t s_state
static
Initial value:
= {
.initialized = false,
.bus = {},
.pec_enabled = false,
.alert_fn = nullptr,
.alert_ctx = nullptr,
}

Singleton driver state.

Definition at line 73 of file ra8_smbus.c.

◆ s_tag

const char* s_tag = "SMBUS"
static

Log tag for this driver.

Definition at line 34 of file ra8_smbus.c.