I am developing a biopotential amplifier and I want to sample the signal and pass it into LabView application with Arduino via UART. Currently I am trying to get the highest possible sample rate. I have managed to get 100Hz using LINX and now I am testing how high I can get using Arduino IDE and I have managed to reach 200Hz, any higher than that and Arduino freezes. I have put together a simple program which takes input from ADC and outputs it through UART together with sample number. The problem is that I recieve an unexpected values every 255 samples. I believe the problem lies in arduino program but i can't find it, maybe I am missing something obvious.
Here I enclose my timer interrupt routine and graph I have acquired with LabView.
My second question is if I can manage to get much faster sampling by using pure C instead od Arduino IDE. I need miminum 300Hz preferably even 800Hz.
By the way, how can I check how much time does my routine takes to finish? Is there a simulator for Arduino IDE?
core.a(main.cpp.o): In function `main':
C:\Arduino\arduino-1.0.5\hardware\arduino\cores\arduino/main.cpp:11: undefined reference to `setup'
C:\Arduino\arduino-1.0.5\hardware\arduino\cores\arduino/main.cpp:14: undefined reference to `loop'
I thought Serial.write/print didn't work within ISRs because interrupts were disabled within interrupt handling routines, and Serial library uses interrupts?
CrossRoads:
I thought Serial.write/print didn't work within ISRs because interrupts were disabled within interrupt handling routines, and Serial library uses interrupts?
They will work until the outgoing buffer gets full. Then, the Arduino will freeze, with Serial.write() waiting for room in the buffer to store the character, and room being made only by interrupts happening, shifting a byte out. Since interrupts don't happen in an ISR, the Serial.write() function will never return.
It was jus a snippet, not the whole code so ido not get these.
I tweaked the code a bit , moved serial communication to the main loop and left just analogRead in timer isr.
This allowed for the better timing and now the cortroller doesn't hang. Of course I forgot to change timings in LabView proigram. Now after I corrected it I have sampling rate at 1kHz which is more than enough.
Robin2:
What do you mean by with Arduino via UART Do you mean sending data to the PC though the regular USB cable?
What baud rate are you using?
...R
This is exactly what i mean. I have baud rate at 115200.
CrossRoads:
I thought Serial.write/print didn't work within ISRs because interrupts were disabled within interrupt handling routines, and Serial library uses interrupts?
I did not really take it into consideration. I don't know the implementation of serial nor timer1 library but it used to work. Now that I have changed the code a bit, it is no longer an issue.
Now my sampling rate is good and I am not losing any samples, but those weird spikes persisted. I noticed that vaulty sample happens every time when sample number is 14 and additionally when input signal changes very quickly. It is not dependent on baud rate or any other parameter.
val is used by the interrupt service routine AND by loop(), but it is not volatile. That will cause garbage output to the serial port, for two reasons.
One is that the current value of val is not fetched every time it is accessed, since loop() doesn't know that the variable can change outside of loop().
The second is that the value of val COULD change between the two accesses of val in loop().
You need to male val volatile, and you need to disable interrupts before computing upper and lower, and enable them again afterwards.
Ok, I looked closer at the problem. It turns out that I lose one byte of transmission when sample number is equal 14, additionally when i pull ADC input to the ground everything goes bananas and I get rubbish every second sample. I looked closer on transmission with serial port monitor and everything seems to be in order so there must be some problem in labview visa I use to communicate on serial port. I bypassed the problem by rejecting frames that do not consist of four bytes.
I corrected my code according to your suggestions:
Because i need to know exactly how long is interval between consecutive samples. I will want to do some spectral analisys later. And I like interrupts.
Robin2:
Now that we know you are just trying to do ordinary serial communications ....
If you get your code organized properly you will be able to send about 11,000 characters per second at 115200 baud.
You need to post your full code - snippets are no use.
You can't use Serial.print() within an ISR.
Since we haven't seen your full code it is impossible to know if interrupts are necessary at all.
...R
You can't use Serial.print() within an ISR.
I know now that I shouldn't and generally using nested ISRs is a non trivial issue but the code I enclosed in the first post worked. I will certainly look closer at this matter when I rewrite the code in pure C. This will be a good opportunity to learn how AVRs work at low level.
I've looked at your code but I can't relate it to the problem you describe
It turns out that I lose one byte of transmission when sample number is equal 14, additionally when i pull ADC input to the ground everything goes bananas and I get rubbish every second sample
You could shorten your ISR to the following and put the other code within the existing IF in loop(). I don't know if that would make a difference.
void timerIsr()
{
val = analogRead(A2);
sampleSentFlag = 0;
}
I'm not sure what digitalWrite(A2, HIGH) does for an ADC pin - it is unlikely to help.
I don't know anything about the Timer library. Does a period of 1000 represent 1000 microseconds? I presume you have satisfied yourself that the library works properly?
I wonder if your problem with pulling the ADC low is due to your connection arrangements. Can you post a wiring diagram - a photo of a pencil drawing will be fine.
In consumer software I set '\r' as termination character which is equal to 13. And so if sample number or ADC readout was 13, the software read less bytes from the buffer than it should. This may be a small oversight but took me 4 days to figure out. So embarrasing.
@Robin2
I thought pulling up ADC input will help me get more stable readouts but it did not help at all.
I enclose screencap of my draft LabView code, maybe someone will find it useful or interesting.
Mamobija:
In consumer software I set '\r' as termination character which is equal to 13. And so if sample number or ADC readout was 13, the software read less bytes from the buffer than it should. This may be a small oversight but took me 4 days to figure out. So embarrasing.