03/02/2017

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


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 fromt 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 epect.
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.

[ Note : In the code below, you will notice that I'm using address $76, I had to change this because the 7300 is not yet supported in WSPR, JT65HF etc ... The addres $76 makes these programs think the rig is an IC-7200, and all works fine. Now figure out for yourself how to change the CI-V address in your 7300 ... hi ]

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 bute 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 $E0 $94 $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 $E0 $94 $14 $0A $00 $28 $FD:          put the TX power at 10 W
$FE $FE $E0 $94 $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/10 = 26. In a test, I found out that 28 is nearer to 10W.
This feature saves the endless rotations with the multi-switch, it will certainly 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
  • one more resistor if you want to read the reply from the rig (not used in this project)
  • a 3.5 mm jack with a shielded cable end



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 as 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

// 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 6 via resistor 4k7 (not used here)
// TX = Arduino to IC7300  : direct to pin 7, with pull up 10k to Vcc (5V)
SoftwareSerial mySerial(6, 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(0x76); // radio address, changed from normal 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(0x76); // radio address, changed from normal 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

// 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 6 via resistor 4k7 (not used now)
// TX = Arduino to IC7300  : direct to pin 7, with pull up 10k to Vcc (5V)
SoftwareSerial mySerial(6, 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(0x76); // radio address, changed from normal 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(0x76);
    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(0x76);
    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(0x76);
    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).
BUT there are NO commands to do actually send the messages.
There is a circuit in the manual to do this, but this uses the microphone jack, so you'll need another box and more connectors ...
Solution: integrate the two projects into one container. I'll make another post if I ever get that far !
So much for now ... have a lot of Arduino and ... CW fun !

Luc - ON7DQ/KF0CR

2 comments:

  1. I too have the same problem when I wish to change from paddle to key or vice versa. I like to interchange "on the fly" and find the pushing of all those menu buttons too tedious. I will have to have a think about your proposal
    Ian ZL2AIM

    ReplyDelete
    Replies
    1. Don't think too long Ian, since I made this, I use it very often, and I couldn't miss it! I use a manual tuner for wire antennas (that the internal tuner won't tune), so I use the 10W/100W switching also very frequently for tuning up.
      And it's really very simple. I power the circuit from an old cellphone charger (5V/1A). Good luck es 73 - Luc

      Delete