Decoding SENT output signal from MLX90366 sensor using Arduino UNO

I am using MLX90366 magneto-resistive sensor to measure the rotation angle of a motor. The sensor uses SENT(SAE J2716 Protocol) signal for communication. I have no idea how to decode this signal nor can I find any libraries for it.

I will attach the frame format it uses provided in its documentation. Is there any way to decode this using any available libraries? I can integrate it with Matlab/simulink , but I cannot find any suitable libraries for decoding SENT data.

if you intend to process the data using matlab/simulink what is the UNO for?
connect the device directly to your PC?
ask for assistance on the Matlab forum

It's not because I want to process it in MATLAB, I just need a solution on how to process it so that I can get the angle value i need from the sensor. I need to process it in UNO, it is not clear to me how exactly I can do that.

found this thread that has a sample code to read this protocol and this other link to send it. Hopefully you can make it work for your purpose! :wink:

Good Luck!

1 Like

looking at the timing of the SENT protocol I doubt if a UNO is fast enough - possibly a Arduino Due or a ESP32 may be
a web search for Head Automotive Interface4 Sent SAE J2716-CAN gives plenty of links, e.g. 48-automotive-interface-4
Edit: thinking again - I would probably use an FPGA to interface to this protocol

It seems that automotive sensors are not that common in arduino world.

A first step is to decode the bitstream. For this you need to measure the time between falling edges and convert it to binary.

Hook the sensor up to an logic analyzer and take a look at what the sensor spits out.

This video shows how to decode a captured sent frame:

I will update this thread as soon as I get back to work on my sensor and get any result. Thank you for the replies and help.

I used this code to decode the SENT signal for my mlx sensor, thanks to @Rintin . You can refer to this thread and also this thread .

// Connect data pin of sensor to D8 of the Arduino Uno/Nano/Mini
// Change based on the tick time for your component
// Time for one tick (in µs)
constexpr uint8_t tick_time = 3;

constexpr auto serial_baud = 115200;

/************************************************************/

constexpr uint8_t tick_syn = 56;
constexpr uint8_t tick_offest = 12;

constexpr uint16_t cycl_tick = F_CPU / 1000000 * tick_time; // CPU cycles per tick

// Allow +/- 20% difference
constexpr uint16_t cycl_syn_min = cycl_tick * tick_syn * 4 / 5;
constexpr uint16_t cycl_syn_max = cycl_tick * tick_syn * 6 / 5;

constexpr auto LOOKUP_SIZE = 256;
constexpr auto LOOKUP_DIV = 4;

uint16_t cycl_syn;
uint16_t cycl_offset;
int8_t cycl_lookup[LOOKUP_SIZE];

constexpr uint8_t BUFFER_SIZE = 32;

volatile uint16_t buffer[BUFFER_SIZE];
volatile uint8_t buffer_write_pointer;
volatile uint8_t buffer_read_pointer;

uint16_t last_icr = 0;
volatile bool error = false;
ISR(TIMER1_CAPT_vect) {
  uint16_t value = ICR1;
  buffer[buffer_write_pointer] = value - last_icr;
  last_icr = value;

  buffer_write_pointer++;
  if (buffer_write_pointer >= BUFFER_SIZE) {
    buffer_write_pointer = 0;
  }
  if (buffer_write_pointer == buffer_read_pointer) {
    error = true;
  }
}

bool buffer_available() {
  return buffer_write_pointer != buffer_read_pointer;
}

uint16_t buffer_read() {
  while (!buffer_available()) {
    // wait for data
  }
  uint16_t ret = buffer[buffer_read_pointer];
  auto new_p = buffer_read_pointer + 1;
  if (new_p >= BUFFER_SIZE) {
    new_p = 0;
  }

  uint8_t oldSREG = SREG;
  cli();
  buffer_read_pointer = new_p;
  SREG = oldSREG;

  return ret;
}

uint16_t get_syn_cycl() {
  while (true) {
    uint16_t dx = buffer_read();
    if (dx >= cycl_syn_min && dx <= cycl_syn_max) {
      return dx;
    }
  }
}

void wait_for_syn() {
  while (true) {
    uint16_t dx = buffer_read();
    auto t = dx > cycl_syn ? dx - cycl_syn : cycl_syn - dx;
    if ( t < 10) {
      return;
    }
  }
}

void setup() {
  Serial.begin(serial_baud);
  Serial.print("cycl_tick = ");
  Serial.println(cycl_tick);

  TCCR1A = 0;
  TCCR1B = 1;
  TCCR1C = 0;

  TIMSK1 = (1 << ICIE1);

  cycl_syn = get_syn_cycl();
  cycl_offset = cycl_syn * (tick_offest * 2 - 1) / tick_syn / 2; // cycl_tick * 11.5

  for (uint16_t c = 0; c < LOOKUP_SIZE; c++) {
    int8_t value = c * tick_syn * LOOKUP_DIV / cycl_syn;
    if ( value >= 16) {
      value = -1;
    }
    cycl_lookup[c] = value;
  }

  auto cycl_syn1 = get_syn_cycl();
  auto dx = cycl_syn > cycl_syn1 ? cycl_syn - cycl_syn1 : cycl_syn1 - cycl_syn;

  Serial.print("cycl_syn = ");
  Serial.println(cycl_syn);

  Serial.print("cycl_syn ok? ");
  Serial.println(dx < 10 ? "yes" : "no");

  Serial.print("cycl_offset = ");
  Serial.println(cycl_offset);

  if (LOOKUP_SIZE < (cycl_syn * 17 / tick_syn / LOOKUP_DIV)) {
    Serial.println("Lookup table would exceed expected size!");
    while (true) {
      ;
    }
  }

  Serial.println("Lookup table:");
  for (int x = 0; x < 16; x++) {
    Serial.print(x * 16, HEX);
    Serial.print(": ");
    for (int y = 0; y < 16; y++) {
      Serial.print(cycl_lookup[x * 16 + y], HEX);
      Serial.print(" ");
    }
    Serial.println("");
  }
  Serial.println("************************");
  Serial.flush();
  error = false;
}

constexpr char toHex[] = "0123456789ABCDEF";
void loop() {
  constexpr auto FRAME_SIZE = 8;
  char frame[FRAME_SIZE + 1];

  wait_for_syn();
  for (int c = 0; c < FRAME_SIZE; c++) {
    auto dx = buffer_read();
    dx = (dx - cycl_offset) / LOOKUP_DIV;
    if (dx > LOOKUP_SIZE || cycl_lookup[dx] < 0) {
      frame[c] = '!';
    } else {
     frame[c] = cycl_lookup[dx];
    }
  }
  Serial.write(frame, FRAME_SIZE);
  Serial.println("");
// decimalValue is the angle, wrt the frame format for mlx90366 sensor
//int decimalValue = (frame[1] << 8) | (frame[2] << 4) | frame[3];
//Serial.println(decimalValue); // Comment the rest of serial prints to directly print the angle

if (error) {
// I commented this if condition, since it was operating properly without this.
Serial.println("Buffer overflow");
    while (true) {
   ;
    }
  }
}

The output should look similar to this:

cycl_tick = 48
cycl_syn = 2699
cycl_syn ok? yes
cycl_offset = 554
Lookup table:
0: 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1
10: 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
20: 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3
30: 3 4 4 4 4 4 4 4 4 4 4 4 4 5 5 5
40: 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6
50: 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 7
60: 7 8 8 8 8 8 8 8 8 8 8 8 8 9 9 9
70: 9 9 9 9 9 9 9 9 9 A A A A A A A
80: A A A A A B B B B B B B B B B B
90: B C C C C C C C C C C C C D D D
A0: D D D D D D D D D E E E E E E E
B0: E E E E E F F F F F F F F F F F
C0: F FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
E0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF


030FEFC7
030FF0C3
030FF1C1
030EF2C3
030FF3C5
830EF4CF
030FF5C9
C30FF6CF
C30FF7CD
C30FF8CE
C30FF9CC
830FFACA
C30FFBC8
030FFCC6
030FFDC4
030FFEC2
030FFFC0
030F00C9
031001C3
030F02CD
831003C7

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.