Skip to content
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
37 changes: 26 additions & 11 deletions NeoSWSerial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ static uint8_t rxTail; // buffer pointer output

static uint8_t rxBitMask, txBitMask; // port bit masks
static volatile uint8_t *txPort; // port register
static bool inv; //invert the signal on the line

//#define DEBUG_NEOSWSERIAL
#ifdef DEBUG_NEOSWSERIAL
Expand Down Expand Up @@ -115,8 +116,13 @@ void NeoSWSerial::listen()

txBitMask = digitalPinToBitMask( txPin );
txPort = portOutputRegister( digitalPinToPort( txPin ) );
inv = inverse;
// set idle state: logic 1
if (txPort)
*txPort |= txBitMask; // high = idle
if (inv)
*txPort &= ~txBitMask; // set TX line low
else
*txPort |= txBitMask; // set TX line high
pinMode(txPin, OUTPUT);

if (F_CPU == 8000000L) {
Expand All @@ -132,7 +138,7 @@ void NeoSWSerial::listen()
flush();

// Set up timings based on baud rate

switch (_baudRate) {
case 9600:
txBitWidth = TICKS_PER_BIT_9600 ;
Expand Down Expand Up @@ -212,7 +218,7 @@ void NeoSWSerial::setBaudRate(uint16_t baudRate)
int NeoSWSerial::available()
{
uint8_t avail = ((rxHead - rxTail + RX_BUFFER_SIZE) % RX_BUFFER_SIZE);

if (avail == 0) {
cli();
if (checkRxTime()) {
Expand Down Expand Up @@ -266,6 +272,9 @@ void NeoSWSerial::startChar()
void NeoSWSerial::rxISR( uint8_t rxPort )
{
uint8_t t0 = TCNTX; // time of data transition (plus ISR latency)
if (inv) {
rxPort = ~rxPort;
}
uint8_t d = rxPort & rxBitMask; // read RX data level

if (rxState == WAITING_FOR_START_BIT) {
Expand Down Expand Up @@ -337,6 +346,7 @@ bool NeoSWSerial::checkRxTime()
if (rxState != WAITING_FOR_START_BIT) {

uint8_t d = *rxPort & rxBitMask;
if (inv) d = ~d;

if (d) {
// Ended on a 1, see if it has been too long
Expand Down Expand Up @@ -410,13 +420,13 @@ ISR(PCINT0_vect)

#elif defined(__AVR_ATtiny25__) | \
defined(__AVR_ATtiny45__) | \
defined(__AVR_ATtiny85__)
defined(__AVR_ATtiny85__)

PCINT_ISR(0, PINB);

#elif defined(__AVR_ATtiny24__) | \
defined(__AVR_ATtiny44__) | \
defined(__AVR_ATtiny84__)
defined(__AVR_ATtiny84__)

PCINT_ISR(0, PINA);
PCINT_ISR(1, PINB);
Expand Down Expand Up @@ -471,21 +481,21 @@ size_t NeoSWSerial::write(uint8_t txChar)

uint8_t width; // ticks for one bit
uint8_t txBit = 0; // first bit is start bit
uint8_t b = 0; // start bit is low
bool b = false; // start bit is logic 0
uint8_t PCIbit = bit(digitalPinToPCICRbit(rxPin));

uint8_t prevSREG = SREG;
cli(); // send the character with interrupts disabled

uint8_t t0 = TCNTX; // start time

// TODO: This would benefit from an early break after
// TODO: This would benefit from an early break after
// the last 0 data bit. Then we could wait for the
// remaining 1 data bits and stop bit with interrupts
// remaining 1 data bits and stop bit with interrupts
// re-enabled.

while (txBit++ < 9) { // repeat for start bit + 8 data bits
if (b) // if bit is set
if (b != inv) // if desired state is high
*txPort |= txBitMask; // set TX line high
else
*txPort &= ~txBitMask; // else set TX line low
Expand All @@ -495,7 +505,7 @@ size_t NeoSWSerial::write(uint8_t txChar)
(width == TICKS_PER_BIT_9600/4) &&
(txBit & 0x01)) {
// The width is 6.5 ticks, so add a tick every other bit
width++;
width++;
}

// Hold the line for the bit duration
Expand All @@ -516,7 +526,12 @@ size_t NeoSWSerial::write(uint8_t txChar)
// Q: would a signed >> pull in a 1?
}

*txPort |= txBitMask; // stop bit is high
// stop bit is logic 1
if (inv)
*txPort &= ~txBitMask; // else set TX line low
else
*txPort |= txBitMask; // set TX line high

SREG = prevSREG; // interrupts on for stop bit
while ((uint8_t)(TCNTX - t0) < width) {
if (checkRxTime())
Expand Down
18 changes: 11 additions & 7 deletions NeoSWSerial.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
//
// Constructor: NeoSWSerial ss(RX_PIN, TX_PIN);
//
// Any of the pins supported by SoftwareSerial may be used. Pins (0-19)
// on the Uno may be used. Other boards can use any of the pins
// Any of the pins supported by SoftwareSerial may be used. Pins (0-19)
// on the Uno may be used. Other boards can use any of the pins
// allowed by digitalPinToPCMSK in pins_arduino.h
//
// This code uses a pin change interrupt on the selected RX pin.
Expand All @@ -25,9 +25,9 @@
// Supported baud rates are 9600 (default), 19200 and 38400.
// The baud rate is selectable at run time.
//
// The size of the RX buffer may be changed by editing the
// accompanying .cpp file. For optimal performance of the interrupt
// service routines, the buffer size should be chosen to be a
// The size of the RX buffer may be changed by editing the
// accompanying .cpp file. For optimal performance of the interrupt
// service routines, the buffer size should be chosen to be a
// power of 2 (i.e., 2, 4, 8, 16, 32, 64,...).
//
// Nov/Dec 2014 jboyton - Created
Expand All @@ -38,18 +38,20 @@
// Nov 2015 SlashDev - Add support for other boards,
// add end() and attach/detachInterrupt
// Jun 2016 SlashDev - Add support for all character values
//
// Jan 2017 Matthew Marks - Added support for inverse logic


class NeoSWSerial : public Stream
{
NeoSWSerial( const NeoSWSerial & ); // Not allowed
NeoSWSerial & operator =( const NeoSWSerial & ); // Not allowed

public:
NeoSWSerial(uint8_t receivePin, uint8_t transmitPin)
NeoSWSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false)
{
rxPin = receivePin;
txPin = transmitPin;
inverse = inverse_logic;
_isr = (isr_t) NULL;
}

Expand All @@ -70,6 +72,7 @@ class NeoSWSerial : public Stream

private:
uint8_t rxPin, txPin;
bool inverse;
volatile uint8_t *rxPort;

uint16_t _baudRate;
Expand All @@ -84,5 +87,6 @@ class NeoSWSerial : public Stream
public:
// visible only so the ISRs can call it...
static void rxISR( uint8_t port_input_register );
static bool invert; // invert levels on line
};
#endif