Peripheral UART, rx timeout and notification size

Hi,

I'm running the sample "peripheral_uart" on an nRF52dk. It has a config called CONFIG_BT_NUS_UART_RX_WAIT_TIME, which is set to 50. The comment says the unit is milliseconds. That value is sent into function uart_rx_enable(). When I read about that function (docs.zephyrproject.org/.../uart.html, it is said that the unit is microseconds. Which is correct?

What is the behaviour if two bytes are sent on UART to the DK right after each other? That is, the first bit of the second byte comes immediately after the first byte is finished. If communicating at 115200 it takes about 70 microseconds for a byte to be transmitted. If having the timeout set to 50 (supposing the unit is microseconds), will the timer expire before the byte is completed? Or how does the timer work?

What is a good value to have on the timer if communicating at 115200?

The sample handles long UART messages by splitting them into several 40-byte parts before they are supposed to be sent on BLE. But if a message is more than 21 bytes, I get the following warnings (in this case the UART message was 22 bytes):

<wrn> bt_att: No ATT channel for MTU 24
<wrn> bt_gatt: No buffer available to send notification
<wrn> peripheral_uart: Failed to send data over BLE connection

There is a maximum of 23 bytes (CONFIG_BT_L2CAP_TX_MTU) for notifcations. Is it meant that each programmer should solve this? If splitting, for instance, the UART-data into 20-byte parts instead of 40 bytes, it works fine.

Best regards,
Lars

  • Hello Lars,

    It seems like there are some mismatches between Zephyr and this NCS sample at this point in time. Zephyr updated this from ms to µs, and the peripheral UART sample didn't update anything. So the correct should be microseconds, but the peripheral_uart believes it is milliseconds. Try changing it from 50 to 50000.

    For the rest of your questions:

    All BLE connections start with a message size of 23 bytes of payload. After connecting, they can negotiate a higher message size (MTU) up to 247 bytes. What version of NCS are you using? I believed that this sample would already have the larger MTU negotiation implemented. Are you in a connection when you are testing this, or are you advertising?

    Best regards,

    Edvin

  • Hi Edvin,

    And thanks for your answers! Ok, so 50000 should be a good value when using 115200?

    But how does the rx timeout work? If I use 50 microseconds and run the UART at 115200 (70 microseconds for a whole byte), will there be an interrupt after each byte since the timer is set lower than it takes for a byte to be transmitted?

    I use version 1.8.0. Maybe it is updated to version 1.9.1?

    My device is connected when I test this.

    All BLE connections start with a message size of 23 bytes of payload. After connecting, they can negotiate a higher message size (MTU) up to 247 bytes.

    What does that mean? Is this negotiation performed automatically when the devices have connected, or do I need to do something explicitly to ba able to use a bigger payload?

    Best regards,

    Lars

  • Lars M said:
    And thanks for your answers! Ok, so 50000 should be a good value when using 115200?

    I see from the declaration of uart_rx_enable() in uart.h from ncs\zephyr\include\drivers\uart.h that this timeout is the inactivity period from receiving at least one byte until the UART_RX_RDY event is generated. If you set it to SYS_FOREVER_US, it disables the timeout, and the event will only be generated when the buffer is full. If you set it to any other value, then it will wait for that amount of time after receiving the last byte until it generates this event. 

    Using a baudrate of 115200 means that one byte takes 8/115200 = 0,0000694 seconds = 70µs.

    So to give it some slack, perhaps you want to set it to at least 100µs, but depending on your application, perhaps you want to set it back to 50 000, which is 50ms, in case the device transmitting the UART was held up doing something else for a while before resuming the UART.

    Lars M said:
    I use version 1.8.0. Maybe it is updated to version 1.9.1?

    This bug is still present in NCS v1.9.1.

    Actually, I wasn't aware of it before seeing this. I'll report it to our NCS team.

    Lars M said:
    What does that mean? Is this negotiation performed automatically when the devices have connected, or do I need to do something explicitly to ba able to use a bigger payload?

    It does not happen automatically. It takes some configs. You can look at the sample found in NCS\nrf\samples\bluetooth\throughput\prj.conf to see what CONFIGs you need to enable.

    These are probably a good starting point:

    CONFIG_BT_BUF_ACL_RX_SIZE=251
    CONFIG_BT_GATT_CLIENT=y
    CONFIG_BT_ATT_PREPARE_COUNT=2
    CONFIG_BT_CONN_TX_MAX=10
    CONFIG_BT_L2CAP_TX_BUF_COUNT=10
    CONFIG_BT_L2CAP_TX_MTU=247
    CONFIG_BT_L2CAP_DYNAMIC_CHANNEL=y
    CONFIG_BT_CTLR_PHY_2M=y
    CONFIG_BT_CTLR_RX_BUFFERS=2
    CONFIG_BT_BUF_ACL_TX_COUNT=10
    CONFIG_BT_BUF_ACL_TX_SIZE=251
    CONFIG_BT_CTLR_DATA_LENGTH_MAX=251

    I am not sure what all of them do, and you probably don't need all. You can look them up. I guess that e.g. CONFIG_BT_CONN_MAX=10 means you can queue 10 messages at once, which you might not need, while the CONFIG_BT_CTLR_DATA_LENGTH_MAX is related to the message length.

    You see that there are some numbers that are repeating, and different from one another. 247 and 251. These are just lengths with and without some headers.

    If you want to increase the packet size, you should also have a look at the main.c file for the throughput sample. The le_param_req(), le_param_updated() and le_data_length_updated() are functions that you can add to your main.c file. Remember to add them to the conn_callbacks in main.c as well.

    Other than that, you can request the data length update using bt_conn_le_data_len_update() like it is done in the connection_configuration_set() function in the throughput sample. You will see from the callbacks (particularly the le_data_length_updated()) what connection parameters you end up with.

    Please note that you can only request a new data length once in every connection. So if you want a large message length for your UART over BLE, try requesting the maximum allowed (247).

    Best regards,

    Edvin

  • Ok, thanks for your explanations! Yes, I will increase the timeout from 50, and set it to a value that suits my application. Don't really know yet how the UART messages in my application will work yet.

    But still I want to know what happens if I set the timeout to 50 and use 115200 (70 microseconds for a whole byte). Will there be an interrupt after each byte since the timer is set lower than it takes for a byte to be transmitted? The comment for timeout in the code is

    "Inactivity period after receiving at least a byte which triggers uart_event_type::UART_RX_RDY event."

    Is the inactivity period running during reception of a byte? And the timeout is cleared when a whole byte is completed? I have tried to figure it out by looking at the implementation of the uart in uart_nrfx_uarte.c. But I haven't succeeded yet.

    Good information when it comes to the negotiation-process. I don't know yet what my need will be there either, so I will also wait with this part.

    Best regards,
    Lars

  • Lars M said:
    But still I want to know what happens if I set the timeout to 50 and use 115200 (70 microseconds for a whole byte). Will there be an interrupt after each byte since the timer is set lower than it takes for a byte to be transmitted?

    In theory, yes, you should get an interrupt on every byte. But at these limits I guess you would see it from time to time, since interrupts at this speed may be delayed in an OS (zephyr). Have you tested?

    Best regards,

    Edvin

Related