mirror of
https://github.com/halleysfifthinc/Toyota-AVC-LAN
synced 2025-06-11 01:46:28 +00:00
6239 lines
164 KiB
C
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
|