Modbus RTU slave library for STM32F103(blue pill) that works?

Hi, I lost whole day today to try multiple libraries for modbus RTU slave/RS485... Some of them compile and non of them work with STM32, but working fine with ESP8266 or UNO, for example, https://github.com/CMB27/ModbusRTUSlave

Any tested library for STM32?

Have you tried GitHub - parasbhanot/Modbus: Implementation of Modbus using Arduino and Stm32 ?

No, I haven't found this one, thanks a lot, but have you tried it ?
There is no documentation and even no example...
Any other solutions?

I have never tested it with a bluepill:

https://werner.rothschopf.net/microcontroller/202112_arduino_modbus_server.htm

but it should be documented in the web,
has examples
and has a local doc folder to read.

If you have questions - you can ask the author (me). :wink:

If you have some experience with the modbus master library from doc walker you will find this slave library very similar (at least this was my idea).

1 Like

Thank you, I`ll try it and inform you later.
Cheers.

Hi, I tried your library and it`s same as few other libraries and this is what I concluded so far.
I upload the example for RS485, using HardwareSerial instance Serial2 (pins PA3 and PA2), and PA4 for RE/DE pin. When I try that, with serial/usb adapter and QModbus software, as a master, it works as expected!
But, when I connect it over RS485 module to ESP32-based RS485 master, it's not working, there is no pulse on the RE/DE pins and I get Timeout error on the master.
ESP32 based master, is working over RS485 with ESP8266 based slave using same library that doesn't work with STM32F103.
Any ideas what could be the issue?

You will need the callback to activate/deactivate the RE/DE pins.
You might need to initialize/pinMode the used pin as OUTPUT (at least this has to be done for Arduino Unos, ESP...)
Are there any restrictions which pins on the STM32 can be used as output?

Please post your actual code.

It`s all been done, as I said it works like few other libraries, but there's no activity on RE/DE pin. There are no restrictions on for PA4 pin, I tried few others as well..
Anyone tried any library with blue pill that works good for sure?

I used this library a couple years ago.

It is not for STM32, but worked with bluepill without issues.
You may have to slightly edit the variable types there, for example, replace int with int16.

But I not tested it with ESP32, the master was on the PC

Thanks, do you remember what serial you have been using for RS485? I tried that library last week and it is same as I described in post #6.
It's obviously some stupid mistake Im not seeing :) . Ill post the code later, just in case.

I found my old code:

/* ====== MODBAS PARAMETERS ======== */
#define TXEN PA8           // TX/RX Enable PIN
#define SLAVE_ADDRESS 1   // Modbus slave address              
Modbus bus(SLAVE_ADDRESS,Serial1,TXEN); 

This is the code I'm testing it`s slightly edited library example:

/**
 *  Modbus slave example 3:
 *  The purpose of this example is to link a data array
 *  from the Arduino to an external device through RS485.
 *
 *  Recommended Modbus Master: QModbus
 *  http://qmodbus.sourceforge.net/
 */

#include <ModbusRtu.h>
#include <HardwareSerial.h>

HardwareSerial Serial2(PA3, PA2);


// assign the Arduino pin that must be connected to RE-DE RS485 transceiver
#define RE_DE PA4

// data array for modbus network sharing
uint16_t inputRegisters[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };

/**
 *  Modbus object declaration
 *  u8id : node id = 0 for master, = 1..247 for slave
 *  port : serial port
 *  u8txenpin : 0 for RS-232 and USB-FTDI 
 *               or any pin number > 1 for RS-485
 */
Modbus slave(11, Serial2, RE_DE);  // this is slave @11 and RS-485

void setup() {
  Serial.begin(115200);
  delay(500);
  Serial2.begin(9600);  // modbus RS485 RX_PA3,  TX_PA2
  delay(500);
  pinMode(RE_DE, OUTPUT);

  slave.start();
}

void loop() {
  slave.poll(inputRegisters, 8);
  inputRegisters[0] = random(0, 100);
  inputRegisters[1] = random(100, 200);
  delay(10);
}

I have used noiasca's library and it is working perfectly fine on my custom stm32f103c8t6 board which is blue pill based. I had to make some changes though because it was giving some errors. I am using Serial1 (PA9,PA10) of the stm32 controller. The Tx enable pin (PA0 in my case) is also working fine. Thanks noiasca

1 Like

Thanks, I have to get a few new RS485 modules and try again.

I think your RE/DE pin is not working because you have not set up the pretransmission and posttransmission call back function. I have used the helloworld example and it contains that function.

It's an example of the library from post #9 , and there are no transmission callback functions, I'll try noiasca's library later.

Agreed, I used the library without callbacks too, it works fine for me

Hi, after losing a full 2 days to this i think i found out the problem. i confirmed this on my scope but the instant DE is made high, it immediately goes low at the same time the TX transmission begins, and it seems to be that flush() is not blocking as it should. its what ensures proper timing by waiting to set DE low again once the buffer is empty or transmission is complete. all libraries ive seen and tried are all based on the same original which uses a serial flush function as the delay blocking code.

What i have been told, and read from just a few sources is that serial.flush() has not actually been implemented in arduino for stm32, its just been given an empty namespace, whatever that means, until a substitute could be developed. Now, im not skilled enough to confirm this, im just taking what i was told at face value.

given what flush does and what i am observing on the scope, it makes sense though. I wouldnt know where to begin to manually do what flush does, although i think its just a while loop that is checking certain bits in the uart register, i dont know why that wouldnt be supported, someone mentioned something about memory limitations being a factor.
Anyway, sorry i couldnt be more useful, and just dropped this heresay. In my own project ive just resigned myself to manually writing a write function with an aproximated delay time if delays can be reliably calculated with small overestimation, but always overestimated, based on the string length, since my library already passes the transmission length through anyway

Hm, that is interesting!

This is Serial.flush() function from the latest STM32 core:

void USBSerial::flush(void)
{
  // Wait for TransmitQueue read size becomes zero
  // TS: safe, because it not be stopped while receive 0
  while (CDC_TransmitQueue_ReadSize(&TransmitQueue) > 0) {}
}

and

// Determine size of data, stored in queue
int CDC_TransmitQueue_ReadSize(CDC_TransmitQueue_TypeDef *queue)
{
  return (queue->write + CDC_TRANSMIT_QUEUE_BUFFER_SIZE - queue->read)
         % CDC_TRANSMIT_QUEUE_BUFFER_SIZE;
}