Electronic – PIC18F + MAX232 USART Bizarreness

max232picrs232serialuart

Okay, I've been struggling with this for weeks, and it's blowing my mind. I have been working with PICs for a long time, and I'm very confused as to why I can't make my USART work.

First off, a few questions for people that don't want to read through this post but might be able to help:

  • How do I invert the signals to use with the MAX232 chip?
  • Should TX and RX be set to outputs, inputs, or output for RX and input for TX? The datasheet says one, examples say another.
  • Do I need to use the PLL?
  • What are the USART_ADDEN_OFF and BAUD_IDLE_RX_PIN_STATE_HIGH flags for, and why aren't they in the C18 documentation?

For everyone else, here is the long story:

The setup:
PIC18F46K20 <–> MAX232 <–> PC

RC7 is RX, and RC6 is TX.

Terminal software is just a Python interpreter:

port = serial.Serial("COM6", 2400, timeout=5)
port.write("abcd")
print port.read(1)
etc...
  • If I connect the T1in and R1out pins of the MAX232 together, then serial-loopback works perfectly from my PC, so I know that the MAX232 board is okay.
  • I moved the PIC off of it's board, and it's sitting on a breadboard for debugging. The only things plugged into it are power, ground, and TX & RX.

I have tried an incredible different number of code variations – none are doing the trick. Here are some of the things I have tried:

This is basically taken entirely from this post:
PIC18 USART problem

Note the use of a PLL and the HS setting for BRGH, and that the TX pin is set to input, and only RX is set to output, contrary to the datasheet.

#include <p18cxxx.h>
#include <usart.h>

void main(void)
{
char c = 'a';

TRISC = 0x80;
    // Internal osc. 8 MHz, PLL 4x
    OSCCON |= 0xE2;
    OSCTUNEbits.PLLEN = 1;

    // wait until IOFS = 1 (osc. stable)
    while (!OSCCONbits.IOFS)
        ;


    /*
     * Open the USART configured as
     * 8N1, 2400 baud, in polled mode
     */
     OpenUSART (USART_TX_INT_OFF &
                USART_RX_INT_OFF &
                USART_ASYNCH_MODE &
                USART_EIGHT_BIT &
                USART_CONT_RX &
                USART_BRGH_HIGH, 207);

     while (1)
     {
          putcUSART(c);
          c = getcUSART();
          Nop();
     }

}

Anyway, I feel silly that I can't make a silly USART work, but I'm completely stumped. What am I missing? What am I doing that's stupid? Someone please help!

Addition
I'm exhausted – posting this last thing before I go to bed and try more tomorrow.

This returns a constant stream of gibberish, even if I'm not writing anything to the USART from the PC:

#include <p18cxxx.h>
#include <usart.h>

void main(void)
{
char test = 'a';
TRISC = 0xFF;
OSCCON |= 0b11100010;
OSCTUNEbits.PLLEN = 1;

    while (!OSCCONbits.IOFS);

baudUSART(BAUD_IDLE_CLK_LOW & 
          BAUD_AUTO_OFF & 
          BAUD_8_BIT_RATE & 
          BAUD_IDLE_RX_PIN_STATE_HIGH);

OpenUSART (USART_TX_INT_OFF &
           USART_RX_INT_OFF &
           USART_ASYNCH_MODE &
           USART_EIGHT_BIT &
           USART_CONT_RX &
           USART_ADDEN_OFF &
           USART_BRGH_HIGH, 207);
    while (1)
    {
        WriteUSART(test);
        while(!DataRdyUSART());
        test = ReadUSART();
        Nop();
    }
}

UPDATE

Okay, now my TX pin is at a constant 0.00 Volts. It's almost like it is tied directly to ground (it very well may be at this point, I don't know). I have tried switching out PICs, making it constantly transmit, making it do nothing, changing configuration bits… nothing seems to help. The RX pin sits high (which is correct, because it isn't receiving anything), but the TX pin sits flat at 0V – whether it's supposed to be transmitting or not.

Here is my current code:

#include <p18cxxx.h>
#include <usart.h>

void main(void)
{
char test = 't';
TRISCbits.RC7 = 1;
TRISCbits.RC6 = 0;
OSCCON = 0b11100010;
OSCTUNEbits.PLLEN = 0;

    while (!OSCCONbits.IOFS);

baudUSART(BAUD_IDLE_CLK_LOW & 
          BAUD_AUTO_OFF & 
          BAUD_8_BIT_RATE & 
          BAUD_IDLE_RX_PIN_STATE_HIGH &
          BAUD_IDLE_TX_PIN_STATE_HIGH);

OpenUSART (USART_TX_INT_OFF &
           USART_RX_INT_OFF &
           USART_ASYNCH_MODE &
           USART_EIGHT_BIT &
           USART_CONT_RX &
           USART_ADDEN_OFF &
           USART_BRGH_HIGH, 207);
    while (1) {
//       WriteUSART(test);
//      while(!DataRdyUSART());
//        test = ReadUSART();
        Nop();
    }
}

What on Earth did I do to make it do that? Note that I also rebuilt my old code (an example from above, that was previously just spitting out gibberish) – and now the voltage is 0.0V with that hex file as well. Also, the MAX232 loopback still works correctly. Huh?

Best Answer

Okay, for anyone that ever encounters something like this in the future:

The issue was that there was leakage from the power trace into the serial trace, such that a 60Hz wave was appearing on the SPI line, which obviously would mess things up.

I know the likelihood of this same fix applying to other people is small, but maybe it will at least give you some ideas!