UART Interrupts disabling I/O on Sam3X8E/ Arduino Due

2.3k Views Asked by At

I am starting to use an Arduino Due for some project work which requires a UART and am confused by what looks like an interaction between UART interrupts and I/O.

My first piece of code was a small routine to set up the UART, send out data continuously by loading the transmit buffer upon receipt of a TXBE interrupt. I had the UART output hooked up to an oscilloscope and had set another I/O pin as a general purpose output which would flip state and therefore be used to trigger the scope when the transmit buffer was reloaded. Problem was that I was seeing UART data and it looked good, but the I/O wasn't flipping. At this point my loop() routine was empty so I set up another output port and in loop() just toggled its state as a sanity check. Still no output except for the UART.

Here's the code that I ended up with:

uint32_t tempo; // 32-bit temporary variable
boolean flag = true;

void UART_Handler(void) {
  REG_UART_THR = 0x6DL; // load data into the transmit buffer
  if (flag) {
    REG_PIOD_SODR = 0x02L; // drive PD1 high
    flag = false;
  } else {
    REG_PIOD_CODR = 0x02L; // drive PD1 low
    flag = true;
  }
}

void setup() {
  // set up the UART I/O
  REG_PIOA_IDR = 0x0300L; // disable interrupts on PA8 and PA9
  tempo = REG_PIOA_ABSR; // get the current settings of the AB select register
  REG_PIOA_ABSR = tempo & 0xFFFFFCFF; // set PA8 and PA9 to peripheral A control
  REG_PIOA_PDR = 0x0300L; // disable parallel I/O for PA8 and PA9
  NVIC_EnableIRQ(UART_IRQn); // enable UART interrupts in NVIC
  // now set up the UART
  tempo = REG_PMC_PCSR0; // get the current settings of the peripheral clock register 0
  REG_PMC_PCER0 = tempo | 0x0100L; // enable the UART clocks
  REG_UART_CR = 0x0CL; // reset UART receiver and transmitter
  REG_UART_MR = 0x0800L; // set to normal outputs with no parity
  REG_UART_BRGR = 0x89L; // baud rate set to 38400
  REG_UART_IDR = 0x1FBL; // disable all UART interrupts
  REG_UART_IER = 0x0800L; // enable TXBUFE interrupt
  REG_UART_CR = 0x50L; // enable UART receiver and transmitter
  // set up the debug outputs
  REG_PIOD_IDR = 0x03L; // disable interrupts on PD0 and PD1
  REG_PIOD_PER = 0x03L; // enable parallel I/O for PD0 & PD1
  REG_PIOD_OER = 0x03L; // set PD0 & PD1 output enabled
  REG_PIOD_CODR = 0x03L; // drive PD0 & PD1 low
}

void loop() // run over and over
{
   REG_PIOD_SODR = 0x01L; // drive PD0 high
   delay(1);
   REG_PIOD_CODR = 0x01L; // drive PD0 low 
   delay(1);
}

the scope output can be viewed at http://www.iwanczuk.com/temp/scope1.png (don't have enough reputation here to post images!).

After staring at things for while and getting no insight I disabled the TXBUFE interrupts by commenting out the line REG_UART_IER = 0x0800L; // enable TXBUFE interrupt and the toggling of PortD1 was then visible but obviously no UART output (see http://www.iwanczuk.com/temp/scope2.png). It seems that the two are mutually exclusive which would be just silly if it were true. I am sure I'm missing something but I can't see or find what it is.

I have read the SAM3X8E data sheet to see if there's anything obvious I'm missing and if there is I can't see it. I've also done what I think are relevant web searches with no luck in finding a solution. I have also tried using general purpose outputs for the two outputs on port A and port D and have tried this on two Arduino Due boards with similar results on both.

Anyone have any ideas what I might be doing wrong? Thanks in advance.

2

There are 2 best solutions below

0
On

I just realised what could be the real error at the source of my problem. The UART interrupt register descriptions talk about the TXBUFE bit in the context of transmit buffer empty and so my assumption was that this is the bit that tells me when I can put another byte into the transmit holding register. However the UART Status Register description say that the TXBUFE bit is "the buffer full signal from the transmitter PDC channel". The latter puts a whole different slant on what this bit does. According to the UART Status Register description the bit I need to be looking at is the TXRDY bit!

0
On

Well, I have got to the bottom of this problem. Not sure it's the best answer but it's a solution. The long and short of it is to avoid TXBE interrupts. If I use TXEMPTY interrupts instead it works fine.

A line on page 168 of the Atmel data sheet says (sic) "A interrupt can enter pending state even it is disabled" so I wondered if the problem with TXBE was because I was not clearing the pending interrupt before or even inside the ISR so I added NVIC_ClearPendingIRQ(UART_IRQn); at the start of the ISR and also just before I enabled the TXBE interrupt but the (mis)behaviour didn't change.

The operation of TXEMPTY is still a little odd (to me) because it appears that the interrupt is generated by the transmit shift register just being empty, not when it goes empty. If you enable interrupts without having loaded the transmit buffer you will immediately get an interrupt. Some may like this "self=priming' behaviour, but it doesn't do it for me. I am writing my sending routine such that the TXEMPTY interrupt is not enabled until the transmitter has been loaded with the first byte to be sent.

Based on this post on the Arduino Forum: http://forum.arduino.cc/index.php?topic=186388.0 I presume that the USARTs have a similar issue.

Hopefully this will help others.