UM7 UART stopped working aftrer register writes

I’m using UM7 IMU and I think I accidentally changed a UART-related register setting, and now I cannot communicate with the sensor over UART at all.

Previously, I successfully received UM7 data packets over UART. I wrote code to change settings UM7 register writes to switch toward quaternion mode. After running that code, UART communication stopped completely.

Current symptoms

Redshift cannot connect (tiimeout error)
No data reception

Is there a code-based recovery method to restore UART communication force factory reset if the baud rate / COM settings were misconfigured?

Below is the code I ran:

#include <Arduino.h>
#include <math.h>

static const int IMU_RX_PIN = 38;
static const int IMU_TX_PIN = 39;

// UART 1
HardwareSerial IMU(1);

struct Um7Packet {
  uint8_t addr;
  uint8_t packet;
  uint8_t data_len;
  uint8_t data[64];
};

static uint8_t rx_buffer[512];
static size_t  rx_len = 0;

// -------------------------
// RX parser (unchanged)
// -------------------------
static bool try_parse_one_packet(uint8_t* buf, size_t len, Um7Packet& out, size_t& bytes_to_discard) {
  bytes_to_discard = 0;
  if (len < 7) return false;

  // Search for header 's' 'n' 'p' (0x73 0x6E 0x70)
  size_t i = 0;
  for (; i + 2 < len; i++)
    if (buf[i] == 's' && buf[i + 1] == 'n' && buf[i + 2] == 'p') break;

  // No header found -> Discard all
  if (i + 2 >= len) { bytes_to_discard = len; return false; }

  // Header found but not enough bytes
  if (len - i < 7) { bytes_to_discard = i; return false; }

  uint8_t packet = buf[i + 3];
  uint8_t addr   = buf[i + 4];

  bool has_data = (packet >> 7) & 0x01;
  bool is_batch = (packet >> 6) & 0x01;

  // batch length (register count)
  uint8_t batch_len = (packet >> 2) & 0x0F;

  size_t data_len = 0;
  if (has_data) data_len = is_batch ? (4 * (size_t)batch_len) : 4;

  // 'snp'(3) + packet(1) + addr(1) + data + checksum(2)
  size_t packet_len = 7 + data_len;

  // Full packet not yet received
  if (len - i < packet_len) { bytes_to_discard = i; return false; }

  // Verify checksum (16-bit sum)
  uint16_t sum = (uint16_t)('s' + 'n' + 'p' + packet + addr);
  for (size_t k = 0; k < data_len; k++) sum += buf[i + 5 + k];

  uint16_t rx_ck = ((uint16_t)buf[i + 5 + data_len] << 8) | buf[i + 6 + data_len];

  // Checksum mismatch -> shift by one byte and try again
  if (sum != rx_ck) {
    bytes_to_discard = i + 1;
    return false;
  }

  // Fill output packet structure
  out.packet   = packet;
  out.addr     = addr;
  out.data_len = (uint8_t)data_len;

  for (size_t k = 0; k < data_len && k < sizeof(out.data); k++)
    out.data[k] = buf[i + 5 + k];

  // Confirmed processed bytes
  bytes_to_discard = i + packet_len;
  return true;
}

// -------------------------
// UM7 TX helpers (added)
// -------------------------
static inline uint8_t make_pt(bool hasData, bool isBatch, uint8_t batchLen) {
  // PT bits: [7]=HasData, [6]=IsBatch, [5:2]=BatchLen, [1]=Hidden(0), [0]=CF(0)
  return (uint8_t)((hasData ? 0x80 : 0x00) |
                   (isBatch ? 0x40 : 0x00) |
                   ((batchLen & 0x0F) << 2));
}

static void um7_send_packet(uint8_t pt, uint8_t addr, const uint8_t* data, size_t data_len) {
  // 's''n''p' + PT + ADDR + DATA + CK1 + CK0
  uint16_t sum = (uint16_t)('s' + 'n' + 'p' + pt + addr);
  for (size_t i = 0; i < data_len; i++) sum += data[i];

  IMU.write((uint8_t)'s');
  IMU.write((uint8_t)'n');
  IMU.write((uint8_t)'p');
  IMU.write(pt);
  IMU.write(addr);

  if (data_len > 0) IMU.write(data, data_len);

  IMU.write((uint8_t)(sum >> 8));
  IMU.write((uint8_t)(sum & 0xFF));
}

static void um7_write_reg32(uint8_t addr, uint32_t value) {
  // Non-batch write: HasData=1, IsBatch=0, data_len=4
  uint8_t pt = make_pt(true, false, 0);
  uint8_t data[4] = {
    (uint8_t)(value >> 24),
    (uint8_t)(value >> 16),
    (uint8_t)(value >> 8),
    (uint8_t)(value >> 0)
  };
  um7_send_packet(pt, addr, data, 4);
}

// -------------------------
// Quaternion (replaces RPY)
// -------------------------
static float qa = 0, qb = 0, qc = 0, qd = 1;
static uint32_t last_print_ms = 0;

void setup() {
  Serial.begin(115200);
  delay(500);
  Serial.println("USB SERIAL OK");

  IMU.begin(115200, SERIAL_8N1, IMU_RX_PIN, IMU_TX_PIN);
  Serial.println("IMU UART started");

  delay(200);

  // 1) Quaternion mode ON: CREG_MISC_SETTINGS (0x08) bit1 = 1
  // NOTE: This overwrites other bits in 0x08 (we'll improve later with read-modify-write).
  um7_write_reg32(0x08, (1u << 1));

  // 2) Quaternion telemetry rate: CREG_COM_RATES5 (0x05)
  // B3=QUAT_RATE, B2=EULER_RATE, B1=POSITION_RATE, B0=VELOCITY_RATE
  // 10 = 50 Hz (datasheet table)
  uint32_t rates5 = ((uint32_t)10 << 24); // QUAT_RATE=50Hz, others=0
  um7_write_reg32(0x05, rates5);

  Serial.println("UM7 configured: quaternion mode + QUAT_RATE=50Hz");
}

void loop() {
  // Fill RX buffer (prevent overflow)
  while (IMU.available() && rx_len < sizeof(rx_buffer)) {
    rx_buffer[rx_len++] = (uint8_t)IMU.read();
  }

  // Reset buffer if full without valid packet
  if (rx_len == sizeof(rx_buffer))
    rx_len = 0;

  // Parse as many packets as possible
  while (true) {
    Um7Packet p;
    size_t bytes_to_discard = 0;
    bool ok = try_parse_one_packet(rx_buffer, rx_len, p, bytes_to_discard);

    // Remove processed invalid bytes and shift buffer
    if (bytes_to_discard > 0) {
      memmove(rx_buffer, rx_buffer + bytes_to_discard, rx_len - bytes_to_discard);
      rx_len -= bytes_to_discard;
    }

    if (!ok) break;

    // Quaternion batch starts at 0x6D (DREG_QUAT_AB) and typically includes CD (+TIME)
    // Need at least 8 bytes for AB+CD.
    if (p.addr == 0x6D && p.data_len >= 8) {
      int16_t a_raw = (int16_t)((p.data[0] << 8) | p.data[1]);
      int16_t b_raw = (int16_t)((p.data[2] << 8) | p.data[3]);
      int16_t c_raw = (int16_t)((p.data[4] << 8) | p.data[5]);
      int16_t d_raw = (int16_t)((p.data[6] << 8) | p.data[7]);

      const float Q_SCALE = 29789.09091f;
      qa = (float)a_raw / Q_SCALE;
      qb = (float)b_raw / Q_SCALE;
      qc = (float)c_raw / Q_SCALE;
      qd = (float)d_raw / Q_SCALE;

      // Optional: normalize (numerical stability)
      float n = sqrtf(qa*qa + qb*qb + qc*qc + qd*qd);
      if (n > 1e-6f) { qa /= n; qb /= n; qc /= n; qd /= n; }
    }
  }

  // Print at 50Hz (every 20ms)
  uint32_t now = millis();
  if (now - last_print_ms >= 20) {
    last_print_ms = now;
    Serial.printf("Quat(a,b,c,d): %.5f, %.5f, %.5f, %.5f\n", qa, qb, qc, qd);
  }
}

Hello.

I moved your post to a more appropriate section of the forum.

You could use the “RESET_TO_FACTORY” device to return the device to the factory settings; however, I do not expect that to be helpful if you cannot successfully communicate with the device. Are you able to connect to it through the Redshift Serial Interface software using a USB-to-TTL-serial adapter?

Could you post more details about your setup (such as what microcontroller board you are using) and post some pictures that show all of your connections?

Brandon