EmbeddedRelated.com
Forums

Uart TX interrupt

Started by mrobins99 November 13, 2007
I'm having some difficulty with my transmit interrupt on an LPC2106.
I'm using winarm.

My rx interrupt works perfect, when new data is present I quickly add
it to a buffer and take out the bytes in the buffer in my main loop.

My tx buffer however has a bug. When programming for avr's I had two
types of interrupts tx buffer empty(which I used) and tx complete and
it worked perfectly. With LPC I only have tx complete interrupt. So
I add bytes to the buffer and if when adding a byte, it happens to be
the first byte in the buffer, I begin transmission. Then when the tx
complete interrupt happens I send the next byte and so on until the
buffer is empty once again. But when I add bytes to the buffer (in a
non interrupt routine), I have to disable interrupts to protect my
buffer variables from messing up. If the byte I'm sending doesn't
happen to be the first byte, then I may miss the tx complete
interrupt, and then the bytes just sit in the buffer.

An easy solution is to just transmit from the buffer in the main
loop, but I would like to use this interrupt.

Any suggestions?

An Engineer's Guide to the LPC2100 Series

I'm having some difficulty with my transmit interrupt on an LPC2106.
>I'm using winarm.
>
>My rx interrupt works perfect, when new data is present I quickly add
>it to a buffer and take out the bytes in the buffer in my main loop.
>
>My tx buffer however has a bug. When programming for avr's I had two
>types of interrupts tx buffer empty(which I used) and tx complete and
>it worked perfectly. With LPC I only have tx complete interrupt. So
>I add bytes to the buffer and if when adding a byte, it happens to be
>the first byte in the buffer, I begin transmission. Then when the tx
>complete interrupt happens I send the next byte and so on until the
>buffer is empty once again. But when I add bytes to the buffer (in a
>non interrupt routine), I have to disable interrupts to protect my
>buffer variables from messing up. If the byte I'm sending doesn't
>happen to be the first byte, then I may miss the tx complete
>interrupt, and then the bytes just sit in the buffer.
>
>An easy solution is to just transmit from the buffer in the main
>loop, but I would like to use this interrupt.
>
>Any suggestions?

Maybe this gives you an idea:
LPC2378; Keil compiler.
To send data I wrote the 'put_serial_data' function. You can see that the data is directly written into the UART hardware FIFO as long as the help var UART_TX_FIFO_cntr says the FIFO is not at its limit. Then to write more data the TX_buffer is used (circular type as known).
unsigned int16 put_serial_data(unsigned char data_2_send)
{

VICIntEnClr = (1<<7); /* disable serial interrupt */

if (UART1_TX_FIFO_cntr < UART1_TX_FIFO_LIMIT)
{ /* FIFO not full */
UART1_TX_FIFO_cntr++; /* so we directly feed data */
U1THR = data_2_send;
VICIntEnable = (1<<7); /* enable serial interrupt */
return(0); /* all OK */
}

if (TX_offset < (TX_BUFFER_LENGTH - 1)) /* (max lenght after inc) */
{ /* put only if enough place */
TX_buffer[TX_in_index] = data_2_send; /* write into buffer */
TX_in_index++; /* one more */
if (TX_in_index >= TX_BUFFER_LENGTH) TX_in_index = 0; /* modulo */
TX_offset++; /* buffer is not empty */
VICIntEnable = (1<<7); /* enable serial interrupt */
return(0); /* all was OK */
}
else
{
UART1_TX_overflow_cntr++; /* oops, and one more ERROR */
VICIntEnable = (1<<7); /* enable serial interrupt */
return(1); /* there was an OVERFLOW */
}
}

Now to the interrupt function:
because I only know that the hardware FIFO is empty (but not the amount of bytes to send) I only can reset the UART_FIFO_cntr when the hardware FIFO is really empty. So the THRE bit can be tested.
If all data has been sent the UART_TX_FIFO_cntr is reset. Else the next data block is loaded into hardware FIFO of the UART.

__irq void UART1_IRQHandler(void)
{
unsigned char dummy8;

/******************************/
/* RX handling */
/******************************/

while ((U1LSR & 0x01) != 0x00) /* test RDR (15.3.10) */
{ /* RX data ready */
dummy8 = U1RBR; /* get receiver FIFO data */
if (RX_offset < (RX_BUFFER_LENGTH-1))
{ /* buffer not full */
RX_buffer[RX_in_index] = dummy8; /* store into buffer */
RX_in_index++; /* ...and one more */
if (RX_in_index >= RX_BUFFER_LENGTH) RX_in_index = 0x0000;
RX_offset++;
}
else
{ /* oops, overflow */
UART1_RX_overflow_cntr++;
}
} /* end of while (RDR bit) */
/******************************/
/* TX handling */
/******************************/

if ((U1LSR & 0x20) != 0x00) /* test THRE bit */
{ /* we just know that FIFO */
UART1_TX_FIFO_cntr = 0x0000; /* is empty, not more (wrg) */
dummy8 = (unsigned char)U1IIR; /* clear int flag (15.3.5) */
} /* now FIFO is really empty */

while ((TX_offset != 0) && (UART1_TX_FIFO_cntr < UART1_TX_FIFO_LIMIT))
{ /* space to fill this FIFO */
U1THR = TX_buffer[TX_out_index]; /* so feed data */
TX_out_index++; /* ..and one more */
if (TX_out_index >= TX_BUFFER_LENGTH) TX_out_index = 0x0000;
TX_offset--; /* one less in circular buf */
UART1_TX_FIFO_cntr++; /* but one more in HW FIFO */
}

VICVectAddr = 0; /* ack interrupt */
}
Note that THRE bit is set if the FIFO is empty but if you write the first byte into FIFO there is a timeout to reset THRE (they thought this way you can write more bytes into FIFO without interrupt, wrg) but it's not an indicator to see just ONE byte is in FIFO. But with the help variable UART_TX_FIFO_cntr you don't have to consider this.

(if there are errors in my English, please excuse, here we speak swiss-german)

greeting Specky