Thursday 23 July 2020

2nd CAT - DUO talk

It got very frustrating using the Arduino UNO for the CAT <-> DUO project (below). Mainly due to conflicts between timers and interrupts used by the "SoftwareSerial" library to talk to the DUO USB and interrupts used by the "Rotary" library for the encoder. I wanted to continue to use the Rotary library as I have used it many times and it works well.

 
Rear view of DUO transceiver
Right: CAT USB B interface

So I have switched to an Arduino MEGA, a different beast altogether. The MEGA is longer than the UNO, but has the same basic pinout plus it adds a lot more analog and digital pins, a separate I2C bus and most importantly it has 3 extra serial ports. So the SoftwareSerial library is not needed to talk to the DUO USB.


All that is needed is to start one of the extra serial ports (serial 2, which uses pins 16/TX2 & 17/RX2), is

Serial2.begin(38400);

Which enables the connected USB A host module for a connection to the DUO USB B slave input/output.

Module connected to Serial2 port


BUILD
This is the system

Top, the USB power/programming from my Macbook
on the Left: TR switch
Right: tuning, step and mode
Bottom: display and USB host master to radio CAT USB

Schematic

CODE
Latest code for this CAT_MEGA app is here.

NEXT
I have so far got:

1. Send frequency tuning
2. Send TX/RX command
3. Send mode LSB-USB-CW-FM-AM
4. Change local frequency tuning step (100Hz, 1kHz, 10kHz but could be increased)

I have not managed yet to get data back from the SDR, that is to read values back to the MEGA. Read/Answer does work, but there seems to be timing errors, and to poll the SDR over and over means a huge amount of CAT activity, and maybe either the baud rate (38400 used) is too low or the SDR simply cannot respond quick enough.

However I will try to find out what is going on as one of the targets is to have a "two way" system. So that if you tune or change mode or TX/RX on the radio the MEGA follows along.

          


Monday 13 July 2020

OLED displays for your projects - software

OLED display
For all my projects where I need a display, I use the small 1.3" OLEDs with SH1106 controllers and addressed over a two wire SCL/SDA I2C bus. Like this one from Amazon.

I use the superb display library called U8g2 here. This library is a bit heavy for the Arduino UNO as it uses 10-15Kbytes of memory when complied in a project. But I have never run out of memory in anything I have written...

To use my header Oled.h here and the U8g2 library simply include "Oled.h" in your sketch. This will automatically include the "u8g2lib.h" library itself and the I2C comms library "Wire.h". It will also instantiate an object "oled". So your sketch might simply start like this

#include "Oled.h"

You must begin using the library with a begin call in your setup()

oled.begin();

The basic use of the u8g2 library is to have a "display" function which is called to update the display whenever anything new needs to be displayed. This looks like this in your code

dispUpdate();

the function itself, called the display "loop", is written like this example

void dispUpdate() {                                        // picture loop
  oled.firstPage();
  do {
    dispMsg(30, 0, "VFO HOLD");                            // display title
    dispFreq(15, 23, freq / 100, 0, 2);                    // display frequency
    dispMsgS(58, 52, "Step");                              // disp "Step"
    dispStep(80, 50, freqStep / 100);                      // display step freq
  } while ( oled.nextPage() );
}

All the display functions are put within the "do...while" loop.

DISPLAY FUNCTIONS
I made a pre-defined set of functions in this header which make laying out a display simple with consistent use of fonts. These functions are in my Oled.h header file here. They are:

OLED Header

Includes for 
U8g2lib.h and Wire.h

Instantiation for OLED
U8G2_SH1106_128X64_NONAME_1_HW_I2C oled(U8G2_R0);

Functions & usage
// display bar at x, y, h)eight, l)ength (0-100 pixels)
void dispBar(u8g2_uint_t x, u8g2_uint_t y, byte h, byte l)

// display a horzontal line, start x,y, width w
void dispHline(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w)

// display freq at x, y, of f (Hz) plus cf (cHz), to d)ecimal places (max 3)
void dispFreq(u8g2_uint_t x, u8g2_uint_t y, float f, float cf, byte d)

// display freq small at x, y, of f (Hz) plus cf (cHz), to d)ecimal places (max 3)
void dispFreqS(u8g2_uint_t x, u8g2_uint_t y, float f, float cf, byte d)

// display step at x, y, value s)tep (Hz)
void dispStep(u8g2_uint_t x, u8g2_uint_t y, unsigned int s)

// display small message at at x, y, *m)essage
void dispMsgS(u8g2_uint_t x, u8g2_uint_t y, char *m)

// display message at at x, y, *m)essage
void dispMsg(u8g2_uint_t x, u8g2_uint_t y, char *m)

// display large message at at x, y, *m)essage
void dispMsgL(u8g2_uint_t x, u8g2_uint_t y, char *m)

// display ultra large message at at x, y, *m)essage
void dispMsgUL(u8g2_uint_t x, u8g2_uint_t y, char *m)

// display integer - 32 bit
void dispInt(u8g2_uint_t x, u8g2_uint_t y, uint32_t n)

// display number at x, y, n)umber, d)ecimal places
void dispNum(u8g2_uint_t x, u8g2_uint_t y, float n, byte d)

// display number large at x, y, n)umber, d)ecimal places
void dispNumL(u8g2_uint_t x, u8g2_uint_t y, float n, byte d)

// display number ultra large at x, y, n)umber, d)ecimal places
void dispNumUL(u8g2_uint_t x, u8g2_uint_t y, float n, byte d)

// display date "Mon 21 June 2018"
void dispDate(u8g2_uint_t x, u8g2_uint_t y, byte dw, byte da, byte mo, byte yr)

// display time HH:MM:SS at x), y)
void dispTime(u8g2_uint_t x, u8g2_uint_t y, byte h, byte m, byte s)

// display time large HH:MM:SS at x), y)
void dispTimeL(u8g2_uint_t x, u8g2_uint_t y, byte h, byte m, byte s)

x, y display position (top left, down)
h height, time hour, l length
f Hz 
cf      cHz
d decimal place
*m message
n number
dw day of the week
da day
mo month
yr year
m minute
s second, or step, or screen array pointer

Calling these allows me to quickly format and position the major items I need. Messages are easy, as are numbers. But this also give special formatting for Frequency, Dates and Times. Several sizes can be chosen.

Here's a couple of examples, for a VSWR meter and an Audio level meter.



Should you want to it is easy to add your own functions to the Oled.h header. Use a plain text editor and follow the layout of the existing ones already there. You can use any of the functions in the U8g2 library here.

An example of this being used can be found in this sketch here which displays GPS data.

This library and header will work also with the smaller 0.96" OLEDs
 

Tuesday 7 July 2020

Talking CAT to my FDM-DUO

I am tinkering with a VERY simple CAT controller for my FDM-DUO. Sending CAT signals to switch Transmit & Receive, sideband selection and for frequency tuning. Of course it may grow into something much more complicated...

CAT commands are sent as ASCII text to the "CAT" USB connection on the FDM-DUO. All commands are terminated with a ";". An Arduino UNO is used, connected via an FTDI serial <-> USB converter.



The CAT commands I need are:

"FA00007100000;" // tune to 7.1MHz 11 characters, "0" padded and frequency in Hz
"TXn;" // transmit where n = 0 is MIC input and n = 1 is USB audio input
"RX;" // receive
"MD1;" and "MD2;" for sideband selection

FREQUENCY
The programming challenge is to store the frequency as a "long" and convert it to ASCII, and pad the string with the right number of '0's before sending it out to the FDM-DUO over a USB link at the default baud rate of 38400.

This is the routine for sending a CAT frequency "FA" command ("cat" is the name of the SoftwareSerial port):

void sendFA(long n) {
  int i;

  String out = String(n, DEC);

  cat.print("FA"); // freq CAT command
  for (i = 0; i < (11 - out.length()); i++) { // add padding
    cat.print("0");
  }
  cat.print(out);
  cat.print(";"); // terminator
}
long 'n' is the required frequency in Hz, which is first converted, as a decimal, to a String "out". Then the command "FA" is printed to the Software Serial Port named "cat" connected to the FDM-DUO. It is prepended with the right number of "0"s to make it up to 11 characters total which are printed followed by the frequency in Hz. Lastly the terminator ";" is sent.

TX/RX
Another simple function prints the CAT strings "TX1;" and "RX;" for transmit (from the USB audio input (change to "TX0;" for MIC input) and for receive:
void sendTRX(bool t) {
  if (t == LOW) cat.print("TX1"); // LOW transmit,  0 = MIC, 1 = USB audio
  else cat.print("RX");
  cat.print(";"); // terminator
}
USB/LSB
This is similar and quite simple (only LSB, USB and CW are implemented)
void sendMODE(int m) {
   switch(m) {
    case 1: cat.print("MD1"); // LSB
    break;
    case 2: cat.print("MD2");
    break;
    case 3: cat.print("MD3");
    break;
   }
  cat.print(";");
}
TESTING
Next step is to wire in a switch for TX/RX and a rotary encoder for frequency tuning, with the option to change the frequency step. Here we go...

Arduino UNO wired up
The UNO has only one +5V line so digital outputs 
(set to HIGH or LOW)
are used to connect VCC & GND to the Switch, Encoder and FDTI

The frequency that can be tuned is currently limited in the code to 7.0 to 7.2MHz, it can be tuned in 10kHz, 1kHz or 100Hz steps. LSB or USB is changed by a long press on the encoder button whereas a short press changes the frequency step.

This is the output on a terminal program on my MacBook:


Bit small, sorry
The output is on the screen is

MD1; // sideband switch by long press
MD2;
FA0000710000; // 7.1MHz tune and +100, +200 Hz
TX1; // transmit using USB audio input
RX; // receive

USB PROBLEMS
USB has beaten me. USB is a serial bus structured as a Master and Slaves. And when I tried to connect my Arduino FTDI USB module to the FDM_DUO USB B CAT it did not work. I connected the FTDI to my MacBook and all was well, as you can see above. I also connected my MacBook to the FDM-DUO CAT USB, and all worked well. So what is going on?

Simple, the FTDI and FDM-DUO are Slaves and my MacBook is a Master.

The Arduino uses an FTDI interface, which acts as a Slave, and the FDM-DUO uses an FD232RL chip, the same as the Arduino interface, so it is also a Slave. Two slaves. So they do not talk to each other. What I need is an interface on the Arduino which acts as a "Host" or Master. And this is a rats nest with lots of products on the Web costing from £5 to £45. Most without any Manuals. And there are libraries too, with difficult to understand functions... it's a mess.

SOLUTION?
 A lot of interest has been generated on the ELAD Group.io forum about USB & CAT. It seems that what is needed is a dedicated USB HOST module, like this one, from Hobbytronics. I have ordered one to try.



The fog is clearing now about USB HOST & SLAVE. To summarise, you need a HOST, normally with a USB A socket, to connect to a SLAVE, normally a USB B socket - like a printer connection. And you need the host to support the Serial FTDI Protocol (there are others for keyboards, mouse, etc). What a struggle it has been just to get that clear.

And now here is my system


At the top you just see the TX/RX toggle switch, under this is the tuning/step encoder , also used for USB/LSB selection. At the bottom is the display of RX/TX, USB/LSB. Frequency and step


Here's a couple of shots of the FDM-DUO screen in TX & RX, and USB & LSB modes.



Obviously it is fairly simple to write other functions to read more inputs and send the ASCII codes to the FDM-DUO.

INPUT/OUTPUT
There are two physical ways to converse with the FDM-DUO CAT. Either the USB B connection or a EXTIO 9 pin connector. This connector has a couple of TX/RX serial data pins. But only the data-in pin can control CAT. If sent a request to send a reply (like "FA;" to get the VFO A frequency), then no data is returned on the 9 pin connector out pin. So the 9 pin can only be one way, into the DUO.  The USB B port on the other hand can be asked to also send out data, for example sending "FA;" will generate an output of "FA00007100000;" or VFO A tuned to 7.1MHz.

The first thing to do is to have a couple of functions to read the data from the DUO. Only two of my three planned functionalities can be read - for some reason the DUO is not able to output it's T/R state! Unless I am missing something...

So for reading the mode (USB, LSB, CW etc) I have this function, read from pos)ition in text string (normally character 2)

text character    0 1 2 3
content           M D 1 ;

read from character position '2', up to finding the terminator ';' Result '1'

int readMODE(int pos) {
  char in[20];
  char out[20];
  int c;

  cat.print("MD;"); // send request for mode
  getCAT(in); // get in response
  c = 0;
  while (in[c] != ';') {
    out[c] = in[c + pos];
    c++;
  }
  out[c] = '\0';
  return atoi(out);
}

Here the issue is that the DUO response to a request for mode information is are ASCII text, and the numerical data must be extracted. All CAT commends start with two letters, followed by 1 to 11 numbers. So "MD;" is sent, to which the DUO responds "MD1,2,3,4,5 or 7 for the modes LSB, USB, CW, FM. AM and CWR. I strip out the two first letters and then convert the remaining number to an integer.

And for the frequency the function is

text character    0 1 2 3 4 5 6 7 8 9 0 1
content           F A 0 0 0 0 7 1 0 0 0 0

read from character position '2', up to finding the terminator ';' Result '1'

long readFA(int pos) {
  char in[20];
  char out[20];
  int c;

  cat.print("FA;"); // send request for FA
  getCAT(in); // get in response
  c = 0;
  while (in[c] != ';') { // skip pos char
    out[c] = in[c + pos];
    c++;
  }
  out[c] = '\0';
  return atol(out);
}

The function getCAT(in) reads a line of text from the DUO.

These functions work vert well and now they must be combined with thesend funciton above to have both the Arduino and the DUO locally to control the parameters, and for either to report the status on the Arduino OLED display.


Sunday 5 July 2020

Measuring SSB TX filters

I have just finished building all the blocks of my test lab (so far...). These are:

1. A Direct Conversion RX, DCRX, for the 40m band, with VFO input from an RF SIGGEN
2. An RF SIGGEN. Based on the Si5351 and covering 1-150MHz (my limits, the Si5351 can do more).
3. An AF SIGGEN. Based on the AD9833 and covering 0-100kHz (my limits, the AD9833 cam do more.
4. An RF METER which uses a -30dB TAP to allow power measurements. The TAP includes a 50R dummy load
5. A 12V/1.5A power supply to power the above
6. And finally, not yet boxed, an AF METER measuring in dBv and Vrms.

Also on top of the FDM-DUO transceiver is my MAT-125e auto ATU.


PROJECT
I use these along with my MacBook & software to measure the TX filter response of my ELAD FDM-DUO transceiver. This is the setup

Block diagram of the setup

The FDM-DUO transceiver has an RF output up to 5W over all bands. It has a USB audio input "TX" for digital transmissions. And a "CAT" serial data port which is an input and an output and is used with apps like WSJT for FT8 mode.
Connections on the FDM_DUO

The RF output is fed to the 30dB TAP attenuator, with a built-in 50R dummy load, and on to the RF METER which has an Arduino sketch written to display the power before the attenuator. This meter can display RF from -50 to +30dBm.

The USB CAT and TX audio inputs come from my MacBook. Where I use two applications, first a serial terminal app "iSerial" to connect to the FDM-DUO CAT port. This allows me to send PTT transmit and receive commands, "TX1;" ( 1 = USB Audio selected) and "RX;". The second app is Audio Hijack which is a wonderful app allowing you to make any audio connections inside the MacBook just by dragging the items to the screen. I have a USB audio ADC plugged into the USB input which is connected through to the FDM-DUO TX audio port:

The Hijack audio and iSerial terminal apps

The input to the USB ADC is from my AF SIGGEN I built a while ago (look down this blog for details, schematics and software). This SIGGEN covers 1-100kHz, but I need only 50-3000Hz for filter measurements.

To receive the FDM-DUO RF signals I am using a direct conversion receiver that I designed for the Banbury Amateur Radio Society "LEARN-CODE-BUILD" project that I ran a couple of years ago. It is a 40m DCRX with external VFO input from a matching RF SIGGEN. It was targeted for FT8 reception and performed excellently, allowing club members to become familiar with this digital mode using the WSJT app that few had tried at the time. The audio output of the DCRX goes finally to my new AF METER.

FILTER
To measure the filter response, set to the option of 200-2700Hz, the FDM-DUO is switched into transmit by sending a CAT command "TX1;" from the iSerial app. The AF SIGGEN output is adjusted to give 1-2W output power. The frequency is scanned in 50Hz steps over the low and high filter cut off limits and the AF signal from the DCRX is measured. This is the result


The cutoff frequencies of the FDM-DUO filter set to 200-2700Hz

As you can see the upper cut off is very sharp, which is good to avoid spill over to adjacent stations. The low cut off is a little smoother which gives fuller voice characteristic.

SDR WATERFALLS
It is very noticeable when using an SDR waterfall on your receiver, that you can see the spectrum of the other station. These vary a lot, showing both the Bandwidth and signal from full and solid across the frequency range to very narrow and bassy difficult to read signals or tinny thin signals.. It is also very clear when the station is using audio compression. We should I think give signal reports other than simple "5 & 9" by describing the waterfall specturm  that is seen.