dasKeyboard Repair

There are some of us out there who really can’t stand typing on the cheapo $5 keyboards that come with computers these days and will spend $130 on a very clicky keyboard.  I’m old school, and I started my career using IBM PS/2s with the very heavy and very precise keyboards, and, in fact, I used one of the original PS/2 keyboards for 20 years until it gave up the ghost.  Now, I always use one of the many modern clones of these keyboards on all my computers.  At work, I use a dasKeyboard Model S, but the forward slash/pipe key broke, which is a pretty important key for people who spend a good bit of time working at DOS and Linux shells.

Much like the human body, where they can take some “extra” tendons you have laying around in your body, and fix your ACL, there are plenty of “extra” keys on the dasKeyboard I could use to replace my broken key.  In this case, I used the right Windows key, which I doubt I have ever used (I use ALT-ESC if I want to bring up the start menu with a keystroke).  When you pull the keycap off of the key, you find the switch mechanism:

KeySwitch and I was able to unsolder the broken switch and replace it with the one under the windows key.

This picture shoes the location of the screws.  You have to pull off 2 of the rubber feet to get to screws, and it is important to note that there is no screw under the label, even though it feels like there is one (you can see I ripped up the label trying to find it).

screws

Once you open up the case, which takes a bit of force, you will need to unscrew the PCB, because the ribbon cable does not come off.

PCB

At this point the hard part is over.  Using some resin and desolder braid, it is pretty easy to unsolder the keys from the main PCB of the keyboard.  Getting the keys off the PCB takes a bit of work, because there are some clips on the font side that you just have to pry a little, and pushing the center pin on the back side will eventually pop the key right off the board.  The arrows show where the keys were originally:

DesolderedKeys

You can then just solder the new key in place.

The finished product.  I’ve opened a case with dasKeyboard to find out if I can buy a new key, but if not, or it is too expensive, I will probably solder the broken key into the hole just to cover the spot.

Whole

Update: The key switches are a standard part, Cherry MX MX1A-E1NW, for the blue capped models.  You can get them at Mouser, Digikey, Newark14, and other places.

Telemetry Bridge

Bridging the Telemetry from and APM Quadcopter Controller to a Spektrum Telemetry Module

I came across this post on the RCGroups forum describing how to interface into the Spektrum Telemetry Module and send your own telemetry to a Spektrum radio.   I was building my own Quadcopter centered around the APM flight controller, which is based on an Arduino  Mega 2560.  One of the options on this controller is to put a radio transmitter on the Serial 1 port, and a radio receiver on a PC, and the controller can continuously transmit telemetry information like GPS coordinates, Battery Current and Voltage, Altitude, etc., to software running on the PC.  Since the Spektrum Telemetry is and I2C master, and the APM is sending the telemetry out a serial USART, I thought it would be a fairly straight forward task to use an ATMega 328p to read the telemetry stream from the APM, reformat it and send it on to the Spektrum Telemetry module.

While I will also have a fondness for the Arduino, because it got me started work with microcontrollers, I’ve moved away from using the Arduino in my projects because even a small Arduino is big (compared to the atmega chip itself), expensive and the software is somewhat limited.  In this case, the AVR had to respond to several I2C slave addresses (but not others), and the Arduino Wire interface is not well suited for that, but coding directly to the I2C interface made this possible.

The circuit board I made for this project consists of an ATMega 328p running at 16MHz and 5 V (because you need to run at 5 Volts to be in spec for 16MHz), a voltage level shifter to interface the 5 V I2C interface on the AVR to the 3.3 V Spektrum telemetry module, and connectors for the ISP interface, and a Bluetooth module I use to configure the Quadcopter with my phone.  I used parts I had in my inventory, so some of the components, like the 1 Amp 3.3 V regulator and the 1 Amp diodes are not what I would us if I was ordering parts just for this project.

sch

The circuit board is also designed for my home made PCB process (very large VIA pads), and would not be ideal for a professional PCB fabricator.

brd

The raw Eagle files are located on my GitHub site along with the source code.

Board

The serial stream that comes out of the APM is a protocol called Mavlink, and I spent a good bit of time on their site trying to figure out how to make this work.  First, you have to download the Mavlink include files here, and generate them with a Python script.  After running into some problems, I found that the structure  __mavlink_request_data_stream_t in common/mavlink_msg_request_stream.h was incorrect (the order of the fields was wrong).  It should look like:


typedef struct __mavlink_request_data_stream_t
{
uint8_t target_system; ///< The target requested to send the message stream.
uint8_t target_component; ///< The target requested to send the message stream.
uint8_t req_stream_id; ///< The ID of the requested data stream
uint16_t req_message_rate; ///< The requested interval between two messages of this type
uint8_t start_stop; ///< 1 to start sending, 0 to stop sending.
} mavlink_request_data_stream_t;

The other important Mavlink setting it know about when using a uC is at the top of main.c, before the include of mavlink.h:


// Save memory, MAVLINK by default allocates 4 256 byte buffers
#define MAVLINK_COMM_NUM_BUFFERS 1


#include <stdio.h>
#include <stdlib.h>

If you don’t set the number of buffers to 1 before you include mavlink.h, you will waste 768 bytes of SRAM, which the AVR does not have to spare.

A most invaluable tool for debugging both the Serial connections and the I2C I’ve found is a logic analyzer.  I use the Saleae Analyzer, which I am very happy with.  It would have been very difficult to do this without being able to see exactly what was going on the wires.

Quad hooked up to a logic analyzer

Quad hooked up to a logic analyzer

On the Telemetry side of the process, when the unit is powered on, the Telemetry module requests data from the I2C slaves from address 0x00 to 0x7D twice (0,0,1,1,2,2,etc.).  The bridge has to respond to the slave addresses it is going to fulfill (the RCGroups post above provide the list of slave addresses and functions) during this initialization, or that slave address will not be polled.  The AVR cannot answer to addresses 0x00 and 0x01, because they are for internal use of some sort.  The module Spektrum.c has a list of addresses the AVR will respond to, and, since during initialization the addresses are polled in numeric order, it sets the slave address of the AVR to the lowest address, and once that slave address has been called twice, the code resets the slave address to the next value, and so on util it has hit every address in the list.  The AVR responds to the telemetry unit with the 16 byte response packet with 0 values.

uint8_t addresses[]={0x03,0x0A,0x11,0x12,0x16,0x17,0x00};

ISR(TWI_vect)
{
    switch (TW_STATUS)
    {

        case TW_ST_SLA_ACK:
        if(initializing)
        {
            addrCount++;
            if(addrCount==2)
            {
                addrCount=0;
                if(addresses[++addrIdx]==0)
                {
                    TWAR=addresses[0]<<1;
                    initializing=0;
                }
                else
                    TWAR=addresses[addrIdx]<<1;
            }
    }
    else
        TWAMR=0xFF;

After the initialization phase, the telemetry unit will only poll the slaves that responded during initialization, so the address mask, TWMAR, is set to 0xFF, which means the AVR will respond to any slave address.  When any request for data is sent to the AVR after initialization, it looks at the address that is being requested, and sends the correct buffer back to the master.  Another important thing to note is the telemetry unit does not poll the slave addresses until the radio it is bound to is up and ready to receive data, so if the radio is off, the initialization will occur, but no polling of the slave will occur until the raid is turned on.

One final thing to note is that the AVR does not have division natively built into the instruction set, so it is an expensive operation. Since the AVR needs to be available to handled the asynchronous requests from 2 outside feeds, it has to get the calculations done as quickly as possible .  To get around this, a technique called fixed point arithmetic can be used.  This article has an excellent description of the technique.  For example, the following is a division by 10,000,000.

uint16_t divideBy1E7(uint32_t dividend)
{
	return (uint16_t)((((int64_t)dividend * 0xD6E0LU) >> 16) >> 23);
	//return (uint16_t)(dividend / 1E7);
}

In the source code there is a #define constant called TIMEIT which will include code to time the number of clock cycles the AVR takes to compute the GPS buffers (the most mathematically complex part of the code), and display that value in the Power Box 2nd battery capacity (which is normally 0).  I tested the code with the straight-forward division and with fixed point, and compiled with full optimizations (-o3), the fixed point version of the setGPSBuf call took about 46,500 clock cycles while the division averaged 56,500 clock cycles.  I’m not sure a 17.5% improvement was worth the effort of figuring out the fixed-point parameters, but it was interesting.

As I said above, all the code and eagle files are located on GitHub.