Platform Integration Guide
This guide explains how to implement the hardware abstraction interface for the TLE92466ED driver on your platform.
Understanding the SPI Interface
The TLE92466ED driver uses a polymorphic SPI interface design for hardware abstraction. This design choice provides several critical benefits for embedded systems:
Why This Design?
1. Hardware Portability
- Write driver code once, run on any platform
- Easy migration between MCUs (ESP32, STM32, Arduino, etc.)
- Platform-specific code isolated in one class
2. Type Safety
- Compile-time interface checking
- Clear contract for required methods
- Catch implementation errors at compile time
3. Modern C++23
- Uses
std::expectedfor error handling (no exceptions) - All functions
noexceptfor embedded safety - Zero-overhead abstractions
How It Works
```cpp
// Base interface class (from tle92466ed_spi_interface.hpp)
class SpiInterface {
public:
virtual auto spiTransfer(std::span
1
virtual void delayMicroseconds(uint32_t us) noexcept = 0; };
// Your implementation
class MySpi : public SpiInterface {
public:
auto spiTransfer(std::span
1
2
3
void delayMicroseconds(uint32_t us) noexcept override {
// Your delay implementation
} }; ```cpp
Interface Definition
The TLE92466ED driver requires you to implement the following interface:
```cpp
class SpiInterface {
public:
// Required methods (implement all of these)
virtual auto spiTransfer(std::span
1
2
3
4
5
6
7
8
virtual void delayMicroseconds(uint32_t us) noexcept = 0;
// Optional control pin methods
virtual auto SetGpioPin(ControlPin pin, ActiveLevel level) noexcept
-> std::expected<void, CommError>;
virtual auto GetGpioPin(ControlPin pin) noexcept
-> std::expected<ActiveLevel, CommError>; }; ```cpp
Implementation Steps
Step 1: Create Your Implementation Class
```cpp #include “tle92466ed_spi_interface.hpp”
class MyPlatformSPI : public tle92466ed::SpiInterface
public: // Constructor MyPlatformSPI(spi_device_handle_t device) : spi_device_(device) {}
1
2
3
4
5
6
7
8
9
10
11
12
// Implement required methods
auto spiTransfer(std::span<const uint8_t> txData,
std::span<uint8_t> rxData) noexcept
-> std::expected<void, tle92466ed::CommError> override {
// Your transfer code - must handle 32-bit frames
// TLE92466ED uses 32-bit SPI frames with CRC-8
return {};
}
void delayMicroseconds(uint32_t us) noexcept override {
// Your delay implementation
} }; ```cpp
Step 2: Platform-Specific Examples
ESP32 (ESP-IDF)
```cpp #include “driver/spi_master.h” #include “tle92466ed_spi_interface.hpp”
class Esp32SPIBus : public tle92466ed::SpiInterface
public: Esp32SPIBus(spi_host_device_t host, const spi_device_interface_config_t& config, gpio_num_t cs) { spi_bus_add_device(host, &config, &spi_device_); cs_pin_ = cs; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
auto spiTransfer(std::span<const uint8_t> txData,
std::span<uint8_t> rxData) noexcept
-> std::expected<void, tle92466ed::CommError> override {
// TLE92466ED uses 32-bit frames
if (txData.size() < 4 || rxData.size() < 4) {
return std::unexpected(tle92466ed::CommError::InvalidParameter);
}
spi_transaction_t trans = {};
trans.length = 32; // 32 bits per frame
trans.tx_buffer = txData.data();
trans.rx_buffer = rxData.data();
esp_err_t ret = spi_device_transmit(spi_device_, &trans);
if (ret != ESP_OK) {
return std::unexpected(tle92466ed::CommError::BusError);
}
return {};
}
void delayMicroseconds(uint32_t us) noexcept override {
esp_rom_delay_us(us);
} }; ```cpp
STM32 (HAL)
```cpp #include “stm32f4xx_hal.h” #include “tle92466ed_spi_interface.hpp”
extern SPI_HandleTypeDef hspi1;
class STM32SPIBus : public tle92466ed::SpiInterface
public: STM32SPIBus(GPIO_TypeDef* cs_port, uint16t cs_pin) : cs_port(cs_port), cs_pin_(cs_pin) {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
auto spiTransfer(std::span<const uint8_t> txData,
std::span<uint8_t> rxData) noexcept
-> std::expected<void, tle92466ed::CommError> override {
// Assert CS
HAL_GPIO_WritePin(cs_port_, cs_pin_, GPIO_PIN_RESET);
// Transfer 32-bit frame (4 bytes)
HAL_StatusTypeDef status = HAL_SPI_TransmitReceive(&hspi1,
const_cast<uint8_t*>(txData.data()),
rxData.data(),
4,
100);
// Deassert CS
HAL_GPIO_WritePin(cs_port_, cs_pin_, GPIO_PIN_SET);
if (status != HAL_OK) {
return std::unexpected(tle92466ed::CommError::BusError);
}
return {};
}
void delayMicroseconds(uint32_t us) noexcept override {
// STM32 HAL delay (approximate)
HAL_Delay((us + 999) / 1000); // Convert to milliseconds
} }; ```cpp
Arduino
```cpp
#include
class ArduinoSPIBus : public tle92466ed::SpiInterface
public: ArduinoSPIBus(uint8t cs_pin) : cs_pin(cs_pin) { pinMode(cs_pin_, OUTPUT); digitalWrite(cs_pin_, HIGH); SPI.begin(); SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE1)); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
auto spiTransfer(std::span<const uint8_t> txData,
std::span<uint8_t> rxData) noexcept
-> std::expected<void, tle92466ed::CommError> override {
digitalWrite(cs_pin_, LOW);
// Transfer 32-bit frame (4 bytes)
for (size_t i = 0; i < 4; i++) {
rxData[i] = SPI.transfer(txData[i]);
}
digitalWrite(cs_pin_, HIGH);
return {};
}
void delayMicroseconds(uint32_t us) noexcept override {
delayMicroseconds(us);
} }; ```cpp
SPI Frame Format
The TLE92466ED uses 32-bit SPI frames with CRC-8 (SAE J1850):
Write Frame Format
cpp
Bits 31-24 | Bits 23-17 | Bit 16 | Bits 15-0
-----------+------------+--------+-----------
CRC (8-bit)| Address(7) | R/W | Data (16)
| | 1=W |
cpp
Read Frame Format
cpp
Bits 31-24 | Bits 23-17 | Bit 16 | Bits 15-0
-----------+------------+--------+-----------
CRC (8-bit)| Don't Care | R/W | Address (16-bit)
| | 0=R |
text
SPI Configuration
- Mode: SPI Mode 1 (CPOL=0, CPHA=1)
- Speed: Up to 10 MHz
- Bit Order: MSB first
- CS Polarity: Active low
- Frame Size: 32 bits (4 bytes)
Control Pins (Optional)
The TLE92466ED has optional control pins that can be implemented:
- RESN: Active-low reset pin
- EN: Active-high enable pin
- FAULTN: Active-low fault output (open drain)
cpp
auto SetGpioPin(tle92466ed::ControlPin pin, tle92466ed::ActiveLevel level) noexcept
-> std::expected<void, tle92466ed::CommError> override {
switch (pin) {
case tle92466ed::ControlPin::RESN:
// Set RESN pin (active low)
gpio_set_level(resn_pin_, level == tle92466ed::ActiveLevel::ACTIVE ? 0 : 1);
break;
case tle92466ed::ControlPin::EN:
// Set EN pin (active high)
gpio_set_level(en_pin_, level == tle92466ed::ActiveLevel::ACTIVE ? 1 : 0);
break;
default:
return std::unexpected(tle92466ed::CommError::InvalidParameter);
}
return {};
}
cpp
Error Handling
All methods return std::expected<T, CommError>. Handle errors like this:
cpp
if (auto result = spi_interface.spiTransfer(tx, rx); !result) {
// Handle error
switch (result.error()) {
case tle92466ed::CommError::BusError:
// SPI bus error
break;
case tle92466ed::CommError::Timeout:
// Operation timeout
break;
default:
// Other errors
break;
}
}
cpp
Testing Your Implementation
- Create a simple test that transfers a known frame
- Verify CRC calculation matches expected values
- Test error conditions (timeout, bus error, etc.)
- Verify timing requirements are met
Next Steps
- Review the API Reference for driver methods
- Check Examples for complete usage examples
- See Troubleshooting for common issues
Navigation ⬅️ Hardware Setup | Next: Configuration ➡️ | Back to Index