/**
* \file
*
* \brief megaAVR STK600 UART interrupt example
*
* Copyright (c) 2014-2015 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/**
* \mainpage
* \section board STK600 development board
* \section intro Introduction
* This example demonstrates how to use the megaAVR UART with interrupts.
*
* \section files Files:
* - mega_uart_interrupt_example.c: megaAVR STK600 UART interrupt example
*
* \section exampledescription Brief description of the example application
* This application will initialize the UART, send a string and then receive
* it and check if it is the same string as we sent.
*
* \note The RX and TX pins should be externally connected in order to pass the
* test.
*
* \section compinfo Compilation Info
* This software was written for the GNU GCC
* for AVR. \n
* Other compilers may or may not work.
*
* \section contactinfo Contact Information
* For further information, visit
* Atmel.\n
*/
/*
* Support and FAQ: visit Atmel Support
*/
// _ASSERT_ENABLE_ is used for enabling assert, typical for debug purposes
#define _ASSERT_ENABLE_
#include
#include "compiler.h"
/**
* \def BUFFER_SIZE
* \brief The size of the UART buffer
*/
#define BUFFER_SIZE 20
// set the correct BAUD and F_CPU defines before including setbaud.h
#include "conf_clock.h"
#include "conf_uart.h"
/**
* \name avr_libc_inc avr libc include files
* @{
*/
#include
#include
//! @}
#include "ring_buffer.h"
// buffers for use with the ring buffer (belong to the UART)
uint8_t out_buffer[BUFFER_SIZE];
uint8_t in_buffer[BUFFER_SIZE];
// the string we send and receive on UART
const char test_string[] = "Hello, world!";
//! ring buffer to use for the UART transmission
struct ring_buffer ring_buffer_out;
//! ring buffer to use for the UART reception
struct ring_buffer ring_buffer_in;
/**
* \brief UART data register empty interrupt handler
*
* This handler is called each time the UART data register is available for
* sending data.
*/
ISR(UART0_DATA_EMPTY_IRQ)
{
// if there is data in the ring buffer, fetch it and send it
if (!ring_buffer_is_empty(&ring_buffer_out)) {
UDR0 = ring_buffer_get(&ring_buffer_out);
}
else {
// no more data to send, turn off data ready interrupt
UCSR0B &= ~(1 << UDRIE0);
}
}
/**
* \brief Data RX interrupt handler
*
* This is the handler for UART receive data
*/
ISR(UART0_RX_IRQ)
{
ring_buffer_put(&ring_buffer_in, UDR0);
}
/**
* \brief Initialize the UART with correct baud rate settings
*
* This function will initialize the UART baud rate registers with the correct
* values using the AVR libc setbaud utility. In addition set the UART to
* 8-bit, 1 stop and no parity.
*/
static void uart_init(void)
{
#if defined UBRR0H
// get the values from the setbaud tool
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
#else
#error "Device is not supported by the driver"
#endif
#if USE_2X
UCSR0A |= (1 << U2X0);
#endif
// enable RX and TX and set interrupts on rx complete
UCSR0B = (1 << RXEN0) | (1 << TXEN0) | (1 << RXCIE0);
// 8-bit, 1 stop bit, no parity, asynchronous UART
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00) | (0 << USBS0) |
(0 << UPM01) | (0 << UPM00) | (0 << UMSEL01) |
(0 << UMSEL00);
// initialize the in and out buffer for the UART
ring_buffer_out = ring_buffer_init(out_buffer, BUFFER_SIZE);
ring_buffer_in = ring_buffer_init(in_buffer, BUFFER_SIZE);
}
/**
* \brief Function for putting a char in the UART buffer
*
* \param data the data to add to the UART buffer and send
*
*/
static inline void uart_putchar(uint8_t data)
{
// Disable interrupts to get exclusive access to ring_buffer_out.
cli();
if (ring_buffer_is_empty(&ring_buffer_out)) {
// First data in buffer, enable data ready interrupt
UCSR0B |= (1 << UDRIE0);
}
// Put data in buffer
ring_buffer_put(&ring_buffer_out, data);
// Re-enable interrupts
sei();
}
/**
* \brief Function for getting a char from the UART receive buffer
*
* \retval Next data byte in receive buffer
*/
static inline uint8_t uart_getchar(void)
{
return ring_buffer_get(&ring_buffer_in);
}
/**
* \brief Function to check if we have a char waiting in the UART receive buffer
*
* \retval true if data is waiting
* \retval false if no data is waiting
*/
static inline bool uart_char_waiting(void)
{
return !ring_buffer_is_empty(&ring_buffer_in);
}
/**
* \brief The main application
*
* This application will initialize the UART, send a character and then receive
* it and check if it is the same character as was sent.
*
* \note The RX and TX pins should be externally connected in order to pass the
* test.
*/
int main(void)
{
uint8_t data;
uint8_t cnt;
cli();
uart_init();
sei();
// Send the test string
for (cnt = 0; cnt < strlen(test_string); cnt++) {
uart_putchar(test_string[cnt]);
}
// Check if we have received the string we sent
cnt = 0;
do {
// Wait for next character
while (!uart_char_waiting());
data = uart_getchar();
// Compare to what we sent
Assert (data == test_string[cnt++]);
} while (cnt < strlen(test_string));
while (true);
}