damaris-backends/drivers/DAC-AD5791/AD5791.cpp

315 lines
12 KiB
C++
Raw Normal View History

2015-11-25 16:43:12 +00:00
/**
* \file
* \brief Implementation of the Driver for the AD5791
* Digital to Analog Converter Board
*
*
* The board inverts all digital inputs.
*/
#include "AD5791.h"
2016-12-19 14:03:14 +00:00
#include "../../core/states.h"
2015-11-25 16:43:12 +00:00
#include <cstdio>
#include <cmath>
#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
using std::reverse;
using std::cout;
using std::vector;
#ifndef TIMING
#define TIMING 9e-8
#endif
// The bit depth of the DAC
2016-12-19 14:03:14 +00:00
#define DAC_DATA_BITS 20
#define DAC_CONTROL_BITS 4
2015-11-25 16:43:12 +00:00
// The channel configuration
#define DATA_BIT 18//18
#define CLK_BIT 16//16
2016-12-19 14:03:14 +00:00
// this bit needs to be set to write the DAC register
#define WRITE_DAC 1<<20
// software control register
#define RESET 1
#define CLR 2
#define LDAC 4
// control register
// Linearity error compensation for varying reference input spans.
#define LINCOMP_10V 0*1<<9 + 0*1<<8 + 0*1<<7 + 0*1<<6
#define LINCOMP_12V 1*1<<9 + 0*1<<8 + 0*1<<7 + 1*1<<6
#define LINCOMP_16V 1*1<<9 + 0*1<<8 + 1*1<<7 + 0*1<<6
#define LINCOMP_19V 1*1<<9 + 0*1<<8 + 1*1<<7 + 1*1<<6
#define LINCOMP_20V 1*1<<9 + 1*1<<8 + 0*1<<7 + 0*1<<6
// SDO pin enable/disable control.
#define SDODIS 32
// DAC register coding select.
#define DAC_CODING_SELECT 16
// DAC tristate control.
#define DACTRI 8
// Output ground clamp control. (set by default)
#define OPGND 4
// Output amplifier configuration control. (set by default)
#define RBUF 2
AD5791::AD5791(int myid) : id(myid) {
dac_value = 0;
set_latch_bit(17);
2015-11-25 16:43:12 +00:00
}
AD5791::~AD5791() {}
// This sets the dac_value
void AD5791::set_dac(signed dw) {
2016-12-19 14:03:14 +00:00
dac_value = dw;
2015-11-25 16:43:12 +00:00
}
2016-12-19 14:03:14 +00:00
void AD5791::set_latch_bit(int le_bit) {
latch_bit = le_bit;
2015-11-25 16:43:12 +00:00
}
// This sets the DAC
2016-12-19 14:03:14 +00:00
void AD5791::set_dac(state &experiment) {
state_sequent *exp_sequence = dynamic_cast<state_sequent *>(&experiment);
if (exp_sequence == NULL)
// is a very state on top level, todo: change interface
throw pfg_exception("cannot work on a single state, sorry (todo: change interface)");
else {
for (state_sequent::iterator child_state = exp_sequence->begin();
child_state != exp_sequence->end(); ++child_state)
set_dac_recursive(*exp_sequence, child_state);
2015-11-25 16:43:12 +00:00
// std::cout << "first state"<< std::endl;
2016-12-19 14:03:14 +00:00
// Set DAC to 0 at start of experiment
set_dac_to_zero(exp_sequence, exp_sequence->begin());
// but first initialize DAC
init_dac(exp_sequence, exp_sequence->begin());
// And at the end of the experiment set DAC to zero
set_dac_to_zero(exp_sequence, exp_sequence->end());
}
}
void AD5791::set_dac_to_zero(state_sequent *exp_sequence, state::iterator where) {
// 0001 0000 0000 0000 0000 0000
state s(TIMING);
ttlout *ttl_state = new ttlout();
ttl_state->id = 0;
s.push_front(ttl_state);
state_sequent *rep_sequence = new state_sequent();
// 0
ttl_state->ttls = 0 + (1 << CLK_BIT);
rep_sequence->push_back(s.copy_new());
ttl_state->ttls = 0;
rep_sequence->push_back(s.copy_new());
// 0
ttl_state->ttls = 0 + (1 << CLK_BIT);
rep_sequence->push_back(s.copy_new());
ttl_state->ttls = 0;
rep_sequence->push_back(s.copy_new());
// 0
ttl_state->ttls = 0 + (1 << CLK_BIT);
rep_sequence->push_back(s.copy_new());
ttl_state->ttls = 0;
rep_sequence->push_back(s.copy_new());
// 1
ttl_state->ttls = (1<<DATA_BIT) + (1 << CLK_BIT);
rep_sequence->push_back(s.copy_new());
ttl_state->ttls = (1<<DATA_BIT);
rep_sequence->push_back(s.copy_new());
// the rest
rep_sequence->repeat = DAC_DATA_BITS;
ttl_state->ttls = 0 + (1 << CLK_BIT);
rep_sequence->push_back(s.copy_new());
ttl_state->ttls = 0;
rep_sequence->push_back(s.copy_new());
exp_sequence->insert(where, rep_sequence);
//read in the word
ttl_state->ttls = 0;
exp_sequence->insert(where, s.copy_new());
ttl_state->ttls = (1 << latch_bit);
exp_sequence->insert(where, s.copy_new());
2015-11-25 16:43:12 +00:00
}
2016-12-19 14:03:14 +00:00
void AD5791::init_dac(state_sequent *exp_sequence, state::iterator where) {
state s(TIMING);
ttlout *ttl_state = new ttlout();
ttl_state->id = 0;
s.push_front(ttl_state);
state_sequent *rep_sequence = new state_sequent();
// 0010 0000 0000 0000 0000 0000
// 0
ttl_state->ttls = 0 + (1 << CLK_BIT);
rep_sequence->push_back(s.copy_new());
ttl_state->ttls = 0;
rep_sequence->push_back(s.copy_new());
// 0
ttl_state->ttls = 0 + (1 << CLK_BIT);
rep_sequence->push_back(s.copy_new());
ttl_state->ttls = 0;
rep_sequence->push_back(s.copy_new());
// 1
ttl_state->ttls = (1<<DATA_BIT) + (1 << CLK_BIT);
rep_sequence->push_back(s.copy_new());
ttl_state->ttls = (1<<DATA_BIT);
rep_sequence->push_back(s.copy_new());
// 0
ttl_state->ttls = 0 + (1 << CLK_BIT);
rep_sequence->push_back(s.copy_new());
ttl_state->ttls = 0;
rep_sequence->push_back(s.copy_new());
// the rest
rep_sequence->repeat = DAC_DATA_BITS;
ttl_state->ttls = 0 + (1 << CLK_BIT);
rep_sequence->push_back(s.copy_new());
ttl_state->ttls = 0;
rep_sequence->push_back(s.copy_new());
exp_sequence->insert(where, rep_sequence);
//read in the word
ttl_state->ttls = 0;
exp_sequence->insert(where, s.copy_new());
ttl_state->ttls = (1 << latch_bit);
exp_sequence->insert(where, s.copy_new());
2015-11-25 16:43:12 +00:00
}
2016-12-19 14:03:14 +00:00
2015-11-25 16:43:12 +00:00
// This loops recursive through the state tree
2016-12-19 14:03:14 +00:00
void AD5791::set_dac_recursive(state_sequent &the_sequence, state::iterator &the_state) {
state_sequent *a_sequence = dynamic_cast<state_sequent *>(*the_state);
// Am I a sequence? Yes? Go one sequence further
if (a_sequence != NULL) {
for (state_sequent::iterator child_state = a_sequence->begin(); child_state != a_sequence->end(); ++child_state)
set_dac_recursive(*a_sequence, child_state);
}
// I am not a sequence, but a state
else {
state *this_state = dynamic_cast<state *>(*the_state);
if (this_state == NULL)
throw pfg_exception("state_atom in state_sequent not expected");
analogout *dac_analog_out = NULL;
// find an analogout section with suitable id
state::iterator pos = this_state->begin();
while (pos != this_state->end()) { // state members loop
analogout *aout = dynamic_cast<analogout *>(*pos); // initialize new analogout
// This is for me, analogout is != NULL (there is an analogout) and has my ID
if (aout != NULL && aout->id == id) {
if (dac_analog_out == NULL) {
// save the information of this aout
dac_analog_out = aout;
}
// there is no place for me here
else {
throw pfg_exception("found another DAC section, ignoring");
delete aout;
}
// remove the analog out section
this_state->erase(pos++);
} else {
++pos;
}
} // state members loop
if (dac_analog_out != NULL) { // state modifications
//std::cout<<"found a analog out section, value="<<dac_analog_out->dac_value<<std::endl;
// check the length of the state
if (this_state->length < TIMING * (DAC_CONTROL_BITS + DAC_DATA_BITS) * 2 + 1)
throw pfg_exception("time is too short to save DAC information");
else {
// copy of original state
state *register_state = new state(*this_state);
ttlout *register_ttls = new ttlout();
register_ttls->id = 0;
register_state->length = TIMING;
register_state->push_back(register_ttls);
if (dac_analog_out->dac_value > (pow(2.0, int(DAC_DATA_BITS - 1)) - 1))
throw pfg_exception("dac_value too high");
if (abs(dac_analog_out->dac_value) > pow(2.0, int(DAC_DATA_BITS - 1)))
throw pfg_exception("dac_value too low");
// set dac write register 1<<20
dac_analog_out->dac_value += WRITE_DAC;
vector<int> dac_word;
// generate the bit pattern, this is MSB last
for (int j = 0; j < (DAC_DATA_BITS + DAC_CONTROL_BITS); j++) {
int bit = dac_analog_out->dac_value & 1;
dac_word.push_back(bit);
dac_analog_out->dac_value >>= 1;
}
// reverse the bit pattern (MSB first)
reverse(dac_word.begin(), dac_word.end());
// need one clock cycle to read in bit
// latch enable (LE) should always be high while doing so
// except for the last bit
// do run length encoding, grouping same bit values in loops
int last_seen_bit = dac_word[0];
int last_seen_bit_count = 1;
for (int i = 1; i < (DAC_DATA_BITS + DAC_CONTROL_BITS) + 1; i++) {
if (i == (DAC_DATA_BITS + DAC_CONTROL_BITS) || last_seen_bit != dac_word[i]) {
// so we have to write the bits
// either because the previous were different or we are finished
if (last_seen_bit_count > 1) {
// insert a loop
state_sequent *rep_sequence = new state_sequent();
rep_sequence->repeat = last_seen_bit_count;
register_ttls->ttls = (1 << DATA_BIT) * last_seen_bit + (1 << CLK_BIT) + (1 << latch_bit);
rep_sequence->push_back(register_state->copy_new());
register_ttls->ttls = (1 << DATA_BIT) * last_seen_bit + (1 << latch_bit);
rep_sequence->push_back(register_state->copy_new());
the_sequence.insert(the_state, rep_sequence);
} else {
// no loop necessary, insert two states
register_ttls->ttls = (1 << DATA_BIT) * last_seen_bit + (1 << CLK_BIT) + (1 << latch_bit);
the_sequence.insert(the_state, register_state->copy_new());
register_ttls->ttls = (1 << DATA_BIT) * last_seen_bit + (1 << latch_bit);
the_sequence.insert(the_state, register_state->copy_new());
}
// reset counter and bits if we are not finished
if (i < (DAC_DATA_BITS + DAC_CONTROL_BITS)) {
last_seen_bit = dac_word[i];
last_seen_bit_count = 1;
}
} // finished writing
else
last_seen_bit_count += 1; // same bit value, so continue
} // end of bit loop
register_ttls->ttls = 0;
the_sequence.insert(the_state, register_state->copy_new());
// shorten the remaining state
// and add LE high to this state
ttlout *ttls = new ttlout();
// 2 clocks per bit + 1 for sync
this_state->length -= TIMING * 2 * (DAC_DATA_BITS + DAC_CONTROL_BITS) + 1;
ttls->ttls = 1 << latch_bit;
this_state->push_front(ttls);
2015-11-25 16:43:12 +00:00
2016-12-19 14:03:14 +00:00
// cleanup
delete register_state;
delete dac_analog_out;
} // state was long enough to work on
} else {
ttlout *le_ttls = new ttlout();
// le_ttls->ttls = 1 << latch_bit;
this_state->push_back(le_ttls);
}
// end of state modifications
} // I was a state
2015-11-25 16:43:12 +00:00
}