Quickstart¶
Read the ADS7952 from your MCU: wire the SPI bus and the analog front end, write a one-method port class, call three driver functions.
1. Wire it¶
| MCU | ADS7952 (TSSOP-38 pin) | Notes |
|---|---|---|
| SPI SCLK | SCLK (32) | SPI mode 0, up to 20 MHz; start at 1 MHz to 4 MHz |
| SPI MOSI | SDI (33) | 16-bit command word, MSB first |
| SPI MISO | SDO (34) | 16-bit reply: channel address in DO15:12, count in DO11:0 |
| SPI CS | CS (31) | Active low; one CS frame per 16-bit word |
| I/O supply | +VBD (36), BDGND (35) | 1.7 V to +VA; sets the logic levels, so match your MCU |
| GND | AGND, BDGND | Common ground |
On the analog side, connect MXO (7) to AINP (8) and AINM (9) to AGND: the multiplexer output is not routed to the converter inside the chip. Put a 2.0 V to 3.0 V reference on REFP (4) with REFM (3) to AGND, and +VA (5, 29) at 2.7 V to 5.25 V. The Hardware page has every pin, the bus timing and the power ranges.
2. Add the driver¶
Add the repository as a submodule and link the hf_ads7952 CMake target (or add inc/ and src/ to your include
path and build with C++20). Installation covers CMake and ESP-IDF.
3. Write the port¶
The port is the only platform code: one full-duplex transfer with chip select held low for the whole word. Replace
platform_spi_transfer() with your SDK's call.
class MySpi : public ads7952::SpiInterface<MySpi> {
public:
// One 16-bit frame: SPI mode 0, MSB first, CS low for both bytes and high again afterwards.
// Return false on a bus error: the driver call that sent the frame then fails.
bool transfer(const uint8_t* tx, uint8_t* rx, std::size_t len) {
return platform_spi_transfer(tx, rx, len);
}
};
The driver always calls transfer() with two bytes. Porting explains the contract and shows how to
check a port.
4. Read the channels¶
#include "ads7952.hpp"
#include <cstdio>
int read_adc(MySpi& spi) {
ads7952::ADS7952<MySpi> adc(spi, 2.5f, 5.0f); // REFP = 2.5 V, +VA = 5 V
if (!adc.EnsureInitialized()) { // 1. discard power-up frame, program sequences
return -1;
}
const ads7952::ReadResult ch3 = adc.ReadChannel(3); // 2. one channel (Manual mode)
if (!ch3.ok()) {
return -1; // Timeout: wiring, SPI mode or CS framing
}
std::printf("CH3 = %.3f V (%u counts)\n", ch3.voltage, static_cast<unsigned>(ch3.count));
const ads7952::ChannelReadings all = adc.ReadAllChannels(); // 3. every channel (Auto-1 mode)
for (uint8_t ch = 0; ch < 12; ++ch) {
if (all.hasChannel(ch)) {
std::printf("CH%u = %.3f V\n", static_cast<unsigned>(ch), all.voltage[ch]);
}
}
return all.ok() ? 0 : -1;
}
What each step does:
- The constructor stores the reference (REFP) and supply (+VA) voltages used to convert counts to volts. It sends nothing.
EnsureInitialized()discards the invalid first conversion after power-up, programs the Auto-1 sequence (all 12 channels) and the Auto-2 last channel (CH11), and enters Auto-1 mode. Calling it again does nothing.ReadChannel()selects one channel in Manual mode and clocks frames until the reply carries that channel's address: three frames when the bus is healthy.ReadAllChannels()restarts the Auto-1 sequence and collects one result per programmed channel.
This example is built by the host CI, so it compiles against the current headers.
If it does not work¶
| Symptom | First thing to check |
|---|---|
ReadChannel() returns Error::Timeout |
SPI mode 0, CS low for all 16 clocks and high between words, MISO wiring |
| Every count is 0 | +VA and the reference are present; MXO is connected to AINP |
| Every count is 4095 | The input is above the range: VREF, or 2 × VREF in Range::TwoVref |
| Every channel reads the same count | MXO to AINP wiring, source impedance; see Troubleshooting |
Next¶
- API guide: sequences, ranges, alarms, GPIOs and errors.
- Modes and the frame pipeline: why a result arrives two frames after its command.
- Examples: ESP32-S3 applications for every feature.