RAK3172 Serial (UART2) dying after prolonged use

Hi there,

I posted this forum post a few months back as I was experiencing trouble with uploading Arduino IDE sketches to a RAK3172 on a custom PCB (schematic linked below, same as previous post). I swapped out the board for another one and the issues went away - Arduino BSP worked fine, Arduino sketch uploaded properly (quite a few times) and I was getting proper uplinks with TTN. I thought the issues I was facing with the Arduino BSP / Serial were isolated incidents due to a bad board.

Fast forward to today and I was attempting to upload a modified version of my sketch (which I will attach below) and the Arduino BSP failed with “failed to get baudrate”. Not only that but the Serial is unresponsive to AT commands. However strangely enough reflashing the RAK3172 via the STM32CubeProgrammer as per this guide works every time (but still no Serial response to AT commands). This essentially puts me back in the same situation as my first post. As such, I felt it was worthwhile to reopen this issue as this seems to be a systematic problem. It seems to me that repeated flashing of the RAK3172 using the Arduino BSP is somehow messing up its internals and causing it to fail in the long-run (I lack experience in computer engineering to describe this precisely but you get the point).

What I have tried:

  • Replacing the RAK3172 board entirely
  • Bypassing the CH340C on my PCB and using an external FTDI adapter
  • Reflashing using STM32CubeProgrammer with latest image (RAK3172-E_latest_final.hex)
  • Putting the RAK3172 into boot mode first before uploading via ArduinoIDE

What I may try

  • I purchased a RAK3272 breakout board and so I will observe if a similar thing happens to it since if it does it will rule out my custom PCB being the culprit.
  • Remove the GPS module on UART1. Perhaps that is somehow conflicting with UART2?

Just throwing this out there so that anyone who experiences this same problem can chime in so that I can figure out if this problem is unique to my setup or a general problem.



#include <TinyGPS++.h>
TinyGPSPlus gps;

#define OTAA_BAND     (RAK_REGION_AS923)
#define OTAA_DEVEUI   {xxx}
#define OTAA_APPEUI   {xxx} 
#define OTAA_APPKEY   {xxx} //keys removed for privacy reasons
#define OTAA_PERIOD   900000 //interval for device to wake up and send data to TTN
#define GPS_GRACE_PERIOD 5000 //grace period for GPS to get readings
uint8_t message[64] = { 0 };

uint64_t last = 0;

long latDec; //latDec = lattitude * 100000
long longDec; //longDec = longitude * 100000
uint8_t altDec = 0; //altDec = altitude * 1000
unsigned int battery; //battery = voltage * 100

boolean GPSFlag = true;
boolean batteryFlag = false;

uint8_t latIsNegative;
uint8_t longIsNegative;
uint8_t latArray[3] = {0, 0, 0};
uint8_t longArray[3] = {0, 0, 0};
uint8_t altArray[2] = {0, 0};

void recvCallback(SERVICE_LORA_RECEIVE_T * data)
  if (data->BufferSize > 0) {
    Serial.println("Something received!");
    for (int i = 0; i < data->BufferSize; i++) {
      Serial.printf("%x", data->Buffer[i]);
void joinCallback(int32_t status)
  Serial.printf("Join status: %d\r\n", status);

void sendCallback(int32_t status)
  if (status == 0) {
    Serial.println("Successfully sent");
  } else {
    Serial.println("Sending failed");

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200, RAK_DEFAULT_MODE);
  Serial1.begin(9600, RAK_CUSTOM_MODE);


  pinMode(PA0, OUTPUT);
  pinMode(PB4, INPUT);
  pinMode(PA8, INPUT_PULLUP);
  api.system.sleep.setup(RUI_WAKEUP_FALLING_EDGE, PA8);

  // OTAA Device EUI MSB first
  uint8_t node_device_eui[8] = OTAA_DEVEUI;
  // OTAA Application EUI MSB first
  uint8_t node_app_eui[8] = OTAA_APPEUI;
  // OTAA Application Key MSB first
  uint8_t node_app_key[16] = OTAA_APPKEY;
  if (!api.lorawan.appeui.set(node_app_eui, 8)) {
    Serial.printf("LoRaWan OTAA - set application EUI is incorrect! \r\n");
  if (!api.lorawan.appkey.set(node_app_key, 16)) {
    Serial.printf("LoRaWan OTAA - set application key is incorrect! \r\n");
  if (!api.lorawan.deui.set(node_device_eui, 8)) {
    Serial.printf("LoRaWan OTAA - set device EUI is incorrect! \r\n");

  if (!api.lorawan.band.set(OTAA_BAND)) {
    Serial.printf("LoRaWan OTAA - set band is incorrect! \r\n");
  if (!api.lorawan.deviceClass.set(RAK_LORA_CLASS_A)) {
    Serial.printf("LoRaWan OTAA - set device class is incorrect! \r\n");
  if (!api.lorawan.njm.set(RAK_LORA_OTAA))  // Set the network join mode to OTAA
    ("LoRaWan OTAA - set network join mode is incorrect! \r\n");
  if (!api.lorawan.join())  // Join to Gateway
    Serial.printf("LoRaWan OTAA - join fail! \r\n");

  /** Wait for Join success */
  while (api.lorawan.njs.get() == 0) {
    Serial.print("Wait for LoRaWAN join...");

  if (!api.lorawan.adr.set(true)) {
    ("LoRaWan OTAA - set adaptive data rate is incorrect! \r\n");
  if (!api.lorawan.rety.set(1)) {
    Serial.printf("LoRaWan OTAA - set retry times is incorrect! \r\n");
  if (!api.lorawan.cfm.set(1)) {
    Serial.printf("LoRaWan OTAA - set confirm mode is incorrect! \r\n");
  Serial.printf("Duty cycle is %s\r\n", api.lorawan.dcs.get() ? "ON" : "OFF"); // Check Duty Cycle status
  Serial.printf("Packet is %s\r\n", api.lorawan.cfm.get() ? "CONFIRMED" : "UNCONFIRMED"); // Check Confirm status
  uint8_t assigned_dev_addr[4] = { 0 };
  api.lorawan.daddr.get(assigned_dev_addr, 4);
  Serial.printf("Device Address is %02X%02X%02X%02X\r\n", assigned_dev_addr[0], assigned_dev_addr[1], assigned_dev_addr[2], assigned_dev_addr[3]);  // Check Device Address
  Serial.printf("Uplink period is %ums\r\n", OTAA_PERIOD);
void uplink_routine()
  /** Payload of Uplink */
  uint8_t data_len = 0;
  message[data_len++] = (uint8_t) latIsNegative;
  message[data_len++] = (uint8_t) latArray[0];
  message[data_len++] = (uint8_t) latArray[1];
  message[data_len++] = (uint8_t) latArray[2];
  message[data_len++] = (uint8_t) longIsNegative;
  message[data_len++] = (uint8_t) longArray[0];
  message[data_len++] = (uint8_t) longArray[1];
  message[data_len++] = (uint8_t) longArray[2];
  message[data_len++] = (uint8_t) altArray[0];
  message[data_len++] = (uint8_t) altArray[1];
  message[data_len++] = (uint8_t) battery;

  Serial.println("Data Packet:");
  for (int i = 0; i < data_len; i++) {
    Serial.printf("0x%02X ", message[i]);

  /** Send the data package */
  if (api.lorawan.send(data_len, (uint8_t *) & message, 2, true, 1)) {
    Serial.println("Sending is requested");
  } else {
    Serial.println("Sending failed");
void loop() {

      GPSFlag = false;
      Serial.println("Turn the GPS ON");
      digitalWrite(PA0, LOW);
      Serial.println("GPS is ready");
      delay(7000); //wait 7s for the GPS to boot up
    // Simulate the collection of data:
    //latDec = 12345678; //latDec = lattitude * 100000
    //longDec = 12345678; //longDec = longitude * 100000
    //altDec = 200 //altDec = altitude*1000
    //battery = 100; //battery = voltage / 3.3 * 100
    while (Serial1.available() > 0) {
      //char c = Serial1.read();
      if (gps.encode(Serial1.read())) {
        if (gps.location.isValid()) {
          latDec = gps.location.lat() * 100000;
          longDec = gps.location.lng() * 100000;
          altDec = gps.altitude.meters()*1000;
          latIsNegative = (latDec < 0) ? 1 : 0;
          longIsNegative = (longDec < 0) ? 1 : 0;
          convert(abs(latDec), 1, 0);
          convert(abs(longDec), 2, 0);
          convert(altDec, 3, 0);
          Serial.println("GPS Coordinates: ");
          Serial.print("Lattitude: "); Serial.print(latDec); Serial.print(", Longitude: "); Serial.print(longDec); Serial.print(". Alt: "); Serial.print(altDec);
        } else {
          Serial.println("GPS is present but no valid coordinates!");
      } else {
        Serial.println("No valid GPS found");
      battery = analogRead(PB4) / 930 * 100;
      Serial.print("Battery: "); Serial.println(battery);  
      batteryFlag = false;

  if(millis()-last > OTAA_PERIOD + GPS_GRACE_PERIOD){
      last = millis();
      Serial.println("Turn the GPS OFF");
      digitalWrite(PA0, HIGH);
      Serial.print("Going to sleep for "); Serial.print(OTAA_PERIOD); Serial.println(" ms");
      GPSFlag = true;
      batteryFlag = true;

void convert(long number, int flag, int index) {
  if (number >= 256) convert(round(number / 256), flag, index + 1);
  if (flag == 1) {
    latArray[index] = number % 256;
  } else if (flag == 2) {
    longArray[index] = number % 256;
  }else if(flag == 3){
    altArray[index] = number %256;

Hi @RCPilot1604 ,

Can you try to execute at+run command? Also, one more thing you can try is to upload RUI3 previous stable firmware version v3.5.1.

You can upload the hex file using same approach via STM32CubeProgrammer guide.

Hi @carlrowan,

Serial is unresponsive to at+run.

I tried uploading the following files:

All to no avail. The Serial is still unresponsive to AT+RUN and other AT commands.

Perhaps I will detail my exact steps for flashing the RAK3172:

  1. Connecting BOOT0 to +3V3 via jumper
  2. Plug FTDI adapter into computer USB
  3. Connect via STM32CubeProgrammer (UART)
  4. Download firmware
  5. Disconnect from STM32CubeProgrammer (UART)
  6. Unplug FTDI adapter from computer USB
  7. Disconnect BOOT0 from +3V3 via jumper
  8. Plug FTDI adapter back into computer USB
  9. Open Arduino IDE Serial Monitor to test Serial

Maybe I am making a mistake in this process of flashing the firmware to the board? I have attached a screenshot of the STM32CubeProgrammer if that helps.

Thanks to everyone in helping me solve this strange problem.

Indeed strange @RCPilot1604 ,

Can you try to upload this again RUI_3.5.1_RAK3172-E.hex then execute at+run not AT+RUN. Sorry for not being specific about this. I just want to validate you are in bootloader mode but just can’t jump on the right memory location. Doing at+run should show some replies.

I uploaded RUI_3.5.1_RAK3172-E.hex and tried sending at+run. In boot mode (BOOT0 connected to +3V3), I got the following reply:

In non-boot mode (BOOT0 not connected to +3V3), I got no response.

Thanks once again.

Hi @RCPilot1604 ,

I think you are missing the carrier return as shown in the image.


Hi @carlrowan

I tried changing it to Both NL & CR but still same response:

Also tried using the RAK Serial Port Tool to no avail.

I never encountered this with my RAK3172 units. Let me forward this to the RUI3 R&D team.

Can you help me confirm the trail on the firmware of this device so I can give more info to the team?

  • (What is the original FW when you received the device?) Is it 3.4.2 based on your old post?
  • (Did you update) Is it 3.5.3 as you said on your previous post.
  • Did the issue occur on 3.4.2 or only started on 3.5.3?
  • Is 3.5.1 the last firmware uploaded as I suggested?

Hi @carlrowan ,

  • I wasn’t able to get the original firmware of the boards because they were initially unresponsive to serial AT commands (I had to flash them with the firmware here before it started responding).
  • In my previous post, I used the firmware files from here. I am not sure what version it was but I assumed it was the latest. I will try flashing 3.5.3 downloaded from here.
    I am assuming you are referring to the RAK3172 FW and not the ArduinoBSP version.
  • The issue occurred on both 3.4.2 and 3.5.3 (I am referring to the ArduinoBSP version). As mentioned earlier I flashed the RAK3172 with the OS found here so I have no clue which version the firmware was. I also did not think of getting the firmware version using AT+VER)
  • As of now, 3.5.1 is the latest firmware uploaded.


Out of curiosity, I decided to try flashing all versions of RUI firmware and testing AT commands on serial. It turns out that flashing RUI_3.5.2_RAK3172-E.hex caused the serial interface to start responding to AT commands again.

However I am still unable to get the Arduino BSP to work as it shows the following error:

Hi @RCPilot1604 ,

RAK3172 will go to boot mode via AT+BOOT, you can get out of bootloader mode via at+run.

Thank you for providing the details. Btw, if you can share me the code that causes the issue (you can also send via private message), I will run it on my RAK3172 and see if I can duplicate. Hopefully I can. It will be helpful for the RUI3 team.