269 frame.tx_fields.address = 0;
270 frame.tx_fields.data = (addr & 0xFFFF);
271 frame.tx_fields.crc = 0;
299 frame.tx_fields.address = (addr) & 0x7F;
300 frame.tx_fields.data =
data;
301 frame.tx_fields.crc = 0;
306static_assert(
sizeof(SPIFrame) == 4,
"SPIFrame must be exactly 4 bytes");
340 uint8_t fault_byte = frame.rx_fault.fault_flags;
342 flags.dig_clk_too_fast = (fault_byte & 0x02) != 0;
343 flags.dig_clk_too_slow = (fault_byte & 0x04) != 0;
344 flags.clk_too_fast = (fault_byte & 0x08) != 0;
345 flags.clk_too_slow = (fault_byte & 0x10) != 0;
346 flags.adc_bandgap_ok = (fault_byte & 0x20) != 0;
347 flags.supply_2v5_ok = (fault_byte & 0x40) != 0;
348 flags.supply_1v5_ok = (fault_byte & 0x80) != 0;
428template <
typename Derived>
446 return static_cast<Derived*
>(
this)->
Init();
459 return static_cast<Derived*
>(
this)->
Deinit();
494 return static_cast<Derived*
>(
this)->
Transfer32(tx_data);
522 std::span<uint32_t> rx_data)
noexcept {
523 return static_cast<Derived*
>(
this)->
TransferMulti(tx_data, rx_data);
541 return static_cast<Derived*
>(
this)->
Delay(microseconds);
562 return static_cast<Derived*
>(
this)->
Configure(config);
575 return static_cast<const Derived*
>(
this)->
IsReady();
588 return static_cast<const Derived*
>(
this)->
GetLastError();
626 return static_cast<Derived*
>(
this)->
GpioSet(pin, signal);
648 return static_cast<Derived*
>(
this)->
GpioRead(pin);
684 void Log(
LogLevel level,
const char* tag,
const char* format, ...) noexcept {
686 va_start(args, format);
687 static_cast<Derived*
>(
this)->
Log(level, tag, format, args);
768 std::span<uint32_t> values,
769 uint16_t& valid_mask) noexcept;
794 bool verify_crc = true) noexcept;
856#if __cpp_concepts >= 201907L
871concept SpiInterfaceLike =
873 { comm.Init() } -> std::same_as<CommResult<void>>;
874 { comm.Transfer32(data) } -> std::same_as<CommResult<uint32_t>>;
875 { comm.IsReady() } -> std::same_as<bool>;
876 { comm.Configure(cfg) } -> std::same_as<CommResult<void>>;
877 { comm.GpioSet(pin, signal) } -> std::same_as<CommResult<void>>;
878 { comm.GpioRead(pin) } -> std::same_as<CommResult<GpioSignal>>;
893template <
typename Derived>
921 const uint32_t tx_words[3] = {dummy_frame.
word, tx_frame.
word,
935 constexpr uint8_t kReadAttempts = 2;
937 uint32_t rx_all[3] = {};
938 uint32_t last_reply = 0;
939 uint32_t last_flush = 0;
940 bool saw_any_frame =
false;
942 for (uint8_t attempt = 0; attempt < kReadAttempts; ++attempt) {
943 auto multi =
static_cast<Derived*
>(
this)->TransferMulti(
944 std::span<const uint32_t>{tx_words}, std::span<uint32_t>{rx_all});
950 last_reply = rx_all[2];
951 last_flush = rx_all[1];
954 candidate.
word = last_reply;
958 if (last_reply == 0U || last_reply == 0xFFFFFFFFU) {
961 saw_any_frame =
true;
967 if (candidate.rx_common.reply_mode == 0x02) {
968 NoteCriticalFault(candidate);
976 const bool width_ok =
978 : (candidate.rx_common.reply_mode == 0x00);
983 return (candidate.rx_common.reply_mode == 0x01)
984 ?
static_cast<uint32_t
>(candidate.rx_22bit.data)
985 :
static_cast<uint32_t
>(candidate.rx_16bit.data);
988 const uint32_t rx_words[2] = {last_flush, last_reply};
995 auto extract_icvid_candidate = [](uint32_t word)
noexcept -> uint16_t {
996 if (word == 0U || word == 0xFFFFFFFFU) {
1001 const uint16_t cands[] = {
1002 static_cast<uint16_t
>(f.rx_16bit.data),
1003 static_cast<uint16_t
>((word >> 8) & 0xFFFFU),
1004 static_cast<uint16_t
>((word >> 16) & 0xFFFFU),
1005 static_cast<uint16_t
>(word & 0xFFFFU),
1007 for (uint16_t c : cands) {
1012 if ((c & 0xFF00U) == 0x8200U || (c & 0xFF00U) == 0x8000U ||
1013 (c & 0xFF00U) == 0xC000U) {
1014 const uint16_t unshift =
1015 static_cast<uint16_t
>((
static_cast<uint32_t
>(c) << 1) & 0xFFFFU);
1023 for (uint32_t word : {rx_words[1], rx_words[0]}) {
1024 const uint16_t
id = extract_icvid_candidate(word);
1026 return static_cast<uint32_t
>(id);
1044template <
typename Derived>
1046 std::span<const uint16_t> addresses, std::span<uint32_t> values,
1047 uint16_t& valid_mask)
noexcept {
1049 const size_t n = addresses.size();
1050 if (n == 0U || n > kMaxPipelinedReads || values.size() != n) {
1059 uint32_t tx_words[kMaxPipelinedReads + 2] = {};
1060 uint32_t rx_words[kMaxPipelinedReads + 2] = {};
1061 tx_words[0] = dummy_frame.
word;
1062 for (
size_t i = 0; i < n; ++i) {
1065 tx_words[i + 1] = cmd.
word;
1068 tx_words[n + 1] = dummy_frame.
word;
1070 const size_t frames = n + 2U;
1071 auto multi =
static_cast<Derived*
>(
this)->TransferMulti(
1072 std::span<const uint32_t>{tx_words, frames},
1073 std::span<uint32_t>{rx_words, frames});
1078 for (
size_t i = 0; i < n; ++i) {
1080 candidate.
word = rx_words[i + 2U];
1081 if (candidate.word == 0U || candidate.word == 0xFFFFFFFFU) {
1084 if (candidate.rx_common.reply_mode == 0x02) {
1088 NoteCriticalFault(candidate);
1096 ? (candidate.rx_common.reply_mode == 0x01)
1097 : (candidate.rx_common.reply_mode == 0x00);
1101 values[i] = (candidate.rx_common.reply_mode == 0x01)
1102 ?
static_cast<uint32_t
>(candidate.rx_22bit.data)
1103 :
static_cast<uint32_t
>(candidate.rx_16bit.data);
1104 valid_mask =
static_cast<uint16_t
>(valid_mask | (1U << i));
1109template <
typename Derived>
1111 bool verify_crc)
noexcept {
1125 const uint32_t tx_words[3] = {dummy_frame.
word, tx_frame.
word,
1127 uint32_t rx_words[3] = {};
1128 auto multi =
static_cast<Derived*
>(
this)->TransferMulti(
1129 std::span<const uint32_t>{tx_words}, std::span<uint32_t>{rx_words});
1136 rx_frame.
word = rx_words[2];
1141 if (rx_frame.rx_common.reply_mode == 0x02) {
1142 NoteCriticalFault(rx_frame);
1152 if (rx_frame.rx_common.reply_mode == 0x00) {
1154 if (rx_frame.rx_16bit.status != 0x00) {
CRTP-based Communication Interface template class.
Definition tle92466ed_spi_interface.hpp:429
CommResult< void > Configure(const SPIConfig &config) noexcept
Configure SPI parameters.
Definition tle92466ed_spi_interface.hpp:561
bool saw_critical_fault_
Definition tle92466ed_spi_interface.hpp:847
static constexpr size_t kMaxPipelinedReads
Largest burst ReadMulti will issue in one CS-session chain.
Definition tle92466ed_spi_interface.hpp:732
SpiInterface & operator=(const SpiInterface &)=delete
SpiInterface(const SpiInterface &)=delete
Prevent copying.
CommResult< GpioSignal > GpioRead(CtrlPin pin) noexcept
Read GPIO control pin signal state (input state).
Definition tle92466ed_spi_interface.hpp:647
void Log(LogLevel level, const char *tag, const char *format,...) noexcept
Log a message with specified severity level and tag.
Definition tle92466ed_spi_interface.hpp:684
uint8_t last_critical_fault_flags_
Definition tle92466ed_spi_interface.hpp:846
CommResult< uint32_t > Transfer32(uint32_t tx_data) noexcept
Transfer 32-bit data via SPI (full-duplex)
Definition tle92466ed_spi_interface.hpp:493
CommResult< uint32_t > Read(uint16_t address, bool verify_crc=true) noexcept
Read a register from the TLE92466ED (High-Level API)
Definition tle92466ed_spi_interface.hpp:894
void NoteCriticalFault(const SPIFrame &frame) noexcept
Latch a critical-fault reply so callers can report the cause.
Definition tle92466ed_spi_interface.hpp:841
SpiInterface(SpiInterface &&) noexcept=default
Allow moving.
~SpiInterface()=default
Protected destructor.
CommResult< void > GpioSetInactive(CtrlPin pin) noexcept
Set GPIO pin to inactive state (convenience method).
Definition tle92466ed_spi_interface.hpp:665
CommResult< void > Deinit() noexcept
Deinitialize the hardware interface.
Definition tle92466ed_spi_interface.hpp:458
CommResult< void > ReadMulti(std::span< const uint16_t > addresses, std::span< uint32_t > values, uint16_t &valid_mask) noexcept
Read several registers in ONE pipelined chain.
Definition tle92466ed_spi_interface.hpp:1045
CommResult< void > ClearErrors() noexcept
Clear any pending errors.
Definition tle92466ed_spi_interface.hpp:600
CommResult< void > Init() noexcept
Initialize the hardware interface.
Definition tle92466ed_spi_interface.hpp:445
CommResult< void > Write(uint16_t address, uint16_t value, bool verify_crc=true) noexcept
Write a register to the TLE92466ED (High-Level API)
Definition tle92466ed_spi_interface.hpp:1110
uint8_t LastCriticalFaultFlags() const noexcept
Fault byte from the most recent critical-fault reply frame.
Definition tle92466ed_spi_interface.hpp:810
CommResult< void > GpioSet(CtrlPin pin, GpioSignal signal) noexcept
Set GPIO control pin signal state (output control).
Definition tle92466ed_spi_interface.hpp:625
CommResult< void > Delay(uint32_t microseconds) noexcept
Delay for specified duration.
Definition tle92466ed_spi_interface.hpp:540
CommError GetLastError() const noexcept
Get the last error that occurred.
Definition tle92466ed_spi_interface.hpp:587
CommResult< void > GpioSetActive(CtrlPin pin) noexcept
Set GPIO pin to active state (convenience method).
Definition tle92466ed_spi_interface.hpp:656
CommResult< void > TransferMulti(std::span< const uint32_t > tx_data, std::span< uint32_t > rx_data) noexcept
Transfer multiple 32-bit words via SPI in one CS assertion window.
Definition tle92466ed_spi_interface.hpp:521
bool IsReady() const noexcept
Check if hardware is ready for communication.
Definition tle92466ed_spi_interface.hpp:574
bool SawCriticalFault() const noexcept
True once a critical-fault reply frame has been decoded.
Definition tle92466ed_spi_interface.hpp:815
SpiInterface()=default
Protected constructor to prevent direct instantiation.
Expected type — holds either a value of type T or an error of type E.
Definition tle92466ed_expected.hpp:82
Wrapper for an error value (mirrors std::unexpected)
Definition tle92466ed_expected.hpp:56
constexpr uint16_t ICVID
IC Version and ID.
Definition tle92466ed_registers.hpp:59
constexpr bool IsValidDevice(uint16_t icvid) noexcept
Check if ICVID value is valid for TLE92466ED.
Definition tle92466ed_registers.hpp:101
Definition tle92466ed.hpp:15
GpioSignal
GPIO signal states with board-agnostic naming.
Definition tle92466ed_spi_interface.hpp:88
@ ACTIVE
Active signal state (logical active)
@ INACTIVE
Inactive signal state (logical inactive)
SPIStatus
SPI Status codes.
Definition tle92466ed_spi_interface.hpp:366
@ SPI_FRAME_ERROR
SPI frame error.
@ INTERNAL_BUS_FAULT
Internal bus fault.
@ WRITE_RO_REG
Write to read-only register.
@ CRC_ERROR
Parity/CRC error.
@ InvalidParameter
Invalid parameter value.
@ CRCError
CRC mismatch in SPI communication.
CtrlPin
Control pin enumeration for TLE92466ED.
Definition tle92466ed_spi_interface.hpp:73
@ RESN
Reset pin (active low) - Must be HIGH for device operation.
@ FAULTN
Fault pin (active low) - Indicates device fault condition.
@ EN
Enable pin (active high) - Enables/disables output channels.
bool VerifyFrameCrc(const tle92466ed::SPIFrame &frame) noexcept
Verify CRC in received frame.
Definition tle92466ed_registers.hpp:2357
ExpectedReply
Reply-frame width a register is required to answer with.
Definition tle92466ed_registers.hpp:2117
@ Bits22
Reply mode 01B — 22-bit data, no status field.
CommError
Error codes for communication interface operations.
Definition tle92466ed_spi_interface.hpp:45
@ BusError
SPI bus communication error.
@ HardwareNotReady
Hardware not initialized or ready.
@ InvalidParameter
Invalid parameter passed to function.
@ BufferOverflow
Buffer size exceeded.
@ CRCError
CRC mismatch error.
@ NoReply
MISO carried no frame at all (all-zero or all-ones word).
@ TransferError
Data transfer failed.
@ UnknownError
Unknown error occurred.
@ Timeout
Operation timed out.
ReplyMode
SPI Reply Mode enumeration.
Definition tle92466ed_spi_interface.hpp:356
@ REPLY_16BIT
16-bit reply frame
@ REPLY_22BIT
22-bit reply frame (extended data)
@ CRITICAL_FAULT
Critical fault frame.
constexpr ExpectedReply ExpectedReplyFor(uint16_t address) noexcept
Reply width the device must use when answering a read of address.
Definition tle92466ed_registers.hpp:2143
uint8_t CalculateFrameCrc(const tle92466ed::SPIFrame &frame) noexcept
Calculate CRC for SPI frame.
Definition tle92466ed_registers.hpp:2343
LogLevel
Log severity levels for driver logging.
Definition tle92466ed_spi_interface.hpp:99
@ Info
Informational messages.
@ Error
Error messages (highest severity)
@ Debug
Debug messages (lowest severity)
@ Verbose
Verbose messages (lowest severity, most detailed)
Helper structure for critical fault frame flags.
Definition tle92466ed_spi_interface.hpp:323
bool dig_clk_too_fast
Bit 1: Digital clock too fast (1=YES, 0=NO)
Definition tle92466ed_spi_interface.hpp:325
static constexpr CriticalFaultFlags Extract(const SPIFrame &frame) noexcept
Extract fault flags from critical fault frame.
Definition tle92466ed_spi_interface.hpp:338
bool clk_too_fast
Bit 3: Clock too fast (1=YES, 0=NO)
Definition tle92466ed_spi_interface.hpp:327
bool supply_2v5_ok
Bit 6: 2V5 supply OK (1=OK, 0=NOT OK)
Definition tle92466ed_spi_interface.hpp:330
bool dig_clk_too_slow
Bit 2: Digital clock too slow (1=YES, 0=NO)
Definition tle92466ed_spi_interface.hpp:326
bool supply_1v5_ok
Bit 7: 1V5 supply OK (1=OK, 0=NOT OK)
Definition tle92466ed_spi_interface.hpp:331
bool clk_too_slow
Bit 4: Clock too slow (1=YES, 0=NO)
Definition tle92466ed_spi_interface.hpp:328
bool wd_ref_clk_missing
Bit 0: Clock watchdog reference clock missing (1=MISSING, 0=OK)
Definition tle92466ed_spi_interface.hpp:324
bool adc_bandgap_ok
Bit 5: ADC Bandgap OK (1=OK, 0=NOT OK)
Definition tle92466ed_spi_interface.hpp:329
SPI transaction configuration.
Definition tle92466ed_spi_interface.hpp:131
uint8_t mode
SPI mode (CPOL=0, CPHA=1 for TLE92466ED)
Definition tle92466ed_spi_interface.hpp:133
bool msb_first
MSB first transmission.
Definition tle92466ed_spi_interface.hpp:134
uint32_t frequency
SPI clock frequency in Hz (max 8 MHz, datasheet 5.1.4 Table 18)
Definition tle92466ed_spi_interface.hpp:132
uint32_t timeout_ms
Transaction timeout in milliseconds.
Definition tle92466ed_spi_interface.hpp:135
C++20-compatible expected<T,E> polyfill for TLE92466ED driver.
Register definitions and bit field mappings for TLE92466ED.
32-bit SPI frame structure for TLE92466ED communication
Definition tle92466ed_spi_interface.hpp:200
uint32_t _field_16
Field at bit 16 (interpretation depends on reply mode)
Definition tle92466ed_spi_interface.hpp:214
struct tle92466ed::SPIFrame::@1 rx_common
MISO (Receive) frame structure - common fields.
uint32_t data
Data field [15:0].
Definition tle92466ed_spi_interface.hpp:205
uint32_t fault_flags
Fault flags [7:0].
Definition tle92466ed_spi_interface.hpp:238
uint32_t _reserved2
Reserved/Don't care [16].
Definition tle92466ed_spi_interface.hpp:240
uint32_t crc
CRC-8 SAE J1850 [31:24].
Definition tle92466ed_spi_interface.hpp:208
uint32_t address
Register address [23:17].
Definition tle92466ed_spi_interface.hpp:207
uint32_t reply_mode
Reply mode [23:22] - determines frame type.
Definition tle92466ed_spi_interface.hpp:216
uint32_t _reserved
Reserved/Don't care [15:8].
Definition tle92466ed_spi_interface.hpp:239
uint32_t rw_echo
R/W bit echoed [16].
Definition tle92466ed_spi_interface.hpp:223
struct tle92466ed::SPIFrame::@0 tx_fields
MOSI (Transmit) frame structure.
uint32_t _dont_care
Don't care [31:24] (not CRC in fault frames)
Definition tle92466ed_spi_interface.hpp:243
uint32_t _reserved3
Reserved/Don't care [21:17].
Definition tle92466ed_spi_interface.hpp:241
uint32_t _data_low
Lower data bits [15:0] (interpretation depends on reply mode)
Definition tle92466ed_spi_interface.hpp:213
struct tle92466ed::SPIFrame::@2 rx_16bit
MISO 16-bit Reply Frame (Reply Mode = 00B)
struct tle92466ed::SPIFrame::@4 rx_fault
MISO Critical Fault Frame (Reply Mode = 10B)
uint32_t rw
Read/Write bit [16] (1=Write, 0=Read)
Definition tle92466ed_spi_interface.hpp:206
uint32_t _field_17_21
Fields at bits 21:17 (interpretation depends on reply mode)
Definition tle92466ed_spi_interface.hpp:215
uint32_t status
Status bits [21:17].
Definition tle92466ed_spi_interface.hpp:224
uint32_t word
Complete 32-bit frame.
Definition tle92466ed_spi_interface.hpp:201
static constexpr SPIFrame MakeRead(uint16_t addr) noexcept
Construct read frame (without CRC - must be calculated separately)
Definition tle92466ed_spi_interface.hpp:266
static constexpr SPIFrame MakeWrite(uint16_t addr, uint16_t data) noexcept
Construct write frame (without CRC - must be calculated separately)
Definition tle92466ed_spi_interface.hpp:296
struct tle92466ed::SPIFrame::@3 rx_22bit
MISO 22-bit Reply Frame (Reply Mode = 01B)