I'd like to be able to generate a variable waveform based on data I send from my computer over serial. My basic thinking is that I have a Python script that will generate the wave magnitudes then send a byte of data at a time over serial to the Arduino. On the Arduino end of things, I'd read from serial then do direct port manipulation. That part works. The two problems I have are that I need very precise timing and I need to send more data than the Arduino's memory can hold. I think this is solvable by using a queue that will buffer data from my computer until the Arduino's RAM is full, then have a timer routine that pops an item out of the queue and writes it out to the ports. When there is sufficiently free memory, I can send more bytes. I figured out timers and I've verified with an oscilloscope that my timer works. I'd like to update at 16kHz, which I think should be doable if I choose a sufficiently high baud rate. I found a FIFO library (Arduino Playground - QueueArray Library) which seems to work.
The problem I'm having is that when I set my timer to interrupt very frequently (like at every 1/16000th of a second), nothing ever gets written into the array. Setting the timer to interrupt a lot less frequently fixes the issue, so I know it must be something that the interrupt is doing. I guess that makes sense, but is there any way around this? I've posted my code below, thanks!
I haven't studied your program, but the way I handle sending "too much" data from pc to Arduino is
void loop() {
if ( Serial.available()>10 && !XOFFState ) { Serial.write(XOFF) ; XOFFState = true ; }
if ( Serial.available()<5 && XOFFState) { Serial.write(XON) ; XOFFState = false ; }
:
otherwise handle input and processing as before
The sending software must of course also read what the Arduino sends (here as Processing code)
void draw() {
if ( PortSMP.available()>0 ) {
char C = char(PortSMP.read()) ;
if ( C == XOFF ) XFLOW = false ;
else if ( C == XON ) XFLOW = true ; }
:
and then cease to send data if XFLOW is false
The characters XON XOFF can be any charcter that is unique in what you send from the Ardino, but theye are usually ^S and ^Q.
I have found by experimentation that it fails if one first triggers XOFF at - say - 50 characters in the buffer (there is room for 64). The delay of the character oing from the Arduino via the USB and through the whole of Windows/Linux OS and to the sending program takes some time. You may need to tweak the start/stop levels to fit your app.
You haven't protected the queue from interrupts in the middle of queue operations. in general, code has to be written very carefully if it uses data structures that are also manipulated at interrupt level, and I doubt that the queueArray code you are using was written that way. (The alternative is just to enclose the manipulation inside interrupts()/noInterrupts() calls.)
Also, it looks as though the queueArray implementation automatically grows the storage used for the queue (at substantial expense!), but since you avoid calling it when the queue is full, I don't think it will ever grow beyond its initial size of 2.
Finally, the Serial code already implements a very similar datastructure, so you're essentially pulling things off of one queue and putting them onto another queue, which is less efficient than it could be. You might be better off figuring out how to write modified Serial code so that your timer interrupt can pull things directly off of its queue.
Yeah, I was thinking of writing my own queue. All I need is a circular array of some fixed length. How can I make sure my code is interrupt safe? Thanks.
you can define an array of bytes that is volatile. array size depends on what you want the buffer size to be.
you need a head and tail pointer.
the push will add the new value to [head]
the pop will get the value from [tail]
if head==tail, there is no value
make sure head does not overrun tail
increment head/tail after push/pop access, then % to queue size.
wrap the code in loop that push to buffer between cli() and sei()
I'm fairly sure that I'm sending the XON and XOFFs because if I manually flood my Ardunio I can see the XOFF or XONs come back. However, I'm having trouble getting this to work with pySerial. I know that the it takes a parameter xonxoff which should get the library to start doing flow control but I don't think this is working since the program finishes way before it should.
Does anyone have any experience with flow control and Python, Java, C, Objective-C or anything else?