Quickstart¶
Read all 16 inputs of an ADS9324 from your MCU: wire seven signals, write two small port classes, call three driver functions.
1. Wire it¶
| MCU | ADS9324 (pin) | Notes |
|---|---|---|
| SPI SCLK | SCLK (37) | SPI mode 0; up to 60 MHz, start at 1 to 8 MHz |
| SPI MOSI | SDI (36) | Register frames, zeros during a conversion read |
| SPI MISO | SDOUT (38) | Register read-back and, in the driver's mode, conversion data |
| SPI CS | CS (35) | Active low; one CS-low window per transfer |
| GPIO out | CONVST (50) | The falling edge samples all channels |
| GPIO in | DRDY/ALARM (49) | Optional; active high when a conversion is ready |
| IOVDD | RESET (32), REFSEL (31) | RESET is active low: hold it high. REFSEL high selects the internal reference |
| GND | GND | Common ground; also the thermal pad |
The ADS9324 needs three supplies (5 V, 1.8 V and the 1.7 V to 3.6 V I/O rail) and its reference capacitors before it answers. The Hardware page has the full pin list, the supplies and the timing.
2. Add the driver¶
Add the repository as a submodule and link the hf::ads9324 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 SPI transfer, the CONVST and DRDY pins, and two delays. Replace the
platform_* calls with your SDK's.
// SPI: one CS-low window per call, SPI mode 0, MSB first.
class MySpi : public ads9324::SpiInterface<MySpi> {
public:
// tx == nullptr: clock out zeros. rx == nullptr: discard what arrives on SDOUT.
// Return false on a bus error: the driver then fails the call that sent the frame.
bool transfer(const uint8_t* tx, uint8_t* rx, std::size_t len) {
return platform_spi_transfer(tx, rx, len);
}
};
// Host: the CONVST output, the optional DRDY input and two delays.
class MyHost : public ads9324::HostInterface<MyHost> {
public:
static constexpr int kConvst = 3; // GPIO wired to CONVST (pin 50)
static constexpr int kDrdy = 11; // GPIO wired to DRDY/ALARM (pin 49)
static constexpr int kReset = 12; // GPIO wired to RESET (pin 32); optional
void ConvstWrite(bool high) { platform_gpio_write(kConvst, high); }
bool DrdyRead() { return platform_gpio_read(kDrdy); } // high = conversion done
bool HasDrdy() const { return true; } // false: fixed wait instead
void DelayUs(uint32_t us) { platform_delay_us(us); }
void DelayMs(uint32_t ms) { platform_delay_us(ms * 1000U); }
void ResetWrite(bool high) {
platform_gpio_write(kReset, high);
} // optional: HardwareReset()
};
HasDrdy() returning false makes the driver wait a fixed time after CONVST instead of polling DRDY.
Porting explains each method.
4. Read the channels¶
#include "ads9324.hpp"
int read_all_16_channels(MySpi& spi, MyHost& host) {
ads9324::ADS9324<MySpi, MyHost> adc(spi, host);
if (!adc.EnsureInitialized()) { // 1. reset, 1-lane SDOUT, DEVICE_ID
return -1; // wiring, supplies or SPI mode
}
ads9324::ChannelConfig cfg; // 2. every input: differential, ±10 V
cfg.type = ads9324::InputType::Differential;
cfg.range = ads9324::InputRange::PlusMinus10V;
if (!adc.ConfigureAllChannels(cfg)) {
return -2;
}
const ads9324::Snapshot snap = adc.ReadSnapshot(); // 3. CONVST, wait DRDY, read 32 bytes
if (!snap.ok()) {
return -3; // snap.error says why
}
std::printf("AIN1 = %.4f V\n", static_cast<double>(snap.voltage[0])); // 4. channel 0 is AIN1
return 0;
}
What each step does:
EnsureInitialized()waits 30 ms for the supplies and reference, resets the chip, writes GEN_CFG3 =0x0032(1 lane, 16-bit words, data on SDOUT), checks DEVICE_ID =0x0004and writes the compile-time PGA defaults (±5 V differential unless configured) to every channel. Nothing else works until it returnstrue.ConfigureAllChannels()writes each channel's PGA nibble and filter bit. The ranges are bipolar; the driver remembers them to convert counts to volts.ReadSnapshot()pulses CONVST, waits for DRDY, then clocks 32 bytes out of SDOUT in one CS-low window.- Channel 0 in the API is AIN1 on the chip; channel 15 is AIN16.
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 |
|---|---|
EnsureInitialized() returns false |
ReadDeviceId(): 0x0000 means no SDOUT data (wiring, SPI mode, supplies); anything else but 0x0004 means a framing problem |
Snapshot error Timeout |
CONVST wiring, DRDY polarity, or set HasDrdy() to false |
| All counts near zero | Input type and range, a floating input in open-wire-safe mode, or the AINxM pin not connected |
| Voltages off by a fixed factor | The range you configured is not the range you assumed (PGA and calibration) |
Next¶
- API guide: per-channel set-up, calibration, window comparator, errors.
- Examples: ESP32-C6 applications, including the integration test suite.
- Registers and SPI frames: what goes over the wire.