Cheap USB-serial adapter neither fish nor fowl

Blog ยป Cheap USB-serial adapter neither fish nor fowl

Posted on 1288575246|%A: %d %B, %Y|agohover

You can get USB-serial adapters for absurdly low prices from ebay or Asian import stores like Deal Extreme. Needless to say these are not exactly high-quality electronics, however they can do the job for hacking purposes. USB-serial adapters are a convenient way to supply both a small amount of regulated power and simple communications to a peripheral device.

The big problem with these adapters is that they implement neither an RS232 compliant waveform, nor a TTL waveform that can be understood by the AVR's UART. Rather, they implement sort of a pseudo-RS232 that produces a clipped waveform from 0 to 5V. But as it turns out, this is simply inverted from what the UART expects.

There are a few different solutions to this problem. You can use a hardware inverter if you have one handy, like some sort of inverting logic, or just a 5 cent transistor. You can use a software serial decoder, which seems reasonable if you're already using such software instead of an integrated UART. But if you're using a chip that has a UART, it seems sort of dumb not to use it somehow.

If you have a couple of spare pins on your micro, I found another solution which uses less than 10 lines of code. This example is for an attiny2313, but the basic form will work with any AVR with a UART (or most any microcontroller for that matter):

// some cheap pl2303 usb->serial adapters use a pseudo-rs232 output with
// 0-5V levels, but with an inverted waveform relative to real TTL serial
//
// we can use a pin change interrupt to re-invert this input on another pin to
// feed the UART a signal that looks like normal TTL serial
//
ISR(INT1_vect)
{
    // invert pin D3 on pin A0
    PORTA = !( PIND & _BV(3) || PINA & _BV(0) );
}

void pl2303_init(void)
{
    // configure pin D3 to invert input on pin A0 for non-TTL serial links
    DDRA  = 0b01;        // pin A0 is output
    MCUCR = _BV(ISC10);    // interrupt on any pin change
    GIMSK = _BV(INT1);     // enable interrupt
    PORTA |= 1;
}

Leave a comment

Add a New Comment