I have a simple example where I configure the UART0 to interrupt on RX and TX.
The TX interrupt works great, but the RX interrupt handler hangs no matter what I put in it.
If I remove the interrupt handler then it correctly crashes. If I turn off the interrupts then it doesn't hang anymore. As soon as I turn on the interrupt and add an ISR, then it hangs when receiving a character. The watchdog then resets the device.
I examined the Arduino Core implementation and can't see anything they're doing that I'm not.
Any ideas?
/* USART Interrupts */
#define USART_RX_vect __vector_18
#define USART_UDRE_vect __vector_19
#define USART_TX_vect __vector_20
void usart_init_hardware(USART_CONFIG_T cfg)
{
usart_set_mode(cfg.mode);
usart_set_baud(cfg.baud);
usart_set_parity(cfg.parity);
usart_set_stop_bits(cfg.stop_bits);
usart_set_character_size(cfg.character_size);
if (USART_MODE_SYNCHRONOUS == cfg.mode) {
/* This bit is used for synchronous mode only.
* - ATmega328P Datasheet page 162 */
usart_set_clock_polarity(cfg.clock_polarity);
}
/* Enable interrupts on RX and TX */
UCSR0B.bits.RXCIEn = TRUE;
UCSR0B.bits.TXCIEn = TRUE;
UCSR0B.bits.UDRIEn = FALSE;
/* Enable TX and RX */
UCSR0B.bits.RXENn = TRUE;
UCSR0B.bits.TXENn = TRUE;
}
ISR(USART_RX_vect)
{
volatile U8_T c;
/* Clear interrupt flag */
c = UDR0.byte;
}
I tried removing everything from the ISR, which should cause a hang as the interrupt gets called repeatedly.
I then added the UDR0
retrieval back into the ISR, which should cure the hang as it disables the interrupt flag.
I tried manually disabling the interrupt flag.
Nothing appears to cure the hang.
UDR0
is a union which is mapped to 0xC6
typedef union {
struct {
VBOOL_T bit0 : 1;
VBOOL_T bit1 : 1;
VBOOL_T bit2 : 1;
VBOOL_T bit3 : 1;
VBOOL_T bit4 : 1;
VBOOL_T bit5 : 1;
VBOOL_T bit6 : 1;
VBOOL_T bit7 : 1;
} bits;
VU8_T byte;
} REGISTER_T;
extern volatile REGISTER_T UDR0;
and
SECTIONS
{
/* USART */
UCSR0A = 0xC0;
UCSR0B = 0xC1;
UCSR0C = 0xC2;
UBRR0 = 0xC4;
UDR0 = 0xC6;
...
The problem was that I defined my ISR in terms of interrupt
instead of signal
. I'm still researching what the implications of this difference are, but as far as I can tell, it's related to disabling global interrupts on entry.
#define ISR(vect) \
void vect(void) __attribute__((interrupt, used, externally_visible)); \
void vect(void)
should have been
#define ISR(vect) \
void vect(void) __attribute__((signal, used, externally_visible)); \
void vect(void)