How to deal with multiple SoftwareSerial at the same time

Hi,

I'm wondering if I can deal with multiple SoftwareSerial at the same time.
This is not about receiving things from SoftwareSerial, but just about writing.

I need to write 18 SoftwareSerial at the same time.
I'm trying to control 18 thermal printers simultaneously, sending them exactly same data via SoftwareSerial. (but not to all 18 printers everytime. it could be just 1, 5, or some random number)
No need to read data from printers.

First I tried using array.
I declared an array of SoftwareSerial, and sent data one by one like this:

void handOverLine() {
  for(int i = 0; i < 18; i++) {
    if(targets[i] == 1) {
      printBitmap(Thermal[i], 48, line);
    }
  }
}

void printBitmap(SoftwareSerial thermal, int w, byte data[]) {
  //w = width/8 of bitmap, data = pixel data(one line = 48bytes, 384px)

  thermal.write(28);          //FS
  thermal.write(75);          //K
  thermal.write((byte)0x00);  //n1
  thermal.write(w);           //n2
  for(int i = 0; i < w; i++) {
    thermal.write(data[i]);
  }
}

Note that the code is just an excerpt.

I succeeded with this code.
However, the problem was that it took forever to print entire picture!

So I tried to fix the SoftwareSerial library.
But I just cannot figure out how.

What I'm imagining is like this:

  • When you declare ModifiedSoftwareSerial, there is no need of arguments for construction.
  • Instead, ALL pins I'm planning to use are set as OUTPUT and pulled-up. (just TX pins)
  • When you write something with ModifiedSoftwareSerial, ALL TX pins write the same data simultaneously.
  • Then chips like 74HC245 filters signal in order to send data just to printers that I want to print. (This part is nothing to do with library)

Okay, this cannot be something universal.
I just want a library only for this project.

What I cannot understand of the SoftwareSerial library is this 'tx_pin_write' thing.

void SoftwareSerial::tx_pin_write(uint8_t pin_state)
{
  if (pin_state == LOW)
    *_transmitPortRegister &= ~_transmitBitMask;
  else
    *_transmitPortRegister |= _transmitBitMask;
}

I can't figure out what _transmitPortRegister is about.
And it looks like controlling just a pin of A port.
I need to control total 6 ports: PA, PB, PC, PD, PG, PL.
Can anyone advice me?

Thank you for reading my poor English,
and thanks again in advance for replies :slight_smile:

Please feel free to reply and to ask me more information to solve this problem.
Oh and I'm only friendly with Arduino code, not competent in any other languages, though I can understand most of easy codes.

However, the problem was that it took forever to print entire picture!

At what baud rate? How big is the picture? How long is "forever"?

So I tried to fix the SoftwareSerial library.
But I just cannot figure out how.

What changes are you trying to make?

I can't figure out what _transmitPortRegister is about.

It is defined when you define the transmit pin. That pin maps to some port. The combination of port and pin is stored in that variable.

For more details, look at PortManipulation.

At what baud rate? How big is the picture? How long is "forever"?

At maximum baud rate that the thermal printer supports: 19200bps.
Image size is 384x600 pixels and it's 600 lines for thermal printer.
And the time taken to print image with multiple printers is, I guess, (typical speed for one printer) / (numbers of printer), though I haven't measured it exactly.
What is important is not the exact time but that it becomes slower and slower to print multiple printers because I print one by one with SoftwareSerial, not printing simultaneously.

What changes are you trying to make?

I wrote what I was imagining in the next paragraph.
And my actual trial contains thing like this:

  • Change construction part
void SoftwareSerial::setTX(uint8_t tx)
{
  pinMode(tx, OUTPUT);
  digitalWrite(tx, HIGH);
  _transmitBitMask = digitalPinToBitMask(tx);
  uint8_t port = digitalPinToPort(tx);
  _transmitPortRegister = portOutputRegister(port);
}

This is an excerpt from SoftwareSerial.cpp.
I wanted to make _transmitPortRegister points not only a pin, but multiple pins.
So I tried like this:

void SoftwareSerial::setTX(uint8_t tx)
{
  for(unsigned i = 19; i < 54; i += 2) {
    pinMode(i, OUTPUT);
    digitalWrite(i, HIGH);
    _transmitBitMask |= digitalPinToBitMask(i);
    uint8_t port = digitalPinToPort(i);
    _transmitPortRegister |= portOutputRegister(port);
  }
}

But _transmitPortRegister part didn't compiled.
I'm not confident with how _transmitPortRegister looks like, because those digitalPinToPort and portOutputRegister things are not functions in this cpp file so that I don't know what shape of value they returns.
Anyway it looks clear that _transmitPortRegister should not be bitwise operated.

Thus, as I mentioned in original post, I thought _transmitPortRegister was only for one port.
I'm not sure with this.

  • Writing part is simple, so if I succeed to make change in construction part, I think there would be no reason for change this.
    But not sure as well. You may suggest me change this part.
void SoftwareSerial::tx_pin_write(uint8_t pin_state)
{
  if (pin_state == LOW)
    *_transmitPortRegister &= ~_transmitBitMask;
  else
    *_transmitPortRegister |= _transmitBitMask;
}

It is defined when you define the transmit pin. That pin maps to some port. The combination of port and pin is stored in that variable.

Thanks for your answer.
But still I can't figure it out how the combination looks like.
I knew about port manipulation and thought quite accustomed dealing with it, but this does not give me a clue about the shape of _transmitPortRegister, because as I mentioned above I don't know about portOutputRegister things.

Thanks again! :slight_smile:

Recently there was a post about using SoftwareSerial with only 1 output pin, and no input. This will free up some pins for you.