Kinetis K10 UART reads the same byte twice

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Kinetis K10 UART reads the same byte twice

Jump to solution
883 Views
BarryGJones
Contributor II

This has been driving me nuts all day. I have a custom PCB I've designed using a K10 to take serial packets of data from a PC and route them out to one of the other four UARTs on the K10. It also receives packets from those other UARTs to parcel up and feed back to the PC. I'm talking to the PC at 115200 baud, and everything works fine if I only have one slave device hooked to one of the other UARTs. When several are hooked up, I occasionally get the same byte twice. I'm using interrupts, (no DMA), have looked through a lot of example source code and studied the documentation without finding an answer. Here's hoping someone can offer a suggestion. Here's the IRQ handling code:


#define GET_UART_DATA(channel) \

    { \

    s_UartRXBuffers[channel][s_UartRXWriteIdx[channel]++] = UART_D_REG(UART__base_ptr_tbl[channel]) & s_DataMask[channel];     /* Read data from UART buffer.*/ \

    s_UartRXWriteIdx[channel] &= UART_BUF_MASK; /* account for wrap; */ \

    }

PE_ISR(Uart3_ISR)

{

   volatile uint8 StatReg = UART_PDD_ReadInterruptStatusReg(UART3_BASE_PTR); // Read status register

  if (StatReg & (UART_S1_NF_MASK | UART_S1_OR_MASK | UART_S1_FE_MASK | UART_S1_PF_MASK))  // Is any error flag set?

  {

    (void)UART_PDD_GetChar8(UART3_BASE_PTR);                // Dummy read 8-bit character from receiver to clear the rdrf bit

    if (StatReg & UART_S1_RDRF_MASK)              // Is the receiver's interrupt flag set?

    {

        StatReg &= ~(uint8)UART_S1_RDRF_MASK;    // Clear the receive data flag to discard the erroneous data

        // Reading an empty data register to clear one of the flags makes FIFO pointers misaligned. RX FIFO flush reinitialises pointers.

        UART_PDD_FlushFifo(UART3_BASE_PTR, UART_PDD_RX_FIFO_FLUSH ); /* Flush RX FIFO */

    }

  }

  else if (StatReg & UART_S1_RDRF_MASK)              // Is the receiver's interrupt flag set?

    GET_UART_DATA(3);

  if( (StatReg & UART_S1_TC_MASK) && (UART_C2_REG(UART3_BASE_PTR) & s_TXIRQMask[3]) ) // Transmit complete flag and correct interrupt enabled??

    UartTXIRQHandler(3);                     // If yes, then invoke the TX irq service routine.

}

This is just the latest iteration of the code, I've tried all sorts of things and this is how it's ended up.
As an example of the problem : one of the peripherals I'm talking to sends me a packet like this: 0x02, 0x31, 0xd7, 3f, b7
When things go wrong (once every several hundred packets) I see this in my RX buffer: 0x02, 0x31, 0x31, 0xd7, 3f, b7
Any suggestions, good, bad, or completely crazy gladly accepted:
Cheers,

Tags (1)
0 Kudos
1 Solution
557 Views
BarryGJones
Contributor II

Ok, turns out to have been a problem elsewhere. All that UART code is in fact working as it should and I fixed a bug elsewhere which was causing the occasional byte to be duplicated in my RX buffer.
That one sorted, on to the next stage of the development :smileyhappy:
Cheers, Barry.

View solution in original post

0 Kudos
3 Replies
557 Views
mjbcswitzerland
Specialist V

Hi Barry

You don't show UartTXIRQHandler().

What are the UART interrupt priorities?  I suspect that you may have a problem when one of the UARTs is writing data to the output when another UART (with higher priority) interrupts it. Do you enable Tx interrupts or just Rx interrupts?

Regards

Mark

0 Kudos
557 Views
BarryGJones
Contributor II

Hi Mark, thanks for the response. I hadn't wanted to spam the group with too much code in my first post, but here is the TX handler:

void UartTXIRQHandler(uint8 a_UartChannel)

{

    volatile int readIdx = s_UartTXReadIdx[a_UartChannel];

    volatile int writeIdx = s_UartTXWriteIdx[a_UartChannel];

    if(readIdx == writeIdx)  // all bytes are now done transmitting?

    {

        s_UartTXState[a_UartChannel] = UART_TXSTATE_IDLE;

        UART_C2_REG( UART__base_ptr_tbl[a_UartChannel] ) &= ~(UART_C2_TCIE_MASK | UART_C2_TIE_MASK);  // disable transmitter interrupts

        return;

    }

    UART_MemMapPtr pUartbase = UART__base_ptr_tbl[a_UartChannel];

    volatile uint8 *pSrc = s_UartTXBuffers[a_UartChannel];

    uint8 freeSpace = s_FifoSize[a_UartChannel] - UART_TCFIFO_REG(pUartbase);

    while(freeSpace != 0)

    {

        --freeSpace;

        uint8 val = pSrc[readIdx++];

        (void)UART_PDD_ReadInterruptStatusReg(pUartbase);   // to ensure we clear the flags

        UART_PDD_PutChar8(pUartbase, val); // Put an 8-bit character to the transmit register

        readIdx &= UART_BUF_MASK;   // account for wrap

        if(readIdx == writeIdx)  // all bytes are now done transmitting?

        {

            s_UartTXState[a_UartChannel] = UART_TXSTATE_IDLE;

            UART_C2_REG(pUartbase) &= ~(UART_C2_TCIE_MASK | UART_C2_TIE_MASK);  // disable transmitter interrupts

            break;

        }

     }

    s_UartTXReadIdx[a_UartChannel] = readIdx;

}

I have the receiver interrupt permanently enabled, and enable the transmitter interrupt when I have bytes to send in my local tx buffer.
Here's a portion of my setup code:

    // disable transmitter and receiver (Transmitter MUST be disabled to write to the FIFO watermark register!!)

    UART_C2_REG( UART__base_ptr_tbl[a_UartChannel] ) &= ~(UART_C2_TE_MASK | UART_C2_RE_MASK );

    // this chip appears to only have an 8 byte deep FIFO

    UART_PDD_EnableFifo(UART__base_ptr_tbl[a_UartChannel], (UART_PDD_TX_FIFO_ENABLE | UART_PDD_RX_FIFO_ENABLE)); /* Enable RX and TX FIFO */

    UART_RWFIFO_REG( UART__base_ptr_tbl[a_UartChannel] ) = UART_RWFIFO_RXWATER( 1 );

    UART_TWFIFO_REG( UART__base_ptr_tbl[a_UartChannel] ) = UART_TWFIFO_TXWATER( 1 );

    UART_PDD_FlushFifo(UART__base_ptr_tbl[a_UartChannel], (UART_PDD_TX_FIFO_FLUSH | UART_PDD_RX_FIFO_FLUSH)); /* Flush RX and TX FIFO */

    // enable UART transmitter and receiver

    UART_C2_REG( UART__base_ptr_tbl[a_UartChannel] ) |= (UART_C2_TE_MASK | UART_C2_RE_MASK );

    // enable noise, parity, overruyn, framing error interrupts

    UART_C3_REG( UART__base_ptr_tbl[a_UartChannel] ) |= (UART_C3_PEIE_MASK | UART_C3_FEIE_MASK | UART_C3_NEIE_MASK | UART_C3_ORIE_MASK);

    UART_PDD_EnableInterrupt(UART__base_ptr_tbl[a_UartChannel], ( UART_PDD_INTERRUPT_RECEIVER )); // Enable RX interrupts


I'm using Kinetis Design Studio version 3.1.0 and have set the RXTX interrupt priority level for all the UARTs to "Maximal". I've also enabled error interrupt and it's also "Maximal".
The only other interrupt I have enabled is a timer interrupt at "Medium Priority"

Cheers,
Barry.

0 Kudos
558 Views
BarryGJones
Contributor II

Ok, turns out to have been a problem elsewhere. All that UART code is in fact working as it should and I fixed a bug elsewhere which was causing the occasional byte to be duplicated in my RX buffer.
That one sorted, on to the next stage of the development :smileyhappy:
Cheers, Barry.

0 Kudos