1
0
mirror of https://github.com/halleysfifthinc/Toyota-AVC-LAN synced 2025-06-07 07:56:21 +00:00

6239 lines
164 KiB
C

/*!
* \brief
*
* \author Jan Oleksiewicz <jnk0le@hotmail.com>
* \license SPDX-License-Identifier: MIT
*/
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include <stdlib.h>
#include <util/atomic.h>
#include "../../src/timing.h"
#include <util/delay.h>
#include "usart.h"
#ifndef NO_TX0_INTERRUPT
volatile uint8_t tx0_Tail, tx0_Head;
char tx0_buffer[TX0_BUFFER_SIZE] __attribute__((used));
#endif
#ifndef NO_RX0_INTERRUPT
volatile uint8_t rx0_Tail, rx0_Head;
char rx0_buffer[RX0_BUFFER_SIZE] __attribute__((used));
#endif
#ifndef NO_TX1_INTERRUPT
volatile uint8_t tx1_Tail, tx1_Head;
char tx1_buffer[TX1_BUFFER_SIZE] __attribute__((used));
#endif
#ifndef NO_RX1_INTERRUPT
volatile uint8_t rx1_Tail, rx1_Head;
char rx1_buffer[RX1_BUFFER_SIZE] __attribute__((used));
#endif
#ifndef NO_TX2_INTERRUPT
volatile uint8_t tx2_Tail, tx2_Head;
char tx2_buffer[TX2_BUFFER_SIZE] __attribute__((used));
#endif
#ifndef NO_RX2_INTERRUPT
volatile uint8_t rx2_Tail, rx2_Head;
char rx2_buffer[RX2_BUFFER_SIZE] __attribute__((used));
#endif
#ifndef NO_TX3_INTERRUPT
volatile uint8_t tx3_Tail, tx3_Head;
char tx3_buffer[TX3_BUFFER_SIZE] __attribute__((used));
#endif
#ifndef NO_RX3_INTERRUPT
volatile uint8_t rx3_Tail, rx3_Head;
char rx3_buffer[RX3_BUFFER_SIZE] __attribute__((used));
#endif
#ifdef USART_NO_LOCAL_BUFFERS
extern char u_tmp_buff[];
#endif
#ifdef USE_USART0
/*
void uart_init(uint16_t ubrr_value)
{
#ifdef USART0_RS485_MODE
RS485_CONTROL0_DDR |= (1<<RS485_CONTROL0_IONUM); // default pin
state is low #endif
UBRR0L_REGISTER = (uint8_t) ubrr_value;
UBRR0H_REGISTER = (ubrr_value>>8);
#ifdef USART0_U2X_SPEED
#ifdef USART0_MPCM_MODE
UCSR0A_REGISTER = (1<<U2X0_BIT)|(1<<MPCM0_BIT);
#else
UCSR0A_REGISTER = (1<<U2X0_BIT); // enable double speed
#endif
#elif defined(USART0_MPCM_MODE)
UCSR0A_REGISTER |= (1<<MPCM0_BIT);
#endif
UCSR0B_REGISTER = USART0_CONFIG_B;
// 8n1 is set by default, setting UCSRC is not needed
#ifdef USART0_USE_SOFT_RTS
RTS0_DDR |= (1<<RTS0_IONUM);
#endif
}
*/
//******************************************************************
// Function : To reinitialize USART interface (runtime speed changing).
// Arguments : Calculated UBRR value to initialize equal speed.
// Return : none
// Note : Use BAUD_CALC(speed) macro to calculate UBRR value.
// : All data inside UDR shift register will be lost.
// : U2X bit is cleared if USARTn_U2X_SPEED is not defined.
//******************************************************************
void uart0_reinit(uint16_t ubrr_value) {
#ifdef USART0_USE_SOFT_RTS
RTS0_PORT |= (1 << RTS0_IONUM);
#endif
#ifdef USART0_RS485_MODE
RS485_CONTROL0_PORT &= ~(1 << RS485_CONTROL0_IONUM); // set low
RS485_CONTROL0_DDR |= (1 << RS485_CONTROL0_IONUM);
#endif
UCSR0B_REGISTER = 0; // flush all hardware buffers
#if __AVR_ARCH__ == 103
UCSR0A_REGISTER = 0;
#endif
//(writing TXENn to zero) will not become effective until ongoing and pending
// transmissions are completed
UBRR0L_REGISTER = (uint8_t)ubrr_value;
UBRR0H_REGISTER = (ubrr_value >> 8);
#if __AVR_ARCH__ == 103
#if (!defined(NO_RX0_INTERRUPT) && !defined(NO_TX0_INTERRUPT))
#ifdef USART0_RS485_MODE
UCSR0A_REGISTER = (1 << RXCIE0_BIT) | (1 << TXCIE0_BIT) | (1 << RS485_BIT);
#else
UCSR0A_REGISTER = (1 << RXCIE0_BIT);
#endif
#endif
#else
#ifdef USART0_U2X_SPEED
#ifdef USART0_MPCM_MODE
UCSR0A_REGISTER = (1 << U2X0_BIT) | (1 << MPCM0_BIT);
#else
UCSR0A_REGISTER = (1 << U2X0_BIT); // enable double speed
#endif
#elif defined(USART0_MPCM_MODE)
UCSR0A_REGISTER |= (1 << MPCM0_BIT);
#endif
#endif
UCSR0B_REGISTER = USART0_CONFIG_B;
// 8n1 is set by default, setting UCSRC is not needed
#if defined(USART0_MPCM_MODE) && __AVR_ARCH__ == 103
UCSR0C_REGISTER = USART_CHSIZE_9BITH_gc;
#endif
#ifdef USART0_USE_SOFT_RTS
RTS0_DDR |= (1 << RTS0_IONUM);
RTS0_PORT &= ~(1 << RTS0_IONUM);
#endif
}
#endif // USE_USART0
#ifdef USE_USART1
void uart1_reinit(uint16_t ubrr_value) {
#ifdef USART1_USE_SOFT_RTS
RTS1_PORT |= (1 << RTS1_IONUM);
#endif
#ifdef USART1_RS485_MODE
RS485_CONTROL1_PORT &= ~(1 << RS485_CONTROL1_IONUM); // set low
RS485_CONTROL1_DDR |= (1 << RS485_CONTROL1_IONUM);
#endif
UCSR1B_REGISTER = 0; // flush all hardware buffers
#if __AVR_ARCH__ == 103
UCSR1A_REGISTER = 0;
#endif
//(writing TXENn to zero) will not become effective until ongoing and pending
// transmissions are completed
UBRR1L_REGISTER = (uint8_t)ubrr_value;
UBRR1H_REGISTER = (ubrr_value >> 8);
#if __AVR_ARCH__ == 103
#if (!defined(NO_RX1_INTERRUPT) && !defined(NO_TX1_INTERRUPT))
#ifdef USART1_RS485_MODE
UCSR1A_REGISTER = (1 << RXCIE1_BIT) | (1 << TXCIE1_BIT) | (1 << RS485_BIT);
#else
UCSR1A_REGISTER = (1 << RXCIE1_BIT);
#endif
#endif
#else
#ifdef USART1_U2X_SPEED
#ifdef USART1_MPCM_MODE
UCSR1A_REGISTER = (1 << U2X1_BIT) | (1 << MPCM1_BIT);
#else
UCSR1A_REGISTER = (1 << U2X1_BIT); // enable double speed
#endif
#elif defined(USART1_MPCM_MODE)
UCSR1A_REGISTER |= (1 << MPCM1_BIT);
#endif
#endif
UCSR1B_REGISTER = USART1_CONFIG_B;
// 8n1 is set by default, setting UCSRC is not needed
#if defined(USART1_MPCM_MODE) && __AVR_ARCH__ == 103
UCSR1C_REGISTER = USART_CHSIZE_9BITH_gc;
#endif
#ifdef USART1_USE_SOFT_RTS
RTS1_DDR |= (1 << RTS1_IONUM);
RTS1_PORT &= ~(1 << RTS1_IONUM);
#endif
}
#endif // USE_USART1
#ifdef USE_USART2
void uart2_reinit(uint16_t ubrr_value) {
#ifdef USART2_USE_SOFT_RTS
RTS2_PORT |= (1 << RTS2_IONUM);
#endif
#ifdef USART2_RS485_MODE
RS485_CONTROL2_PORT &= ~(1 << RS485_CONTROL2_IONUM); // set low
RS485_CONTROL2_DDR |= (1 << RS485_CONTROL2_IONUM);
#endif
UCSR2B_REGISTER = 0; // flush all hardware buffers
#if __AVR_ARCH__ == 103
UCSR2A_REGISTER = 0;
#endif
//(writing TXENn to zero) will not become effective until ongoing and pending
// transmissions are completed
UBRR2L_REGISTER = (uint8_t)ubrr_value;
UBRR2H_REGISTER = (ubrr_value >> 8);
#if __AVR_ARCH__ == 103
#if (!defined(NO_RX2_INTERRUPT) && !defined(NO_TX2_INTERRUPT))
#ifdef USART2_RS485_MODE
UCSR2A_REGISTER = (1 << RXCIE2_BIT) | (1 << TXCIE2_BIT) | (1 << RS485_BIT);
#else
UCSR2A_REGISTER = (1 << RXCIE2_BIT);
#endif
#endif
#else
#ifdef USART2_U2X_SPEED
#ifdef USART2_MPCM_MODE
UCSR2A_REGISTER = (1 << U2X2_BIT) | (1 << MPCM2_BIT);
#else
UCSR2A_REGISTER = (1 << U2X2_BIT); // enable double speed
#endif
#elif defined(USART2_MPCM_MODE)
UCSR2A_REGISTER |= (1 << MPCM2_BIT);
#endif
#endif
UCSR2B_REGISTER = USART2_CONFIG_B;
// 8n1 is set by default, setting UCSRC is not needed
#if defined(USART2_MPCM_MODE) && __AVR_ARCH__ == 103
UCSR2C_REGISTER = USART_CHSIZE_9BITH_gc;
#endif
#ifdef USART2_USE_SOFT_RTS
RTS2_DDR |= (1 << RTS2_IONUM);
RTS2_PORT &= ~(1 << RTS2_IONUM);
#endif
}
#endif // USE_USART2
#ifdef USE_USART3
void uart3_reinit(uint16_t ubrr_value) {
#ifdef USART3_USE_SOFT_RTS
RTS3_PORT |= (1 << RTS3_IONUM);
#endif
#ifdef USART3_RS485_MODE
RS485_CONTROL3_PORT &= ~(1 << RS485_CONTROL3_IONUM); // set low
RS485_CONTROL3_DDR |= (1 << RS485_CONTROL3_IONUM);
#endif
UCSR3B_REGISTER = 0; // flush all hardware buffers
#if __AVR_ARCH__ == 103
UCSR3A_REGISTER = 0;
#endif
UBRR3L_REGISTER = (uint8_t)ubrr_value;
UBRR3H_REGISTER = (ubrr_value >> 8);
#if __AVR_ARCH__ == 103
#if (!defined(NO_RX3_INTERRUPT) && !defined(NO_TX3_INTERRUPT))
#ifdef USART3_RS485_MODE
UCSR3A_REGISTER = (1 << RXCIE3_BIT) | (1 << TXCIE3_BIT) | (1 << RS485_BIT);
#else
UCSR3A_REGISTER = (1 << RXCIE3_BIT);
#endif
#endif
#else
#ifdef USART3_U2X_SPEED
#ifdef USART3_MPCM_MODE
UCSR3A_REGISTER = (1 << U2X3_BIT) | (1 << MPCM3_BIT);
#else
UCSR3A_REGISTER = (1 << U2X3_BIT); // enable double speed
#endif
#elif defined(USART3_MPCM_MODE)
UCSR3A_REGISTER |= (1 << MPCM3_BIT);
#endif
#endif
UCSR3B_REGISTER = USART3_CONFIG_B;
// 8n1 is set by default, setting UCSRC is not needed
#if defined(USART3_MPCM_MODE) && __AVR_ARCH__ == 103
UCSR3C_REGISTER = USART_CHSIZE_9BITH_gc;
#endif
#ifdef USART3_USE_SOFT_RTS
RTS3_DDR |= (1 << RTS3_IONUM);
RTS3_PORT &= ~(1 << RTS3_IONUM);
#endif
}
#endif // USE_USART3
#ifndef NO_USART_TX
#ifndef NO_TX0_INTERRUPT
//******************************************************************
// Function : Send single character/byte.
// Arguments : Character/byte to send.
// Return : none
//******************************************************************
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart0_putc(char data) {
#ifdef PUTC0_CONVERT_LF_TO_CRLF
if (data == '\n')
uart0_putc('\r');
#endif
#ifdef USART0_PUTC_FAST_INSERTIONS
register uint8_t tmp_tx_Head = tx0_Head;
register uint8_t tmp_tx_Tail = tx0_Tail;
#ifdef USART0_USE_SOFT_CTS
if (!(CTS0_PIN & (1 << CTS0_IONUM)))
#endif
if (tmp_tx_Tail == tmp_tx_Head &&
#if __AVR_ARCH__ == 103
(USR0_REGISTER & UDRE0_BIT)
#else
(UCSR0A_REGISTER & UDRE0_BIT)
#endif
) {
UDR0_REGISTER = data;
return;
}
tmp_tx_Head = (tmp_tx_Head + 1) & TX0_BUFFER_MASK;
while (tmp_tx_Tail == tmp_tx_Head) // wait for free space in buffer
{
// for faster pass through, results in a little bigger code
tmp_tx_Tail = tx0_Tail;
}
#else // !USART0_PUTC_FAST_INSERTIONS
// calculate new position of TX head in buffer
register uint8_t tmp_tx_Head = (tx0_Head + 1) & TX0_BUFFER_MASK;
while (tx0_Tail == tmp_tx_Head) {} // wait for free space in buffer
#endif
tx0_buffer[tmp_tx_Head] = data;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
tx0_Head = tmp_tx_Head;
#ifdef USART0_RS485_MODE
RS485_CONTROL0_PORT |= (1 << RS485_CONTROL0_IONUM); // set high
#endif
#ifdef USART0_USE_SOFT_CTS
if (!(CTS0_PIN & (1 << CTS0_IONUM)))
#endif
{
uart0_enable_UDREI(); // enable UDRE interrupt
}
}
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart0_putc(char data) {
register uint8_t tmp_tx_Head asm("r25");
#ifdef PUTC0_CONVERT_LF_TO_CRLF
asm volatile("\n\t"
"cpi %[dat], '\n' \n\t"
"brne skip_recursive_%=\n\t"
"push %[dat] \n\t"
"ldi %[dat], '\r' \n\t"
"rcall uart0_putc \n\t"
"pop %[dat] \n\t"
"skip_recursive_%=:"
: // outputs
[dat] "+r"(data) // will be used later, do not let the compiler
// to do anything weird
: // inputs
: // clobbers
);
#endif
#ifdef USART0_PUTC_FAST_INSERTIONS
asm volatile(
"\n\t"
"lds %[head], (tx0_Head) \n\t"
#ifdef USART0_USE_SOFT_CTS
"sbic %M[cts_port], %M[cts_pin] \n\t"
"rjmp normal_insert_%= \n\t"
#endif
"lds r27, (tx0_Tail) \n\t"
"cpse r27, %[head] \n\t"
"rjmp normal_insert_%= \n\t"
#ifdef USART0_IN_IO_ADDRESS_SPACE
"sbis %M[UDRE_reg_IO], %M[udre_bit] \n\t"
#elif defined(USART0_IN_UPPER_IO_ADDRESS_SPACE)
"in r26, %M[UDRE_reg_IO] \n\t"
"sbrs r26, %M[udre_bit] \n\t"
#else
"lds r26, %M[UDRE_reg] \n\t"
"sbrs r26, %M[udre_bit] \n\t"
#endif
"rjmp normal_insert_%= \n\t"
#ifdef USART0_IN_IO_ADDRESS_SPACE
"out %M[UDR_reg], %[dat] \n\t"
#else
"sts %M[UDR_reg], %[dat] \n\t"
#endif
"ret \n\t"
"normal_insert_%=:"
"inc %[head] \n\t"
#if (TX0_BUFFER_MASK != 0xff)
"andi %[head], %M[mask] \n\t"
#endif
"waitforspace_%=:"
"lds r27, (tx0_Tail) \n\t"
"cp r27, %[head] \n\t"
"breq waitforspace_%= \n\t"
: // outputs
[head] "=r"(tmp_tx_Head),
[dat] "+r"(data) // will be used later, do not let the compiler to do
// anything weird
: // inputs
#ifdef USART0_USE_SOFT_CTS
[cts_port] "M"(_SFR_IO_ADDR(CTS0_PORT)), [cts_pin] "M"(CTS0_IONUM),
#endif
[mask] "M"(TX0_BUFFER_MASK),
#if __AVR_ARCH__ == 103
[UDRE_reg] "n"(_SFR_MEM_ADDR(USR0_REGISTER)),
[UDRE_reg_IO] "M"(_SFR_IO_ADDR(USR0_REGISTER)),
#else
[UDRE_reg] "n"(_SFR_MEM_ADDR(UCSR0A_REGISTER)),
[UDRE_reg_IO] "M"(_SFR_IO_ADDR(UCSR0A_REGISTER)),
#endif
[UDR_reg] "n"(_SFR_MEM_ADDR(UDR0_REGISTER)),
[UDR_reg_IO] "M"(_SFR_IO_ADDR(UDR0_REGISTER)),
[udre_bit] "M"(UDRE0_BIT)
: // clobbers
"r26", "r27");
#else
asm volatile("\n\t"
"lds %[head], (tx0_Head) \n\t"
"inc %[head] \n\t"
#if (TX0_BUFFER_MASK != 0xff)
"andi %[head], %M[mask] \n\t"
#endif
"waitforspace_%=:"
"lds r27, (tx0_Tail) \n\t"
"cp r27, %[head] \n\t"
"breq waitforspace_%= \n\t"
: // outputs
[head] "=r"(tmp_tx_Head)
: // inputs
[mask] "M"(TX0_BUFFER_MASK)
: // clobbers
"r27");
#endif
asm volatile(
"\n\t"
"mov r26, %[index] \n\t"
#if !defined(__AVR_ATtiny2313__) && \
!defined(__AVR_ATtiny2313A__) // on ATtiny2313 upper byte in pointer
// pair is ignored
"ldi r27, 0x00 \n\t"
#endif
"subi r26, lo8(-(tx0_buffer)) \n\t"
#ifndef USART_USE_TINY_MEMORY_MODEL
"sbci r27, hi8(-(tx0_buffer)) \n\t"
#endif
"st X, %[dat] \n\t"
: // outputs
[index] "+r"(tmp_tx_Head), // will be used later, do not let the compiler
// to do anything weird
[dat] "+r"(data) // not modified, so reduce register moves if inlined
: // inputs
: // clobbers
"r26", "r27");
cli();
{
tx0_Head = tmp_tx_Head;
#ifdef USART0_RS485_MODE
RS485_CONTROL0_PORT |= (1 << RS485_CONTROL0_IONUM); // start transmitting
#endif
#ifdef USART0_USE_SOFT_CTS
if (!(CTS0_PIN & (1 << CTS0_IONUM)))
#endif
{
#ifdef USART0_IN_IO_ADDRESS_SPACE
UCSR0B_REGISTER |= (1 << UDRIE0_BIT); // enable UDRE interrupt
#else
asm volatile("\n\t"
#ifdef USART0_IN_UPPER_IO_ADDRESS_SPACE
"in r25, %M[control_reg_IO] \n\t"
"ori r25, (1<<%M[udrie_bit]) \n\t"
"out %M[control_reg_IO], r25\n\t"
#else
"lds r25, %M[control_reg] \n\t"
"ori r25, (1<<%M[udrie_bit]) \n\t"
"sts %M[control_reg], r25 \n\t"
#endif
: // outputs
: // inputs
#if __AVR_ARCH__ == 103
[control_reg] "n"(_SFR_MEM_ADDR(UCSR0A_REGISTER)),
#else
[control_reg] "n"(_SFR_MEM_ADDR(UCSR0B_REGISTER)),
#endif
[udrie_bit] "M"(UDRIE0_BIT)
: // clobbers
"r25");
#endif
}
}
reti();
asm volatile("\n\t" ::"r"(data)
:); // data was passed in r24 and will be returned in the same
// register, make sure it is not affected by the compiler
}
// alias for uart_putc that returns passed argument unaffected by omitting any
// existent rule
char uart0_putc_(char data) __attribute__((alias("uart0_putc")));
#endif // USART_NO_ABI_BREAKING_PREMATURES
//******************************************************************
// Function : Send single character/byte.
// Arguments : Character/byte to send.
// Return : Status value: 0 = BUFFER_FULL, 1 = COMPLETED.
// Note : If character cannot be sent due to full transmit buffer,
// function will abort transmitting character
//******************************************************************
#ifdef USART_NO_ABI_BREAKING_PREMATURES
uint8_t uart0_putc_noblock(char data) {
#ifdef USART0_PUTC_FAST_INSERTIONS
register uint8_t tmp_tx_Head = tx0_Head;
register uint8_t tmp_tx_Tail = tx0_Tail;
#ifdef USART0_USE_SOFT_CTS
if (!(CTS0_PIN & (1 << CTS0_IONUM)))
#endif
if (tmp_tx_Tail == tmp_tx_Head && (UCSR0A_REGISTER & UDRE0_BIT)) {
UDR0_REGISTER = data;
return COMPLETED;
}
tmp_tx_Head = (tmp_tx_Head + 1) & TX0_BUFFER_MASK;
if (tmp_tx_Tail == tmp_tx_Head)
return BUFFER_FULL;
#else
register uint8_t tmp_tx_Head =
(tx0_Head + 1) &
TX0_BUFFER_MASK; // calculate new position of TX head in buffer
if (tx0_Tail == tmp_tx_Head)
return BUFFER_FULL;
#endif
tx0_buffer[tmp_tx_Head] = data;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
tx0_Head = tmp_tx_Head;
#ifdef USART0_RS485_MODE
RS485_CONTROL0_PORT |= (1 << RS485_CONTROL0_IONUM); // set high
#endif
#ifdef USART0_USE_SOFT_CTS
if (!(CTS0_PIN & (1 << CTS0_IONUM)))
#endif
{
UCSR0B_REGISTER |= (1 << UDRIE0_BIT); // enable UDRE interrupt
}
}
return COMPLETED;
}
#else //! USART_NO_ABI_BREAKING_PREMATURES
uint8_t uart0_putc_noblock(char data) {
#ifdef USART0_PUTC_FAST_INSERTIONS
register uint8_t tmp_tx_Head = tx0_Head;
register uint8_t tmp_tx_Tail = tx0_Tail;
#ifdef USART0_USE_SOFT_CTS
if (!(CTS0_PIN & (1 << CTS0_IONUM)))
#endif
if (tmp_tx_Tail == tmp_tx_Head && (UCSR0A_REGISTER & UDRE0_BIT)) {
UDR0_REGISTER = data;
return COMPLETED;
}
tmp_tx_Head = (tmp_tx_Head + 1) & TX0_BUFFER_MASK;
if (tmp_tx_Tail == tmp_tx_Head)
return BUFFER_FULL;
#else
register uint8_t tmp_tx_Head =
(tx0_Head + 1) &
TX0_BUFFER_MASK; // calculate new position of TX head in buffer
if (tx0_Tail == tmp_tx_Head)
return BUFFER_FULL;
#endif
asm volatile(
"\n\t"
"mov r26, %[index] \n\t"
#if !defined(__AVR_ATtiny2313__) && \
!defined(__AVR_ATtiny2313A__) // on ATtiny2313 upper byte in pointer
// pair is ignored
"ldi r27, 0x00 \n\t"
#endif
"subi r26, lo8(-(tx0_buffer)) \n\t"
#ifndef USART_USE_TINY_MEMORY_MODEL
"sbci r27, hi8(-(tx0_buffer)) \n\t"
#endif
"st X, %[dat] \n\t"
: // outputs
[index] "+r"(tmp_tx_Head), // will be used later, do not let the compiler
// to do anything weird
[dat] "+r"(data) // not modified, so reduce register moves if inlined
: // inputs
: // clobbers
#if !defined(__AVR_ATtiny2313__) && !defined(__AVR_ATtiny2313A__)
"r27",
#endif
"r26");
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
tx0_Head = tmp_tx_Head;
#ifdef USART0_RS485_MODE
RS485_CONTROL0_PORT |= (1 << RS485_CONTROL0_IONUM); // start transmitting
#endif
#ifdef USART0_USE_SOFT_CTS
if (!(CTS0_PIN & (1 << CTS0_IONUM)))
#endif
{
UCSR0B_REGISTER |= (1 << UDRIE0_BIT); // enable UDRE interrupt
}
}
return COMPLETED;
}
#endif
//******************************************************************
// Function : Send string array.
// Arguments : Pointer to string array terminated by NULL.
// Return : none
//******************************************************************
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart0_putstr(char *string) {
char c;
while ((c = *string++))
uart0_putc(c);
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart0_putstr(char *string) {
asm volatile(
"\n\t"
"load_loop_%=:"
"ld r24, Z+ \n\t"
"and r24, r24 \n\t" // test for NULL
"breq skip_loop_%= \n\t"
"rcall uart0_putc \n\t" // Z pointer will not be affected in uart_putc()
"rjmp load_loop_%= \n\t"
"skip_loop_%=:"
: // outputs
: // inputs
"z"(string)
: // clobbers
"r24", "r25", "r26", "r27" // uart_putc()
);
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
//******************************************************************
// Function : Send string not terminated by NULL or part of the string
// array. Arguments : 1. Pointer to string array.
// : 2. Number of characters/bytes to send.
// Return : none
//******************************************************************
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart0_putstrl(char *string, uint8_t BytesToWrite) {
while (BytesToWrite--)
uart0_putc(*string++);
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart0_putstrl(char *string, uint8_t BytesToWrite) {
asm volatile("\n\t"
"add %[counter], r30 \n\t" // add ZL to a counter to compare
// against current pointer (8 bit
// length, doesn't care if overflow)
"load_loop_%=:"
"cp %[counter], r30\n\t"
"breq skip_loop_%= \n\t"
"ld r24, Z+ \n\t"
"rcall uart0_putc \n\t" // counter and Z pointer will not be
// affected in uart_putc()
"rjmp load_loop_%= \n\t"
"skip_loop_%=:"
: // outputs
: // inputs
[counter] "r"(BytesToWrite),
"z"(string)
: // clobbers
"r24", "r25", "r26", "r27" // uart_putc()
);
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
//******************************************************************
// Function : Send string from flash memory.
// Arguments : Pointer to string placed in flash memory.
// Return : none
//******************************************************************
#if __AVR_ARCH__ != 103
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart0_puts_p(const __flash char *string) {
#ifndef USART0_NOT_ACCESIBLE_FROM_CBI // tiny 102/104
register char c;
while ((c = *string++))
uart0_putc(c);
#endif
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart0_puts_p(const __flash char *string) {
#if !defined(__AVR_ATtiny102__) || !defined(__AVR_ATtiny104__)
asm volatile(
"\n\t"
"load_loop_%=:"
"lpm r24, Z+ \n\t"
"and r24, r24 \n\t" // test for NULL
"breq skip_loop_%= \n\t"
"rcall uart0_putc \n\t" // Z pointer will not be affected in uart_putc()
"rjmp load_loop_%= \n\t"
"skip_loop_%=:"
: // outputs
: // inputs
"z"(string)
: // clobbers
"r24", "r25", "r26", "r27" // uart_putc()
);
#endif
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
#endif
//******************************************************************
// Function : Send integer formated into ASCI string (base 10).
// Arguments : int16_t data value.
// Return : none
//******************************************************************
void uart0_putint(int16_t data) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[7]; // heading, 5 digit bytes, NULL
#endif
itoa(data, u_tmp_buff, 10);
uart0_putstr(u_tmp_buff);
}
//******************************************************************
// Function : Send integer formated into ASCI string.
// Arguments : 1. uint16_t data value.
// : 2. Base value (DEC, HEX, OCT, BIN, etc.).
// Return : none
//******************************************************************
void uart0_putintr(int16_t data, uint8_t radix) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[17]; // heading, 15 digit bytes, NULL
#endif
itoa(data, u_tmp_buff, radix);
uart0_putstr(u_tmp_buff);
}
//******************************************************************
// Function : Send unsigned integer formated into ASCI string (base 10).
// Arguments : uint16_t data value.
// Return : none
//******************************************************************
void uart0_putuint(uint16_t data) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[7]; // heading, 5 digit bytes, NULL
#endif
utoa(data, u_tmp_buff, 10);
uart0_putstr(u_tmp_buff);
}
//******************************************************************
// Function : Send unsigned integer formated into ASCI string.
// Arguments : 1. uint16_t data value.
// : 2. Base value (DEC, HEX, OCT, BIN, etc.).
// Return : none
//******************************************************************
void uart0_putuintr(uint16_t data, uint8_t radix) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[17]; // heading, 15 digit bytes, NULL
#endif
utoa(data, u_tmp_buff, radix);
uart0_putstr(u_tmp_buff);
}
//******************************************************************
// Function : Send unsigned integer formated into ASCI string (base 16)
// Arguments : uint16_t data value.
// Return : none
//******************************************************************
void uart0_puthex(uint8_t data) {
uint8_t tmp;
tmp = (data >> 4) & 0x0f;
#ifdef USART_PUTHEX_IN_UPPERCASE
uart0_putc((tmp <= 9 ? '0' + tmp : 'A' - 10 + tmp));
#else
uart0_putc((tmp <= 9 ? '0' + tmp : 'a' - 10 + tmp));
#endif
tmp = data & 0x0f;
#ifdef USART_PUTHEX_IN_UPPERCASE
uart0_putc((tmp <= 9 ? '0' + tmp : 'A' - 10 + tmp));
#else
uart0_putc((tmp <= 9 ? '0' + tmp : 'a' - 10 + tmp));
#endif
}
//******************************************************************
// Function : Send long integer formated into ASCI string (base 10).
// Arguments : int32_t data value.
// Return : none
//******************************************************************
void uart0_putlong(int32_t data) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[12]; // heading, 10 digit bytes, NULL
#endif
ltoa(data, u_tmp_buff, 10);
uart0_putstr(u_tmp_buff);
}
//******************************************************************
// Function : Send long integer formated into ASCI string.
// Arguments : 1. int32_t data value.
// : 2. Base value (DEC, HEX, OCT, BIN, etc.).
// Return : none
//******************************************************************
void uart0_putlongr(int32_t data, uint8_t radix) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[17]; // heading, 15 digit bytes, NULL
#endif
ltoa(data, u_tmp_buff, radix);
uart0_putstr(u_tmp_buff);
}
//******************************************************************
// Function : Send unsigned long integer formated into ASCI string (base 10).
// Arguments : uint32_t data value.
// Return : none
//******************************************************************
void uart0_putulong(uint32_t data) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[12]; // heading, 10 digit bytes, NULL
#endif
ultoa(data, u_tmp_buff, 10);
uart0_putstr(u_tmp_buff);
}
//******************************************************************
// Function : Send unsigned long integer formated into ASCI string.
// Arguments : 1. uint32_t data value.
// : 2. Base value (DEC, HEX, OCT, BIN, etc.).
// Return : none
//******************************************************************
void uart0_putulongr(uint32_t data, uint8_t radix) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[17]; // heading, 15 digit bytes, NULL
#endif
ultoa(data, u_tmp_buff, radix);
uart0_putstr(u_tmp_buff);
}
//******************************************************************
// Function : Send floating point value formated into ASCI string.
// Arguments : float data value.
// Return : none
//******************************************************************
void uart0_putfloat(float data) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[16];
#endif
dtostrf(data, 15, 6, u_tmp_buff);
char *p = u_tmp_buff;
while (*p == ' ') // remove all unwanted spaces
p++;
uart0_putstr(p);
}
//******************************************************************
// Function : Send floating point integer formated into ASCI string.
// Arguments : 1. Float data value.
// : 2. Number of displayed digits after the dot.
// Return : none
//******************************************************************
void uart0_fputfloat(float data, uint8_t precision) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[16];
#endif
dtostrf(data, 15, precision, u_tmp_buff);
char *p = u_tmp_buff;
while (*p == ' ') // remove all unwanted spaces
p++;
uart0_putstr(p);
}
//******************************************************************
// Function : Wait until all data in TX buffer are flushed.
// Arguments : none
// Return : none
//******************************************************************
void uart0_flush(void) {
#ifdef USART0_RS485_MODE // flush UDR buffer
while (RS485_CONTROL0_PORT & (1 << RS485_CONTROL0_IONUM))
;
#else
while (tx0_Tail != tx0_Head)
; // just flush the ring buffer
#endif
}
//******************************************************************
// Function : To check how many bytes are waiting in the transmitter
// buffer. Arguments : none Return : Number of bytes waiting in
// transmitter buffer.
//******************************************************************
// uint8_t uart0_BytesToSend(void)
// {
// return (tx0_Head - tx0_Tail) & TX0_BUFFER_MASK;
// }
//******************************************************************
// Function : Transmit address of selected slave in MPCM mode.
// Arguments : Address of selected slave.
// Return : none
//******************************************************************
#ifdef USART0_MPCM_MODE
void uart0_mpcm_transmit_addres_Frame(uint8_t dat) {
while (tx0_Tail != tx0_Head) {}
#if __AVR_ARCH__ == 103
UDR0H_REGISTER |= (1 << TXB80_BIT);
#else
UCSR0B_REGISTER |= (1 << TXB80_BIT);
#endif
uart_putc(dat);
while (tx0_Tail != tx0_Head) {}
#if __AVR_ARCH__ == 103
UDR0H_REGISTER &= ~(1 << TXB80_BIT); // not sure if necessary
#else
UCSR0B_REGISTER &= ~(1 << TXB80_BIT); // not sure if necessary
#endif
}
#endif
#endif // NO_TX0_INTERRUPT
#ifndef NO_TX1_INTERRUPT
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart1_putc(char data) {
#ifdef PUTC1_CONVERT_LF_TO_CRLF
if (data == '\n')
uart1_putc('\r');
#endif
#ifdef USART1_PUTC_FAST_INSERTIONS
register uint8_t tmp_tx_Head = tx1_Head;
register uint8_t tmp_tx_Tail = tx1_Tail;
#ifdef USART1_USE_SOFT_CTS
if (!(CTS1_PIN & (1 << CTS1_IONUM)))
#endif
if (tmp_tx_Tail == tmp_tx_Head && (UCSR1A_REGISTER & UDRE1_BIT)) {
UDR1_REGISTER = data;
return;
}
tmp_tx_Head = (tmp_tx_Head + 1) & TX1_BUFFER_MASK;
while (tmp_tx_Tail == tmp_tx_Head) // wait for free space in buffer
{
tmp_tx_Tail =
tx1_Tail; // for faster pass through, results in a little bigger code
}
#else
register uint8_t tmp_tx_Head =
(tx1_Head + 1) &
TX1_BUFFER_MASK; // calculate new position of TX head in buffer
while (tx1_Tail == tmp_tx_Head)
; // wait for free space in buffer
#endif
tx1_buffer[tmp_tx_Head] = data;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
tx1_Head = tmp_tx_Head;
#ifdef USART1_RS485_MODE
RS485_CONTROL1_PORT |= (1 << RS485_CONTROL1_IONUM); // set high
#endif
#ifdef USART1_USE_SOFT_CTS
if (!(CTS1_PIN & (1 << CTS1_IONUM)))
#endif
{
UCSR1B_REGISTER |= (1 << UDRIE1_BIT); // enable UDRE interrupt
}
}
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart1_putc(char data) {
register uint8_t tmp_tx_Head asm("r25");
#ifdef PUTC1_CONVERT_LF_TO_CRLF
asm volatile("\n\t"
"cpi %[dat], '\n' \n\t"
"brne skip_recursive_%=\n\t"
"push %[dat] \n\t"
"ldi %[dat], '\r' \n\t"
"rcall uart1_putc \n\t"
"pop %[dat] \n\t"
"skip_recursive_%=:"
: // outputs
[dat] "+r"(data) // will be used later, do not let the compiler
// to do anything weird
: // inputs
: // clobbers
);
#endif
#ifdef USART1_PUTC_FAST_INSERTIONS
asm volatile(
"\n\t"
"lds %[head], (tx1_Head) \n\t"
#ifdef USART1_USE_SOFT_CTS
"sbic %M[cts_port], %M[cts_pin] \n\t"
"rjmp normal_insert_%= \n\t"
#endif
"lds r27, (tx1_Tail) \n\t"
"cpse r27, %[head] \n\t"
"rjmp normal_insert_%= \n\t"
#ifdef USART1_IN_IO_ADDRESS_SPACE
"sbis %M[UDRE_reg_IO], %M[udre_bit] \n\t"
#else
"lds r26, %M[UDRE_reg] \n\t"
"sbrs r26, %M[udre_bit] \n\t"
#endif
"rjmp normal_insert_%= \n\t"
#ifdef USART1_IN_IO_ADDRESS_SPACE
"out %M[UDR_reg], %[dat] \n\t"
#else
"sts %M[UDR_reg], %[dat] \n\t"
#endif
"ret \n\t"
"normal_insert_%=:"
"inc %[head] \n\t"
#if (TX1_BUFFER_MASK != 0xff)
"andi %[head], %M[mask] \n\t"
#endif
"waitforspace_%=:"
"lds r27, (tx1_Tail) \n\t"
"cp r27, %[head] \n\t"
"breq waitforspace_%= \n\t"
: // outputs
[head] "=r"(tmp_tx_Head),
[dat] "+r"(data)
: // inputs
#ifdef USART1_USE_SOFT_CTS
[cts_port] "M"(_SFR_IO_ADDR(CTS1_PORT)), [cts_pin] "M"(CTS1_IONUM),
#endif
[mask] "M"(TX1_BUFFER_MASK),
#if __AVR_ARCH__ == 103
[UDRE_reg] "n"(_SFR_MEM_ADDR(USR1_REGISTER)),
[UDRE_reg_IO] "M"(_SFR_IO_ADDR(USR1_REGISTER)),
#else
[UDRE_reg] "n"(_SFR_MEM_ADDR(UCSR1A_REGISTER)),
[UDRE_reg_IO] "M"(_SFR_IO_ADDR(UCSR1A_REGISTER)),
#endif
[UDR_reg] "n"(_SFR_MEM_ADDR(UDR1_REGISTER)),
[UDR_reg_IO] "M"(_SFR_IO_ADDR(UDR1_REGISTER)),
[udre_bit] "M"(UDRE1_BIT)
: // clobbers
"r26", "r27");
#else
asm volatile("\n\t"
"lds %[head], (tx1_Head) \n\t"
"inc %[head] \n\t"
#if (TX1_BUFFER_MASK != 0xff)
"andi %[head], %M[mask] \n\t"
#endif
"waitforspace_%=:"
"lds r27, (tx1_Tail) \n\t"
"cp r27, %[head] \n\t"
"breq waitforspace_%= \n\t"
: // outputs
[head] "=r"(tmp_tx_Head)
: // inputs
[mask] "M"(TX1_BUFFER_MASK)
: // clobbers
"r27");
#endif
asm volatile("\n\t"
"mov r26, %[index] \n\t"
"ldi r27, 0x00 \n\t"
"subi r26, lo8(-(tx1_buffer)) \n\t"
"sbci r27, hi8(-(tx1_buffer)) \n\t"
"st X, %[dat] \n\t"
: // outputs
[index] "+r"(tmp_tx_Head),
[dat] "+r"(data)
: // inputs
: // clobbers
"r26", "r27");
cli();
{
tx1_Head = tmp_tx_Head;
#ifdef USART1_RS485_MODE
RS485_CONTROL1_PORT |= (1 << RS485_CONTROL1_IONUM); // start transmitting
#endif
#ifdef USART1_USE_SOFT_CTS
if (!(CTS1_PIN & (1 << CTS1_IONUM)))
#endif
{
#ifdef USART1_IN_IO_ADDRESS_SPACE
UCSR1B_REGISTER |= (1 << UDRIE1_BIT); // enable UDRE interrupt
#else
asm volatile("\n\t"
"lds r25, %M[control_reg] \n\t"
"ori r25, (1<<%M[udrie_bit]) \n\t"
"sts %M[control_reg], r25 \n\t"
: // outputs
: // inputs
#if __AVR_ARCH__ == 103
[control_reg] "n"(_SFR_MEM_ADDR(UCSR1A_REGISTER)),
#else
[control_reg] "n"(_SFR_MEM_ADDR(UCSR1B_REGISTER)),
#endif
[udrie_bit] "M"(UDRIE1_BIT)
: // clobbers
"r25");
#endif
}
}
reti();
asm volatile("\n\t" ::"r"(data)
:); // data was passed in r24 and will be returned in the same
// register, make sure it is not affected by the compiler
}
char uart1_putc_(char data) __attribute__((
alias("uart1_putc"))); // alias for uart_putc that returns passed argument
// unaffected by omitting any existent rule
#endif // USART_NO_ABI_BREAKING_PREMATURES
#ifdef USART_NO_ABI_BREAKING_PREMATURES
uint8_t uart1_putc_noblock(char data) {
#ifdef USART1_PUTC_FAST_INSERTIONS
register uint8_t tmp_tx_Head = tx1_Head;
register uint8_t tmp_tx_Tail = tx1_Tail;
#ifdef USART1_USE_SOFT_CTS
if (!(CTS1_PIN & (1 << CTS1_IONUM)))
#endif
if (tmp_tx_Tail == tmp_tx_Head && (UCSR1A_REGISTER & UDRE1_BIT)) {
UDR1_REGISTER = data;
return COMPLETED;
}
tmp_tx_Head = (tmp_tx_Head + 1) & TX1_BUFFER_MASK;
if (tmp_tx_Tail == tmp_tx_Head)
return BUFFER_FULL;
#else
register uint8_t tmp_tx_Head =
(tx1_Head + 1) &
TX1_BUFFER_MASK; // calculate new position of TX head in buffer
if (tx1_Tail == tmp_tx_Head)
return BUFFER_FULL;
#endif
tx1_buffer[tmp_tx_Head] = data;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
tx1_Head = tmp_tx_Head;
#ifdef USART1_RS485_MODE
RS485_CONTROL1_PORT |= (1 << RS485_CONTROL1_IONUM); // set high
#endif
#ifdef USART1_USE_SOFT_CTS
if (!(CTS1_PIN & (1 << CTS1_IONUM)))
#endif
{
UCSR1B_REGISTER |= (1 << UDRIE1_BIT); // enable UDRE interrupt
}
}
return COMPLETED;
}
#else //! USART_NO_ABI_BREAKING_PREMATURES
uint8_t uart1_putc_noblock(char data) {
#ifdef USART1_PUTC_FAST_INSERTIONS
register uint8_t tmp_tx_Head = tx1_Head;
register uint8_t tmp_tx_Tail = tx1_Tail;
#ifdef USART1_USE_SOFT_CTS
if (!(CTS1_PIN & (1 << CTS1_IONUM)))
#endif
if (tmp_tx_Tail == tmp_tx_Head && (UCSR1A_REGISTER & UDRE1_BIT)) {
UDR1_REGISTER = data;
return COMPLETED;
}
tmp_tx_Head = (tmp_tx_Head + 1) & TX1_BUFFER_MASK;
if (tmp_tx_Tail == tmp_tx_Head)
return BUFFER_FULL;
#else
register uint8_t tmp_tx_Head =
(tx1_Head + 1) &
TX1_BUFFER_MASK; // calculate new position of TX head in buffer
if (tx1_Tail == tmp_tx_Head)
return BUFFER_FULL;
#endif
asm volatile("\n\t"
"mov r26, %[index] \n\t"
"ldi r27, 0x00 \n\t"
"subi r26, lo8(-(tx1_buffer)) \n\t"
"sbci r27, hi8(-(tx1_buffer)) \n\t"
"st X, %[dat] \n\t"
: // outputs
[index] "+r"(tmp_tx_Head),
[dat] "+r"(data)
: // inputs
: // clobbers
"r26", "r27");
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
tx1_Head = tmp_tx_Head;
#ifdef USART1_RS485_MODE
RS485_CONTROL1_PORT |= (1 << RS485_CONTROL1_IONUM); // start transmitting
#endif
#ifdef USART1_USE_SOFT_CTS
if (!(CTS1_PIN & (1 << CTS1_IONUM)))
#endif
{
UCSR1B_REGISTER |= (1 << UDRIE1_BIT); // enable UDRE interrupt
}
}
return COMPLETED;
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart1_putstr(char *string) {
char c;
while ((c = *string++))
uart1_putc(c);
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart1_putstr(char *string) {
asm volatile(
"\n\t"
"load_loop_%=:"
"ld r24, Z+ \n\t"
"and r24, r24 \n\t" // test for NULL
"breq skip_loop_%= \n\t"
"rcall uart1_putc \n\t" // Z pointer will not be affected in uart_putc()
"rjmp load_loop_%= \n\t"
"skip_loop_%=:"
: // outputs
: // inputs
"z"(string)
: // clobbers
"r24", "r25", "r26", "r27" // uart_putc()
);
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart1_putstrl(char *string, uint8_t BytesToWrite) {
while (BytesToWrite--)
uart1_putc(*string++);
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart1_putstrl(char *string, uint8_t BytesToWrite) {
asm volatile("\n\t"
"add %[counter], r30 \n\t" // add ZL to a counter to compare
// against current pointer (8 bit
// length, doesn't care if overflow)
"load_loop_%=:"
"cp %[counter], r30\n\t"
"breq skip_loop_%= \n\t"
"ld r24, Z+ \n\t"
"rcall uart1_putc \n\t" // counter and Z pointer will not be
// affected in uart_putc()
"rjmp load_loop_%= \n\t"
"skip_loop_%=:"
: // outputs
: // inputs
[counter] "r"(BytesToWrite),
"z"(string)
: // clobbers
"r24", "r25", "r26", "r27" // uart_putc()
);
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart1_puts_p(const __flash char *string) {
register char c;
while ((c = *string++))
uart1_putc(c);
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart1_puts_p(const __flash char *string) {
asm volatile(
"\n\t"
"load_loop_%=:"
"lpm r24, Z+ \n\t"
"and r24, r24 \n\t" // test for NULL
"breq skip_loop_%= \n\t"
"rcall uart1_putc \n\t" // Z pointer will not be affected in uart_putc()
"rjmp load_loop_%= \n\t"
"skip_loop_%=:"
: // outputs
: // inputs
"z"(string)
: // clobbers
"r24", "r25", "r26", "r27" // uart_putc()
);
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
void uart1_putint(int16_t data) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[7]; // heading, 5 digit bytes, NULL
#endif
itoa(data, u_tmp_buff, 10);
uart1_putstr(u_tmp_buff);
}
void uart1_putintr(int16_t data, uint8_t radix) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[17]; // heading, 15 digit bytes, NULL
#endif
itoa(data, u_tmp_buff, radix);
uart1_putstr(u_tmp_buff);
}
void uart1_putuint(uint16_t data) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[7]; // heading, 5 digit bytes, NULL
#endif
utoa(data, u_tmp_buff, 10);
uart1_putstr(u_tmp_buff);
}
void uart1_putuintr(uint16_t data, uint8_t radix) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[17]; // heading, 15 digit bytes, NULL
#endif
utoa(data, u_tmp_buff, radix);
uart1_putstr(u_tmp_buff);
}
void uart1_puthex(uint8_t data) {
uint8_t tmp;
tmp = (data >> 4) & 0x0f;
#ifdef USART_PUTHEX_IN_UPPERCASE
uart1_putc((tmp <= 9 ? '0' + tmp : 'A' - 10 + tmp));
#else
uart1_putc((tmp <= 9 ? '0' + tmp : 'a' - 10 + tmp));
#endif
tmp = data & 0x0f;
#ifdef USART_PUTHEX_IN_UPPERCASE
uart1_putc((tmp <= 9 ? '0' + tmp : 'A' - 10 + tmp));
#else
uart1_putc((tmp <= 9 ? '0' + tmp : 'a' - 10 + tmp));
#endif
}
void uart1_putlong(int32_t data) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[12]; // heading, 10 digit bytes, NULL
#endif
ltoa(data, u_tmp_buff, 10);
uart1_putstr(u_tmp_buff);
}
void uart1_putlongr(int32_t data, uint8_t radix) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[17]; // heading, 15 digit bytes, NULL
#endif
ltoa(data, u_tmp_buff, radix);
uart1_putstr(u_tmp_buff);
}
void uart1_putulong(uint32_t data) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[12]; // heading, 10 digit bytes, NULL
#endif
ultoa(data, u_tmp_buff, 10);
uart1_putstr(u_tmp_buff);
}
void uart1_putulongr(uint32_t data, uint8_t radix) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[17]; // heading, 15 digit bytes, NULL
#endif
ultoa(data, u_tmp_buff, radix);
uart1_putstr(u_tmp_buff);
}
void uart1_putfloat(float data) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[16];
#endif
dtostrf(data, 15, 6, u_tmp_buff);
char *p = u_tmp_buff;
while (*p == ' ') // remove all unwanted spaces
p++;
uart1_putstr(p);
}
void uart1_fputfloat(float data, uint8_t precision) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[16];
#endif
dtostrf(data, 15, precision, u_tmp_buff);
char *p = u_tmp_buff;
while (*p == ' ') // remove all unwanted spaces
p++;
uart1_putstr(p);
}
void uart1_flush(void) {
#ifdef USART1_RS485_MODE // flush UDR buffer
while (RS485_CONTROL1_PORT & (1 << RS485_CONTROL1_IONUM))
;
#else
while (tx1_Tail != tx1_Head)
; // just flush the ring buffer
#endif
}
#ifdef USART1_MPCM_MODE
void uart1_mpcm_transmit_addres_Frame(uint8_t dat) {
while (tx1_Tail != tx1_Head)
;
UCSR1B_REGISTER |= (1 << TXB81_BIT);
uart1_putc(dat);
while (tx1_Tail != tx1_Head)
;
UCSR1B_REGISTER &= ~(1 << TXB81_BIT); // not sure if necessary
}
#endif
#endif // NO_TX1_INTERRUPT
#ifndef NO_TX2_INTERRUPT
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart2_putc(char data) {
#ifdef PUTC2_CONVERT_LF_TO_CRLF
if (data == '\n')
uart2_putc('\r');
#endif
#ifdef USART2_PUTC_FAST_INSERTIONS
register uint8_t tmp_tx_Head = tx2_Head;
register uint8_t tmp_tx_Tail = tx2_Tail;
#ifdef USART2_USE_SOFT_CTS
if (!(CTS2_PIN & (1 << CTS2_IONUM)))
#endif
if (tmp_tx_Tail == tmp_tx_Head && (UCSR2A_REGISTER & UDRE2_BIT)) {
UDR2_REGISTER = data;
return;
}
tmp_tx_Head = (tmp_tx_Head + 1) & TX2_BUFFER_MASK;
while (tmp_tx_Tail == tmp_tx_Head) // wait for free space in buffer
{
tmp_tx_Tail =
tx2_Tail; // for faster pass through, results in a little bigger code
}
#else
register uint8_t tmp_tx_Head =
(tx2_Head + 1) &
TX2_BUFFER_MASK; // calculate new position of TX head in buffer
while (tx2_Tail == tmp_tx_Head)
; // wait for free space in buffer
#endif
tx2_buffer[tmp_tx_Head] = data;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
tx2_Head = tmp_tx_Head;
#ifdef USART2_RS485_MODE
RS485_CONTROL2_PORT |= (1 << RS485_CONTROL2_IONUM); // set high
#endif
#ifdef USART2_USE_SOFT_CTS
if (!(CTS2_PIN & (1 << CTS2_IONUM)))
#endif
{
UCSR2B_REGISTER |= (1 << UDRIE2_BIT); // enable UDRE interrupt
}
}
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart2_putc(char data) {
register uint8_t tmp_tx_Head asm("r25");
#ifdef PUTC2_CONVERT_LF_TO_CRLF
asm volatile("\n\t"
"cpi %[dat], '\n' \n\t"
"brne skip_recursive_%=\n\t"
"push %[dat] \n\t"
"ldi %[dat], '\r' \n\t"
"rcall uart2_putc \n\t"
"pop %[dat] \n\t"
"skip_recursive_%=:"
: // outputs
[dat] "+r"(data) // will be used later, do not let the compiler
// to do anything weird
: // inputs
: // clobbers
);
#endif
#ifdef USART2_PUTC_FAST_INSERTIONS
asm volatile(
"\n\t"
"lds %[head], (tx2_Head) \n\t"
#ifdef USART2_USE_SOFT_CTS
"sbic %M[cts_port], %M[cts_pin] \n\t"
"rjmp normal_insert_%= \n\t"
#endif
"lds r27, (tx2_Tail) \n\t"
"cpse r27, %[head] \n\t"
"rjmp normal_insert_%= \n\t"
"lds r26, %M[UDRE_reg] \n\t"
"sbrs r26, %M[udre_bit] \n\t"
"rjmp normal_insert_%= \n\t"
"sts %M[UDR_reg], %[dat] \n\t"
"ret \n\t"
"normal_insert_%=:"
"inc %[head] \n\t"
#if (TX2_BUFFER_MASK != 0xff)
"andi %[head], %M[mask] \n\t"
#endif
"waitforspace_%=:"
"lds r27, (tx2_Tail) \n\t"
"cp r27, %[head] \n\t"
"breq waitforspace_%= \n\t"
: // outputs
[head] "=r"(tmp_tx_Head),
[dat] "+r"(data)
: // inputs
#ifdef USART2_USE_SOFT_CTS
[cts_port] "M"(_SFR_IO_ADDR(CTS2_PORT)), [cts_pin] "M"(CTS2_IONUM),
#endif
[mask] "M"(TX2_BUFFER_MASK),
#if __AVR_ARCH__ == 103
[UDRE_reg] "n"(_SFR_MEM_ADDR(USR2_REGISTER)),
[UDRE_reg_IO] "M"(_SFR_IO_ADDR(USR2_REGISTER)),
#else
[UDRE_reg] "n"(_SFR_MEM_ADDR(UCSR2A_REGISTER)),
[UDRE_reg_IO] "M"(_SFR_IO_ADDR(UCSR2A_REGISTER)),
#endif
[UDR_reg] "n"(_SFR_MEM_ADDR(UDR2_REGISTER)),
[UDR_reg_IO] "M"(_SFR_IO_ADDR(UDR2_REGISTER)),
[udre_bit] "M"(UDRE2_BIT)
: // clobbers
"r26", "r27");
#else
asm volatile("\n\t"
"lds %[head], (tx2_Head) \n\t"
"inc %[head] \n\t"
#if (TX2_BUFFER_MASK != 0xff)
"andi %[head], %M[mask] \n\t"
#endif
"waitforspace_%=:"
"lds r27, (tx2_Tail) \n\t"
"cp r27, %[head] \n\t"
"breq waitforspace_%= \n\t"
: // outputs
[head] "=r"(tmp_tx_Head)
: // inputs
[mask] "M"(TX2_BUFFER_MASK)
: // clobbers
"r27");
#endif
asm volatile("\n\t"
"mov r26, %[index] \n\t"
"ldi r27, 0x00 \n\t"
"subi r26, lo8(-(tx2_buffer)) \n\t"
"sbci r27, hi8(-(tx2_buffer)) \n\t"
"st X, %[dat] \n\t"
: // outputs
[index] "+r"(tmp_tx_Head),
[dat] "+r"(data)
: // inputs
: // clobbers
"r26", "r27");
cli();
{
tx2_Head = tmp_tx_Head;
#ifdef USART2_RS485_MODE
RS485_CONTROL2_PORT |= (1 << RS485_CONTROL2_IONUM); // start transmitting
#endif
#ifdef USART2_USE_SOFT_CTS
if (!(CTS2_PIN & (1 << CTS2_IONUM)))
#endif
{
asm volatile("\n\t"
"lds r25, %M[control_reg] \n\t"
"ori r25, (1<<%M[udrie_bit]) \n\t"
"sts %M[control_reg], r25 \n\t"
: // outputs
: // inputs
#if __AVR_ARCH__ == 103
[control_reg] "n"(_SFR_MEM_ADDR(UCSR2A_REGISTER)),
#else
[control_reg] "n"(_SFR_MEM_ADDR(UCSR2B_REGISTER)),
#endif
[udrie_bit] "M"(UDRIE2_BIT)
: // clobbers
"r25");
}
}
reti();
asm volatile("\n\t" ::"r"(data)
:); // data was passed in r24 and will be returned in the same
// register, make sure it is not affected by the compiler
}
char uart2_putc_(char data) __attribute__((
alias("uart2_putc"))); // alias for uart_putc that returns passed argument
// unaffected by omitting any existent rule
#endif // USART_NO_ABI_BREAKING_PREMATURES
#ifdef USART_NO_ABI_BREAKING_PREMATURES
uint8_t uart2_putc_noblock(char data) {
#ifdef USART2_PUTC_FAST_INSERTIONS
register uint8_t tmp_tx_Head = tx2_Head;
register uint8_t tmp_tx_Tail = tx2_Tail;
#ifdef USART2_USE_SOFT_CTS
if (!(CTS2_PIN & (1 << CTS2_IONUM)))
#endif
if (tmp_tx_Tail == tmp_tx_Head && (UCSR2A_REGISTER & UDRE2_BIT)) {
UDR2_REGISTER = data;
return COMPLETED;
}
tmp_tx_Head = (tmp_tx_Head + 1) & TX2_BUFFER_MASK;
if (tmp_tx_Tail == tmp_tx_Head)
return BUFFER_FULL;
#else
register uint8_t tmp_tx_Head =
(tx2_Head + 1) &
TX2_BUFFER_MASK; // calculate new position of TX head in buffer
if (tx2_Tail == tmp_tx_Head)
return BUFFER_FULL;
#endif
tx2_buffer[tmp_tx_Head] = data;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
tx2_Head = tmp_tx_Head;
#ifdef USART2_RS485_MODE
RS485_CONTROL2_PORT |= (1 << RS485_CONTROL2_IONUM); // set high
#endif
#ifdef USART2_USE_SOFT_CTS
if (!(CTS2_PIN & (1 << CTS2_IONUM)))
#endif
{
UCSR2B_REGISTER |= (1 << UDRIE2_BIT); // enable UDRE interrupt
}
}
return COMPLETED;
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
uint8_t uart2_putc_noblock(char data) {
#ifdef USART2_PUTC_FAST_INSERTIONS
register uint8_t tmp_tx_Head = tx2_Head;
register uint8_t tmp_tx_Tail = tx2_Tail;
#ifdef USART2_USE_SOFT_CTS
if (!(CTS2_PIN & (1 << CTS2_IONUM)))
#endif
if (tmp_tx_Tail == tmp_tx_Head && (UCSR2A_REGISTER & UDRE2_BIT)) {
UDR2_REGISTER = data;
return COMPLETED;
}
tmp_tx_Head = (tmp_tx_Head + 1) & TX2_BUFFER_MASK;
if (tmp_tx_Tail == tmp_tx_Head)
return BUFFER_FULL;
#else
register uint8_t tmp_tx_Head =
(tx2_Head + 1) &
TX2_BUFFER_MASK; // calculate new position of TX head in buffer
if (tx2_Tail == tmp_tx_Head)
return BUFFER_FULL;
#endif
asm volatile("\n\t"
"mov r26, %[index] \n\t"
"ldi r27, 0x00 \n\t"
"subi r26, lo8(-(tx2_buffer)) \n\t"
"sbci r27, hi8(-(tx2_buffer)) \n\t"
"st X, %[dat] \n\t"
: // outputs
[index] "+r"(tmp_tx_Head),
[dat] "+r"(data)
: // inputs
: // clobbers
"r26", "r27");
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
tx2_Head = tmp_tx_Head;
#ifdef USART2_RS485_MODE
RS485_CONTROL2_PORT |= (1 << RS485_CONTROL2_IONUM); // start transmitting
#endif
#ifdef USART2_USE_SOFT_CTS
if (!(CTS2_PIN & (1 << CTS2_IONUM)))
#endif
{
UCSR2B_REGISTER |= (1 << UDRIE2_BIT); // enable UDRE interrupt
}
}
return COMPLETED;
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart2_putstr(char *string) {
char c;
while ((c = *string++))
uart2_putc(c);
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart2_putstr(char *string) {
asm volatile(
"\n\t"
"load_loop_%=:"
"ld r24, Z+ \n\t"
"and r24, r24 \n\t" // test for NULL
"breq skip_loop_%= \n\t"
"rcall uart2_putc \n\t" // Z pointer will not be affected in uart_putc()
"rjmp load_loop_%= \n\t"
"skip_loop_%=:"
: // outputs
: // inputs
"z"(string)
: // clobbers
"r24", "r25", "r26", "r27" // uart_putc()
);
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart2_putstrl(char *string, uint8_t BytesToWrite) {
while (BytesToWrite--)
uart2_putc(*string++);
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart2_putstrl(char *string, uint8_t BytesToWrite) {
asm volatile("\n\t"
"add %[counter], r30 \n\t" // add ZL to a counter to compare
// against current pointer (8 bit
// length, doesn't care if overflow)
"load_loop_%=:"
"cp %[counter], r30\n\t"
"breq skip_loop_%= \n\t"
"ld r24, Z+ \n\t"
"rcall uart2_putc \n\t" // counter and Z pointer will not be
// affected in uart_putc()
"rjmp load_loop_%= \n\t"
"skip_loop_%=:"
: // outputs
: // inputs
[counter] "r"(BytesToWrite),
"z"(string)
: // clobbers
"r24", "r25", "r26", "r27" // uart_putc()
);
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart2_puts_p(const __flash char *string) {
register char c;
while ((c = *string++))
uart2_putc(c);
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart2_puts_p(const __flash char *string) {
asm volatile(
"\n\t"
"load_loop_%=:"
"lpm r24, Z+ \n\t"
"and r24, r24 \n\t" // test for NULL
"breq skip_loop_%= \n\t"
"rcall uart2_putc \n\t" // Z pointer will not be affected in uart_putc()
"rjmp load_loop_%= \n\t"
"skip_loop_%=:"
: // outputs
: // inputs
"z"(string)
: // clobbers
"r24", "r25", "r26", "r27" // uart_putc()
);
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
void uart2_putint(int16_t data) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[7]; // heading, 5 digit bytes, NULL
#endif
itoa(data, u_tmp_buff, 10);
uart2_putstr(u_tmp_buff);
}
void uart2_putintr(int16_t data, uint8_t radix) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[17]; // heading, 15 digit bytes, NULL
#endif
itoa(data, u_tmp_buff, radix);
uart2_putstr(u_tmp_buff);
}
void uart2_putuint(uint16_t data) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[7]; // heading, 5 digit bytes, NULL
#endif
utoa(data, u_tmp_buff, 10);
uart2_putstr(u_tmp_buff);
}
void uart2_putuintr(uint16_t data, uint8_t radix) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[17]; // heading, 15 digit bytes, NULL
#endif
utoa(data, u_tmp_buff, radix);
uart2_putstr(u_tmp_buff);
}
void uart2_puthex(uint8_t data) {
uint8_t tmp;
tmp = (data >> 4) & 0x0f;
#ifdef USART_PUTHEX_IN_UPPERCASE
uart2_putc((tmp <= 9 ? '0' + tmp : 'A' - 10 + tmp));
#else
uart2_putc((tmp <= 9 ? '0' + tmp : 'a' - 10 + tmp));
#endif
tmp = data & 0x0f;
#ifdef USART_PUTHEX_IN_UPPERCASE
uart2_putc((tmp <= 9 ? '0' + tmp : 'A' - 10 + tmp));
#else
uart2_putc((tmp <= 9 ? '0' + tmp : 'a' - 10 + tmp));
#endif
}
void uart2_putlong(int32_t data) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[12]; // heading, 10 digit bytes, NULL
#endif
ltoa(data, u_tmp_buff, 10);
uart2_putstr(u_tmp_buff);
}
void uart2_putlongr(int32_t data, uint8_t radix) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[17]; // heading, 15 digit bytes, NULL
#endif
ltoa(data, u_tmp_buff, radix);
uart2_putstr(u_tmp_buff);
}
void uart2_putulong(uint32_t data) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[12]; // heading, 10 digit bytes, NULL
#endif
ultoa(data, u_tmp_buff, 10);
uart2_putstr(u_tmp_buff);
}
void uart2_putulongr(uint32_t data, uint8_t radix) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[17]; // heading, 15 digit bytes, NULL
#endif
ultoa(data, u_tmp_buff, radix);
uart2_putstr(u_tmp_buff);
}
void uart2_putfloat(float data) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[16];
#endif
dtostrf(data, 15, 6, u_tmp_buff);
char *p = u_tmp_buff;
while (*p == ' ') // remove all unwanted spaces
p++;
uart2_putstr(p);
}
void uart2_fputfloat(float data, uint8_t precision) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[16];
#endif
dtostrf(data, 15, precision, u_tmp_buff);
char *p = u_tmp_buff;
while (*p == ' ') // remove all unwanted spaces
p++;
uart2_putstr(p);
}
void uart2_flush(void) {
#ifdef USART2_RS485_MODE // flush UDR buffer
while (RS485_CONTROL2_PORT & (1 << RS485_CONTROL2_IONUM))
;
#else
while (tx2_Tail != tx2_Head)
; // just flush the ring buffer
#endif
}
#ifdef USART2_MPCM_MODE
void uart2_mpcm_transmit_addres_Frame(uint8_t dat) {
while (tx2_Tail != tx2_Head)
;
UCSR2B_REGISTER |= (1 << TXB82_BIT);
uart2_putc(dat);
while (tx2_Tail != tx2_Head)
;
UCSR2B_REGISTER &= ~(1 << TXB82_BIT); // not sure if necessary
}
#endif
#endif // NO_TX2_INTERRUPT
#ifndef NO_TX3_INTERRUPT
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart3_putc(char data) {
#ifdef PUTC3_CONVERT_LF_TO_CRLF
if (data == '\n')
uart3_putc('\r');
#endif
#ifdef USART3_PUTC_FAST_INSERTIONS
register uint8_t tmp_tx_Head = tx3_Head;
register uint8_t tmp_tx_Tail = tx3_Tail;
#ifdef USART3_USE_SOFT_CTS
if (!(CTS3_PIN & (1 << CTS3_IONUM)))
#endif
if (tmp_tx_Tail == tmp_tx_Head && (UCSR3A_REGISTER & UDRE3_BIT)) {
UDR3_REGISTER = data;
return;
}
tmp_tx_Head = (tmp_tx_Head + 1) & TX3_BUFFER_MASK;
while (tmp_tx_Tail == tmp_tx_Head) // wait for free space in buffer
{
tmp_tx_Tail =
tx3_Tail; // for faster pass through, results in a little bigger code
}
#else
register uint8_t tmp_tx_Head =
(tx3_Head + 1) &
TX3_BUFFER_MASK; // calculate new position of TX head in buffer
while (tx3_Tail == tmp_tx_Head)
; // wait for free space in buffer
#endif
tx3_buffer[tmp_tx_Head] = data;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
tx3_Head = tmp_tx_Head;
#ifdef USART3_RS485_MODE
RS485_CONTROL3_PORT |= (1 << RS485_CONTROL3_IONUM); // set high
#endif
#ifdef USART3_USE_SOFT_CTS
if (!(CTS3_PIN & (1 << CTS3_IONUM)))
#endif
{
UCSR3B_REGISTER |= (1 << UDRIE3_BIT); // enable UDRE interrupt
}
}
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart3_putc(char data) {
register uint8_t tmp_tx_Head asm("r25");
#ifdef PUTC3_CONVERT_LF_TO_CRLF
asm volatile("\n\t"
"cpi %[dat], '\n' \n\t"
"brne skip_recursive_%=\n\t"
"push %[dat] \n\t"
"ldi %[dat], '\r' \n\t"
"rcall uart3_putc \n\t"
"pop %[dat] \n\t"
"skip_recursive_%=:"
: // outputs
[dat] "+r"(data) // will be used later, do not let the compiler
// to do anything weird
: // inputs
: // clobbers
);
#endif
#ifdef USART3_PUTC_FAST_INSERTIONS
asm volatile(
"\n\t"
"lds %[head], (tx3_Head) \n\t"
#ifdef USART3_USE_SOFT_CTS
"sbic %M[cts_port], %M[cts_pin] \n\t"
"rjmp normal_insert_%= \n\t"
#endif
"lds r27, (tx3_Tail) \n\t"
"cpse r27, %[head] \n\t"
"rjmp normal_insert_%= \n\t"
"lds r26, %M[UDRE_reg] \n\t"
"sbrs r26, %M[udre_bit] \n\t"
"rjmp normal_insert_%= \n\t"
"sts %M[UDR_reg], %[dat] \n\t"
"ret \n\t"
"normal_insert_%=:"
"inc %[head] \n\t"
#if (TX3_BUFFER_MASK != 0xff)
"andi %[head], %M[mask] \n\t"
#endif
"waitforspace_%=:"
"lds r27, (tx3_Tail) \n\t"
"cp r27, %[head] \n\t"
"breq waitforspace_%= \n\t"
: // outputs
[head] "=r"(tmp_tx_Head),
[dat] "+r"(data)
: // inputs
#ifdef USART3_USE_SOFT_CTS
[cts_port] "M"(_SFR_IO_ADDR(CTS3_PORT)), [cts_pin] "M"(CTS3_IONUM),
#endif
[mask] "M"(TX2_BUFFER_MASK),
#if __AVR_ARCH__ == 103
[UDRE_reg] "n"(_SFR_MEM_ADDR(USR3_REGISTER)),
[UDRE_reg_IO] "M"(_SFR_IO_ADDR(USR3_REGISTER)),
#else
[UDRE_reg] "n"(_SFR_MEM_ADDR(UCSR3A_REGISTER)),
[UDRE_reg_IO] "M"(_SFR_IO_ADDR(UCSR3A_REGISTER)),
#endif
[UDR_reg] "n"(_SFR_MEM_ADDR(UDR3_REGISTER)),
[UDR_reg_IO] "M"(_SFR_IO_ADDR(UDR3_REGISTER)),
[udre_bit] "M"(UDRE3_BIT)
: // clobbers
"r26", "r27");
#else
asm volatile("\n\t"
"lds %[head], (tx3_Head) \n\t"
"inc %[head] \n\t"
#if (TX3_BUFFER_MASK != 0xff)
"andi %[head], %M[mask] \n\t"
#endif
"waitforspace_%=:"
"lds r27, (tx3_Tail) \n\t"
"cp r27, %[head] \n\t"
"breq waitforspace_%= \n\t"
: // outputs
[head] "=r"(tmp_tx_Head)
: // inputs
[mask] "M"(TX3_BUFFER_MASK)
: // clobbers
"r27");
#endif
asm volatile("\n\t"
"mov r26, %[index] \n\t"
"ldi r27, 0x00 \n\t"
"subi r26, lo8(-(tx3_buffer)) \n\t"
"sbci r27, hi8(-(tx3_buffer)) \n\t"
"st X, %[dat] \n\t"
: // outputs
[index] "+r"(tmp_tx_Head),
[dat] "+r"(data)
: // inputs
: // clobbers
"r26", "r27");
cli();
{
tx3_Head = tmp_tx_Head;
#ifdef USART3_RS485_MODE
RS485_CONTROL3_PORT |= (1 << RS485_CONTROL3_IONUM); // start transmitting
#endif
#ifdef USART3_USE_SOFT_CTS
if (!(CTS3_PIN & (1 << CTS3_IONUM)))
#endif
{
asm volatile("\n\t"
"lds r25, %M[control_reg] \n\t"
"ori r25, (1<<%M[udrie_bit]) \n\t"
"sts %M[control_reg], r25 \n\t"
: // outputs
: // inputs
#if __AVR_ARCH__ == 103
[control_reg] "n"(_SFR_MEM_ADDR(UCSR3A_REGISTER)),
#else
[control_reg] "n"(_SFR_MEM_ADDR(UCSR3B_REGISTER)),
#endif
[udrie_bit] "M"(UDRIE3_BIT)
: // clobbers
"r25");
}
}
reti();
asm volatile("\n\t" ::"r"(data)
:); // data was passed in r24 and will be returned in the same
// register, make sure it is not affected by the compiler
}
char uart3_putc_(char data) __attribute__((
alias("uart3_putc"))); // alias for uart_putc that returns passed argument
// unaffected by omitting any existent rule
#endif // USART_NO_ABI_BREAKING_PREMATURES
#ifdef USART_NO_ABI_BREAKING_PREMATURES
uint8_t uart3_putc_noblock(char data) {
#ifdef USART3_PUTC_FAST_INSERTIONS
register uint8_t tmp_tx_Head = tx3_Head;
register uint8_t tmp_tx_Tail = tx3_Tail;
#ifdef USART3_USE_SOFT_CTS
if (!(CTS3_PIN & (1 << CTS3_IONUM)))
#endif
if (tmp_tx_Tail == tmp_tx_Head && (UCSR3A_REGISTER & UDRE3_BIT)) {
UDR3_REGISTER = data;
return COMPLETED;
}
tmp_tx_Head = (tmp_tx_Head + 1) & TX3_BUFFER_MASK;
if (tmp_tx_Tail == tmp_tx_Head)
return BUFFER_FULL;
#else
register uint8_t tmp_tx_Head =
(tx3_Head + 1) &
TX3_BUFFER_MASK; // calculate new position of TX head in buffer
if (tx3_Tail == tmp_tx_Head)
return BUFFER_FULL;
#endif
tx3_buffer[tmp_tx_Head] = data;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
tx3_Head = tmp_tx_Head;
#ifdef USART3_RS485_MODE
RS485_CONTROL3_PORT |= (1 << RS485_CONTROL3_IONUM); // set high
#endif
#ifdef USART3_USE_SOFT_CTS
if (!(CTS3_PIN & (1 << CTS3_IONUM)))
#endif
{
UCSR3B_REGISTER |= (1 << UDRIE3_BIT); // enable UDRE interrupt
}
}
return COMPLETED;
}
#else //! USART_NO_ABI_BREAKING_PREMATURES
uint8_t uart3_putc_noblock(char data) {
#ifdef USART3_PUTC_FAST_INSERTIONS
register uint8_t tmp_tx_Head = tx3_Head;
register uint8_t tmp_tx_Tail = tx3_Tail;
#ifdef USART3_USE_SOFT_CTS
if (!(CTS3_PIN & (1 << CTS3_IONUM)))
#endif
if (tmp_tx_Tail == tmp_tx_Head && (UCSR3A_REGISTER & UDRE3_BIT)) {
UDR3_REGISTER = data;
return COMPLETED;
}
tmp_tx_Head = (tmp_tx_Head + 1) & TX3_BUFFER_MASK;
if (tmp_tx_Tail == tmp_tx_Head)
return BUFFER_FULL;
#else
register uint8_t tmp_tx_Head =
(tx3_Head + 1) &
TX3_BUFFER_MASK; // calculate new position of TX head in buffer
if (tx3_Tail == tmp_tx_Head)
return BUFFER_FULL;
#endif
asm volatile("\n\t"
"mov r26, %[index] \n\t"
"ldi r27, 0x00 \n\t"
"subi r26, lo8(-(tx3_buffer)) \n\t"
"sbci r27, hi8(-(tx3_buffer)) \n\t"
"st X, %[dat] \n\t"
: // outputs
[index] "+r"(tmp_tx_Head),
[dat] "+r"(data)
: // inputs
: // clobbers
"r26", "r27");
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
tx3_Head = tmp_tx_Head;
#ifdef USART3_RS485_MODE
RS485_CONTROL3_PORT |= (1 << RS485_CONTROL3_IONUM); // start transmitting
#endif
#ifdef USART3_USE_SOFT_CTS
if (!(CTS3_PIN & (1 << CTS3_IONUM)))
#endif
{
UCSR3B_REGISTER |= (1 << UDRIE3_BIT); // enable UDRE interrupt
}
}
return COMPLETED;
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart3_putstr(char *string) {
char c;
while ((c = *string++))
uart3_putc(c);
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart3_putstr(char *string) {
asm volatile(
"\n\t"
"load_loop_%=:"
"ld r24, Z+ \n\t"
"and r24, r24 \n\t" // test for NULL
"breq skip_loop_%= \n\t"
"rcall uart3_putc \n\t" // Z pointer will not be affected in uart_putc()
"rjmp load_loop_%= \n\t"
"skip_loop_%=:"
: // outputs
: // inputs
"z"(string)
: // clobbers
"r24", "r25", "r26", "r27" // uart_putc()
);
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart3_putstrl(char *string, uint8_t BytesToWrite) {
while (BytesToWrite--)
uart3_putc(*string++);
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart3_putstrl(char *string, uint8_t BytesToWrite) {
asm volatile("\n\t"
"add %[counter], r30 \n\t" // add ZL to a counter to compare
// against current pointer (8 bit
// length, doesn't care if overflow)
"load_loop_%=:"
"cp %[counter], r30\n\t"
"breq skip_loop_%= \n\t"
"ld r24, Z+ \n\t"
"rcall uart3_putc \n\t" // counter and Z pointer will not be
// affected in uart_putc()
"rjmp load_loop_%= \n\t"
"skip_loop_%=:"
: // outputs
: // inputs
[counter] "r"(BytesToWrite),
"z"(string)
: // clobbers
"r24", "r25", "r26", "r27" // uart_putc()
);
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart3_puts_p(const __flash char *string) {
register char c;
while ((c = *string++))
uart3_putc(c);
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart3_puts_p(const __flash char *string) {
asm volatile(
"\n\t"
"load_loop_%=:"
"lpm r24, Z+ \n\t"
"and r24, r24 \n\t" // test for NULL
"breq skip_loop_%= \n\t"
"rcall uart3_putc \n\t" // Z pointer will not be affected in uart_putc()
"rjmp load_loop_%= \n\t"
"skip_loop_%=:"
: // outputs
: // inputs
"z"(string)
: // clobbers
"r24", "r25", "r26", "r27" // uart_putc()
);
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
void uart3_putint(int16_t data) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[7]; // heading, 5 digit bytes, NULL
#endif
itoa(data, u_tmp_buff, 10);
uart3_putstr(u_tmp_buff);
}
void uart3_putintr(int16_t data, uint8_t radix) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[17]; // heading, 15 digit bytes, NULL
#endif
itoa(data, u_tmp_buff, radix);
uart3_putstr(u_tmp_buff);
}
void uart3_putuint(uint16_t data) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[7]; // heading, 5 digit bytes, NULL
#endif
utoa(data, u_tmp_buff, 10);
uart3_putstr(u_tmp_buff);
}
void uart3_putuintr(uint16_t data, uint8_t radix) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[17]; // heading, 15 digit bytes, NULL
#endif
utoa(data, u_tmp_buff, radix);
uart3_putstr(u_tmp_buff);
}
void uart3_puthex(uint8_t data) {
uint8_t tmp;
tmp = (data >> 4) & 0x0f;
#ifdef USART_PUTHEX_IN_UPPERCASE
uart3_putc((tmp <= 9 ? '0' + tmp : 'A' - 10 + tmp));
#else
uart3_putc((tmp <= 9 ? '0' + tmp : 'a' - 10 + tmp));
#endif
tmp = data & 0x0f;
#ifdef USART_PUTHEX_IN_UPPERCASE
uart3_putc((tmp <= 9 ? '0' + tmp : 'A' - 10 + tmp));
#else
uart3_putc((tmp <= 9 ? '0' + tmp : 'a' - 10 + tmp));
#endif
}
void uart3_putlong(int32_t data) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[12]; // heading, 10 digit bytes, NULL
#endif
ltoa(data, u_tmp_buff, 10);
uart3_putstr(u_tmp_buff);
}
void uart3_putlongr(int32_t data, uint8_t radix) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[17]; // heading, 15 digit bytes, NULL
#endif
ltoa(data, u_tmp_buff, radix);
uart3_putstr(u_tmp_buff);
}
void uart3_putulong(uint32_t data) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[12]; // heading, 10 digit bytes, NULL
#endif
ultoa(data, u_tmp_buff, 10);
uart3_putstr(u_tmp_buff);
}
void uart3_putulongr(uint32_t data, uint8_t radix) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[17]; // heading, 15 digit bytes, NULL
#endif
ultoa(data, u_tmp_buff, radix);
uart3_putstr(u_tmp_buff);
}
void uart3_putfloat(float data) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[16];
#endif
dtostrf(data, 15, 6, u_tmp_buff);
char *p = u_tmp_buff;
while (*p == ' ') // remove all unwanted spaces
p++;
uart3_putstr(p);
}
void uart3_fputfloat(float data, uint8_t precision) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[16];
#endif
dtostrf(data, 15, precision, u_tmp_buff);
char *p = u_tmp_buff;
while (*p == ' ') // remove all unwanted spaces
p++;
uart3_putstr(p);
}
void uart3_flush(void) {
#ifdef USART3_RS485_MODE // flush UDR buffer
while (RS485_CONTROL3_PORT & (1 << RS485_CONTROL3_IONUM))
;
#else
while (tx3_Tail != tx3_Head)
; // just flush the ring buffer
#endif
}
#ifdef USART3_MPCM_MODE
void uart3_mpcm_transmit_addres_Frame(uint8_t dat) {
while (tx3_Tail != tx3_Head)
;
UCSR3B_REGISTER |= (1 << TXB83_BIT);
uart3_putc(dat);
while (tx3_Tail != tx3_Head)
;
UCSR3B_REGISTER &= ~(1 << TXB83_BIT); // not sure if necessary
}
#endif
#endif // NO_TX3_INTERRUPT
#endif // NO_USART_TX
#ifndef NO_USART_RX
#ifndef NO_RX0_INTERRUPT
//******************************************************************
// Function : To receive single character/byte.
// Arguments : none
// Return : Received character or NULL if buffer is empty.
//******************************************************************
#ifdef USART_NO_ABI_BREAKING_PREMATURES
char uart0_getc(void) {
register uint8_t tmp_rx_Tail = rx0_Tail;
char tmp;
if (tmp_rx_Tail == rx0_Head)
return 0;
tmp_rx_Tail = (tmp_rx_Tail + 1) & RX0_BUFFER_MASK;
tmp = rx0_buffer[tmp_rx_Tail];
rx0_Tail = tmp_rx_Tail;
#ifdef USART0_EXTEND_RX_BUFFER
#if __AVR_ARCH__ == 103
UCSR0A_REGISTER |= (1 << RXCIE0_BIT);
#else
UCSR0B_REGISTER |= (1 << RXCIE0_BIT);
#endif
#endif
#ifdef USART0_USE_SOFT_RTS
if (RTS0_PORT & (1 << RTS0_IONUM))
#if __AVR_ARCH__ == 103
if (!(USR0_REGISTER & (1 << RXC0_BIT)))
#else
// isr has fired so check if there is no unread data in UDR (if missed
// then next read will release RTS line)
if (!(UCSR0A_REGISTER & (1 << RXC0_BIT)))
#endif
RTS0_PORT &= ~(1 << RTS0_IONUM);
#endif
#ifdef RX0_GETC_ECHO
#ifdef RX_NEWLINE_MODE_N
if (tmp == '\n')
uart0_putc('\r');
#endif
tmp = uart0_putc_(tmp);
#ifdef RX_NEWLINE_MODE_R
if (tmp == '\r')
uart0_putc('\n');
#endif
#endif // RX0_GETC_ECHO
return tmp;
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
char uart0_getc(void) {
register uint8_t tmp_rx_Tail asm("r25");
char tmp;
tmp_rx_Tail = rx0_Tail;
if (tmp_rx_Tail == rx0_Head)
return 0;
tmp_rx_Tail = (tmp_rx_Tail + 1) & RX0_BUFFER_MASK;
asm volatile("\n\t"
"mov r26, %[index] \n\t"
#if !defined(__AVR_ATtiny2313__) && \
!defined(__AVR_ATtiny2313A__) // on ATtiny2313 upper byte in pointer
// pair is ignored
"ldi r27, 0x00 \n\t"
#endif
"subi r26, lo8(-(rx0_buffer)) \n\t"
#ifndef USART_USE_TINY_MEMORY_MODEL
"sbci r27, hi8(-(rx0_buffer)) \n\t"
#endif
"ld %[temp], X \n\t"
: // outputs
[index] "+r"(tmp_rx_Tail),
[temp] "=r"(tmp)
: // inputs
: // clobbers
#if !defined(__AVR_ATtiny2313__) && !defined(__AVR_ATtiny2313A__)
"r27",
#endif
"r26");
rx0_Tail = tmp_rx_Tail;
#ifdef USART0_EXTEND_RX_BUFFER
#if __AVR_ARCH__ == 103
UCSR0A_REGISTER |= (1 << RXCIE0_BIT);
#else
UCSR0B_REGISTER |= (1 << RXCIE0_BIT);
#endif
#endif
#ifdef USART0_USE_SOFT_RTS
if (RTS0_PORT & (1 << RTS0_IONUM))
#if __AVR_ARCH__ == 103
if (!(USR0_REGISTER & (1 << RXC0_BIT)))
#else
// isr has fired so check if there is no unread data in UDR (if missed
// then next read will release RTS line)
if (!(UCSR0A_REGISTER & (1 << RXC0_BIT)))
#endif
RTS0_PORT &= ~(1 << RTS0_IONUM);
#endif
#ifdef RX0_GETC_ECHO
#ifdef RX_NEWLINE_MODE_N
if (tmp == '\n')
uart0_putc('\r');
#endif
tmp = uart0_putc_(tmp);
#ifdef RX_NEWLINE_MODE_R
if (tmp == '\r')
uart0_putc('\n');
#endif
#endif // RX0_GETC_ECHO
return tmp;
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
//******************************************************************
// Function : Reads actual string from receiver buffer.
// Arguments : Pointer to array to fill with received string.
// Return : none
// Note : Received string will be terminated by NULL.
// : OBSOLETE - possibility of buffer overflows
//******************************************************************
// void uart0_getBuffer(char *buffer)
// {
// do *buffer = uart_getc();
// while(*buffer++);
// }
//******************************************************************
// Function : Reads string from receiver buffer
// Arguments : 1. Pointer to array to fill with received string.
// : 2. Limit for receiving string size (array size)
// Return : none
// Note : Received string will be terminated by NULL positioned at
// bufferlimit-1
// : or at the end of the string if it's shorter than bufferlimit-1
// : terminators CR LF will not be cut
//******************************************************************
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart0_gets(char *buffer, uint8_t bufferlimit) {
while (--bufferlimit) {
*buffer = uart0_getc();
if (*buffer++ == 0)
break;
}
*buffer = 0;
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart0_gets(char *buffer, uint8_t bufferlimit) {
asm volatile("\n\t"
"loop_%=:"
"dec %[limit] \n\t"
"breq store_NULL_%= \n\t" // buffer limit hit, quit loop
"rcall uart0_getc \n\t" // counter and Z pointer will not be
// affected in uart_getc()
"st Z+, r24 \n\t"
"cpse r24, __zero_reg__ \n\t"
"rjmp loop_%= \n\t"
"store_NULL_%=:"
"st Z, __zero_reg__ \n\t"
: // outputs
: // inputs
"z"(buffer),
[limit] "r"(bufferlimit)
: // clobbers
"r24", "r25", "r26", "r27" // uart_getc()
);
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
//******************************************************************
// Function : Reads one line from the receiver buffer. (waits for EOL
// terminator) Arguments : 1. Pointer to array to fill with received string.
// : 2. Limit for receiving string size (array size)
// Return : none
// Note : Received string will be terminated by NULL positioned at
// bufferlimit-1
// : or at the end of the string if it's shorter than bufferlimit-1
// : CR and LF terminators will be cut.
// : Function will return if bufferlimit is reached without waiting
// for newline terminator
//******************************************************************
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart0_getln(char *buffer, uint8_t bufferlimit) {
while (--bufferlimit) {
do {
*buffer = uart0_getc();
} while (*buffer == 0);
#ifdef RX_NEWLINE_MODE_N
if (*buffer == '\n')
#else
if (*buffer == '\r')
#endif
{
#ifdef RX_NEWLINE_MODE_RN
while (!(uart0_getc()))
;
#endif
break;
}
buffer++;
}
*buffer = 0;
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart0_getln(char *buffer, uint8_t bufferlimit) {
asm volatile("\n\t"
"loop_%=:"
"dec %[limit] \n\t"
"breq store_NULL_%= \n\t" // buffer limit hit, quit loop
"wait_loop_%=:"
"rcall uart0_getc \n\t" // counter and Z pointer will not be
// affected in uart_getc()
"and r24, r24 \n\t" // test for NULL
"breq wait_loop_%= \n\t"
#ifdef RX_NEWLINE_MODE_N
"cpi r24, '\n' \n\t"
#else
"cpi r24, '\r' \n\t"
#endif
#ifdef RX_NEWLINE_MODE_RN
"breq wait_loop2_%= \n\t"
#else
"breq store_NULL_%= \n\t"
#endif
"st Z+, r24 \n\t"
"rjmp loop_%= \n\t"
#ifdef RX_NEWLINE_MODE_RN
"wait_loop2_%=:"
"rcall uart0_getc \n\t"
"and r24, r24 \n\t"
"breq wait_loop2_%= \n\t"
#endif
"store_NULL_%=:"
"st Z, __zero_reg__ \n\t"
: // outputs
: // inputs
"z"(buffer),
[limit] "r"(bufferlimit)
: // clobbers
"r24");
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
//******************************************************************
// Function : Reads burst of characters until first whitespace (waits for
// EOL terminator or first whitespace) Arguments : 1. Pointer to array to
// fill with received string.
// : 2. Limit for receiving string size (array size)
// Return : none
// Note : Received string will be terminated by NULL positioned at
// bufferlimit-1
// : or at the end of the string if it's shorter than bufferlimit-1
// : CR and LF terminators will be cut.
// : Function will return if bufferlimit is reached without waiting
// for newline terminator : Function will cut all whitespaces
// before first nonspace character
//******************************************************************
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart0_getlnToFirstWhiteSpace(char *buffer, uint8_t bufferlimit) {
do {
*buffer = uart0_getc();
} while (*buffer <= 32);
buffer++;
bufferlimit--;
while (--bufferlimit) {
do {
*buffer = uart0_getc();
} while (*buffer == 0);
#ifdef RX_NEWLINE_MODE_N
if (*buffer == '\n')
#else
if (*buffer == '\r')
#endif
{
#ifdef RX_NEWLINE_MODE_RN
while (!(uart0_getc()))
;
#endif
break;
} else if (*buffer <= 32)
break; // string reading is done, we will exit
buffer++;
}
*buffer = 0;
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart0_getlnToFirstWhiteSpace(char *buffer, uint8_t bufferlimit) {
asm volatile(
"\n\t"
"skip_whitespaces_loop_%=:"
"rcall uart0_getc \n\t" // counter and Z pointer will not be affected in
// uart0_getc()
"cpi r24, 0x21\n\t" // if(tmp <= 32)
"brcs skip_whitespaces_loop_%= \n\t" // skip all received whitespaces
"st Z+, r24 \n\t"
"dec %[limit] \n\t"
"loop_%=:"
"dec %[limit] \n\t"
"breq store_NULL_%= \n\t" // buffer limit hit, quit loop
"wait_loop_%=:"
"rcall uart0_getc \n\t" // counter and Z pointer will not be affected in
// uart_getc()
"and r24, r24 \n\t" // test for NULL
"breq wait_loop_%= \n\t"
#ifdef RX_NEWLINE_MODE_N
"cpi r24, '\n' \n\t"
#else
"cpi r24, '\r' \n\t"
#endif
#ifdef RX_NEWLINE_MODE_RN
"breq exit_wait_loop_%= \n\t"
#else
"breq store_NULL_%= \n\t"
#endif
"cpi r24, 0x21 \n\t" // if(tmp <= 32)
"brcs store_NULL_%= \n\t" // whitespace means end of this function, quit
// loop
"st Z+, r24 \n\t"
"rjmp loop_%=\n\t"
#ifdef RX_NEWLINE_MODE_RN
"exit_wait_loop_%=:"
"rcall uart0_getc \n\t"
"and r24, r24 \n\t" // test for NULL
"breq exit_wait_loop_%= \n\t"
#endif
"store_NULL_%=:"
"st Z, __zero_reg__ \n\t"
: // outputs
: // inputs
"z"(buffer),
[limit] "r"(bufferlimit)
: // clobbers
"r24", "r25", "r26", "r27" // uart_getc()
);
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
//******************************************************************
// Function : To skip all incoming whitespace characters until first nonspace
// character. Arguments : none Return : First received nonspace character.
// Note : First nonspace character is cut from receiver buffer.
//******************************************************************
// char uart0_skipWhiteSpaces(void)
// {
// register char c;
//
// do{
// c = uart0_getc();
// }while(c <= 32);
//
// return c;
// }
//******************************************************************
// Function : Read 16bit integer value from the input stream.
// Arguments : none
// Return : Received 16bit integer value.
//******************************************************************
int16_t uart0_getint(void) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[7]; // heading, 5 digit bytes, NULL
#endif
uart0_getlnToFirstWhiteSpace(u_tmp_buff, 7);
return atoi(u_tmp_buff);
}
//******************************************************************
// Function : Read 32bit integer value from the input stream.
// Arguments : none
// Return : Received 32bit integer value
//******************************************************************
int32_t uart0_getlong(void) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[12]; // heading, 10 digit bytes, NULL
#endif
uart0_getlnToFirstWhiteSpace(u_tmp_buff, 12);
return atol(u_tmp_buff);
}
//******************************************************************
// Function : Read floating point value from the input stream.
// Arguments : none
// Return : Received float value.
//******************************************************************
float uart0_getfloat(void) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[32];
#endif
uart0_getlnToFirstWhiteSpace(u_tmp_buff, 32);
return atof(u_tmp_buff);
}
//******************************************************************
// Function : To receive single byte in binary transmission.
// Arguments : none
// Return : Signed 16 bit integer containing data in lower 8 bits
// Note : This function doesn't cut CR, LF, NULL terminators
// : If receiver buffer is empty, return value is negative
// : so only sign bit have to be checked (x < 0 // x >= 0)
//******************************************************************
#ifdef USART_NO_ABI_BREAKING_PREMATURES
int16_t uart0_getData(void) {
register uint8_t tmp_rx_Tail = rx0_Tail;
uint8_t tmp;
if (tmp_rx_Tail == rx0_Head)
return -1;
tmp_rx_Tail = (tmp_rx_Tail + 1) & RX0_BUFFER_MASK;
tmp = rx0_buffer[tmp_rx_Tail];
rx0_Tail = tmp_rx_Tail;
#ifdef USART0_EXTEND_RX_BUFFER
#if __AVR_ARCH__ == 103
UCSR0A_REGISTER |= (1 << RXCIE0_BIT);
#else
UCSR0B_REGISTER |= (1 << RXCIE0_BIT);
#endif
#endif
#ifdef USART0_USE_SOFT_RTS
if (RTS0_PORT & (1 << RTS0_IONUM))
#if __AVR_ARCH__ == 103
if (!(USR0_REGISTER & (1 << RXC0_BIT)))
#else
// isr has fired so check if there is no unread data in UDR (if missed
// then next read will release RTS line)
if (!(UCSR0A_REGISTER & (1 << RXC0_BIT)))
#endif
RTS0_PORT &= ~(1 << RTS0_IONUM);
#endif
return tmp;
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
int16_t uart0_getData(void) {
register uint8_t tmp_rx_Tail = rx0_Tail;
uint8_t tmp;
if (tmp_rx_Tail == rx0_Head)
return -1;
tmp_rx_Tail = (tmp_rx_Tail + 1) & RX0_BUFFER_MASK;
asm volatile("\n\t"
"mov r26, %[index] \n\t"
#if !defined(__AVR_ATtiny2313__) && \
!defined(__AVR_ATtiny2313A__) // on ATtiny2313 upper byte in pointer
// pair is ignored
"ldi r27, 0x00 \n\t"
#endif
"subi r26, lo8(-(rx0_buffer)) \n\t"
#ifndef USART_USE_TINY_MEMORY_MODEL
"sbci r27, hi8(-(rx0_buffer)) \n\t"
#endif
"ld %[temp], X \n\t"
: // outputs
[index] "+r"(tmp_rx_Tail),
[temp] "=r"(tmp)
: // inputs
: // clobbers
#if !defined(__AVR_ATtiny2313__) && !defined(__AVR_ATtiny2313A__)
"r27",
#endif
"r26");
rx0_Tail = tmp_rx_Tail;
#ifdef USART0_EXTEND_RX_BUFFER
#if __AVR_ARCH__ == 103
UCSR0A_REGISTER |= (1 << RXCIE0_BIT);
#else
UCSR0B_REGISTER |= (1 << RXCIE0_BIT);
#endif
#endif
#ifdef USART0_USE_SOFT_RTS
if (RTS0_PORT & (1 << RTS0_IONUM))
#if __AVR_ARCH__ == 103
if (!(USR0_REGISTER & (1 << RXC0_BIT)))
#else
// isr has fired so check if there is no unread data in UDR (if missed
// then next read will release RTS line)
if (!(UCSR0A_REGISTER & (1 << RXC0_BIT)))
#endif
RTS0_PORT &= ~(1 << RTS0_IONUM);
#endif
return tmp;
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
//******************************************************************
// Function : To receive single byte in binary transmission.
// Arguments : Pointer to byte which have to be filed by incoming data.
// Return : Status value: 0 = BUFFER_EMPTY, 1 = COMPLETED.
// Note : This function doesn't cut CR, LF, NULL terminators
// : If receiver buffer is empty return status = BUFFER_EMPTY instead
// of returning NULL (as in getc).
//******************************************************************
uint8_t uart0_LoadData(uint8_t *data) {
register uint8_t tmp_rx_Tail = rx0_Tail;
if (tmp_rx_Tail == rx0_Head)
return BUFFER_EMPTY; // result = 0
tmp_rx_Tail = (tmp_rx_Tail + 1) & RX0_BUFFER_MASK;
*data = rx0_buffer[tmp_rx_Tail];
rx0_Tail = tmp_rx_Tail;
#ifdef USART0_EXTEND_RX_BUFFER
#if __AVR_ARCH__ == 103
UCSR0A_REGISTER |= (1 << RXCIE0_BIT);
#else
UCSR0B_REGISTER |= (1 << RXCIE0_BIT);
#endif
#endif
#ifdef USART0_USE_SOFT_RTS
if (RTS0_PORT & (1 << RTS0_IONUM))
#if __AVR_ARCH__ == 103
if (!(USR0_REGISTER & (1 << RXC0_BIT)))
#else
// isr has fired so check if there is no unread data in UDR (if missed
// then next read will release RTS line)
if (!(UCSR0A_REGISTER & (1 << RXC0_BIT)))
#endif
RTS0_PORT &= ~(1 << RTS0_IONUM);
#endif
return COMPLETED; // result = 1
}
//******************************************************************
// Function : To check how many bytes are waiting in the receiver buffer.
// Arguments : none
// Return : Number of bytes waiting in receiver buffer.
//******************************************************************
// uint8_t uart0_AvailableBytes(void)
// {
// return (rx0_Head - rx0_Tail) & RX0_BUFFER_MASK;
// }
//******************************************************************
// Function : Peek at the next byte in buffer.
// Arguments : none
// Return : Next byte in buffer.
//******************************************************************
uint8_t uart0_peek(void) {
return rx0_buffer[(rx0_Tail + 1) & RX0_BUFFER_MASK];
}
#endif // NO_RX0_INTERRUPT
#ifndef NO_RX1_INTERRUPT
#ifdef USART_NO_ABI_BREAKING_PREMATURES
char uart1_getc(void) {
register uint8_t tmp_rx_Tail = rx1_Tail;
char tmp;
if (tmp_rx_Tail == rx1_Head)
return 0;
tmp_rx_Tail = (tmp_rx_Tail + 1) & RX1_BUFFER_MASK;
tmp = rx1_buffer[tmp_rx_Tail];
rx1_Tail = tmp_rx_Tail;
#ifdef USART1_EXTEND_RX_BUFFER
UCSR1B_REGISTER |= (1 << RXCIE1_BIT);
#endif
#ifdef USART1_USE_SOFT_RTS
if (RTS1_PORT & (1 << RTS1_IONUM))
if (!(UCSR1A_REGISTER &
(1 << RXC1_BIT))) // isr has fired so check if there is no unread data
// in UDR (if missed then next read will release RTS
// line)
RTS1_PORT &= ~(1 << RTS1_IONUM);
#endif
#ifdef RX1_GETC_ECHO
#ifdef RX_NEWLINE_MODE_N
if (tmp == '\n')
uart1_putc('\r');
#endif
tmp = uart1_putc_(tmp);
#ifdef RX_NEWLINE_MODE_R
if (tmp == '\r')
uart1_putc('\n');
#endif
#endif // RX1_GETC_ECHO
return tmp;
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
char uart1_getc(void) {
register uint8_t tmp_rx_Tail asm("r25");
char tmp;
tmp_rx_Tail = rx1_Tail;
if (tmp_rx_Tail == rx1_Head)
return 0;
tmp_rx_Tail = (tmp_rx_Tail + 1) & RX1_BUFFER_MASK;
asm volatile("\n\t"
"mov r26, %[index] \n\t"
"ldi r27, 0x00 \n\t"
"subi r26, lo8(-(rx1_buffer)) \n\t"
"sbci r27, hi8(-(rx1_buffer)) \n\t"
"ld %[temp], X \n\t"
: // outputs
[index] "+r"(tmp_rx_Tail),
[temp] "=r"(tmp)
: // inputs
: // clobbers
"r26", "r27");
rx1_Tail = tmp_rx_Tail;
#ifdef USART1_EXTEND_RX_BUFFER
UCSR1B_REGISTER |= (1 << RXCIE1_BIT);
#endif
#ifdef USART1_USE_SOFT_RTS
if (RTS1_PORT & (1 << RTS1_IONUM))
if (!(UCSR1A_REGISTER &
(1 << RXC1_BIT))) // isr has fired so check if there is no unread data
// in UDR (if missed then next read will release RTS
// line)
RTS1_PORT &= ~(1 << RTS1_IONUM);
#endif
#ifdef RX1_GETC_ECHO
#ifdef RX_NEWLINE_MODE_N
if (tmp == '\n')
uart1_putc('\r');
#endif
tmp = uart1_putc_(tmp);
#ifdef RX_NEWLINE_MODE_R
if (tmp == '\r')
uart1_putc('\n');
#endif
#endif // RX1_GETC_ECHO
return tmp;
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart1_gets(char *buffer, uint8_t bufferlimit) {
while (--bufferlimit) {
*buffer = uart1_getc();
if (*buffer++ == 0)
break;
}
*buffer = 0;
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart1_gets(char *buffer, uint8_t bufferlimit) {
asm volatile("\n\t"
"loop_%=:"
"dec %[limit] \n\t"
"breq store_NULL_%= \n\t" // buffer limit hit, quit loop
"rcall uart1_getc \n\t" // counter and Z pointer will not be
// affected in uart_getc()
"st Z+, r24 \n\t"
"cpse r24, __zero_reg__ \n\t"
"rjmp loop_%= \n\t"
"store_NULL_%=:"
"st Z, __zero_reg__ \n\t"
: // outputs
: // inputs
"z"(buffer),
[limit] "r"(bufferlimit)
: // clobbers
"r24", "r25", "r26", "r27" // uart_getc()
);
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart1_getln(char *buffer, uint8_t bufferlimit) {
while (--bufferlimit) {
do {
*buffer = uart1_getc();
} while (*buffer == 0);
#ifdef RX_NEWLINE_MODE_N
if (*buffer == '\n')
#else
if (*buffer == '\r')
#endif
{
#ifdef RX_NEWLINE_MODE_RN
while (!(uart1_getc()))
;
#endif
break;
}
buffer++;
}
*buffer = 0;
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart1_getln(char *buffer, uint8_t bufferlimit) {
asm volatile("\n\t"
"loop_%=:"
"dec %[limit] \n\t"
"breq store_NULL_%= \n\t" // buffer limit hit, quit loop
"wait_loop_%=:"
"rcall uart1_getc \n\t" // counter and Z pointer will not be
// affected in uart_getc()
"and r24, r24 \n\t" // test for NULL
"breq wait_loop_%= \n\t"
#ifdef RX_NEWLINE_MODE_N
"cpi r24, '\n' \n\t"
#else
"cpi r24, '\r' \n\t"
#endif
#ifdef RX_NEWLINE_MODE_RN
"breq wait_loop2_%= \n\t"
#else
"breq store_NULL_%= \n\t"
#endif
"st Z+, r24 \n\t"
"rjmp loop_%= \n\t"
#ifdef RX_NEWLINE_MODE_RN
"wait_loop2_%=:"
"rcall uart1_getc \n\t"
"and r24, r24 \n\t"
"breq wait_loop2_%= \n\t"
#endif
"store_NULL_%=:"
"st Z, __zero_reg__ \n\t"
: // outputs
: // inputs
"z"(buffer),
[limit] "r"(bufferlimit)
: // clobbers
"r24", "r25", "r26", "r27" // uart_getc()
);
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart1_getlnToFirstWhiteSpace(char *buffer, uint8_t bufferlimit) {
do {
*buffer = uart1_getc();
} while (*buffer <= 32);
buffer++;
bufferlimit--;
while (--bufferlimit) {
do {
*buffer = uart1_getc();
} while (*buffer == 0);
#ifdef RX_NEWLINE_MODE_N
if (*buffer == '\n')
#else // RX_NEWLINE_MODE_R
if (*buffer == '\r')
#endif
{
#ifdef RX_NEWLINE_MODE_RN
while (!(uart1_getc()))
;
#endif
break;
} else if (*buffer <= 32)
break; // string reading is done, we will exit
buffer++;
}
*buffer = 0;
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart1_getlnToFirstWhiteSpace(char *buffer, uint8_t bufferlimit) {
asm volatile(
"\n\t"
"skip_whitespaces_loop_%=:"
"rcall uart1_getc \n\t" // counter and Z pointer will not be affected in
// uart_getc()
"cpi r24, 0x21\n\t" // if(tmp <= 32)
"brcs skip_whitespaces_loop_%= \n\t" // skip all received whitespaces
"st Z+, r24 \n\t"
"dec %[limit] \n\t"
"loop_%=:"
"dec %[limit] \n\t"
"breq store_NULL_%= \n\t" // buffer limit hit, quit loop
"wait_loop_%=:"
"rcall uart1_getc \n\t" // counter and Z pointer will not be affected in
// uart_getc()
"and r24, r24 \n\t" // test for NULL
"breq wait_loop_%= \n\t"
#ifdef RX_NEWLINE_MODE_N
"cpi r24, '\n' \n\t"
#else
"cpi r24, '\r' \n\t"
#endif
#ifdef RX_NEWLINE_MODE_RN
"breq exit_wait_loop_%= \n\t"
#else
"breq store_NULL_%= \n\t"
#endif
"cpi r24, 0x21 \n\t" // if(tmp <= 32)
"brcs store_NULL_%= \n\t" // whitespace means end of this function, quit
// loop
"st Z+, r24 \n\t"
"rjmp loop_%=\n\t"
#ifdef RX_NEWLINE_MODE_RN
"exit_wait_loop_%=:"
"rcall uart1_getc \n\t"
"and r24, r24 \n\t" // test for NULL
"breq exit_wait_loop_%= \n\t"
#endif
"store_NULL_%=:"
"st Z, __zero_reg__ \n\t"
: // outputs
: // inputs
"z"(buffer),
[limit] "r"(bufferlimit)
: // clobbers
"r24", "r25", "r26", "r27" // uart_getc()
);
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
int16_t uart1_getint(void) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[7]; // heading, 5 digit bytes, NULL
#endif
uart1_getlnToFirstWhiteSpace(u_tmp_buff, 7);
return atoi(u_tmp_buff);
}
int32_t uart1_getlong(void) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[12]; // heading, 10 digit bytes, NULL
#endif
uart1_getlnToFirstWhiteSpace(u_tmp_buff, 12);
return atol(u_tmp_buff);
}
float uart1_getfloat(void) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[32];
#endif
uart1_getlnToFirstWhiteSpace(u_tmp_buff, 32);
return atof(u_tmp_buff);
}
#ifdef USART_NO_ABI_BREAKING_PREMATURES
int16_t uart1_getData(void) {
register uint8_t tmp_rx_Tail = rx1_Tail;
uint8_t tmp;
if (tmp_rx_Tail == rx1_Head)
return -1;
tmp_rx_Tail = (tmp_rx_Tail + 1) & RX1_BUFFER_MASK;
tmp = rx1_buffer[tmp_rx_Tail];
rx1_Tail = tmp_rx_Tail;
#ifdef USART1_EXTEND_RX_BUFFER
UCSR1B_REGISTER |= (1 << RXCIE1_BIT);
#endif
#ifdef USART1_USE_SOFT_RTS
if (RTS1_PORT & (1 << RTS1_IONUM))
if (!(UCSR1A_REGISTER & (1 << RXC1_BIT)))
RTS1_PORT &= ~(1 << RTS1_IONUM);
#endif
return tmp;
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
int16_t uart1_getData(void) {
register uint8_t tmp_rx_Tail = rx1_Tail;
uint8_t tmp;
if (tmp_rx_Tail == rx1_Head)
return -1;
tmp_rx_Tail = (tmp_rx_Tail + 1) & RX1_BUFFER_MASK;
asm volatile("\n\t"
"mov r26, %[index] \n\t"
"ldi r27, 0x00 \n\t"
"subi r26, lo8(-(rx1_buffer)) \n\t"
"sbci r27, hi8(-(rx1_buffer)) \n\t"
"ld %[temp], X \n\t"
: // outputs
[index] "+r"(tmp_rx_Tail),
[temp] "=r"(tmp)
: // inputs
: // clobbers
"r26", "r27");
rx1_Tail = tmp_rx_Tail;
#ifdef USART1_EXTEND_RX_BUFFER
UCSR1B_REGISTER |= (1 << RXCIE1_BIT);
#endif
#ifdef USART1_USE_SOFT_RTS
if (RTS1_PORT & (1 << RTS1_IONUM))
if (!(UCSR1A_REGISTER & (1 << RXC1_BIT)))
RTS1_PORT &= ~(1 << RTS1_IONUM);
#endif
return tmp;
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
uint8_t uart1_LoadData(uint8_t *data) {
register uint8_t tmp_rx_Tail = rx1_Tail;
if (tmp_rx_Tail == rx1_Head)
return BUFFER_EMPTY; // result = 0
tmp_rx_Tail = (tmp_rx_Tail + 1) & RX1_BUFFER_MASK;
*data = rx1_buffer[tmp_rx_Tail];
rx1_Tail = tmp_rx_Tail;
#ifdef USART1_EXTEND_RX_BUFFER
UCSR1B_REGISTER |= (1 << RXCIE1_BIT);
#endif
#ifdef USART1_USE_SOFT_RTS
if (RTS1_PORT & (1 << RTS1_IONUM))
if (!(UCSR1A_REGISTER & (1 << RXC1_BIT)))
RTS1_PORT &= ~(1 << RTS1_IONUM);
#endif
return COMPLETED; // result = 1
}
// uint8_t uart1_AvailableBytes(void)
//{
// return (rx1_Head - rx1_Tail) & RX1_BUFFER_MASK;
// }
uint8_t uart1_peek(void) {
return rx1_buffer[(rx1_Tail + 1) & RX1_BUFFER_MASK];
}
#endif // NO_RX1_INTERRUPT
#ifndef NO_RX2_INTERRUPT
#ifdef USART_NO_ABI_BREAKING_PREMATURES
char uart2_getc(void) {
register uint8_t tmp_rx_Tail = rx2_Tail;
char tmp;
if (tmp_rx_Tail == rx2_Head)
return 0;
tmp_rx_Tail = (tmp_rx_Tail + 1) & RX2_BUFFER_MASK;
tmp = rx2_buffer[tmp_rx_Tail];
rx2_Tail = tmp_rx_Tail;
#ifdef USART2_EXTEND_RX_BUFFER
UCSR2B_REGISTER |= (1 << RXCIE2_BIT);
#endif
#ifdef USART2_USE_SOFT_RTS
if (RTS2_PORT & (1 << RTS2_IONUM))
if (!(UCSR2A_REGISTER &
(1 << RXC2_BIT))) // isr has fired so check if there is no unread data
// in UDR (if missed then next read will release RTS
// line)
RTS2_PORT &= ~(1 << RTS2_IONUM);
#endif
#ifdef RX2_GETC_ECHO
#ifdef RX_NEWLINE_MODE_N
if (tmp == '\n')
uart2_putc('\r');
#endif
tmp = uart2_putc_(tmp);
#ifdef RX_NEWLINE_MODE_R
if (tmp == '\r')
uart2_putc('\n');
#endif
#endif // RX2_GETC_ECHO
return tmp;
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
char uart2_getc(void) {
register uint8_t tmp_rx_Tail asm("r25");
char tmp;
tmp_rx_Tail = rx2_Tail;
if (tmp_rx_Tail == rx2_Head)
return 0;
tmp_rx_Tail = (tmp_rx_Tail + 1) & RX2_BUFFER_MASK;
asm volatile("\n\t"
"mov r26, %[index] \n\t"
"ldi r27, 0x00 \n\t"
"subi r26, lo8(-(rx2_buffer)) \n\t"
"sbci r27, hi8(-(rx2_buffer)) \n\t"
"ld %[temp], X \n\t"
: // outputs
[index] "+r"(tmp_rx_Tail),
[temp] "=r"(tmp)
: // inputs
: // clobbers
"r26", "r27");
rx2_Tail = tmp_rx_Tail;
#ifdef USART2_EXTEND_RX_BUFFER
UCSR2B_REGISTER |= (1 << RXCIE2_BIT);
#endif
#ifdef USART2_USE_SOFT_RTS
if (RTS2_PORT & (1 << RTS2_IONUM))
if (!(UCSR2A_REGISTER &
(1 << RXC2_BIT))) // isr has fired so check if there is no unread data
// in UDR (if missed then next read will release RTS
// line)
RTS2_PORT &= ~(1 << RTS2_IONUM);
#endif
#ifdef RX2_GETC_ECHO
#ifdef RX_NEWLINE_MODE_N
if (tmp == '\n')
uart2_putc('\r');
#endif
tmp = uart2_putc_(tmp);
#ifdef RX_NEWLINE_MODE_R
if (tmp == '\r')
uart2_putc('\n');
#endif
#endif // RX2_GETC_ECHO
return tmp;
}
#endif
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart2_gets(char *buffer, uint8_t bufferlimit) {
while (--bufferlimit) {
*buffer = uart2_getc();
if (*buffer++ == 0)
break;
}
*buffer = 0;
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart2_gets(char *buffer, uint8_t bufferlimit) {
asm volatile("\n\t"
"loop_%=:"
"dec %[limit] \n\t"
"breq store_NULL_%= \n\t" // buffer limit hit, quit loop
"rcall uart2_getc \n\t" // counter and Z pointer will not be
// affected in uart_getc()
"st Z+, r24 \n\t"
"cpse r24, __zero_reg__ \n\t"
"rjmp loop_%= \n\t"
"store_NULL_%=:"
"st Z, __zero_reg__ \n\t"
: // outputs
: // inputs
"z"(buffer),
[limit] "r"(bufferlimit)
: // clobbers
"r24", "r25", "r26", "r27" // uart_getc()
);
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart2_getln(char *buffer, uint8_t bufferlimit) {
while (--bufferlimit) {
do {
*buffer = uart2_getc();
} while (*buffer == 0);
#ifdef RX_NEWLINE_MODE_N
if (*buffer == '\n')
#else
if (*buffer == '\r')
#endif
{
#ifdef RX_NEWLINE_MODE_RN
while (!(uart2_getc()))
;
#endif
break;
}
buffer++;
}
*buffer = 0;
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart2_getln(char *buffer, uint8_t bufferlimit) {
asm volatile("\n\t"
"loop_%=:"
"dec %[limit] \n\t"
"breq store_NULL_%= \n\t" // buffer limit hit, quit loop
"wait_loop_%=:"
"rcall uart2_getc \n\t" // counter and Z pointer will not be
// affected in uart_getc()
"and r24, r24 \n\t" // test for NULL
"breq wait_loop_%= \n\t"
#ifdef RX_NEWLINE_MODE_N
"cpi r24, '\n' \n\t"
#else
"cpi r24, '\r' \n\t"
#endif
#ifdef RX_NEWLINE_MODE_RN
"breq wait_loop2_%= \n\t"
#else
"breq store_NULL_%= \n\t"
#endif
"st Z+, r24 \n\t"
"rjmp loop_%= \n\t"
#ifdef RX_NEWLINE_MODE_RN
"wait_loop2_%=:"
"rcall uart2_getc \n\t"
"and r24, r24 \n\t"
"breq wait_loop2_%= \n\t"
#endif
"store_NULL_%=:"
"st Z, __zero_reg__ \n\t"
: // outputs
: // inputs
"z"(buffer),
[limit] "r"(bufferlimit)
: // clobbers
"r24", "r25", "r26", "r27" // uart_getc()
);
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart2_getlnToFirstWhiteSpace(char *buffer, uint8_t bufferlimit) {
do {
*buffer = uart2_getc();
} while (*buffer <= 32);
buffer++;
bufferlimit--;
while (--bufferlimit) {
do {
*buffer = uart2_getc();
} while (*buffer == 0);
#ifdef RX_NEWLINE_MODE_N
if (*buffer == '\n')
#else // RX_NEWLINE_MODE_R
if (*buffer == '\r')
#endif
{
#ifdef RX_NEWLINE_MODE_RN
while (!(uart2_getc()))
;
#endif
break;
} else if (*buffer <= 32)
break; // string reading is done, we will exit
buffer++;
}
*buffer = 0;
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart2_getlnToFirstWhiteSpace(char *buffer, uint8_t bufferlimit) {
asm volatile(
"\n\t"
"skip_whitespaces_loop_%=:"
"rcall uart2_getc \n\t" // counter and Z pointer will not be affected in
// uart_getc()
"cpi r24, 0x21\n\t" // if(tmp <= 32)
"brcs skip_whitespaces_loop_%= \n\t" // skip all received whitespaces
"st Z+, r24 \n\t"
"dec %[limit] \n\t"
"loop_%=:"
"dec %[limit] \n\t"
"breq store_NULL_%= \n\t" // buffer limit hit, quit loop
"wait_loop_%=:"
"rcall uart2_getc \n\t" // counter and Z pointer will not be affected in
// uart_getc()
"and r24, r24 \n\t" // test for NULL
"breq wait_loop_%= \n\t"
#ifdef RX_NEWLINE_MODE_N
"cpi r24, '\n' \n\t"
#else
"cpi r24, '\r' \n\t"
#endif
#ifdef RX_NEWLINE_MODE_RN
"breq exit_wait_loop_%= \n\t"
#else
"breq store_NULL_%= \n\t"
#endif
"cpi r24, 0x21 \n\t" // if(tmp <= 32)
"brcs store_NULL_%= \n\t" // whitespace means end of this function, quit
// loop
"st Z+, r24 \n\t"
"rjmp loop_%=\n\t"
#ifdef RX_NEWLINE_MODE_RN
"exit_wait_loop_%=:"
"rcall uart2_getc \n\t"
"and r24, r24 \n\t" // test for NULL
"breq exit_wait_loop_%= \n\t"
#endif
"store_NULL_%=:"
"st Z, __zero_reg__ \n\t"
: // outputs
: // inputs
"z"(buffer),
[limit] "r"(bufferlimit)
: // clobbers
"r24", "r25", "r26", "r27" // uart_getc()
);
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
int16_t uart2_getint(void) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[7]; // heading, 5 digit bytes, NULL
#endif
uart2_getlnToFirstWhiteSpace(u_tmp_buff, 7);
return atoi(u_tmp_buff);
}
int32_t uart2_getlong(void) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[12]; // heading, 10 digit bytes, NULL
#endif
uart2_getlnToFirstWhiteSpace(u_tmp_buff, 12);
return atol(u_tmp_buff);
}
float uart2_getfloat(void) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[32];
#endif
uart2_getlnToFirstWhiteSpace(u_tmp_buff, 32);
return atof(u_tmp_buff);
}
#ifdef USART_NO_ABI_BREAKING_PREMATURES
int16_t uart2_getData(void) {
register uint8_t tmp_rx_Tail = rx2_Tail;
uint8_t tmp;
if (tmp_rx_Tail == rx2_Head)
return -1;
tmp_rx_Tail = (tmp_rx_Tail + 1) & RX2_BUFFER_MASK;
tmp = rx2_buffer[tmp_rx_Tail];
rx2_Tail = tmp_rx_Tail;
#ifdef USART2_EXTEND_RX_BUFFER
UCSR2B_REGISTER |= (1 << RXCIE2_BIT);
#endif
#ifdef USART2_USE_SOFT_RTS
if (RTS2_PORT & (1 << RTS2_IONUM))
if (!(UCSR2A_REGISTER & (1 << RXC2_BIT)))
RTS2_PORT &= ~(1 << RTS2_IONUM);
#endif
return tmp;
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
int16_t uart2_getData(void) {
register uint8_t tmp_rx_Tail = rx2_Tail;
uint8_t tmp;
if (tmp_rx_Tail == rx2_Head)
return -1;
tmp_rx_Tail = (tmp_rx_Tail + 1) & RX2_BUFFER_MASK;
asm volatile("\n\t"
"mov r26, %[index] \n\t"
"ldi r27, 0x00 \n\t"
"subi r26, lo8(-(rx2_buffer)) \n\t"
"sbci r27, hi8(-(rx2_buffer)) \n\t"
"ld %[temp], X \n\t"
: // outputs
[index] "+r"(tmp_rx_Tail),
[temp] "=r"(tmp)
: // inputs
: // clobbers
"r26", "r27");
rx2_Tail = tmp_rx_Tail;
#ifdef USART2_EXTEND_RX_BUFFER
UCSR2B_REGISTER |= (1 << RXCIE2_BIT);
#endif
#ifdef USART2_USE_SOFT_RTS
if (RTS2_PORT & (1 << RTS2_IONUM))
if (!(UCSR2A_REGISTER & (1 << RXC2_BIT)))
RTS2_PORT &= ~(1 << RTS2_IONUM);
#endif
return tmp;
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
uint8_t uart2_LoadData(uint8_t *data) {
register uint8_t tmp_rx_Tail = rx2_Tail;
if (tmp_rx_Tail == rx2_Head)
return BUFFER_EMPTY; // result = 0
tmp_rx_Tail = (tmp_rx_Tail + 1) & RX2_BUFFER_MASK;
*data = rx2_buffer[tmp_rx_Tail];
rx2_Tail = tmp_rx_Tail;
#ifdef USART2_EXTEND_RX_BUFFER
UCSR2B_REGISTER |= (1 << RXCIE2_BIT);
#endif
#ifdef USART2_USE_SOFT_RTS
if (RTS2_PORT & (1 << RTS2_IONUM))
if (!(UCSR2A_REGISTER & (1 << RXC2_BIT)))
RTS2_PORT &= ~(1 << RTS2_IONUM);
#endif
return COMPLETED; // result = 1
}
// uint8_t uart2_AvailableBytes(void)
//{
// return (rx2_Head - rx2_Tail) & RX2_BUFFER_MASK;
// }
uint8_t uart2_peek(void) {
return rx2_buffer[(rx2_Tail + 1) & RX2_BUFFER_MASK];
}
#endif // NO_RX2_INTERRUPT
#ifndef NO_RX3_INTERRUPT
#ifdef USART_NO_ABI_BREAKING_PREMATURES
char uart3_getc(void) {
register uint8_t tmp_rx_Tail = rx3_Tail;
char tmp;
if (tmp_rx_Tail == rx3_Head)
return 0;
tmp_rx_Tail = (tmp_rx_Tail + 1) & RX3_BUFFER_MASK;
tmp = rx3_buffer[tmp_rx_Tail];
rx3_Tail = tmp_rx_Tail;
#ifdef USART3_EXTEND_RX_BUFFER
UCSR3B_REGISTER |= (1 << RXCIE3_BIT);
#endif
#ifdef USART3_USE_SOFT_RTS
if (RTS3_PORT & (1 << RTS3_IONUM))
if (!(UCSR3A_REGISTER &
(1 << RXC3_BIT))) // isr has fired so check if there is no unread data
// in UDR (if missed then next read will release RTS
// line)
RTS3_PORT &= ~(1 << RTS3_IONUM);
#endif
#ifdef RX3_GETC_ECHO
#ifdef RX_NEWLINE_MODE_N
if (tmp == '\n')
uart3_putc('\r');
#endif
tmp = uart3_putc_(tmp);
#ifdef RX_NEWLINE_MODE_R
if (tmp == '\r')
uart3_putc('\n');
#endif
#endif // RX3_GETC_ECHO
return tmp;
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
char uart3_getc(void) {
register uint8_t tmp_rx_Tail asm("r25");
char tmp;
tmp_rx_Tail = rx3_Tail;
if (tmp_rx_Tail == rx3_Head)
return 0;
tmp_rx_Tail = (tmp_rx_Tail + 1) & RX3_BUFFER_MASK;
asm volatile("\n\t"
"mov r26, %[index] \n\t"
"ldi r27, 0x00 \n\t"
"subi r26, lo8(-(rx3_buffer)) \n\t"
"sbci r27, hi8(-(rx3_buffer)) \n\t"
"ld %[temp], X \n\t"
: // outputs
[index] "+r"(tmp_rx_Tail),
[temp] "=r"(tmp)
: // inputs
: // clobbers
"r26", "r27");
rx3_Tail = tmp_rx_Tail;
#ifdef USART3_EXTEND_RX_BUFFER
UCSR3B_REGISTER |= (1 << RXCIE3_BIT);
#endif
#ifdef USART3_USE_SOFT_RTS
if (RTS3_PORT & (1 << RTS3_IONUM))
if (!(UCSR3A_REGISTER &
(1 << RXC3_BIT))) // isr has fired so check if there is no unread data
// in UDR (if missed then next read will release RTS
// line)
RTS3_PORT &= ~(1 << RTS3_IONUM);
#endif
#ifdef RX3_GETC_ECHO
#ifdef RX_NEWLINE_MODE_N
if (tmp == '\n')
uart3_putc('\r');
#endif
tmp = uart3_putc_(tmp);
#ifdef RX_NEWLINE_MODE_R
if (tmp == '\r')
uart3_putc('\n');
#endif
#endif // RX3_GETC_ECHO
return tmp;
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart3_gets(char *buffer, uint8_t bufferlimit) {
while (--bufferlimit) {
*buffer = uart3_getc();
if (*buffer++ == 0)
break;
}
*buffer = 0;
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart3_gets(char *buffer, uint8_t bufferlimit) {
asm volatile("\n\t"
"loop_%=:"
"dec %[limit] \n\t"
"breq store_NULL_%= \n\t" // buffer limit hit, quit loop
"rcall uart3_getc \n\t" // counter and Z pointer will not be
// affected in uart_getc()
"st Z+, r24 \n\t"
"cpse r24, __zero_reg__ \n\t"
"rjmp loop_%= \n\t"
"store_NULL_%=:"
"st Z, __zero_reg__ \n\t"
: // outputs
: // inputs
"z"(buffer),
[limit] "r"(bufferlimit)
: // clobbers
"r24", "r25", "r26", "r27" // uart_getc()
);
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart3_getln(char *buffer, uint8_t bufferlimit) {
while (--bufferlimit) {
do {
*buffer = uart3_getc();
} while (*buffer == 0);
#ifdef RX_NEWLINE_MODE_N
if (*buffer == '\n')
#else
if (*buffer == '\r')
#endif
{
#ifdef RX_NEWLINE_MODE_RN
while (!(uart3_getc()))
;
#endif
break;
}
buffer++;
}
*buffer = 0;
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart3_getln(char *buffer, uint8_t bufferlimit) {
asm volatile("\n\t"
"loop_%=:"
"dec %[limit] \n\t"
"breq store_NULL_%= \n\t" // buffer limit hit, quit loop
"wait_loop_%=:"
"rcall uart3_getc \n\t" // counter and Z pointer will not be
// affected in uart_getc()
"and r24, r24 \n\t" // test for NULL
"breq wait_loop_%= \n\t"
#ifdef RX_NEWLINE_MODE_N
"cpi r24, '\n' \n\t"
#else
"cpi r24, '\r' \n\t"
#endif
#ifdef RX_NEWLINE_MODE_RN
"breq wait_loop2_%= \n\t"
#else
"breq store_NULL_%= \n\t"
#endif
"st Z+, r24 \n\t"
"rjmp loop_%= \n\t"
#ifdef RX_NEWLINE_MODE_RN
"wait_loop2_%=:"
"rcall uart3_getc \n\t"
"and r24, r24 \n\t"
"breq wait_loop2_%= \n\t"
#endif
"store_NULL_%=:"
"st Z, __zero_reg__ \n\t"
: // outputs
: // inputs
"z"(buffer),
[limit] "r"(bufferlimit)
: // clobbers
"r24", "r25", "r26", "r27" // uart_getc()
);
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
#ifdef USART_NO_ABI_BREAKING_PREMATURES
void uart3_getlnToFirstWhiteSpace(char *buffer, uint8_t bufferlimit) {
do {
*buffer = uart3_getc();
} while (*buffer <= 32);
buffer++;
bufferlimit--;
while (--bufferlimit) {
do {
*buffer = uart3_getc();
} while (*buffer == 0);
#ifdef RX_NEWLINE_MODE_N
if (*buffer == '\n')
#else // RX_NEWLINE_MODE_R
if (*buffer == '\r')
#endif
{
#ifdef RX_NEWLINE_MODE_RN
while (!(uart3_getc()))
;
#endif
break;
} else if (*buffer <= 32)
break; // string reading is done, we will exit
buffer++;
}
*buffer = 0;
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
void uart3_getlnToFirstWhiteSpace(char *buffer, uint8_t bufferlimit) {
asm volatile(
"\n\t"
"skip_whitespaces_loop_%=:"
"rcall uart3_getc \n\t" // counter and Z pointer will not be affected in
// uart_getc()
"cpi r24, 0x21\n\t" // if(tmp <= 32)
"brcs skip_whitespaces_loop_%= \n\t" // skip all received whitespaces
"st Z+, r24 \n\t"
"dec %[limit] \n\t"
"loop_%=:"
"dec %[limit] \n\t"
"breq store_NULL_%= \n\t" // buffer limit hit, quit loop
"wait_loop_%=:"
"rcall uart3_getc \n\t" // counter and Z pointer will not be affected in
// uart_getc()
"and r24, r24 \n\t" // test for NULL
"breq wait_loop_%= \n\t"
#ifdef RX_NEWLINE_MODE_N
"cpi r24, '\n' \n\t"
#else
"cpi r24, '\r' \n\t"
#endif
#ifdef RX_NEWLINE_MODE_RN
"breq exit_wait_loop_%= \n\t"
#else
"breq store_NULL_%= \n\t"
#endif
"cpi r24, 0x21 \n\t" // if(tmp <= 32)
"brcs store_NULL_%= \n\t" // whitespace means end of this function, quit
// loop
"st Z+, r24 \n\t"
"rjmp loop_%=\n\t"
#ifdef RX_NEWLINE_MODE_RN
"exit_wait_loop_%=:"
"rcall uart3_getc \n\t"
"and r24, r24 \n\t" // test for NULL
"breq exit_wait_loop_%= \n\t"
#endif
"store_NULL_%=:"
"st Z, __zero_reg__ \n\t"
: // outputs
: // inputs
"z"(buffer),
[limit] "r"(bufferlimit)
: // clobbers
"r24", "r25", "r26", "r27" // uart_getc()
);
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
int16_t uart3_getint(void) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[7]; // heading, 5 digit bytes, NULL
#endif
uart3_getlnToFirstWhiteSpace(u_tmp_buff, 7);
return atoi(u_tmp_buff);
}
int32_t uart3_getlong(void) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[12]; // heading, 10 digit bytes, NULL
#endif
uart3_getlnToFirstWhiteSpace(u_tmp_buff, 12);
return atol(u_tmp_buff);
}
float uart3_getfloat(void) {
#ifndef USART_NO_LOCAL_BUFFERS
char u_tmp_buff[32];
#endif
uart3_getlnToFirstWhiteSpace(u_tmp_buff, 32);
return atof(u_tmp_buff);
}
#ifdef USART_NO_ABI_BREAKING_PREMATURES
int16_t uart3_getData(void) {
register uint8_t tmp_rx_Tail = rx3_Tail;
uint8_t tmp;
if (tmp_rx_Tail == rx3_Head)
return -1;
tmp_rx_Tail = (tmp_rx_Tail + 1) & RX3_BUFFER_MASK;
tmp = rx3_buffer[tmp_rx_Tail];
rx3_Tail = tmp_rx_Tail;
#ifdef USART3_EXTEND_RX_BUFFER
UCSR3B_REGISTER |= (1 << RXCIE3_BIT);
#endif
#ifdef USART3_USE_SOFT_RTS
if (RTS3_PORT & (1 << RTS3_IONUM))
if (!(UCSR3A_REGISTER & (1 << RXC3_BIT)))
RTS3_PORT &= ~(1 << RTS3_IONUM);
#endif
return tmp;
}
#else // !USART_NO_ABI_BREAKING_PREMATURES
int16_t uart3_getData(void) {
register uint8_t tmp_rx_Tail = rx3_Tail;
uint8_t tmp;
if (tmp_rx_Tail == rx3_Head)
return -1;
tmp_rx_Tail = (tmp_rx_Tail + 1) & RX3_BUFFER_MASK;
asm volatile("\n\t"
"mov r26, %[index] \n\t"
"ldi r27, 0x00 \n\t"
"subi r26, lo8(-(rx3_buffer)) \n\t"
"sbci r27, hi8(-(rx3_buffer)) \n\t"
"ld %[temp], X \n\t"
: // outputs
[index] "+r"(tmp_rx_Tail),
[temp] "=r"(tmp)
: // inputs
: // clobbers
"r26", "r27");
rx3_Tail = tmp_rx_Tail;
#ifdef USART3_EXTEND_RX_BUFFER
UCSR3B_REGISTER |= (1 << RXCIE3_BIT);
#endif
#ifdef USART3_USE_SOFT_RTS
if (RTS3_PORT & (1 << RTS3_IONUM))
if (!(UCSR3A_REGISTER & (1 << RXC3_BIT)))
RTS3_PORT &= ~(1 << RTS3_IONUM);
#endif
return tmp;
}
#endif // USART_NO_ABI_BREAKING_PREMATURES
uint8_t uart3_LoadData(uint8_t *data) {
register uint8_t tmp_rx_Tail = rx3_Tail;
if (tmp_rx_Tail == rx3_Head)
return BUFFER_EMPTY; // result = 0
tmp_rx_Tail = (tmp_rx_Tail + 1) & RX3_BUFFER_MASK;
*data = rx3_buffer[tmp_rx_Tail];
rx3_Tail = tmp_rx_Tail;
#ifdef USART3_EXTEND_RX_BUFFER
UCSR3B_REGISTER |= (1 << RXCIE3_BIT);
#endif
#ifdef USART3_USE_SOFT_RTS
if (RTS3_PORT & (1 << RTS3_IONUM))
if (!(UCSR3A_REGISTER & (1 << RXC3_BIT)))
RTS3_PORT &= ~(1 << RTS3_IONUM);
#endif
return COMPLETED; // result = 1
}
// uint8_t uart3_AvailableBytes(void)
//{
// return (rx3_Head - rx3_Tail) & RX3_BUFFER_MASK;
// }
uint8_t uart3_peek(void) {
return rx3_buffer[(rx3_Tail + 1) & RX3_BUFFER_MASK];
}
#endif // NO_RX3_INTERRUPT
#endif // NO_USART_RX
/************************************************************************************
* stdio.h stuff *
************************************************************************************/
#if defined(USE_USART1) || defined(USE_USART2) || defined(USE_USART3)
#ifndef NO_USART_TX
int uart_putchar(char data, FILE *stream) {
switch ((uint16_t)stream->udata) {
default:
#ifndef NO_TX0_INTERRUPT
case 0:
if (data == '\n')
uart0_putc('\r');
uart0_putc(data);
break;
#endif
#ifndef NO_TX1_INTERRUPT
case 1:
if (data == '\n')
uart1_putc('\r');
uart1_putc(data);
break;
#endif
#ifndef NO_TX2_INTERRUPT
case 2:
if (data == '\n')
uart2_putc('\r');
uart2_putc(data);
break;
#endif
#ifndef NO_TX3_INTERRUPT
case 3:
if (data == '\n')
uart3_putc('\r');
uart3_putc(data);
break;
#endif
}
return 0;
}
#endif // NO_USART_TX
#ifndef NO_USART_RX
int uart_getchar(FILE *stream) {
int16_t tmp;
switch ((uint16_t)stream->udata) {
default:
#ifndef NO_RX0_INTERRUPT
case 0:
while ((tmp = uart0_getData()) < 0)
;
#ifdef RX_STDIO_GETCHAR_ECHO
tmp = uart0_putc_((uint8_t)tmp);
#endif
break;
#endif
#ifndef NO_RX1_INTERRUPT
case 1:
while ((tmp = uart1_getData()) < 0)
;
#ifdef RX_STDIO_GETCHAR_ECHO
tmp = uart1_putc_((uint8_t)tmp);
#endif
break;
#endif
#ifndef NO_RX2_INTERRUPT
case 2:
while ((tmp = uart2_getData()) < 0)
;
#ifdef RX_STDIO_GETCHAR_ECHO
tmp = uart2_putc_((uint8_t)tmp);
#endif
break;
#endif
#ifndef NO_RX3_INTERRUPT
case 3:
while ((tmp = uart3_getData()) < 0)
;
#ifdef RX_STDIO_GETCHAR_ECHO
tmp = uart3_putc_((uint8_t)tmp);
#endif
break;
#endif
}
return (uint8_t)tmp;
}
#endif // NO_USART_RX
#ifdef USE_USART0
#if defined(NO_RX0_INTERRUPT)
FILE uart0_out =
FDEV_SETUP_STREAM_U(uart_putchar, NULL, _FDEV_SETUP_WRITE, (void *)0);
#elif defined(NO_TX0_INTERRUPT)
FILE uart0_in =
FDEV_SETUP_STREAM_U(NULL, uart_getchar, _FDEV_SETUP_READ, (void *)0);
#else
FILE uart0_io =
FDEV_SETUP_STREAM_U(uart_putchar, uart_getchar, _FDEV_SETUP_RW, (void *)0);
FILE uart0_in =
FDEV_SETUP_STREAM_U(NULL, uart_getchar, _FDEV_SETUP_READ, (void *)0);
FILE uart0_out =
FDEV_SETUP_STREAM_U(uart_putchar, NULL, _FDEV_SETUP_WRITE, (void *)0);
#endif
#endif // USE_USART0
#ifdef USE_USART1
#if defined(NO_RX1_INTERRUPT)
FILE uart1_out =
FDEV_SETUP_STREAM_U(uart_putchar, NULL, _FDEV_SETUP_WRITE, (void *)1);
#elif defined(NO_TX1_INTERRUPT)
FILE uart1_in =
FDEV_SETUP_STREAM_U(NULL, uart_getchar, _FDEV_SETUP_READ, (void *)1);
#else
FILE uart1_io =
FDEV_SETUP_STREAM_U(uart_putchar, uart_getchar, _FDEV_SETUP_RW, (void *)1);
FILE uart1_in =
FDEV_SETUP_STREAM_U(NULL, uart_getchar, _FDEV_SETUP_READ, (void *)1);
FILE uart1_out =
FDEV_SETUP_STREAM_U(uart_putchar, NULL, _FDEV_SETUP_WRITE, (void *)1);
#endif
#endif // USE_USART1
#ifdef USE_USART2
#if defined(NO_RX2_INTERRUPT)
FILE uart2_out =
FDEV_SETUP_STREAM_U(uart_putchar, NULL, _FDEV_SETUP_WRITE, (void *)2);
#elif defined(NO_TX2_INTERRUPT)
FILE uart2_in =
FDEV_SETUP_STREAM_U(NULL, uart_getchar, _FDEV_SETUP_READ, (void *)2);
#else
FILE uart2_io =
FDEV_SETUP_STREAM_U(uart_putchar, uart_getchar, _FDEV_SETUP_RW, (void *)2);
FILE uart2_in =
FDEV_SETUP_STREAM_U(NULL, uart_getchar, _FDEV_SETUP_READ, (void *)2);
FILE uart2_out =
FDEV_SETUP_STREAM_U(uart_putchar, NULL, _FDEV_SETUP_WRITE, (void *)2);
#endif
#endif // USE_USART2
#ifdef USE_USART3
#if defined(NO_RX3_INTERRUPT)
FILE uart3_out =
FDEV_SETUP_STREAM_U(uart_putchar, NULL, _FDEV_SETUP_WRITE, (void *)3);
#elif defined(NO_TX3_INTERRUPT)
FILE uart3_in =
FDEV_SETUP_STREAM_U(NULL, uart_getchar, _FDEV_SETUP_READ, (void *)3);
#else
FILE uart3_io =
FDEV_SETUP_STREAM_U(uart_putchar, uart_getchar, _FDEV_SETUP_RW, (void *)3);
FILE uart3_in =
FDEV_SETUP_STREAM_U(NULL, uart_getchar, _FDEV_SETUP_READ, (void *)3);
FILE uart3_out =
FDEV_SETUP_STREAM_U(uart_putchar, NULL, _FDEV_SETUP_WRITE, (void *)3);
#endif
#endif // USE_USART3
#else // single USART mcu
#ifndef NO_TX0_INTERRUPT
int uart_putchar(char data, FILE *stream) {
if (data == '\n')
uart0_putc('\r');
uart_putc(data);
return 0;
}
#endif // NO_TX0_INTERRUPT
#ifndef NO_RX0_INTERRUPT
int uart_getchar(FILE *stream) {
int16_t tmp;
while ((tmp = uart0_getData()) < 0)
;
#ifdef RX_STDIO_GETCHAR_ECHO
tmp = uart0_putc_((uint8_t)tmp);
#endif
return (uint8_t)tmp;
}
#endif // NO_RX0_INTERRUPT
#if defined(NO_RX0_INTERRUPT)
FILE uart0_out = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
#elif defined(NO_TX0_INTERRUPT)
FILE uart0_in = FDEV_SETUP_STREAM(NULL, uart_getchar, _FDEV_SETUP_READ);
#else
FILE uart0_io = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
FILE uart0_in = FDEV_SETUP_STREAM(NULL, uart_getchar, _FDEV_SETUP_READ);
FILE uart0_out = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
#endif
#endif // single/multi USART
//******************************************************************
// ISR prototypes
//******************************************************************
/*
ISR(TXn_INTERRUPT) // do it in a little weird way
{
register uint8_t tmp_tx_Tail = (txn_Tail + 1) & TXn_BUFFER_MASK;
if(tmp_tx_Tail == txn_Head)
UCSRnB_REGISTER &= ~(1<<UDRIEn_BIT); // may be racing
with putc insertions
txn_Tail = tmp_tx_Tail; // it would create race condition if not
used in isr UDRn_REGISTER = txn_buffer[tmp_tx_Tail]; // transmit character
from the buffer
}
ISR(TXn_INTERRUPT) // non racing one // not used anymore
{
register uint8_t tmp_tx_Tail = txn_Tail;
if(tmp_tx_Tail != txn_Head)
{
tmp_tx_Tail = (tmp_tx_Tail + 1) & TXn_BUFFER_MASK;
txn_Tail = tmp_tx_Tail; // it would create race
condition if not used in isr UDRn_REGISTER = txn_buffer[tmp_tx_Tail]; //
transmit character from the buffer
}
else
UCSRnB_REGISTER &= ~(1<<UDRIEn_BIT);
}
ISR(RXn_INTERRUPT)
{
register uint8_t tmp_rx_Head = (rxn_Head + 1) & RXn_BUFFER_MASK;
register uint8_t tmp = UDRn_REGISTER;
#if defined(USART0_MPCM_MODE)&&!defined(MPCM0_MASTER_ONLY)
if(UCSRnA & (1<<MPCMn))
{
if(tmp == MPCMn_ADDRESS || tmp == MPCMn_GCALL_ADDRESS)
UCSRnA &= ~(1<<MPCMn);
else
return;
}
#endif
if(rxn_Tail != tmp_rx_Head)
{
rxn_Head = tmp_rx_Head; // it would create race
condition if not used in isr rxn_buffer[tmp_rx_Head] = tmp;
}
}
*/
#ifndef NO_TX0_INTERRUPT
ISR(UDRE0_INTERRUPT, ISR_NAKED) {
asm volatile(
"\n\t"
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_SREG_SAVE
"push r16 \n\t"
"in r16, __SREG__ \n\t"
#else
"in %[sreg_save], __SREG__ \n\t"
#endif
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_Z_SAVE
"push r30 \n\t"
"push r31 \n\t"
#else
#ifdef __AVR_HAVE_MOVW__
"movw %[z_save], r30 \n\t"
#else // in this case only 4 cycles are prematured out
"mov %A[z_save], r30 \n\t"
"mov %B[z_save], r31 \n\t"
#endif
#endif
#ifdef USART_UNSAFE_TX_INTERRUPT
#ifdef USART0_IN_IO_ADDRESS_SPACE
"cbi %M[control_reg_IO], %M[udrie_bit] \n\t"
#elif defined(USART0_IN_UPPER_IO_ADDRESS_SPACE)
"in r31, %M[control_reg_IO] \n\t"
"andi r31, ~(1<<%M[udrie_bit]) \n\t"
"out %M[control_reg_IO], r31\n\t"
#else
"lds r31, %M[control_reg] \n\t"
"andi r31, ~(1<<%M[udrie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
#endif
"sei \n\t"
#endif
TX0_EVERYCAL_EVENT
"lds r30, (tx0_Tail) \n\t"
"lds r31, (tx0_Head) \n\t"
#ifdef USART_UNSAFE_TX_INTERRUPT
"cp r30, r31 \n\t"
"breq USART0_TX_EXIT \n\t"
#endif
"inc r30 \n\t"
#if (TX0_BUFFER_MASK != 0xff)
"andi r30, %M[mask]\n\t"
#endif
#ifndef USART_UNSAFE_TX_INTERRUPT
"cpse r30, r31 \n\t"
"rjmp USART0_TX_CONTINUE \n\t"
#ifdef USART0_IN_IO_ADDRESS_SPACE
"cbi %M[control_reg_IO], %M[udrie_bit] \n\t"
#elif defined(USART0_IN_UPPER_IO_ADDRESS_SPACE)
"in r31, %M[control_reg_IO] \n\t"
"andi r31, ~(1<<%M[udrie_bit]) \n\t"
"out %M[control_reg_IO], r31\n\t"
#else
"lds r31, %M[control_reg] \n\t"
"andi r31, ~(1<<%M[udrie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
#endif
"USART0_TX_CONTINUE: "
#endif
"sts (tx0_Tail), r30 \n\t"
#if !defined(__AVR_ATtiny2313__) && \
!defined(__AVR_ATtiny2313A__) // on ATtiny2313 upper byte in pointer pair
// is ignored
"ldi r31, 0x00 \n\t"
#endif
"subi r30, lo8(-(tx0_buffer)) \n\t"
#ifndef USART_USE_TINY_MEMORY_MODEL
"sbci r31, hi8(-(tx0_buffer)) \n\t"
#endif
"ld r30, Z \n\t"
#ifdef USART0_IN_IO_ADDRESS_SPACE
"out %M[UDR_reg_IO], r30 \n\t"
#else
"sts %M[UDR_reg], r30 \n\t"
#endif
TX0_TRANSMIT_EVENT
#ifdef USART_UNSAFE_TX_INTERRUPT
"cli \n\t"
#ifdef USART0_IN_IO_ADDRESS_SPACE
"sbi %M[control_reg_IO], %M[udrie_bit] \n\t"
#elif defined(USART0_IN_UPPER_IO_ADDRESS_SPACE)
"in r31, %M[control_reg_IO] \n\t"
"ori r31, (1<<%M[udrie_bit]) \n\t"
"out %M[control_reg_IO], r31\n\t"
#else
"lds r31, %M[control_reg] \n\t"
"ori r31, (1<<%M[udrie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
#endif
#endif
"USART0_TX_EXIT: "
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_Z_SAVE
"pop r31 \n\t"
"pop r30 \n\t"
#else
#ifdef __AVR_HAVE_MOVW__
"movw r30, %[z_save] \n\t"
#else
"mov r31, %B[z_save] \n\t"
"mov r30, %A[z_save] \n\t"
#endif
#endif
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_SREG_SAVE
"out __SREG__, r16 \n\t"
"pop r16 \n\t"
#else
"out __SREG__, %[sreg_save] \n\t"
#endif
"reti \n\t"
: // output operands
USART_REG_SAVE_LIST
: // input operands
#if defined(USART0_IN_IO_ADDRESS_SPACE) || \
defined(USART0_IN_UPPER_IO_ADDRESS_SPACE)
TX0_INPUT_OPERAND_LIST[UDR_reg_IO] "M"(_SFR_IO_ADDR(UDR0_REGISTER)),
#else
[UDR_reg] "n"(_SFR_MEM_ADDR(UDR0_REGISTER)),
#endif
#if __AVR_ARCH__ == 103
[control_reg] "n"(_SFR_MEM_ADDR(UCSR0A_REGISTER)),
#else
[control_reg_IO] "M"(_SFR_IO_ADDR(UCSR0B_REGISTER)),
[control_reg] "n"(_SFR_MEM_ADDR(UCSR0B_REGISTER)),
#endif
[udrie_bit] "M"(UDRIE0_BIT), [mask] "M"(TX0_BUFFER_MASK)
// no clobbers
);
}
#if defined(USART0_USE_TXC_INTERRUPT)
#ifdef USATR0_NO_NAKED_TXC_INTERRUPT
ISR(TXC0_INTERRUPT)
#else
ISR(TXC0_INTERRUPT, ISR_NAKED) // ISR is compiled to only one cbi instruction -
// no need for large prologue/epilogue
#endif
{
#ifdef USART0_RS485_MODE
RS485_CONTROL0_PORT &=
~(1 << RS485_CONTROL0_IONUM); // set low after completed transaction
#endif
TXC0_interrupt_event();
#ifndef USATR0_NO_NAKED_TXC_INTERRUPT
reti();
#endif
}
#endif
#endif // NO_TX0_INTERRUPT
#ifndef NO_RX0_INTERRUPT
ISR(RX0_INTERRUPT, ISR_NAKED) {
asm volatile(
"\n\t"
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_SREG_SAVE
"push r16 \n\t"
"in r16, __SREG__ \n\t"
#else
"in %[sreg_save], __SREG__ \n\t"
#endif
"push r25 \n\t"
#ifdef USART0_PUSH_BEFORE_RX
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_Z_SAVE
"push r30 \n\t"
"push r31 \n\t"
#else
#ifdef __AVR_HAVE_MOVW__
"movw %[z_save], r30 \n\t"
#else // in this case only 4 cycles are prematured out
"mov %A[z_save], r30\n\t"
"mov %B[z_save], r31\n\t"
#endif
#endif
#endif
#ifndef USART0_EXTEND_RX_BUFFER
RX0_FRAMING_EVENT
#ifdef USART0_IN_IO_ADDRESS_SPACE
"in r25, %M[UDR_reg_IO] \n\t"
#else
"lds r25, %M[UDR_reg] \n\t"
#endif
#endif
#ifndef USART0_PUSH_BEFORE_RX
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_Z_SAVE
"push r30 \n\t"
"push r31 \n\t"
#else
#ifdef __AVR_HAVE_MOVW__
"movw %[z_save], r30 \n\t"
#else // in this case only 4 cycles are prematured out
"mov %A[z_save], r30\n\t"
"mov %B[z_save], r31\n\t"
#endif
#endif
#endif
#ifdef USART_UNSAFE_RX_INTERRUPT
#ifdef USART0_IN_IO_ADDRESS_SPACE
"cbi %M[control_reg_IO], %M[rxcie_bit] \n\t"
#elif defined(USART0_IN_UPPER_IO_ADDRESS_SPACE)
"in r31, %M[control_reg_IO] \n\t"
"andi r31, ~(1<<%M[rxcie_bit]) \n\t"
"out %M[control_reg_IO], r31\n\t"
#else
"lds r31, %M[control_reg] \n\t"
"andi r31, ~(1<<%M[rxcie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
#endif
"sei \n\t"
#endif
RX0_EVERYCALL_EVENT
"lds r30, (rx0_Head) \n\t"
"lds r31, (rx0_Tail) \n\t"
"inc r30 \n\t"
#if (RX0_BUFFER_MASK != 0xff)
"andi r30, %M[mask]\n\t"
#endif
"cp r31, r30 \n\t"
#if defined(USART0_USE_SOFT_RTS) || (defined(USART0_EXTEND_RX_BUFFER) && \
!defined(USART_UNSAFE_RX_INTERRUPT))
"breq USART0_DISABLE_RXCIE \n\t"
#elif defined(USART0_EXTEND_RX_BUFFER) && defined(USART_UNSAFE_RX_INTERRUPT)
"breq USART0_RX_EXIT_SKIP \n\t"
#else
"breq USART0_RX_EXIT \n\t"
#endif
#ifdef USART0_EXTEND_RX_BUFFER
RX0_FRAMING_EVENT
#ifdef USART0_IN_IO_ADDRESS_SPACE
"in r25, %M[UDR_reg_IO] \n\t"
#else
"lds r25, %M[UDR_reg] \n\t"
#endif
#endif
RX0_EARLY_RECEIVE_EVENT
#if defined(USART0_MPCM_MODE) && !defined(MPCM0_MASTER_ONLY)
#ifdef USART0_IN_IO_ADDRESS_SPACE
"in r31, %M[MPCM_reg_IO] \n\t"
#else
"lds r31, %M[MPCM_reg] \n\t"
#endif
"sbrs r31, %M[mpcm_bit] \n\t"
"rjmp USART0_RX_CONTINUE \n\t"
"cpi r25, %M[mpcm_address] \n\t"
#ifdef MPCM0_GCALL_ADDRESS
"breq p_%= \n\t"
"cpi r25, %M[mpcm_gcall_address] \n\t"
#endif
"brne USART0_RX_EXIT \n\t"
"p_%=: "
"andi r31, ~(1<<%M[mpcm_bit]) \n\t"
#ifdef USART0_IN_IO_ADDRESS_SPACE
"out %M[MPCM_reg_IO], r31 \n\t"
#else
"sts %M[MPCM_reg], r31 \n\t"
#endif
"USART0_RX_CONTINUE: "
#endif
"sts (rx0_Head), r30 \n\t"
#if !defined(__AVR_ATtiny2313__) && \
!defined(__AVR_ATtiny2313A__) // on ATtiny2313 upper byte in pointer pair
// is ignored
"ldi r31, 0x00 \n\t"
#endif
"subi r30, lo8(-(rx0_buffer))\n\t"
#ifndef USART_USE_TINY_MEMORY_MODEL
"sbci r31, hi8(-(rx0_buffer))\n\t"
#endif
"st Z, r25 \n\t"
RX0_LATE_RECEIVE_EVENT
"USART0_RX_EXIT: "
#ifdef USART_UNSAFE_RX_INTERRUPT
"cli \n\t"
#ifdef USART0_IN_IO_ADDRESS_SPACE
"sbi %M[control_reg_IO], %M[rxcie_bit] \n\t"
#elif defined(USART0_IN_UPPER_IO_ADDRESS_SPACE)
"in r31, %M[control_reg_IO] \n\t"
"ori r31, (1<<%M[rxcie_bit]) \n\t"
"out %M[control_reg_IO], r31\n\t"
#else
"lds r31, %M[control_reg] \n\t"
"ori r31, (1<<%M[rxcie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
#endif
"USART0_RX_EXIT_SKIP: "
#endif
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_Z_SAVE
"pop r31 \n\t"
"pop r30 \n\t"
#else
#ifdef __AVR_HAVE_MOVW__
"movw r30, %[z_save] \n\t"
#else
"mov r31, %B[z_save] \n\t"
"mov r30, %A[z_save] \n\t"
#endif
#endif
"pop r25 \n\t"
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_SREG_SAVE
"out __SREG__, r16 \n\t"
"pop r16 \n\t"
#else
"out __SREG__, %[sreg_save] \n\t"
#endif
"reti \n\t"
#if defined(USART0_USE_SOFT_RTS) || (defined(USART0_EXTEND_RX_BUFFER) && \
!defined(USART_UNSAFE_RX_INTERRUPT))
"USART0_DISABLE_RXCIE: "
#ifdef USART0_USE_SOFT_RTS
"sbi %M[rts_port], %M[rts_pin] \n\t"
#endif
#ifndef USART_UNSAFE_RX_INTERRUPT
#ifdef USART0_IN_IO_ADDRESS_SPACE
"cbi %M[control_reg_IO], %M[rxcie_bit] \n\t"
#elif defined(USART0_IN_UPPER_IO_ADDRESS_SPACE)
"in r31, %M[control_reg_IO] \n\t"
"andi r31, ~(1<<%M[rxcie_bit]) \n\t"
"out %M[control_reg_IO], r31\n\t"
#else
"lds r31, %M[control_reg] \n\t"
"andi r31, ~(1<<%M[rxcie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
#endif
#endif
#ifdef USART_UNSAFE_RX_INTERRUPT
"rjmp USART0_RX_EXIT_SKIP \n\t"
#else
"rjmp USART0_RX_EXIT \n\t"
#endif
#endif
: // output operands
USART_REG_SAVE_LIST
: // input operands
#if __AVR_ARCH__ == 103
[UDR_reg] "n"(_SFR_MEM_ADDR(RX0_REGISTER)),
#else
RX0_INPUT_OPERAND_LIST[UDR_reg_IO] "M"(_SFR_IO_ADDR(UDR0_REGISTER)),
[UDR_reg] "n"(_SFR_MEM_ADDR(UDR0_REGISTER)),
#endif
[mask] "M"(RX0_BUFFER_MASK), [mpcm_address] "M"(MPCM0_ADDRESS),
#ifdef MPCM0_GCALL_ADDRESS
[mpcm_gcall_address] "M"(MPCM0_GCALL_ADDRESS),
#endif
[mpcm_bit] "M"(MPCM0_BIT),
#ifdef USART0_USE_SOFT_RTS
[rts_port] "M"(_SFR_IO_ADDR(RTS0_PORT)), [rts_pin] "M"(RTS0_IONUM),
#endif
#if __AVR_ARCH__ == 103
[MPCM_reg] "n"(_SFR_MEM_ADDR(UCSR0B_REGISTER)),
[control_reg] "n"(_SFR_MEM_ADDR(UCSR0A_REGISTER)),
#else
[MPCM_reg] "n"(_SFR_MEM_ADDR(UCSR0A_REGISTER)),
[MPCM_reg_IO] "M"(_SFR_IO_ADDR(UCSR0A_REGISTER)),
[control_reg_IO] "M"(_SFR_IO_ADDR(UCSR0B_REGISTER)),
[control_reg] "n"(_SFR_MEM_ADDR(UCSR0B_REGISTER)),
#endif
[rxcie_bit] "M"(RXCIE0_BIT)
// no clobbers
);
}
#endif // NO_RX0_INTERRUPT
#ifndef NO_TX1_INTERRUPT
ISR(UDRE1_INTERRUPT, ISR_NAKED) {
asm volatile(
"\n\t"
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_SREG_SAVE
"push r16 \n\t"
"in r16, __SREG__ \n\t"
#else
"in %[sreg_save], __SREG__ \n\t"
#endif
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_Z_SAVE
"push r30 \n\t"
"push r31 \n\t"
#else
"movw %[z_save], r30 \n\t"
#endif
#ifdef USART_UNSAFE_TX_INTERRUPT
#ifdef USART1_IN_IO_ADDRESS_SPACE
"cbi %M[control_reg_IO], %M[udrie_bit] \n\t"
#else
"lds r31, %M[control_reg] \n\t"
"andi r31, ~(1<<%M[udrie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
#endif
"sei \n\t"
#endif
TX1_EVERYCAL_EVENT
"lds r30, (tx1_Tail) \n\t"
"lds r31, (tx1_Head) \n\t"
#ifdef USART_UNSAFE_TX_INTERRUPT
"cp r30, r31 \n\t"
"breq USART1_TX_EXIT \n\t"
#endif
"inc r30 \n\t"
#if (TX1_BUFFER_MASK != 0xff)
"andi r30, %M[mask]\n\t"
#endif
#ifndef USART_UNSAFE_TX_INTERRUPT
"cpse r30, r31 \n\t"
"rjmp USART1_TX_CONTINUE \n\t"
#ifdef USART1_IN_IO_ADDRESS_SPACE
"cbi %M[control_reg_IO], %M[udrie_bit] \n\t"
#else
"lds r31, %M[control_reg] \n\t"
"andi r31, ~(1<<%M[udrie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
#endif
"USART1_TX_CONTINUE: "
#endif
"sts (tx1_Tail), r30 \n\t"
"ldi r31, 0x00 \n\t"
"subi r30, lo8(-(tx1_buffer)) \n\t"
"sbci r31, hi8(-(tx1_buffer)) \n\t"
"ld r30, Z \n\t"
#ifdef USART1_IN_IO_ADDRESS_SPACE
"out %M[UDR_reg_IO], r30 \n\t"
#else
"sts %M[UDR_reg], r30 \n\t"
#endif
TX1_TRANSMIT_EVENT
#ifdef USART_UNSAFE_TX_INTERRUPT
"cli \n\t"
#ifdef USART1_IN_IO_ADDRESS_SPACE
"sbi %M[control_reg_IO], %M[udrie_bit] \n\t"
#else
"lds r31, %M[control_reg] \n\t"
"ori r31, (1<<%M[udrie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
#endif
#endif
"USART1_TX_EXIT: "
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_Z_SAVE
"pop r31 \n\t"
"pop r30 \n\t"
#else
"movw r30, %[z_save] \n\t"
#endif
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_SREG_SAVE
"out __SREG__, r16 \n\t"
"pop r16 \n\t"
#else
"out __SREG__, %[sreg_save] \n\t"
#endif
"reti \n\t"
: // output operands
USART_REG_SAVE_LIST
: // input operands
TX1_INPUT_OPERAND_LIST[UDR_reg_IO] "M"(_SFR_IO_ADDR(UDR1_REGISTER)),
[UDR_reg] "n"(_SFR_MEM_ADDR(UDR1_REGISTER)),
#if __AVR_ARCH__ == 103
[control_reg_IO] "M"(_SFR_IO_ADDR(UCSR1A_REGISTER)),
[control_reg] "n"(_SFR_MEM_ADDR(UCSR1A_REGISTER)),
#else
[control_reg_IO] "M"(_SFR_IO_ADDR(UCSR1B_REGISTER)),
[control_reg] "n"(_SFR_MEM_ADDR(UCSR1B_REGISTER)),
#endif
[udrie_bit] "M"(UDRIE1_BIT), [mask] "M"(TX1_BUFFER_MASK)
// no clobbers
);
}
#if defined(USART1_USE_TXC_INTERRUPT)
#ifdef USATR1_NO_NAKED_TXC_INTERRUPT
ISR(TXC1_INTERRUPT)
#else
ISR(TXC1_INTERRUPT, ISR_NAKED) // ISR is compiled to only one cbi instruction -
// no need for large prologue/epilogue
#endif
{
#ifdef USART1_RS485_MODE
RS485_CONTROL1_PORT &=
~(1 << RS485_CONTROL1_IONUM); // set low after completed transaction
#endif
TXC1_interrupt_event();
#ifndef USATR1_NO_NAKED_TXC_INTERRUPT
reti();
#endif
}
#endif // USART1_RS485_MODE
#endif // NO_TX1_INTERRUPT
#ifndef NO_RX1_INTERRUPT
ISR(RX1_INTERRUPT, ISR_NAKED) {
asm volatile(
"\n\t"
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_SREG_SAVE
"push r16 \n\t"
"in r16, __SREG__ \n\t"
#else
"in %[sreg_save], __SREG__ \n\t"
#endif
"push r25 \n\t"
#ifdef USART1_PUSH_BEFORE_RX
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_Z_SAVE
"push r30 \n\t"
"push r31 \n\t"
#else
"movw %[z_save], r30 \n\t"
#endif
#endif
#ifndef USART1_EXTEND_RX_BUFFER
RX1_FRAMING_EVENT
#ifdef USART1_IN_IO_ADDRESS_SPACE
"in r25, %M[UDR_reg_IO] \n\t"
#else
"lds r25, %M[UDR_reg] \n\t"
#endif
#endif
#ifndef USART1_PUSH_BEFORE_RX
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_Z_SAVE
"push r30 \n\t"
"push r31 \n\t"
#else
"movw %[z_save], r30 \n\t"
#endif
#endif
#ifdef USART_UNSAFE_RX_INTERRUPT
#ifdef USART1_IN_IO_ADDRESS_SPACE
"cbi %M[control_reg_IO], %M[rxcie_bit] \n\t"
#else
"lds r31, %M[control_reg] \n\t"
"andi r31, ~(1<<%M[rxcie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
#endif
"sei \n\t"
#endif
RX1_EVERYCALL_EVENT
"lds r30, (rx1_Head) \n\t"
"lds r31, (rx1_Tail) \n\t"
"inc r30 \n\t"
#if (RX1_BUFFER_MASK != 0xff)
"andi r30, %M[mask]\n\t"
#endif
"cp r31, r30 \n\t"
#if defined(USART1_USE_SOFT_RTS) || (defined(USART1_EXTEND_RX_BUFFER) && \
!defined(USART_UNSAFE_RX_INTERRUPT))
"breq USART1_DISABLE_RXCIE \n\t"
#elif defined(USART1_EXTEND_RX_BUFFER) && defined(USART_UNSAFE_RX_INTERRUPT)
"breq USART1_RX_EXIT_SKIP \n\t"
#else
"breq USART1_RX_EXIT \n\t"
#endif
#ifdef USART1_EXTEND_RX_BUFFER
RX1_FRAMING_EVENT
#ifdef USART1_IN_IO_ADDRESS_SPACE
"in r25, %M[UDR_reg_IO] \n\t"
#else
"lds r25, %M[UDR_reg] \n\t"
#endif
#endif
RX1_EARLY_RECEIVE_EVENT
#if defined(USART1_MPCM_MODE) && !defined(MPCM1_MASTER_ONLY)
#ifdef USART1_IN_IO_ADDRESS_SPACE
"in r31, %M[MPCM_reg_IO] \n\t"
#else
"lds r31, %M[MPCM_reg] \n\t"
#endif
"sbrs r31, %M[mpcm_bit] \n\t"
"rjmp USART1_RX_CONTINUE \n\t"
"cpi r25, %M[mpcm_address] \n\t"
#ifdef MPCM1_GCALL_ADDRESS
"breq p_%= \n\t"
"cpi r25, %M[mpcm_gcall_address] \n\t"
#endif
"brne USART1_RX_EXIT \n\t"
"p_%=: "
"andi r31, ~(1<<%M[mpcm_bit]) \n\t"
#ifdef USART1_IN_IO_ADDRESS_SPACE
"out %M[MPCM_reg_IO], r31 \n\t"
#else
"sts %M[MPCM_reg], r31 \n\t"
#endif
"USART1_RX_CONTINUE: "
#endif
"sts (rx1_Head), r30 \n\t"
"ldi r31, 0x00 \n\t"
"subi r30, lo8(-(rx1_buffer))\n\t"
"sbci r31, hi8(-(rx1_buffer))\n\t"
"st Z, r25 \n\t"
RX1_LATE_RECEIVE_EVENT
"USART1_RX_EXIT: "
#ifdef USART_UNSAFE_RX_INTERRUPT
"cli \n\t"
#ifdef USART1_IN_IO_ADDRESS_SPACE
"sbi %M[control_reg_IO], %M[rxcie_bit] \n\t"
#else
"lds r31, %M[control_reg] \n\t"
"ori r31, (1<<%M[rxcie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
#endif
"USART1_RX_EXIT_SKIP: "
#endif
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_Z_SAVE
"pop r31 \n\t"
"pop r30 \n\t"
#else
"movw r30, %[z_save] \n\t"
#endif
"pop r25 \n\t"
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_SREG_SAVE
"out __SREG__, r16 \n\t"
"pop r16 \n\t"
#else
"out __SREG__, %[sreg_save] \n\t"
#endif
"reti \n\t"
#if defined(USART1_USE_SOFT_RTS) || (defined(USART1_EXTEND_RX_BUFFER) && \
!defined(USART_UNSAFE_RX_INTERRUPT))
"USART1_DISABLE_RXCIE: "
#ifdef USART1_USE_SOFT_RTS
"sbi %M[rts_port], %M[rts_pin] \n\t"
#endif
#ifndef USART_UNSAFE_RX_INTERRUPT
#ifdef USART1_IN_IO_ADDRESS_SPACE
"cbi %M[control_reg_IO], %M[rxcie_bit] \n\t"
#else
"lds r31, %M[control_reg] \n\t"
"andi r31, ~(1<<%M[rxcie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
#endif
#endif
#ifdef USART_UNSAFE_RX_INTERRUPT
"rjmp USART1_RX_EXIT_SKIP \n\t"
#else
"rjmp USART1_RX_EXIT \n\t"
#endif
#endif
: // output operands
USART_REG_SAVE_LIST
: // input operands
#if __AVR_ARCH__ == 103
RX1_INPUT_OPERAND_LIST[UDR_reg_IO] "M"(_SFR_IO_ADDR(RX1_REGISTER)),
[UDR_reg] "n"(_SFR_MEM_ADDR(RX1_REGISTER)),
#else
RX1_INPUT_OPERAND_LIST[UDR_reg_IO] "M"(_SFR_IO_ADDR(UDR1_REGISTER)),
[UDR_reg] "n"(_SFR_MEM_ADDR(UDR1_REGISTER)),
#endif
[mask] "M"(RX1_BUFFER_MASK), [mpcm_address] "M"(MPCM1_ADDRESS),
#ifdef MPCM1_GCALL_ADDRESS
[mpcm_gcall_address] "M"(MPCM1_GCALL_ADDRESS),
#endif
[mpcm_bit] "M"(MPCM1_BIT),
#ifdef USART1_USE_SOFT_RTS
[rts_port] "M"(_SFR_IO_ADDR(RTS1_PORT)), [rts_pin] "M"(RTS1_IONUM),
#endif
#if __AVR_ARCH__ == 103
[MPCM_reg] "n"(_SFR_MEM_ADDR(UCSR1B_REGISTER)),
[MPCM_reg_IO] "M"(_SFR_IO_ADDR(UCSR1B_REGISTER)),
[control_reg_IO] "M"(_SFR_IO_ADDR(UCSR1A_REGISTER)),
[control_reg] "n"(_SFR_MEM_ADDR(UCSR1A_REGISTER)),
#else
[MPCM_reg] "n"(_SFR_MEM_ADDR(UCSR1A_REGISTER)),
[MPCM_reg_IO] "M"(_SFR_IO_ADDR(UCSR1A_REGISTER)),
[control_reg_IO] "M"(_SFR_IO_ADDR(UCSR1B_REGISTER)),
[control_reg] "n"(_SFR_MEM_ADDR(UCSR1B_REGISTER)),
#endif
[rxcie_bit] "M"(RXCIE1_BIT)
// no clobbers
);
}
#endif // NO_RX1_INTERRUPT
#ifndef NO_TX2_INTERRUPT
ISR(UDRE2_INTERRUPT, ISR_NAKED) {
asm volatile(
"\n\t"
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_SREG_SAVE
"push r16 \n\t"
"in r16, __SREG__ \n\t"
#else
"in %[sreg_save], __SREG__ \n\t"
#endif
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_Z_SAVE
"push r30 \n\t"
"push r31 \n\t"
#else
"movw %[z_save], r30 \n\t"
#endif
#ifdef USART_UNSAFE_TX_INTERRUPT
"lds r31, %M[control_reg] \n\t"
"andi r31, ~(1<<%M[udrie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
"sei \n\t"
#endif
TX2_EVERYCAL_EVENT
"lds r30, (tx2_Tail) \n\t"
"lds r31, (tx2_Head) \n\t"
#ifdef USART_UNSAFE_TX_INTERRUPT
"cp r30, r31 \n\t"
"breq USART2_TX_EXIT \n\t"
#endif
"inc r30 \n\t"
#if (TX2_BUFFER_MASK != 0xff)
"andi r30, %M[mask]\n\t"
#endif
#ifndef USART_UNSAFE_TX_INTERRUPT
"cpse r30, r31 \n\t"
"rjmp USART2_TX_CONTINUE \n\t"
"lds r31, %M[control_reg] \n\t"
"andi r31, ~(1<<%M[udrie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
"USART2_TX_CONTINUE: "
#endif
"sts (tx2_Tail), r30 \n\t"
"ldi r31, 0x00 \n\t"
"subi r30, lo8(-(tx2_buffer)) \n\t"
"sbci r31, hi8(-(tx2_buffer)) \n\t"
"ld r30, Z \n\t"
"sts %M[UDR_reg], r30 \n\t"
TX2_TRANSMIT_EVENT
#ifdef USART_UNSAFE_TX_INTERRUPT
"cli \n\t"
"lds r31, %M[control_reg] \n\t"
"ori r31, (1<<%M[udrie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
#endif
"USART2_TX_EXIT: "
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_Z_SAVE
"pop r31 \n\t"
"pop r30 \n\t"
#else
"movw r30, %[z_save] \n\t"
#endif
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_SREG_SAVE
"out __SREG__, r16 \n\t"
"pop r16 \n\t"
#else
"out __SREG__, %[sreg_save] \n\t"
#endif
"reti \n\t"
: // output operands
USART_REG_SAVE_LIST
: // input operands
TX2_INPUT_OPERAND_LIST[UDR_reg] "n"(_SFR_MEM_ADDR(UDR2_REGISTER)),
#if __AVR_ARCH__ == 103
[control_reg] "n"(_SFR_MEM_ADDR(UCSR2A_REGISTER)),
#else
[control_reg] "n"(_SFR_MEM_ADDR(UCSR2B_REGISTER)),
#endif
[udrie_bit] "M"(UDRIE2_BIT), [mask] "M"(TX2_BUFFER_MASK)
// no clobbers
);
}
#if defined(USART2_USE_TXC_INTERRUPT)
#ifdef USATR2_NO_NAKED_TXC_INTERRUPT
ISR(TXC2_INTERRUPT)
#else
ISR(TXC2_INTERRUPT, ISR_NAKED) // ISR is compiled to only one cbi instruction -
// no need for large prologue/epilogue
#endif
{
#ifdef USART2_RS485_MODE
RS485_CONTROL2_PORT &=
~(1 << RS485_CONTROL2_IONUM); // set low after completed transaction
#endif
TXC2_interrupt_event();
#ifndef USATR2_NO_NAKED_TXC_INTERRUPT
reti();
#endif
}
#endif // USART2_RS485_MODE
#endif // NO_TX2_INTERRUPT
#ifndef NO_RX2_INTERRUPT
ISR(RX2_INTERRUPT, ISR_NAKED) {
asm volatile(
"\n\t"
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_SREG_SAVE
"push r16 \n\t"
"in r16, __SREG__ \n\t"
#else
"in %[sreg_save], __SREG__ \n\t"
#endif
"push r25 \n\t"
#ifdef USART2_PUSH_BEFORE_RX
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_Z_SAVE
"push r30 \n\t"
"push r31 \n\t"
#else
"movw %[z_save], r30 \n\t"
#endif
#endif
#ifndef USART2_EXTEND_RX_BUFFER
RX2_FRAMING_EVENT "lds r25, %M[UDR_reg] \n\t"
#endif
#ifndef USART2_PUSH_BEFORE_RX
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_Z_SAVE
"push r30 \n\t"
"push r31 \n\t"
#else
"movw %[z_save], r30 \n\t"
#endif
#endif
#ifdef USART_UNSAFE_RX_INTERRUPT
"lds r31, %M[control_reg] \n\t"
"andi r31, ~(1<<%M[rxcie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
"sei \n\t"
#endif
RX2_EVERYCALL_EVENT
"lds r30, (rx2_Head) \n\t"
"lds r31, (rx2_Tail) \n\t"
"inc r30 \n\t"
#if (RX2_BUFFER_MASK != 0xff)
"andi r30, %M[mask]\n\t"
#endif
"cp r31, r30 \n\t"
#if defined(USART2_USE_SOFT_RTS) || (defined(USART2_EXTEND_RX_BUFFER) && \
!defined(USART_UNSAFE_RX_INTERRUPT))
"breq USART2_DISABLE_RXCIE \n\t"
#elif defined(USART2_EXTEND_RX_BUFFER) && defined(USART_UNSAFE_RX_INTERRUPT)
"breq USART2_RX_EXIT_SKIP \n\t"
#else
"breq USART2_RX_EXIT \n\t"
#endif
#ifdef USART2_EXTEND_RX_BUFFER
RX2_FRAMING_EVENT "lds r25, %M[UDR_reg] \n\t"
#endif
RX2_EARLY_RECEIVE_EVENT
#if defined(USART2_MPCM_MODE) && !defined(MPCM2_MASTER_ONLY)
"lds r31, %M[MPCM_reg] \n\t"
"sbrs r31, %M[mpcm_bit] \n\t"
"rjmp USART2_RX_CONTINUE \n\t"
"cpi r25, %M[mpcm_address] \n\t"
#ifdef MPCM2_GCALL_ADDRESS
"breq p_%= \n\t"
"cpi r25, %M[mpcm_gcall_address] \n\t"
#endif
"brne USART2_RX_EXIT \n\t"
"p_%=: "
"andi r31, ~(1<<%M[mpcm_bit]) \n\t"
"sts %M[MPCM_reg], r31 \n\t"
"USART2_RX_CONTINUE: "
#endif
"sts (rx2_Head), r30 \n\t"
"ldi r31, 0x00 \n\t"
"subi r30, lo8(-(rx2_buffer))\n\t"
"sbci r31, hi8(-(rx2_buffer))\n\t"
"st Z, r25 \n\t"
RX2_LATE_RECEIVE_EVENT
"USART2_RX_EXIT: "
#ifdef USART_UNSAFE_RX_INTERRUPT
"cli \n\t"
"lds r31, %M[control_reg] \n\t"
"ori r31, (1<<%M[rxcie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
"USART2_RX_EXIT_SKIP: "
#endif
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_Z_SAVE
"pop r31 \n\t"
"pop r30 \n\t"
#else
"movw r30, %[z_save] \n\t"
#endif
"pop r25 \n\t"
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_SREG_SAVE
"out __SREG__, r16 \n\t"
"pop r16 \n\t"
#else
"out __SREG__, %[sreg_save] \n\t"
#endif
"reti \n\t"
#if defined(USART2_USE_SOFT_RTS) || (defined(USART2_EXTEND_RX_BUFFER) && \
!defined(USART_UNSAFE_RX_INTERRUPT))
"USART2_DISABLE_RXCIE: "
#ifdef USART3_USE_SOFT_RTS
"sbi %M[rts_port], %M[rts_pin] \n\t"
#endif
#ifndef USART_UNSAFE_RX_INTERRUPT
"lds r31, %M[control_reg] \n\t"
"andi r31, ~(1<<%M[rxcie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
#endif
#ifdef USART_UNSAFE_RX_INTERRUPT
"rjmp USART2_RX_EXIT_SKIP \n\t"
#else
"rjmp USART2_RX_EXIT \n\t"
#endif
#endif
: // output operands
USART_REG_SAVE_LIST
: // input operands
#if __AVR_ARCH__ == 103
RX2_INPUT_OPERAND_LIST[UDR_reg] "n"(_SFR_MEM_ADDR(RX2_REGISTER)),
#else
RX2_INPUT_OPERAND_LIST[UDR_reg] "n"(_SFR_MEM_ADDR(UDR2_REGISTER)),
#endif
[mask] "M"(RX2_BUFFER_MASK), [mpcm_address] "M"(MPCM2_ADDRESS),
#ifdef MPCM2_GCALL_ADDRESS
[mpcm_gcall_address] "M"(MPCM2_GCALL_ADDRESS),
#endif
[mpcm_bit] "M"(MPCM2_BIT),
#ifdef USART2_USE_SOFT_RTS
[rts_port] "M"(_SFR_IO_ADDR(RTS2_PORT)), [rts_pin] "M"(RTS2_IONUM),
#endif
#if __AVR_ARCH__ == 103
[MPCM_reg] "n"(_SFR_MEM_ADDR(UCSR2B_REGISTER)),
[control_reg] "n"(_SFR_MEM_ADDR(UCSR2A_REGISTER)),
#else
[MPCM_reg] "n"(_SFR_MEM_ADDR(UCSR2A_REGISTER)),
[control_reg] "n"(_SFR_MEM_ADDR(UCSR2B_REGISTER)),
#endif
[rxcie_bit] "M"(RXCIE2_BIT)
// no clobbers
);
}
#endif // NO_RX2_INTERRUPT
#ifndef NO_TX3_INTERRUPT
ISR(UDRE3_INTERRUPT, ISR_NAKED) {
asm volatile(
"\n\t"
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_SREG_SAVE
"push r16 \n\t"
"in r16, __SREG__ \n\t"
#else
"in %[sreg_save], __SREG__ \n\t"
#endif
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_Z_SAVE
"push r30 \n\t"
"push r31 \n\t"
#else
"movw %[z_save], r30 \n\t"
#endif
#ifdef USART_UNSAFE_TX_INTERRUPT
"lds r31, %M[control_reg] \n\t"
"andi r31, ~(1<<%M[udrie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
"sei \n\t"
#endif
TX3_EVERYCAL_EVENT
"lds r30, (tx3_Tail) \n\t"
"lds r31, (tx3_Head) \n\t"
#ifdef USART_UNSAFE_TX_INTERRUPT
"cp r30, r31 \n\t"
"breq USART3_TX_EXIT \n\t"
#endif
"inc r30 \n\t"
#if (TX3_BUFFER_MASK != 0xff)
"andi r30, %M[mask]\n\t"
#endif
#ifndef USART_UNSAFE_TX_INTERRUPT
"cpse r30, r31 \n\t"
"rjmp USART3_TX_CONTINUE \n\t"
"lds r31, %M[control_reg] \n\t"
"andi r31, ~(1<<%M[udrie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
"USART3_TX_CONTINUE: "
#endif
"sts (tx3_Tail), r30 \n\t"
"ldi r31, 0x00 \n\t"
"subi r30, lo8(-(tx3_buffer)) \n\t"
"sbci r31, hi8(-(tx3_buffer)) \n\t"
"ld r30, Z \n\t"
"sts %M[UDR_reg], r30 \n\t"
TX3_TRANSMIT_EVENT
#ifdef USART_UNSAFE_TX_INTERRUPT
"cli \n\t"
"lds r31, %M[control_reg] \n\t"
"ori r31, (1<<%M[udrie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
#endif
"USART3_TX_EXIT: "
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_Z_SAVE
"pop r31 \n\t"
"pop r30 \n\t"
#else
"movw r30, %[z_save] \n\t"
#endif
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_SREG_SAVE
"out __SREG__, r16 \n\t"
"pop r16 \n\t"
#else
"out __SREG__, %[sreg_save] \n\t"
#endif
"reti \n\t"
: // output operands
USART_REG_SAVE_LIST
: // input operands
TX3_INPUT_OPERAND_LIST[UDR_reg] "n"(_SFR_MEM_ADDR(UDR3_REGISTER)),
#if __AVR_ARCH__ == 103
[control_reg] "n"(_SFR_MEM_ADDR(UCSR3A_REGISTER)),
#else
[control_reg] "n"(_SFR_MEM_ADDR(UCSR3B_REGISTER)),
#endif
[udrie_bit] "M"(UDRIE3_BIT), [mask] "M"(TX3_BUFFER_MASK)
// no clobbers
);
}
#if defined(USART3_USE_TXC_INTERRUPT)
#ifdef USATR3_NO_NAKED_TXC_INTERRUPT
ISR(TXC3_INTERRUPT)
#else
ISR(TXC3_INTERRUPT, ISR_NAKED) // ISR is compiled to only one cbi instruction -
// no need for large prologue/epilogue
#endif
{
#ifdef USART3_RS485_MODE
RS485_CONTROL3_PORT &=
~(1 << RS485_CONTROL3_IONUM); // set low after completed transaction
#endif
TXC3_interrupt_event();
#ifndef USATR3_NO_NAKED_TXC_INTERRUPT
reti();
#endif
}
#endif // USART0_RS485_MODE
#endif // NO_TX3_INTERRUPT
#ifndef NO_RX3_INTERRUPT
ISR(RX3_INTERRUPT, ISR_NAKED) {
asm volatile(
"\n\t"
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_SREG_SAVE
"push r16 \n\t"
"in r16, __SREG__ \n\t"
#else
"in %[sreg_save], __SREG__ \n\t"
#endif
"push r25 \n\t"
#ifdef USART3_PUSH_BEFORE_RX
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_Z_SAVE
"push r30 \n\t"
"push r31 \n\t"
#else
"movw %[z_save], r30 \n\t"
#endif
#endif
#ifndef USART3_EXTEND_RX_BUFFER
RX3_FRAMING_EVENT "lds r25, %M[UDR_reg] \n\t"
#endif
#ifndef USART3_PUSH_BEFORE_RX
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_Z_SAVE
"push r30 \n\t"
"push r31 \n\t"
#else
"movw %[z_save], r30 \n\t"
#endif
#endif
#ifdef USART_UNSAFE_RX_INTERRUPT
"lds r31, %M[control_reg] \n\t"
"andi r31, ~(1<<%M[rxcie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
"sei \n\t"
#endif
RX3_EVERYCALL_EVENT
"lds r30, (rx3_Head) \n\t"
"lds r31, (rx3_Tail) \n\t"
"inc r30 \n\t"
#if (RX3_BUFFER_MASK != 0xff)
"andi r30, %M[mask]\n\t"
#endif
"cp r31, r30 \n\t"
#if defined(USART3_USE_SOFT_RTS) || (defined(USART3_EXTEND_RX_BUFFER) && \
!defined(USART_UNSAFE_RX_INTERRUPT))
"breq USART3_DISABLE_RXCIE \n\t"
#elif defined(USART3_EXTEND_RX_BUFFER) && defined(USART_UNSAFE_RX_INTERRUPT)
"breq USART3_RX_EXIT_SKIP \n\t"
#else
"breq USART3_RX_EXIT \n\t"
#endif
#ifdef USART3_EXTEND_RX_BUFFER
RX3_FRAMING_EVENT "lds r25, %M[UDR_reg] \n\t"
#endif
RX3_EARLY_RECEIVE_EVENT
#if defined(USART3_MPCM_MODE) && !defined(MPCM3_MASTER_ONLY)
"lds r31, %M[MPCM_reg] \n\t"
"sbrs r31, %M[mpcm_bit] \n\t"
"rjmp USART3_RX_CONTINUE \n\t"
"cpi r25, %M[mpcm_address] \n\t"
#ifdef MPCM3_GCALL_ADDRESS
"breq p_%= \n\t"
"cpi r25, %M[mpcm_gcall_address] \n\t"
#endif
"brne USART3_RX_EXIT \n\t"
"p_%=: "
"andi r31, ~(1<<%M[mpcm_bit]) \n\t"
"sts %M[MPCM_reg], r31 \n\t"
"USART3_RX_CONTINUE: "
#endif
"sts (rx3_Head), r30 \n\t"
"ldi r31, 0x00 \n\t"
"subi r30, lo8(-(rx3_buffer))\n\t"
"sbci r31, hi8(-(rx3_buffer))\n\t"
"st Z, r25 \n\t"
RX3_LATE_RECEIVE_EVENT
"USART3_RX_EXIT: "
#ifdef USART_UNSAFE_RX_INTERRUPT
"cli \n\t"
"lds r31, %M[control_reg] \n\t"
"ori r31, (1<<%M[rxcie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
"USART3_RX_EXIT_SKIP: "
#endif
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_Z_SAVE
"pop r31 \n\t"
"pop r30 \n\t"
#else
"movw r30, %[z_save] \n\t"
#endif
"pop r25 \n\t"
#ifndef USART_USE_GLOBALLY_RESERVED_ISR_SREG_SAVE
"out __SREG__, r16 \n\t"
"pop r16 \n\t"
#else
"out __SREG__, %[sreg_save] \n\t"
#endif
"reti \n\t"
#if defined(USART3_USE_SOFT_RTS) || (defined(USART3_EXTEND_RX_BUFFER) && \
!defined(USART_UNSAFE_RX_INTERRUPT))
"USART3_DISABLE_RXCIE: "
#ifdef USART3_USE_SOFT_RTS
"sbi %M[rts_port], %M[rts_pin] \n\t"
#endif
#ifndef USART_UNSAFE_RX_INTERRUPT
"lds r31, %M[control_reg] \n\t"
"andi r31, ~(1<<%M[rxcie_bit]) \n\t"
"sts %M[control_reg], r31 \n\t"
#endif
#ifdef USART_UNSAFE_RX_INTERRUPT
"rjmp USART3_RX_EXIT_SKIP \n\t"
#else
"rjmp USART3_RX_EXIT \n\t"
#endif
#endif
: // output operands
USART_REG_SAVE_LIST
: // input operands
#if __AVR_ARCH__ == 103
RX3_INPUT_OPERAND_LIST[UDR_reg] "n"(_SFR_MEM_ADDR(RX3_REGISTER)),
#else
RX3_INPUT_OPERAND_LIST[UDR_reg] "n"(_SFR_MEM_ADDR(UDR3_REGISTER)),
#endif
[mask] "M"(RX3_BUFFER_MASK), [mpcm_address] "M"(MPCM3_ADDRESS),
#ifdef MPCM3_GCALL_ADDRESS
[mpcm_gcall_address] "M"(MPCM3_GCALL_ADDRESS),
#endif
[mpcm_bit] "M"(MPCM3_BIT),
#ifdef USART3_USE_SOFT_RTS
[rts_port] "M"(_SFR_IO_ADDR(RTS3_PORT)), [rts_pin] "M"(RTS3_IONUM),
#endif
#if __AVR_ARCH__ == 103
[MPCM_reg] "n"(_SFR_MEM_ADDR(UCSR3B_REGISTER)),
[control_reg] "n"(_SFR_MEM_ADDR(UCSR3A_REGISTER)),
#else
[MPCM_reg] "n"(_SFR_MEM_ADDR(UCSR3A_REGISTER)),
[control_reg] "n"(_SFR_MEM_ADDR(UCSR3B_REGISTER)),
#endif
[rxcie_bit] "M"(RXCIE3_BIT)
// no clobbers
);
}
#endif // NO_RX3_INTERRUPT