Sunday, March 29, 2015

Teensy 3.1 Impressions and the Audio Library

I have been hearing a lot of good things about the Teensy 3.1 development board regarding its use as a SDR platform HERE. It seems like it has a great deal of capability over the the Teensy 2.0 that I have been using. This power is due to it's 32 bit ARM processor. The coolest thing is that it uses the Arduino IDE and nearly all of your sketches will run on it. The Teensy SDR linked above exploits the Teensy 3.1 audio DSP functions and PJRC has created a simple GUI tool to help you create your audio projects easily.

As a simple test after I powered up my Teensy 3.1, I used the audio design tool to define two sine wave sources, mix them together and output them to the on-board DAC. Below is an image of my session with the tool (it is web based or you can download and run locally).



After the design is completed in the tool you just press the RED "Export" button and it will output the code for your sketch. I ended up tailoring mine to generate a Dial Tone and I was blown away how good it sounded! I just took the output of the DAC and feed it directly into a standard PC powered speaker.

You do need to do a little coding since the tool just sets up the streams. The tool generated the code that is between the "// GUItool ..." comments below in the example. I needed to call the audio objects in the "loop()" section which you can figure out from the docs and the examples provided. The comment section at the bottom is when I was playing with other Tel-co sounds (e.g. Busy Signal).

I am very impressed with the Teensy 3.1 platform and intend on replacing my Teensy 2.0 in my Proto Type Radio with it soon and try out some of the audio SDR functions.

Example Code:

 // Simple Mixer to generate a Dialtone  
 #include <Audio.h>  
 #include <Wire.h>  
 #include <SPI.h>  
 #include <SD.h>  
 // GUItool: begin automatically generated code  
 AudioSynthWaveformSine  sine1;     //xy=183,181  
 AudioSynthWaveformSine  sine2;     //xy=192,251  
 AudioMixer4       mixer1;     //xy=392,207  
 AudioOutputAnalog    dac;      //xy=591,178  
 AudioConnection     patchCord1(sine1, 0, mixer1, 0);  
 AudioConnection     patchCord2(sine2, 0, mixer1, 1);  
 AudioConnection     patchCord3(mixer1, dac);  
 // GUItool: end automatically generated code  
 void setup() {  
  // Audio connections require memory to work. For more  
  // detailed information, see the MemoryAndCpuUsage example  
  AudioMemory(3);  
  }  
  void loop() {  
  sine1.frequency(350); //350  
  sine1.amplitude(0.1);  
  sine2.frequency(440);//440  
  sine2.amplitude(0.1);  
  //delay(100);  
  //sine1.amplitude(0);  
  //sine2.amplitude(0);  
  //delay(100);  
  }  

Saturday, March 14, 2015

Prototype Radio V - CAT Control with Omni-Rig

I continue to experiment with the CAT control of the Si5351 with the simple DC receiver. I wanted to document the use of Omni-rig that I mentioned in the last post. After Omni-Rig is installed, HDSDR will be able to access the Omni-Rig setup screen below. You just select the rig type, the COM port the Arduino is on, and the baud rate (e.g. we are using 4800, but it can be changed in the code).
The best way to run it is to Sync the LO frequency and then check the sync to/from Omni-Rig as seen below. The you just click on the frequency and type in the frequency you want and press enter. Then you will see the span of frequencies based on your bandwidth setting. To tune around at this point, change the LO not the TUNE frequency. Your offsite will remain fixed based on the setting below. This works well for me at this point. I am able to use 192K sample rate which gives me more than 80 Khz (this is half of the 192 since this is not a true SDR which would center you and give you 80 below and 80 above)
There is a setting that positions the SDR cursor when you tune it. The default is 10000 hz or 10Khz, but you may want to adjust it to the best part of the pass-band. I find that 40khz is the lowest noise part of my pass-band for my setup. I have also been investigating noise issues that are caused by the PC's USB port. I will need to devise some filtering next. In the mean time I have found that placing an "un-powered" USB power block across the DC buss cuts most of the noise. I just use a USB cable that has the power pins broken out to pins plugged into the breadboard and plugged into the power block.
Here is the offsite screen with the default 10khz setting.

Sunday, March 8, 2015

Prototype Radio IV - CAT Control

I mentioned to my friend Gary N6SER how cool it would be to write some code for the Arduino to control the Si5351 via the standard Computer Aided Transceiver (CAT) control. He used Ham Radio Deluxe HRD as his standard platform for testing and picked the Elecraft K2 to model. Here is the programming guide --> HERE. He got a basic sketch running that controlled frequency and Mode (e.g. CW, LSB, USB, etc). I then took his sketch and incorporated the Si5351 library to control the clock module. The idea is to build the simplest radio system and use the Arduino serial port to control it with already existing software that uses the CAT interface. No display is needed, no knobs, switches, etc. the software provides the front panel. The sketch has now been tested on my Prototype Radio with HRD version 5.xFLRigCommander, and most exciting - OmniRig with HDSDR. The choice of using the K2 was brilliant because it has one of the simplest command structures. There is more work to be done but it does work. One issue is that the Arduino connected to the computer couples a lot of noise sources into the prototype radio's simple direct conversion receiver. I had no problem tuning around with HDSDR and it controlling the local oscillator (LO) of the Si5351. The OmniRig integration with HDSDR worked great. Below is what the code looks like so far. I do have a simple LCD display on it for debugging purposes only.




1:  #include <Wire.h>   
2:  //#include <Encoder.h>  
3:  #include "si5351.h"  
4:  #include <LiquidCrystal_I2C.h> // F Malpartida's NewLiquidCrystal library  
5:  #define I2C_ADDR  0x20 // Define I2C Address where the PCF8574A is  
6:  #define BACKLIGHT_PIN   7  
7:  #define En_pin 4  
8:  #define Rw_pin 5  
9:  #define Rs_pin 6  
10:  #define D4_pin 0  
11:  #define D5_pin 1  
12:  #define D6_pin 2  
13:  #define D7_pin 3  
14:  LiquidCrystal_I2C lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);  
15:  Si5351 clockgen;  
16:  long int freq = 7040000; // In Hz  
17:  long int frequency = freq;  
18:  int mode = 1; //(1=LSB, 2=USB, 3=CW, 6=RTTY, 7=CW-REV, 9=RTTY-REV)  
19:  String received;  
20:  String command;  
21:  String parameter;  
22:  String sent;  
23:  const int ledPin = 11;  
24:  void setup()  
25:  {  
26:   // Setup for Ham Radio Deluxe 5.24.0.38  
27:   // Elecraft K2  
28:   Serial.begin(4800);  
29:   lcd.begin (8,2); // initialize the lcd   
30:   lcd.home();  
31:   lcd.print("CAT-RMT");  
32:   lcd.setCursor(0, 1);  
33:   lcd.print("v1.35");  
34:   delay(4000);  
35:   lcd.clear();  
36:   pinMode(ledPin, OUTPUT);  
37:   clockgen.init(SI5351_CRYSTAL_LOAD_8PF);  
38:   // Set CLK0 to output current value with a fixed PLL frequency  
39:   clockgen.set_pll(SI5351_PLL_FIXED, SI5351_PLLA);  
40:   clockgen.set_freq(frequency, SI5351_PLL_FIXED, SI5351_CLK0);  
41:  }  
42:  void loop()  
43:  {  
44:   if(Serial.available() > 0)  
45:   {  
46:    received = Serial.readStringUntil(';');  
47:    received.toUpperCase();  
48:    received.replace("\n","");  
49:    command = received.substring(0,2);  
50:    parameter = received.substring(2,received.length());  
51:    if (command == "FA")  
52:    {  
53:     if (parameter != "")  
54:     {  
55:      freq = parameter.toInt();  
56:      frequency = freq;  
57:      clockgen.set_freq(frequency, SI5351_PLL_FIXED, SI5351_CLK0);  
58:      lcd.setCursor(0, 0);  
59:      lcd.print(frequency);  
60:      lcd.setCursor(0, 0);  
61:     }  
62:     sent = "FA" // Return 11 digit frequency in Hz.  
63:     + String("00000000000").substring(0,11-(String(freq).length()))   
64:      + String(freq) + ";";  
65:    }  
66:    else if (command == "IF")  
67:    {  
68:     sent = "IF" // Return 11 digit frequency in Hz.  
69:     + String("00000000000").substring(0,11-(String(freq).length()))   
70:      + String(freq) + String("   ") + "+" + "0000" + "0" + "0" + String(" ") + "00" + "0" + String(mode) + "0" + "0" + "0" + "0" + "01" + String(" ") + ";";  
71:    }  
72:    else if (command == "MD")  
73:    {  
74:     if (parameter != "")  
75:     {  
76:      mode = parameter.toInt();  
77:      //PrintToTft(String(mode),9);  
78:      lcd.setCursor(0, 1);  
79:      lcd.print(String(mode));  
80:      lcd.setCursor(0, 1);  
81:     }  
82:     sent = "MD"   
83:      + String(mode) + ";";  
84:    }  
85:    else if (command == "ID")  
86:    {  
87:     sent = "ID"   
88:      + String("017") + ";";  
89:    }  
90:    else if (command == "TX")  
91:    {  
92:     digitalWrite(ledPin, HIGH);   
93:     sent = command  
94:      + String(parameter) + ";";   
95:    }  
96:    else if (command == "RX")  
97:    {  
98:     digitalWrite(ledPin, LOW);   
99:     sent = command  
100:      + String(parameter) + ";";   
101:    }  
102:    else if (command == "SM")  
103:    {  
104:     sent = command  
105:      + String(parameter) + "0010" + ";";   
106:    }  
107:   else  
108:   {  
109:       sent = command  
110:       + String(parameter) + ";";  
111:   }  
112:    Serial.println(sent);  
113:    //PrintToTft(sent,5);  
114:    sent = String("");      
115:   }  
116:  }