Go Down

Topic: HELP: Reading UART From Serial Port Without Using Interrupts (Read 760 times) previous topic - next topic

anonymousUser

Hello all,

As the subject states, I would like to read UART without using interrupts.

Within my program, I'm essentially polling the UART message by using Serial.available() each main loop iteration. I also know how big the UART messages are (2 bytes).

Is there any way to directly access the message in the UART_RHR? And are there any flags I need to be aware of resetting/setting once I've read the UART message?


Thanks in advance

AdderD

Look at the file UARTClass.cpp within the Arduino core files for the Due. It'll be somewhere like

<UserDirectory>/AppData/Local/Arduino15/packages/arduino/hardware/sam/1.6.11/cores/arduino

In there you can see how it sets up the serial port and how the interrupt works. Basically copy this stuff into your sketch and do what the interrupt handler does.

But, to more directly answer your question:
read UART_SR to a variable to reset the status flags
Then if UART_SR_RXRDY is set you read from UART_RHR

There's your byte.

You probably need to #include "UARTClass.h" in your sketch to make sure you've got access to all the register definitions. And, you'll have to go searching to find a way to snag the proper pointer to the Serial hardware so you can do pUart->UART_RHR and all that. You won't normally have access to the _pUart pointer in your sketch so you'll have to recreate it.

ard_newbie

read UART_SR to a variable to reset the status flags
Reading UART_SR will NOT reset the status flags. The bit RXRDY in UART_SR is automatically cleared in UART_SR when the receive holding register UART_RHR is read.

westfw

You'll have to first reconfigure the UART to turn off the interrupts that the arduino core turns on.

anonymousUser

Thank you all. You guys are the best!

Reading UART_SR will NOT reset the status flags. The bit RXRDY in UART_SR is automatically cleared in UART_SR when the receive holding register UART_RHR is read.
Thanks. I was wondering if I would have to manually clear any bits when I read.

I found this while doing some research.

< /   while ((uart->UART_CR & UART_SR_RXRDY) == 0);
    return uart->UART_RHR; />

To me that hints that UART_RHR is FIFO. Is my assumption correct?

I've also read this in the data sheet...
"When a complete character is received, it is transferred to the UART_RHR and the RXRDY status bit in UART_SR
(Status Register) is set. The bit RXRDY is automatically cleared when the receive holding register UART_RHR is
read.

If UART_RHR has not been read by the software (or the Peripheral Data Controller or DMA Controller) since the
last transfer, the RXRDY bit is still set and a new character is received, the OVRE status bit in UART_SR is set.
OVRE is cleared when the software writes the control register UART_CR with the bit RSTSTA (Reset Status) at 1."

Because my message is 2 bytes, I might also have to worry about the OVRE status bit depending on the performance of my program. What happens to the second byte in this case? Does it also get transferred into the RHR?

PS. I might be overthinking this, but I do like learning exactly how this works.

westfw

Quote
To me that hints that UART_RHR is FIFO. Is my assumption correct?
No.  :-(

Quote
What happens to the second byte in this case? Does it also get transferred into the RHR?
Yes, apparently.  Overwriting the first character :-(

This is actually somewhat unusual.  Many UARTs that I've used will not transfer data to the RHR when it is "full", giving you essentially a two-byte buffer.   The AVR has a two byte FIFO for the RHR, AND doesn't transfer from the RSR to the RHR if there is no room.   I'm not sure whether the SAM3X UART is especially stupid, or whether this was a design choice that makes working with DMA easier...

Here's a little test program.  It disables ALL interrupts and waits while you send data to it, so the data buffering (if any) is only what is done in the hardware.   If you send "ABCDE" to an Arduino Uno, you get "ABE" out.  If you do that on a Due, you just get "E"...

Code: [Select]

void setup() {
  Serial.begin(9600);
}
int c;
void loop() {
  Serial.println("Waiting for input"); Serial.flush();
  noInterrupts();
  for (volatile int32_t i = 0; i < F_CPU; i++) ; // delay for about 10s
  interrupts();
  Serial.println("Woke up.  Queued on Serial Port:");
  while ((c = Serial.read()) > 0)
    Serial.println((char)c);
}



anonymousUser

Ooof, Yes. I'm having lots of problems with this code. It reads information, but there's a lot of weird behavior.

Code: [Select]

char charArray[2] = {0,0};

...

while(1) {
    if ((UART_SR_RXRDY==1) && (i == 0)) {
      charArray[i] = UART->UART_RHR; //read byte
      i++;
    }
    else if ((UART_SR_RXRDY==1) && (i == 1)) {
      charArray[i] = UART->UART_RHR;
      i = 0;
    }
    UART->UART_CR = UART_CR_RSTSTA; //clears errors
}




1. When I run the program, it enters the if/else statement even when there's no incoming message. This makes me think that UART_SR_RXRDY flag remains set even after UART_RHR is read.
2. The 1 byte long message is sometimes read at the wrong frame.
Sending 0100 0001 can potentially be read as 0000 0101 or 0100 0001 or 0101 0000.
3. When sending a 2 byte long message, one of the bytes gets overwritten or ignored. I'll only get the first byte or the second byte loaded into charArray.

ard_newbie

I would like to read UART without using interrupts.

I don't see any good reason for that.

However, this basic code should do this job :

Code: [Select]

void setup() {
 
  Serial.begin(250000);
  NVIC_DisableIRQ(UART_IRQn);

}

void loop() {

  char data;
    while ((UART->UART_SR & UART_SR_RXRDY) == 0);
    data = UART->UART_RHR;

    while ((UART->UART_SR & UART_SR_TXRDY) == 0);
      UART->UART_THR = data;

}

anonymousUser

Thank you so much! That fixes the majority of the problems! May I ask what the meaning of this line of code is?

Code: [Select]


while((UART->UART_SR & UART_SR_RXRDY) == 0);



I'm still occasionally getting this problem, though.

3. When sending a 2 byte long message, one of the bytes gets overwritten or ignored. I'll only get the first byte or the second byte loaded into charArray.
This is what I'm sending to RX0.

Code: [Select]


  Serial.write('A');
  Serial.write('1');
  delay(3000);



This is what the Due is reading.

Code: [Select]


A111A1AA1A1



It sometimes reads the entire UART message and relays the information correctly, but the majority of the time, it reads only one byte and ignores the other.

anonymousUser

It would also probably be helpful to show what the Arduino Due code looks like right now.

Code: [Select]


  while (i < 2) {

    while ((UART->UART_SR & UART_SR_RXRDY) == 0);
    charArray[i] = UART->UART_RHR;

    while ((UART->UART_SR & UART_SR_TXRDY) == 0);
    UART->UART_THR = charArray[i];

    i++;

  }

  i = 0;



Thanks again!

anonymousUser

Never mind! I got it to work. It was just something wrong with how I configured the UART.

Go Up