0

I'm currently using an PIC18F67J60 to try and print out a string and or an integer value using the UART, but am only getting "00" out of it. I'm somewhat new to embedded C so there's probably something I'm missing realistically.

The function is defined as:

u8 UART_TxMessage(u8 Count, u8 *Bufr)
{
    if (Timer_Expired(RxTimer))
    {
        Timer_Stop(RxTimer);
        RxIndex = 0;
    }
    if (TxCount)
        return(0); // still sending last message
    if (Count > MAX_MSG)
        return(Count);
    memcpy(TxBufr,Bufr,Count);
    TxIndex = 0;
    TxCount = Count;
    PIR1bits.TX1IF = 0;
    TXREG1 = Count;
    PIE1bits.TX1IE = 1;
    return(Count);

}

The only way I've been able to get anything other than "00" is by echoing back what's been recieved on the Rx side; so I'm confident it's just my lack of knowledge.

I'd really appreciate any examples!

ISR Function as requested:

void UART_ISR()
{
    u8 c;

    if (PIR1bits.TX1IF && PIE1bits.TX1IE)
    {
        PIR1bits.TX1IF = 0;
        if (TxIndex < TxCount)
        {
            TXREG1 = TxBufr[TxIndex++];
        } else {
            PIE1bits.TX1IE = 0;
        }
    }

    if (PIR1bits.RC1IF)
    {
        Timer_Set(RxTimer,100);
        PIR1bits.RC1IF = 0;
        c = RCREG1;
        if (RxCount)
            return; // buffer in use
        if (RxIndex >= MAX_MSG)
        {
            RxIndex = 0; // abort
            return;
        }
        RxBufr[RxIndex++] = c;
    }
}
Sam W
  • 243
  • 3
  • 11
  • I guess there is an interrupt function that you wrote. Could you post it? – alx - recommends codidact Mar 04 '19 at 21:09
  • Also, avoid bitfields if you know how to do the same with masks. They are faster, and also bitfields are Implementation Defined, which means your code is not portable and could behave different that expected. (i.e.: `PIE1 |= _PIE1_TX1IE_MASK;`) or something like that. – alx - recommends codidact Mar 04 '19 at 21:16
  • @CacahueteFrito Edited original post to show ISR – Sam W Mar 04 '19 at 21:18
  • By the way, I don't know your exact PIC, but at least on the PIC16f1829 TXIF is read-only. – alx - recommends codidact Mar 04 '19 at 21:19
  • Following the last comment, in the PIC I mention, and probably in yours, you shouldn't reset TXIF, and also, you shouldn't fill TXREG outside of the ISR, so I would remove those two lines and see if it works. – alx - recommends codidact Mar 04 '19 at 21:25
  • How are you calling it? – user253751 Mar 04 '19 at 21:27
  • Also, I'm almost sure that `volatile` is needed for the `TxBufr`, which would also imply that you cannot use `memcpy()` – alx - recommends codidact Mar 04 '19 at 21:35
  • Who resets `TxCount` after the message has been sent? It should be reset in the ISR. – alx - recommends codidact Mar 04 '19 at 21:38
  • The exact PIC I'm using is the PIC18F67J60. Also I did not write these functions; I was handed this project. Is there a better alternative that I can replace the entire UART library with? Or what would be the proper way to call this to print a character or string? – Sam W Mar 04 '19 at 21:42
  • I wrote a UART library for a PIC lasst week, and it is very similar, so I can help you. With little modifications it should work, and you will learn a lot if you achieve that, so try it. :) If you want, you can see my last 3 or 4 questions here, and they are all about this. You will get an idea of what you need. – alx - recommends codidact Mar 04 '19 at 21:55
  • @CacahueteFrito given that I've made your changes, how would I go about printing say a "hello world" statement via this serial tx function? Also where can I find your library? – Sam W Mar 05 '19 at 20:09
  • I haven't uploaded it to GitHub yet, but I will (under `LGPL-2.0-only` license). However, you can find all the relevant code in this question (with `Do whatever the heck you want with it` license): https://stackoverflow.com/q/54964154/6872717 – alx - recommends codidact Mar 05 '19 at 20:15

1 Answers1

0

From the Datasheet (page 134):

TX1IF is read only, and therefore, you shouldn't write to it (I guess it does nothing if you try, but I wouldn't mess with that).

R-0

TX1IF

TX1IF: EUSART1 Transmit Interrupt Flag bit

1 = The EUSART1 transmit buffer, TXREG1, is empty (cleared when TXREG1 is written)

0 = The EUSART1 transmit buffer is full


Also, as the interrupt fires immediately when you set TX1IE, you don't have to write to TXREG1, because the interrupt will immediately start the next character, and that would probably cause problems, so delete this:

PIR1bits.TX1IF = 0;
TXREG1 = Count;

I have a question still open (volatile for variable that is only read in ISR?) about the need of volatile for the buffer, and I think you need it to disable some optimizations that the compiler could try to do, and that would imply that you will not be able to use memset() (in that case you can use a version of memset that I did a few days ago: Is `memcpy((void *)dest, src, n)` with a `volatile` array safe? (in this case, memset_vout())).

Edit: As the answer (and its comments) to the first of those two questions says, you need volatile to prevent unwanted optimizations. And therefore you need to rewrite memset (the second link).


You have another problem: You don't reset TxCount (which should also be volatile for the same reason as the buffer) after you end the transmission, so the second (and subsequents) message that you send you will always return in the check. The ISR should reset that just after it resets TX1IE