16bit DAC parallel bits, AD669

if I can use a shift register without adding "loop-time", that would be fine too.

What do you mean by loop time?

You an always use a MCP23S17, this is an SPI 16 bit port expander, that can run quite fast. How fast do you need?

If you use shift registers it will be a bit slower than writing 2 8-bit ports. But what do you need for speed? The difference is a small fraction of a millisecond.

I withdraw my suggestion about the 595 register, that is an output one. But something like the 74HC165 will do input.

Some of these are even bi-directional:

I don't know those people but I have bought from them a few times and never a problem with an order. Obviously though, you don't just buy 1 or 2 50-cent chips on a $4+ shipping charge. But they have component bags and all kinds of goodies. The prices are close enough to eBay for me and these guys do have datasheets so I know what I'm ordering, not just hoping it is what it seems.

(ships from Hong Kong, there's a how-long table)

SHIPPING METHODS
For Australian, Canada, UK, EU and USA customers, we can offer domestic postage rates as follows,

USA, Canada, UK, European Union(EU) and Australia

Standard Post*
For orders up to US$29, Delivery Charge - US$4.00.
For orders US$30 to US$49, Delivery Charge - US$6.00
For order US$50 to US$99, Delivery Charge - US$9.00
For order US$100 and above, Delivery Charge - US$14.00

Express Post - Express Pak Only
For orders up to US$99, Delivery Charge - US$22.00.
For order US$100 and above, Delivery Charge - US$44.00
For orders shipped in Cartons, Express Charges are charged at actual cost.

Courier - Courier Pak Only
For orders up to US$99, Delivery Charge - US$33.00.
For orders US$100 and above, Delivery Charge - US$66.00
For orders shipped in Cartons, Courier Charges are charged at actual cost.

All Other Countries

Standard Post - Air Mail*
For orders up to US$29, Delivery Charge - US$5.00.
For orders US$30 to US$49, Delivery Charge - US$7.00
For order US$50 to US$99, Delivery Charge - US$12.00
For order US$100 and above, Delivery Charge - US$18.00

Express Post - Express Pak Only - Where Available
For orders up to US$99, Delivery Charge - US$28.00.
For order US$100 and above, Delivery Charge - US$55.00
For orders shipped in Cartons, Express Charges are charged at actual cost.

Courier - Courier Pak Only
For orders up to US$99, Delivery Charge - US$45.00.
For orders US$100 and above, Delivery Charge - US$75.00
For orders shipped in Cartons, Courier Charges are charged at actual cost.

Hmmmm, after the USPS charges thread I have to wonder if the site needs updating or they subsidize the difference. And heyyy, ship to Down-Under is the same as to the US!

Ok, I think I got it up and running. I now need to write some code to transform a value of desire to 16 parallel bits. I have enough digital output pin available so I would like to use just the 16 output pins for the data.

Any suggestions?

I have looked at bitRead. That seems to work but puts out a value of 1 or 0 while ideally, I want a LOW or HIGH.

for instance, for bit 0, I would like to output;

I did not expect this to work but it does;

  • digitalWrite(2,bitRead(8,3));
    delay(2000);
    digitalWrite(2,bitRead(8,2));
    delay(2000);

Here's you pin map:

You have Ports A, B, C, D with pins as SAM3X pin names PA##, PB##, etc.
If you can get 16 pins in a row on the same port then you should be able to write 16 bits to that port in one go. Once the bits are written however you do it, the pins should reflect what you wrote. It's a lot quicker than setting 16 pins 1 at a time.

I can hook it up to 16 digital outputs on my Arduino Due, no problem, but maybe there are smarter options

I read the entire thread before I realised you're using a Due, just hook up 16 (or 19) pins and learn how to directly write to a port. Job done, there's no "better" way unless you're desperate to save pins for another purpose.


Rob

That seems to work but puts out a value of 1 or 0 while ideally, I want a LOW or HIGH.

So what is the difference between a 1 and a high?
I will tell you, nothing at all.
See it is ideal!

Grumpy_Mike:

That seems to work but puts out a value of 1 or 0 while ideally, I want a LOW or HIGH.

So what is the difference between a 1 and a high?
I will tell you, nothing at all.
See it is ideal!

Once here I was warned that TRUE/FALSE and HIGH/LOW might some day not be 1/0 so my code should not assume that and won't be compatible. I had to LOL since hey, I should live so long! But then that person advocates using C++ Strings on UNO's and not being hardware-centered.

Ok, I got it working in "slow"-mode.
I indeed put each individual pin either High or Low. It is more of a proof-of concept than it is the end result. The loop now takes as much a 80-100uS with a analogread and normal digitalwrites (16 of them)
Now I know what kind of signals are required to use the DAC, I will try to use one of the ports for a shorter looptime.

I will try to use portC to driving the DAC.

"So what is the difference between a 1 and a high?"
In the digitalWrite help it says explicitly it want either HIGH or LOW so I was under the assumption that those two inputs were the only ones accepted.

More to come.

For the ADC I will be implementing I will use this code, which speeds up the digitalwrites and reads drastically. I will first try to implement the same type of bitsetting on the DAC and if that works nicely, keep it that way.

inline void digitalWriteDirect(int pin, boolean val){
if(val) g_APinDescription[pin].pPort -> PIO_SODR = g_APinDescription[pin].ulPin;
else g_APinDescription[pin].pPort -> PIO_CODR = g_APinDescription[pin].ulPin;
}

inline int digitalReadDirect(int pin){
return !!(g_APinDescription[pin].pPort -> PIO_PDSR & g_APinDescription[pin].ulPin);

Once here I was warned that TRUE/FALSE and HIGH/LOW might some day not be 1/0 so my code should not assume that and won't be compatible. I had to LOL since hey, I should live so long! But then that person advocates using C++ Strings on UNO's and not being hardware-centered.

Yes but two things, one that is rubbish, two he was talking about a chip outputting something, so that means a physical output. Lets see the guardians of C redefine a TTL output.

In the digitalWrite help it says explicitly it want either HIGH or LOW so I was under the assumption that those two inputs were the only ones accepted.

As an engineer once told be assumption is the mother of all **** ups.

For the ADC I will be implementing I will use this code,

Won't that only work with 8 bits?

I have not tried it yet with more than 4 pins. For the ADC I will read 1 byte per ADC. When I put "byte" high, the lowbyte and highbyte flip so per ADC I can read the 16 bits with "just" 8 inputs. Therefore I can use 2 ADC's and a DAC without running out of pins.

Grumpy_Mike:

Once here I was warned that TRUE/FALSE and HIGH/LOW might some day not be 1/0 so my code should not assume that and won't be compatible. I had to LOL since hey, I should live so long! But then that person advocates using C++ Strings on UNO's and not being hardware-centered.

Yes but two things, one that is rubbish, two he was talking about a chip outputting something, so that means a physical output. Lets see the guardians of C redefine a TTL output.

I'm not sure that person is a he but was talking about source code. I called it garbage too. But perhaps that person doesn't recognize the relation of bits to wire states as anything but incidental or thinks that code now should be compatible to some future age where binary logic is outdated and the crass obfuscation of using tricky operations like XOR will die with the ancient ones who lived close to the metal.
I've seen it in new compsci degree holders back since 87 but we're still here and LOW is still 0 and HIGH is still 1 without any sign of a big change, and XOR is still useful and used!

Ok, now the loop takes 12.5 us. So every 12.5us, a new value is put into the dac and outputted. I think I can reduce this period by smarter bitsetting, but I don't know how to do best. Ideally I want to stick to the pins I use now, 30-45, so not an unique port. I expect the for loop to take most of the time.

//Definieer digitalwrite en digitalread-direct

inline void digitalWriteDirect(int pin, boolean val){
  if(val) g_APinDescription[pin].pPort -> PIO_SODR = g_APinDescription[pin].ulPin;
  else    g_APinDescription[pin].pPort -> PIO_CODR = g_APinDescription[pin].ulPin;
}

inline int digitalReadDirect(int pin){
  return !!(g_APinDescription[pin].pPort -> PIO_PDSR & g_APinDescription[pin].ulPin);


}


int update = 8;

//trim DC output to 0, depends on resistor specs and board layout
int offset = 23;

//Halfway ideal value 2^16 / 2 + the offset adjustment
int zero = 32768+offset;

//2^16 / 20 volts is value per volt
float scale = 3276.8;

//DAC reference, what should the output be? In volts.
float input = 0.1; 

//Define the value which is send to the DAC, with scaling and offset.
int value = 0; //Value to DAQ;

void setup() {                
  
  
  //Define DAC PINS
  pinMode(update, OUTPUT);
  digitalWrite(update, LOW);
  pinMode(A0, INPUT);
  pinMode(30, OUTPUT);
  pinMode(31, OUTPUT);
  pinMode(32, OUTPUT);
  pinMode(33, OUTPUT);
  pinMode(34, OUTPUT);
  pinMode(35, OUTPUT);
  pinMode(36, OUTPUT);
  pinMode(37, OUTPUT);
  pinMode(38, OUTPUT);
  pinMode(39, OUTPUT);
  pinMode(40, OUTPUT);
  pinMode(41, OUTPUT);
  pinMode(42, OUTPUT);
  pinMode(43, OUTPUT);
  pinMode(44, OUTPUT);
  pinMode(45, OUTPUT);
                          
  
}

// the loop routine runs over and over again forever:
void loop() {

//Put value out to DAC

//Determine integer to DAC
value = round(zero+input*scale);

//Put DAC pins high  
for(int x = 30; x < 46; x++){digitalWriteDirect(x, bitRead(value,x-30)); }

//Update DAC output value
digitalWriteDirect(update, HIGH);
digitalWriteDirect(update, HIGH);
//Fix outpur value
digitalWriteDirect(update, LOW); 
    
}

Get rid of the floats and it will speed up.

scaling integers ---- scaled_value = value x scale_numerator / scale_denominator

don't forget to use an integer type that will hold intermediate results.

I took apart the for loop and gained another us. After that, I tested the time it actually takes to put the pins high by copying the 16 lines of code and pasted it below. The loop now takes 5 us more time. So that is the most amount of time I can gain by smarted output writing.

Concerning the float;
The signal that will be output by the DAC will be the outcome of some equations which may vary anywhere between -10 V and +10 V. If using integers really speeds up the progress I will keep that in mind when I built de code which does the calculations.

I think the DAC is going to be ok. Now it's time for the ADC, but I am waiting for some logc level converters before I can use the DUE for that purpose.

Get rid of the floats and it will speed up.
scaling integers ---- scaled_value = value x scale_numerator / scale_denominator
don't forget to use an integer type that will hold intermediate results.

biggest step can be gained by removing float divisions as these are the worst.

Volts = analogRead(A0) * 5.0/1024;
performs worse than
Volts = analogRead(A0) * 0.004882812;

but yes removing floats completely gains even more.

Integer scaling is done completely with integers. The order of operations, * before / preserves the most accuracy.
If I want to ensure 3 places extra accuracy I might multiply by an extra 1000 that I don't divide by and treat the result as 1000x bigger. Like in printing I would insert a decimal point before the last 3 digits in text.

Pick your working units to suit your methods and leave what the humans see have it's own routines.