Arduino Forum

Using Arduino => Programming Questions => Topic started by: Robin2 on Jun 27, 2014, 01:28 pm

Title: Yet another Software Serial
Post by: Robin2 on Jun 27, 2014, 01:28 pm
In a recent Thread (http://forum.arduino.cc/index.php?topic=246805.17) the usual complaints were made about the SoftwareSerial library not functioning alongside the Servo library. In Reply #17 @oric_dan suggested a limited version of SoftwareSerial for the Uno that would work in parallel with other libraries.

That prompted the realization that I had a few projects that together probably contained all of the concepts necessary to achieve that.

The attached code sss.ino is the result. It uses Pins 3 (INT1) and 4 and Timer2A and seems to work quite happily with the Servo library. It is only intended for use on an Uno (or standalone Atmega 328).

The file DemoSimpleSoftSerial.ino illustrates the use of sss.ino. And the file DemoPartner.ino is a program that I have run on a Mega (because it has multiple hardware Serial Ports) to receive data from and send data to the Uno.

I concluded that there is little advantage in converting the code into a Class or into a proper Library. Because of its simplicity there cannot be multiple instances of it - in other words you can only use it to add one Software Serial connection to an Uno. Because of the way the Arduino manages projects the variables in sss.ino are not accessible to the code in the main .ino file but the various functions are. I have prefixed the names of all the functions and variables with sss to reduce the possibility of clashing with names in other parts of a project.

To use the code you just need to add a copy of the file sss.ino into the Arduino project. Using the demo program attached you would put both of the file DemoSimpleSoftSerial.ino and sss.ino into a directory called DemoSimpleSoftSerial.

Interestingly the code works exactly as I expected it would when the idea first occurred to me but I could fill a whole book with the stupid mistakes that wasted time while bringing the various pieces together.

...R
Title: Re: Yet another Software Serial
Post by: abeltomillo on Sep 03, 2014, 07:19 pm
Hello!

great job! I was reading the code along, and tried to make it to work with an ATMEGA 328, but in Freaduino Pro Mini 16MHz 5V. Only the RX pin seems to work, as I can't send any data successfully with that sss.ino and my project...

I am using a compatible arduino pro mini board, from elecfreaks, and need to control a servo at same time I need to communicate with a GSM board. And I need that 5V version, as it is for a robot... so can't use big batteries and so on.

Can you explain me a little bit more about that code? I need a software serial using timer2 and not fighting with Servo Library... on pro mini...

Can this program be ported to that board? Is there another library?

Thanks a lot! I'll keep trying to make it to work.

cheers.
Title: Re: Yet another Software Serial
Post by: Robin2 on Sep 04, 2014, 11:12 am
You also asked this question somewhere else (http://forum.arduino.cc/index.php?topic=261932) and I replied to it there.

DON'T DOUBLE POST - it just wastes everyone's time.

I don't have a Freaduino ProMini so I can't try the code on one.

Have you got my code working on an Uno?

What sort of differences might there be with the Freaduino - the clock speed springs to mind?

...R
Title: Re: Yet another Software Serial
Post by: abeltomillo on Sep 05, 2014, 08:57 pm
yeah, sorry. I double posted because this thread is speaking about sss.ino. And the other post is speaking about a generalistic sollution ;).

I've asked you before. Thanks a lot, and sorry for asking you double time :P
Title: I want to implement "my own SoftwareSerial"
Post by: abeltomillo on Sep 07, 2014, 01:00 pm
Hello,

I have this code:

Code: [Select]
#define rb(NBIT, SFR) ((SFR & ( 1 << NBIT )) >> NBIT)


volatile char rx_buf[200], rx_byte;
volatile int rx_buf_len = 0;
volatile unsigned char tcnt2;

void setup() {
  Serial.begin(57600);
  pinMode(3, INPUT);
  attachInterrupt(1, gsm_rx_int1, FALLING);
}

void (*gsm_rx_timer2)() = NULL;

void gsm_rx_int1 () {
  detachInterrupt(1);
  rx_byte = 0;
  gsm_rx_timer2 = gsm_rx_bit0;
  TIMSK2 &= ~(1<<TOIE2);
  TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
  TCCR2B &= ~(1<<WGM22);
  ASSR &= ~(1<<AS2);
  TIMSK2 &= ~(1<<OCIE2A);
  TCCR2B |= (1<<CS21);
  TCCR2B &= ~((1<<CS22) | (1<<CS20));
  float prescaler = 8.0;
  tcnt2 = 256 - (int)((float)F_CPU * 0.0001045 / prescaler);
  TCNT2 = tcnt2;
  TIMSK2 |= (1<<TOIE2);
}

ISR(TIMER2_OVF_vect){
  TCNT2 = tcnt2;
  gsm_rx_timer2();
}

void gsm_rx_bit0 () {
  rx_byte = rx_byte | (rb(3, PIND) << 0);
  gsm_rx_timer2 = gsm_rx_bit1;
}
void gsm_rx_bit1 () {
  rx_byte = rx_byte | (rb(3, PIND) << 1);
  gsm_rx_timer2 = gsm_rx_bit2;
}
void gsm_rx_bit2 () {
  rx_byte = rx_byte | (rb(3, PIND) << 2);
  gsm_rx_timer2 = gsm_rx_bit3;
}
void gsm_rx_bit3 () {
  rx_byte = rx_byte | (rb(3, PIND) << 3);
  gsm_rx_timer2 = gsm_rx_bit4;
}
void gsm_rx_bit4 () {
  rx_byte = rx_byte | (rb(3, PIND) << 4);
  gsm_rx_timer2 = gsm_rx_bit5;
}
void gsm_rx_bit5 () {
  rx_byte = rx_byte | (rb(3, PIND) << 5);
  gsm_rx_timer2 = gsm_rx_bit6;
}
void gsm_rx_bit6 () {
  rx_byte = rx_byte | (rb(3, PIND) << 6);
  gsm_rx_timer2 = gsm_rx_bit7;
}
void gsm_rx_bit7 () {
  rx_byte = rx_byte | (rb(3, PIND) << 7);
  gsm_rx_timer2 = gsm_rx_end;
}

void gsm_rx_end () {
  TIMSK2 &= ~(1<<TOIE2);
  rx_buf [ rx_buf_len ++ ] = rx_byte;
  attachInterrupt(1, gsm_rx_int1, FALLING);
}

void loop () {
  delay (1000);
  Serial.print("\r\n");
  for (int i = 0; i < rx_buf_len; i++) {
    Serial.print(rx_buf[i]);
  }
  Serial.print("\r\n");
}


I've copied the TIMER2 code from an URL that I have closed trying to copy the URL... lol.

I'm receiving strange chars in the arduino console, but I want to see human readable ones, as the gsm module sends to me, but i am not able to read well.

I implemented a delayed serial rx disabling interrupts, and everything read ok. but I need to do with interrupts, and the reason because I am doing "my own softwareserial" it's because I'm searching the way of making to work together my servo and my gsm module in my own robot, which uses an ATMEGA328 at 5V. So there's no extra hardware serial for working with gsm module. And the softwareserial with the servo library doesn't work fine at all... i had a lot of buzz in the servo while rx from gsm...

the true, is i could rx data from gsm and handle the servo at same time, but the reading functions were using delayMicroseconds(), and used to detect bit falling in a continous reading, so some data wen't to trash... now I want to try with interrupts, but I can detect bit falling and use delays again... but I don't really like, because I must disable interrupts, and then the servo has some spikes, and if I don't disable them, then the servo works fine, but reading sometimes is bad, so the sollution is the FALLING int1, but as I said, I also want to take profit of these delaytimes to handle the servo, so better performance if I find the sollution.

Hope that project helps others, and to get helped.

Thanks,

cheers.
Title: Re: I want to implement "my own SoftwareSerial"
Post by: holmes4 on Sep 07, 2014, 02:16 pm
Code: [Select]
void gsm_rx_int1 () {
 cli();
 detachInterrupt(1);
 TCCR2A = 0;// set entire TCCR2A register to 0
.
.
.
.
 rx_byte = 0;
 gsm_rx_timer2 = gsm_rx_bit0;
 sei();
}
There is no need for the cli(), as interrupts are automatically of at this point any way.

Why are you detaching interrupt 1? leave it alone!

Never ever use sei() within an interrupt handler. It results in random crashes these are rare but will happen.

And the rest of your code makes on sense at all. Why are you only looking for a falling edge to start things off.

All your gsm_rx_bitX functions are called from with in an ISR so whats with the cli/sei - pust not needed and th sei may crash your program!.

Mark


Mark
Title: Re: I want to implement "my own SoftwareSerial"
Post by: Robin2 on Sep 07, 2014, 04:44 pm
@abeltomillo - you seem to be spreading stuff all over the place like a shotgun. make it easier for everyone by sticking to a single Thread.

I already gave you a link to my software serial implementation in this Thread (http://forum.arduino.cc/index.php?topic=261932.msg1848753#msg1848753).

It did not seem to work perfectly for you but until your most recent post in that other Thread you had not given any feedback which would give me a chance to fix it if something is wrong.

Please the moderator to merge this Thread with the earlier one.

...R
Title: Re: I want to implement "my own SoftwareSerial"
Post by: abeltomillo on Sep 07, 2014, 07:48 pm
Hi,

thanks for the answers.

I need to disable the INT1 and re-enable it after reading the whole byte. because if not, the rx process will be reset on every bit falling from same pin... about cli and sei I didn't know it.

about you Robin2, yes, you're right, the best is to merge the thread, sorry. I'll keep in mind for the next time, ok?
about your code, I want to understand it, but I don't really understand every it all. Things like "2.5 times lenght of...", "1.5 times", and dividing by 2, the baud rate timings...

other thing is, I have in mind what I want to do, but I don't want to waste time in modifying your program as I haven't clear at all everything. If you don't mind, I'll try to do a library called: SoftSerialServo, which will be the first library which supports handling an emulated serial comm. by soft. and handle a servo (for sure 2 later) which the people could modify it.

obviously, I am basing much ideas on your code, but really, I don't want to modify it because I want to do it from zero, and merge the 2 concepts the best as possible... because I have no clear 100% how AVRs works.

Hope you don't be angry with me, because you helped me a lot without knowing it, but that's the true.

thanks for all,

cheers.

p.d. Im doing some more tests and reporting back them, ok? ;)
Title: Re: I want to implement "my own SoftwareSerial"
Post by: abeltomillo on Sep 07, 2014, 08:05 pm
I'm going to edit the code, by the new one, which also doesn't work, but TIMER2 is configured as MsTimer2 shows, but instead for 1mS for 104.5uS, and it still doesn't show readable chars... :(

p.d. it is modified now. :).
Title: Re: I want to implement "my own SoftwareSerial"
Post by: Robin2 on Sep 07, 2014, 09:22 pm

I don't really understand every it all. Things like "2.5 times lenght of...", "1.5 times", and dividing by 2, the baud rate timings...


It seems to me a clear understanding of baud rate timings is essential if one wants to write a software serial program. And I suspect that if you understand how serial transmission works those comments in my code will make sense.

If you want to ask questions about serial transmission I will try to answer them.

I'm not clear - have you asked the moderator to merge the Threads, or should I do so?

...R
Title: Re: I want to implement "my own SoftwareSerial"
Post by: abeltomillo on Sep 07, 2014, 10:31 pm
I don't know how to contact moderator. If you explain me I can do. If you want you can do by yourself. ;)

Ok, I think I know a bit about serial transmissions, look my minimal knowledges I guessed by myself and made them in a "working program" for atmega328 (correct me if wrong, please):

1. When a byte is going to be transmitted, the value of a pin goes from HIGH to LOW.
2. On every bit transmission, there's a timing/delay of 1000000/baud_rate.
3. What does it happen when a byte is transfered? How many time is there between another byte transmission, is it maybe 100000/baudrate?

So, what did I do in my first implementation?

for transferring a byte at 9600bps,

1. set TX pin from HIGH to LOW.
2. wait 105 microseconds (100000/9600).
3. send first bit (bit 0)
4. delayMicroseconds(105).
5. send second bit (bit 1).
6. ... repeat step 4 and 5 until transfer the 7th bit.
7. delay 105 microseconds before transfer another byte.


So, for RX is the same as TX but at inverse. And the best way of detecting a transmission start, is to setup the INT on FALLING edge for a pin. In my case pin 3.

But, what is wrong in my code? If using timer, knowing accuracy is better than delay routine, I can RX a byte every 1.5 * 104.1 uS, going to half, isn't it?

Thanks Robin2,

cheers.
Title: Re: I want to implement "my own SoftwareSerial"
Post by: abeltomillo on Sep 07, 2014, 10:45 pm
I've been reading you sss.ino code again, I start to understand a lot more than before, I am happy to tell you you are so genius ;).

I think I am going to use your method for TIMER2 and INT1, let me a bit of more time, this is going to work soon ;)

thanks for all robin, you really a good person.

cheers,

abel.
Title: Re: I want to implement "my own SoftwareSerial"
Post by: abeltomillo on Sep 07, 2014, 11:32 pm
Ok Robin2, I decided to fix your code, if this time doesn't work. Because I got the same conclusion than you, use timer2 for serial and timer1 for servo (by servo library), i think this is going to work fine. So Im on it.

thanks for that great code!

cheers,

abel.
Title: Re: I want to implement "my own SoftwareSerial"
Post by: nickgammon on Sep 07, 2014, 11:36 pm

I don't know how to contact moderator. If you explain me I can do. If you want you can do by yourself. ;)


<sigh>

Just stick to this thread from now on please.
Title: Re: I want to implement "my own SoftwareSerial"
Post by: abeltomillo on Sep 07, 2014, 11:39 pm
Ok, thanks.

So, sorry because I am not english, i am spanish, and I didn't understand well. Do you mean that you are stick on the thread from now, or that we should use this thread instead of the "Yet another software Serial" ? hehe...

thanks!

cheers,

abel.
Title: Re: I want to implement "my own SoftwareSerial"
Post by: abeltomillo on Sep 07, 2014, 11:50 pm
Robin!! Finally! It does work! Don't ask me how, but it does, without any modification. I knew I was doing something bad, for sure it was the reading, because I didn't know the protocol well.

I am using Freaduino Pro Mini 5V, which has an ATMEGA328P and it is Arduino Pro Mini 5V LIKE.


Fine!!! Thanks a lot, now I am going to try the servo with it's library ;)

yupiiiyeiiii!!


cheers,

thanks.
Title: Re: I want to implement "my own SoftwareSerial"
Post by: nickgammon on Sep 07, 2014, 11:52 pm
How many threads did you start? (don't answer that).

I merged those two.
Title: Re: I want to implement "my own SoftwareSerial"
Post by: abeltomillo on Sep 08, 2014, 12:03 am
Thanks Nick, now it looks very good. :D
Title: Re: I want to implement "my own SoftwareSerial"
Post by: Robin2 on Sep 08, 2014, 09:11 am

How many threads did you start? (don't answer that).

I merged those two.


It seems that you merged (some or all of) @abeltomillo's Threads into one of mine and managed to change my Title to his Title.
Imagine my surprise to discover I was the owner of a Thread I didn't know I started.

The merge probably doesn't matter because he might have started his questions in my Thread anyway.

I have changed the Thread title back to the original.

@abeltomillo - NO thanks for all the confusion.
                              YES thanks for confirming my code works.

The extra "half" bit width is to ensure the samples are taken in the middle of a bit rather than at the edge. It also provides some slack to cope with slight timing errors. The interrupt that detects the start-bit resets the timing measurements for every byte so there are no long-run cumulative errors.

...R
Title: Re: Yet another Software Serial
Post by: nickgammon on Sep 08, 2014, 10:29 am
@Robin2 - sorry.
Title: Re: Yet another Software Serial
Post by: Robin2 on Sep 08, 2014, 12:08 pm

@Robin2 - sorry.


I think, where you come from, my response would be  "no worries".

...R
Title: Re: Yet another Software Serial
Post by: nickgammon on Sep 08, 2014, 01:37 pm
That's right. ;)
Title: Re: Yet another Software Serial
Post by: abeltomillo on Sep 11, 2014, 12:45 am
Oh, sorry. Thanks for all.
Title: Re: Yet another Software Serial
Post by: abeltomillo on Sep 11, 2014, 12:51 am
but I can't just be quiet, I must say:

I won't comment about your code, just to say it's horrible that people thinks that helping others mean radical criticism and comments that doesn't help neither to make you feel good because someone answered you.

really, don't understand how people can be so rude, just because they don't get paid.

And yes, your code is crappy coded, that's the way I didn't understood the first line. How can a software be called: sss?

Seriously, improve your person before to tell others how they should be, you make me went crazy because your comments were out of topic, please be less, and more. If you don't understand, then you have a problem.

be safe, be good.

abel.
Title: Re: Yet another Software Serial
Post by: Robin2 on Sep 11, 2014, 03:00 pm

but I can't just be quiet, I must say:

I won't comment about your code, just to say it's horrible that people thinks that helping others mean radical criticism and comments that doesn't help neither to make you feel good because someone answered you.

really, don't understand how people can be so rude, just because they don't get paid.

And yes, your code is crappy coded, that's the way I didn't understood the first line. How can a software be called: sss?

Seriously, improve your person before to tell others how they should be, you make me went crazy because your comments were out of topic, please be less, and more. If you don't understand, then you have a problem.

be safe, be good.

abel.


I really don't understand what this is all about or who it is aimed at.

I assume the bit I have highlighted in bold is aimed at me.

I'm real broken up that you didn't understand the first line which is
Code: [Select]
const int sssBaudRate = 9600;

I called it sss because at the time I was naming it Simple Software Serial and I was too lazy to type all of that - but feel free to rename your copy to anything that pleases you. The name is not a critical part of the functionality.

...R
Title: Re: Yet another Software Serial
Post by: abeltomillo on Sep 12, 2014, 02:15 am
Robin2, the following words are not aimed to you, i'm speaking in general, and a bit referencing you because you were rude, and I get very disgusted. So, just to say I'm pissed of people that thinks helping mean criticism agains the people who doesn't know so much as the helpers do. And they use the forums, which are open, to hit psichologically pepople who are very sensible, and they don't blame against them just to keep the peace. I was very sad to read your answers against my confussion. YES! I was confussed, as it was very hard to understand the whole code, but I am strong, and I got it! but, please, don't feel angry or disgusted because of my words now, and before. Just I understand you, but I was very angry with that kind of people. Just sorry, and thanks for helping me in that company.

Now, I just want to tell you that I've been developing a new simple software serial, but this time for pure C, but it doesn't use the TIMER2 only. It allows tx and rx at same time. But as I don't use the Arduino's core, I can use TIMER0 for rx, and TIMER2 for tx. The  I will use TIMER1 for pulse and refresh the servo. I hope that version works with no buzzing.

as your style is so concrete, I finally liked it, so:

NO thanks for being rude.
YES thanks for being so helpful, and share your great idea of serial com. implementation by software for Arduino.

And I finish this post, just saying: I copied your idea, and I copied the way you handle the buffer with the routines: sssRead(), sssWrite(), and sssAvailable(). It's crazy amazing how you did, and how I can't still understand... well (sssRead() concretelly).

Cheers,

Abel.
Title: Re: Yet another Software Serial
Post by: abeltomillo on Sep 12, 2014, 02:22 am
About sss, I recommend you to use TIMER2 in CTC mode and avoiding clearing Compate Match A flag the whole time, and also Overflow... It's not necessary really.

cheers,

abel.
Title: Re: Yet another Software Serial
Post by: Robin2 on Sep 12, 2014, 09:55 am

About sss, I recommend you to use TIMER2 in CTC mode and avoiding clearing Compate Match A flag the whole time, and also Overflow... It's not necessary really.


You may well be correct. I just work things out from the Atmel datasheet and I probably just use the first thing that works. But I am not going to spend an hour or so that would be necessary to re-learn my own code before I could come to a conclusion.

I have now reviewed all of my Replies in this Thread and I don't believe I was in the least bit rude to you in any of them and I object strongly to your suggestion that I was. If I have overlooked something please be good enough to quote the item that upset you and don't speak in generalities.

...R
Title: Re: Yet another Software Serial
Post by: abeltomillo on Sep 12, 2014, 10:02 am
Don't worry, I understand.

If your were working well with Servo library (official) I would do the changes, but I started the software project from scratch and without Arduino core for taking advantage of the speed, interrupts free, and more light code. But also I learnt a lot.

Maybe I finish this project, and make a library for software serial based on your code, but with some pluses or improvements. The thing is I try to make to work a servo and a GSM module, without hardware serial, and without buzzing on my servo. And... damn dude, I'm paining a lot...

cheers,

abel.
Title: Re: Yet another Software Serial
Post by: abeltomillo on Sep 18, 2014, 03:38 am
Hello all! again.. :)

Robin2, Hello, how r you? hope fine, let me to tell you something I've discovered on my implementation of "Yet another software serial". Hoping it no worries you ;) and not so long time since this develop. for you to know what can be happening, or not...

I'm experimenting some issues on reading by this implementation, it works 99% well. I explain to you all:

the problem comes, when the module slows a bit, then some bit is bad read. It usually happens at beggining of the INT1. So, it starts bad the counting of time, then the last bit is same as the before of the last.

So, If my module sends: 10101001, for example. Then sometimes, I am having 10101000 on my byte.

Do you know why is happening that? It's crucial to get a 100% safe data, as my implementation of the software for my robot, is very dedicated, and to implement a bit correction would result in a hard job.

Do you think I should down the baudrate? for getting more timing resolution, and then get more accurate data? maybe 100%?

I am using my module at 19200 bps. What do you think?

Hoping your answer,

have a good day all.

Abel.

Cheers.
Title: Re: Yet another Software Serial
Post by: abeltomillo on Sep 18, 2014, 04:50 am
Seems like I got it!

I just downgrade the baudrate to 9600 and using uart-lib at 19200. Using 250 ticks at first INT1, and 208 at the consecutive ones. Using 209 ticks to TX. Prescaler is /8. Timer0 and 2.

Any suggestions? ;)
Title: Re: Yet another Software Serial
Post by: Robin2 on Sep 18, 2014, 09:16 am

I just downgrade the baudrate to 9600 and using uart-lib at 19200. Using 250 ticks at first INT1, and 208 at the consecutive ones. Using 209 ticks to TX. Prescaler is /8. Timer0 and 2.


I have no idea what all this means.

...R
Title: Re: Yet another Software Serial
Post by: abeltomillo on Sep 18, 2014, 10:54 am
hahaha.

ticks are the values for OCR0A and OCR2A.
They are cfged for 104ms. except for the first time delay after INT1, which is 250 ticks.

that's all.
Title: Re: Yet another Software Serial
Post by: Robin2 on Sep 18, 2014, 02:41 pm
That's good news.

...R
Title: Re: Yet another Software Serial
Post by: abeltomillo on Sep 18, 2014, 06:15 pm
happy to hear that ;)
Title: Re: Yet another Software Serial
Post by: jhs73 on Oct 21, 2014, 05:38 pm
I feel stupid, because I cannot see where to download the sss.ino Any hints where to download it? Thanks
Jan
Title: Re: Yet another Software Serial
Post by: PaulS on Oct 21, 2014, 05:46 pm
I feel stupid, because I cannot see where to download the sss.ino Any hints where to download it? Thanks
Jan
The new forum stripped attachments from posts in the old forum. Your best bet is to PM Robin2, and ask for the file.
Title: Re: Yet another Software Serial
Post by: Robin2 on Oct 21, 2014, 08:15 pm
I feel stupid, because I cannot see where to download the sss.ino Any hints where to download it? Thanks
Jan
Sorry about this. You don't feel nearly as stupid as I feel angry.

I believe the attachments will be restored tonight. If not I will fix the problem tomorrow.

...R
Title: Re: Yet another Software Serial
Post by: jhs73 on Oct 21, 2014, 08:48 pm
I feel stupid, because I cannot see where to download the sss.ino Any hints where to download it? Thanks
Jan
Sorry about this. You don't feel nearly as stupid as I feel angry.

I believe the attachments will be restored tonight. If not I will fix the problem tomorrow.

...R
Thanks, I will try tomorrow
Jan
Title: Re: Yet another Software Serial
Post by: jboyton on Oct 22, 2014, 12:03 am
I believe the attachments will be restored tonight. If not I will fix the problem tomorrow.
Is the code simple enough to post here?

I'm in the middle of writing my own software serial. I don't want to reinvent the wheel but the existing wheels don't turn very well, at least not for my purposes. I would love to see what your approach was; maybe I can use it.
Title: Re: Yet another Software Serial
Post by: Robin2 on Oct 22, 2014, 10:09 am
I will try to attach the files here. I am still hoping the Forum techies will reinstate the links in the original Post. There must be hundreds or thousands of Posts that have been rendered useless by this stupid error.

I'm not even 100% certain that the 2 files in the ZIP are identical to those that were in the original Post.

Let me know if they don't work.

...R

Edit to add - now that the links to attachments have been restored it seems there are three files in the original post but I only put 2 of them in the .zip file. Please disregard the .zip file and use the attachments in the original post.
...R
Title: Re: Yet another Software Serial
Post by: jboyton on Oct 22, 2014, 09:13 pm
Thanks for posting the code.

I can't use pin3/INT1 so I'll have to make a few modifications before trying it. I'm still going to try my alternate strategy that doesn't use timer1 or timer2, but I will borrow from your code even if my approach is successful.
Title: Re: Yet another Software Serial
Post by: Robin2 on Oct 22, 2014, 10:45 pm
I can't use pin3/INT1 so I'll have to make a few modifications before trying it.
It was deliberately written to be simple so it MUST use either INT1 or INT0. I just chose INT1 (pin3) because it was beside pin 4.

Feel free to use it as the basis for anything you choose.

...R
Title: Re: Yet another Software Serial
Post by: jboyton on Oct 23, 2014, 02:50 am
It was deliberately written to be simple so it MUST use either INT1 or INT0.
I'm not sure why you say that. I got it to receive data using pin 8 without too much drama.

Thanks for the code!
Title: Re: Yet another Software Serial
Post by: jboyton on Oct 24, 2014, 07:41 pm
Robin, did the transmit side work flawlessly for you?

I thought that getting transmit to work would be easy since all I had to do was change the pin number (and the hard coded port and bit masks). But the device I was communicating with (a GPS) didn't accept the commands I sent it. I looked into the code and initially found a number of issues, only one of which was fatal.

One was that within an ISR you were disabling interrupts (which does nothing) and then enabling them (which is potentially an issue).

Another is that your timing scheme (adding to the count with each interrupt) ignores the latency for entering the ISR. I found that instead of 104us the bit width averaged 108us and occasionally was 112-114us. Once I got everything working I found that this was right on the "okay" side of the edge of what the GPS's UART would accept. I adjusted the increment value down a little to reduce the odds of failure from this.

But what was actually keeping the transmit from functioning correctly was a failure to set the TX line high earlier. When it came time to transmit, the code set it high for one bit period which was insufficient. This caused the first character to be effectively lost, rendering the command unrecognizable by the GPS.

So the transmit seems to work now... I think. I'm not sure I trust it yet.

That said it's a huge improvement over the system Software_Serial, at least in this limited application. While receiving data at 9600 baud, Software_Serial hogs about 97% of the uP bandwidth. Your sss Serial code uses less than 10%.
Title: Re: Yet another Software Serial
Post by: Robin2 on Oct 24, 2014, 09:09 pm
Robin, did the transmit side work flawlessly for you?
I didn't come across any problems but I did not do extensive testing. I certainly make no claim for perfection.

I may have another look at it tomorrow with your comments in mind.

...R
Title: Re: Yet another Software Serial
Post by: Hackscribble on Oct 24, 2014, 09:19 pm
Hi jboyton

Quote
While receiving data at 9600 baud, Software_Serial hogs about 97% of the uP bandwidth. Your sss Serial code uses less than 10%.
I'm interested in how you measured the utilisation - can you post details?

Thanks

Ray
Title: Re: Yet another Software Serial
Post by: jboyton on Oct 24, 2014, 09:33 pm
I certainly make no claim for perfection.
And I wasn't expecting it. I appreciate the code.
Title: Re: Yet another Software Serial
Post by: jboyton on Oct 24, 2014, 09:43 pm
I'm interested in how you measured the utilisation - can you post details?
I used timer1 to count how long it took to interate N loops of a piece of code (that was mostly just checking the timer). Any interrupts make this take longer so I could determine the relative amount of processor time used by the interrupts. For example, I calculated that the timer0 overflow interrupt (that millis() and delay() use) eats up about 0.6% of the processor time.

It's possible this method is flawed in some way, but I think it's giving me ballpark numbers at the very least.

The trick with the serial code was that the data from the GPS only flowed intermittently, so I had to catch it in action. And this also meant I had to reduce the number of loops, which affected the precision of the measurement.

Without even doing this it is obvious from the code that Software_Serial uses over 95% of the bandwidth at 9600 baud. That's one of the reasons I wanted to write my own software serial code. Of course to support higher baud rates they probably had to write it that way but I'm happy to trade that for more memory and processor bandwidth.

Here's the code:
Code: [Select]
//
// Measures relative processor bandwidth.
// Uses timer1 at 4us/step to time N loops of a piece of code.
// Interrupts result in more time to complete the loops.
//

void setup() {
  Serial.begin(115200);

  uint16_t t0, t;
  uint32_t total;
  uint32_t loops;
  uint8_t prevSREG;
 
  TCCR1A = 0;                         // reset timer1
  TCCR1B = 0;             
  TCNT1 = 0;
  TCCR1B =  bit (CS10) | bit (CS11);  // prescale 64 for 4us increment

//  TIMSK0 &= ~_BV(TOIE0);  // disable timer0 overflow interrupt
//  noInterrupts();         // disable all interrupts

  loops = 1000000;
  total = 0;
  prevSREG = SREG;
  cli();
  t0 = TCNT1;
  SREG = prevSREG;
  for (uint32_t i=0; i<loops; i++) {
    prevSREG = SREG;
    cli();;
    t = TCNT1;
    SREG = prevSREG;
    total += uint32_t(uint16_t(t-t0));
    t0 = t;
  }
 
//  interrupts();          // turn interrupts on for Serial output
 
  Serial.println("\n\nuP relative bandwidth measurement\n");
  float totms = total*4/float(1000);
  Serial.print(total); Serial.print(" x4us = "); Serial.print(totms); Serial.println(" ms");
  Serial.print(loops); Serial.println(" loops");
  float perLoop = total*4/float(loops);
  Serial.print(perLoop); Serial.println(" us/loop");

}

void loop() {}
Title: Re: Yet another Software Serial
Post by: Robin2 on Oct 26, 2014, 09:26 pm
One was that within an ISR you were disabling interrupts (which does nothing) and then enabling them (which is potentially an issue).

Another is that your timing scheme (adding to the count with each interrupt) ignores the latency for entering the ISR. I found that instead of 104us the bit width averaged 108us and occasionally was 112-114us.

But what was actually keeping the transmit from functioning correctly was a failure to set the TX line high earlier.
I have now had a look at my code in light of your comments. I think they are all well founded.

In retrospect I don't know why I had the noInterrupts() and interrupts() stuff. That was the first time I had tried using function pointers and they may have been a hangover from other test code I had been trying.

Another way of looking at the "failure to set the TX line high earlier" is to delay the start of transmission a bit longer (literally) after the TX has been set HIGH.

I don't propose to make any changes to the example. It was always only intended as illustrative and with your comments I think people will be able to get it to work. In any case, someone has mucked up the Forum so we can't edit our posts. If that gets fixed I will try to remember to put a foward link from the first Post to your post.

...R
Title: Re: Yet another Software Serial
Post by: jboyton on Oct 26, 2014, 10:22 pm
That's what I first did, added more of a delay to the start. But I found it conceptually simpler to set the line high in sssBegin().

I'm still not sure how I'm going to implement soft serial but if I go with your basic approach I will change the timing so that the initial timer delay is 49 for transmit (instead of 52 x 2us) and base subsequent delays on the match value rather than the timer value so that the latency isn't additive.

That is, instead of

OCR2A = TCNT2 + 52;

use

OCR2A += 52;
Title: Re: Yet another Software Serial
Post by: Robin2 on Oct 26, 2014, 10:39 pm
It's quite a while since I was fully immersed in the project but I seem to remember that all the timing was restarted for every byte so that any cumulative errors would only accumulate within the 10 (?) bits.

That said, I am not in any way opposing a more accurate approach.

...R
Title: Re: Yet another Software Serial
Post by: jboyton on Oct 27, 2014, 05:07 pm
That's right, your code syncs on the leading edge of the start bit. The latency, as I measured it, was typically 4us, although sometimes it was longer. You can't control that. By the time you get to the last bit in the character the accumulated latency was over 30us. At 9600 baud you can get away with this since the receiver is likely sampling the data in the middle of where it expects the bit to be. But since the latency doesn't scale with the baud rate I would expect this approach to fail at 19,200 baud where being 30us late means the receiver would likely sample the data before you send the bit.

On the RX side you're initially sampling near the leading edge of each bit so you have more room to be sloppy, assuming the transmitting device has precise timing.

I get the idea of keeping things simple to fit them in a system with limited resources. What you did worked for you and it seems to be working for me now too. But in this instance making it a little more robust doesn't add extra code.
Title: Re: Yet another Software Serial
Post by: sanotronics on Mar 30, 2015, 09:13 pm
Hi!

Would this work with pin 2 as Tx?

And what about latency? I am planning a MIDI controller.

Thanks!
Title: Re: Yet another Software Serial
Post by: CrossRoads on Mar 30, 2015, 09:20 pm
Might be better off with a uC with dual hardware serial ports if both serial's are running at MIDI speeds (31250?) Atmega1284P, another plus is 128K flash and 16K SRAM if needed.
Example '1284P board I offer - has some prototype area also for Midi connectors or whatever, and extra power/Gnd connection points.
Shown with offboard and onboard USB/Serial modules.
http://www.crossroadsfencing.com/BobuinoRev17 (http://www.crossroadsfencing.com/BobuinoRev17)
(http://www.crossroadsfencing.com/BobuinoRev17/Bobuino2_FTDI_basic.jpg)
(http://www.crossroadsfencing.com/BobuinoRev17/Bobuino2_MIKROE483_screw.jpg)
Title: Re: Yet another Software Serial
Post by: Robin2 on Mar 31, 2015, 11:14 am
Would this work with pin 2 as Tx?

And what about latency? I am planning a MIDI controller.
It would work with pin 2 as Tx. I chose not to use pin2 so that it would be available for other required interrupts.

This is really just a demo project. You will have to figure out its suitability yourself. I know nothing about Midi.

I suspect @CrossRoads' advice is sound. Use a Mega with 4 hardware serial ports, or a Leonardo which does not use its UART for comms with the PC. Or, of course, one of @CrossRoads' boards.

...R
Title: Re: Yet another Software Serial
Post by: universam on Jun 10, 2015, 03:08 pm
I get the idea of keeping things simple to fit them in a system with limited resources. What you did worked for you and it seems to be working for me now too. But in this instance making it a little more robust doesn't add extra code.
I'm getting a lot of corrupted frames.
So I wanted to ask if someone could post the improved source here where this timing is probably better?

Thank you for your efforts!
Title: Re: Yet another Software Serial
Post by: Robin2 on Jun 10, 2015, 05:07 pm
I'm getting a lot of corrupted frames.
With what?

You seem to have jumped into a conversation without explaining what you are trying to do and without posting the code that is causing you a problem?

...R
Title: Re: Yet another Software Serial
Post by: jboyton on Jun 10, 2015, 06:01 pm
I'm getting a lot of corrupted frames.
So I wanted to ask if someone could post the improved source here where this timing is probably better?
I made some changes to Robin's code since it didn't work for me straight out of the box, so to speak. Since I needed to use an RX pin other than 2 or 3 I modified the code to use pin change interrupts instead of INT0/1. That got the RX side up and running at 9600 baud. But the transmit side wouldn't work until I modified the timing. Basically, everywhere that OCR2A was incremented by TCTN2 + sssBaudTimerCount on the transmit side (there are three places) I used a constant of 49 instead of sssBaudTimerCount.

Although it worked at 9600 baud I discovered the RX timing was also off and I tweaked it in a similar way, replacing the remaining two instances of sssBaudTimerCount with a constant of 52.

But I don't think this approach (using different constants of course) would have worked for any higher baud rates. Adding TCNT2+constant to OCR2A was causing an error to accumulate as the character was received or transmitted. Tweaking the constant helped but probably wouldn't work for higher rates. What really needed to be done was simply to add OCR2A to itself. That is, OCR2A += some baud rate dependent constant.

But I never finished working that out since I decided to implement software serial in a different manner.
Title: Re: Yet another Software Serial
Post by: ammritt on Jul 02, 2015, 04:14 am
Hi,
Can somebody suggest me what changes need to be made to sss.ino if i want to use another pins let' say 6,7.
Title: Re: Yet another Software Serial
Post by: Robin2 on Jul 02, 2015, 09:51 am
Hi,
Can somebody suggest me what changes need to be made to sss.ino if i want to use another pins let' say 6,7.

That would require a major change as you would have to use pinChange interrupts. That should certainly be possible - but I don't plan to do it.

For simplicity I wrote the code so it uses interrupt1 (pin 3) for Rx. It could also easily use interrupt0 (pin 2). It can use any pin for Tx.

Why do you have a problem using pins 3 and 4 ?

...R
Title: Re: Yet another Software Serial
Post by: ammritt on Jul 02, 2015, 05:17 pm
I am using GSM shield which works on 2,3
https://www.arduino.cc/en/Main/ArduinoGSMShield
Title: Re: Yet another Software Serial
Post by: jboyton on Jul 02, 2015, 05:34 pm
You can use any TX pin with the software as it is.

To use an RX pin other than 3 or 4 2 or 3 you have to use pin change interrupts. It's not terribly difficult to do. Mainly it's just using a different interrupt vector and writing to different registers. Also, since a pin change can occur for either a "0" or "1" you have to check that. The SoftwareSerial library can be used as a template.

I used pin 8 for RX and just hand coded the registers, masks and vector. If you want to use a different pin you'll have to tweak those values.

I have attached the test code I used.
Title: Re: Yet another Software Serial
Post by: jboyton on Jul 02, 2015, 05:43 pm
Alternatively, you can use the software serial library I wrote. It's fleshed out a bit better so you can specify the pins in the constructor, just like with SoftwareSerial. I tested it with a GPS and it worked for 9600, 19200 and 38400 baud. A version of this library is part of a finished data logger project, running at 38400 without errors.

I took a slightly different tack than Robin did. Rather than check the RX line every bit period my code doesn't use a timer interrupt at all. Instead, it's interrupted only when the RX line changes from 0 to 1 or 1 to 0. Then it back calculates what has happened before, using timer 0 as a time reference. It doesn't modify timer 0 though. It expects it to be running in its standard mode as set up by the system.

The penalty for doing it this way is that it only works with ASCII character input. It won't work if binary data needs to be received. But I wrote it for use with a GPS that sends ASCII NMEA strings.

It also doesn't have a transmit buffer. It sends strings in a way similar to how SoftwareSerial does, with interrupts temporarily disabled. The idea was that you usually only need to transmit GPS commands at startup so you don't need a buffer.

It's attached below.
Title: Re: Yet another Software Serial
Post by: Robin2 on Jul 02, 2015, 08:23 pm
@jboyton, thanks for your two contributions - I'm sure they will be useful to people.

...R
Title: Re: Yet another Software Serial
Post by: paynterf on Aug 25, 2015, 11:16 pm
Thanks for the great code to establish a workable virtual serial port on a Uno!  I ran your 'Demo' code on a Uno, and the 'Partner' code on a Teensy 2.0 and it worked great.

The Teensy 2.0 module I used was one I have connected to a NEATO XV-11 LIDAR module, and I now plan to try and get the XV-11 data over to the Uno where I can use it for navigation in my wall-following robot project.  See http://fpaynter.com/2015/08/more-work-on-the-neato-xv-11-lidar-module/ for details.

Frank
Title: Re: Yet another Software Serial
Post by: James81 on Nov 11, 2015, 06:59 pm
I first want to thank Robin for creating this code as it addresses a specific need I and the community in general have for using the servo library and software serial.

This is the error message I receive when attempting to compile the sketch.

Arduino: 1.6.5 (Windows 7), Board: "Arduino/Genuino Uno"

sss.ino: In function 'void loop()':
sss:80: error: a function-definition is not allowed here before '{' token
sss:116: error: a function-definition is not allowed here before '{' token
sss:123: error: a function-definition is not allowed here before '{' token
sss:446: error: expected '}' at end of input
Multiple libraries were found for "Servo.h"

 Used: C:\Users\Owner\Documents\Arduino\libraries\Servo

 Not used: C:\Program Files (x86)\Arduino\libraries\Servo

a function-definition is not allowed here before '{' token

I am sure my question seems elementary to the folks on this forum but this semester is the only course I have had with any programming at all so please be gentle. I have attached the code for the receiving uno in case my uno code is causing the conflict with the sss ino.


A little background on my project I am building a robotic hand potentially a test bed for a later prosthesis model. I have a glove with 5 flex sensors being read by an arduino mini and transmitted with a series 2 xbee. On the receiving end in the forearm assembly of the hand I have a series 2 xbee with an arduino uno.

The uno is receiving from the xbee on pins 3 and 4 and the servos for the fingers are on PWM pins 5,6,9,10, and 11.

Any suggestions are appreciated.
Title: Re: Yet another Software Serial
Post by: Robin2 on Nov 11, 2015, 08:16 pm
You are missing the closing } for the line if(startPackage == '$'){   // Verifying that the first value is "$" in your program

If you use the Auto Format tool to indent your code consistently it is easier to spot that sort of problem.

I try always to create the closing bracket immediately after I create the opening bracket and before I fill in the code between them.

The error message you got is typical for the situation where you attempt to create one function inside another.

...R
Title: Re: Yet another Software Serial
Post by: James81 on Nov 11, 2015, 09:17 pm
Thank you Robin.
Title: Re: Yet another Software Serial
Post by: GaganGholia on Mar 02, 2016, 09:00 pm
How software serial works?
Title: Re: Yet another Software Serial
Post by: Robin2 on Mar 02, 2016, 11:19 pm
How software serial works?
I'm not sure what you want to know. The code for the regular SoftwareSerial is included with the Arduino IDE and the code my version is in this Thread.

If you want to know more generally how serial communication works I suspect Google is your best bet.

...R
Title: Re: Yet another Software Serial
Post by: juan3211 on May 04, 2020, 04:17 pm
Hi Robin2, I have read the post. Is your last version in the first post? or in 2015 year?
Thanks.
Title: Re: Yet another Software Serial
Post by: Robin2 on May 04, 2020, 07:42 pm
Hi Robin2, I have read the post. Is your last version in the first post? or in 2015 year?
Thanks.
Sorry, it's so long ago I can't remember.

...R
Title: Re: Yet another Software Serial
Post by: juan3211 on May 04, 2020, 08:07 pm
Sorry, it's so long ago I can't remember.

...R
Anyway, thanks a lot for your code.
Title: Porting YASS
Post by: urbantigerau on Jun 29, 2020, 03:00 pm
Hi All,

I was writing a "roll your own" software serial which was actually looking like it worked until I tried to use it in anger grabbing NMEA messages and feeding them into TinyGPS+. It seems latency around interrupt timing is pretty fatal to the approach I was using.

The reason for my interest in software serial at all was that I have a preference for using a 1284P in a project where I needed 2 and 1/2 serial ports. The 1284P has precisely 2. I needed only the receive side of the 1/2 port and then very specifically at 9600 baud, 1 stop bit, no parity. Pretty vanilla. I first thought of the standard Software Serial but the compiler balked on fatal interrupt vector re-definitions associated with the pin change interrupts which are core to the HMI of my project. So vanilla SS was out. There are alternatives but my success with the others was also constrained.

So I tried writing my own and I found that if the input character stream  is directed to the console it worked like a bought one. But it failed on dropped characters when used to feed TinyGPS+. It looked so good on my scope too, the timing of the bit sampling was near perfect on test characters. But fall over it does. A mystery I still don't understand. And given how hard it is to research interrupt latency maybe I never will.

Under another thread Robin2 directed me to the code in this thread. Hereafter I will refer to it as YASS.
While YASS is specifically directed to the Uno the scalability of the ATMEGA AVR familiy is such that it is relatively easy, provided you do a bit of research and keep your wits about you, to port the code to another processor in the family.

In general the port process is made possible by reference to a couple of good friends that everyone dabbling in Arduino should have to hand. That is the data sheets for the ATEMGA 328 and the 1280/1284P/2560 families.

It is easy to see why some see these data sheets as scary monsters. The 328 datasheets is just shy of 300 pages. And they are not a real easy read, being full of abbreviations, acronyms and technical detail at a very high level. They are meant for serious users, who (at least purport to) know what they are doing. However there a few salient facts that makes these documents true friends:



If you have not made friends yet with the data sheets I urge you to do so. I could not have done this port without access to the data sheets.

So to the port itself.

YASS serial in relies on an interrupt to get the serial start bit and then a a timer to read the bits from each point in time as they fly past. I am not going to explain serial communications here. If you are reading this and wondering what a start bit is please take the time to research how serial communications work, what the baud rate is, and why it is a much much much better idea to use a device called a UART (or USART) to manage your serial communications than trying to do it in software.

Lets start with the timer. YASS serial in uses Timer 2. Timer 2 is an 8 bit timer and is present across all of the family discussed here. Is it in all the families? I don't know but you can find out by peeking at the index of the data sheets of the processor of your choice. The data isn't hidden, it is in plain sight.

I was pretty confident that the code in YASS for timer 2 would port as it was. A peek at the registers used for the 328 and 1284 showed identical bit assignments and usage. Sure the register addresses were different but if you stick to referring to registers by name the compiler will make sure it all lines up. The registers in question are: TIFR2, TCCR2A, TCCR2B, OCR2A and TIFR2. And you can see the mapping in the attachment timer2_mapping.pdf. Now I troubled myself to build this table. What you do is up to you. If you can glance at data sheets and make conclusions that's great. I like documentation though and I have an aversion to doing things twice.

Now the interrupt is another matter. On the 1284 Interrupts 0 and 1 share pins in the transmit and receive for the second serial port on the 1284. So it would be counter-productive to use either interrupt 0 or 1. That leaves INT 2 and the registers used are: EIMSK, EICRA and EIFR.

INT2 on the 1284 is Arduino pin 2, being bit 2 of Port B. That isn't secret information either. If you have not come across the work of user Alberto on DeviantAart (also known as Pighixxx) then it is time you did. You can go to https://www.deviantart.com/pighixxx/gallery (https://www.deviantart.com/pighixxx/gallery) for some truly helpful single sheet pin assignment diagrams. Great work!

Now the attachment interrupt_mapping shows the usage of the isr registers by YASS. For example for the register EIMSK the bit pattern to enable INT 1 (which incidentally is bit 3 on Port D) is binary 00000010.

On the 1284P side to enable INT2 that number becomes binary 00000100. All the registers are treated the same. See and compare the orange highlighting.

So everywhere we see a reference to EIFR for example we replace the 328 specific data 00000010 with 00000100, and so on. You can see that in the attached code.

Now there are a couple of extra traps. The bit read of the data stream is done with a port read for speed and the bit of data is moved to the bit zero position with a shift. Arduino digitalRead is a tad too slow. Convenient but it does a pack of stuff in the background that YASS really does not have time for. I am not going to explain that here, you can research it pretty easily. And when you do dip your lid to cleverness of the people who came up with the idea. Slow yes, but pure simplicity for a novice. However I am sure all you that have gotten this for are up for a port read rather than a digitalRead.


The final result is in the attached code segment. Note I have placed a warning in the form of a comment like //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! where I have made a change and if you are porting further you may have to make a change.

Note that I have not changed the transmit part, however anyone who has followed the above (and it is pretty simple really) will be able to port the transmit side for themselves. In this code the transmit part is commented out and may compile to error if un-commented.

Just one or two little things more.

I probably should not bother to explain this but it is perhaps a little less than obvious to some so forgive me please. C's peccadilloes.

Where you see something like:

EIFR |=   B00000100;

the idea here is that the EIFR register contents is logically ORed (|=)  with the constant 00000100 and the result placed back in the EIFR register. The idea is that all bits except the 1 in the 00000100 are left the way they were and the 1 is set to 1. It's clever and compact. Readability??

Other languages would write this as:
EIFR =  EIFR | B00000100;
and a halfway decent optimizing compiler would produce the same size binary code as the C version.

Similarly
TIMSK2 &= B11111100;
sets all the bits to zero that are zero in the constant and leaves the the bits that were 1 as they were.

Don't believe me??, try a few examples. This code is fast and effective and if you not already using it you should be.

Finally you will see I have changed the style of the program from
int sssAvailable() {
..........................
}

to

int sssAvailable()
{
..........................
}

If you don't like it don't bother telling me. I understand the original is "standard" and it is in very common usage, but I like a vertical stripe of corresponding curly braces. Readability. It has saved me hours more than once in locating the missing one or the one too many brace.

So good luck with the code as presented and the transmit component if you need it. And thanks again to Robin for  great piece of code.


Title: Re: Yet another Software Serial
Post by: Robin2 on Jun 29, 2020, 03:17 pm
If you don't like it don't bother telling me. I understand the original is "standard" and it is in very common usage, but I like a vertical stripe of corresponding curly braces. Readability.
Ah well ...

I much prefer the style that I use - for readability !

...R