USART0 Recieve Interrupt does not return.

Started by userpaul2 November 21, 2007
When I enable a Uart recieve interrupt, it either continually
interrupts, or if I clear the interrupt in the AIC with:
AT91C_BASE_AIC->AIC_EOICR = 0; then execution hangs.
Both situations prevent the running of both the program and
higher priority interrupts.

Does anybody know why this is?
Is it because the PDC HAS to be used with UART recieve interrupt?

#define BR 115200 // Baud Rate
#define BRD (MCK/16/BR) // Baud Rate Divisor
void USART0_handler() {

volatile unsigned int dummy;

AT91F_PIO_SetOutput(AT91C_BASE_PIOB, LED1|LED2|LED3|LED4); // Turn Off
AT91F_PIO_ClearOutput(AT91C_BASE_PIOB,LED1); // LED 1

dummy = AT91C_BASE_US0->US_CSR;

AT91F_PIO_ClearOutput(AT91C_BASE_PIOB,LED2); // LED 2

AT91C_BASE_US0->US_CR = AT91C_US_RSTSTA;

AT91F_PIO_ClearOutput(AT91C_BASE_PIOB,LED3); // LED 3

// AT91C_BASE_AIC->AIC_EOICR = 0;

AT91F_PIO_ClearOutput(AT91C_BASE_PIOB,LED4); // LED 4
}
void InitialiseUART() { // Initialize Serial Interface

AT91F_PMC_EnablePeriphClock ( AT91C_BASE_PMC, 1<
*AT91C_PIOA_PDR = AT91C_PA0_RXD0 | // Enable RxD0 Pin
AT91C_PA1_TXD0; // Enable TxD0 Pin

*AT91C_PIOA_PDR = AT91C_PA3_RTS0 | // Enable RTS0 Pin
AT91C_PA4_CTS0; // Enable CTS0 Pin

AT91C_BASE_US0->US_CR = AT91C_US_RSTRX | // Reset Receiver
AT91C_US_RSTTX | // Reset Transmitter
AT91C_US_RXDIS | // Receiver Disable
AT91C_US_TXDIS; // Transmitter Disable

AT91C_BASE_US0->US_MR = AT91C_US_USMODE_NORMAL | // Normal Mode
AT91C_US_CLKS_CLOCK | // Clock = MCK
AT91C_US_CHRL_8_BITS | // 8-bit Data
AT91C_US_PAR_NONE | // No Parity
AT91C_US_NBSTOP_1_BIT; // 1 Stop Bit

AT91C_BASE_US0->US_BRGR = BRD; // Baud Rate Divisor
AT91C_BASE_US0->US_CR = AT91C_US_RXEN | // Receiver Enable
AT91C_US_TXEN; // Transmitter Enable

AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_US0, 3,
AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, USART0_handler);
AT91C_BASE_US0->US_IER = AT91C_US_RXBUFF;
AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_US0);

}
A few things wrong there, this can be confusing at the start :

> AT91C_BASE_AIC->AIC_EOICR = 0; then execution hangs.
You only do this when you have SW handler, and call your ISR from there.
Note that this should be the LAST thing you do AFTER returning from your ISR.
With HW handler this is taken care of.

> Is it because the PDC HAS to be used with UART recieve interrupt?
No, this is optional and not necessary in your case.

> When I enable a Uart recieve interrupt, it either continually
> interrupts, or if I clear the interrupt in the AIC with:
This is because you're not handling the interrupt properly. Read the users' guide on
USART and AIC.
Basically first of all you need to distinguish between TX and RX interrupt.
Secondly, if you indeed have an RX interrupt, you need to clear the interrupt by reading RHR
(which is why you get continuous interrupts)

An example (using SW AIC handler, excerpt from CrossWorks ARM code, adjust for IAR lib)

void uart0_isr (void)
{
UINT status = US0_CSR;

if (status & US_TXRDY) // Data to TX ?
{
// yes, check if more data to send
if (rs232_tx_head != rs232_tx_tail)
{
US0_THR = rs232_tx[rs232_tx_tail++];
rs232_tx_tail %= RS232_SIZE;
rs232_tx_chars--; // update # of TX
chars
}
else
{
CLRB(ext_flags,COMM_TX_RUNNING); // Done flushing TX buffer
US0_IDR = US_TXRDY; // clear transmit interrupt
}
}

// check for receive errors
if (status & (US_RXBRK | US_OVRE | US_FRAME | US_PARE))
US0_CR = US_RSTSTA; // clear them

// check for RX character ready
if (status & US_RXRDY)
{
char ch = US0_RHR; // buffer the RXd char
// DO YOUR THING HERE for RX INTs
}

}

Best Regards,
Kris

-----Original Message-----
From: A... [mailto:A...] On Behalf Of userpaul2
Sent: Wednesday, 21 November 2007 9:42 PM
To: A...
Subject: [AT91SAM] USART0 Recieve Interrupt does not return.

When I enable a Uart recieve interrupt, it either continually
interrupts, or if I clear the interrupt in the AIC with:
AT91C_BASE_AIC->AIC_EOICR = 0; then execution hangs.
Both situations prevent the running of both the program and
higher priority interrupts.

Does anybody know why this is?
Is it because the PDC HAS to be used with UART recieve interrupt?

#define BR 115200 // Baud Rate
#define BRD (MCK/16/BR) // Baud Rate Divisor
void USART0_handler() {

volatile unsigned int dummy;

AT91F_PIO_SetOutput(AT91C_BASE_PIOB, LED1|LED2|LED3|LED4); // Turn Off
AT91F_PIO_ClearOutput(AT91C_BASE_PIOB,LED1); // LED 1

dummy = AT91C_BASE_US0->US_CSR;

AT91F_PIO_ClearOutput(AT91C_BASE_PIOB,LED2); // LED 2

AT91C_BASE_US0->US_CR = AT91C_US_RSTSTA;

AT91F_PIO_ClearOutput(AT91C_BASE_PIOB,LED3); // LED 3

// AT91C_BASE_AIC->AIC_EOICR = 0;

AT91F_PIO_ClearOutput(AT91C_BASE_PIOB,LED4); // LED 4
}
void InitialiseUART() { // Initialize Serial Interface

AT91F_PMC_EnablePeriphClock ( AT91C_BASE_PMC, 1<
*AT91C_PIOA_PDR = AT91C_PA0_RXD0 | // Enable RxD0 Pin
AT91C_PA1_TXD0; // Enable TxD0 Pin

*AT91C_PIOA_PDR = AT91C_PA3_RTS0 | // Enable RTS0 Pin
AT91C_PA4_CTS0; // Enable CTS0 Pin

AT91C_BASE_US0->US_CR = AT91C_US_RSTRX | // Reset Receiver
AT91C_US_RSTTX | // Reset Transmitter
AT91C_US_RXDIS | // Receiver Disable
AT91C_US_TXDIS; // Transmitter Disable

AT91C_BASE_US0->US_MR = AT91C_US_USMODE_NORMAL | // Normal Mode
AT91C_US_CLKS_CLOCK | // Clock = MCK
AT91C_US_CHRL_8_BITS | // 8-bit Data
AT91C_US_PAR_NONE | // No Parity
AT91C_US_NBSTOP_1_BIT; // 1 Stop Bit

AT91C_BASE_US0->US_BRGR = BRD; // Baud Rate Divisor
AT91C_BASE_US0->US_CR = AT91C_US_RXEN | // Receiver Enable
AT91C_US_TXEN; // Transmitter Enable

AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_US0, 3,
AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, USART0_handler);
AT91C_BASE_US0->US_IER = AT91C_US_RXBUFF;
AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_US0);

}
Thanks, that's made it a bit more clear.
I thought i wasn't clearing the interrupt, but couldn't figure why.

Cheers :)