Creating UART that's not interrupt driven

Go To Last Post
17 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello all,

 

I'm creating a program on the Arduino Due which requires an interrupt to fire every 6.5 us. In its basic form, it reads a UART message and outputs an encoder trace. The problem I'm running into is that when the UART message is being read, the 6.5 us interrupt doesn't fire consistently. I suspect that it's because reading UART is generally interrupt driven on the Arduino. Is there a way to read UART without interrupts? I know the size of the UART messages. Could I simply keep peeking into the RHR and read only when a message is received by directly accessing the registers the UART is held in?

 

Thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You just check the RXC bit in the timer interrupt. If it is set then a character has arrived that should be lifted from UDR and processed otherwise just wait until the next 6.5us interrupt. BTW 6.5us is a very fast ISR rate. Arduino runs at 16MHz so there are 16 cycles in 1us. In 6.5us there are 104 cycles. Your ISr is going to take the best part of 20 of those to get in/out. I guess there's still time for other things but you do need to keep an eye on exactly what it is you do in the ISR as you could quickly eat the rest of the cycles available.

 

EDIT: sorry just realised the "Due" is the one based on SAM3 so forget the 16MHz and cycle count thing!

EDIT2 and once again this shows how this site is wrongly constructed - there really needs to be an "Arduino" section under "ARM" as well as this one under "AVR".

Last Edited: Mon. Feb 26, 2018 - 05:51 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mguieb wrote:

Could I simply keep peeking into the RHR and read only when a message is received by directly accessing the registers the UART is held in?

 

You can. But at 6.5us you've only got 104 machine cycles to play with. Can you get all your work done in that time? That probably equates to about 30 lines of C code assuming you've got no complex maths in there.

"This forum helps those that help themselves."

"How have you proved that your chip is running at xxMHz?" - Me

"If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Arduino runs at 16MHz

But he's talking about the Due:

 

 ... based on the Atmel SAM3X8E ARM Cortex-M3 CPU. ... 84 MHz clock

 

https://store.arduino.cc/arduino...

 

EDIT

 

I see Cliff has updated his post.

 

EDIT2 and once again this shows how this site is wrongly constructed

Really?  Ya don't say ...

 

surprise

 

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Mon. Feb 26, 2018 - 05:55 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

D'Oh! Like Cliff I missed it was a Due. Still, it means you've only got around 500 machine cycles to play with so my question still stands except you'll have about 130 lines of C with one operation per line.

"This forum helps those that help themselves."

"How have you proved that your chip is running at xxMHz?" - Me

"If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

Last Edited: Mon. Feb 26, 2018 - 05:56 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
But he's talking about the Due:
Yes, my edit at 5:51 beat this comment at 5:53. See my second EDIT2 - there should be a "boundary" between AVR and SAM (as there should be for ASF too).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes; you updated while I was still writing - see my update!

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mguieb wrote:
Could I simply keep peeking into the RHR

Not the RHR (Receive Holding Register) - you'd need to watch the RXRDY (Receive Ready) flag to know when a new value was received.

 

Note that this process is commonly know as "Polling" or "Polled" operation (as opposed to "interrupt-driven").

 

https://en.wikipedia.org/wiki/Polling_(computer_science)

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

clawson wrote:
once again this shows how this site is wrongly constructed

It's #8 on Johan's list: https://www.avrfreaks.net/forum/consolidating-site-errors-and-deficiencies

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Haha. I guess I should have mentioned SAM3x8e to better let everyone know it's different. It can also handle ASF as well. 

 

I've done a bit of research, and it seems that I won't need to worry about resetting RXRDY. It automatically resets when RHR is read. 

 

I also found this little gem floating around this forum.

uint8_t UART_GetChar(Uart *uart)
{
    while ((uart->UART_CR & UART_SR_RXRDY) == 0);
    return uart->UART_RHR;
}

Is it safe to assume that UART_RHR is FIFO?

 

 

From the datasheet, it says..

"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."

 

So to summarize, once a complete byte has been received, it is transferred to UART_RHR and RXRDY is set in UART_SR. When a second byte has been received, OVRE is set. 

 

My next question is... what happens to the second byte?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

mguieb wrote:
My next question is... what happens to the second byte?

 

Most likely it overwrites the first byte, thus losing the first byte that was not read fast enough.

 

Frankly, it sounds like proper design was not performed before writing code, this should have been considered before now.

 

Jim

 

Mission: Improving the readiness of hams world wide : flinthillsradioinc.com

Interests: Ham Radio, Solar power, futures & currency trading - whats yours?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

mguieb wrote:
what happens to the second byte?

Read it again:

 

"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."

So, if a new character is received before the last one was read from RHR, then the new one is put into RHR (thus overwriting the previous one).

 

OVRE tells you when this has happened - it's called an overrun error.

 

This is why a UART ISR needs to be as quick & simple as possible - to ensure that it can get the character out of RHR before another one arrives.

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks. I'm totally a noob when it comes to all of this. I asked because RHR is 32 bits big. I was hoping that the second byte would be written into the register after the first byte which would have made writing the code much easier.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

An interrupt every 6.5us is 150000 interrupts / s

This is doable, but needs carefull planning and programming.

 

"arduino" is certainly not the right environment for that.

<Rant>  One of the very stupid things about arduino is that they "pre-instanciate" a lot of (potentially unused) objects.

In normal C++ you can initialize peripherals (such as UsART) in the constructor of a class, which means that if you instanciate a class that peripheral is initialized and ready to use, but if you don't instantiate the class, then the object isn't even there and you can do whatever you want with that particular peripheral.

If "arduino" was written like this it would have been a MUCH better environment for beginners to learn coding.

Another thing I dislike very much about "arduino" is that they are themselves so ashamed (I presume they should be) of themseves that they don't even dare to call their "language" C++ or even C. The hacked together mix of C++ and C in the "arduino" framework is learning bad habits to new programmers. And because they are specifically targeting new programmers, they don't even realize they are being set up to have to unlearn those bad habits later to become decent programmers.

</Rant>

 

I have no love for "arduino", others opinions may vary.

If you want to keep using the "arduino" platform, then at least try out platformio. Platformio enables you to use a real IDE (default to atom, but Qt Creator, Eclipse or any you like can be used).  With a real IDE you can pretty easily examine all the innards of "arduino" and then you can decide for yourself what you do and/or do not like about it.

 

A quick hack is indeed to make sure that the interrupt you want serviced fast is the only interrupt which is enabled in your whole system.

You'll have to comb through all the arduino code. You will also have to disable the "milli second interrupt".

 

You can send uart data by just writing to UDR. (Oops, Atmel's SAM's have different names for the UsART registers).

And if you poll UDR fast enough you will not miss any received data (Check data overrun flag).

 

I really don't care much about "arduino" or what an "arduino due" is, but:

Acording to Awneil #4 your board has a SAM3x8E which should be a pretty capable processor.

I suspect that this processor has some interrupt controller with different interrupt priorities.

If so, you can simply set your most important interrupt to the highest priority and use interrupts for both your 6.5us and UsART.

 

octave:1> u=1e-6
u =    1.0000e-06
octave:3> 1/(6.5*u)
ans =    1.5385e+05
octave:4> M=1e6
M =  1000000
octave:5> 84*M/ans
ans =  546
octave:6> I love the touch of a decent calculator in the morning.

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you guys for all this. I'm learning a lot. 

 

I am beginning to get the UART to work. I'm able to read the incoming UART. However, I'm having trouble with setting and resetting the flags. (Some registers are read only. Others are write only. Etc.) Because the RXRDY is still set after the read, weird things happen. 

 

My program has become so low level that I'm not even using "arduino code" anymore. The Serial library is the only arduino library I'm somewhat using now, and I'm replacing those functions slowly but surely. I'm beginning to migrate everything into Visual Studios (since that's what a lot of people in my company uses), but now I'm running into other problems like which libraries to include and slight syntax differences. Overall, it's not too big of a deal, but I do wish that I had started this project on another IDE because it's so much nicer when it comes to debugging and much easier on the eyes.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mguieb wrote:
My program has become so low level that I'm not even using "arduino code" anymore. 

Then probably best to continue in the Cortex-M forum: https://community.atmel.com/foru...

 

Start your new thread with a summary & link back to this thread.

 

Give a link here to your new thread.

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...