Macs don’t have Parallel Ports. That’s no problem for using nowaday devices but its a real disadvantage if you like to hack hardware and need to access ports or like to work on toggle-bits level with any kind of homebrew hardware.
I had a look at the cool DTV transfer tool called dtvtrans written by TLR. There you build a parallel to joystick port cable and then you can transfer memory blocks directly from and to the DTV’s RAM or ROM. This is ultra handy for development and fast testing…
But without a parport on my Mac, what to do?
I remembered an older project I built that was presented in the german c’t magazine called com2lan where a serial port was connected to an AVR microcontroller (an ATmega8535) to do some simple tasks like measuring the temperature. Back in 2005, I already implemented a firmware called lancre for this little hardware.
With an AVR you can implement your code in C on the host, cross compile it there and then transfer and flash it via an ISP to the device. The AVR has lots of I/O pins which can be controlled directly in your program…
So, the idea was: why not connect the DTV directly to the AVR, do the dtvtrans bit baning there and then use the serial port of the AVR to transfer the data to my Mac. With a standard USB-to-Serial Adapter (I use the well supported Keyspan USA-19HS) you can easily connect any Mac (or other new PCs) to the AVR’s serial port.
A new project was born, called dtv2ser!!
The Dataflow of the project will look like this:
Mac ---[USB]--- USA-19HS ---[RS232]--- dtv2ser ---[dtvtrans]--- DTV
Since many other new PCs also lack a parport, I think this will be a nice add on for the DTV community and a real alternative to the initial dtvtrans parallel cable approach
With com2lan’s schematic at hand, I quickly found some free I/O pins and soldered a connector cable with a DB9 joystick plug for the DTV
Here you can see the wiring of the cable:
AVR Port Pint dtvtrans DB9 Pin DTV PA3 RESET 9 PA2 ACK 6 PC7 CLK 4 PC6 D2 3 PC5 D1 2 PC4 D0 1 GND GND 8
Note: You have to connect the DTV’s Reset Pin to DB9 Pin 9 which is a non-standard mapping on the joystick port. This will allow you to reset the DTV remotely from the host.
Here is a snapshot of my experimental setup on my desk: On the left is my MBP with the Keyspan serial adapter connected to the com2lan Board (inside the silver housing with blue LCD top put back). From there the colorful wires connect to my DTV mod. I additionally connected the ISP (with USB) to the com2lan to do quick updates of the firmware while developing:
And another close up of the com2lan box and the DTV:
Now the hardware was ready to go, the software needs to be done…
I started with building an AVR toolchain, so all current versions of avr-gcc, avr-binutils and avrdude are available.
As a starting point I used my lancre firmware and TLR’s source of dtvtrans-0.6 as a reference implementation of the dtvtrans protocol.
The dtvtrans core was ported quickly to pin i/O and I soon had some code running that sends a command from the AVR via dtvtrans to the DTV. Yohoo(!), a proof of concept was done and it was really a good feeling to see the flashing border on DTV while transferring data
The data now needs to be transferred to the Mac and I chose the serial port that is available on each AVR for that… Some digging in the specs revealed that my USB adapter supports up to 230 Kbps… so why not use it That would be a max of approx. 20 kbyte/s for transfer and matches the 11-16 kbyte/s reported for a parallel dtvtrans transfer. Some data transfer tests later (done with the old but still good Zterm) revealed that some sort of transfer control is needed to handle these data speeds. I chose the reliable hardware RTS/CTS handshaking to control when to send or not and achieved up to 20 kbyte/s with pure send and receives from the AVR to the Mac. Just add two more wires to the AVR and you can do handshaking from there. Fortunately the MAX232A level converter for RS232 already has 2 inputs and 2 outputs: TxD, RxD, CTS and, RTS.
For the actual device I’d like it to be very similar to a good ol’ modem. There are two modes involved: command and transfer mode. In command mode the device (here dtv2ser) waits for commands from the host (here the Mac). You then enter a short and human readable sequence of chars and finish them with a new line. The device processes the command and gives a result wether the command is reasonable. If everything is ok then the command performs some actions and optionally returns a result.
If the command is a transfer command (e.g. read or write memory from the DTV) then the device enters transfer mode. Now there are only raw blocks of data that are transferred between the host and the device. In dtv2ser, a transfer command fully specifies the amount of data that will be transferred so both sides know when to enter command mode again. Error conditions (e.g. missing data or dtvtrans problems) will lead to missing transferred bytes that will trigger a receiption timeout on the host side.
Here is an example:
# dtv2ser is in command mode # mac sends command: read memory, 00=ram, 000000=start address, 000100=length mac: r 00 000000 000100 +newline # dtv2ser replies with 00=command ok d2s: 00 # now dtv2ser enters transfer mode d2s: ... sends 0x100 bytes ... # raw transfer of the bytes mac: ... reveives 0x100 bytes ... # dtv2ser automatically leaves transfer mode and reenters command mode # mac sends command: return transfer status mac: tr +newline # 00=transfer ok d2s: 00
First experiments with this approach worked really well… and thus I’ll keep this approach. With this basic mechanism working, I really needed a host tool on my Mac to control the dtv2ser device. Something similar to the dtvtrans program that is supplied to control the dtvtrans cable in TLR’s approach, but does talking with the dtv2ser device instead.
First I thought about extending the dtvtrans C++ code but then I thought that (portable) serial handling in C++ is really too much to code for now. I want to start more quickly and looked at my favorite scripting language Python if serial support is availble. It is! Not out of box but on SF.net: PySerial. Just download, unpack and install and volia: You have a serial class that manages the serial port including RTS/CTS handling and timeouts! Considering that 20 kbyte/s transfer are really slow, even compared to the execution time of scripting language, I think the Python code will do fine as a host tool.
With serial commands in Python I really quickly hacked the first version of dtv2sertrans the host tool of the dtv2ser device. I added the basic methods of dtvtrans and also cloned its syntax:
# reset the DTV dtv2sertrans reset # read DTV RAM starting at 0x400 of size 0x200 and store a PRG file on disc dtv2sertrans read 0x400,0x200 dump.prg # write the local program file to the DTV RAM starting at the embedded address dtv2sertrans write myprog.prg
The handling of the host tool is now similar to the usage of dtvtrans and behaves like that (I believe, because I never had a chance to run the original one . The only difference is the back end…
My first experiments with the dtv2ser serial-to-dtvtrans bridge were very successful and really motivated me to bring this along in a full open-source project.
Things that need to be done for the first release are:
- A dedicated HW board: Using an ATmega8 and a MAX232A (for serial level conversion), the board only needs a 14.547600 MHz quartz (for exact baud rate matching) and some LEDs for status. Should be a cheap and small design.
- A schematic in Eagle – good for publication. Currently, all my schematics are drawn on paper – this project is a good opportunity to learn eagle
- Source Code clean up. Both the firmware and the host utility got quite ugly while experimenting and definitely need more structure for a release…
- Checking Error Conditions. There are many cases that something times out or errors… need to handle these….
- Testing…. ok, it’s an OSS project, so you can take this one, too
I started with most points already, so the first release is not far away…. Just stay tuned and watch out for the new dtv2ser project page here on my blog!