andygock / avr-uart Goto Github PK
View Code? Open in Web Editor NEWAn interrupt driven UART Library for 8-bit AVR microcontrollers. Uses built-in UART with circular transmit and receive buffers.
License: Other
An interrupt driven UART Library for 8-bit AVR microcontrollers. Uses built-in UART with circular transmit and receive buffers.
License: Other
I've come across this issue while debugging the other issue I posted.
The problem is that the Indexes for the circular buffer are manipulated in functions that are outside the Interrupts and are also manipulated inside the interrupts.
Calculations such as:
tmphead = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;
are very dangerous and prone to errors caused by race conditions.
In particular when this code is compiled and ran it is broken down into a fetch of UART TX Head to a register and then an addition and then a bitwise operation.
The potential risk here, is having the interrupt fire after UART TX Head has been pulled to a register for caulcation and before the calculation is complete, an interrupt firing that halts processing of the main code, changes the value of UART Tx Head and returning.
At this point, the UART TX Head has changed value as a result of the interrupt.
However in the main code thread, UART TX Head is not re-read; it had already been read into a register. All further calculations will be done using a value that is outdated and will cause un wanted behaviour.
The correct way to do it, would be enclose all atomic calculations done in main code (not interrupts) in an "ATOMIC_BLOCK(ATOMIC_FORCEON)".
For example, the above code, should become:
ATOMIC_BLOCK(ATOMIC_FORCEON) {
tmphead = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;
}
to ensure the operation is performed atomically and that the value of UART TX Head is guaranteed to be the correct one.
This happens in several parts of the code so a code revision would be advisable.
ATOMIC_BLOCK is supported by including "util/atomic.h"
Thank you
Would it not be better to use ATOMIC_RESTORESTATE
? As in:
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
//do things atomically
}
This would avoid enabling interrupts when a user doesn't expect them to be on. I understand that the library requires interrupts, but maybe there are cases when the user has interrupts disabled and still wants to interact with the library in some way.
Hi,
The issue is that, if the buffer gets full, the calculation that you have at *_available returns 0 for empty but also returns 0 if the buffer is full because of the formula used:
The formula is
result = (UART_RX_BUFFER_MASK + UART_RxHead - UART_RxTail) % UART_RX_BUFFER_MASK
If RXHead = RXTail, it means RXHead-RxTail = 0, which in turn becomes: result = UART_RX_BUFFER_MASK % UART_RX_BUFFER_MASK which equals 0.
This means that any code relying on *available, when the buffer is full, will treat it as being empty and not pull any characters.
However the *putc functions can see the buffer is full and wll not receive any more data, efefctivelly making the UART stop working, without any notice.
A simpler way to rewrite available is:
result = (UART_RxHead != UART_RxTail);
I know that we are not supposed to come to a full buffer, but if we do, we should have a chance to understand it happened, as opposed to the UART mysteriously stopping to work.
This problem is particularly evident if you use high baud rates (250Kbps~500Kbps) and have a small buffer.
I would suggest implementing the change proposed on *available functions.
Thank you
Pedro.
Hi,
The following program does not work (tested on ATmega328P):
#include avr/interrupt.h>
#include "uart/uart.h"
int main(int argc, char *argv[])
{
uart_init(UART_BAUD_SELECT(115200, 16000000L));
sei();
uart_puts("Hello World!\r\n");
for(;;);
}
Upon opening the connection with picocom, garbage characters are printed (i.e. the baud rate is wrong). I suspect this is something to do with the way gcc is handling the integer division - i.e. it rounds the calculation down to 7 rather than the correct value of 8 (see table 20.6 on page 200 of the ATmega328 datasheet).
As a workaround using the line below works:
uart_init(UART_BAUD_SELECT(115200, 16000000L)+1);
Cheers,
Rob
There is a bug that I can't track down as yet with TX interrupts on an ATMega2560.
If I use USART0 I can get TX empty interrupts but if I use USART's 1 to 3 there is no interrupts from any of them.
The code looks OK from what I can see and everything checks out with the datasheets.
When #define USART0_ENABLED
is commented out in uart.h
following compilation error occurs:
uart.c:513:17: error: 'UART_RxHead' undeclared (first use in this function)
tmphead = ( UART_RxHead + 1) & UART_RX0_BUFFER_MASK;
^
Problem can be solved with adding preprocessor definitions to exclude all UART0 functions.
directly before line 484 add #if defined( USART0_ENABLED )
and
directly after line 757 add #endif /* defined( USART0_ENABLED ) */
Is there any way to disable reception of data? On my project I only send from MCU to another device. Would it save some memory/flash or would it be the same as setting RX buffer to zero?
This is not a real issues, more a request.
Please add support for ATmega1284P
On file usart.h i add this to work with my ATmega1284P
|| defined(__AVR_ATmega1284P__)
/* ATmega with two USART */
Hi,
should not it be a modulo operation here?
tmphead = (UART_RxHead + 1) & UART_RX0_BUFFER_MASK;
Kind regards, Frank
How to read a string send over uart and store in array using getc method please help..
Not able to receive full string some bytes goes missing
Please provide a simple code please
I am using a translator, so please understand. Thank you sir.
change the getc() code location
The code below is only applied to uart1, so it seems like it should be applied to other codes as well.
/* uart1_getc */
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
if (UART1_RxHead == UART1_RxTail) {
return UART_NO_DATA; /* no data available */
}
/* calculate / store buffer index */
tmptail = (UART1_RxTail + 1) & UART_RX1_BUFFER_MASK;
UART1_RxTail = tmptail;
}
/* uart0_getc */
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
if (UART_RxHead == UART_RxTail) {
return UART_NO_DATA; /* no data available */
}
}
/* calculate / store buffer index */
tmptail = (UART_RxTail + 1) & UART_RX0_BUFFER_MASK;
UART_RxTail = tmptail; // <- This is not atomic when LARGE_BUFFER.
I think it would be better to do something like below. It was also applied to peek.
/* uart1_getc */
#ifdef USART1_LARGE_BUFFER
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
#endif
{
if (UART1_RxHead == UART1_RxTail) {
return UART_NO_DATA; /* no data available */
}
/* calculate / store buffer index */
tmptail = (UART1_RxTail + 1) & UART_RX1_BUFFER_MASK;
UART1_RxTail = tmptail;
}
putc atomic
When LARGE_BUFFER
, UART1_TxHead
is uint16_t
. So the code below is not atomic.
UART1_TxHead = tmphead;
I think it would be good to change it atomically as follows.
#ifdef USART1_LARGE_BUFFER
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
#endif
{
UART1_TxHead = tmphead;
}
There are a lot of duplicates, so I think it would be better to do something like this:
#ifdef USART0_LARGE_BUFFER
#define UART0_ATOMIC_BLOCK ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
#else
#define UART0_ATOMIC_BLOCK
#endif
If you agree with this, I'll put in a pull request.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.