Sending large buffer through serial rs485

hi, i've been trying to send an array of bytes with 108 buffer size through serial rs485. what happened is, it is only send the last 44 buffer data and sometimes it merged with the next buffer. does anyone have any idea on how to send large bugger through serial?

p.s i try to use serial flush after a chunk of buffer, but it doesn't sent instead and only the last chunk that have been sent

Welcome. code. circuit diagram. description of what you're trying to do.
Perhaps, read:

and come back and post what's needed.
Thanks.

1 Like

The Arduino has print buffers for both rece3ive and transmit. You are probably overflowing one or the other or both. Try cutting your packet size to about 30 bytes and see if it works, if it does that would be the problem.

You're only talking about sending an array; we have no idea what is the receiving side and how you know that you only receive 44 bytes.

That would indicate that the code in the receiver has flaws.

One can not overflow the transmit buffer; code will just stall till there is place again to send more :smiley:

1 Like

okay, i apologize for the minimum information.... i'm using STM32 microcontroller board with arduino ide. i've been trying to commuicate two board by sending 108 bytes of data using serial with rs485 module, here's the wiring (both receiver and sender):

  • DE --- PE14
  • RE --- PE13
  • DI --- PA2
  • RO --- PA3

here's the code for sender:

#define PIN_DE PE14
#define PIN_RE PE13
#define PIN_DI PA2
#define PIN_RO PA3

HardwareSerial Serial2(PIN_RO, PIN_DI);

unsigned long prevMillis = 0;

void setup() {
  Serial.begin(115200);
  Serial2.begin(9600);
  pinMode(PIN_DE, OUTPUT);
  pinMode(PIN_RE, OUTPUT);
  prevMillis = millis();
}

void loop() {
  if (millis() - prevMillis >= 3000) {
    uint8_t data[108] = { 0 };
    data[0] = 0x01;     // Start
    data[1] = 0x04;     // Ack
    data[103] = 0xE1;   // CRC L
    data[104] = 0x74;   // CRC H
    preTransmission();
    for (int i = 0; i < 64; i++) {
      Serial2.write(data[i]);
    }
    Serial2.flush();
    for (int i = 0; i < 44; i++) {
      Serial2.write(data[64 + i]);
    }
    postTransmission();
    prevMillis = millis();
  }
}

void preTransmission() {
  digitalWrite(PIN_DE, LOW);
  digitalWrite(PIN_RE, HIGH);
}

void postTransmission() {
  digitalWrite(PIN_DE, HIGH);
  digitalWrite(PIN_RE, LOW);
}

and here's the code for receiver:

#define PIN_DE PE14
#define PIN_RE PE13
#define PIN_DI PA2
#define PIN_RO PA3

HardwareSerial Serial2(PIN_RO, PIN_DI);

unsigned long prevMillis = 0;

void setup() {
  Serial.begin(115200);
  Serial2.begin(9600);
  pinMode(PIN_DE, OUTPUT);
  pinMode(PIN_RE, OUTPUT);
  digitalWrite(PIN_DE, HIGH);
  digitalWrite(PIN_RE, LOW);
  prevMillis = millis();
}

void loop() {
  if(Serial2.available() > 0){
    Serial.print(Serial2.read());
    Serial.print(" ");
    prevMillis = millis();
  } else if (millis() - prevMillis >= 1000) {
    Serial.println();
  }
}

i've try it, i divide the packet size into 3 chunk with 36 bytes each with serial.flush() between each chunk... and the receiver only receive the last chunk

i also try removing the serial.flush() but there are no different as well

i use serial.available() and serial.read() to receive the data sent by sender. and on receiver side i serial.print() the received data, there are only 44 data printed in serial monitor

Hi @ice_cream_123 ,

Welcome to the forum..

I'm thinking should be like this..


void preTransmission() {
  digitalWrite(PIN_DE, HIGH);
  digitalWrite(PIN_RE, HIGH);
}

void postTransmission() {
  digitalWrite(PIN_DE, LOW);
  digitalWrite(PIN_RE, LOW);
}

can usually ties these 2 together and use 1 pin..
add a Serial2.flush() just before postTransmission to make sure all has been sent before disabling the driver..
and really you should be able to write it all it once..
Serial2.write(data,sizeof(data));

good luck.. ~q

I'm actually kind of surprised you got anything..
Driver enable must be high (enabled) to transmit..
Receive enable should be high (disabled) else you recv what you trans..
Receive enable's logic is reversed from the Driver enable..

~q

I don't have RS485 modules so I just used the code without the additional code for the RS485. I also don't have your boards so I used a Mega as the sender and a Leonardo as the receiver (both using Serial1). I can not reproduce your problem.

One thing that I noticed is that you're spamming the serial monitor with empty lines after a timeout. I suggest that you use a flag to only print one new line after a timeout; something like below for the receiver.

void loop()
{
  static bool received = false;
  if (Serial1.available() > 0)
  {
    received = true;
    Serial.print(Serial1.read());
    Serial.print(" ");
    prevMillis = millis();
  }
  else if (millis() - prevMillis >= 1000)
  {
    if(received == true)
    {
      Serial.println();
      received = false;
    }
  }
}

There is one point that might be important and that is interrupt priorities. I have had serious problems on a Mega to receive blocks of data (200 bytes at 100000 baud nearly continuously) and trying to print them. The reason was that the Serial Tx interrupt had a higher priority than the Serial1 Rx interrupt; eventually I only printed new data if it had changed.

hi @qubits-us ,
yes, i used to do this on my ESP32 or Arduino UNO
but when it comes to STM32 (STM32F407VG) board i got nothing, so i experimented with the DE and RE pin until i got something on the receive side which result on this:

void preTransmission() {
  digitalWrite(PIN_DE, LOW);
  digitalWrite(PIN_RE, HIGH);
}

void postTransmission() {
  digitalWrite(PIN_DE, HIGH);
  digitalWrite(PIN_RE, LOW);
}

okay, let me try this on some other board as well to see wether it is the board or the module that affect serial communication.
also, the interrupt priorities you stated might do something in this matter i think i've to include this as well

thinking why it's working at all..
that pre, shuts down the 485 completely..
you then send out 64 bytes and then flush them away..
the next 44 bytes are sent for transmission, no flush..
then your post, turns the 485 back on for transmission and reception..
luckily the last 44 bytes which weren't flushed get sent..
that's my observations anyways..

good luck.. ~q

1 Like

I'm with @qubits-us here. RE & DE are usually either tied together or if separately controlled, both high or both low. The only time I've had RE != DE is when I wanted to hear my own transmission.

Have you tried the comms without the RS485 line drivers?

I'm guessing that the STM32F407VG is a 3.3v device. Which RS485 line driver chip are you using?

1 Like

To be clear, many of the MAX485 piggyback adapters from Amazon, AliExpress, etc. have very poor (misleading) labelling. Often, both RE and DE are labeled exactly that way, with no indication that RE is in fact a low-enable input, vs the high-enable for DE.
The MAX485 diagram, from the AnalogDevices datasheet:

Note how the RE is an inverted input, while the DE is not. When we tie them together and drive from one output, which is standard practice, either Driver or Receiver is enabled, and the other is the opposite. This creates a 'half duplex' connection arrangement, where the Arduino can talk, or Receive, but not both. Thus, when you set one low and one high, you've enabled or disabled both at the same time.

okay, so i grab a new pair of rs485 module, change receiver board with ESP32 and also i change my code on the pre/post transmission like @qubits-us shown.

i tested by sending 64 bytes of data using rs485 module from STM32 to ESP32, here's the code on the sender side:

#define PIN_DE PE14
#define PIN_RE PE13
#define PIN_DI PA2
#define PIN_RO PA3

HardwareSerial Serial2(PIN_RO, PIN_DI);

unsigned long prevMillis = 0;

void setup() {
  Serial.begin(115200);
  Serial2.begin(9600);
  pinMode(PIN_DE, OUTPUT);
  pinMode(PIN_RE, OUTPUT);
  prevMillis = millis();
}

void loop() {
  if (millis() - prevMillis >= 2000) {
    preTransmission();
    uint8_t data[64] = { 0 };
    data[0] = 0x01;
    data[1] = 0x04;
    data[62] = 0xAA;
    data[63] = 0xBB;
    Serial2.write(data, sizeof(data));
    postTransmission();
    prevMillis = millis();
  }
}

void preTransmission() {
  digitalWrite(PIN_DE, HIGH);
  digitalWrite(PIN_RE, HIGH);
}

void postTransmission() {
  digitalWrite(PIN_DE, LOW);
  digitalWrite(PIN_RE, LOW);
}

and this what i got on the receiver side:

1 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 AA 
1 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 AA 
1 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 AA 
1 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 AA 

it only receive until 62nd array, the 63rd array and so on isn't received by receiver. does anyone got any idea if i want to send more than 63 array size?

yes, i tried the communication without rs485 module and it works. i send 108 bytes and the receiver managed to receive all bytes.

yes it is, STM32F407VG indeed a 3.3V device... the chip driver is MAX485 from MAXIM

If you are using a hardware serial port, then add in a flush command like this:

void postTransmission() {
  Serial2.flush();
  digitalWrite(PIN_DE, LOW);
  digitalWrite(PIN_RE, LOW);
}

That will ensure that all of the data is transmitted before you switch your line driver back to receive.

hello, thank you everyone for the answers
i somehow managed to make it work. i reckon the problem was the first RS485 module, after getting a new module and changing the MAX485 chip it works now.

also i think it's because the message interval as well, i set the interval to 3 seconds and it works fine (maybe because of the 9600 baudrate).

and just like @markd833 stated i'm adding Serial.flush() after each transmission.

here's the final code, just in case someone stumble into similar problem

// Sender STM32F407
#define PIN_DE PE14
#define PIN_RE PE13
#define PIN_DI PA2
#define PIN_RO PA3

HardwareSerial Serial2(PIN_RO, PIN_DI);

unsigned long prevMillis = 0;

void setup() {
  Serial.begin(115200);
  Serial2.begin(9600);
  pinMode(PIN_DE, OUTPUT);
  pinMode(PIN_RE, OUTPUT);
  prevMillis = millis();
}

void loop() {
  if (millis() - prevMillis >= 3000) {
    preTransmission();
    uint8_t data[108] = { 0 };
    data[0] = 0x01;
    data[1] = 0x04;
    data[106] = 0xAA;
    data[107] = 0xBB;
    Serial2.write(data, sizeof(data));
    Serial2.flush();
    postTransmission();
  }
}

void preTransmission() {
  digitalWrite(PIN_DE, HIGH);
  digitalWrite(PIN_RE, HIGH);
}

void postTransmission() {
  digitalWrite(PIN_DE, LOW);
  digitalWrite(PIN_RE, LOW);
}

// Receiver ESP32
#define PIN_DE 19
#define PIN_RE 18

unsigned long prevMillis = 0;

void setup() {
  Serial.begin(115200);
  Serial2.begin(9600);
  pinMode(PIN_DE, OUTPUT);
  pinMode(PIN_RE, OUTPUT);
  prevMillis = millis();
}

void loop() {
  if (Serial2.available() > 0) {
    isReceived = true;
    Serial.print(Serial2.read(), HEX);
    Serial.print(" ");
    prevMillis = millis();
  } else if (millis() - prevMillis >= 1000) {
    if (isReceived) {
      Serial.println();
      isReceived = false;
    }
  }
}

void preTransmission() {
  digitalWrite(PIN_DE, HIGH);
  digitalWrite(PIN_RE, HIGH);
}

void postTransmission() {
  digitalWrite(PIN_DE, LOW);
  digitalWrite(PIN_RE, LOW);
}

cheers m8...

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.