Not achieving maximmum bitrate (2Mbps)

Hello everyone,

I’m working with a project where I want to send 5 packets 255bytes long. Then go to deep sleep mode for minimmum current consumption. After some minutes (15min at all) I want to send another 5 packets 255 bytes long.

I currently have the ability of send this 5packets I was talking about and then go to deep sleep. With DIO0 I can wake up the processor to send one more time this 5 packets.
Here I post you my current graphics about the behaviour of my program:

As you can see in the graph, there are some problems I set out below:

  • First of all, the bitrate I can achive is very poor. It is about 9.6kbps at best. Someone can kindly explain me how to increase it to 2Mbps?
  • Looking at my measurements, I realised that one of the problems with the low bitrate could be the moment between the trasmission of the packets, when the transmitter goes to sleep mode (not deep sleep). In this case, how could I do a burst to send data at maximmum bitrate? In case to be impossible, how can I reduce the sleep time to its minimmum value?

By the way I give you some data about my setup. I am working with a standard RSL10 SIP development board ( RSL10-SIP-001GEVB, Evaluation Boards from ON Semiconductor) as a transmitter and for now I have my smartphone as a receiver.

For measuring the current I am using an Agilent B2912A Precision Source/Measure Unit that feeds the development board and measures it’s current.

Also I am using as project sample the peripheral_server_ext project where I found it in the Software Package in the CMSIS Pack (v10.3.5.285) and I am working with the Eclipse-based IDE from OnSemi’s webpage.

Here I attach you my modified project if it can help to understand my issues. (I upload it on my GitHub repository because I can upload it on this post since it is too big):

I would greatly appreciate your suggestions.

Greetings,

Enric Puigvert

Hi @epuigvert,

Please see my feedback outlined below:

This is likely because the bitrate you are calculating has many more components in it than just the Radio TX portion. By observing the screenshots below, you can see that each Connection interval is made up of several different components (Setup Time, RX Time, TX Time, Teardown Time, Sleep Time).

When you consider the TX Time below (the largest of the current spikes) it can be seen that each 244 packet will be create ~1ms in TX Time which corresponds to a 2Mbps Radio link (2Mbps = 4uS/byte ; 244byte * 4uS/byte = 976uS).


As discussed above, this low theoretical bitrate is caused by all of the time that the RSL10 has to spend on tasks other than TX Time (Setup Time, RX Time, Teardown Time, Sleep Time) within the Connection Interval.

The easiest way to increase the theoretical bitrate is to decrease all other components that are not TX related, and the three best option for decreasing these values are:

  1. Queuing up all 5 notification packets to be sent during a single Connection Event. As seen in my current measurement below, this will result in all 5 packets being sent in one interval, greatly reducing the number of connection intervals required to send all of the data (less Sleep Time, less Setup Time and less Teardown Time).
  2. Forcing the MD Bit to be 0. This will allow the Connection Supervision packet to be automatically sent alongside one of the notifications (removes one of the Rx/Tx events, which means less unnecessary Rx/Tx time).
  3. Reducing your connection interval time (less time spent in Sleep mode). If we are using my current measurements below as an example, the event takes ~12ms to complete, so setting a Connection Interval of 20ms will result in only 8ms of Sleep time.

To give a quick estimate of the theoretical bit rate of my current consumption below, consider the following:

  1. TX Time is ~5ms worth of the ~12ms Connection Event.
  2. Sleep time will make up the other ~8ms of each interval.
  3. Therefore we are operating at 2Mbps TX for 5ms out of the 20ms interval.
  4. The theoretical bit rate of this setup is ~ 500kbps

Hi @brandon.shannon.

Thank you very much for your answers to all my questions. It helps me a lot in my understanding.

I have some doubts:

Could you kindly explain me how can I queue up this 5 notification packets on a single Connection Event? I thought that modifying APP_CS_TX_VALUE_NOTF_LENGTH to a value of 20 (the maximmum number of bytes on a custom service notification according to the peripheral_server_ext sample comments). Is that correct?

About reducing the connection interval, looking at the peripheral_server_ext sample and considering your annotations, I understand that APP_CS_TX_VALUE_NOTF_SLEEP_CYCLE has to be reduced at its minimmum value (20ms as you said). Is that correct?

Thank you in advance.

Greetings,

Enric Puigvert

Hello again.

I forgot to ask you another question about the behaviour of RSL10:

After sending a burst of packets and then go to deep sleep mode I realised that I need to do a Cancel_cmd() and then a BLE_Reset() function to be able to send another burst of packets.
I don’t know if this is the best way to do it but is the only way I found.

Could you explain me which is the way to do this?

Thank you very much.

Greetings,

Enric Puigvert

Hi @epuigvert,

Please see my follow-ups below:

There are a few steps required to setup the ‘peripheral_server_ext ’ sample code to send 5x 244byte payload notifications:

  1. You must enable Data Length Extension feature, which adds support for payloads up to 244bytes. By default, BLE only supports 27byte payload notifications without DLE.
    The necessary exchanges to enable DLE can be done using the ‘GATTC_EXC_MTU_CMD’ & ‘GAPC_SET_LE_PKT_SIZE_CMD’ Stack commands. Using the ‘peripheral_server_UART’ sample code as an example of how to configure DLE and 2Mbps is a good place to start, as it performs all of the necessary commands.
  2. To queue up 5 of these packets during the next connection event, I used the following code snippet directly within the ‘main_loop()’ function:
        if (ble_env.state == APPM_CONNECTED)
        {
            if (cs_env.tx_value_changed && (cs_env.tx_cccd_value & 1))
            {
                cs_env.tx_value_changed = 0;

                /* Packet #1 */
                cs_env.sentSuccess = 0;
                CustomService_SendNotification(ble_env.conidx,
                                               CS_IDX_TX_VALUE_VAL,
											   packet_data,
                                               244);
                while(cs_env.sentSuccess == 0)
                {
                	Kernel_Schedule();
                	Sys_Watchdog_Refresh();
                }

                /* Packet #2 */
                cs_env.sentSuccess = 0;
                CustomService_SendNotification(ble_env.conidx,
                                               CS_IDX_TX_VALUE_VAL,
											   packet_data,
                                               244);
                while(cs_env.sentSuccess == 0)
                {
                	Kernel_Schedule();
                	Sys_Watchdog_Refresh();
                }

                /* Packet #3 */
                cs_env.sentSuccess = 0;
                CustomService_SendNotification(ble_env.conidx,
                                               CS_IDX_TX_VALUE_VAL,
											   packet_data,
                                               244);
                while(cs_env.sentSuccess == 0)
                {
                	Kernel_Schedule();
                	Sys_Watchdog_Refresh();
                }

                /* Packet #4 */
                cs_env.sentSuccess = 0;
                CustomService_SendNotification(ble_env.conidx,
                                               CS_IDX_TX_VALUE_VAL,
											   packet_data,
                                               244);
                while(cs_env.sentSuccess == 0)
                {
                	Kernel_Schedule();
                	Sys_Watchdog_Refresh();
                }

                /* Packet #5 */
                cs_env.sentSuccess = 0;
                CustomService_SendNotification(ble_env.conidx,
                                               CS_IDX_TX_VALUE_VAL,
											   packet_data,
                                               244);
                while(cs_env.sentSuccess == 0)
                {
                	Kernel_Schedule();
                	Sys_Watchdog_Refresh();
                }

            }
        }

Not quite. The ‘APP_CS_TX_VALUE_NOTF_SLEEP_CYCLE’ variable acts as a counter to determine how many Connection Intervals must pass before the notifications are sent out again.

Setting the Connection Interval from a Peripheral device can be done by initiating the ‘GAPC_PARAM_UPDATE_CMD’ after the Connection has been formed. When this command is loaded with the desired Connection Interval, it will start a negotiation with the Central to determine the new Connection Interval.


This can be done by applying the exact same logic done when the maximum number of Advertising Intervals has been reached without a Connection occurring. By default, this sample will advertise by sending out ‘ADV_CNT_MAX’ # of packets, and then returning to Sleep.

By counting the occurrences of the ‘Main_Loop()’ function while the ‘ble_env.state == APPM_CONNECTED’ condition is true, you can effectively count the number of Connection Intervals that have passed.

Once you have reached the desired number of Connection Intervals, you can use the ‘GAPC_DISCONNECT_CMD’ command to force a Disconnect, and then perform the same ‘GAPM_CANCEL_CMD’ operations that are used to Sleep after advertising.


1 Like

Hello again,
@brandon.shannon I apreciate all your answers that you gave to me. Are helping me a lot.

I’ve been working on the project and thanks to your suggestions I successfully enabled DLE to send 244 bytes on every packet. I followed your steps and it works!
Also, using BLE_Set_ForcedMDbit(0) function before the initialization of BLE, I think I could force the MD bit to be 0. (I am not very sure about this…)

But now I have some issues I cannot resolve and some other questions I want to ask you:

First of all I would like to ask you about the connection interval connection and the configuration of bitRate of MTU.

To configure MTU to 2Mbps bitrate, 244 byte size packets and a 20 ms interval connection I do this in my code. (inside GAPC_ConnectionReqInd function):

Connection_SetPktLength(ble_env.conidx, MTU_SIZE);  //Increase the packet size to 244
 Connection_ExchangeMTUCmd(ble_env.conidx);  //apply the changes to MTU controller
Connection_SetPHY(GAP_RATE_LE_2MBPS, GAP_RATE_LE_2MBPS);  //Increase datarates
GAPC_ParamUpdateCmd(ble_env.conidx, 20, 20, 0, 10, 244, 244); //to select  Connection interval

I am doing it right? I am not convinced about it. Could you confirm it that it is not correct? Could you kindly explain me which is the way?

Also I tried to disconnect from my central client (my smartphone is doing this task), following your annotations. Doesn’t worked for me at all. After sending the 5 queued packets like you told me, and after a deep sleep period I am not able to reconnect with the central client and send another burst of 5 packets. I do the following steps:

GAPC_DisconnectCmd(ble_env.conidx,CO_ERROR_UNDEFINED); (the error is not important, I need it only to use the function as is)
GAPM_CancelCmd();
ble_env.state = APPM_READY

What I am doing wrong? Could you explain me how can I do this?

Note: this happens at the second time I try to send the burst of packets. In my Android app, I get “Gatt status 133” error notification. I don’t know if it can help you to understand my problem.

Thank you very much

Greetings,

Enric Puigvert

Hello again,

An update about the problems on closing the connection:

I realised that changing the reason code from the GAPC_DisconnectCmd() function, it changes the behaviour of my receiver. For example, if I configure the reason of disconnection as CO_ERROR_REMOTE_DEV_POWER_OFF my Android App acting as central client returns “gatt status 14” instead of “gatt status 13”.

Another important aspect I realised, that the disconnection is faster with this error code than the other one I said before.

I hope it helps to understand my issues.

Thank you very much

Enric Puigvert

UPDATE: I realised after some tests, that it happens when I wakeup my peripheral server and it advertises normaly, but nobody is listening and connecting to it. Then, in the next connections they will not be able to connect each other.