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();
...
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
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.
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