Coder Social home page Coder Social logo

avr-uart's Introduction

avr-uart

An interrupt driven UART Library for 8-bit AVR microcontrollers.

Maintained by Andy Gock.

https://github.com/andygock/avr-uart

Derived from original library by Peter Fleury.

Interrupt driven UART library using the built-in UART with circular transmit and receive buffers.

An interrupt is generated when the UART has finished transmitting or receiving a byte. The interrupt handling routines use circular buffers for buffering received and transmitted data.

Setting up

Define USARTs enabled and buffer sizes

The UART_RXn_BUFFER_SIZE and UART_TXn_BUFFER_SIZE symbols define the size of the circular buffers in bytes. These values must be a power of 2. You may need to adapt this symbols to your target and your application by adding into your compiler options:

-DUART_RXn_BUFFER_SIZE=nn -DUART_TXn_BUFFER_SIZE=nn

RXn and TXn refer to the UART number, for UART3 with 128 byte buffers, add:

-DUART_RX3_BUFFER_SIZE=128 -DUART_TX3_BUFFER_SIZE=128

UART0 is always enabled by default, to enable the other available UARTs, add the following to your compiler's symbol options for the relevant UART (also known as USART) number.

-DUSART1_ENABLED -DUSART2_ENABLED -DUSART3_ENABLED

To enable large buffer support (over 256 bytes, up to 2^15 bytes) use:

-DUSARTn_LARGE_BUFFER

Where n is the USART number. The maximum buffer size is 32768 bytes.

This library supports AVR devices with up to 4 hardware USARTs.

Define CPU frequency

Define F_CPU in your Makefile or compiler examples. Example, if you're running a 8 MHz clock, then use:

-DF_CPU=8000000UL

Compiler flags

AVR/GNU C compiler requires the -std=gnu99 flag.

Documentation

Doxygen based documentation can be viwed at:

Notes

Buffer overflow behaviour

When the RX circular buffer is full, and it receives further data from the UART, a buffer overflow condition occurs. Any new data is dropped. The RX buffer must be read before any more incoming data from the UART is placed into the RX buffer.

If the TX buffer is full, and new data is sent to it using one of the uartN_put*() functions, this function will loop and wait until the buffer is not full any more. It is important to make sure you have not disabled your UART transmit interrupts (TXEN*) elsewhere in your application (e.g with cli()) before calling the uartN_put*() functions, as the application will lock up. The UART interrupts are automatically enabled when you use the uartN_init() functions. This is probably not the idea behaviour, I'll probably fix this some time.

For now, make sure TXEN* interrupts are enabled when calling uartN_put*() functions. This should not be an issue unless you have code elsewhere purposely turning it off.

avr-uart's People

Contributors

andygock avatar baghayi avatar baldowl avatar dlobato avatar maugsburger avatar raffaello avatar smdjeff avatar thiefmaster avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

avr-uart's Issues

Support for AVR_ATmega1284P

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 */

When USART0 is not enabled compile fails

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 ) */

Reading string from uart

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

USART 1-3 TX empty Interrupt does not fire

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.

Atomic operations should use ATOMIC_RESTORESTATE

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.

Disable RX

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?

Buffer Indexes are not atomic when uint16_t(LARGE_BUFFER)

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.

Bug in *_available function: returns 0 if the buffer is full, halting communication

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.

Operations manipulating Buffer Indexes are not atomic and therefore prone to Race conditions

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

Baud rate calculation for 115.2k incorrect

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.