MPC5643L UART interrupt handling

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

MPC5643L UART interrupt handling

910 Views
emagii
Contributor II

I have an bootloader which runs the UARTs in polled mode.
When I switch to the application, I want to run the UARTs in interrupt mode
which maintains S/W FIFOs in both directions.

After I initialize and enable interrupts, I get continuous interrupts on the receiver.
I have looked at the UARTCR and UARTSR, and cannot find a reason for this.

How can I stop the UART from generating continuous receive interrupts?

Here are the UARTCR/SR.

UARTCR = 233

TDFL    0
RDFL   0
RFBM  1 FIFO
TFBM   0 BUFFER
WL       01 8 bit
PC       00 No Parity?
RXEN  1 Enabled
TXEN  1 Enabled
PCE    0 ?
UART 1 UART Mode

UARTSR = 0x4C

<upper>   0
RPS        1 Receive Pin State
WUF        0 Wakeup
TO           1 Timeout
DRFRFE 1 FIFO Empty
DTFTFF  0 Not Completed
NF           0 No event

I enable the receiver before the transmitter, and in a previous revision without disabling global interruipts, I got this stream of receive interrupts before enabling the transmit interrupt.

I am also curious how the transmit interrupt should work in a real system.
I am reusing code for another processor.

This works as follows:
In idle mode, the transmitter is empty, which generates a transmit interrupt request.
The transmit interrupt is disabled as long as there are no characters to send..
The putchar routine inserts a byte in the S/W FIFO and enables the transmit interrupt.

The transmit interrupt will send characters as long as the S/W FIFO is not empty.
When the S/W FIFO is empty, then the transmit interrupt will turn off the transmit interrupt.

How do you do something similar with the MPC5643l?

#define ENABLE_UART_RX_INTERUPT(reg) reg->LINIER.B.DRIE = 1
#define ENABLE_UART_TX_INTERUPT(reg) reg->LINIER.B.DTIE = 1

void UART_enable_rx_irq(UART_channel_t *uart)
{
UART_reg_t* reg = uart->reg;
uart->rx.mode = BUFFERED_UART;
reg->LINIER.B.DRIE = 1
}

void UART_enable_tx_irq(UART_channel_t *uart)
{
UART_reg_t* reg = uart->reg;
uart->tx.mode = BUFFERED_UART;
reg->LINIER.B.DTIE = 1;
}

void UART_init(UART_channel_t *uart, uint32_t brs )
{

void UART_init(UART_channel_t* uart, const uint32_t speed) {
UART_reg_t* reg = uart->reg;
uint32_t br;
ASSERT( reg != 0ul, "Invalid linflex pointer");

/* enter INIT mode */
reg->LINCR1.R = 0x0081u; /* SLEEP=0, INIT=1 */

while (0x1000u != (reg->LINSR.R & 0xf000u)) {
/* wait for the INIT mode */
}

reg->UARTCR.B.UART = 1u; /* make the LINflex just be a UART */
reg->UARTCR.B.WL0 = 1u; /* 8 bits */
reg->UARTCR.B.WL1 = 0u; /* 4 bytes buffer */
reg->UARTCR.B.PCE = 0u; /* no parity */
reg->UARTCR.B.PC0 = 0u;
reg->UARTCR.B.PC1 = 0u; /* no fixed parity */
reg->UARTCR.B.TFBM = 1u; /* FIFO mode = 0 for TX */
reg->UARTCR.B.RFBM = 1u; /* FIFO mode = 0 for RX */

reg->UARTCR.B.TDFL_TFC = 4u; /* Number of bytes to transmit = 1 */
reg->UARTCR.B.RDFL_RFC0 = 4u; /* Number of bytes to receive = 1 */

br = 120000000u / speed; /* assuming 120 MHz peripheral set 1 ck */

reg->LINFBRR.R = br & 0xfu; /* fractional baudrate */
reg->LINIBRR.R = br >> 4; /* whole baudrate */

reg->LINIER.R = 0u; /* disable all interrupts */

/* enter NORMAL mode */
reg->LINCR1.R = 0x0080u; /* BYPASS_FILTER=1, INIT=0 (this clears any loopback) */

/* these bits work outside of init mode */
reg->UARTCR.B.TXEN = 1u; /* TX enabled */
reg->UARTCR.B.RXEN = 1u; /* RX enabled */

/**
*
*/
reg->LINCR1.R = 0x0081u; /* SLEEP=0, INIT=1 */

while (0x1000u != (reg->LINSR.R & 0xf000u)) {
/* wait for the INIT mode to start. */
}
reg->UARTCR.B.RFBM = 4u;
reg->UARTCR.B.TFBM = 4u;
reg->DMATXE.R = 0u;

reg->LINCR1.R = 0x0080u; /* Leave INIT mode. */
TIMER_delay(10);
}

void UART_rx_interrupt(UART_channel_t *uart)
{
UART_reg_t* reg = uart->reg;
uint8_t byte;
uint32_t rx_length;
uint32_t rx_size;
uint32_t flags;

byte = (uint8_t)(reg->RXD & 0x000000FFU); // BDRM.B.DATA4
flags = reg->FLAGS;
flags &= UART_ERRORS;
reg->FLAGS = (uint32_t) flags;

rx_length = uart->rx.length;
rx_size = uart->rx.size;
if (rx_length < rx_size ) { /* We have room for one more char */
uint32_t *rx_wr_p;
uint32_t rx_wr;

rx_wr_p = (uint32_t *)&uart->rx.wr; /* It is not volatile in the IRQ */
rx_wr = *rx_wr_p;
uart->rx.data[rx_wr++] = byte;
rx_wr &= uart->rx.mask;
*rx_wr_p = rx_wr;

uart->rx.length++;
} else {
uart->rx.dropped++;
}

if (FRAMING_ERROR(flags)) {
uart->framing_error++;
}
if (OVERRUN_ERROR(flags)) {
uart->overrun_error++;
}
if (PARITY_ERROR(flags)) {
uart->parity_error++;
}
uart->counter++;
}

/**
* @fn void UART_tx_interrupt(UART_channel_t *uart)
* @brief UART transmit interrupt routine
* @retval None
*/
void UART_tx_interrupt(UART_channel_t *uart)
{
UART_reg_t* reg = uart->reg;
uint8_t byte;
if (uart->tx.length > 0U) {
uint32_t *tx_rd_p;
uint32_t tx_rd;

tx_rd_p = (uint32_t *) &uart->tx.rd; /* It is not volatile in the IRQ */
tx_rd = *tx_rd_p;

byte = uart->tx.data[tx_rd++];
reg->TXD = (uint32_t) byte; // BDRL.B.DATA0

tx_rd &= uart->tx.mask;
*tx_rd_p = tx_rd;

uart->tx.length--;
} else {
/* Nothing to send */
CLEAR_TX_INTERRUPT(reg);
}
}

#define UART2_RX_VECTOR (99U)
#define UART2_TX_VECTOR (100U)
#define UART2_RX_PRIO (6U)
#define UART2_TX_PRIO (8U)
#define UART_RX_ACK (4U)
#define UART_TX_ACK (2U)

void UART2_rxIrq(void)
{
UART_channel_t* uart = uart2;
uart->reg->UARTSR.R = UART_RX_ACK;
UART_rx_interrupt(uart2);
}

void UART2_txIrq(void)
{
UART_channel_t* uart = uart2;
uart->reg->UARTSR.R = UART_TX_ACK;
UART_tx_interrupt(uart2);
}

main init.
{
__disable_interrupt();
// Init device structure, does not touch UART
UART_channel_init("UART2", &LINFLEX1, uart2, u2_rx, U2_RX_SIZE, u2_tx, U2_TX_SIZE);
// H/W reinit
UART_init(uart2, B875000);
INTC_InstallINTCInterruptHandler(UART2_rxIrq, UART2_RX_VECTOR,UART2_RX_PRIO);
INTC_InstallINTCInterruptHandler(UART2_txIrq, UART2_TX_VECTOR,UART2_TX_PRIO);
INTC.CPR.B.PRI = 0;
UART_enable_rx_irq(uart2);
UART_enable_tx_irq(uart2);
__enable_interrupt();

...

 

 

Tags (3)
0 Kudos
2 Replies

880 Views
PetrS
NXP TechSupport
NXP TechSupport

Hi,

RxFIFO and TxFIFO interrupts of LinFlex in UART mode works in the opposite way 
- DRFRFE is set when the Rx FIFO is EMPTY
- DTFTFF is set when the Tx FIFO is FULL.
Moreover both DRFRFE and DTFTFF are read only in FIFO mode.

So I would recommend to use either polling mode or interrupts with buffer mode.

BR, Petr

0 Kudos

886 Views
emagii
Contributor II

I have managed this to work, by making the following modifications to UART_init.

reg->UARTCR.B.TFBM = 0u; /* Buffered mode = 0 for TX */
reg->UARTCR.B.RFBM = 0u; /* Buffered mode = 0 for RX */
reg->UARTCR.B.TDFL_TFC = 0u; /* Number of bytes to transmit = 1 */
reg->UARTCR.B.RDFL_RFC0 = 0u; /* Number of bytes to receive = 1 */

This disables the FIFO which is undesirable in high speed transfers.

Seems to me that the spec of the UART is very strange.

  • You do not expect to get receive interrupts without incoming characters.
  • You expect to have an active transmit interrupt if the FIFO is empty.

It seems like the FIFOs are useless in interrupt mode. 

What is the expected structure of a UART driver in interrupt mode with FIFO enabled?.

Right now, I am forced to keep track if I am sending or not
The UART write character function will have to check a "sending" flag.
The function will place the character in a S/W FIFO.
If the "sending" flag is not set, the character has to be written to the UART.
The flag is then set.

The UART send interrupt will read a character from the S/W FIFO.
If empty, the flag will be cleared.

"Normal" UARTs will assert the TX interrupt if the FIFO is empty.
The Write character function will just enable the TX interrupt at the end.

 

 

, and if I am sending

 

0 Kudos