Skip to main content
Pieter Conradie
Associate III
January 24, 2023
Solved

STM32WL (SX1262) vs S2-LP (CC1101) data whitening algorithm incompatible?

  • January 24, 2023
  • 2 replies
  • 2617 views

Hi there!

 

We are developing a new STM32WL based product that must be compatible with the existing STM32L0 + S2-LP products.

 

It appears that the GFSK data whitening algorithm is different(?). I used an SDR dongle to sniff the raw bytes transmitted over the air.

 

A 4 byte packet is transmitted with the following content (in HEX; before data whitening):

PREAMBLE: 55 55 55 55

SYNC: 93 0B 51 DE

LEN: 04

DATA: AA BB CC DD

 

The packet transmitted over the air by the S2-LP is (after data whitening):

PREAMBLE: 55 55 55 55

SYNC: 93 0B 51 DE

LEN: FB

DATA: 4B A6 56 30

 

The packet transmitted over the air by the STM32WL is (after data whitening):

PREAMBLE: 55 55 55 55

SYNC: 93 0B 51 DE

LEN: FB

DATA: 2D 03 95 6A

 

So the LEN field is correct but the DATA is different. I have looked at section 7.10 of the S2-LP datasheet and section 6.2.3.4 of the SX1261/2 datasheet but can't figure out the difference.

 

The STM32WL whitening seed is set to 0x1FF (alll ones) with:

SUBGRF_SetWhiteningSeed(0x01FF);

 

Are the two data whitening algorithms different? Can it be fixed?

 

Thanks in advance,

Pieter

https://piconomix.com

This topic has been closed for replies.
Best answer by Pieter Conradie

OK, I've answered my own question :)

The relevant info is contained in NXP AN5070 "Implementing Data Whitening and CRC Verification in Software in Kinetis KW01 Microcontrollers":

https://www.nxp.com/docs/en/application-note/AN5070.pdf

The S2-LP implements the IBM whitening algorithm. The STM32WL implements the CCITT whitening algorithm. You must apply both algorithms on the data to be transmitted and then the receive side will de-whiten it correctly (4 XOR operation during the whole process)... see whiten_fix() below.

Here's my C code implementation:

uint8_t reverse_u8(uint8_t data)
{
	data = (data & 0xf0) >> 4 | (data & 0x0f) << 4;
	data = (data & 0xcc) >> 2 | (data & 0x33) << 2;
	data = (data & 0xaa) >> 1 | (data & 0x55) << 1;
	return data;
}
 
void whiten_ibm(uint8_t * data, size_t nr_of_bytes)
{
	uint16_t key = 0x1ff;
	uint16_t msb;
 
	while (nr_of_bytes != 0)
	{
		*data++ ^= key & 0xff;
		for (int i = 0; i < 8; i++)
		{
			msb = ((key >> 5) & 0x01) ^ ((key >> 0) & 0x01);
			key >>= 1;
			key |= msb << 8;
		}
		nr_of_bytes--;
	}
}
 
void whiten_ccitt(uint8_t* data, size_t nr_of_bytes)
{
	uint16_t key = 0x1ff;
	uint16_t msb;
 
	while (nr_of_bytes != 0)
	{
		*data++ ^= reverse_u8(key & 0xff);
		for (int i = 0; i < 8; i++)
		{
			msb = ((key >> 5) & 0x01) ^ ((key >> 0) & 0x01);
			key >>= 1;
			key |= msb << 8;
		}
		nr_of_bytes--;
	}
}
 
void whiten_fix(uint8_t* data, size_t nr_of_bytes)
{
	uint16_t key = 0x1ff; // Seed is all ones
	uint16_t msb;
 
	while (nr_of_bytes != 0)
	{
		*data ^= key & 0xff; // Apply IBM whitening
		*data ^= reverse_u8(key & 0xff); // Apply CCITT whitening
		data++;
		// Calc new key. LFSR Polynomial = x^9 + x^5 + 1
		for (int i = 0; i < 8; i++)
		{
			msb = ((key >> 5) & 0x01) ^ ((key >> 0) & 0x01);
			key >>= 1;
			key |= msb << 8;
		}
		nr_of_bytes--;
	}
}

2 replies

Pieter Conradie
Pieter ConradieAuthorBest answer
Associate III
January 24, 2023

OK, I've answered my own question :)

The relevant info is contained in NXP AN5070 "Implementing Data Whitening and CRC Verification in Software in Kinetis KW01 Microcontrollers":

https://www.nxp.com/docs/en/application-note/AN5070.pdf

The S2-LP implements the IBM whitening algorithm. The STM32WL implements the CCITT whitening algorithm. You must apply both algorithms on the data to be transmitted and then the receive side will de-whiten it correctly (4 XOR operation during the whole process)... see whiten_fix() below.

Here's my C code implementation:

uint8_t reverse_u8(uint8_t data)
{
	data = (data & 0xf0) >> 4 | (data & 0x0f) << 4;
	data = (data & 0xcc) >> 2 | (data & 0x33) << 2;
	data = (data & 0xaa) >> 1 | (data & 0x55) << 1;
	return data;
}
 
void whiten_ibm(uint8_t * data, size_t nr_of_bytes)
{
	uint16_t key = 0x1ff;
	uint16_t msb;
 
	while (nr_of_bytes != 0)
	{
		*data++ ^= key & 0xff;
		for (int i = 0; i < 8; i++)
		{
			msb = ((key >> 5) & 0x01) ^ ((key >> 0) & 0x01);
			key >>= 1;
			key |= msb << 8;
		}
		nr_of_bytes--;
	}
}
 
void whiten_ccitt(uint8_t* data, size_t nr_of_bytes)
{
	uint16_t key = 0x1ff;
	uint16_t msb;
 
	while (nr_of_bytes != 0)
	{
		*data++ ^= reverse_u8(key & 0xff);
		for (int i = 0; i < 8; i++)
		{
			msb = ((key >> 5) & 0x01) ^ ((key >> 0) & 0x01);
			key >>= 1;
			key |= msb << 8;
		}
		nr_of_bytes--;
	}
}
 
void whiten_fix(uint8_t* data, size_t nr_of_bytes)
{
	uint16_t key = 0x1ff; // Seed is all ones
	uint16_t msb;
 
	while (nr_of_bytes != 0)
	{
		*data ^= key & 0xff; // Apply IBM whitening
		*data ^= reverse_u8(key & 0xff); // Apply CCITT whitening
		data++;
		// Calc new key. LFSR Polynomial = x^9 + x^5 + 1
		for (int i = 0; i < 8; i++)
		{
			msb = ((key >> 5) & 0x01) ^ ((key >> 0) & 0x01);
			key >>= 1;
			key |= msb << 8;
		}
		nr_of_bytes--;
	}
}

Visitor II
September 20, 2023

Hi Pieter,

i have a similar problem and want to ask for more information.
Based on your example above, i am sending a string wih CC1101:

Clear:     55 55 55 55   93 0B 51 DE   04   AA BB CC DD

Whitend: 55 55 55 55   93 0B 51 DE    FB   4B A6 56 30

In you example above was the len byte with both different whitening schemes correct calculated.
In my setup is the len byte not correct calculated, means RX cannot finish.

Not sure if this issue is caused by my general setup or if i have overseen something.

Is your len byte calculated all time correct? Could you please share more information on your setup of the RX function?

Cheers, Horst