Problem with hardware serial STM32 F103C8T6 Bluepill

Hi everybody,

Since last Friday I'm struggling with strange to me problem.
I'm using STM32 F103C8T6 Bluepill with Arduino framework. I'm preparing code in vscode with PlatformIO extension.

Brief introduction to project (feel free to skip it).
The project idea is very simple. Bluepill has 3 USART line. Two of them are connected to ultrasonic senors AJ-SR04M. They are working in Low serial mode. This mode waiting for command to execute measurement, in response I'm getting back my measurements. When I get my measurements I want send it over mqtt to Home Assistant. 3rd USART (PA9, PA10) is used for debugging and upload new code.

My side problem:
The code written line by line working well, except one small thing mqttClient.connected() always return false, but it doesn't matter. Regardless to this state messages are send through (I tried 3 libraries with same result). Anybody meet same problem ?

Main problem
I started to creating my first small library for this sensor. I tried all 3 possibilities for serial Pointer/Reference/copy of instance to HW serial
In current code the input to library constructor is:
Pointer to HW serial, mode number and array size for average results.
Aj_sr04m jsn1(&jsn1Serial, 4, 5);
Aj_sr04m jsn2(&jsn2Serial, 4, 5);

*Definition of HW serials *
HardwareSerial DebugSerial(USART1);
HardwareSerial jsn1Serial(USART2);
HardwareSerial jsn2Serial(USART3);

The problem appears only to USART2 serial.
When I upload code with commented out part related to this sensor/communication line it works without problem. When the USART2 is not commented code compile, upload but not works. No any response from STM.

My code consist of 3 files:
main.cpp:

#include <Arduino.h>
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetICMP.h>
#include <Timers.h>
#include <PubSubClient.h>
#include <HardwareSerial.h>
#include <Aj_sr04m.h>

// Define pins for the W5500
#define W5500_CS_PIN PA4                           // CS chip select
#define W5500_RST_PIN PB0                          // RST reset
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; // MAC address
EthernetClient ethClient;
// Ping
SOCKET pingSocket = 0;
EthernetICMPPing ping(pingSocket, (uint16_t)random(0, 255));
IPAddress gatewayIP; // Variable to store the gateway IP
IPAddress mqttServerIP(192, 168, 1, 12);
// Serials
HardwareSerial DebugSerial(USART1);
HardwareSerial jsn1Serial(USART2);
HardwareSerial jsn2Serial(USART3);
// Timers
Timer checkConnTimer;
Timer measurementsUpdateTimer;
void connectToEthernet();
void maintainDHCP();
void checkConnEthernet();
bool pingCheckConn(IPAddress ipAddr);
void checkConnMqtt();
void connectToMqtt();
void mqttCallback(char *topic, byte *payload, unsigned int length);

// Aj_sr04m jsn1(&jsn1Serial, 4, 5);
Aj_sr04m jsn2(&jsn2Serial, 4, 5);

/////////////////////
// MQTT
PubSubClient mqttClient(mqttServerIP, 1883, mqttCallback, ethClient);

// Config
int checkConnInterval = 1000;
int measurementsUpdateInterval = 2000;
void setup()
{
  delay(500);
  DebugSerial.begin(115200);
  DebugSerial.println("Setup starting...");
  // jsn1.Setup();
  jsn2.Setup();
  pinMode(W5500_RST_PIN, OUTPUT); // Initialize W5500 Reset pin
  digitalWrite(W5500_RST_PIN, HIGH);
  delay(100);
  digitalWrite(W5500_RST_PIN, LOW); // Reset pulse
  delay(100);
  digitalWrite(W5500_RST_PIN, HIGH);
  // Initialize Ethernet with DHCP
  Ethernet.init(W5500_CS_PIN); // Set the CS pin for W5500
  checkConnTimer.begin(checkConnInterval);
  measurementsUpdateTimer.begin(measurementsUpdateInterval);
  DebugSerial.println("Setup done!");
}
void loop()
{
  if (checkConnTimer.available())
  {
    checkConnEthernet();
    checkConnTimer.restart();
  }
  if (measurementsUpdateTimer.available())
  {
    // DebugSerial.print("CH1: ");
    // DebugSerial.print(jsn1.Read());
    // DebugSerial.print(" || ");
    // DebugSerial.print(jsn1.IsArrFull());
    // DebugSerial.print(" || F: ");
    // DebugSerial.print(jsn1.GetCounter());
    // DebugSerial.print(" || Avg: ");
    // DebugSerial.print(jsn1.GetAverage());
    // DebugSerial.println();

    delay(500);

    DebugSerial.print("CH2: ");
    DebugSerial.print(jsn2.Read());
    DebugSerial.print(" || ");
    DebugSerial.print(jsn2.IsArrFull());
    DebugSerial.print(" || F: ");
    DebugSerial.print(jsn2.GetCounter());
    DebugSerial.print(" || Avg: ");
    DebugSerial.print(jsn2.GetAverage());
    DebugSerial.println();
    measurementsUpdateTimer.restart();
  }
  // mqttClient.loop();
}
void checkConnEthernet()
{
  // DebugSerial.print("ETH status: ");
  switch (Ethernet.linkStatus())
  {
  case LINK_ON:
    // DebugSerial.print(" Link ON || ");
    if (!pingCheckConn(gatewayIP)) // if no logical connection
    {
      DebugSerial.println("Ping Failed || Reconnecting");
      connectToEthernet();
    }
    else
    {
      DebugSerial.println("Ping isGood || Maintain DHCP");
      // maintainDHCP();
      // checkConnMqtt();
    }
    break;
  case LINK_OFF:
    // DebugSerial.println("Link OFF || Waiting for Link up");
    break;
  case UNKNOWN:
    DebugSerial.println("Unknown No communication to module");
    break;
  default:
    break;
  }
}

void checkConnMqtt()
{
  DebugSerial.println(pingCheckConn(mqttServerIP));
  DebugSerial.print("Mqtt state: ");
  DebugSerial.print(mqttClient.connected());
  DebugSerial.print(" || ");
  DebugSerial.println(mqttClient.state());
  if (!mqttClient.connected()) // the one which always return false
  {
    DebugSerial.println("Reconecting MQTT");
    // connectToMqtt();
  }
}

void connectToEthernet()
{
  DebugSerial.println("Attempting to connect to Ethernet...");
  // Attempt to configure via DHCP
  if (Ethernet.begin(mac) == 0)
  {
    DebugSerial.println("Failed to configure Ethernet using DHCP.");
  }
  else
  {
    // DHCP configuration successful; get the gateway IP
    gatewayIP = Ethernet.gatewayIP();
    DebugSerial.print("Connected! IP Address: ");
    DebugSerial.println(Ethernet.localIP());
    DebugSerial.print("Gateway IP: ");
    DebugSerial.println(gatewayIP);
    // connectToMqtt();
  }
}

void connectToMqtt()
{
  // mqtt
  // mqttClient.begin("192.168.1.12", 1883, ethClient);
  DebugSerial.println("Connecting to MQTT...");
  String clientId = "tank-" + String(random(0xffff), HEX);
  if (mqttClient.connect(clientId.c_str(), "********", "********"))
  {
    DebugSerial.println("MQTT Connected successfully.");
    mqttClient.publish("/hello", "world");
  }
  else
  {
    DebugSerial.print("Failed to connect to MQTT, error: ");
    DebugSerial.println(mqttClient.state());
  }
}

// Function to check logical connection by pinging the gateway
bool pingCheckConn(IPAddress ipAddr)
{
  EthernetICMPEchoReply echoReply = ping(ipAddr, 4);
  if (echoReply.status == PING_SUCCESS)
  {
    DebugSerial.println("Ping succeeded");
    return true;
  }
  else
  {
    DebugSerial.println("Ping failed");
    return false;
  }
}
void maintainDHCP()
{
  switch (Ethernet.maintain())
  {
  case 1:
    DebugSerial.println("Error: renewed fail"); // renewal failed
    break;
  case 2:
    DebugSerial.println("Renewed success"); // renewed success
    DebugSerial.print("IP address: ");
    DebugSerial.println(Ethernet.localIP());
    break;
  case 3:
    DebugSerial.println("Error: rebind fail"); // rebind fail
    break;
  case 4:
    DebugSerial.println("Rebind success"); // rebind success
    DebugSerial.print("IP address: ");
    DebugSerial.println(Ethernet.localIP());
    break;
  default:
    break;
  }
}

void mqttCallback(char *topic, byte *payload, unsigned int length)
{
  // Handle incoming messages here (if needed)
  DebugSerial.print("Mqtt message comes: ");
  DebugSerial.print(topic);
  DebugSerial.print(" || ");
  for (int i = 0; i < length; i++)
  {
    DebugSerial.print(payload[i]);
  }
  DebugSerial.println();
}

Aj_sr04m.h

#ifndef Aj_sr04m_H
#define Aj_sr04m_H

#include <Arduino.h>
#include <HardwareSerial.h>
#include <array> // Include for std::array

class Aj_sr04m
{
private:
    HardwareSerial *_serial; // Pointer to HardwareSerial
    int _mode;
    float _result;
    bool _isArrFull;
    int _arrSize;
    int _dataInArrCounter;
    std::vector<float> _dataArray; // Dynamic array using vector

    void sendRequestCmd();
    std::array<unsigned char, 4> readAnswer();
    bool checkIfDataCorrupted(const std::array<unsigned char, 4> &dataBuffer);
    void parseData(const std::array<unsigned char, 4> &dataBuffer);
    void updateArr();

public:
    // Constructor
    Aj_sr04m(HardwareSerial *serial, int mode, int arrSize);

    // Methods
    float Read();
    bool IsArrFull();
    void Setup();
    float GetAverage();
    int GetCounter();
};

#endif

Aj_sr04m.cpp

#include <Aj_sr04m.h>
#include <HardwareSerial.h>

// Constructor
Aj_sr04m::Aj_sr04m(HardwareSerial *serial, int mode, int arrSize)
    : _serial(serial), _mode(mode), _arrSize(arrSize)
{
    _result = 0;
    _isArrFull = false;
    _dataInArrCounter = 0;
}

// Methods
float Aj_sr04m::Read()
{
    sendRequestCmd();
    delay(6);
    auto data = readAnswer();
    if (!checkIfDataCorrupted(data)) // proceed only if data not corrupted
    {
        parseData(data);
        updateArr();
    }
    return _result;
}

void Aj_sr04m::sendRequestCmd()
{
    _serial->write(0x01);
}

std::array<unsigned char, 4> Aj_sr04m::readAnswer()
{
    std::array<unsigned char, 4> dataBuffer = {0};
    if (_serial->available() > 0)
    {
        if (_serial->read() == 0xFF)
        {
            dataBuffer[0] = 0xFF;
            for (int ii = 1; ii < 4; ii++)
            {
                unsigned long start = millis();
                while (_serial->available() == 0)
                {
                    if (millis() - start > 10)
                    {
                        // Timeout after 10ms
                        return dataBuffer;
                    }
                }
                dataBuffer[ii] = _serial->read();
            }
        }
    }
    return dataBuffer;
}

bool Aj_sr04m::checkIfDataCorrupted(const std::array<unsigned char, 4> &dataBuffer)
{
    unsigned char checksum;
    // compute checksum
    checksum = dataBuffer[0] + dataBuffer[1] + dataBuffer[2];
    // compare computed checksum to recived one
    return checksum != dataBuffer[3];
}

void Aj_sr04m::parseData(const std::array<unsigned char, 4> &dataBuffer)
{
    _result = (dataBuffer[1] << 8) + dataBuffer[2];
}

void Aj_sr04m::updateArr()
{
    _dataArray[_dataInArrCounter] = _result;
    _dataInArrCounter++;
    if (_dataInArrCounter >= _arrSize)
    {
        _dataInArrCounter = 0;
        _isArrFull = true;
    }
}

float Aj_sr04m::GetAverage()
{
    if (_dataInArrCounter == 0 && !_isArrFull)
    {
        return 0; // No data available yet
    }

    int accumulator = 0;
    if (!_isArrFull)
    {
        for (byte i = 0; i < _dataInArrCounter; i++)
        {
            accumulator = accumulator + _dataArray[i];
        }
        return (float)accumulator / _dataInArrCounter;
    }
    else
    {
        for (byte i = 0; i < _arrSize; i++)
        {
            accumulator = accumulator + _dataArray[i];
        }
        return (float)accumulator / _arrSize;
    }
}

bool Aj_sr04m::IsArrFull()
{
    return _isArrFull;
}

int Aj_sr04m::GetCounter()
{
    return _dataInArrCounter;
}

void Aj_sr04m::Setup()
{
    _serial->begin(9600); // Initialize serial connection
    // Resize _dataArray based on arrSize, enforcing a maximum size of 256
    _dataArray.resize(_arrSize > 256 ? 256 : _arrSize);
}

What pins did you use for USART2 and USART3?

According to the STM Errata for the F103C8T6 :
STM32F10xx8 STM32F10xxB Errata there is a problem with USART and SPI under some circumstances. Check out Section 2.3 GPIO.

Some people experienced problems with counterfeit chips, see comments: Stackexchange Bluepill

Which board did you select?

Some more clues maybe here: Arduino_Core_STM32 Wiki

Maybe try the Arduino IDE, as some have indicated that plattform.io behaves somewhat differently: STM32 multiple serial

This sounds like your problem: DanLL post

@b707 For usart2 I'm using PA2 and PA3 pins, current state is that I keep one communication on library and usart2 one in main cpp in function.

I will take a look in free time what @bergernetch send and try fix it. Maybe there is hardware initiation issue.