Can't get HardwareSerial Serial1(2400) working (F446RE)

Post here first, or if you can't find a relevant section!
Post Reply
killacycle
Posts: 14
Joined: Tue Nov 19, 2024 1:59 am

Can't get HardwareSerial Serial1(2400) working (F446RE)

Post by killacycle »

I can't seem to get HardwareSerial Serial1(2400) to work on my F446RE for some reason. (Won't work on Serial2 either.)

The goal is to simply listen to the data stream that my laser diameter sensor is putting out on RS-485. (2400 BAUD, 8 data, No parity, 1 Stop) I have tested the _exact_ same RS-485 board setup on a Mega just to be certain everything external to the F446RE is correct and fully functional. I even tried exchanging the Rx and Tx pins to be sure that wasn't the issue. No bueno. :-(

I'm sure it is something simple that I have foolishly overlooked.

Here is my code:

Code: Select all

/*
 * Version 01 RS485 Laser RS-484 reading test program (with LCD added)
 * Bill Dube, Nov 24, 2024
 * Nucleo F446RE Ver 01
 * 
 */ 
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

HardwareSerial Serial1(USART1); //D10/(PB6) =TX1  PB7 = RX1

#define VER 01 
#define SERIAL_XMT 2 // DE control pin on RS 485 board
#define SERIAL_RCV 3 // RE control pin on RS 485 board

#define LCD_SCL PB8  // I2C clock pin
#define LCD_SDA PB9  // I2C data pin

LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display  
  
  byte getdata;
  int ByteCount;
  long LaserDiaReadingI =0;
  float LaserDiaReadingF;
  String DigitString, ReadingString;
  unsigned long int TimeNow;
  float SecondsElapsed;
  
void setup() {

  lcd.init();                      // initialize the lcd 
  lcd.backlight();
 
  //Using Serial1 Port for RS485, 
  // Pin PB6 (D10) TX  Connected to pin DI on RS-485 board 
  // Pin PB7 RX  Connected to pin R0 on RS-485 board 
  // (This is the opposite to what is typically shown in tutorials, but this indeed is what works.)
  
  Serial1.begin(2400);  // Serial1 port = 2400 baud, 8 data, No parity, 1 stop
  // Serial.begin(115200); // Start serial monitor port when running this on a Mega
  // Pin D2 connected to pin DE on rs485 board
  // Pin D3 connected to pin RE on rs485 board
  pinMode(SERIAL_XMT, OUTPUT);//DE Controling pin of RS-485
  pinMode(SERIAL_RCV, OUTPUT);//RE Controling pin of RS-485
  // Set DE and RE to logic LOW
  digitalWrite(SERIAL_XMT,LOW);//DE=LOW Receive Enabled M1
  digitalWrite(SERIAL_RCV,LOW);//RE=LOW Receive Enabled M1
  delay(100); // Give a bit of time for board to get its serail pins sorted...
  lcd.setCursor(0,0);  
  lcd.print("RS485 Ver= ");
  lcd.println(VER);
  delay(1000); // Pause to leave the starting splash up on the monitor for a second...
  TimeNow = millis();
} // end setup()

void loop() {

  getdata=0;
  if(Serial1.available()){ //if there is a byte is available on the RS485
    getdata=Serial1.read();
    if (getdata == 0xF1) { // We have the beginning of a reading
      ByteCount=1; // Reset the byte counter
//      lcd.setCursor(0,0);  // Time stamp stuff for using with Mega and serial monitor
//      lcd.print("Time="); 
//      SecondsElapsed = (millis() - TimeNow) / 1000.0; // divide by a float to force the type conversion
//      lcd.print(SecondsElapsed,3);
      lcd.setCursor(0,0); // Row 1 col 1
      lcd.print("Laser Reading = ");
      lcd.setCursor(0,1); // Row 1 col 2
      lcd.print("                "); // clear it out with blanks
      lcd.setCursor(0,1); // Row 1 col 2
      lcd.print(LaserDiaReadingF, 3); // Write what we get back from the laser
      ReadingString =String(""); // Clear out for a new reading
    }
    else
    {
     DigitString =String("");  // Clear out the digit string
     if (getdata < 16){
       DigitString =String(0,HEX);
     }
     //Serial.print(getdata,HEX);
     DigitString +=String(getdata,HEX);
     if (ByteCount <=3 ) { // only save first 3 bytes
       ReadingString = DigitString + ReadingString; // Put the latest data in the _front_
       ByteCount++;  // increment the byte counter
     }
     if (ByteCount == 4) {
       LaserDiaReadingI = ReadingString.toInt();
       LaserDiaReadingF = LaserDiaReadingI / 1000.0;
       ByteCount++;
     }  
    } 
  } // if Serial1 avalible
} // end loop()
by GonzoG » Mon Nov 25, 2024 11:13 am
It can't work. USART1 default pins are PA9 and PA10.
If you want to use PB6 and PB7 you need to reassign those pins:

Code: Select all

HardwareSerial Serial1(PB7,PB6);
or

Code: Select all

void setup(){
...
Serial1.setRx(PB7)
Serial1.setTx(PB6)
...
}
as USART1 should be defined by default as Serial1 if you have enabled USB CDC as "Serial"
Go to full post
killacycle
Posts: 14
Joined: Tue Nov 19, 2024 1:59 am

Re: Can't get HardwareSerial Serial1(2400) working (F446RE)

Post by killacycle »

I should note that SoftwareSerial does work. However, I hesitate to implement the serial port in software it as it may tax the CPU and grab a timer I may be trying to use. The proper way to do this is using the existing hardware USART. Seems like a kludge, actually.

The F446RE reads the RS-485 perfectly if I substitute these lines in my code, :

SoftwareSerial mySerial(PB6, PB7); // RX, TX
(I swapped RX and TX pins in software and swapped the wires in hardware. Either way works if you swap both.)

(In place of: HardwareSerial Serial1(USART1); //D10/(PB6) =TX1 PB7 = RX1 )

and....

mySerial.begin(2400); // mySerial port = 2400 baud, 8 data, No parity, 1 stop

and....

if(mySerial.available()){ //if there is a byte is available on the RS485
getdata=mySerial.read();

It is a mystery to me why it won't work in hardware....

Bill D.
GonzoG
Posts: 492
Joined: Wed Jan 15, 2020 11:30 am
Answers: 36
Location: Prudnik, Poland

Re: Can't get HardwareSerial Serial1(2400) working (F446RE)

Post by GonzoG »

It can't work. USART1 default pins are PA9 and PA10.
If you want to use PB6 and PB7 you need to reassign those pins:

Code: Select all

HardwareSerial Serial1(PB7,PB6);
or

Code: Select all

void setup(){
...
Serial1.setRx(PB7)
Serial1.setTx(PB6)
...
}
as USART1 should be defined by default as Serial1 if you have enabled USB CDC as "Serial"
fpiSTM
Posts: 1946
Joined: Wed Dec 11, 2019 7:11 pm
Answers: 108
Location: Le Mans
Contact:

Re: Can't get HardwareSerial Serial1(2400) working (F446RE)

Post by fpiSTM »

I've tested and it works at 2400.
Thanks @GonzoG to answer this.
killacycle
Posts: 14
Joined: Tue Nov 19, 2024 1:59 am

Re: Can't get HardwareSerial Serial1(2400) working (F446RE)

Post by killacycle »

I tried your pin reassignment and it works marvelously!!
Thank you so much for your prompt reply. :-)

>> Here is what led me astray <<<<
I was misled by what is apparently a misprint in the Zephyr Nucleo F446RE web page:
>>>>>>>>>>>>>>>>>>>>>>>>>
For more details please refer to STM32 Nucleo-64 board User Manual.
Default Zephyr Peripheral Mapping:
UART_1_TX : PB6
UART_1_RX : PB7
UART_2_TX : PA2
UART_2_RX : PA3
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
https://github.com/zephyrproject-rtos/z ... /index.rst

If you look at the figure above this quote, you can indeed see that the Serial1 Tx is the prime option on PA9, but is also shown as the 3rd alternate on PB6.
https://github.com/zephyrproject-rtos/z ... _right.jpg

If you scroll up to the illustration for CN7 it shows Serial1 RX as the prime option for PB7. It also shows Serial1 RX as the prime option for PB10.

Very odd. :?

Well, hopefully I have all the puzzle pieces in place now.
Again, thank you so much for your expert help. :D

Bill D.
GonzoG
Posts: 492
Joined: Wed Jan 15, 2020 11:30 am
Answers: 36
Location: Prudnik, Poland

Re: Can't get HardwareSerial Serial1(2400) working (F446RE)

Post by GonzoG »

It has nothing to do with hardware. There are no hardware defined default pins. It's just how IDE is configured.
Zephyr and stm32duino may have different default pin assignment and for Nucleo F446RE they do.

stm32duino uses PeripheralPins.c to look for pin assignment and uses first pin on the list. In case of F446RE it's in "variants\STM32F4xx\F446R(C-E)T\" and UART RX/TX pins are defined:

Code: Select all

#ifdef HAL_UART_MODULE_ENABLED
WEAK const PinMap PinMap_UART_TX[] = {
  {PA_0,       UART4,  STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)},
  {PA_2,       USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)},
  {PA_9,       USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, [u]GPIO_AF7_USART1)},
  {PB_6,       USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)},
...
  {NC,         NP,     0}
};
#endif

#ifdef HAL_UART_MODULE_ENABLED
WEAK const PinMap PinMap_UART_RX[] = {
  {PA_1,       UART4,  STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF8_UART4)},
  {PA_3,       USART2, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART2)},
  {PA_10,      USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)},
  {PB_7,       USART1, STM_PIN_DATA(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF7_USART1)},
...
  {NC,         NP,     0}
};
#endif
PA9/PA10 pins are before PB6/PB7.

In Zephyr you have:

Code: Select all

&usart1 {
	pinctrl-0 = <&usart1_tx_pb6 &usart1_rx_pb7>;
	pinctrl-names = "default";
	current-speed = <115200>;
	status = "okay";
};
Post Reply

Return to “General discussion”