Using two serial ports + USB Serial on WeAct BlackPill (STM32F411CE)

Post here first, or if you can't find a relevant section!
Post Reply
Tokyo_Dom
Posts: 4
Joined: Sat May 16, 2026 4:14 pm

Using two serial ports + USB Serial on WeAct BlackPill (STM32F411CE)

Post by Tokyo_Dom »

I have a WeAct Studio Black Pill (STM32F411CE).

I am trying to port this Arduino project to run on it: https://github.com/dbloemhard/Arduino-T ... or-ELRS3.x

Arduino only has one Serial port, so i used #defines to switch between debug data sent to Serial Monitor, and serial with the ExpressLRS transmitter module. And now I want to take advantage of there being 3 serial ports on the F411 :
1 Serial port to communicate with the ExpressLRS transmitter module (Serial1 on PB6/PB7)
1 Serial port to receive SBUS data from a head tracking device (Serial2 on PA2/PA3)
1 USB Serial so that debug data is fed to a com port that can be read by my PC (Serial? Or Serial6?)

But i am confused about the hardware serial implementation in the STMDuino core https://github.com/stm32duino/Arduino_C ... wareserial and the
And the Tools/USB Support and Tools U(S)ART Support options in the IDE.

Is it possible to use all 3 UARTs, and feed one of them through the USB port? If so, how would this be implemented?
by ag123 » Thu May 21, 2026 5:31 pm
welcome,

for usb-serial, choose Tools > USB support > CDC Generic 'Serial' supercede U(S)ART

You still have those Serial1, Serial2, Serial3 for your UART
https://github.com/stm32duino/Arduino_C ... wareserial

To bridge data between USB and UART , codes usually looks like

Code: Select all

void setup() {

	Serial.begin(); // USB
	Serial1.begin(115200); 
	Serial2.begin(115200);
	
	pinMode(LED_BUILTIN, OUTPUT);

}

void loop() {
	// copy usb to uart
	if (Serial.available()) {
		while(Serial.available()) {
			int c = Serial.read();
			Serial1.write(c);
			Serial2.write(c);
			// blink the led for traffic optional
			digitalWrite(LED_BUILTIN, ! digitalRead(LED_BUILTIN));
		}
	}
	// copy serial1 to usb
	if (Serial1.available()) {
		while(Serial1.available()) {
			int c = Serial1.read();
			Serial.write(c);
			// blink the led for traffic optional
			digitalWrite(LED_BUILTIN, ! digitalRead(LED_BUILTIN));			
		}
	}
	// copy serial2 to usb
	if (Serial2.available()) {
		while(Serial2.available()) {
			int c = Serial2.read();
			Serial.write(c);
			// blink the led for traffic optional
			digitalWrite(LED_BUILTIN, ! digitalRead(LED_BUILTIN));			
		}
	}
	// turn off led, check the schematics, this assume led is active low, i.e. the led sink VDD 3.3 into the pin e.g. PC13)
	digitalWrite(LED_BUILTIN, HIGH);
}

hope it helps

this would 'mix up' the traffic, i.e. 2 uart into/out of 1 usb (virtual) com port, you could optionally comment / remove one block of codes, e.g. that from / to one of the SerialN.
Or you could improve the codes, make your own scheme / protocol etc, to tell one from another.
e.g.
https://www.modbustools.com/modbus.html
this would take programming on the firmware (stm32) and the client s/w
Go to full post
ag123
Posts: 1976
Joined: Thu Dec 19, 2019 5:30 am
Answers: 32

Re: Using two serial ports + USB Serial on WeAct BlackPill (STM32F411CE)

Post by ag123 »

welcome,

for usb-serial, choose Tools > USB support > CDC Generic 'Serial' supercede U(S)ART

You still have those Serial1, Serial2, Serial3 for your UART
https://github.com/stm32duino/Arduino_C ... wareserial

To bridge data between USB and UART , codes usually looks like

Code: Select all

void setup() {

	Serial.begin(); // USB
	Serial1.begin(115200); 
	Serial2.begin(115200);
	
	pinMode(LED_BUILTIN, OUTPUT);

}

void loop() {
	// copy usb to uart
	if (Serial.available()) {
		while(Serial.available()) {
			int c = Serial.read();
			Serial1.write(c);
			Serial2.write(c);
			// blink the led for traffic optional
			digitalWrite(LED_BUILTIN, ! digitalRead(LED_BUILTIN));
		}
	}
	// copy serial1 to usb
	if (Serial1.available()) {
		while(Serial1.available()) {
			int c = Serial1.read();
			Serial.write(c);
			// blink the led for traffic optional
			digitalWrite(LED_BUILTIN, ! digitalRead(LED_BUILTIN));			
		}
	}
	// copy serial2 to usb
	if (Serial2.available()) {
		while(Serial2.available()) {
			int c = Serial2.read();
			Serial.write(c);
			// blink the led for traffic optional
			digitalWrite(LED_BUILTIN, ! digitalRead(LED_BUILTIN));			
		}
	}
	// turn off led, check the schematics, this assume led is active low, i.e. the led sink VDD 3.3 into the pin e.g. PC13)
	digitalWrite(LED_BUILTIN, HIGH);
}

hope it helps

this would 'mix up' the traffic, i.e. 2 uart into/out of 1 usb (virtual) com port, you could optionally comment / remove one block of codes, e.g. that from / to one of the SerialN.
Or you could improve the codes, make your own scheme / protocol etc, to tell one from another.
e.g.
https://www.modbustools.com/modbus.html
this would take programming on the firmware (stm32) and the client s/w
Tokyo_Dom
Posts: 4
Joined: Sat May 16, 2026 4:14 pm

Re: Using two serial ports + USB Serial on WeAct BlackPill (STM32F411CE)

Post by Tokyo_Dom »

Hi! And thanks for the explanation. So I can think of it like this: The "Serial" is the one that goes to USB (virtual), and Serial1/Serial2 are the com ports going to the actual STM UARTs.

Just trying this now, but i am getting a compile error.

Code: Select all

C:/Users/tokyodom/AppData/Local/Arduino15/packages/STMicroelectronics/tools/xpack-arm-none-eabi-gcc/14.2.1-1.1/bin/../lib/gcc/arm-none-eabi/14.2.1/../../../../arm-none-eabi/bin/ld.exe: C:\Users\tokyodom\AppData\Local\arduino\cores\25798f7135ec24e7978629365a7a97a3\core.a(HardwareSerial.cpp.o):(.bss.Serial1+0x0): multiple definition of `Serial1'; C:\Users\tokyodom\AppData\Local\arduino\sketches\D25F0A21588097169B4513AC9DAF3C8D\sketch\STMpleTX.ino.cpp.o:(.bss.Serial1+0x0): first defined here
collect2.exe: error: ld returned 1 exit status
exit status 1

Compilation error: exit status 1
If i comment out the Serial1 define

Code: Select all

//HardwareSerial Serial1(PB7, PB6);
HardwareSerial Serial2(PA3, PA2);

void setup() {
    ...
    Serial.begin(115200);
    Serial1.begin(SERIAL_BAUDRATE, SERIAL_8N1);
    Serial2.begin(100000); // SBUS Input
}
then it compiles, but not actually sure if this works for all three ports, nor why i am commenting out one of the serial ports to get it to compile.
Tokyo_Dom
Posts: 4
Joined: Sat May 16, 2026 4:14 pm

Re: Using two serial ports + USB Serial on WeAct BlackPill (STM32F411CE)

Post by Tokyo_Dom »

Unfortunately i cannot make my own scheme for this since the devices i am interfacing with are fixed in their function.

Actually the ELRS module on Serial1 is already using the modbus protocol (called CRSF after the company that originated it). It would support having multiple devices on the same port, each with their own address. So, i could potentially make a client on the PC to read messages on that port, but i do like the convenience of using serial port monitor :D
ag123
Posts: 1976
Joined: Thu Dec 19, 2019 5:30 am
Answers: 32

Re: Using two serial ports + USB Serial on WeAct BlackPill (STM32F411CE)

Post by ag123 »

the defines are mostly in the variant files
https://github.com/stm32duino/Arduino_C ... L_F411CE.h
https://github.com/stm32duino/Arduino_C ... F411CE.cpp
https://github.com/stm32duino/Arduino_C ... L_F411CE.c

the various HardwareSerial are defined here:
https://github.com/stm32duino/Arduino_C ... ial.h#L200

hence, some of the definitions e.g. Serial, Serial1 are 'default' if the variant defines them.
you could test Serial2, Serial3 though, if using Serial2, Serial3 errors when you don't define them in your sketch, then most likely you need to define/configure it in the sketch.

it is quite possible to 'convert' that by programming your sketch, e.g. if you use the same protocol (modbus?) and kind of connect the same pheripheral to the same port, then when funneling that to the usb port, you could add the headers. But it'd still take some programming on the client / app side to work with that.

messing with usb (driver) is feasible, but normally is 'beyond beginners' and you can kind of make it appear like 3 'virtual com' ports if you bother to go the distance. That is normally not 'basic' arduino style programming, i.e. rework the usb device driver e.g. Serial().
--
note, there are also stuff like such
https://wiki.archlinux.org/title/USB/IP
https://usbip.sourceforge.net/
https://github.com/jtornosm/USBIP-Virtual-USB-Device
https://github.com/lcgamboa/USBIP-Virtual-USB-Device
https://github.com/cezanne/usbip-win
https://github.com/vadimgrn/usbip-win2

but I've not played with it, that'd still (likely) require programming on the client/host side and if it works in e.g. windows / linux etc.
Tokyo_Dom
Posts: 4
Joined: Sat May 16, 2026 4:14 pm

Re: Using two serial ports + USB Serial on WeAct BlackPill (STM32F411CE)

Post by Tokyo_Dom »

To close the loop here, i have it working now. The only odd thing is that Serial1 is already defined, which means i cannot define it myself (or it will result in a compile error). I did want to do my own definition to keep the code looking clean, but the following code works and outputs to the respective pins, as well as the usb serial port

Code: Select all

#include <Arduino.h>
//HardwareSerial Serial1(PB7, PB6);
HardwareSerial Serial2(PA3, PA2);
uint32_t lastMicros = micros();

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

    Serial1.setRx(PB7);
    Serial1.setTx(PB6);
    Serial1.begin(9600);

    Serial2.setRx(PA3);
    Serial2.setTx(PA2);
    Serial2.begin(9600);
}

void loop() {
  if (lastMicros - micros() > 1000) {
    Serial.print("Serial current Micros: ");
    Serial.println(micros());
    Serial1.print("Serial1 current Micros: ");
    Serial1.println(micros());
    Serial2.print("Serial2 current Micros: ");
    Serial2.println(micros());
    lastMicros = micros();
  }
}
USB Support is set to CDC (generic 'Serial' supersede U(S)ART)
U(S)ART Support is set to Enabled (generic 'Serial')
Post Reply

Return to “General discussion”