Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 16 of 16

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

  1. #1
    Junior Member
    Join Date
    Sep 2013
    Posts
    3

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

    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.

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,083
    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 by PaulStoffregen; 09-09-2013 at 09:32 AM.

  3. #3
    Junior Member
    Join Date
    Sep 2013
    Posts
    3
    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

  4. #4
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,083
    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.

  5. #5
    Junior Member
    Join Date
    Sep 2013
    Posts
    3
    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_ */

  6. #6
    Senior Member
    Join Date
    Oct 2014
    Posts
    167
    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

  7. #7
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,083
    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!

  8. #8
    Senior Member
    Join Date
    Oct 2014
    Posts
    167
    Thank you, I saw that after the post. I will get a few on order and try them out.

  9. #9
    Senior Member
    Join Date
    Oct 2014
    Posts
    167
    Ordered from another source as overnight. 3 are on the way..

    I will have fun..

  10. #10
    Junior Member
    Join Date
    Apr 2015
    Posts
    2
    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.

  11. #11
    Junior Member
    Join Date
    Apr 2015
    Posts
    2
    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!!!

  12. #12
    Junior Member
    Join Date
    Apr 2015
    Posts
    1
    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 by matassis; 04-29-2015 at 02:15 PM.

  13. #13
    Junior Member
    Join Date
    Jan 2016
    Posts
    2
    I was not successfull in applying the patch above to a current version of AltSoftSerial.
    Has someone managed it or is it downloadable somewhere?

  14. #14
    Junior Member
    Join Date
    Jan 2016
    Posts
    2
    I was not successfull in applying the patch above to a current version of AltSoftSerial.
    Has someone managed it or is it downloadable somewhere?

  15. #15

    AltSoftSerial Parity

    Quote Originally Posted by Idealix View Post
    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

  16. #16
    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?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •