I wrote a routine to sample the Mic at 8khz with interrupts in CTC mode it works! As you know the available RAM is only 2K. What to do with all this data? I could write it to Openlog, USB, or Xbee. All of these are Serial. 115kbaud is fast enough. But whenever I write a character or buffer I have to turn off Interrupts first. If I send more than a character at a time without servicing the Mic interrupt I will miss sampling the Mic on time. These 2 speed, in and out, are about the same so I can't even send 2 characters in the time between Mic samples. How do I send data serially without waiting for the buffer to finish sending? During this time interrupts are disabled.
After more research I see that I can send ONE character without waiting, assuming the single character output buffer is always empty. There will be retries with XBee so this might not always be true. Or 2 characters and only need to wait for the 1st to send. This does not help much for a buffer of size 100. I still have to wait to send 99.
Let's keep it simple:
Can I send 1 byte each time from within the Mic sampling ISR using Serial.write?
In this case can I leave Interrupts enabled since I know it won't be called twice? Does Serial.write or Serial.print disable interrupts? If so I'll just re-enable them. I guess I have to do this anyway since I'm in an ISR. I guess my real question is can I call Serial.write from within an ISR? Anything special I need to do first?
Let's assume that'll work. Please correct me if I'm wrong. I should test it. Now I'm going to get more complicated. Let's say I want to modify the data in a buffer before sending it serially. Can I use a small circular buffer for this? Instead of sending each byte as it's received from the Mic directly, I can store it in the buffer in the ISR, then send the next single byte from the other side of the circle, all within the ISR. 1 byte in, 1 byte out. Who says I have to send the byte I just got? Noone right?
The traditional way to handle that sort of problem is to use a ring buffer. The interrupt service routine puts data in. loop pulls data out and writes it to the serial port.
Sure, Circular/ring buffer. I understand that part. But if I send it to the serial port in loop, I have to disable interrupts for each byte sent. Otherwise the ISR will interrupt the serial routine. If I send more than one byte, the interrupts will be disabled for too long and I'll miss a Mic sample. So I have to send one byte at a time then check for (enable) interrupts to sample the Mic. If that's the deal, why not just send 1 byte at a time within the ISR? My first experiment will be simple, the byte I just got. Then add the ring buffer.
Can I send 1 byte from within the Mic sampling ISR? There is no delay, assuming the buffer is empty.
According to what I've read, you have to disable interrupts during serial transmission. I assumed this is because you don't want it to be interrupted in the middle of a string of 8 bits? Maybe this is wrong? Is it as simple as you say? Just send it in loop without turning off the interrupts to service the Mic? That makes sense since the Serial.write call only takes a few uSecs anyway. You wouldn't be interrupting the UART itself. It is unlikely the write call would be interrupted if it's being called when the 1 byte buffer is empty.
If I do have to disable interrupts, it wouldn't delay the Mic sample much, only a few uSecs, not milliseconds. The key is to avoid waiting for the 1 byte buffer. Maybe interrupting this wait is bad? Probably not.
I've realized the transmit buffer before the UART is only 1 byte. But in the XBee it is 100?
The code will slow down on it's own waiting if the 1 byte buffer is full. But I have to monitor CTS to avoid filling the bigger one.
sbright33:
According to what I've read, you have to disable interrupts during serial transmission.
By "you" I assume you mean you personally (as opposed to someone writing a library or core or a group of users).
I assumed this is because you don't want it to be interrupted in the middle of a string of 8 bits?
Which is a potential problem to be addressed by the person who wrote NewSoftSerial and by the person who wrote SoftwareSerial.
In any case, it is not a problem for you personally (you are not writing a bit-bang software library) and is a problem that does not involve your project (you are using Serial).
The key is to avoid waiting for the 1 byte buffer. Maybe interrupting this wait is bad? Probably not.
You need to use a ring buffer to hold the data to be serially transmitted and use the uart tx interrupt to send each character. I'm surprised the Serial class wasn't written to do this. I think this is fixed in the 1.0 revision.
dc42:
You need to use a ring buffer to hold the data to be serially transmitted and use the uart tx interrupt to send each character. I'm surprised the Serial class wasn't written to do this.
Right, as far as I know, HardwareSerial.cpp does not use asynchronous serial transmission, just receive. This app needs a ring buffer for sending data, and the ring buffer needs to be serviced by the USARTs interrupt. There is another thread where this was discussed and another member posted a link to beta code of HardwareSerial.cpp that uses async transmission.
But, his concern is what happens when the microphone needs to be sampled.
In the AVR world, interrupts can be prioritized. You can make the interrupt for the mic a higher priority than the interrupt for sending serial data. I expect that could be configured in the Arduino by writing to the registers directly.
And he is quite correct that NewSoftSerial is not a suitable tool for this, because without a UART, interrupts need to be pu down to send or receive even 1 byte of data. So the OP should look at an Arduino with more than 1 UART, something like Crossroads' 1284P board, which has lots of RAM for buffers and 2 USARTs. Then he can use the beta version of HardwareSerial.cpp for async sending. For interrupt prioritization, we'll have to consult the data sheet for the MPU.
Another idea, on a different track. I wouldn't have to write any code. I wouldn't even need a controller!
On either end. Could just hook 2 XBees to 2 amps, Mic, Speaker to hear it. http://www.digi.com/support/kbase/kbaseresultdetl.jsp?kb=180
But it's only 1khz.
Of course this is not what I'm trying to achieve, but how Cool!
Wouldn't this allow the processor to be totally free to manipulate the higher frequency 8khz samples I've taken in 1K RAM? I realize this is only 1/8th sec. Once I've done that, I wouldn't have to store/send them. Just store the short results to Openlog, while the XBee is sending the LoFi audio for me to hear.
Works great even without interrupts! Plenty of processing time left over at 4k sampling, just make sure you're not late by checking within the innermost loop of your processing.