AltSoftSerial & parity, e.g. begin(9600, SERIAL_8E1)

tim

New member
I'm using an external serial device with 9600 baud and even parity. Using Arduino's HardwareSerial I was able to call Serial.begin(9600, SERIAL_8E1). But I need to run this device on AltSoftwareSerial. I already changed (New)SoftwareSerial to receive the parity bit but AltSoftSerial's code is much more advanced. Actually: fortunately it is more advanced :)

I plan on adding Parity support in three small steps:
  1. receive the parity bit without evaluating it
  2. calculate parity on received byte and compare it
  3. transfer with parity

When I will have managed to implement step 3 I also should have obtained enough knowledge about AltSoftSerial to implement different stop bit lengths as well as different data bit lengths. I'm new to using hardware timers in more than the most basic ways and right now I'm researching on how the comparator works, Google "ICR1 328" yields a lot of results. I guess I have to read the parity bit in the "ISR(CAPTURE_INTERRUPT)" function:
Code:
			//PORTD |= 1;
			rx_byte = (rx_byte >> 1) | rx_bit;
			target += ticks_per_bit;
			//PORTD &= ~1;
			state++;
			if (state >= 9) {
				DISABLE_INT_COMPARE_B();
				head = rx_buffer_head + 1;
				if (head >= RX_BUFFER_SIZE) head = 0;
				if (head != rx_buffer_tail) {

Did you work in AltSoftSerial, are my assumptions corrent? I just need some encouragement that I'm on the right path.
 
Yes, I wrote AltSoftSerial.

As far as I know, nobody has ever successfully modified AltSoftSerial's format, or managed to hack on the code in any meaningful way. Hopefully you'll be the first. ;)

If you have an oscilloscope, those commented out lines inside ISR(CAPTURE_INTERRUPT) can help you to "see" when the code is executing, relative to the incoming waveform. There's 2 useful pairs commented out. If you have a 4 channel scope, you could set each to different pins. But even a cheap 2 channel scope using 1 channel for the incoming serial waveform and the other channel for only one pair at a time will really help. As you work on the code, you can place those lines within your parity capture and easily see on the scope screen if you've got it at the correct place.

If you don't have a scope, there are a number of cheap microcontroller-based logic analyzers and scope projects, some can even run on Arduino hardware (of course, I hope you're using a Teensy....) They have limited performance, but if you set the baud rate to something slow like 1200, those tools should work fine. You might need to add a delayMicroseconds() in the code before driving the pin low so the pulse is wide enough to be seen. You can always test at slow speeds to get the software logic right, then delete or comment that stuff out when you're done.

The reception uses a simple state machine, where "state" is the index of the bit number. Bit 0 is the start bit, 1 to 9 are the data bits, and 10 is the stop bit. So look for this part:

Code:
                while (1) {
                        offset = capture - target;
                        if (offset < 0) break;
                        //PORTD |= 1;
                        rx_byte = (rx_byte >> 1) | rx_bit;  ---------- obviously you want to NOT do this for state #9.
                        target += ticks_per_bit;
                        //PORTD &= ~1;
                        state++;
                        if (state >= 9) {   ------------------------------- change this to 10, since you're adding 1 more bit state
                                DISABLE_INT_COMPARE_B();

Well, actually, you could increase rx_byte to 16 bits, and the buffer array to 16 bit words. But remember that will capture the start bit as well as the parity bit, so you'll have to sort those things out when the user calls the read() function. On AVR there's not a lot a RAM, so maybe you'd prefer to just add if (state < 9) { rx_byte= } else if (state == 9) { do parity processing }.

Hopefully this helps? If you get it working, I hope you'll publish the code somewhere.
 
Last edited:
Paul,

I'm happy to finally deliver a patch that enables the use of AltSoftSerial.begin(baud, config) in the same way Arduino's HardwareSerial does. I was able to verify it using a Leonardo as logic analyzer at 1200 baud and my actual setup at 9600 baud with even parity. I also checked odd parity but I did not yet try all the other combinations (5 data bits, 2 stop bits, ...). Actually getting the logic analyzer running was the hardest part. I only have one Leonardo and a couple of 3V Arduino Minis, all my other devices are Teensy 3.0 and I needed an ATmega328 like board, but that's off topic.

Working with your code was a great adventure! I tried my best to adapt your coding style, please correct me as much as you can. I was aware of hardware timers and even guessed their part in PWM output almost correctly, but the advanced features you make use of did not come to my attention. The RAM usage grows by 6 bytes to store configuration and state data, and the CPU overhead increases by a couple of conditions and additions. I believe my modifications don't cause enough additional overhead to degrade AltSoftSerial's performance at high baud rates.

I will continue my development on this patch and post results as soon as I feel comfortable enough with OLS & my SUMP compatible.

Tim

Code:
diff -ru AltSoftSerialOrig/AltSoftSerial.cpp AltSoftSerial/AltSoftSerial.cpp
--- AltSoftSerialOrig/AltSoftSerial.cpp	2013-09-14 17:50:20.679368900 +0200
+++ AltSoftSerial/AltSoftSerial.cpp	2013-09-14 17:46:02.268588700 +0200
@@ -52,13 +52,17 @@
 static volatile uint8_t tx_buffer_tail;
 #define TX_BUFFER_SIZE 68
 static volatile uint8_t tx_buffer[RX_BUFFER_SIZE];
+static uint8_t tx_parity;
 
+static uint8_t data_bits, stop_bits;
+static uint8_t parity; // 0 for none, 1 for odd, 2 for even
+static uint8_t total_bits, almost_total_bits; // these are sums calculated during .begin() to speed up the loop in ISR(CAPTURE_INTERRUPT)
 
 #ifndef INPUT_PULLUP
 #define INPUT_PULLUP INPUT
 #endif
 
-void AltSoftSerial::init(uint32_t cycles_per_bit)
+void AltSoftSerial::init(uint32_t cycles_per_bit, uint8_t config)
 {
 	if (cycles_per_bit < 7085) {
 		CONFIG_TIMER_NOPRESCALE();
@@ -82,6 +86,7 @@
 	tx_state = 0;
 	tx_buffer_head = 0;
 	tx_buffer_tail = 0;
+	setBitCounts(config);
 	ENABLE_INT_INPUT_CAPTURE();
 }
 
@@ -116,6 +121,8 @@
 		tx_state = 1;
 		tx_byte = b;
 		tx_bit = 0;
+		if (parity)
+			tx_parity = parity_even_bit(b) == (parity==2);
 		ENABLE_INT_COMPARE_A();
 		CONFIG_MATCH_CLEAR();
 		SET_COMPARE_A(GET_TIMER_COUNT() + 16);
@@ -132,7 +139,7 @@
 	state = tx_state;
 	byte = tx_byte;
 	target = GET_COMPARE_A();
-	while (state < 9) {
+	while (state < (data_bits+1)) {
 		target += ticks_per_bit;
 		bit = byte & 1;
 		byte >>= 1;
@@ -151,9 +158,23 @@
 			return;
 		}
 	}
-	if (state == 9) {
-		tx_state = 10;
+
+	if((!parity && state == (data_bits + 1)) || 
+		state == (data_bits + 2)) {
+		tx_state = data_bits + 3;
 		CONFIG_MATCH_SET();
+		SET_COMPARE_A(target + (stop_bits * ticks_per_bit));
+		return;
+	} else if (state == (data_bits + 1)) {
+		tx_state = data_bits + 2;
+		if (tx_parity != tx_bit) {
+			if (tx_parity) {
+				CONFIG_MATCH_SET();
+			} else {
+				CONFIG_MATCH_CLEAR();
+			}
+			tx_bit = tx_parity;
+		}
 		SET_COMPARE_A(target + ticks_per_bit);
 		return;
 	}
@@ -169,6 +190,8 @@
 		tx_buffer_tail = tail;
 		tx_byte = tx_buffer[tail];
 		tx_bit = 0;
+		if (parity)
+			tx_parity = parity_even_bit(tx_byte) == (parity==2);
 		CONFIG_MATCH_CLEAR();
 		SET_COMPARE_A(target + ticks_per_bit);
 		// TODO: how to detect timing_error?
@@ -189,7 +212,7 @@
 #if 1
 ISR(CAPTURE_INTERRUPT)
 {
-	uint8_t state, bit, head;
+	uint8_t state, bit, head, rx_parity;
 	uint16_t capture, target;
 	int16_t offset;
 
@@ -217,22 +240,28 @@
 			offset = capture - target;
 			if (offset < 0) break;
 			//PORTD |= 1;
-			rx_byte = (rx_byte >> 1) | rx_bit;
+			if (state >= 1 && state <= data_bits) // only store data bits
+				rx_byte = (rx_byte >> 1) | rx_bit;
 			target += ticks_per_bit;
 			//PORTD &= ~1;
 			state++;
-			if (state >= 9) {
+			if (state >= total_bits) { // this is 9 for 8N1 or 10 for 8E1
 				DISABLE_INT_COMPARE_B();
-				head = rx_buffer_head + 1;
-				if (head >= RX_BUFFER_SIZE) head = 0;
-				if (head != rx_buffer_tail) {
-					rx_buffer[head] = rx_byte;
-					rx_buffer_head = head;
+				if (!parity || (parity_even_bit(rx_byte) == (parity==2)) == rx_parity) {
+					head = rx_buffer_head + 1;
+					if (head >= RX_BUFFER_SIZE) head = 0;
+					if (head != rx_buffer_tail) {
+						rx_buffer[head] = rx_byte;
+						rx_buffer_head = head;
+					}
 				}
 				CONFIG_CAPTURE_FALLING_EDGE();
 				rx_bit = 0;
 				rx_state = 0;
 				return;
+			} else if (state < almost_total_bits) {
+				// in parity bit
+				rx_parity = rx_bit;
 			}
 		}
 		rx_target = target;
@@ -251,7 +280,7 @@
 	CONFIG_CAPTURE_FALLING_EDGE();
 	state = rx_state;
 	bit = rx_bit ^ 0x80;
-	while (state < 9) {
+	while (state < (data_bits + 1)) {
 		rx_byte = (rx_byte >> 1) | bit;
 		state++;
 	}
@@ -389,5 +418,112 @@
 	rx_buffer_head = rx_buffer_tail;
 }
 
-
-
+void AltSoftSerial::setBitCounts(uint8_t config) {
+	parity = 0;
+	stop_bits = 1;
+	switch (config) {
+		case SERIAL_5N1:
+			data_bits = 5;
+			break;
+		case SERIAL_6N1:
+			data_bits = 6;
+			break;
+		case SERIAL_7N1:
+			data_bits = 7;
+			break;
+		case SERIAL_8N1:
+			data_bits = 8;
+			break;
+		case SERIAL_5N2:
+			data_bits = 5;
+			stop_bits = 2;
+			break;
+		case SERIAL_6N2:
+			data_bits = 6;
+			stop_bits = 2;
+			break;
+		case SERIAL_7N2:
+			data_bits = 7;
+			stop_bits = 2;
+			break;
+		case SERIAL_8N2:
+			data_bits = 8;
+			stop_bits = 2;
+			break;
+		case SERIAL_5O1:
+			parity = 1;
+			data_bits = 5;
+			break;
+		case SERIAL_6O1:
+			parity = 1;
+			data_bits = 6;
+			break;
+		case SERIAL_7O1:
+			parity = 1;
+			data_bits = 7;
+			break;
+		case SERIAL_8O1:
+			parity = 1;
+			data_bits = 8;
+			break;
+		case SERIAL_5O2:
+			parity = 1;
+			data_bits = 5;
+			stop_bits = 2;
+			break;
+		case SERIAL_6O2:
+			parity = 1;
+			data_bits = 6;
+			stop_bits = 2;
+			break;
+		case SERIAL_7O2:
+			parity = 1;
+			data_bits = 7;
+			stop_bits = 2;
+			break;
+		case SERIAL_8O2:
+			parity = 1;
+			data_bits = 8;
+			stop_bits = 2;
+			break;
+		case SERIAL_5E1:
+			parity = 2;
+			data_bits = 5;
+			break;
+		case SERIAL_6E1:
+			parity = 2;
+			data_bits = 6;
+			break;
+		case SERIAL_7E1:
+			parity = 2;
+			data_bits = 7;
+			break;
+		case SERIAL_8E1:
+			parity = 2;
+			data_bits = 8;
+			break;
+		case SERIAL_5E2:
+			parity = 2;
+			data_bits = 5;
+			stop_bits = 2;
+			break;
+		case SERIAL_6E2:
+			parity = 2;
+			data_bits = 6;
+			stop_bits = 2;
+			break;
+		case SERIAL_7E2:
+			parity = 2;
+			data_bits = 7;
+			stop_bits = 2;
+			break;
+		case SERIAL_8E2:
+			parity = 2;
+			data_bits = 8;
+			stop_bits = 2;
+			break;
+	}
+	
+	total_bits = data_bits + (parity?1:0) + stop_bits;
+	almost_total_bits = total_bits - stop_bits;
+}
diff -ru AltSoftSerialOrig/AltSoftSerial.h AltSoftSerial/AltSoftSerial.h
--- AltSoftSerialOrig/AltSoftSerial.h	2013-09-14 17:50:20.680369000 +0200
+++ AltSoftSerial/AltSoftSerial.h	2013-09-10 18:40:55.316404600 +0200
@@ -25,6 +25,7 @@
 #define AltSoftSerial_h
 
 #include <inttypes.h>
+#include <util/parity.h>
 
 #if ARDUINO >= 100
 #include "Arduino.h"
@@ -38,7 +39,7 @@
 public:
 	AltSoftSerial() { }
 	~AltSoftSerial() { end(); }
-	static void begin(uint32_t baud) { init((F_CPU + baud / 2) / baud); }
+	static void begin(uint32_t baud, uint8_t config = SERIAL_8N1) { init((F_CPU + baud / 2) / baud, config); }
 	static void end();
 	int peek();
 	int read();
@@ -62,8 +63,9 @@
 	static void enable_timer0(bool enable) { }
 	static bool timing_error;
 private:
-	static void init(uint32_t cycles_per_bit);
+	static void init(uint32_t cycles_per_bit, uint8_t config);
 	static void writeByte(uint8_t byte);
+	static void setBitCounts(uint8_t config);
 };
 
 #endif
 
This patch seems to be missing util/parity.h.

Any chance you post that file? Or if you recreate the patch, running "diff -ruN" should do the trick. The "N" option tells diff to include the contents of any newly added files. Otherwise, it only shows the changes to existing files.
 
util/parity.h is part of my Arduino 1.0.5 and 1.5.2 toolchain at ./hardware/tools/avr/avr/include/util/parity.h
I know it's AVR specific and won't work on Teensy 3.0, Due and other non-AVR Arduinos, but so is the use of the timers and I thought it's fine. Here's the content:

Code:
/* Copyright (c) 2002, Marek Michalkiewicz
   Copyright (c) 2004,2005,2007 Joerg Wunsch
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

   * Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.

   * Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
     distribution.

   * Neither the name of the copyright holders nor the names of
     contributors may be used to endorse or promote products derived
     from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  POSSIBILITY OF SUCH DAMAGE. */

/* $Id: parity.h,v 1.2 2007/01/23 15:32:48 joerg_wunsch Exp $ */

#ifndef _UTIL_PARITY_H_
#define _UTIL_PARITY_H_

/** \file */
/** \defgroup util_parity <util/parity.h>: Parity bit generation
    \code #include <util/parity.h> \endcode

    This header file contains optimized assembler code to calculate
    the parity bit for a byte.
*/
/** \def parity_even_bit
    \ingroup util_parity
    \returns 1 if \c val has an odd number of bits set. */
#define parity_even_bit(val)				\
(__extension__({					\
	unsigned char __t;				\
	__asm__ (					\
		"mov __tmp_reg__,%0" "\n\t"		\
		"swap %0" "\n\t"			\
		"eor %0,__tmp_reg__" "\n\t"		\
		"mov __tmp_reg__,%0" "\n\t"		\
		"lsr %0" "\n\t"				\
		"lsr %0" "\n\t"				\
		"eor %0,__tmp_reg__" 			\
		: "=r" (__t)				\
		: "0" ((unsigned char)(val))		\
		: "r0"					\
	);						\
	(((__t + 1) >> 1) & 1);				\
 }))

#endif /* _UTIL_PARITY_H_ */
 
Hello Paul,

I was wondering if this AltSoftSerial still active. I to give it a try on a SparkFun Pro Micro. What I need to do or like is to emulate a 2560 as close as possible in a smaller package. I have to talk to a serial port @ 9600 8N2 and one at 57600.
The 9600 8N2 is important that it expects answer backs. And if so, I need to Serial.write(00) as well. THe SoftwareSerial hates that..

I see this is an old subject, but I got here via GitHub

If the patch of tim is useable, I surely would like to try it..

Wayne
 
You should really consider upgrading to Teensy 3.1, which has 3 real hardware serial ports. It's much more capable than the Pro Micro, at about the same price!
 
Greetings,

Im a windows user and have been trying to get the patch posted online to work, but no luck!

I have manually patched the altsoftserial files 4 times with notepad++ and still cant get it to compile in the arduino ide.

Currently Im working on a project that requires such functionality, and is also the very last thing that is holding me up to complete the project. In fact I promised to have the project complete more than a week ago and now my integrity is starting to look bad!

May I be so bold as to ask if someone would not mind, to zip up the modified/patched altsoftserial folder in your libraries folder and email it to me? a working test file would also be appreciated if its there.

Seriously this would save my bacon!

I may be emailed at njs3141 [you know that an AT symbol goes here!] gmail.com

I would really, really appreciate this, and maybe I can be of use to you in return at some point in the future.
 
Thank you Tim.

I was in contact with Tim regarding the issues I was having.
Within an hour he had managed to solve the problem and got back to me with a quick 5 second solution.

There was an omission in the patch file that was submitted, of which I include here:

This applies to alsoftserial.h file

to quote from my new friend:
"
static void begin(uint32_t baud) { init((ALTSS_BASE_FREQ + baud / 2) / baud); }
should actually be
static void begin(uint32_t baud) { init((ALTSS_BASE_FREQ + baud / 2) / baud, SERIAL_8N1); }
"

the complete corrected patch should be as follows:
(Tim just double check this for me and if need be I'll correct and repost)

diff -ru AltSoftSerialOrig/AltSoftSerial.cpp AltSoftSerial/AltSoftSerial.cpp
--- AltSoftSerialOrig/AltSoftSerial.cpp 2013-09-14 17:50:20.679368900 +0200
+++ AltSoftSerial/AltSoftSerial.cpp 2013-09-14 17:46:02.268588700 +0200
@@ -52,13 +52,17 @@
static volatile uint8_t tx_buffer_tail;
#define TX_BUFFER_SIZE 68
static volatile uint8_t tx_buffer[RX_BUFFER_SIZE];
+static uint8_t tx_parity;

+static uint8_t data_bits, stop_bits;
+static uint8_t parity; // 0 for none, 1 for odd, 2 for even
+static uint8_t total_bits, almost_total_bits; // these are sums calculated during .begin() to speed up the loop in ISR(CAPTURE_INTERRUPT)

#ifndef INPUT_PULLUP
#define INPUT_PULLUP INPUT
#endif

-void AltSoftSerial::init(uint32_t cycles_per_bit)
+void AltSoftSerial::init(uint32_t cycles_per_bit, uint8_t config)
{
if (cycles_per_bit < 7085) {
CONFIG_TIMER_NOPRESCALE();
@@ -82,6 +86,7 @@
tx_state = 0;
tx_buffer_head = 0;
tx_buffer_tail = 0;
+ setBitCounts(config);
ENABLE_INT_INPUT_CAPTURE();
}

@@ -116,6 +121,8 @@
tx_state = 1;
tx_byte = b;
tx_bit = 0;
+ if (parity)
+ tx_parity = parity_even_bit(b) == (parity==2);
ENABLE_INT_COMPARE_A();
CONFIG_MATCH_CLEAR();
SET_COMPARE_A(GET_TIMER_COUNT() + 16);
@@ -132,7 +139,7 @@
state = tx_state;
byte = tx_byte;
target = GET_COMPARE_A();
- while (state < 9) {
+ while (state < (data_bits+1)) {
target += ticks_per_bit;
bit = byte & 1;
byte >>= 1;
@@ -151,9 +158,23 @@
return;
}
}
- if (state == 9) {
- tx_state = 10;
+
+ if((!parity && state == (data_bits + 1)) ||
+ state == (data_bits + 2)) {
+ tx_state = data_bits + 3;
CONFIG_MATCH_SET();
+ SET_COMPARE_A(target + (stop_bits * ticks_per_bit));
+ return;
+ } else if (state == (data_bits + 1)) {
+ tx_state = data_bits + 2;
+ if (tx_parity != tx_bit) {
+ if (tx_parity) {
+ CONFIG_MATCH_SET();
+ } else {
+ CONFIG_MATCH_CLEAR();
+ }
+ tx_bit = tx_parity;
+ }
SET_COMPARE_A(target + ticks_per_bit);
return;
}
@@ -169,6 +190,8 @@
tx_buffer_tail = tail;
tx_byte = tx_buffer[tail];
tx_bit = 0;
+ if (parity)
+ tx_parity = parity_even_bit(tx_byte) == (parity==2);
CONFIG_MATCH_CLEAR();
SET_COMPARE_A(target + ticks_per_bit);
// TODO: how to detect timing_error?
@@ -189,7 +212,7 @@
#if 1
ISR(CAPTURE_INTERRUPT)
{
- uint8_t state, bit, head;
+ uint8_t state, bit, head, rx_parity;
uint16_t capture, target;
int16_t offset;

@@ -217,22 +240,28 @@
offset = capture - target;
if (offset < 0) break;
//PORTD |= 1;
- rx_byte = (rx_byte >> 1) | rx_bit;
+ if (state >= 1 && state <= data_bits) // only store data bits
+ rx_byte = (rx_byte >> 1) | rx_bit;
target += ticks_per_bit;
//PORTD &= ~1;
state++;
- if (state >= 9) {
+ if (state >= total_bits) { // this is 9 for 8N1 or 10 for 8E1
DISABLE_INT_COMPARE_B();
- head = rx_buffer_head + 1;
- if (head >= RX_BUFFER_SIZE) head = 0;
- if (head != rx_buffer_tail) {
- rx_buffer[head] = rx_byte;
- rx_buffer_head = head;
+ if (!parity || (parity_even_bit(rx_byte) == (parity==2)) == rx_parity) {
+ head = rx_buffer_head + 1;
+ if (head >= RX_BUFFER_SIZE) head = 0;
+ if (head != rx_buffer_tail) {
+ rx_buffer[head] = rx_byte;
+ rx_buffer_head = head;
+ }
}
CONFIG_CAPTURE_FALLING_EDGE();
rx_bit = 0;
rx_state = 0;
return;
+ } else if (state < almost_total_bits) {
+ // in parity bit
+ rx_parity = rx_bit;
}
}
rx_target = target;
@@ -251,7 +280,7 @@
CONFIG_CAPTURE_FALLING_EDGE();
state = rx_state;
bit = rx_bit ^ 0x80;
- while (state < 9) {
+ while (state < (data_bits + 1)) {
rx_byte = (rx_byte >> 1) | bit;
state++;
}
@@ -389,5 +418,112 @@
rx_buffer_head = rx_buffer_tail;
}

-
-
+void AltSoftSerial::setBitCounts(uint8_t config) {
+ parity = 0;
+ stop_bits = 1;
+ switch (config) {
+ case SERIAL_5N1:
+ data_bits = 5;
+ break;
+ case SERIAL_6N1:
+ data_bits = 6;
+ break;
+ case SERIAL_7N1:
+ data_bits = 7;
+ break;
+ case SERIAL_8N1:
+ data_bits = 8;
+ break;
+ case SERIAL_5N2:
+ data_bits = 5;
+ stop_bits = 2;
+ break;
+ case SERIAL_6N2:
+ data_bits = 6;
+ stop_bits = 2;
+ break;
+ case SERIAL_7N2:
+ data_bits = 7;
+ stop_bits = 2;
+ break;
+ case SERIAL_8N2:
+ data_bits = 8;
+ stop_bits = 2;
+ break;
+ case SERIAL_5O1:
+ parity = 1;
+ data_bits = 5;
+ break;
+ case SERIAL_6O1:
+ parity = 1;
+ data_bits = 6;
+ break;
+ case SERIAL_7O1:
+ parity = 1;
+ data_bits = 7;
+ break;
+ case SERIAL_8O1:
+ parity = 1;
+ data_bits = 8;
+ break;
+ case SERIAL_5O2:
+ parity = 1;
+ data_bits = 5;
+ stop_bits = 2;
+ break;
+ case SERIAL_6O2:
+ parity = 1;
+ data_bits = 6;
+ stop_bits = 2;
+ break;
+ case SERIAL_7O2:
+ parity = 1;
+ data_bits = 7;
+ stop_bits = 2;
+ break;
+ case SERIAL_8O2:
+ parity = 1;
+ data_bits = 8;
+ stop_bits = 2;
+ break;
+ case SERIAL_5E1:
+ parity = 2;
+ data_bits = 5;
+ break;
+ case SERIAL_6E1:
+ parity = 2;
+ data_bits = 6;
+ break;
+ case SERIAL_7E1:
+ parity = 2;
+ data_bits = 7;
+ break;
+ case SERIAL_8E1:
+ parity = 2;
+ data_bits = 8;
+ break;
+ case SERIAL_5E2:
+ parity = 2;
+ data_bits = 5;
+ stop_bits = 2;
+ break;
+ case SERIAL_6E2:
+ parity = 2;
+ data_bits = 6;
+ stop_bits = 2;
+ break;
+ case SERIAL_7E2:
+ parity = 2;
+ data_bits = 7;
+ stop_bits = 2;
+ break;
+ case SERIAL_8E2:
+ parity = 2;
+ data_bits = 8;
+ stop_bits = 2;
+ break;
+ }
+
+ total_bits = data_bits + (parity?1:0) + stop_bits;
+ almost_total_bits = total_bits - stop_bits;
+}
diff -ru AltSoftSerialOrig/AltSoftSerial.h AltSoftSerial/AltSoftSerial.h
--- AltSoftSerialOrig/AltSoftSerial.h 2013-09-14 17:50:20.680369000 +0200
+++ AltSoftSerial/AltSoftSerial.h 2013-09-10 18:40:55.316404600 +0200
@@ -25,6 +25,7 @@
#define AltSoftSerial_h

#include <inttypes.h>
+#include <util/parity.h>

#if ARDUINO >= 100
#include "Arduino.h"
@@ -38,7 +39,7 @@
public:
AltSoftSerial() { }
~AltSoftSerial() { end(); }
- static void begin(uint32_t baud) { init((F_CPU + baud / 2) / baud); }
+ static void begin(uint32_t baud, uint8_t config = SERIAL_8N1) { init((F_CPU + baud / 2) / baud, config); }
+ static void begin(uint32_t baud) { init((ALTSS_BASE_FREQ + baud / 2) / baud, SERIAL_8N1); }
static void end();
int peek();
int read();
@@ -62,8 +63,9 @@
static void enable_timer0(bool enable) { }
static bool timing_error;
private:
- static void init(uint32_t cycles_per_bit);
+ static void init(uint32_t cycles_per_bit, uint8_t config);
static void writeByte(uint8_t byte);
+ static void setBitCounts(uint8_t config);
};

#endif

The original altsoftserial is brilliant, this patch makes it more versatile and AWSOME!!!
 
Hello NJS and Tim.

I was trying to use AltSoft with a diferent config than 8N1 when I found the code you've posted. The adjustment were almost perfect, every test I did worked fine, excepted for the realy one that I need: SERIAL_7E1.

For this configuration 7E1, I receive alleatory data for every single input. And the error, I believe, is related to the 7 data bit, because with the 8E1 everything works fine.

Do you have any hint to discover where is the error? Or, am I doing anything wrong?

Thank you very much
Matheus
 
Last edited:
I was not successfull in applying the patch above to a current version of AltSoftSerial.
Has someone managed it or is it downloadable somewhere?
 
I was not successfull in applying the patch above to a current version of AltSoftSerial.
Has someone managed it or is it downloadable somewhere?
 
AltSoftSerial Parity

I was not successfull in applying the patch above to a current version of AltSoftSerial.
Has someone managed it or is it downloadable somewhere?

I'm in the same boat. The version available through the Arduino IDE does not support the second parameter (eg SERIAL_8E1).
Is it somewhere to be had? Or was it so buggy it was dropped?

Thanks
Graham
 
I would very much like to use parity to at least throw away bad data, which I seem to get very so often otherwise.

Just spotted that (the or a) parity patch has been submitted to github: https://github.com/PaulStoffregen/AltSoftSerial/pull/52
but not yet committed. It seems no-one is assigned to review or merge it, which probably explains why nothing happened since October 2018.

I would like to continue using AltSoftSerial, but is it a dead horse?
 
To update this thread I saw it added to https://github.com/stattin42/AltSoftSerial
I've merged it to my fork https://github.com/neilh10/AltSoftSerial and tested it against a device that uses 19200 8E1 and its worked.
I'm using it on the enviroDIY.org/Mayfly mega1284 with limited serial ports communicating to RS485 transducers over AltSoftSerial
I only wish I could be moving to the beautiful pjrc boards, but gotta live with the h/w & libs that I have. Many thanks to Paul for the initial AltsoftSerial
 
Hi, In marine electronics some companies use RS485 and 8 databits, 1 ´parity` bit and 2 stopbits. 9600 baud.
However the parits bit is used for special control, signal to receivers. Not for parity.
So I need a way to read the parity bit also! (9600, 8E_2) , parity bit avaiable for reading. Or (9600, 9N_2).
Could this be Done ??
Board : Arduino UNO or Adafruit M0 or Adafruit M4 or Adafruit ESP32 or Teensy 3.6 or Teensy 4.0
 
Back
Top