Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(uart): support UART Tx Rx pin swap function #2601

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

fronders
Copy link

This enables UART Tx and Rx pin swap function on STM32 families that support it (F0, L0, L4, G0, G4, H7 etc.)

In order to enable pin swap, user just needs to swap the pins either when declaring HardwareSerial object:

//                      RX    TX
HardwareSerial Serial1(PA10, PA9); // uses normal pins
//                      RX    TX
HardwareSerial Serial1(PA9, PA10); // uses swapped pins

or by using setTx() and setRx() methods:

Serial1.setRx(PA9);  // normally it is a Tx pin
Serial1.setTx(PA10); // normally it is a Rx pin
Serial1.begin(9600);

If the chip does not support the swap, or the pins are incorrect, the library behaves the same way as before (throws an error for invalid pins).

The cool thing is that it even supports half-duplex mode on the normally Rx pin - the Rx pin is used for transmission and reception then. User can either use Rx == Tx trick as before or just provide a single pin definition

Fixes: #2538
See also: #1418

@fpistm fpistm marked this pull request as ready for review December 11, 2024 19:58
@fronders
Copy link
Author

Hi @fpistm, I'm finishing testing at the moment with different STM32 chips and will report back as soon as I'm done and things are ready to be merged :)

@fronders
Copy link
Author

@fpistm I've finished testing on multiple ST families Nucleo-64 boards. Code works as intended and is ready for merging!

In case you want to test yourself here's my sketch:

#include <Arduino.h>

#define __XSTR(a) __STR(a)
#define __STR(a) #a

// #define USE_HALFDUPLEX

// Define serials with normal pins order
//                       RX    TX
HardwareSerial Serial4(PC11, PC10);
#ifdef USE_HALFDUPLEX
//                       TX
HardwareSerial Serial5(PC12);
#else
//                      RX    TX
HardwareSerial Serial5(PD2, PC12);
#endif

// Send from USB to SerialTx, then via wires to SerialRx and then back to USB
#define SerialTx Serial5
#define SerialRx Serial4

int lastButtonState;

void setup() {
  pinMode(USER_BTN, INPUT);
  Serial.begin(115200);
  if (digitalRead(USER_BTN) == LOW) {
    // Button held on startup - enable SerialTx pinswap
#ifdef USE_HALFDUPLEX
    SerialTx.setTx(PD2);
    SerialTx.setHalfDuplex();
#else
    SerialTx.setTx(PD2);
    SerialTx.setRx(PC12);
#endif
  }
  SerialTx.begin(9600);
  SerialRx.begin(9600);
  Serial.printf("%s: pin swap %s, half duplex %s\r\n", __XSTR(SerialTx),
    READ_BIT(SerialTx.getHandle()->Instance->CR2, USART_CR2_SWAP) ? "enabled" : "disabled",
    SerialTx.isHalfDuplex() ? "enabled" : "disabled");
  Serial.println("How to use:");
  Serial.printf("Button released USB->%s->%s->USB\r\n", __XSTR(SerialTx), __XSTR(SerialRx));
  Serial.printf("Button pressed  USB->%s->%s->USB\r\n", __XSTR(SerialRx), __XSTR(SerialTx));
  lastButtonState = digitalRead(USER_BTN);
}

void loop() {
  int buttonState = digitalRead(USER_BTN);
  if (buttonState) {
    // Forward transmission SerialTx->SerialRx
    if (!lastButtonState) {
#ifdef USE_HALFDUPLEX
      // Just switched, enable half-duplex receiver
      SerialTx.enableHalfDuplexRx();
#endif
      Serial.printf("\r\nButton released: USB->%s->%s->USB\r\n", __XSTR(SerialTx), __XSTR(SerialRx));
    }
    if (Serial.available()) {      // If anything comes in Serial (USB),
      SerialTx.write(Serial.read());   // read it and send it out SerialTx
    }
    if (SerialRx.available()) {     // If anything comes in SerialRx
      Serial.write(SerialRx.read());   // read it and send it out Serial (USB)
    }
  } else {
    // Reverse transmission SerialRx->SerialTx
    if (lastButtonState) {
#ifdef USE_HALFDUPLEX
      // Just switched, enable half-duplex receiver
      SerialTx.enableHalfDuplexRx();
#endif
      Serial.printf("\r\nButton pressed  USB->%s->%s->USB\r\n", __XSTR(SerialRx), __XSTR(SerialTx));
    }
    if (Serial.available()) {      // If anything comes in Serial (USB),
      SerialRx.write(Serial.read());   // read it and send it out SerialTx
    }
    if (SerialTx.available()) {     // If anything comes in SerialRx
      Serial.write(SerialTx.read());   // read it and send it out Serial (USB)
    }
  }
  lastButtonState = buttonState;
}

So I would do the following:

  1. Connect UART4 and UART5 with two wires (Rx to Tx and Tx to Rx)
  2. Send stuff over ST-Link's USB COM port and observe it being received back
  3. Hold the button to reverse the direction and send/observe again
  4. Reset the board while holding the button to enable pin swap
  5. Swap the wires (Rx to Rx and Tx to Tx) and test again
  6. Enable half-duplex by uncommenting the define
  7. Flash and test again, this time it needs more wire swapping to match all 4 cases

@fpistm fpistm self-requested a review December 17, 2024 09:56
@fpistm fpistm added the enhancement New feature or request label Dec 17, 2024
@fpistm
Copy link
Member

fpistm commented Dec 17, 2024

Hi @fronders,

thanks for the PR, will try to review it this week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: In progress
Development

Successfully merging this pull request may close these issues.

UART Tx/Rx Pin Swap
2 participants