arduino pwm dac behaving very strange

Hi,
I have a java code that sends pcm recorded sample to a esp8266 via wifi, which in turn sends the data to arduino via serial that plays the sample using pwm DAC. I am using Timer1 as fast pwm for carrier frequency whereas Timer2 is used to set the sample rate. Please see below the code snippets.

  1. Arduino code
#include "Arduino.h"
#include <avr/interrupt.h> // Use timer interrupt library


void setup() {
 Serial.begin(400000);
 //Serial.begin(266666);
 /****Set timer1 for 8-bit fast PWM output ****/
 pinMode(9, OUTPUT); // Make timer’s PWM pin an output
 TCCR1B = (1 << CS10); // Set prescaler to full 16MHz,
 TCCR1A |= (1 << COM1A1); // Pin low when TCNT1=OCR1A
 TCCR1A |= (1 << WGM10); // Use 8-bit fast PWM mode, so it will count from 0-255, and the duty cycle would be set by OCR1AL(OCR1A lower byte)
 TCCR1B |= (1 << WGM12);
 //freq calculation: at 16mhz, time taken to count till 255 is (1,000,000/16,000,000)*256usec=16usec
 //freq is 16,000,000/256=62500hz=62.5khz,

 /******** Set up timer2 to call ISR ********/
 TCCR2A = 0; // No options in control register A
 TCCR2B = (1 << CS21); // Set prescaler to divide by 8,
 //i.e., 16,000,000/8=2,000,000 clock tick/sec,
 //so every tick at 500ns (.5us), so to spend 32 usec it needs to count upto 64, 64*.5=32
 TIMSK2 = (1 << OCIE2A); // Call ISR when TCNT2 = OCRA2
 OCR2A = 64; // Set frequency of generated wave=2,000,000/64=31250hz
 sei(); // Enable interrupts to generate waveform!
}

void loop() { // Nothing to do!
}
uint32_t stime=millis();
uint32_t counter=0;
uint32_t etime=0;
/******** Called every time TCNT2 = OCR2A ********/
ISR(TIMER2_COMPA_vect) { // Called when TCNT2 == OCR2A
 TCNT2 = 6; // Timing to compensate for ISR run time
 if(Serial.available()){
 uint8_t byte=Serial.read();
 OCR1AL=byte;
 }//else{
 //OCR1AL=0;// duty cycle is zero, no output
 //}
 /*counter++;
 if(counter>=31250){
 counter=0;
 etime=millis()-stime;
 stime=millis();
 Serial.println(etime);
 }*/
 //Serial.write(100);
}
  1. ESP 8266 code:
/*
 *  This sketch demonstrates how to scan WiFi networks.
 *  The API is almost the same as with the WiFi Shield library,
 *  the most obvious difference being the different file you need to include:
 */
#include "ESP8266WiFi.h"
const char* ssid = "debojit-dlink";
const char* password = "India@123";
uint8_t outBuffer[2920];
uint8_t inBuffer[2920];

const char* host="192.168.0.105";
WiFiClient client;
void setup(){
 Serial.begin(400000);
 //Serial.begin(266666);
 setup_connect_as_station();
}
void setup_connect_as_station(){
 Serial.println();
 Serial.print("Connecting to ");
 Serial.println(ssid);
 Serial.print("Configuring access point...");
 /* You can remove the password parameter if you want the AP to be open. */
 WiFi.softAP("ESPAP");
 IPAddress myIP = WiFi.softAPIP();
 Serial.print("AP IP address: ");
 Serial.println(myIP);

 WiFi.begin(ssid, password);

 while (WiFi.status() != WL_CONNECTED) {
 delay(500);
 Serial.print(".");
 }
 Serial.println("");
 Serial.println("WiFi connected ip is");
 Serial.println(WiFi.localIP());
 Serial.println("#################");
 WiFi.printDiag(Serial);
 WiFi.hostname("esp8266");
 WiFi.printDiag(Serial);
}

void loop(){
 const int httpPort = 8086;
 if (!client.connect(host, httpPort)) {
 Serial.println("connection failed");
 delay(2000);
 return;
 }
 Serial.println("Connected, now receiving...");
 int cnt=0;
 long readBytesTotal=0;
 int writeBytestoSerialTotal=0;
 uint32_t sTime=millis();
 while(true){
 cnt++;
 int readBytes=client.read(inBuffer,2920);
 if(readBytes>0){
 int writeBytestoSerial=Serial.write(inBuffer,readBytes);
 //Serial.read();
 //readBytesTotal+=readBytes;
 //writeBytestoSerialTotal+=writeBytestoSerial;
 //Serial.print(readBytes);
 }
 if(cnt>=10){
 //sTime=millis()-sTime;
 //Serial.print(sTime);Serial.println("-------------------");
 cnt=0;
 yield();
 }
 /*if(readBytesTotal>=29200){
 uint32_t eTime=millis()-sTime;
 sTime=millis();
 Serial.println("-----------------------------------------");
 Serial.println("-----------------------------------------");
 Serial.println("-----------------------------------------");
 Serial.println("-----------------------------------------");
 Serial.print("Time taken: ");Serial.println(eTime);
 Serial.print("read bytes: ");Serial.println(readBytesTotal);
 Serial.print("write bytes: ");Serial.println(writeBytestoSerialTotal);
 readBytesTotal=0;
 writeBytestoSerialTotal=0;

 }*/

 }
}



void setup_as_station() {

 // Set WiFi to station mode and disconnect from an AP if it was previously connected
 WiFi.mode(WIFI_STA);
 WiFi.disconnect();
 delay(100);
 WiFi.printDiag(Serial);
 Serial.println("Setup done");
}

void loop_wifi_scanner() {
 Serial.println("scan start");

 // WiFi.scanNetworks will return the number of networks found
 int n = WiFi.scanNetworks();
 Serial.println("scan done");
 if (n == 0)
 Serial.println("no networks found");
 else
 {
 Serial.print(n);
 Serial.println(" networks found");
 for (int i = 0; i < n; ++i)
 {
 // Print SSID and RSSI for each network found
 Serial.print(i + 1);
 Serial.print(": ");
 Serial.print(WiFi.SSID(i));
 Serial.print(" (");
 Serial.print(WiFi.RSSI(i));
 Serial.print(")");
 Serial.println((WiFi.encryptionType(i) == ENC_TYPE_NONE)?" ":"*");
 delay(10);
 }
 }
 Serial.println("");

 // Wait a bit before scanning again
 delay(5000);
}
  1. java code
package com.test.socket;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketTimeoutException;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;

public class DataTransceiverSocket extends Thread {
 private ServerSocket serverSocket;
 private SocketAddress remoteSocketAddress;

 public DataTransceiverSocket(ServerSocket serverSocket, String name) throws IOException {
 this.setName(name);
 this.serverSocket = serverSocket;
 // serverSocket.setSoTimeout(10000);
 }

 public void run() {
 while(true){
 System.out.println(getName() + "->Waiting for client on port " + serverSocket.getLocalPort() + "...");
 Socket server = null;
 try {
 server = serverSocket.accept();
 remoteSocketAddress = server.getRemoteSocketAddress();
 System.out.println(getName() + "->Just connected to " + remoteSocketAddress);
 } catch (IOException e1) {
 // TODO Auto-generated catch block
 e1.printStackTrace();
 return;
 }
 Sender sender=new Sender(server);
 sender.start();

 }
 }

 public static void main(String[] args) {
 try {
 ServerSocket serverSocket = new ServerSocket(8086);
 Thread t = new DataTransceiverSocket(serverSocket, "T1");
 t.start();
 } catch (IOException e) {
 e.printStackTrace();
 }
 }

}

class Sender extends Thread{
 Socket socket;
 byte buffer[] = new byte[2920];
 private DataOutputStream out;
 public Sender(Socket socket) {
 this.socket=socket;
 try {
 out = new DataOutputStream(this.socket.getOutputStream());
 } catch (IOException e) {
 }
 }
 @Override
 public void run() {
 while(true){
 try{
 FileInputStream fis=new FileInputStream("C:\\Users\\debojitk\\Desktop\\esp\\samples\\test40000_1.raw");
 
 int readBytes=0;
 while((readBytes=fis.read(buffer, 0, buffer.length))>-1){
 out.write(buffer,0,readBytes);
 //Thread.sleep(40);
 }
 fis.close();
 }catch(Exception ex){
 ex.printStackTrace();
 }
 }
 }
}

I have set the arduino Timer2 to generate clock frequency of 31250hz, and sending a sample of same rate. But strangely the speed is actually matching with the serail speed and not the timer speed. In my code the serial speed is 400000 baud, i.e., it can send 50000 bytes/second so, if I send a sample of 40000hz it play perfectly on pwm the ratio of baud rate and sample rate is 50000:40000=1.25. Same things happen when I set the serial speed at 500000 baud and the sample rate is 50000hz, here also serial speed is 62500 (16usec per byte), and the the ratio is 62500:50000=1.25.
More strangely if I decrease the timer interrupt frequency by increasing the OCR2A (say from 64 to 128) the audio quality degrades, i.e., the effective sampling rate gets halved. If i make it 255, the quality gets even lowered but the speed remains same, i.e., the timer speed is not controlling the play speed rather it is driven by serial speed.
Can anyone explain this phenomenon.
Is it occuring due to serail buffer overflow issue because nowhere else in the data path i did any flow control but it is done at the arduino end only. should I try putting a timer at esp end to synchronize things.
Thanks is advance.
Debojit

I was expecting a reply by this time.

Kindly help.

Thanks, debojit

Hi All, I got the solution my myself. It was indeed the buffer overflow issue Now I added a timer at esp end, and both the timers are synchronized, I am able to play smoothly at intended rate. Thanks for all your support. Debojit