This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

[ble_app_uart] UART overrun

Hello,

I am trying to fix the UART communication error in a peripheral side.

First of all, the setup that I am using is as below.

[SDK] nRF5_SDK_11.0.0_89a8197

[Softdevice] s130_nrf51_2.0.0_softdevice.hex

[Central] nRF51 dongle (PCA10031) to the Master Control Panel in PC

-MEFW nRF51822 0.11.0 with 1M bps UART baud rate & 20 ms Connection Interval

[Peripheral] nRF51822 QFAA (3rd revision) based 3rd party module

-Application firmware: ble_app_uart

(...\Nordic Semiconductor\nRF5_SDK_11.0.0_89a8197\examples\ble_peripheral\ble_app_uart\custom\s130\arm5_no_packs)

-Bandwidth: High (6 packets per an interval)

cf. by default, connections as a Peripheral will be set to high bandwidth. (11.4 BLE role configuration in S130_SDS_v2.0.pdf (page 38))

-Connection Interval: 20 ms

define MIN_CONN_INTERVAL MSEC_TO_UNITS(20, UNIT_1_25_MS)

define MAX_CONN_INTERVAL MSEC_TO_UNITS(20, UNIT_1_25_MS)

-Slave latency: 0

define SLAVE_LATENCY 0

-Maximum character length: 20 characters

define GATT_MTU_SIZE_DEFAULT 23

define BLE_NUS_MAX_DATA_LEN (GATT_MTU_SIZE_DEFAULT - 3)

-Mode: Write command ("ble_nus_c_string_send" function)

-TX FIFO size: 512 bytes

In the peripheral side, an external MCU sends the data to the nRF51822 module via the UART communication with a 57600 baud rate. The sampling rate is 250 Hz, so the interval of the UART RX is 4 ms. For now, an external MCU does NOT support the hardware flow control but the flow control is emulated by the firmware of the MCU, which means that an external MCU reads the RTS pin (P.08) of the nRF51822 module before sending the data, and then send the data only when the RTS is low.

When the MCU sends the 6 bytes data with the 250 Hz sampling rate, I’ve not obtained the UART communication error so far. However, when trying the 9 bytes data with the 250 Hz sampling rate, the UART overrun error occurs in the debug mode as below.

image description

I’ve also monitored the CTS pin of the MCU (=the RTS of the nRF51822) by a logic analyzer as below. After some point, the CTS pin of the MCU goes “high” and the UART overrun error occurs. image description image description

This attached file is the received data in a Master Control Panel. mcp_packets_9bytes_250Hz.xlsx

Regarding the data throughput, the total UART RX data per second is the 2250 bytes/sec. (= 9 bytes x 250 sampling rate) The expected maximum radio TX data throughput for the current setting is 6000 bytes/sec. (= 20 bytes (packet size) x 6 (maximum packet number per a connection interval) / 20 msec (connection interval)) In this calculation, the expected maximum radio TX data throughput per second is larger than the UART RX data per second.

Regarding the processing time, in this link (devzone.nordicsemi.com/.../), the CPU blocked duration for one packet is about 1 msec. The UART RX duration for 9 bytes (= 72 bits) per one sampling is 1.25 msec with 57600 UART baud rate. If there are 5 samplings in the 20 msec interval (250 Hz sampling rate = 4 msec period), the total UART RX duration is 6.25 msec (= 1.25 msec x 5 samplings). For this case with the write command mode, 45 bytes (9 bytes x 5 samplings) can be sent to the radio event handler, so 2 packets (= 40 bytes) are sent in this connection interval and the remained 5 bytes will be sent with 15 bytes of next sample in next connection interval. The CPU blocked duration for 2 packets is about 2 msec according to the above link. Thus the total duration for the UART RX and radio event is about 8.25 msec, which is shorter than the 20 msec connection interval.

I’ve read this link (devzone.nordicsemi.com/.../), which commented that the transmitting speed of ble_over_uart in the SDK is slow, especially for Softdevice central role and recommend the EHAL library (embeddedsoftdev.blogspot.kr/.../ehal-nrf51.html) or nRF52 with DMA, but I wonder why the UART FIFO overrun error occurs even with sufficient data throughput and processing time for the application. Is there any way to work current setup using the ble_over_uart of the SDK with nRF51? Please let me know if I missed or misunderstood something.

Here is the complete project file that I am using. ble_app_uart.zip

Thank you in advance.

[Updated on Aug 10 2016]

Hi, Stefan,

Thanks to your comment about completely blocking UART transfer, I could consider the error “BLE_ERROR_NO_TX_PACKETS”.

When I tried several same experiments, sometimes I’ve experienced a different error as below, which was the error code 0x0304 meaning the “BLE_ERROR_NO_TX_PACKETS”. (I am not sure yet why different errors occurred.)

image description

Thus I’ve modified the “ble_app_uart” code to stop transmitting the data to the stack when receiving the “BLE_ERROR_NO_TX_PACKETS” and to wait until receiving the “BLE_EVT_TX_COMPLETE” . After receiving the “BLE_EVT_TX_COMPLETE”, then transmitting the data to the stack is started again

I added a global variable for the flag to enable or disable the data transfer to the stack. For this modification, I referred to these links.

devzone.nordicsemi.com/.../

devzone.nordicsemi.com/.../

devzone.nordicsemi.com/.../

After the modification, no error occurred sending 9 bytes data with the 250 Hz sampling rate during about 30 minutes.

However, when increasing the data to 15 bytes with the same sampling rate, I obtained the UART_COMMUNICATION_ERROR again. At this case, the data throughput and the processing time are still sufficient.

I've tried checking the actual CI as you advised. However, when hitting the breakpoint (shorter than 5 seconds), I could not find the “m_current_connection_params” variable. The below image is the MCP (left) and the debugger (right) when hitting the breakpoint. Could you let me know why this happened?

image description

Regarding the -O3 compiler option that you mentioned, I am still using -O0 option for debug purpose.

[Updated on Aug 12 2016]

Hi, Stefan,

Thanks again for the good comment!

Unfortunately, the final data throughput that we want is the 6750 bytes/sec (=27 bytes with 250 Hz sampling rate). Actually, I thought that this would be possible using the nRF51822 with the “ble_app_uart” example of the SDK because the calculated maximum RF throughput is much higher, which is the 16000 bytes/sec (=20 bytes packet size x 6 packets per one CI / 7.5ms the shortest CI). Is this correct?

This is a first time for me to use the nRF51822, so I’ve tried increasing the data throughput step by step from the 6 bytes with 250 Hz sampling rate by the 3 bytes step.

As your previous comments, I made some changes on the central side (PCA10031 dongle) to find where the UART error takes place (Central or Peripheral side).

This is a new setting of the central.

[Softdevice] s130_nrf51_2.0.0_softdevice.hex

[Application] ble_app_uart_c with a terminal program in PC

-The stack configuration for high bandwidth (6 packets per a CI) is made thank to Petter Myhre’s help. (devzone.nordicsemi.com/.../)

In several tests with different baud rates and received data sizes, I've found that the change waiting for the "BLE_EVT_TX_COMPLETE" event improved the performance as you said. The below parameters are the configurations that I am using.

[Central]

UART_TX_BUF_SIZE: 512, UART_RX_BUF_SIZE: 256

MIN_CONNECTION_INTERVAL MSEC_TO_UNITS(7.5, UNIT_1_25_MS)

MAX_CONNECTION_INTERVAL MSEC_TO_UNITS(7.5, UNIT_1_25_MS)

UART_BAUDRATE_BAUDRATE_Baud57600

[Peripheral]

UART_TX_BUF_SIZE: 256, UART_RX_BUF_SIZE: 512

MIN_CONNECTION_INTERVAL MSEC_TO_UNITS(7.5, UNIT_1_25_MS)

MAX_CONNECTION_INTERVAL MSEC_TO_UNITS(7.5, UNIT_1_25_MS)

UART_BAUDRATE_BAUDRATE_Baud57600

As a below figure of the peripheral side, I could see that the data communication works well for 15 bytes with 250 Hz sampling rate (3750 bytes/sec) under my observation about 10 minutes, but not for 18 bytes with 250 Hz sampling rate (4500 bytes/sec).

image description

When calculating durations under the view of one CI, the number of sampling per one CI is 1.875 (=7.5 msec CI / 4 msec sampling period).

Thus the UART RX duration in a CI is about 3.9 msec (= 15 bytes x 8 bits x 1.875/ 57600 baud rate) and the required packet number per a CI is about 1.4 (15 bytes x 1.875/ 20 packets), which takes 1.4 msec at most. (I’m using the 3rd version hardware, so maybe CPU is blocked shorter than 1.4 msec. Is this correct? devzone.nordicsemi.com/.../)

So, the CPU processing margin in a CI is about 2.2 msec (=7.5 msec CI – (3.9 msec UART RX + 1.4 msec Radio TX)). This number might be sufficient for the CPU because the communication works well.

For larger received data throughputs, however I’ve tried the higher baud rate to make more room for the CPU or stack. The strange thing that I experienced is that as below figure of the peripheral side, the CTS gets high in one second and never goes back to low when using 115200 baud rate (only for peripheral side) even with same 15 bytes with 250 Hz sampling rate. I thought that for the same received data throughput, the higher baud rate can guarantee more processing time for CPU or stack but the UART error took place so early.

image description

Do you have any idea what I should consider to use higher baud rates such as 115200?

[Updated on Aug 24 2016]

Hi, Stefan

First of all, thank you for your work.

I’ve tested the “ble_app_uart_test_throughput” that you provided, but using 230400 baud rate still causes the “APP_UART_COMMUNICATION_ERROR” in the debug mode.

The time length for the high CTS depends on the data size. As the below figure, it takes about 0.4 sec for the 250 Hz/6 bytes data (12 kbps) with the 230400 baud rate.

image description

[SDK] nRF5_SDK_11.0.0_89a8197

[Softdevice] s130_nrf51_2.0.1_softdevice.hex (updated from s130_nrf51_2.0.0)

[Central] nRF51 dongle (PCA10031) with “ble_app_uart_c” and a terminal program in PC

  • High bandwidth (6 packets per a CI), 57600 UART baud rate, 7.5 ms Connection Interval

  • -O3 option with “optimize for time”

[Peripheral] nRF51822 QFAA (3rd revision) based 3rd party module with your modified “ble_app_uart_test_throughput”

  • High bandwidth (6 packets per a CI), 230400 UART baud rate, 7.5 ms Connection Interval

  • -O0 option (for debugging)

  • TX buffer size: 64, RX buffer size: 64

The way to increase the RX buffer size to 256 works for the 250 Hz/6 bytes data (12 kbps) with the 230400 baud rate, but the UART transfer is blocked after less than 2 seconds for the 250 Hz/9 bytes data (18 kbps) with the 230400 baud rate and I could find the “APP_UART_COMMUNICATION_ERROR” in the debug mode as below.

image description

image description

First, I wonder which firmware you are using for the central (ble_app_uart_c or MCP). If you use the "ble_app_uart_c", which baud rate are you using?

Second, I could find the modification that you said in the “main.c” file but when I looked at the “app_uart_custom.h” and “app_uart_fifo_custom.c”, I could not find any difference with “app_uart.h” and “app_uart_fifo.c”, respectively. In my view, only one comment and a name of header file were changed. Is this correct?

  • Hi

    In my mind there are three possible throughput bottlenecks for this case, i.e. UART hardware side, BLE side, and nRF51 CPU. I agree with you that there should be excessive bandwidth for your data both on the BLE side and also on the hardware UART side with 57.600 BAUD rate. I would think the CPU should be able to handle this data transfer as well, i.e. that it is not too occupied. So I do not immediately see where the bottleneck is without further investigation.

    Seems that the CTS line is originally allowing for UART transmission more or less all the time. Then after some time (how long exactly?) it totally blocks UART transfer from the external MCU. That I find suspicious. What are the actual connection parameters? Is the connection interval surely 20ms? Are you setting the connection interval in MCP to 20ms originally? Are you seeing 20ms connection interval being set?

    To improve code execution speed, you can set optimization level 3 and check "Optimize for time" in Keil -> Options for target -> C/C++ tab

    I suspect you could test the status of the FIFO, in order to see on which side of the FIFO the bottleneck is.

    Update 9.8.2016 You can see more precise timing in MCP by selecting File->Log file

    Update 18.8.2016 I have uploaded modified ble_app_uart example which features improved throughput from UART RX to BLE. The results I have measured end to end on nRF51-DK are:

    • No compiler optimization: 82 kbps
    • Optimization level 3 & optimized for time: 92 kbps

    I have set UART speed to 230.400 BAUD to prevent the UART from being the a throughput bottleneck. I have connected nRF52-DK board to the UART pins to feed the nRF51 with UART data, could be done also with any UART peer device that supports high UART BAUD rate. I have also set connection interval to 7.5ms in the improved ble_app_throughput example which should enable 128kbps on the BLE side. The bottleneck is CPU processing of transferring data from UART RX hardware buffer to softdevice TX buffer. For now, the example is not complete, as it is handles throughput only from UART RX to BLE TX. It is not documented either the changes I have made, but the main change is that I have rewritten the uart_event_handle handler for the APP_UART_DATA_READY event, which is byte received from RX UART.

    ble_app_uart_test_throughput.zip

    This example is tested with nRF5 SDK 11.0.0, S130 2.0.1 and nRF51-DK

    The logic for unmodified ble_app_uart:

    1. When byte is received on UART RX, put that into rx fifo buffer
    2. Take byte from rx fifo and store that into an array
    3. If array data size is 20 bytes, send it over BLE via nus service
    4. If softdevice buffer full (BLE_ERROR_NO_TX_PACKETS event), then assert

    The logic for the modified ble_app_uart:

    1. When byte is received on UART RX, put that into rx fifo buffer
    2. As long as there is data in rx fifo buffer and softdevice buffers are available, take data from rx fifo buffer and send packets over BLE via nus service
    3. On BLE_EVT_TX_COMPLETE event (BLE packet(s) have been sent), do step 2.
    4. On BLE_GATTS_EVT_WRITE event (BLE services enabled), do step 2.

    Update 24.8.2016 @YSK Thanks for your update and trying this out. I did not spent as much time on the modified ble_app_uart example as I wanted to. Work in progress. I actually first intended to do some optimization in the app_uart_fifo.c to further improve CPU speed, so I started out with linking to app_uart_fifo.c in the project folder. But I think now it was not necessary. Also it is best if modifications can be done purely in the application (not drivers and libraries).

    As central, I use MCP for PC together with Nordic dongle (PCA10001) with Master Emulator Firmware (MEFW) 11. That should allow maximum throughput. If I set original Connection interval in MCP to default 20ms, the ble_app_uart_test_throughput will send connection parameter update request 5 seconds after you enable services in MCP and update the connection interval to 7.5ms. If you anyway set connection interval to 7.5ms in MCP in File->Options, then no connection parameter update will occur. I attach the firmware I used to push UART TX from nRF52-DK board (no softdevice), but it should also work with a second nRF51-DK board.

    uart_throughput_test.zip

    I have tested througput without debug mode. I have enabled services in MCP and received data for a few seconds. From the UART peer side send a 16 bit counter value as data. On the MCP side I disable services after a few seconds, then look at the log file in File -> Log file. There I see Timing of messages and received data counter values. By looking at the received counter values in a certain time period, I can calculate the throughput. Ill anyway try to look at how it works in debug mode, thanks for the notification.

  • @YSK

    Well done about the “BLE_ERROR_NO_TX_PACKETS” packet! This error is normal to get when the softdevice buffers are full, which could happen for a very short time and should not be a showstopper. I think your solution to wait for BLE_EVT_TX_COMPLETE event is the way to go to allow for intermediate pause in packet transfer to the softdevice. Seems that the throughput is sufficient now for your intended purpose, am I correct?

    About the connection interval: Is the initial connection interval, which is set by the MCP, perhaps 20ms, so the connection parameter update never takes place? Is it perhaps that MCP does not accept minimum and maximum connection interval to be the same? You can adjust the interval initially set by MCP in File -> Options. Here is explained how the connection interval update procedure works.

  • @YSK

    The ble_app_uart implementation in the SDK does not handle high throughput well. That is not good as I believe the nRF51 can well handle the 54 kbps throughput you are asking for if the implementation was better. I will help you to reach this throughput next week with ble_app_uart. What you have implemented with the BLE_EVT_TX_COMPLETE event is the first improvement. I recently tested the 128kbps throughput on the BLE side, and it works fine. The UART can support 115 kbps and beond. The software implementation in between is the problem, and I believe we can improve it significantly.

Related