Pages: [1]   Go Down

Author Topic: Arduino Talking To CI-V With No External Hardware  (Read 236 times)

NQ4T

  • Member
  • Posts: 142
    • HomeURL
Arduino Talking To CI-V With No External Hardware
« on: September 11, 2021, 12:07:27 PM »

I'm going to start with some backstory:

A couple of weeks ago I picked-up a project I had started on last year. The project was to create a remote head, powered by Arduino, that communicated with your radio via it's CI-V/CAT/whatever port. Originally I was inspired by the desire to mobile-install my ol' trusty IC-725; it lacks any provision for a remote head which would have been very handy in my car. I started developing this on a RaspberryPi, figuring I'd have to leverage the power of linux and hamlib to hack something together because, at least at the time, "I didn't know how to code." It was after learning enough Python to hack things together I came across one glaring problem; I didn't like working with hamlib. It was doing things in a manner that I really didn't want it to...and I wasn't about to try and modify the library for my purpose. I had a hard enough time trying to figure out how to enable 731MODE in the thing. I wanted near instant behavior out of the thing...hamlib just seemed to be slowing everything down. I instead began learning the CI-V protocol from a bitstream stand point, how to make the RPi's serial port blast out data, and quickly just started controlling the radio the way I wanted it. My 725 went from doing 2 frequency updates per second with hamlib to doing at least 13 with my method. My junkbox only contained a 4-digit LED display...so my prototype essentially made my 725 behavior mimic the tuning of a CB.

I later decided to switch this over to Arduino for a couple of reasons. The primary one is I felt if the project would be any sort of "success", it shouldn't take 25 seconds to get ready waiting for an OS boot. I also determined I didn't need a full SoC. I didn't need a full linux operating system, I wasn't using hamlib, and I realized the stuff I needed to do was pretty simple and in-line with what a microcontroller is capable of. I laid some groundwork last year, put the project on the back burner, and picked it up a couple weeks ago. The most functional prototype reads the VFOs from the radio, displays the set VFO on it's LED display, tunes the VFO if you move the knob, and switches between A/B if you push the knob. Far from anything close to my final idea...but I like to test things in smaller/simpler arrangements. Full details can be found at the HamHead repository (https://gitlab.com/dewdude/hamhead); which I try to update at the end of every weekend (I'm keeping this a "weekend project" and not touching it during the week.) I'm also behind on updating the repository with schematics and pictures; I'll get to that after I get beyond the phase of just testing things. I will share a picture of the test hardware before I get in to the main topic and some videos of the thing in action are linked in the repository.



When working with an older iCom non-USB radio, contol over CI-V (or CAT as some people want to call it) requires a level converter. That is unless of course you're me and you develop a method of doing CI-V without one. This is something that developing with an Arduino let's us do. We can make the Arduino speak CI-V "directly". No level conversion, no need for hardware UART, and a method that will probably make some people's heads explode.

CI-V is just serial data; the same way that most other rig's CATs are serial data. It's a stream of bits sent serially. That's probably too basic and condesending of a definition; but at the core, that's what it is. The difference with CI-V lies in the physical electrical interface as well as the data you send. Most rigs will accept a full-duplex RS-232(like) connection and probably use ASCII characters (at least Kenwood does) for commands. Typically the rigs with an RS-232 port are "fully compliant" RS-232 ports in that they use the RS-232 signaling voltages that can be as high as 15V and as "low" as -15V. However with CI-V, you're not working with RS-232 level signals; this is TTL. So you typically need some kind of level conversion to go between TTL and RS-232 levels. But that's not all that's involved with iCom. CI-V is also a one-wire bus; an open-collector single-wire bus. So the other job of a CI-V level converter is adapt your full-duplex two-wire communiction in to something compabitle with it's bus. This can often be as simple as just a couple of transistors; one with it's base connected to the CI-V data port that triggers RXd on the UART, the other has it's collector connected to the bus and it's base connected to the TXD port. When the bus is pulled low by something transmitting data; this causes the PNP transistor to change the state of the RXD line which is seen as data by the UART. When the UART transmits data, it's TXD line causes the other PNP transistor to pull the bus line low; which similar circuitry allows those devices to see the data you transmitted. Sure, what you transmit probably gets echo'd back to your device since all the RXD transistor does is look for changes on the CI-V line; and this is before the device itself echos your CI-V frame back to you.



Up to this point I've been doing all development on HamHead using a 7404 based level converter. This was not actually for physical level conversion; Arduino and CI-V are both standard 5V TTL level. I was primarily using it to go from the full-duplex hardware UART on the Arduino to CI-V's half-duplex OC bus. I used it both because it was a non-conventional circuit, but it originally did some conversion between TTL level 3.3V UART for a Raspberry Pi; my notes don't show how that could happen, but I suppose if you threw both voltage levels in to the chip, you could accomplish this through the inverters. Mostly what it was doing was providing the isolation between the TXD and RXD lines. I hadn't fully thought about the cost of one interface vs another; I'm sure the handful of transistors you need are a LOT cheaper than the 7404. I had issues getting the two-transistor versions to work; and I was less interested in debugging it than I was doing development. But I got to thinking would it be possible to eliminate a physical interface entirely. We are, after all, working with the same voltage levels; anything that would blow up the microcontroller would likely blow up the radio too. It turns out it is possible; and rather than sitting down and doing math on what logic levels I would need, I decided to just start throwing wires to connections and executing code.

Software based UART exists for Arduino. The ATMega328 only has one physical UART port on it; meaning if you need more you have to do it in software on generic pins. This is one of the reasons I'm developing on a Mega2560; it features 3 hardware UART controllers. I wanted to avoid using software methods when possible; but I mostly wanted to avoid a situation where the software serial might not be up to the task without resorting to lower baud rates. But I'd already determined that the 16mhz AVR core was executing code faster than I anticipated, causing some major problems in implementing some ideas. I had done some software serial testing on the Raspberry Pi; which actually by default uses hardware UART for Bluetooth and software serial for any other purpose. It worked fine on my 9600baud IC-725; but I was dealing with a full 19200 baud my 7100 could do. The only downside, as some told me, was that the SoftwareSerial library was inherently half-duplex.

Of course, in our case, that's fine. CI-V is only a half-duplex bus anyway; the fact our software serial can't TX and RX at the same time doesn't mean anything...it's physically impossible for CI-V. Someone had actually already made a modified version that allowed operation on a single pin; which was pretty much what I want, the only question would be would it actually work or would I run in to a case of inverted logic levels? Code for inverted logic existed in the library, though stated it might not work as is. Again, the only thing I could do is give it a try. I plugged the ground connection from the CI-V remote up to ground and the center pin directly to one of the Arduino's port. Yes...a straight connection from Arduino to radio. No transistors, no opto-isolators, no 7404, no max232; this was going to be pure software bit-banging.



At first I wasn't getting anywhere. I wrote a simple program that would basically echo the software serial port to the hardware port and vise-versa. The idea was I could load up RealTerm, point it to the Arduino's COM port, and then attempt to poke things that way. I should see CI-V transcieve data coming from the radio and I should be able to have RealTerm send CI-V bytes that will get echo'd on the serial port. I quickly added a routine that sent a VFO swap command from within the code during boot-up to give me some indication and attempt debugging. To my surprise I saw the radio flip VFOs when the new code booted up. It told me that I was not only on the correct pin; but that sending data worked! But why couldn't I get any data...and more importantly...why couldn't I send data through my terminal program? I spent a while chasing my tail on this. I thought it was an inverted logic problem; but activating that made nothing work. I thought maybe I only needed logic inversion on RX; so I poked around the driver and made some changes so logic would only be inverted on RX. No change.

One solution turned out to be solving a PEBKAC problem; I had not formatted my bytes in a manner RealTerm wanted. Once I fixed that issue; yeah, no problem sending data to the radio. But...I could not get anything out of it for the life of me. I tried the next pin over, nothing. I tried the pin next to that, nothing. I began to wonder if I'd blown something up. I wired up my 7404 converter and loaded some older code; nope, radio was just fine. Maybe I was blowing up the Arduino pins...which made no sense since they were still sending data...but, I was thinking I could have partially blown them up. I ultimately decided to try again, but using "Pin 13". For those unfamiliar with Arduino, Pin 13 on most boards has a current limiting resistor and LED permanently attached to it. I believe the primary purpose of this is to function as an indicator to see if your Arduino is running; but it's also heavily used for the "Blink" sketch, the hello world of Arduino. You can still use the pin as whatever you wanted with some caution since it's logic level is going to be in a state of permanent pull-down. I figured, if anything, I should be able to see the internal LED flicker with data.

I didn't see any flicker, but what I did see was CI-V transcieve data! I sent a command through RealTerm; and the radio responded! I even saw the radio's response packet. It was far from perfect; it was possible to move the VFO dial so quickly I think the software couldn't keep up....but it's also possible I just exceeded how quickly the radio could pump it out. I attempted to run OmniRig with this hack, but it failed. I did however direct WJST-X to use the IC-7100 on the Arduino's COM port. WJST-X had zero issues with this and I could see the polling interval occuring with the flicker of the various LEDs. I did some additional testing to see if, for some reason, the pull-down did the trick; but that turned out to not be the case. I don't know exactly what the problem is, but the easiest solution was to just use a pin that did.

I do not know what, if any, impact this has on the future CI-V adapters; most radios being used these days have onboard USB adapters. I also don't think it's any cheaper to build a CI-V adapter out of an Arduino; maybe if you get down to some of the smaller ones...but then some of those require a USB-to-UART adapter...which if you have to buy anyway...a couple of transistors is cheaper than adding an Arduino on top of that. A USB-to-UART adapter on Amazon sells for about $8; an Uno R3 for about $10. Of course the other secret is most of the Arduino's are in fact using software to provide USB-to-UART to start with; they actually run dedicated code on a second microcontroller for this purpose. In fact my early testing of my 7404 interface was done by removing the ATMega328 out of it's socket and letting the interface talk directly to the onboard microcontroller's serial output.

It does however open up a bunch of possibilities for not just my project...but anyone else what wants do do anything with CI-V on an Arduino. I can develop a CI-V compatible device that doesn't require any extra components for the physical interface...just a mini-jack and a cable.



Logged

KT4WO

  • Member
  • Posts: 425
    • homeURL
Re: Arduino Talking To CI-V With No External Hardware
« Reply #1 on: September 11, 2021, 01:03:17 PM »

+1   !!

Nice read! and tnx for the gud info!

It's also nice to see some posts to this group.

KT4WO
Logged

K6OK

  • Member
  • Posts: 151
Re: Arduino Talking To CI-V With No External Hardware
« Reply #2 on: September 22, 2021, 10:00:21 PM »

Very good and informative article.

Just as a side note, I too experimented with using a Raspberry Pi clone (NanoPi NEO Plus2) with my Icom 7300.  I used a USB TTL serial adapter, wired the TX and RX together then connected those to the one-wire CI-V port.  You can send CI-V commands directly to /dev/tty/USB0 this way without using hamlib or omnirig.   The tricky part was getting Python to convert plain text to hexadecimal.  To read and write:

Send command: self.my_serial_object.write(bytearray.fromhex(cmd))  // cmd = FEFE94E003FD asks for frequency
Read command: the_frequency = self.my_serial_object.read(17).hex() // 17 byte length for frequency

I use the NanoPi's ethernet port to send/receive the CI-V data over the internet. It works.  But for your use case, a remote head, the Arduino is a better choice -- like you say, instant on, no boot up wait time.
 
Logged
Pages: [1]   Go Up