Go Down

Topic: High speed read of bipolar signal, -> ADC (LTC1605) (Read 2620 times) previous topic - next topic

SuperR

Feb 07, 2013, 04:23 pm Last Edit: Feb 24, 2013, 10:55 am by SuperR Reason: 1
Hi,

I am starting experiments on a setup next week and was interested in using a standalone Arduino application next to the (overkill) Matlab dSpace interface. I really like Matlab and Simulink, but I am intrigued by the idea of implementing a control loop within the Atmega 328P.

Here's the setup;
Reference input, an audio signal, so both positive and negative voltages
Sensor output, an accelerometer, putting out both positive and negative voltages

Once I find a control loop, say, just an error times a transferfunction, it would be nice to implement it in an Arduino environment

Here's the issue;
I want a "sample 2 inputs -> substrackt -> run filter-> output"-time of say 1/10000 s = 100 us
Assume the filter to be quite "filled with dynamics". So no simple 1 zero 2 poles transfer function.

Do any of you have experience with similar implementations? I am not sure whether the Atmega can do this at ease or if it is impossible.

I read about implementing Simulink code on an Arduino. That would be awesome, but then again, I am not sure the (calculation)speed is high enough for my goals.

If it's impossible to do, so be it. However, if with little modifications something like this can be accomplished, that would be great!

http://www.mathworks.com/matlabcentral/fileexchange/35639
http://arduino.cc/forum/index.php/topic,6549.0.html
https://sites.google.com/site/measuringstuff/the-arduino#TOC-Sample-Rates


robtillaart

\Can you give a glimpse of the complexity of the code you want to implement?
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

SuperR

Something like this is the discretized transfer function;

>> c2d(C,0.0001)

Transfer function:

                                                                                   
7.716 z^7 - 37.57 z^6 + 73.23 z^5 - 71.39 z^4 + 34.81 z^3 - 6.785 z^2 - 0.001332 z
                                                                                   
                                                                       - 1.96e-008 
                                                                                   
-------------------------------------------------------------------------------------
                                                                                     
z^7 - 3.882 z^6 + 5.648 z^5 - 3.652 z^4 + 0.8852 z^3 - 1.632e-005 z^2 + 1.002e-010 z
                                                                                     
                                                                     - 2.053e-016 

robtillaart


such a formula can be calculated quite well with an Arduino.

float x1 = ((((((7.716 * z - 37.57) * z + 73.23) * z  - 71.39) * z + 34.81) * z - 6.785) * z - 0.001332) * z - 1.96e-008 

This trick brings it down to 14 "simple" float operations instead of using power

Main problem might be that the Arduino only supports 32bit IEEE754 floats with ~7 significant digits.

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

dc42

If you need to sample 2 inputs, you face an immediate problem which is that the Arduino in its default configuration takes about 100us to do a single ADC conversion. If you can tolerate reducing the number of bits resolution below 10, then you can increase the ADC clock frequency and achieve faster conversion times.

You will need to write the code something like this so that you are not waiting on the ADC conversions:

Start conversion of input A
Do half of the maths on the previous pair of samples
Wait for conversion to complete
Read the result of the conversion of input A
Start conversion of input B
Do the remaining half of the maths on the previous pair of samples
Wait for conversion to complete
Read the result of the conversion of input B
Repeat from start

What I don't know is whether you can do the maths fast enough on an Arduino, but you can measure that yourself.

You will be sampling the inputs at slight different times (maybe 50us apart). If that isn't acceptable, you will have to use an external ADC chip with faster conversion time.
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

SuperR

I think 10bit resolution is fine. However, I have both positive and negative voltages. If it helps to use an external ADC and DAC, I think that's possible. And DC42, nice to know that code can be run while I wait for the ADC is running. I'll investigate further within the next couple weeks.

michinyon

I don't understand how you plan to have output to an accelerometer.

SuperR

From an accelerometer, not to. The accelerometer is my sensor

SuperR

I have been informed of the Arduino Due, which might solve my speed-problems. An order is pending so I should be up and running shortly. More to come :)

SuperR

#9
Feb 24, 2013, 09:06 am Last Edit: Feb 24, 2013, 11:21 am by SuperR Reason: 1
Ok, there's an update on the situation;

Instead of using the analogread or shaping the analog signals so that they fit the requirements of the Arduino Due internal adc, I am going to implement a dedicated ADC. The one available at the lab is a LTC1605. Just the IC, I need to built a PCB so I am free to implement different/extra IC's.

http://cds.linear.com/docs/en/datasheet/1605fc.pdf

Therefore, the questions now turns into;
What is the fastest/best way to turn those 16 output pins of the IC into a value in my Arduino Due? And even worse, I would read two of these ADC's.

After studying the spec sheet my steps would be;
Put CS low, (initiate conversion of ADC)
Wait 8 uS, time it takes between CS low and valid data
Read 1 byte, (8 I/O pins) from ADC1
Read 1 byte, (8 different I/O pins), from ADC2
Put "Byte" high,
Read second byte from ADC1
Read second byte from ADC2

That would cost me around 20 pins for 2ADC's, leaving me plenty pins for the DAC, which uses around 20 too.



SuperR

ADC is up and running, at least, we receive data which matches the voltage on the multimeter :). I was planning on using a TXB0104 for the 5V to 3.3V conversion. That way, I can safely measure the 2 8bit streams. Since I have to wait for parts and we would like to keep our code-progress up, for today, a simple voltage divider will be attemped, 2 r's op 2k5 I thought were used. I'll keep you updated.

If someone has an idea on how to implement the discretized transferfunction, please inform me!

Code: [Select]
>> c2d(C,0.0001)

Transfer function:

                                                                                   
7.716 z^7 - 37.57 z^6 + 73.23 z^5 - 71.39 z^4 + 34.81 z^3 - 6.785 z^2 - 0.001332 z
                                                                                   
                                                                      - 1.96e-008  
                                                                                   
-------------------------------------------------------------------------------------
                                                                                   
z^7 - 3.882 z^6 + 5.648 z^5 - 3.652 z^4 + 0.8852 z^3 - 1.632e-005 z^2 + 1.002e-010 z
                                                                                   
                                                                    - 2.053e-016

SuperR

Hmmz, the ADC is taking around 30us. I was hoping it would be faster. I hope I can read the ports faster. I was hoping to simultaneously read all 8 bits instead of ready each one individually. Please comment

Code: [Select]

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);
}


byte RC = 40;
byte BYTE = 42;
byte b1_pin = 22, b2_pin = 24, b3_pin = 26, b4_pin = 28, b5_pin = 30, b6_pin = 32, b7_pin = 34, b8_pin = 36;

int b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16;

int output;
float outputV;
//long bit1, bit2, bit3, bit4, bit5, bit6, bit7, bit8;


void setup() {

pinMode(b1_pin, INPUT);
pinMode(b2_pin, INPUT);
pinMode(b3_pin, INPUT);
pinMode(b4_pin, INPUT);
pinMode(b5_pin, INPUT);
pinMode(b6_pin, INPUT);
pinMode(b7_pin, INPUT);
pinMode(b8_pin, INPUT);

pinMode(RC, OUTPUT);
pinMode(BYTE, OUTPUT);

digitalWriteDirect(RC,HIGH);
digitalWriteDirect(BYTE,LOW);

// Serial.begin(9600);
}

void loop() {
  digitalWriteDirect(BYTE,LOW);
  digitalWriteDirect(RC,LOW); 
  delayMicroseconds(1);
  digitalWriteDirect(RC,HIGH);
  delayMicroseconds(6);
 
  b9 = digitalReadDirect(b1_pin);
  b10 = digitalReadDirect(b2_pin);
  b11 = digitalReadDirect(b3_pin);
  b12 = digitalReadDirect(b4_pin);
  b13 = digitalReadDirect(b5_pin);
  b14 = digitalReadDirect(b6_pin);
  b15 = digitalReadDirect(b7_pin);
  b16 = digitalReadDirect(b8_pin);
  //bit_val = b8 + 10*b7 + 100*b6 + 1000*b5 + 10000*b4 + 100000*b3 + 1000000*b2 + 10000000*b1;
 
  digitalWriteDirect(BYTE,HIGH);
  delayMicroseconds(1);
  b1 = digitalReadDirect(b1_pin);
  b2 = digitalReadDirect(b2_pin);
  b3 = digitalReadDirect(b3_pin);
  b4 = digitalReadDirect(b4_pin);
  b5 = digitalReadDirect(b5_pin);
  b6 = digitalReadDirect(b6_pin);
  b7 = digitalReadDirect(b7_pin);
  b8 = digitalReadDirect(b8_pin);
 
  output = (b2 << 14) + (b3 << 13) + (b4 << 12) + (b5 << 11) + (b6 << 10) + (b7 << 9) + (b8 << 8) + (b9 << 7) + (b10 << 6) + (b11 << 5) + (b12 << 4) + (b13 << 3) + (b14 << 2) + (b15 << 1) + b16;
  if (b1 == 1) { outputV = (-32767 + output)/3276.8; } // 10V per 2^15 bit
  else {outputV = output/3276.8; } // 10V per 2^15 bit


robtillaart

Quote
If someone has an idea on how to implement the discretized transferfunction, please inform me!


Whjat do you mean exactly, I posted a faster version of your function in reply 3 .
Have you measured the time difference?
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

SuperR

#13
Mar 01, 2013, 07:07 am Last Edit: Mar 01, 2013, 09:04 am by SuperR Reason: 1
Well, either I interpreted your code wrongly, or you did mine.
The z in the transferfunction is not some value but the "Z transform".

Imagine the following problem;

I need to store data from the past in some container/array;
Some "error", which stores values of the past 7 values of error
Some "u", which stores values of the past 7 values of u.

Define k to be the current sample. u(k) therefore will be the output of my equation.
Define (k-7) to be the data from a variable 7 samples ago. error(k-7) should be the value of error, 7 samples ago.

Now here comes the "fun";
To calculate u(k), I need to read all values, from error(k-7) to error(k) and u(k-7) to u(k-1). I then need to multiply those values by a certain set of 13 fixed values, say 7.7662, 2.34632 etc.
After that, I need to sum those values to get to u(k), which is send to the DAC.

Before the next calculation loop begins, I need to shift every "past value" one instance further away to the past. I only need to store the last x values so when the sample is too old, I can discard it.

I think the use of an array should be ideal. Is there a (dis)advantage of using 2 arrays for each value over storing the values in 1 "big" (14 value) array?

And inevitably, there's the float/integer issue again. Since I don't want to waste previous run-time, I was thinking of scaling up all values by 10, 100 of 1000 so that I can use 2byte integers for my calculations instead of the 4 byte floats. Will that help with the speed or is the difference negligible? I would think the calculation time would double, but I'm not the expert.


Go Up