This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC2640R2F: Hardware Assert Error

Part Number: CC2640R2F
Other Parts Discussed in Thread: BLE-STACK

Good day!

I have encountered an `HCI_BLE_HARDWARE_ERROR_EVENT_CODE` when debugging my modified "simple_peripheral" project on the CC2640R2F (using the blestack from simplelink_cc2640r2_sdk_5_30_00_03).  It corresponds with some (but not all) connection events.

I am fairly certain that it relates to heap allocation. Using `HEAPMGR_METRICS` and monitoring `heapmgrMemFail` shows two allocation failures when my breakpoint is hit within the application `processStackMsg()` function, although `heapmgrMemMax` remains below the heap size.

Following the instructions on this page (link), I identified the error code as 129, which I believe corresponds to the `HW_FAIL_OUT_OF_MEMORY` (from "ll_common.h")

Would TI be able to provide any guidance as to the potential source/solutions for this error?  I recognize it is a blestack heap issue (so one solution is to decrease my application's static RAM usage), but I am wondering why it does not occur on every connection event?

Thanks!

  • Hello Kenton, 

    Thanks for the response. We will get back to you as soon as possible. 

    Thanks, 

    Isaac

  • Hi Kenton,

    As you mentioned, HW_FAIL_OUT_OF_MEMORY means the stack is running out of heap memory.

    I recommend ensuring the maximum heap size is used (should be done by default using auto-sized heap). After this, you can considering saving RAM size (see here for some leads), increasing RAM size allocation the Cache and/or the AUX RAM as RAM (see here and here).

    To answer your question "I am wondering why it does not occur on every connection event" - The amount of heap required to handle a connection event may actually vary on the content of the packets sent and received. In addition, the heap consumed by the rest of the application is likely to also vary across time.

    I hope this will help,

    Best regards,

  • Thank you for the response, Clement!

    To ask a few follow-up questions:

    (1) What determines the size of the packets sent/received?  And what are the limiting factors?

    As background, I always utilize the same characteristic for data transfer, although I sometimes pass different `len` parameters into the SimpleProfile_SetParameter() function.  The len is guaranteed to be <= MAX_PDU_SIZE, and is stored in a global variable (let's call it "global_length_variable").

    SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR1, global_length_variable, dataBuffer);

    Within the SimpleProfile_SetParameter() function, I clear the characteristic data, and memcpy's the specified (`len`) number of bytes to `value`:

    memset(simpleProfileChar1, 0, SIMPLEPROFILE_CHAR1_LEN);
    memcpy(simpleProfileChar1, value, len);

    When the host reads this characteristic (i.e., in SimpleProfile_readAttrCB()), we run --

    memcpy( pValue, pAttr->pValue, global_length_variable)

    Do these portions of code relate to the size of the packets sent?  I was under the impression that the host would always just read the full value of the characteristic (i.e., whatever `SIMPLEPROFILE_CHAR1_LEN` is set to).

    (2) I have no dynamic memory allocation in my application code, so heap would be exclusively allocated by the TI-RTOS and/or BLE-STACK code.  Which portions of those code-bases might result in varying heap-usage over time? 

    Thanks again,

    -Kenton

  • To augment (1) above.... I just discovered that my transmission will not succeed if `global_length_variable` is greater than (MAX_PDU_SIZE - 6).  However, there is no hardware assert or allocation failure, so this may be an unrelated issue.

    Is there a limit to the characteristic size based on the value of MAX_PDU_SIZE?

    Thanks!

  • Hi,

    (1) What determines the size of the packets sent/received?  And what are the limiting factors?

    The size of the PDUs sent over the air will have an impact. But other elements may also come into the picture, such as the number of packets sent/received in each connection event. Packet losses (by reducing the available throughput) also have an impact as more local storage is required.

    (2) I have no dynamic memory allocation in my application code, so heap would be exclusively allocated by the TI-RTOS and/or BLE-STACK code.  Which portions of those code-bases might result in varying heap-usage over time? 

    In general, the BLE-STACK code is expected to be responsible for these allocations. However, it depends on the way these elements are used.

    I hope this will help,

    Best regards,

  • Thanks, Clement,

    To confirm a few things:

    1. Am I correct in assuming that, during a characteristic read operation, the peripheral device will always return with a transmission of SIMPLEPROFILE_CHAR1_LEN bytes of data?
      1. OR does the `len` parameter passed to SimpleProfile_readAttrCB() and SimpleProfile_SetParameter() impact the size of the packet sent?
    2. You mentioned packet losses.... How does this increase local storage usage?  Is it because more buffers need to be allocated?
    3. I was under the impression that the host (in my particular application) will only read once-at-a-time.  Is there a way to see how many packets were actually sent/received each connection event? (e.g., by observing a variable or breakpoint within the simple_peripheral project?)
    4. Does MAX_PDU_SIZE impose a limit on the maximum characteristic length that can be successfully set via the the `len` parameter of the SimpleProfile_readAttrCB() and SimpleProfile_SetParameter() functions?
      1. And if so, why does the limit seem to be (MAX_PDU_SIZE - 6)?
  • Hi,

    Am I correct in assuming that, during a characteristic read operation, the peripheral device will always return with a transmission of SIMPLEPROFILE_CHAR1_LEN bytes of data?

    I am afraid you are not totally correct.
    First of all, even if a characteristic is defined with a specific length, the two hosts have a the possibility to send data with a different (larger or shorter) than the expected length. The devices then have the possibility to reject the message (or even to only consider a subset of the data).

    OR does the `len` parameter passed to SimpleProfile_readAttrCB() and SimpleProfile_SetParameter() impact the size of the packet sent?

    Here, we agree :) The size of the packets sent is impacted by these functions.

    You mentioned packet losses.... How does this increase local storage usage?  Is it because more buffers need to be allocated?

    Bluetooth LE connections implement a packet loss detection and re-transmission mechanism at the Link Layer level (a second one can be implemented at the GATT level). It means, the LL will keep in memory (and retry its transmission) a packet until it is acknowledged. In case new packets are queued before the previous packet has gone through, then the memory consumption may grow. Same goes in case the connection interval is larger than the interval between the production of new data.

    I was under the impression that the host (in my particular application) will only read once-at-a-time.  Is there a way to see how many packets were actually sent/received each connection event? (e.g., by observing a variable or breakpoint within the simple_peripheral project?)

    I confirm connection PDUs can be chained. I am not aware of a variable accessible at the application level that would be showing this. However, you can use a Bluetooth sniffer to observe this. Alternatively you can enable the RF observables (see here) so you can see all the radio activity, and, among others see the reception/transmission of chained packets.

    Does MAX_PDU_SIZE impose a limit on the maximum characteristic length that can be successfully set via the the `len` parameter of the SimpleProfile_readAttrCB() and SimpleProfile_SetParameter() functions?

    MAX_PDU_SIZE gives a limit on the maximum size of data transmitted in a single PDU. In case you want to transmit a GATT characteristic with a size larger than the ATT_MTU (see after), then you have to split it between several PDUs. This mechanism should be handled by the task if you use GATT_WriteLongCharValue function.

    why does the limit seem to be (MAX_PDU_SIZE - 6)?

    The answer is more or less in the figure below :)

    You should account for the headers added by each layer.

    I hope this will help,

    Best regards,

  • Thank you for the incredibly detailed response, Clement!  This is very helpful as I start to understand the underlying mechanisms of the protocol.

    I did have a few brief follow up questions.... 

    1. You said "the LL will keep in memory (and retry its transmission) a packet until it is acknowledged."  Does the stack have a mechanism for freeing this memory at some point? (e.g., if the connection is terminated, or after a certain time passes?)
    2. Regarding the "GATT_WriteLongCharValue" function... I assume this is something the host device would use?  Should the host similarly use a "GATT_ReadLongCharValue" function to read a characteristic longer than the max ATT_MTU size?  If it does, will the "simple_peripheral" project automatically split the transmission into multiple PDUs?
    3. The blestack documentation seems to indicate that the maximum ATT_MTU is MAX_PDU_SIZE - 4" (i.e., the L2CAP header size).  This seems to differ from the diagram above, which also includes the LL Header.  I am wondering what I am missing here?
    4. I assume the ATT header is either 1 or 3 bytes, depending on if the operation is a Read or Write, or is that incorrect?

    Thanks again,

    -Kenton

  • Hi,

    Glad to see I am helping :)

    You said "the LL will keep in memory (and retry its transmission) a packet until it is acknowledged."  Does the stack have a mechanism for freeing this memory at some point? (e.g., if the connection is terminated, or after a certain time passes?)

    The memory I referred to will be freed whenever the connection is terminated. It will not be freed otherwise (this is a Bluetooth requirement).

    Regarding the "GATT_WriteLongCharValue" function... I assume this is something the host device would use?  Should the host similarly use a "GATT_ReadLongCharValue" function to read a characteristic longer than the max ATT_MTU size?  If it does, will the "simple_peripheral" project automatically split the transmission into multiple PDUs?

    Correct, and correct. The GATT client should call GATT_ReadLongCharValue" function to read a characteristic longer than the max ATT_MTU size. Then the stack of the GATT server will handle the split of the data.

    The blestack documentation seems to indicate that the maximum ATT_MTU is MAX_PDU_SIZE - 4" (i.e., the L2CAP header size).  This seems to differ from the diagram above, which also includes the LL Header.  I am wondering what I am missing here?

    The ATT_MTU gives the size of the ATT Data (i.e. PDU size - LL Header - L2CAP header). In order to get the size available for the ATT Payload, you have to consider the size of the ATT header (3 bytes - see below).

    I assume the ATT header is either 1 or 3 bytes, depending on if the operation is a Read or Write, or is that incorrect?

    The ATT header has actually a fixed size (3 bytes).

    Best regards,