damaris-backends/drivers/Tecmag-DAC20/DAC20.cpp

231 lines
8.5 KiB
C++
Raw Permalink Normal View History

2014-06-26 11:10:51 +00:00
/**
* \file
* \brief Implementation of the Driver for the DAC20
* Digital to Analog Converter Board
*
* This board was first used in the PFG, and gets now
* adopted by the Field-Cycling spectrometers.
*
* The board inverts all digital inputs.
* This driver partially honors this.
* Especially the data input is not yet inverted.
* -# Inverting the data line is equivalent to inverting
* the value and add/substracting one.
* -# There are different versions of the board around,
* where one board "undoes" the inversion by having an
* inverting op-amp after the DAC.
* -# The digital units have to be calibrated to physical
* units anyway. A sign doesn't hurt much.
*
* This is still a current discussion topic and might
* change.
*/
#include "DAC20.h"
#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
#define DAC_BIT_DEPTH 20
// The channel configuration
#define DATA_BIT 18//18
#define CLK_BIT 16//16
DAC20::DAC20(int myid): id(myid) {
dac_value = 0;
set_latch_bit(17);
}
DAC20::~DAC20() {}
// This sets the dac_value
void DAC20::set_dac(signed dw) {
dac_value = dw;
}
void DAC20::set_latch_bit(int le_bit)
{
latch_bit = le_bit;
}
// This sets the DAC
void DAC20::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);
// std::cout << "first state"<< std::endl;
// Set DAC to 0 at start of experiment
set_dac_to_zero(exp_sequence, exp_sequence->begin());
// And at the end of the experiment
set_dac_to_zero(exp_sequence, exp_sequence->end());
}
}
void DAC20::set_dac_to_zero(state_sequent* exp_sequence, state::iterator where)
{
state s(TIMING);
ttlout* le=new ttlout();
le->id=0;
s.push_front(le);
state_sequent* rep_sequence=new state_sequent();
rep_sequence->repeat=DAC_BIT_DEPTH;
le->ttls = 0 + ( 1 << CLK_BIT );
rep_sequence->push_back(s.copy_new());
le->ttls = 0 ;
rep_sequence->push_back(s.copy_new());
exp_sequence->insert(where, rep_sequence);
//read in the word (41st pulse)
le->ttls=0;
exp_sequence->insert(where, s.copy_new());
// 42nd pulse
// // the state should be 2ms long
// s.length = 2e-3-41*TIMING;
le->ttls= ( 1 << latch_bit );
exp_sequence->insert(where, s.copy_new());
}
// This loops recursive through the state tree
void DAC20::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* PFG_aout = 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 (PFG_aout == NULL) {
// save the informations
PFG_aout = 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 (PFG_aout != NULL) { // state modifications
//std::cout<<"found a analog out section, value="<<PFG_aout->dac_value<<std::endl;
// check the length of the state
if (this_state->length < TIMING*41.0)
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 (PFG_aout->dac_value > (pow(2.0, int(DAC_BIT_DEPTH-1))-1) )
throw pfg_exception("dac_value too high");
if ( abs(PFG_aout->dac_value) > pow(2.0, int(DAC_BIT_DEPTH-1)) )
throw pfg_exception("dac_value too low");
// now, insert the ttl information
vector<int> dac_word;
for (int j = 0; j < DAC_BIT_DEPTH ; j++) {
int bit = PFG_aout->dac_value & 1;
// // invert the bit
// bit = (bit == 0);
dac_word.push_back(bit);
//cout << dac_word[j];
PFG_aout->dac_value >>= 1;
}
// need one clock cycle to read in bit
// latch enable (LE) should always be high while doing so
// except for the last bit
// reverse the bit pattern
reverse(dac_word.begin(), dac_word.end());
// 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_BIT_DEPTH+1; i++) {
if (i==DAC_BIT_DEPTH || 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_BIT_DEPTH) {
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();
// 42nd pulse
this_state->length -= TIMING*41;
ttls->ttls = 1 << latch_bit;
this_state->push_front(ttls);
// cleanup
delete register_state;
delete PFG_aout;
} // 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
}