133 lines
6.2 KiB
C
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)
|