High-Speed Serial Transfer

Hey guys,

I’m having trouble sending serial data at a fast speed (5000 samples per second) through a Bluetooth serial connection and having it reproduced correctly at the receiving end.

For setup, I have a pair of RN-42 modules (SparkFun Bluetooth Modem - BlueSMiRF Silver - WRL-12577 - SparkFun Electronics) interfacing with a pair of Teensy 3.1 microcontrollers (Teensy 3.2 & 3.1: New Features). The microcontrollers are communicating with the Bluetooth modules at 230400 baud rate.

Basically, I want to send low quality audio from a mic from the transmitter to the receiver. I’m using interrupts at the transmitter end to have the audio sampled at 5000 Hz.

Now, when I send a sine wave through the transmitter, what I get on the receiver is a a square-waveish version of the sine wave, along with a bunch of other random jumps when I analogWrite() the signal.

The teensy has true 12-bit analog output, so I expected a near perfect reproduction of the sine wave if I could just feed the analogRead values correctly to the receiver. Any thoughts on what could be causing the receiver to receive a poor signal? My code for transmitting and receiving is included below.

//Transmitter Code
int led = 13; //Power led 
int SAMPLE_RATE_HZ = 5000; //Sampling rate
uint16_t val; //Variable for microphone input
const int AUDIO_INPUT_PIN = 14; //The signal will feed into pin 14
const int ANALOG_READ_RESOLUTION = 12; //12 bit resolution
const int ANALOG_READ_AVERAGING = 12;
const int CTS_PIN = 17;
IntervalTimer samplingTimer; //Set up the interval timer, which lets us specify sampling rate

void setup()
{
  //pinMode(led, OUTPUT);
  pinMode(CTS_PIN, INPUT);
 // digitalWrite(led, HIGH); //Turn on the LED o the Teensy
  Serial.begin(115200);
  Serial1.begin(230400); //Begin serial communications with the Bluetooth and the USB if necessary
  analogReadResolution(ANALOG_READ_RESOLUTION);
  analogReadAveraging(ANALOG_READ_AVERAGING); //Set Analog read resolution and averaging

  delay(2000);

  samplingBegin(); //Begin reading audio immediately

}

void loop() //Do nothing, the interrupt timers handle data acquisition and sending
{ 
  
}

void samplingBegin() //Set up sampling rate, will call the samplingCallback function every 1000000/sampling rate microseconds.
{
  samplingTimer.begin(samplingCallback, 1000000/SAMPLE_RATE_HZ);
}

void samplingCallback() //Continously read in analog input (noise if no input)
{
  if(digitalRead(CTS_PIN) == LOW) //If the bluetooth's internal buffer is not overwhelmed.
 {
  val = analogRead(AUDIO_INPUT_PIN);
  Serial1.print("<"); //Send the entire integer, with a marker for start and end to be recognized by the receiver.
  Serial1.print(val);
  Serial1.print(">");
  }
}
//Receiver code
int led = 13;
char input;


void setup()
{
  pinMode(led, OUTPUT);
  digitalWrite(led, HIGH);
  Serial.begin(115200);
  Serial1.begin(230400); //Open Bluetooth comm
  analogWriteResolution(12);
  delay(3000);

 
}

void loop()
{ 
if(Serial1.available())
  {
    while(Serial1.findUntil("<", ">")) //Find a <, then store the values into an int until a > is met.
    {
      int val = Serial1.parseInt(); //create an int from the characters between < and >
      analogWrite(A14, val);
    }
  }

}

Time for a little math. 230400 / 10 / 5000 = 4.608 bytes per sample. Assuming perfect communications (no retries) you have 4.608 bytes per sample available.

  Serial1.print("<");
  Serial1.print(val);
  Serial1.print(">");

Assuming the input has a balanced histogram over the 0 to 1023 range, on average 4.916 bytes per sample are needed.

You are trying to push too much data through the pipe. You need a more efficient encoding (fewer bytes per sample) or a bigger pipe (higher baud rate).

Thanks for the response. I've tried lowering the sample rate to reduce the number being sent per second, but that only makes the signal received even worse. Another thing I've tried is to break the integers I'm sending into high and low bytes to reduce the number of bytes sent, but the receiver appears to misinterpret the original integer quite often. Any advice on how to improve my encoding, or anything else that could be messing up my transfer?

I assume the Bluetooth modems collect a "full packet" before transmitting which means the receiver will get bursts of data interspersed with silence. To do what you are trying to do, you really need to buffer the data on the receiver and then play it back at the same rate it is collected (that's essentially how all digital audio {and video} playback works).

Why are you converting binary data to ASCII data and back? Just send and receive binary data. Orders of magnitude faster.

Are there any frequencies over 2.5KHz in the sampled signal. Any frequencies over 2.5Khz will be aliased and folded into the data.

I need to send over integer values for AnalogWrite over Serial, and since these are 12 bit integers, I wasn't sure how to do it in binary. As for frequency content, there shouldn't be that many frequencies higher than 1 Khz, as I have hardware band-pass filtering.

Could you give me advice on how to send 12 bit integers as binary over serial correctly? Also, I'm not sure how to go about buffering the data.

and since these are 12 bit integers

There are no such things as 12 bit integers. There are 8 bit and 16 bit and 32 bit and 64 bit integers. Not all on the Arduino, of course.

A 16 bit int, which is what you really have, is 2 bytes, obtained using bitshifting, or highByte() and lowByte() for the less brave.

Serial.write() the high byte. Serial.write() the low byte. Or, vice versa.

Also, I'm not sure how to go about buffering the data.

What compound are you using on your buffer? Why do yo need to use a buffer on your data?