Need to modify Software Serial library - Please Help

Hi,

I am using software serial for one of my serial port. However as part of the serial communication I also get a “serial break” which sets the Rx line LOW for 13 to 18 bits at a time.

This cannot be detected using the software serial library. I have had a look at the library itself to try and create a function within it to detect the event but the coding level is beyond me.

All that I want is function that would set a variable (let’s call it BRK_DETECT) whenever a serial break detected and reset when normal serial data is received.

If anyone could help me with this problem it would be much appreciated! :slight_smile:

SoftwareSerial.h (3.93 KB)

SoftwareSerial.cpp (13.1 KB)

You don't need to edit the library for that. Because it's all software you can just do as the library, check the pin. Just checking the pin doesn't interfere with software serial.

You can even use the external interrupt or pin change interrupt to do the detecting instead of polling.

septillion:
You don't need to edit the library for that. Because it's all software you can just do as the library, check the pin. Just checking the pin doesn't interfere with software serial.

You can even use the external interrupt or pin change interrupt to do the detecting instead of polling.

I can see where you are coming from. Initially I thought it would be more complex but I guess you could connect the Rx pin with a jumper to (say) pin 2 (the INT0 pin) and use an interrupt to detect changes. Whenever the state changes you could record the value of micros() and check the new state. If the new state is HIGH you need to check the interval micros() - savedMicros() to see if it was LOW long enough to be considered to have been a BREAK. If it was you would record that fact in a variable.

...R

Not even a jumper needed. Softserial and the interrupt can just use the same pin :slight_smile:

septillion:
Not even a jumper needed. Softserial and the interrupt can just use the same pin :slight_smile:

Of course. I was thinking of HardwareSerial

...R

hi,

thank you for your suggestions.

I have altered my code according to test the idea but it seems that it does not run fast enough. :frowning:

If I set BREAK_DURATION to 13 the serial breaks are never detected! I had to reduce the value to 5 to set for the code to start detecting a break. Any ideas why?

#include "TimerOne.h"
#include "SoftwareSerial.h"

SoftwareSerial mySerial(2, 4); // RX, TX

#define BREAK_DURATION 5	// Number of bits in the break
#define BAUDRATE 9600UL

volatile unsigned long baud1;
volatile uint8_t brkcnt=0,brk_flg=0,buffer_tail;

//rxtx variable used to set timer into RX or TX mode

void intr_pin2(){
	TCCR1B &= ~((1<<CS10) | (1<<CS11) | (1<<CS12)); // Stop Timer
	
	if(digitalRead(2)==LOW){
		TCNT1 = Timer1.tcnt1_HL;		//reset TCNT1
		brk_flg=0;
    buffer_tail=mySerial._receive_buffer_tail;
	}
	else if(brkcnt>=BREAK_DURATION){
		brk_flg=1;
    buffer_tail= _SS_MAX_RX_BUFF;
	}
 else{
    buffer_tail= _SS_MAX_RX_BUFF;
 }
	brkcnt=0;
	TCCR1B |= Timer1.clockSelectBits; 						//Start Timer	
}

void timer1_intr(){
	++brkcnt;
	
	if(brkcnt > 2*BREAK_DURATION){
		brk_flg=2; //serial brk/ COMM err
		TCCR1B &= ~((1<<CS10) | (1<<CS11) | (1<<CS12)); // Stop Timer
	}
}

void setup() {
  Serial.begin(250000);
  baud1=1000000/BAUDRATE;
  mySerial.begin(BAUDRATE);
  Timer1.EnableTimerInterrupt(timer1_intr,baud1);
  Timer1.StopTimer();
  attachInterrupt(digitalPinToInterrupt(2),intr_pin2,CHANGE);

  Serial.println("READY");
}

void loop() {
  if(mySerial.available() && mySerial._receive_buffer_head!=buffer_tail){
	Serial.print(String(mySerial.read(),HEX));
	Serial.print(", ");
	Serial.println(brk_flg);
  }
}

With that mess, no idea.. Your code is all over the place!

And why not use micros() but mess with a timer?

septillion:
Not even a jumper needed. Softserial and the interrupt can just use the same pin :slight_smile:

SoftwareSerial already uses an interrupt to receive. I'm curious how you see this work?

But I guess that's a pin change interrupt? Then you still have the external interrupt if you connect it to one of those :slight_smile:

And the unclearness is part of why I don't like software serial....

Ah, you’re right

#if defined(PCINT0_vect)
ISR(PCINT0_vect)
{
  SoftwareSerial::handle_interrupt();
}
#endif

#if defined(PCINT1_vect)
ISR(PCINT1_vect, ISR_ALIASOF(PCINT0_vect));
#endif

#if defined(PCINT2_vect)
ISR(PCINT2_vect, ISR_ALIASOF(PCINT0_vect));
#endif

#if defined(PCINT3_vect)
ISR(PCINT3_vect, ISR_ALIASOF(PCINT0_vect));
#endif

sterretje:
SoftwareSerial already uses an interrupt to receive. I'm curious how you see this work?

So ... back to my suggestion for a jumper to one of the external interrupts?

...R

OP is using pin 2. So I think it should be possible to have an isr for INT0.

As a break condition is basically nothing more than a very long start bit, I wonder if it can't be detected using a digitalRead of the software RX pin in e.g. loop().

sterretje:
As a break condition is basically nothing more than a very long start bit, I wonder if it can't be detected using a digitalRead of the software RX pin in e.g. loop().

The timing would be critical to make sure you did not miss a single HIGH during the period

...R