Skip to content

TPMS BMW R1200 #1585

Description

@techmike78

Good day.

I have been working on a project for a long time on esp32s3+cc1101 for decoding readings from BMW motorcycle pressure sensors.
I managed to get the required values ​​using rtl_433, but I can't do the same using esp32+cc1101, I only get garbage at the receiver output.
Most likely, I didn't select the reception parameters correctly, but trying out setBitRate, setFrequencyDeviation and setRxBandwidth didn't give any result.
I ask the community for help, because my programming level and knowledge are not high enough for this.

An example of receiving data using rtl_433:


time : 2025-09-01 10:53:09
model : BMW count : 1 num_rows : 1 rows :
len : 45 data : 058639002248 id : 2c31c8
Pressure : 4 Temp_F : 73 F
codes : {45}058639002248


The latest code for Arduino (Platformio):

/*

rtl_433 -X 'name=BMW,m=OOK_MC_ZEROBIT,s=122,l=122,r=300,preamble=7fff,get=id:@3:{24}:%x,get=pressure:@27:{9}:%d,get=temp:@36:{9}:%d' -f 433.92M

-f 433.92M        - received frequency
name=BMW
m=OOK_MC_ZEROBIT - On-Off Keying with Manchester Code and a fixed leading zero bit.
s=122            - The expected duration of a "short" pulse or half-bit width in microseconds (µs).
l=122            - The expected duration of a "long" pulse or full-bit width in microseconds (µs
r=300            - The expected duration of a reset gap in microseconds (µs)
preamble=7fff

*/
#include <Arduino.h>
#include <RadioLib.h>
#include <SPI.h>

// https://github.com/jgromes/RadioLib/wiki/Debug-mode
//#define RADIOLIB_DEBUG_BASIC        (1)   // basic debugging (e.g. reporting GPIO timeouts or module not being found)
// #define RADIOLIB_DEBUG_PROTOCOL     (1)   // protocol information (e.g. LoRaWAN internal information)
// #define RADIOLIB_DEBUG_SPI          (1)   // verbose transcription of all SPI communication - produces large debug logs!

// https://github.com/jgromes/RadioLib/blob/master/examples/CC1101/CC1101_Receive_Interrupt/CC1101_Receive_Interrupt.ino
/*
esp32s3 super mini cc0111 connection spi pin
SCK - 4
MISO - 5
MOSI - 6
SS - 7
SCL/CSN -9
*/

#define CC1101_MISO 5
#define CC1101_MOSI 6
#define CC1101_SCKL 4
#define CC1101_CS 9

#define CC1101_GDO0 7
#define CC1101_GDO2 10

SPIClass newSPI(HSPI);

CC1101 radio = new Module(CC1101_CS, CC1101_GDO0, RADIOLIB_NC, CC1101_GDO2, newSPI);
// CC1101 radio = new Module(CC1101_CS, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC, newSPI);

// flag to indicate that a packet was received
volatile bool receivedFlag = false;
// this function is called when a complete packet
// is received by the module
// IMPORTANT: this function MUST be 'void' type
//            and MUST NOT have any arguments!
#if defined(ESP8266) || defined(ESP32)
  ICACHE_RAM_ATTR
#endif
void setFlag(void) {
  // we got a packet, set the flag
  receivedFlag = true;
}

void printhex(int h) {
  if (h<16) {
    Serial.print("0");
  }
  Serial.print(h,HEX);
}

byte mc_Arr[255];   // array for Manchester bytes
// https://github.com/cterwilliger/tst_tpms/blob/main/examples/CC1101_tpms_recv_example.ino#L216
/*
 * decodeManI
 * ----------
 * Manchester I (IEEE 802.3) bitstream decoder
 * Manchester encoded bit stream uses 2 bits to represent 1 bit of data.  Manchester I encodes a "1" as a transition 
 * from low to high and "0" as a transition from high to low.  Each byte decodes to 1 nibble.
 */
void decodeManI(byte *array, int size)
{ 
    // array of all possible Manchester I values
    byte manIarray[16] = {0xAA, 0xA9, 0xA6, 0xA5, 0x9A, 0x99, 0x96, 0x95, 0x6A, 0x69, 0x66, 0x65, 0x5A, 0x59, 0x56, 0x55};
    int k = 0;

    // convert each Manchester I byte to it's NRZ equivalent
    for ( int i = 0; i < size; i=i+2 ) // look at every 2 bytes in the payload
    {
        for ( int j = 0; j < 16; j++ )
        {
            if ( array[i] == manIarray[j] ) // search for ManI pattern
            {
                array[k] = j << 4; // shift left one nibble, put back into passed array
            }
        } 

        for ( int j = 0; j < 16; j++ )
        {
            if ( array[i+1] == manIarray[j] )
            {
                array[k] = array[k] | j; // combine previous nibble with this one
            }
        }
        k++;
    }

} // end decodeManI

void setup()
{
  delay(6000);
	Serial.begin(115200);
  Serial.setDebugOutput(true);
  delay(1000);
  Serial.println(F("Starting... "));
  delay(1000);

  Serial.print(F("[CC1101] Initializing ... "));

	//spi.begin();
  newSPI.begin(CC1101_SCKL, CC1101_MISO, CC1101_MOSI, CC1101_CS);
	
  // int state = radio.begin(433.92);
  int state = radio.begin();
  if (state == RADIOLIB_ERR_NONE)
  {
      Serial.println(F("success!"));
      Serial.print(F("[CC1101] Partnumber ")); Serial.println(radio.SPIgetRegValue(0x30), HEX);
      Serial.print(F("[CC1101] Version ")); Serial.println(radio.getChipVersion(), HEX);
  }
  else
  {
      Serial.print(F("failed: code "));
      Serial.println(state);
      // while (true);
  }

  float frequency = 433.92;
  // float frequency = 433.919830;
  if (radio.setFrequency(frequency) == RADIOLIB_ERR_INVALID_FREQUENCY) {
    Serial.println(F("[CC1101] Selected frequency is invalid for this module!"));
    while (true);
  } else {
    Serial.print(F("[CC1101] setFrequency [MHz] ")); Serial.println(frequency);
  }
  // float bitrate = 19.2;  // 19200 baud
    float bitrate = 9.6;  // 9600 baud
  state = radio.setBitRate(bitrate);
  if (state == RADIOLIB_ERR_INVALID_BIT_RATE) {
    Serial.println(F("[CC1101] Selected bit rate is invalid for this module!"));
    while (true);
  } else if (state == RADIOLIB_ERR_INVALID_BIT_RATE_BW_RATIO) {
    Serial.println(F("[CC1101] Selected bit rate to bandwidth ratio is invalid!"));
    Serial.println(F("[CC1101] Increase receiver bandwidth to set this bit rate."));
    while (true);
  } else {
    Serial.print(F("[CC1101] setBitRate [kbps] ")); Serial.println(bitrate);
  }
  // float bandwidth = 135.0;
  // if (radio.setRxBandwidth(bandwidth) == RADIOLIB_ERR_INVALID_RX_BANDWIDTH) {
  //   Serial.println(F("[CC1101] Selected receiver bandwidth is invalid for this module!"));
  //   while (true);
  // } else {
  //   Serial.print(F("[CC1101] setBandwidth [kHz] ")); Serial.println(bandwidth);
  // }
  radio.autoSetRxBandwidth();

  byte syncHigh = 0x7F; byte syncLow = 0xFF;
   radio.SPIwriteRegister(0x04, syncHigh); Serial.print(F("[CC1101] Reg0x04 SetSyncHigh ")); Serial.println(syncHigh);
   radio.SPIwriteRegister(0x05, syncLow); Serial.println(F("[CC1101] Reg0x05 SetSyncLow ")); Serial.println(syncLow);

  radio.setEncoding(RADIOLIB_ENCODING_MANCHESTER);    // for transmitt encodeind

  // set the function that will be called
  // when new packet is received
  radio.setGdo0Action(setFlag, CHANGE);

  // set the function that will be called
  // when new packet is received
  radio.setPacketReceivedAction(setFlag);

  // test cc1101 spi work
  radio.SPIwriteRegister(0, 0x29);
  delay(500);
  if (radio.SPIreadRegister(0) == 0x29)
  {
    Serial.println(F("CC1101 reset successful"));
  }else{
    Serial.println(F("CC1101 reset failed. Try rebooting"));
  }

    radio.setOOK(true);   // OOK is on
    radio.setFrequency(433.92);
    radio.setBitRate(9.6);
    radio.setFrequencyDeviation(50);
    radio.setRxBandwidth(125);
    radio.setCrcFiltering(false);
    
    //radio.setSyncWord(0x7F, 0xFF, 1, true);
    //radio.fixedPacketLengthMode(16);
    radio.disableAddressFiltering();
    radio.disableSyncWordFiltering();

  // start listening for packets
  Serial.print(F("[CC1101] Starting to listen ... "));
  state = radio.startReceive();
  if (state == RADIOLIB_ERR_NONE) {
    Serial.println(F("success!"));
  } else {
    Serial.print(F("failed, code "));
    Serial.println(state);
    while (true) { delay(10); }
  }

  Serial.println(F("Started!"));
  delay(5000);
}

void loop (void)
{
  delay(1);
  
    // check if the flag is set
  if(receivedFlag) {
    bool print_debug=1;
    bool find_pre=0;

    // you can also read received data as byte array
    int len = radio.getPacketLength();
    byte byteArr[len+1];
    int state = radio.readData(byteArr, len);

    if (print_debug==1){

      memset(mc_Arr,'\0',sizeof(mc_Arr)); //обнуляем все данные внутри структуры
      memcpy(mc_Arr, byteArr, len); // переносим данные в буфер для отправки
      // decode manchester I
      decodeManI(mc_Arr, 16);

      Serial.print(len); Serial.print("; ");
      Serial.print(radio.getRSSI());
      Serial.print("; ");
      Serial.print(radio.getLQI());
      Serial.print("; ");

      // print data of the packet
      for (int i=0; i<len; i++) {
        printhex(byteArr[i]);
      }
      Serial.println();
   
      Serial.print("MC: ");
      // print data of the MC packet
      for (int i=0; i<len; i++) {
        printhex(mc_Arr[i]);
      }
      Serial.println();

    }

    
    // BMW tpms preamble
    if (byteArr[0]==0x7F && byteArr[1]==0xFF ){
      // https://github.com/merbanan/rtl_433/blob/master/src/devices/tpms_bmw_g3.c
      Serial.println("BMW header finded !");
      find_pre=1;
    }

    for (int i=0; i<len; i++) {
      if (byteArr[i]==0x7F && byteArr[i+1]==0xFF){
        Serial.println("FINDED !!!");
        find_pre=1;
      }
    }

    if (find_pre==1){
      Serial.print(len); Serial.print("; ");
      Serial.print(radio.getRSSI());
      Serial.print("; ");
      Serial.print(radio.getLQI());
      Serial.print("; ");

      // print data of the packet
      for (int i=0; i<len; i++) {
        printhex(byteArr[i]);
      }
      Serial.println();

    }
    find_pre=0;

    // put module back to listen mode
    radio.startReceive();

    // reset flag
    receivedFlag = false;
  }

}

Data output when receiving readings from the sensor:

Starting...
[CC1101] Initializing ... success!
[CC1101] Partnumber 0
[CC1101] Version 14
[CC1101] setFrequency [MHz] 433.92
[CC1101] setBitRate [kbps] 9.60
[CC1101] Reg0x04 SetSyncHigh 127
[CC1101] Reg0x05 SetSyncLow
255
CC1101 reset successful
[CC1101] Starting to listen ... success!
Started!
152; -135.00; 6; 001F9F9E1F99FFFE67F99F9FF87FE7867E78667E01861F86061F8666187F99E19E1866067FFE1F99879E61F807F99E0660181E0601E7E7E61E7F9E1FFF9F818181001F9F9E1F99FFFE67F99F9FF87FE7867E78667E01861F86061F8666187F99E19E1866067FFE1F99879E61F807F99E0660181E0601E7E7E61E7F9E1FFF9F8181001F9F9E1F99FFFE67F99F9FF87FE7867E78667E01861F
MC: 001F9F9E1F99FFFE67F99F9FF87FE7867E78667E01861F86061F8666187F99E19E1866067FFE1F99879E61F807F99E0660181E0601E7E7E61E7F9E1FFF9F818181001F9F9E1F99FFFE67F99F9FF87FE7867E78667E01861F86061F8666187F99E19E1866067FFE1F99879E61F807F99E0660181E0601E7E7E61E7F9E1FFF9F8181001F9F9E1F99FFFE67F99F9FF87FE7867E78667E01861F
102; -73.50; 31; 67F879FE607E01F9980181FE7E6799F8618001F879E7E1FE67E7FE0619FE079819FE799806019FE7878607879E1800AE43DA0FE8493FFF9E7FFFFE18679FF8F88167F879FE607E01F9980181FE7E6799F8618001F879E7E1FE67E7FE0619FE079819FE799806
MC: 67F879FE607E0150980181FE7E6799F8618001F879E7E1FE67E7FE0619FE079819FE799806019FE7878607879E1800AE43DA0FE8493FFF9E7FFFFE18679FF8F88167F879FE607E01F9980181FE7E6799F8618001F879E7E1FE67E7FE0619FE079819FE799806
FINDED !!!
102; -73.50; 31; 67F879FE607E01F9980181FE7E6799F8618001F879E7E1FE67E7FE0619FE079819FE799806019FE7878607879E1800AE43DA0FE8493FFF9E7FFFFE18679FF8F88167F879FE607E01F9980181FE7E6799F8618001F879E7E1FE67E7FE0619FE079819FE799806

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions