Sine Wave over UART

Hi All

I am trying to read a sine wave into the ADC on an Arduino Due and send this over the UART to a receiving Arduino Due, which will replicate the sine wave (as close as digitally possible) on its DAC output.

I am sending a sine wave with a frequency of 1 kHz. I am trying to calculate if this is possible. However I am finding it difficult to find much information online regarding the transmission of sine wave over an Arduino UART

I am using a baud of 115200.
ADC and DAC resolution of 12 bits

My calculations are as follows:

Duration of each bit=1/Baud=1/115200=8.68μs

To transmit 4069 bits at a baud of 115200 = Duration of each bit×4096
= 8.68μs × 4096 = 0.036s

Therefore maximum frequency capable of being transmitted over the UART =1/0.036=27.77Hz

This seems like a very low frequency, so I am sure there is something wrong with my calculations and my understanding of how to calculate the maximum frequency that can be transmitted over the UART at 115200.

Can anyone steer me on to the right path?

Even though you are using only a 12 bit A/D each sample needs two bytes.
Each byte takes 10 bits to send you forgot a start and stop bit.

You need to send about 20 samples over one cycle of the waveform for it to look like anything decent, although the frequency information will be transferred as long as you send two or more samples over a single cycle.

Why are you using such a slow baud rate?

Yes it is slow.

You are missing connecting the grounds together or else nothing will work.

You also omitted to take into account the time it takes to measure a sample.

Can you clarify what you really want to send out on the serial port?

At 115200 bauds you send roughly 11520 bytes per second. If you want to send the frequency you detected, even in ascii, say 10 characters max total with end marker, you could update the message 1152 times per second.

Thank you for the information, I have updated the diagram to show the GNDs connected together

Initially, I was worried about losing packets which is why I used the 115200 baud. I was thinking of using a baud of 2000000 as this is the maximum baud capable of the Arduino IDE serial monitor

from the ATSAM3X8E data sheet it states:

The maximum allowable baud rate is Master Clock divided by 16.

Since the master clock of the ATSAM3X8E is 84MHz does this mean the maximum allowable baud is 5250000?

If this is the case why does the serial monitor in the Arduino IDE only go up to 2000000?

I have omitted the sample measure time as I will be using an external ADC and DAC later and I am not sure of the sampling capability of them

Don't know, but you are free to use any other terminal program you want, you can even specify what it is in the options.

Maybe not all laptops, especially of the windose variety can keep up with printing stuff reliably p that fast.

Have you thought how you will distinguish between the most significant byte and least significant byte if you get out of sync? One way is to restrict the information to 14 bits of data and have the least significant bit have a zero in the most bit and a one for the most significant byte.

I think UART protocol is probably not suited for your task. Try to use SPI for transfer data - on Due you can easily use 10-20 MHz SPI clock, that give you about 1 Msps (1 Megasample per second) channel for your data points.

In addition, you can use DMA for transferring data from ADC to SPI and from SPI to DAC on receiver side without involving the main controller in the process.

Hi thank you for the information

Do you have any references that I can look at, that allowed you to calculate the amount of bytes per second?

I would like to send the value from the ADC out on the serial port using the serial.println. this sends the data on the serial port using the type size_t.

Do you know how I can get the message to update 1152 times a second?

My code for the transmitter is below

/*
* Reads the value from the ADC with a 12-bit resolution. The input voltage is varied between
* 0-3.3V which corresponds to 0 - 4095  
*/

void setup()
{
  // initalize serial communication at 115200 bits per second:
 Serial.begin(115200);
 analogReadResolution(12);
}

//the loop routine runs over and over again forever:

void loop() {
 // read the input on analog pin 0:
 unsigned int sensorValue = analogRead(A0);

 Serial.println(sensorValue);

 delay(100);  //delay in between reads for stability

}

This is a very bad idea. Using Serial print sends a series of ASCII characters from 1 to 4 for each value. Then you would have to turn it back into a number. Time is of the essence here, you don't have enough to go wasting it by using this silly approach.

A very silly and wholly unnecessary delay.

I misunderstood what you were asking for. I thought you were doing the frequency analysis locally and sending out that frequency to the other arduino.

The math came from the fact that a Serial UART connection requires roughly 10 bits to transfer one byte. So 115200 bauds is roughly 11520 bytes per second

1 Like

with this line you could update the message 10 times per second as maximum

1 Like

In order to properly send the sine wave data, you'll have to satisfy the Nyquist criterion of sampling at least 2x its fundamental frequency. In reality it's more like 10x to get useful data at the other end. So your 1kHz sine now needs to be sampled at 10kHz with two bytes per sample.

So how do you do that if you limit the speed to 115,200bps? Compress it.

A sine wave changes very slowly so it's a perfect candidate for a very simple compression. One method that comes to mind is to send a full 16-bit sample every x seconds, "x" being the longest time that you can allow "bad data" to persist. In between those full samples, you only transmit the delta between the last reading and the current one. You do the math, but it's likely less than a byte (maximum rate of change is going be around 0), so at 115,200bps, you can easily sustain a 10kHz sample rate if you send binary data.

Alternately, you could use something like Run Length Encoding, since at a 12-bit sample resolution, you may get long stretches of the same value, but that's TBD.

You do realize the A0 must always be above 0V?

1 Like

Thank you, I will use the Serial.write(sensorValue); instead

I originally but in the delay so I could separate out the bytes on an oscilloscope. But as you have rightly pointed out, it probably does not need to be as long or isn't needed at all

it won't work because your Serial.write(sensorValue) sends only byte, but your sensorValue definitely wide than 8bit

why don’t you measure the frequency on one Due and tell another Due to generate that frequency?

You can use it to send multiple bytes

Serial.write((byte*)&variable, sizeof variable);

Of course endianness matters then

yes, of course :slight_smile:
but if it used as OP - Serial.write(sensorValue) - it will send only byte

Indeed

Apparently he does not realise or understand this, so rather than asking a question about it, @due_noob has chosen, very unwisely to ignore you, and as a result has probably burned out the Due's analogue input pin.

@mrburnette Yes I knew I could only put 0 - 3.3V on the ADC, it was a poor drawing on my part. That is what the sine wave will look like after it has come out on the DAC and gone through a level converter that is isolated from the Arduino's I/O