Skip to content

Initial implementation of 9bit data support #6443

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 41 additions & 5 deletions hardware/arduino/avr/cores/arduino/HardwareSerial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,18 @@ void HardwareSerial::_tx_udr_empty_irq(void)
{
// If interrupts are enabled, there must be more data in the output
// buffer. Send the next byte
unsigned char c = _tx_buffer[_tx_buffer_tail];
serial_data_t c = _tx_buffer[_tx_buffer_tail];
_tx_buffer_tail = (_tx_buffer_tail + 1) % SERIAL_TX_BUFFER_SIZE;

#ifdef SERIAL9
if (use9bit) {
if (c & 0x100) {
sbi(*_ucsrb, TXB80);
} else {
cbi(*_ucsrb, TXB80);
}
c = c & 0xff;
}
#endif // SERIAL9
*_udr = c;

// clear the TXC bit -- "can be cleared by writing a one to its bit
Expand All @@ -100,8 +109,9 @@ void HardwareSerial::_tx_udr_empty_irq(void)

// Public Methods //////////////////////////////////////////////////////////////

void HardwareSerial::begin(unsigned long baud, byte config)
void HardwareSerial::begin(unsigned long baud, uint16_t extConfig)
{
byte config = extConfig & 0xff;
// Try u2x mode first
uint16_t baud_setting = (F_CPU / 4 / baud - 1) / 2;
*_ucsra = 1 << U2X0;
Expand All @@ -128,7 +138,15 @@ void HardwareSerial::begin(unsigned long baud, byte config)
config |= 0x80; // select UCSRC register (shared with UBRRH)
#endif
*_ucsrc = config;

#ifdef SERIAL9
if (extConfig & 0x100) {
sbi(*_ucsrb, UCSZ02);
use9bit = true;
} else {
use9bit = false;
}
#endif // SERIAL9

sbi(*_ucsrb, RXEN0);
sbi(*_ucsrb, TXEN0);
sbi(*_ucsrb, RXCIE0);
Expand Down Expand Up @@ -169,7 +187,7 @@ int HardwareSerial::read(void)
if (_rx_buffer_head == _rx_buffer_tail) {
return -1;
} else {
unsigned char c = _rx_buffer[_rx_buffer_tail];
serial_data_t c = _rx_buffer[_rx_buffer_tail];
_rx_buffer_tail = (rx_buffer_index_t)(_rx_buffer_tail + 1) % SERIAL_RX_BUFFER_SIZE;
return c;
}
Expand Down Expand Up @@ -210,14 +228,28 @@ void HardwareSerial::flush()
// the hardware finished tranmission (TXC is set).
}

#ifdef SERIAL9
size_t HardwareSerial::write9(uint16_t c)
#else // !defined(SERIAL9)
size_t HardwareSerial::write(uint8_t c)
#endif // SERIAL9
{
_written = true;
// If the buffer and the data register is empty, just write the byte
// to the data register and be done. This shortcut helps
// significantly improve the effective datarate at high (>
// 500kbit/s) bitrates, where interrupt overhead becomes a slowdown.
if (_tx_buffer_head == _tx_buffer_tail && bit_is_set(*_ucsra, UDRE0)) {
#ifdef SERIAL9
if (use9bit) {
if (c & 0x100) {
sbi(*_ucsrb, TXB80);
} else {
cbi(*_ucsrb, TXB80);
}
c = c & 0xff;
}
#endif // SERIAL9
*_udr = c;
sbi(*_ucsra, TXC0);
return 1;
Expand All @@ -239,7 +271,11 @@ size_t HardwareSerial::write(uint8_t c)
}
}

#ifdef SERIAL9
_tx_buffer[_tx_buffer_head] = (c & 0x1ff);
#else // !defined(SERIAL9)
_tx_buffer[_tx_buffer_head] = c;
#endif // SERIAL9
_tx_buffer_head = i;

sbi(*_ucsrb, UDRIE0);
Expand Down
36 changes: 32 additions & 4 deletions hardware/arduino/avr/cores/arduino/HardwareSerial.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ typedef uint16_t rx_buffer_index_t;
typedef uint8_t rx_buffer_index_t;
#endif

#ifdef SERIAL9
typedef unsigned short serial_data_t;
#else
typedef unsigned char serial_data_t;
#endif // SERIAL9

// Define config for Serial.begin(baud, config);
#define SERIAL_5N1 0x00
#define SERIAL_6N1 0x02
Expand All @@ -90,6 +96,17 @@ typedef uint8_t rx_buffer_index_t;
#define SERIAL_7O2 0x3C
#define SERIAL_8O2 0x3E

#ifdef SERIAL9

#define SERIAL_9N1 0x106
#define SERIAL_9N2 (0x106 + SERIAL_5N2)
#define SERIAL_9E1 (0x106 + SERIAL_5E1)
#define SERIAL_9E2 (0x106 + SERIAL_5E2)
#define SERIAL_9O1 (0x106 + SERIAL_5O1)
#define SERIAL_9O2 (0x106 + SERIAL_5O2)

#endif // SERIAL9

class HardwareSerial : public Stream
{
protected:
Expand All @@ -101,6 +118,9 @@ class HardwareSerial : public Stream
volatile uint8_t * const _udr;
// Has any byte been written to the UART since begin()
bool _written;
#ifdef SERIAL9
volatile bool use9bit;
#endif // SERIAL9

volatile rx_buffer_index_t _rx_buffer_head;
volatile rx_buffer_index_t _rx_buffer_tail;
Expand All @@ -110,27 +130,35 @@ class HardwareSerial : public Stream
// Don't put any members after these buffers, since only the first
// 32 bytes of this struct can be accessed quickly using the ldd
// instruction.
unsigned char _rx_buffer[SERIAL_RX_BUFFER_SIZE];
unsigned char _tx_buffer[SERIAL_TX_BUFFER_SIZE];
serial_data_t _rx_buffer[SERIAL_RX_BUFFER_SIZE];
serial_data_t _tx_buffer[SERIAL_TX_BUFFER_SIZE];

public:
inline HardwareSerial(
volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
volatile uint8_t *ucsrc, volatile uint8_t *udr);
void begin(unsigned long baud) { begin(baud, SERIAL_8N1); }
void begin(unsigned long, uint8_t);
void begin(unsigned long, uint16_t);
void end();
virtual int available(void);
virtual int peek(void);
virtual int read(void);
virtual int availableForWrite(void);
virtual void flush(void);
virtual size_t write(uint8_t);
inline size_t write(unsigned long n) { return write((uint8_t)n); }
inline size_t write(long n) { return write((uint8_t)n); }
inline size_t write(unsigned int n) { return write((uint8_t)n); }
inline size_t write(int n) { return write((uint8_t)n); }

#ifdef SERIAL9
size_t write9(unsigned int);
inline size_t write9(long n) { return write9((unsigned int)n); }
inline size_t write9(int n) { return write9((unsigned int)n); }
inline size_t write(uint8_t n) { return write9((unsigned int)n); }
#else // !defined(SERIAL9)
virtual size_t write(uint8_t);
#endif // SERIAL9
using Print::write; // pull in write(str) and write(buf, size) from Print
operator bool() { return true; }

Expand Down
13 changes: 12 additions & 1 deletion hardware/arduino/avr/cores/arduino/HardwareSerial_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ HardwareSerial::HardwareSerial(
_udr(udr),
_rx_buffer_head(0), _rx_buffer_tail(0),
_tx_buffer_head(0), _tx_buffer_tail(0)
#ifdef SERIAL9
,use9bit(false)
#endif // SERIAL9
{
}

Expand All @@ -103,7 +106,15 @@ void HardwareSerial::_rx_complete_irq(void)
if (bit_is_clear(*_ucsra, UPE0)) {
// No Parity error, read byte and store it in the buffer if there is
// room
unsigned char c = *_udr;
serial_data_t c = 0;
#ifdef SERIAL9
if (use9bit) {
if (bit_is_set(*_ucsrb, RXB80)) {
c = 0x100;
}
}
#endif // SERIAL9
c |= *_udr;
rx_buffer_index_t i = (unsigned int)(_rx_buffer_head + 1) % SERIAL_RX_BUFFER_SIZE;

// if we should be storing the received character into the location
Expand Down