2023-01-24 04:36 AM - last edited on 2023-11-30 06:41 AM by Amel NASRI
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
Solved! Go to Solution.
2023-01-24 07:39 AM
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--;
}
}
2023-01-24 07:39 AM
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--;
}
}
2023-09-20 01:46 AM
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