[Solved] Need 'quick' light measurements over Serial or external RAM?

Hey there, so I am relatively new to Arduino and electronics in general. I have a data handling/transfer issue. Here's the short and skinny.

I am using an amplified photodiode on an analog pin. Getting some nice clean values which represent 'intensity' I suppose. The issue is this, I want to collect these measurements everytime I recieve a signal on a digital pin(say a HIGH). Then worse yet, I want to either transfer or record these values. So I have come up with two schemes for doing this...

Scheme 1:
Attach an interrupt for the digital signal. Use a quick if statement to see if the signal is 'high'. Perform an analogRead? Then transfer this information perhaps in chunks over the serial? Running into problems with this. It is obviously pretty poor practice to use an analogread in an interrupt and then follow it by a serial.write (sending two bytes). Well it's not working atleast. Program won't even execute the interrupt. So I am wondering if I am going about this the wrong way, is there a 'smarter' way to program this? For example, could I use the ADC clock and have these two operations slightly out of sync but close enough. Ideally at about 700signals a second (0.0015 seconds per signal)? Where a signal is I suppose two bytes. Or is that simply too fast to be possible while passing the data down Serial?

The other scheme is less involved for what must be happening simultaneously.

Scheme 2:
Similarly to Scheme 1, get the analog read and digital interrupt to be semi-simultaneous. However, rather then chucking the data down the serial, chuck it to a RAM I.C. or some other similar componant. Store the information in an array or something similar on the I.C. then once I am done collecting this information, transfer it as slow or fast as I would like down the Serial. I like this idea more but have no idea what I.C's would be suitable for this type of operation, or if the pace of 'writing' to them would be fast enough(better then sending it straight down the serial). If there are any affordable (poor student here) componants that might be useful for this please let me know. The maximum amount integers (in an array) to be stored would be around 2096 (simply too large for the arduino).

Scheme 2: is more so using the digital pin as a 'gate' to send the data from the analog pin elsewere. So rather then reading somehow 'directly' write the information even if it's on a separate circuit to another storage device (not the arduino RAM).

Essentially any ideas, references, things to look into, tutorials would be greatly appreciated. Thanks for reading through this. I apologize for being new to all of this but I am pretty quick at learning and really will thoughtfully look into any suggestions. What I really lack as a begginner is the technical terminology to do effective searches so that will help too.

Hi there

Can you confirm the max samples per second? Is it the 700 you mention?

And will the trigger occur at regular intervals? If not, what is the minimum interval between samples?

Regards

Ray

Well I can tune the samples per second a little bit. The most I can slow the digital signal 'cycle' is to about three seconds with 2096 analog measurements. So I quickly tabulated ~700 signals a second.

Unfortunately the triggering will not be absolutely uniform. I could try to design it for uniformity. There will be some hysterisis between the digital signals as they are coming from a motor encoder. So I can't exactly say the change in time from the first signal and the second(accelerating) will be the same as the 700-701(roughly no acceleration) or 2095-2096(decelerating). I haven't calculated how much deviation from the signal rise and fall-times or race conditions and do not unfortunately own an oscilliscope. I could try to come up with a rough estimate or attempt to tune a PID control on the motor/encoder to keep it with-in a certain range. However, with the interrupts going it's hard to say how much deviation from said PID control there would be if it was in say a main-loop.

That was why I was thinking that using an interrupt on the digital pin was a good solution, but if I had to use the timers on the ADC this would create a problem. Unless I settle on a time for the digital pulses and can have them delivered uniformly. I could get to work on this today if there is a good work around going this way. I was hoping to avoid going this route but can try if there is no foreseable other means.

Actually you know what I can get the time down to about 7 seconds after a quick test... So 350 signals a second should be possible. Really had to slow down the motor but it isn't straining too much(no hissing).

We've published a library to attach FRAM (ferroelectric RAM) to the Arduino. Details here: http://hackscribble.github.io/hackscribble-ferro-library/

We wrote it for a project with similar requirement to yours: caching test data before sending it on to a controlling PC. The library includes functions to create arrays of types of your choice, and to read / write them with random access (as per normal arrays).

First version of the library (not tuned for performance) takes about 45 microseconds per write and 30 microseconds per read. So writing up to about 22,000 samples per second.

We are actively supporting the library and would like to see it used in applications. So feel free to contact me if you would like more information.

Regards

Ray

Wow hackscribble that is very impressive. I may look into this as the chips are incredibly cheap! Thanks for letting me know.

I have another idea. Or really it's the first idea but slightly different. I am thinking if I set up two byte arrays(64 items in size or 32 integers) I can do the analogread(~120 usec) in my digital pin interrupt with some fast bit shuffling and boolean logic. Should be able to fill an array in about 22ms.

Now what I need is some sort of timer interrupt running at 100Hz(every 10ms) to send the filled buffer over the serial without inteferance? Is this possible? I've theoretically calculated how long it should take to send the array and it should be around ~5ms assuming I miss the 1ms USB poll time that's 4ms of cushion time to account for other things happening. Should also mention that while these measurements are occurring the program is doing effectively nothing else except testing a conditional statement.

Is this too 'heavy' for an attached interrupt?

//Interrupt code to handle the initialization
void rotorPulsedInit() {
if (PINB & 0b00000001) { //if(digitalRead(PinB)==HIGH)
intensity = analogRead(photoDiode);//Approx 120usec

if(!bufferTwo){
//Turn integer into two bits
bufferOne[fillIndex] = intensity & 0xFF;
fillIndex++;
bufferOne[fillIndex] = (intensity >> 8) & 0xFF;
fillIndex++;
if(fillIndex == 63) {//If we have filled the buffer start to fill the next one
indexTwo = true;
fillIndex = 0;
}
} else {
bufferTwo[fillIndex] = intensity & 0xFF;
fillIndex++;
bufferTwo[fillIndex] = (intensity >> 8) & 0xFF;
fillIndex++;
if(fillIndex == 63) {//If we have filled the buffer start to fill the first one
indexTwo = false;
fillIndex = 0;
}
}
pulseCount++;
}
}

Not sure how exactly to go about setting up a timed 100Hz interrupt? Maybe google will help.

Hello

I've just gone back over some of the figures you mentioned.

120 microseconds per analogRead would give over 8,000 samples per second (assuming no other processing).

On the serial side, with a bit rate of 115,200 bps and 10 bits per byte, you could in theory get over 5,700 16 bit integers per second. However, I have never tested Serial to see if it can sustain that rate.

You need 700 samples per second? Have you tried just a simple loop (non-interrupt) that polls the digital pin for a change from low to high, then does the analogRead and then writes the two bytes to serial?

Sorry if I am missing something obvious :slight_smile:

Regards

Ray

(1) You should not put any code in your interrupt service routine. You should just set a flag that the interupt has occured, and then let loop( ) start doing what needs to be done.

(2) You probably don't actually need an interrupt at all. Just get loop( ) to check the digital pin, every time it cycles around. The main good reason why you would want to use an interrupt here, is if the incoming signal is very brief and loop takes a long time.

Just did a quick test on my Uno.

25,000 iterations of doing an analogRead() and writing two bytes to Serial at 115,200 bit rate takes around 4.4 seconds.

That is about 5,600 samples per second.

Thanks again HackScribble and Minchinyon. Maybe my baud was too slow when I was originally trying this (57600). I’ll scrap the byte array idea for now and give it a shot with loop and a flag. Might do a byte array in the off-chance I get an over-load on the serial buffer so I don’t miss any data. Cross that bridge when it comes. It sounds like if I can get my coding up to par I should be able to do this then. If not I’ll go by way of FRAM or SRAM. The 23LC512-I/P looks like an affordable 5V SRAM IC as well. Could be fun to do it that way anyways but hopefully uneccesary as waiting for componants to ship really slows down progress.

I’ll update with progress or failure. Thanks again it means a lot.

Alrighty, so I've done as you both have suggested. The serial monitor from the Arduino IDE appears solid. Really really wish they allowed copy and paste just so I could get a count of how much data was transmitted. In a bothersome but typical fashion the JAVA interface I've made for handling the Arduino serial commands is causing some issues.

The Arduino IDE's serial monitor appears to be working great. However, when I try and catch the data from my JAVA application it's almost like there's an endless loop going on or something is caught up. My pulse counts never reach the condition for ceasing the measuring operation, even though data is being transmitted? Bizarre. Maybe it's my fault? Shouldn't be RXTX, as I copy and pasted the one for my application directly from the arduino dependancies or lib folder if I recall correctly.

Victory!

Needed to look at the serial monitor source code to see what I was missing. Very nice of Arduino to be open source and not require me to pull out the old decompiler. All it needed was a while loop. Fantastic. Thanks everyone!