Electronic – USART transmit problems on a PIC

cinterruptsmicrocontrollerpicserial

I'm trying to send data to an SD card from a PIC18f4580, but the PIC is not sending what it should be.

related global variables:

unsigned char TXBuffer[128]; //tx buffer
unsigned char TXCurrentPos = 0x00; //tracks the next byte to be sent
unsigned char TXEndPos = 0x00; //tracks where new data should be put into the array

I am adding data to a buffer using the following function:

void addToBuffer(char data){

    TXBuffer[TXEndPos] = data;
    TXEndPos++;
}

And putting the data from the TXBuffer into TXREG with the following interrupt:

else if (PIR1bits.TXIF == 1){

    if((TXEndPos - TXCurrentPos) > 0){         // if there is data in the buffer
        TXREG = TXBuffer[TXCurrentPos];           // send next byte
        TXCurrentPos++;               // update to the new position
    }

Using an oscilloscope I am able to see that the PIC is sending 0x98, regardless of what I put into the buffer. In fact I never put 0x98 into the buffer.

However, if I replace

TXREG = TXBuffer[TXCurrentPos];

with

TXREG = 0x55;

or

TXREG = TXCurrentPos;

then I get the expected results, that is the PIC will send 0x55 repeatedly, or count up from 0 respectively.

So why does the PIC have trouble sending data from the array, but any other time it is fine? I'll emphasize that transferring is handled in an interrupt, because I feel like that's the root of my issue.

EDIT: It is a circular buffer in the sense that TXEndPos and TXCurrentPos return to 0 when they reach 127.
I also disable the transmit interrupt when TXEndPos – TXCurrentPos == 0, and re-enable it when adding data to the buffer. Really, my code works completely as expected in that if I add 13 characters to TXBuffer in main, my PIC will transmit 13 characters and then stop. The problem is that they are always the same (wrong) character – 0x98.

EDIT2: more complete functions are here: http://pastebin.com/MyYz1Qzq

EDIT3: By changing our linker script and appropriately using pragmas we're able to get some of our data into our buffer. We statically placed variables related to the buffer into the same memory bank, and that has certainly helped but not all of our data is getting into our buffer. Strangest of all, running the program multiple times yields different data in the buffer, even though all of the data to be placed in the buffer is defined in our code. Also, we get drastically different results when the pic automatically runs after programming it, when we cut the power and restart power with the pickit3 still plugged in, and when we reset the power with the pickit3 disconnected. Also, simulating in MPLAB results in the buffer being filled perfectly, however when actually running the code on the PIC and viewing it's memory, it is not.

Our code as of 5:38 9/22/10 is here.

Our modified linker file is here.

Best Answer

It's a little confusing that the code in the question differs to the code in pastebin - but assuming that the pastebin code is correct, I'd say that the problem is that you're sending uninitialised data from the array instead of the characters that you put in it.

TXREG = TXBuffer[TXEndPos];           // send next byte

should be

TXREG = TXBuffer[TXCurrentPos];           // send next byte

It's important to copy/paste the code directly (using pastebin is great!) because you've actually corrected this yourself in the question - making it hard for people to spot the problem :)

This may have been easier to spot yourself if you initialised the buffer to a known value on startup (eg 0x5A).

You also mention that you reset the TxCurrentPos & TxEndPos variables to zero at some point, but I can't see that in your code. It's best to do this whenever you increment those values. Eg

TxCurrentPos++;
TxCurrentPos %= TX_BUFFER_SIZE;

Aside: I like that you've removed the redundant TxBufferSize variable in the question - this follows the DRY Principle and eliminates the source for an error. Having data duplicated in two spots is asking for trouble.