Radio 2.4GHz LENGTH Field (again)

I was reading the documentation, trying to figure out something specific while reading though source code. I was looking at the LENGTH field specified in the nrf52840 PS guide 6.20 RADIO — 2.4 GHz radio. Under packet configuration section I was looking at the packet layout in memory and it sort of made sense as I read it, but then I looked for anything specific about LENGTH other than it exists. 
To quickly put my confusion away I searched up LENGTH Field Question and then I realized I didn't know what I thought I knew. 
I had sailed past this section with an understanding of the picture but no real knowledge about it.

What I believe is correct now is there are the S0, LENGTH and S1 areas that can be configured in for output the packet.
- S0 and S1 are generic bit fields that can be inserted into the outgoing stream they can be length 0 and therefore not exist. 
- LENGTH is also a generic bit field but is also variable in length and can be 0 and therefore not exist.

These ideas bring me to the following assertions:
1. All three fields can be zero length, they do not affect the transmit or receiver hardware in any way, OTHER than being automatically parsed out of the bitstream, is that correct?
2. If these fields are 0 length, they don't need to be inserted into the transmit buffer. The first bits transmitted will instantly be the payload. Is this correct?
3. The LENGTH field is named LENGTH to give and idea of where a length field could be put into the packet. Its name isn't relevant otherwise. The radio doesn't use this byte (field) for anything. Is this correct? ** this doesn't seem correct by what is said in the Linked question of the same name, and I keep getting hung up on how variable length packet output works.

If you could provide me with clarification, I would appreciate it.

Yes, I am aware of this being handled by the library, but I really want to understand the RADIO peripheral and I am a little unhappy that "LENGTH" isn't given a real good operational definition if it actually causes a change in the behavior of the radio. 
Perhaps I just blew a circuit in my brain trying to read though the operation of esb.c code.

Parents
  • Rather than answer the specific questions, maybe this code will help; The main difficulty (for me) was that the in-RAM layout is not the same as the on-air (bytes transmitted) format.

    // BLE Advertising Packet
    // ======================
    // Every packet begins with an 8 bit preamble, an alternating binary sequence. This is followed by a 32 bit access
    // address (AA) which can be thought of as a unique identifier which defines a particular connection. When a
    // device (master or slave) transmits on an advertising channel it uses a fixed value of 0x8e89bed6 as the access
    // address.
    // Following the 32 bit access address are optional S0, LENGTH and S1 fields then a variable length Protocol Data
    // Unit (PDU) which contains the message data payload. Finally all packets end with a 24 bit CRC.
    // By default, the Nordic BLE address is derived from the NRF_FICR->DEVICEADDR[] and is 48 bits in length (6 bytes)
    // If S0, LENGTH or S1 are specified with zero length their fields will be omitted in memory, otherwise each
    // field will be represented as a separate byte, regardless of the number of bits in their on-air counterpart
    // For the field sizes defined in bits, the occupation in RAM will always be rounded up to the next full byte size
    // (for instance 3 bit length will allocate 1 byte in RAM, 9 bit length will allocate 2 bytes, etc.).
    // On-air packet layout (Note Header in RAM is 3 bytes if S0INC is '1')
    // +-------------------------------------------------------------------------------------------------------------------------+
    // |                                         BLE Advertising Packet - Legacy                                                 |
    // +-------------------------------------------------------------------------------------------------------------------------+
    // |                                         1MHz: 47 octets max total length                                                |
    // +--------+-------+------------------------------------------------------------------------------------------+------+------+
    // |        |Access |                                                                                          | Add  |      |
    // |Preamble|Address|                   Protocol Data Unit PDU                                                 | On   | CRCC | Tone Ext
    // +--------+-------+------------------------------------------------------------------------------------------+------+------+
    // |   1(2) |   4   |                                    2 - 39                                                | (0)  |  3   | 16 - 160uSec
    // |        |       +-----------------+------------------------------------------------------------------------+      |      |
    // |        |       |    Header       |                  Payload                                               |      |      |
    // |        |       +-----------------+------------------------------------------------------------------------+      |      |
    // |        |       |       2         |                  0 - 37                                                |      |      |
    // |        |       +-----+-----+-----+------------------------------------------------------------------------+      |      |
    // |        |       | Opt | Opt | Opt |  MAC Addr  |     AdvData List (example 3 fields)                       |      |      |
    // |        |       | S0  | Len | S1  +------------+-----------------------------------------------------------+      |      |
    // |        |       |-----+-----+-----|    6       |     0 - 31                                                |      |      |
    // |        |       | (1) | (1) | (1) |            +-------------------+-------------------+-------------------+      |      |
    // |        |       |     |     |     |            |    AdvData Flags  |    AdvData Name   |   (AdvData Data)  |      |      |
    // |        |       |     |     |     |            +-------------------+-------------------+-------------------+      |      |
    // |        |       |     |     |     |            |        3          |          6        |       0 - 22      |      |      |
    // |        |       |     |     |     |            +-----+------+------+-----+------+------+-----+------+------+      |      |
    // |        |       |     |     |     |            | Len | Type | Data | Len | Type | Data | Len | Type | Data |      |      |
    // |        |       |     |     |     |            +-----+------+------+-----+------+------+-----+------+------+      |      |
    // |        |       |     |     |     |            |  1  |  1   |  1   |  1  |  1   |  4   |  1  |  1   |  20  |      |      |
    // |        |       |     |     |     |            |     |      |      |     |      |      |     |      |      |      |      |
    // |  1(2)  |  4    | (1) | (1) | (1) |   6        |  1  |  1   |  1   |  1  |  1   |  4   |  1  |  1   |  20  | (0)  |  3   |
    // +--------+-------+-----+-----+-----+------------+-----+------+------+-----+------+------+-----+------+------+------+------+
    //         0x8E89BED6     |     |      \
    //                /       |     |       \
    //               /  RAM uses 2+ bytes    \
    //              / 1 byte | 2 bit | 6 bit  \
    //             /                           \
    //            /  OTA only 2 bytes for BLE   \
    //           |                         |     |
    //           Type RFU ChSet TxAdd RxAdd Length
    //    bits:    4   1    1     1     1     8
    //
    //  1st byte: length of the element (excluding the length byte itself)
    //  2nd byte: AD type specifies what data is included in the element
    //  AD data one or more bytes - the meaning is defined by AD type
    //  The possible AD type values are listed in the Bluetooth SIG website, see following link:
    //  https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile
    //  Data types:
    //    0x01 = flags
    //    0x03 = Complete List of 16-bit Service Class UUIDs
    //    0x09 = Complete Local Name
    //    0x08 = Shortened Local Name
    //    0xFF = Manufacturer Data
    

        // The S0 length is one byte, and exactly maps to p_beacon_pdu[0]. The length field is 6 bits,
        // and uses 6 bits of p_beacon_pdu[1]. S1 field is 2 bits and uses 2 bits of p_beacon_pdu[2].
        // This means the PDU header takes 3 bytes in RAM, but only 2 bytes on air.
        // If S0, LENGTH or S1 are specified with zero length their fields will be omitted in memory, otherwise each
        // field will be represented as a separate byte, regardless of the number of bits in their on-air counterpart
        // ie if the S0INCL field in PCNF0 determines if S0 is present in RAM at all if its length is zero. If present,
        // one byte is allocated in RAM
    
        m_adv_pdu[0]  = 0x40 | 0x02;    // S0:     Optional First header byte: TxAdd|RxAdd (0x40) + PDU Type
        m_adv_pdu[1]  = 0;              // Length: Optional Second header byte: LENGTH (will be updated at the end)
        m_adv_pdu[2]  = 0;              // S1:     Optional Third header byte
    
        // The S0INCL field in PCNF0 determines if S0 is present in RAM at all if its length is zero. If present, one byte is allocated in RAM
        /* PCNF-> Packet Configuration. Now we need to configure the sizes S0, S1 and length field to match the datapacket format of the advertisement packets. */
        NRF_RADIO->PCNF0 =  (
                              (((1UL) << RADIO_PCNF0_S0LEN_Pos) & RADIO_PCNF0_S0LEN_Msk)    // length of S0 field in bytes 0-1.
                            | (((2UL) << RADIO_PCNF0_S1LEN_Pos) & RADIO_PCNF0_S1LEN_Msk)    // length of S1 field in bits 0-8.
                            | (((6UL) << RADIO_PCNF0_LFLEN_Pos) & RADIO_PCNF0_LFLEN_Msk)    // length of length field in bits 0-8.
                          );
    

Reply
  • Rather than answer the specific questions, maybe this code will help; The main difficulty (for me) was that the in-RAM layout is not the same as the on-air (bytes transmitted) format.

    // BLE Advertising Packet
    // ======================
    // Every packet begins with an 8 bit preamble, an alternating binary sequence. This is followed by a 32 bit access
    // address (AA) which can be thought of as a unique identifier which defines a particular connection. When a
    // device (master or slave) transmits on an advertising channel it uses a fixed value of 0x8e89bed6 as the access
    // address.
    // Following the 32 bit access address are optional S0, LENGTH and S1 fields then a variable length Protocol Data
    // Unit (PDU) which contains the message data payload. Finally all packets end with a 24 bit CRC.
    // By default, the Nordic BLE address is derived from the NRF_FICR->DEVICEADDR[] and is 48 bits in length (6 bytes)
    // If S0, LENGTH or S1 are specified with zero length their fields will be omitted in memory, otherwise each
    // field will be represented as a separate byte, regardless of the number of bits in their on-air counterpart
    // For the field sizes defined in bits, the occupation in RAM will always be rounded up to the next full byte size
    // (for instance 3 bit length will allocate 1 byte in RAM, 9 bit length will allocate 2 bytes, etc.).
    // On-air packet layout (Note Header in RAM is 3 bytes if S0INC is '1')
    // +-------------------------------------------------------------------------------------------------------------------------+
    // |                                         BLE Advertising Packet - Legacy                                                 |
    // +-------------------------------------------------------------------------------------------------------------------------+
    // |                                         1MHz: 47 octets max total length                                                |
    // +--------+-------+------------------------------------------------------------------------------------------+------+------+
    // |        |Access |                                                                                          | Add  |      |
    // |Preamble|Address|                   Protocol Data Unit PDU                                                 | On   | CRCC | Tone Ext
    // +--------+-------+------------------------------------------------------------------------------------------+------+------+
    // |   1(2) |   4   |                                    2 - 39                                                | (0)  |  3   | 16 - 160uSec
    // |        |       +-----------------+------------------------------------------------------------------------+      |      |
    // |        |       |    Header       |                  Payload                                               |      |      |
    // |        |       +-----------------+------------------------------------------------------------------------+      |      |
    // |        |       |       2         |                  0 - 37                                                |      |      |
    // |        |       +-----+-----+-----+------------------------------------------------------------------------+      |      |
    // |        |       | Opt | Opt | Opt |  MAC Addr  |     AdvData List (example 3 fields)                       |      |      |
    // |        |       | S0  | Len | S1  +------------+-----------------------------------------------------------+      |      |
    // |        |       |-----+-----+-----|    6       |     0 - 31                                                |      |      |
    // |        |       | (1) | (1) | (1) |            +-------------------+-------------------+-------------------+      |      |
    // |        |       |     |     |     |            |    AdvData Flags  |    AdvData Name   |   (AdvData Data)  |      |      |
    // |        |       |     |     |     |            +-------------------+-------------------+-------------------+      |      |
    // |        |       |     |     |     |            |        3          |          6        |       0 - 22      |      |      |
    // |        |       |     |     |     |            +-----+------+------+-----+------+------+-----+------+------+      |      |
    // |        |       |     |     |     |            | Len | Type | Data | Len | Type | Data | Len | Type | Data |      |      |
    // |        |       |     |     |     |            +-----+------+------+-----+------+------+-----+------+------+      |      |
    // |        |       |     |     |     |            |  1  |  1   |  1   |  1  |  1   |  4   |  1  |  1   |  20  |      |      |
    // |        |       |     |     |     |            |     |      |      |     |      |      |     |      |      |      |      |
    // |  1(2)  |  4    | (1) | (1) | (1) |   6        |  1  |  1   |  1   |  1  |  1   |  4   |  1  |  1   |  20  | (0)  |  3   |
    // +--------+-------+-----+-----+-----+------------+-----+------+------+-----+------+------+-----+------+------+------+------+
    //         0x8E89BED6     |     |      \
    //                /       |     |       \
    //               /  RAM uses 2+ bytes    \
    //              / 1 byte | 2 bit | 6 bit  \
    //             /                           \
    //            /  OTA only 2 bytes for BLE   \
    //           |                         |     |
    //           Type RFU ChSet TxAdd RxAdd Length
    //    bits:    4   1    1     1     1     8
    //
    //  1st byte: length of the element (excluding the length byte itself)
    //  2nd byte: AD type specifies what data is included in the element
    //  AD data one or more bytes - the meaning is defined by AD type
    //  The possible AD type values are listed in the Bluetooth SIG website, see following link:
    //  https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile
    //  Data types:
    //    0x01 = flags
    //    0x03 = Complete List of 16-bit Service Class UUIDs
    //    0x09 = Complete Local Name
    //    0x08 = Shortened Local Name
    //    0xFF = Manufacturer Data
    

        // The S0 length is one byte, and exactly maps to p_beacon_pdu[0]. The length field is 6 bits,
        // and uses 6 bits of p_beacon_pdu[1]. S1 field is 2 bits and uses 2 bits of p_beacon_pdu[2].
        // This means the PDU header takes 3 bytes in RAM, but only 2 bytes on air.
        // If S0, LENGTH or S1 are specified with zero length their fields will be omitted in memory, otherwise each
        // field will be represented as a separate byte, regardless of the number of bits in their on-air counterpart
        // ie if the S0INCL field in PCNF0 determines if S0 is present in RAM at all if its length is zero. If present,
        // one byte is allocated in RAM
    
        m_adv_pdu[0]  = 0x40 | 0x02;    // S0:     Optional First header byte: TxAdd|RxAdd (0x40) + PDU Type
        m_adv_pdu[1]  = 0;              // Length: Optional Second header byte: LENGTH (will be updated at the end)
        m_adv_pdu[2]  = 0;              // S1:     Optional Third header byte
    
        // The S0INCL field in PCNF0 determines if S0 is present in RAM at all if its length is zero. If present, one byte is allocated in RAM
        /* PCNF-> Packet Configuration. Now we need to configure the sizes S0, S1 and length field to match the datapacket format of the advertisement packets. */
        NRF_RADIO->PCNF0 =  (
                              (((1UL) << RADIO_PCNF0_S0LEN_Pos) & RADIO_PCNF0_S0LEN_Msk)    // length of S0 field in bytes 0-1.
                            | (((2UL) << RADIO_PCNF0_S1LEN_Pos) & RADIO_PCNF0_S1LEN_Msk)    // length of S1 field in bits 0-8.
                            | (((6UL) << RADIO_PCNF0_LFLEN_Pos) & RADIO_PCNF0_LFLEN_Msk)    // length of length field in bits 0-8.
                          );
    

Children
  • Thanks, these are very nice and descriptive layouts of the data structure.

    I WAS questioning your first header byte in the second clip of code you presented. All documentation and the zephyr packet layout seem to indicate that the PDU type is the high nibble of the first byte.
    (see struct pdu_adv in v2.7.0\zephyr\subsys\bluetooth\controller\ll_sw\pdu.h for reference)
    Perhaps you have endian set differently. This actually seems like it's the case looking at the struct in pdu.h again. It has a define that switches the order based on the "CONFIG_LITTLE_ENDIAN" setting.
    It also threw me with your allocation of the length field being 6 bits when it is 8 in the docs. But then I realized you backed up the 6 bits with two additional empty bits in S1, so a total of 8 bits. 

    The real overall question for me is, "Does the RADIO peripheral use the LENGTH field in memory to "count" out the packet bytes to send or, in the case of reception does it use it to figure out how many bytes to expect and when to trigger EVENTS_PAYLOAD?"
    I don't see how we can know how the payload has been received without this. 
    I know the radio engine allows for fixed length by adjusting the PCNF1 STATLEN fields. 

    Thanks again for the code packets, this is very helpful information for me.

  • My belief is starting to firm up around the length field being important, using what I am pretty sure how to operate, Enhanced Shockburst. 
    Looking at update_rf_payload_format_esb_dpl() in v2.7.0\nrf\subsys\esb\esb.c seems to indicate that the length is used by the RADIO peripheral.
    Still, I would like to be 100% on this.

  • I concur; maybe Nordic could provide official confirmation ..

  •   Sure, I will have an inquiry with some expert on the matter to be sure.

Related