timdac/src/timdac_ll.h

132 lines
4.5 KiB
C

// intellectual property is bullshit bgdc
#ifndef TIMDAC_LL_H
#define TIMDAC_LL_H
// ============================================================================
// TIMDAC LOW LEVEL DRIVER
// ----------------------------------------------------------------------------
// This module provides the low-level (but still hardware-abstracted) part of
// TIMDAC. It implements the state machine that provides each individual cycle
// of operation, but must be sequenced through cycles correctly. You are not
// generally meant to use it directly; see the high-level interface in timdac.h
// which handles this sequencing.
// ============================================================================
#include <stdbool.h>
#include <stddef.h>
#include <inttypes.h>
#include <ch32v10x_tim.h>
#include <ch32v10x_gpio.h>
#define TIMDAC_MAX_SELCHAN 5
typedef struct timdac_tunediag_s {
// Total number of calibration cycles run (will overflow)
uint16_t cycles;
// Tuning clobber counter.
uint16_t clobbers;
// Current tune value.
uint16_t tune;
// Tuning noise accumulator. This will hold the sum of the squares of
// the tuning errors, and will be reset to zero each time cycles wraps
// around. To get the RMS tuning noise, divide this by cycles, take
// the square root, then divide by 65536.
uint64_t noise;
} timdac_tunediag_t;
typedef struct timdac_ll_s {
// #### BEGIN - USER MUST INITIALIZE ####
// ---- Diagnostics ----
// Optional calibration diagnostics struct
timdac_tunediag_t * tunediag;
// #### END - USER MUST INITIALIZE ####
// Tuning value. This is 65536 times the timer setting required to
// produce Vref. May be read but should not be written; if zero, the
// first tuning has not completed yet.
uint32_t tune;
// Tuning successive approximation upper bound
uint16_t tune_sar_top;
// Tuning successive approximation lower bound
uint16_t tune_sar_bot;
// Current channel number
uint8_t chan;
// Current state
uint8_t state;
// Whether performing a slow update
bool slow;
} timdac_ll_t;
// Initialize the DAC. The mux GPIOs will be initialized as well, but you are
// responsible for configuring the timer channel IOs as well as enabling the
// clock to the GPIO and timer.
//
// td: timdac instance
void timdac_ll_init(timdac_ll_t * td);
// Start to tune the DAC. After calling, run timdac_poll() until it
// reports idle.
//
// Tuning requires external hardware support. A comparator must sense
// when the ramp crosses Vref and signal back to us on the input capture line.
// Note that the CH32V10x has no internal comparator; an external one will be
// needed. Do not use hysteresis as this will make the level less exact.
//
// Returns whether the timer is now busy.
bool timdac_ll_tune(timdac_ll_t * td);
// Start to emit a voltage on a channel. The integrating ramp will be started.
// After calling, run timdac_poll() until it reports idle.
//
// If timdac_poll() was not already reporting idle, the previous cycle will be
// aborted.
//
// td: timdac instance
// chan: channel number, sent to the channel select GPIOs. Remember that 0
// is the discharge channel - you should never use it directly. Behavior
// is undefined if you do.
// value: DAC code
// slow: if true, dwell longer during transfer for large updates
void timdac_ll_emit(timdac_ll_t * td, uint8_t chan, int16_t value, bool slow);
// Poll the timer. This must be called repeatedly while a tuning or output
// cycle is in progress - it does not need to be called with perfect regularity,
// but waiting too long may result in some signal droop and loss of accuracy.
//
// td: timdac instance
// return: true if busy, false if idle
bool timdac_ll_poll(timdac_ll_t * td);
// Run a single idle cycle. This can be used to kickstart an interrupt driven
// timdac. If the timdac is not already at the idle state, does nothing.
void timdac_ll_idle(timdac_ll_t * td);
// ----------------------------------------------------------------------------
// HARDWARE DRIVER INTERFACE
// These functions are implemented by each hardware driver.
void timdac_hw_init(void);
void timdac_hw_timer_set_period(uint16_t counts);
void timdac_hw_timer_set_compare(uint16_t counts);
void timdac_hw_timer_set_oc_enabled(bool en);
void timdac_hw_timer_start(void);
bool timdac_hw_timer_running(void);
void timdac_hw_gpio_muxinhibit(bool en);
void timdac_hw_gpio_discharge(bool en);
void timdac_hw_gpio_polarity(bool pos);
void timdac_hw_gpio_select_channel(uint8_t chan);
bool timdac_hw_gpio_tune_is_high(void);
#endif // !defined(TIMDAC_LL_H)