timdac/inc/timdac.h

133 lines
6.2 KiB
C

// intellectual property is bullshit bgdc
#ifndef TIMDAC_H
#define TIMDAC_H
// ============================================================================
// TIMDAC
// ----------------------------------------------------------------------------
// TIMDAC is a firmware-defined precision 15-bit DAC using external hardware.
// For the full hardware design, see the documentation in this repository.
// In summary, TIMDAC requires:
//
// - A 32-bit (ideally) platform running at somewhere near 72 MHz
//
// (If you can run the timers at that speed, that's fine - 144 MHz with a
// divide-by-two prescale works. Also, necessary frequency is only about
// plus or minus 20% as long as you scale the slope resistor R1 in the
// reference design accordingly.)
//
// - A 16-bit timer that can emit single pulses on demand and interrupt when
// it's done.
//
// - 5 GPIOs, plus log2(number of channels)
//
// ----------------------------------------------------------------------------
// Configuring TIMDAC
// ----------------------------------------------------------------------------
// TIMDAC requires a configuration file called timdac_config.h to be accessible
// on the include path. The core driver only has a few options, but the
// individual hardware drivers will have many more -- see the documentation in
// the driver files for those options. For the TIMDAC core:
//
// #define TIMDAC_TIMERFREQ_HZ 72000000
// Defines the counting frequency of the timer in Hz. Remember that if you
// are running at a frequency other than 72 MHz, one of the resistors in the
// reference design needs changed -- see the notes on the schematic.
//
// #define TIMDAC_N_CHANNELS 4
// Number of output channels. May be up to 254.
//
// #define TIMDAC_DIAGNOSTIC 1
// Define to nonzero to make the diagnostic functions (currently just
// timdac_ll_diagnostic) work. If zero or undefined, the diagnostic
// functionality is not built in. These diagnostics are mostly used to dial
// in parameters for a new reference design, so you shouldn't need them.
//
// ----------------------------------------------------------------------------
// Configuring TIMDAC (advanced / [REFHW])
// ----------------------------------------------------------------------------
// The following parameters pertain to an individual hardware design. Unless
// you're hacking on TIMDAC itself, you should just use a provided set of
// parameters.
//
// #define TIMDAC_TUNE_WEIGHT
// Numerator of the tuning weight. This weight determines how quickly the DAC
// tuning is pulled towards the result of each tuning operation; adjustments
// are made by a factor of (TIMDAC_TUNE_WEIGHT / 65536). This parameter will
// determine how much tuning noise bleeds through into the output; the RMS
// noise can be measured using the TIMDAC_DIAGNOSTIC option, but should also
// be validated using a precise multimeter.
//
// #define TIMDAC_TUNE_NTHRESH
// Tuning noise threshold. Above this amount of error in timer counts, the
// tuning is assumed to have drifted suddenly, and is immediately clobbered.
// Because the tuning algorithm can be noisy, this must be high enough to
// avoid spurious clobbers which can result in sudden shifts in output value.
// The clobber count can be measured using the TIMDAC_DIAGNOSTIC option.
//
// #define TIMDAC_TUNE_INTERVAL
// How many channels may be scanned before tuning. Beware that changing this
// will have ramifications for TIMDAC_TUNE_WEIGHT and TIMDAC_TUNE_NTHRESH.
//
// #define TIMDAC_DISCHARGE_TIME
// Integrator discharge time. It is essential that all charge on the
// integrator be fully discharged before the next channel is emitted. This
// parameter can be validated by setting all channels to zero and measuring
// the output, then setting all channels except one to full-scale and
// ensuring that the channel that remains set to zero has not shifted.
//
// #define TIMDAC_STABILIZATION_TIME
// Stabilization time. This is the time after the pulse finishes before we
// transfer the final ramp value to the holding capacitor. This time allows
// the integrator to settle. If too short, transient edge behavior could
// create offsets or ripple in the output. If too long, the integrator will
// integrate leakage current and create an offset error.
//
// #define TIMDAC_FAST_TRANSFER_TIME
// Fast transfer time in timer counts. This is the time for which the
// integrated ramp is sent to the output when doing fast scanning (no output
// has been changed significantly). It only needs to be fast enough to "top
// up" the output capacitor to account for any leakage that may have occurred
// during a cycle.
//
// #define TIMDAC_SLOW_TRANSFER_TIME
// Slow transfer time in timer counts. This is the time for which the
// integrated ramp is sent to the output when performing an output value
// change.
//
// #define TIMDAC_SLOW_DELTA
// How much can an output change without triggering a slow transfer cycle.
// ============================================================================
#include <stdbool.h>
#include <stddef.h>
#include <inttypes.h>
#include <stdatomic.h>
#include "timdac_ll.h"
// Initialize TIMDAC but do not start scanning yet.
void timdac_init(void);
// Start TIMDAC. It will immediately start with a tuning cycle, then begin
// scanning channels. If you would like the channels to start with an initial
// value other than zero, you may call timdac_set() prior to timdac_start().
void timdac_start(void);
// Set a new value for an output channel. If no other channel has a pending
// immediate update, this channel will also be added to the pend slot so that
// it can be updated as soon as the DAC is ready without waiting for a full
// cycle.
//
// Returns true on success. Only fails on an invalid channel number.
bool timdac_set(uint8_t chan, int32_t value);
// Return whether an update is currently pending. Only one channel can hold the
// pending slot at a time, so if you post an update while another channel is
// pending, the newer update will not be written to the output until it is
// next hit in the normal scanning cycle. To ensure the fastest update, you
// can poll for this flag to clear before calling timdac_set().
bool timdac_pending(void);
#endif // !defined(TIMDAC_H)