10/02/2017

My KX3 Digimode Interface


This is a short description of what I built for using digimodes on my Elecraft KX3.
It's not a final building project, there is no PCB ... you're invited to experiment yourself with what works for you, but I may give you some ideas to get you started.

My main purpose was to use this for SOTA activations in digimodes (mainly PSK31 and RTTY).
Of course you can operate PSK on the KX3 by reading received text on the 8 character decoder in the VFO B area, and sending back your reply with the CW paddle.
I did try that on one activation, but I can assure you, it is not the most flexible way of operating, so there had to be a better way. 

It all started with reading on the SOTA reflector about a cheap Linx 7" tablet running a full Windows 8 install, and it seemed to have a 4-pin audio connector, so audio IN and OUT.
Those were two things my good old Nexus 7 (2012 edition) lacked : running Windows programs like  FLDIGI, and audio input.
So I got me one of those tablets for 99€ in a local electronics supermarket, where it was sold under the brand name Lamina.
In the meantime you can get them much cheaper, and probably with better specs (more memory, faster CPU etc), but it seems they only have an 8" and a 10" version on the market now.
See http://linxtablets.com/

Now I needed an interface !

I based my interface loosely on this circuit :


Since the KX3 can use VOX in the DATA A mode , I didn't need a PTT circuit, just two transformers, some resistors and capacitors and that should be it.
I finally ended up with this much simpler circuit :


The transformers are 1:1 , the type you find in old computer modem boards.
Right angle 4-pin connectors were difficult to find locally, so I just ordered some ready made shielded cables from Ebay, and cut those in two. The straight connector is used at the tablet, the right angle one is for the MIC input on the KX3. Also the Phone connector has a right angle connector, but with only 3 pins.

The connection convention for most tablets and phones is this :
(Google TRRS for more info)

TIP            : LEFT audio out
RING 1     : RIGHT audio out
RING 2     : GND (of course, GND is connected to the real shield of the cable)
SLEEVE   : MIC input

One thing I have been struggling with was the fact that the tablet wouldn't recognize something being connected to the MIC input, and would keep using the built in microphone.
So it is essential that you put a resistor on the MIC connection to the tablet !
I used 10k, another value may work for your phone/tablet ... experiment !
Other resistors are "selected in test" ... just pick whatever you need to obtain acceptable levels in & out. Remember that the KX3 has no separate DATA connector, so we're using the MIC and PHONE connectors, and the levels will depend on your MIC gain and volume settings.

Then I found a nice little case for my project, funny enough ... it is from an old phone modem for a laptop ! Size is only 7.5 x 3 x 2 cm.



The output of my interface is a female 5-pin DIN connector because I also have cables from this DIN connector to other rigs. This way I can also use the interface e.g. on a Kenwood THF7E, which also has built-in VOX. The 5-pin DIN is wired according to the "BayCom" standard (but I don't use the PTT line) :


The cable for the KX3 has a male DIN connector on one end, the other end is split in 2, one cable for the Phone output, and one cable for the Mic input on the KX3. Here the complete assembly, interface + KX3 cable :


Operating the tablet with FLDIGI is not so easy, it takes some practice if you have only the touch screen. I did my first test with a small wireless keyboard and touchpad, and it worked !


Later, I found out that you can enlarge the Macro-buttons in FLDIGI, by going to Configure > User Interface , and then on the tab Macros you will find Button Height. Put that on maximum (66) and the macros are much easier to use.

Have fun making this project, and hope to work you from one of the summits in PSK, RTTY or who knows even in SSTV ?
73 - Luc, ON7DQ

03/02/2017

IC-7300 Paddle or Key ? Easy solution with Arduino !




Instant switching between key and paddle, and setting two power levels without even touching my rig !

[EDIT: I rebuilt this project in 2023, and expanded it to use all 8 buttons in the Nintendo controller, more info and code are here]

What's your problem ?

Since a couple of months I am the proud owner of an Icom IC-7300.
It's a wonderful rig, designed as a direct sampling SDR transceiver, with all sorts of bells and whistles, a user friendly touch screen and so much more ... for a very low price.

But that is not why I am writing this post.
The most important thing that annoyed me from the start is that the Icom designers clearly hadn't thought about the versatile CW operator.

When you are like me, and switch from paddle to straight key fairly often, you will be disappointed with this rig. On their more expensive rigs, Icom have put a straight key input on the back , and another one on the front for a paddle (labeled ELEKEY). The IC-7300 is of course a lower cost rig, but the Kenwood TS-590SG is about the same price, and it does have two keying inputs !

Now, what exactly is the problem ? You can wire a key and a paddle in parallel to the KEY input on the back, right ? Problem solved ?

NOT SO !
You still have to punch in 8 (yes EIGHT) keys on the rig (or on the touch screen), each time you want to change from paddle to key or vice versa. (For those who do not even know how to do this ... press MENU> KEYER> EDIT/SET> CW KEY SET> TYPE KEY> Select KEY or PADDLE> EXIT> HOLD M.SCOPE ... that's all, hi).
And as you can see, it's also very confusing that you have to go via the memory keyer screen, and not via the normal MENU > SETTINGS > ... as you might expect.
Also ... no programmable PF keys on this rig ...

Now, being a great Arduino fan, I thought there had to be an easy solution ...

Most Icom HF transceivers and some receivers can be controlled via the so-called CI-V bus.
The IC-7300 even has two such CI-V busses, one is incorporated into the USB connection to the PC, and there is also a "classic" CI-V connector  (3.5mm).
I have used the latter for my project , leaving the USB connection for CAT control (log program, digimode program, etc ... and for the built in soundcard of course).


CI-V bus

To understand how our Arduino project works, first a brief introduction to the CI-V bus.
I got a lot of information from Jean-Jacques, ON7EQ (see: http://www.qsl.net/on7eq/en/ , then >Projects> Arduino), and also from the "Bible of CI-V" written by Ekki, DF4OR
(see http://www.plicht.de/ekki/civ/index.html).

CI-V stands for Computer Interface 5, and is already in use with Icom transceivers since the eighties.
It is a single wire bus at TTL level, the jack is a 3.5 mm stereo plug of which only the TIP and the SHIELD are used. For control from an RS-232 port (PC) an interface is needed (eg. using a MAX232), but this is not necessary with the Arduino, since we are working at TTL level.

In the idle state, the bus is high, or "floating" (+ 5V). If the computer wants to send something, the bus is pulled low by the computer, if the transceiver sends something, it will pull the bus low.
The format of the data is NRZ (Non Return to Zero).

NRZ Format (source: Icom CI-V Manual)







Now, what do we need for this project ?
We want only to send some bytes from the "controller" (the Arduino) to the rig, and not listen to what comes back. Each message to the transceiver is composed of a fixed number of bytes, and some command bytes with or without extra data bytes (a frequency, a text, a status).

 A message always starts with twice $FE ($ or 0x is the prefix for a hexadecimal number).
Then follows the address of the transceiver, for an IC-7300 is this example $94.

After that comes the controller address, which is always $E0 (and it is never actually used in the transceiver). Now it is time for the command, if needed a sub-command, and finally the data bytes.
To conclude the message, the last byte sent is  $FD, and then the transceiver is ready to receive the next message.

There is still a small problem with the data bytes, these should not be sent in hex, because there is a chance that the data would contain a byte like $FE or $FD (the start and stop codes). Therefore, all data must be sent in BCD format. A number like 123 is then converted into $01 $23. Not difficult, but you have to think about it.

A few examples may make all this complicated stuff a little easier to understand :

Set Mode:
$FE $FE $94 $E0 $06 $00 $FD   =   put the transceiver in LSB MODE
$06 is the mode set command, $00 = LSB, $ 01 = USB etc ... you can find all the modes in the full manual of your transceiver or on the site of DF4OS.

Set USB AF / IF:
$FE $FE $94 $E0 $1A $05 $00 $59 $00 $FD:  put the USB port output (signal going to the PC) in AF mode, with $01 you set the IF mode. This again saves five keystrokes on the transceiver!

[Note : if you haven't used this feature of your 7300, it's great fun !
With the USB port in IF mode, you send 24 kHz of received signal to the PC, which can use it in any SDR program. One thing I use it for, is listening to DRM (Digital Radio Mondiale) with the DReaM software, and without using any additional hardware (converters etc)

Set Power:
$FE $FE $94 $E0 $14 $0A $00 $28 $FD:          put the TX power at 10 W
$FE $FE $94 $E0 $14 $0A $02 $55 $FD:          put the TX power at 100 W
The power is actually expressed as a percentage. The data ranges from 0 to 255, for 10 Watts you would have to send 10%, or about 255 x 0.10 = 26. In a test, I found out that 28 is nearer to 10W.
For 5W, 7% is about right, so send 255 x 0.07 = 18.

This feature saves the endless rotations with the multi-switch, it will certainly prolong it's life ...
I have included this in my project (in the extended code) ... and it uses no extra buttons! (see code).
With a long press on the KEY or PADDLE button, the power is set to 10 or 100 watts respectively.

If you have the courage to read the full manual (it's on the CD supplied with the rig), you will find more interesting commands in chapter 19.

TIP: if you want to test if a command does what you want it to do, DF4OS has written a nice Windows application: the CI-V Tester.
You can download it here: http://www.plicht.de/ekki/software/civtest.html.

The Arduino Hardware

The circuit can not be more simple:

  • an Arduino UNO, or one of the smaller variants (Nano, or Pro Mini), one diode, a resistor and two push buttons
  • a 3.5 mm jack with a shielded cable end


NOTE : Vcc means the 5V pin on an arduino board, and if you power the Arduino via the USB input, you still need to connect the 10k resistor to the 5V pin on the Arduino.

Add one more resistor if you want to read back the reply from the rig (not used in this project), put 4k7 from the TIP of the 3.5 mm connector to an interrupt capable pin (D2 or D3).

*****

Put it in a box !

Now being a very simple project,I still wanted it to be in a nice enclosure.
In my junk box I found this old Nintendo controller with two red buttons ... perfect!
Inside was a printed circuit board with an 8-bit shift register (for the 8 buttons). I removed the chip and so I had nice solder pads for every button in the box.



I'm using only the two red buttons for now, but I can easily expand the project to use the other buttons, just adding the wires and some lines of code ... that's it !
Due to the limited space in the box, I used an Arduino Pro Mini without pins, it fit just below the original PCB. The necessary wires were soldered directly to the Arduino. Some adhesive tape ensures that no short circuits occur.

Here a picture of the finished product:



Anyone building this project and put it in a nice case ? Send me a pic and I will gladly put it on this page ! (my address is on QRZ.com)

Here a detail of the assembly inside, with the two "carbon" switches





Arduino Software

If you ever programmed an Arduino , you know that an Arduino program is called a sketch.
A sketch is written in a special dialect of the C language, with the use of libraries in C++.
A sketch always consists of three parts: first the declarations, then a setup() function and finally a "loop()" function. The latter continues to run forever ... until you disconnect power.

Both the setup and the loop can call additional functions, for example in this project. the function blink() ,  which makes the built-in LED flash briefly for each press of a button.
(Not very useful in my case, since I can't see that LED, hi, but I could wire an extra LED and mount it in the top of the box)

All in all, the code is very straightforward, this is really a beginners project.
Everything should be clear from the added comments (after the // characters).

I made two versions of the sketch, a very simple one for those that only want the paddle/key switch. Then a longer one for detecting short/long press and do the power switching.

VERSION 1.0 only KEY < > PADDLE setting

// IC7300 Paddle <-> Straight Key switch
// by Luc Decroos - ON7DQ/KF0CR
// 20170105

#include <SoftwareSerial.h>  // for comms to IC7300

// IC7300 Serial comms
#define BAUD_RATE 9600       // CI-V speed

// serial connection
// RX = IC7300 to Arduino  : to pin 2 via resistor 4k7 (not used here)
//                           must be an interrupt pin
// TX = Arduino to IC7300  : direct to pin 7, with pull up 10k to Vcc (5V)
SoftwareSerial mySerial(2, 7); // (RX, TX)

int keyPin = 8;        // key button to GND
int paddlePin = 9;     // paddle button to GND
int ledPin    = 13;     // internal LED

boolean paddle = true; // start in paddle mode

void setup()
{
  // connect to IC7300
  mySerial.begin(BAUD_RATE);

  pinMode(keyPin, INPUT);
  digitalWrite(keyPin, HIGH); // turn on internal pull-up on the inputPin

  pinMode(paddlePin, INPUT);
  digitalWrite(paddlePin, HIGH); // turn on internal pull-up on the inputPin

  pinMode(ledPin, OUTPUT);
}

void loop()
{
  if ( digitalRead (keyPin) == LOW)  {
    // set rig to straight key input
    blink();
    paddle = false;
    mySerial.flush();
    mySerial.write(0xFE);  mySerial.write(0xFE);
    mySerial.write(0x94); // radio address
    mySerial.write(0xE0);  mySerial.write(0x1A); mySerial.write(0x05);
    mySerial.write(0x01);  mySerial.write(0x64); mySerial.write((byte)00);
    mySerial.write(0xFD);

  }

  if ( digitalRead (paddlePin) == LOW)  { 
    blink(); 
    // set rig to paddle input
    paddle = true;

    mySerial.flush();
    mySerial.write(0xFE);  mySerial.write(0xFE);
    mySerial.write(0x94); // radio address
    mySerial.write(0xE0);  mySerial.write(0x1A);  mySerial.write(0x05);
    mySerial.write(0x01);  mySerial.write(0x64);  mySerial.write(0x02);
    mySerial.write(0xFD);
  }
  
  digitalWrite(ledPin, paddle); // LED ON = paddle; OFF = key
  delay(100);
}

void blink() {
  digitalWrite(ledPin, HIGH);
  delay(250);
  digitalWrite(ledPin, LOW);
  delay(250);
  digitalWrite(ledPin, HIGH);
  delay(250);
  digitalWrite(ledPin, LOW);
  delay(250);
}

VERSION 2.0 with POWER setting

// IC7300 Paddle <-> Straight Key switch
// by Luc - ON7DQ/KF0CR
// 20170105 started project with only 2 functions
// 20170201 extra code for  : hold buttons sets PWR to 10W or 100W  

#include <SoftwareSerial.h>  // for comms to IC7300
#define BAUD_RATE 9600       // CI-V speed

// serial connection
// RX = IC7300 to Arduino  : to pin 2 via resistor 4k7 (not used now)
//                           must be an interrupt pin
// TX = Arduino to IC7300  : direct to pin 7, with pull up 10k to Vcc (5V)
SoftwareSerial mySerial(2, 7); // (RX, TX)

int keyPin     = 8;     // key button to GND
int paddlePin  = 9;     // paddle button to GND
int ledPin     = 13;    // internal LED
int count = 0;          // counter for press time
int longTime = 500;     // limit for short/long press
boolean paddle = true;  // start in paddle mode

void setup()
{
  // connect to IC7300
  mySerial.begin(BAUD_RATE);
  //mySerial.write(0x00); //send any initialization command if needed, not used yet

  pinMode(keyPin, INPUT);
  digitalWrite(keyPin, HIGH); // turn on internal pull-up on the inputPin
                             
  pinMode(paddlePin, INPUT);
  digitalWrite(paddlePin, HIGH); // turn on internal pull-up on the inputPin

  pinMode(ledPin, OUTPUT);
}

void loop()
{
  count = 0;
  while (digitalRead(keyPin) == LOW) {
    count++; delay(1);
  }
  if (count > 50 && count < longTime) {
    // set rig to straight key input
    blink(); 
    paddle = false;
    mySerial.flush();
    mySerial.write(0xFE); mySerial.write(0xFE); // start
    mySerial.write(0x94);                       // radio address
    mySerial.write(0xE0); 
    mySerial.write(0x1A); mySerial.write(0x05); // command    1A 05
    mySerial.write(0x01); mySerial.write(0x64); // subcommand 164 in BCD
    mySerial.write((byte)00);                   // data   
    mySerial.write(0xFD);                       // stop
  }
  if (count > longTime) {
    // set PWR to 10W
    blink(); 
    mySerial.flush();
    mySerial.write(0xFE); mySerial.write(0xFE); mySerial.write(0x94);
    mySerial.write(0xE0); mySerial.write(0x14); mySerial.write(0x0A); 
    mySerial.write((byte)00); mySerial.write(0x28); mySerial.write(0xFD);
  }

  count = 0;
  while (digitalRead(paddlePin) == LOW) {
    count++; delay(1);
  }
  if (count > 50 && count < longTime) {
    // set rig to paddle input
    paddle = true;
    mySerial.flush();
    mySerial.write(0xFE); mySerial.write(0xFE); mySerial.write(0x94);
    mySerial.write(0xE0); mySerial.write(0x1A); mySerial.write(0x05);
    mySerial.write(0x01); mySerial.write(0x64); mySerial.write(0x02);
    mySerial.write(0xFD);
  }
  if (count > longTime) {
    // set PWR to 100W
    mySerial.flush();
    mySerial.write(0xFE); mySerial.write(0xFE); mySerial.write(0x94);
    mySerial.write(0xE0); mySerial.write(0x14); mySerial.write(0x0A);
    mySerial.write(0x02); mySerial.write(0x55); mySerial.write(0xFD);
  }
  delay(100);
}

void blink() {
  digitalWrite(ledPin, HIGH); delay(250);
  digitalWrite(ledPin, LOW);  delay(250);

}


In the code you may see a strange command :  mySerial.write ((byte)00);
This differs from the other write commands, because you can not write a NULL character.
If you would put write (00) , you would get an error message.

Conclusion

Of course you can extend the hardware and software with the other commands that we discussed, it's just a matter of some extra wires, buttons and some lines of code.

The first extension that I made (setting 10W/100W) can already be seen in version 2 of the code.
I use this for quickly tuning a manual tuner or a magnetic loop, while the IC-7300 autotuner is bypassed.

Another idea I had was making this project fully "auto-sense".
If you briefly touch the paddle, the transceiver would switch to paddle input, ditto for the key.
I tried this, but there is obviously a problem. The contacts for the DITS and the STRAIGHT KEY are wired in parallel. From the first DIT that you send, the Arduino will see this for a "straight key press" and will switch back to key input mode.
Now this can be solved by connecting paddle and key through your Arduino box, and switching them with a relay, so that the Arduino only "looks" to the contact which is not "in use" (the other device is then connected to the rig).
This was soon to be a complicated thing, and I left the idea for what it was ... just an idea , hi.

Some other idea I had was interesting enough ... how about four more buttons to send the first four memories in the memory keyer ?
Well ... I didn't find any command to do this !
Apparently there are CI-V commands to program the text into the memories (I guess those are meant to be used from a contest program on the PC).

EDIT : N1MM found out that the IC-7610 had those commands, and that they also  worked on the  7300 as well , they just were not documented in the 7300 extended manual.
The command struture is as follows (from the N1MM+ help file) :
28 00 00~08 Voice TX Memory (00=Stop, 01=T1 to 08=T8)
BUT another BIG DISAPPOINTMENT : this works only for the vOICE keyer mesaages, not for the CW messages ... what a bummer!

UPDATE on this EDIT :  the commands are now also documented in the 7300 Extended manual , version 8.

In the manual there is of course a circuit to make a 4-button "keyer"box, but the software solution can send all 8 memories.

So much for now ... have a lot of Arduino and ... CW fun !

Luc - ON7DQ/KF0CR