-
Notifications
You must be signed in to change notification settings - Fork 2.1k
nRF52 uart_write get stuck #5954
Description
Using nRF52DK, I have found conditions where the uart_write function stays stuck on waiting the character to be sent(
RIOT/cpu/nrf5x_common/periph/uart.c
Line 146 in 8a74475
| while (NRF_UART0->EVENTS_TXDRDY == 0) {} |
The way to reproduce this is : use the example/microcoap_server, setup the IPv6/6lowPan connection with a host and send ping request every 5s for instance. (the 5s depends on the configuration of the debug functions you have turned on as they change the timing of the processing). I have turned on several enable_debug flags in several module as I'm debugging different ping instabilities(see note below).
Very often, I get the 6lowpan thread stuck on the uart_write function looping on this line :
while (NRF_UART0->EVENTS_TXDRDY == 0) {}
Note: there are other instabilities with the ping and this example/setup: 1/ sometimes the memory is full and thus the ping reply will not be sent. 2/ at some point when configuring the host for IPv6/6lowpan, the UART send garbage characters and then recover.
In my configuration, I have ENABLE_DEBUG(1) for :
pkg/nordic_softdevice_ble/src/ble-mac.c
pkg/nordic_softdevice_ble/src/gnrc_nordic_ble_6lowpan.c
sys/net/gnrc/netapi/gnrc_netapi.c
sys/net/gnrc/network_layer/icmpv6/echo/gnrc_icmpv6_echo.c
sys/net/gnrc/network_layer/icmpv6/gnrc_icmpv6.c
sys/net/gnrc/network_layer/ipv6/gnrc_ipv6.c
sys/net/gnrc/network_layer/sixlowpan/gnrc_sixlowpan.c
sys/net/gnrc/pktbuf_static/gnrc_pktbuf_static.c
In order to workaround this stuck/infinite loop condition, I have modified the uart_write function this way:
void uart_write(uart_t uart, const uint8_t data, size_t len)
{
int count=0;
if (uart == 0) {
for (size_t i = 0; i < len; i++) {
/ write data into transmit register /
NRF_UART0->TXD = data[i];
/ wait for any transmission to be done /
while ((NRF_UART0->EVENTS_TXDRDY == 0)&&(count<1000)) {count+=1;}
if (count >= 1000) dropped+=1;
/ reset ready flag */
NRF_UART0->EVENTS_TXDRDY = 0;
if (count>max_count) max_count=count;
count=0;
}
}
}
I have checked that a "normal" character transfer takes less than 400 while loop iterations, thus deciding to use 1000 as a detection for abnormal condition and decision to drop and continue.
I would like to get feedback on this workaround to discuss if we want to root cause the issue that may take time or put this ugly safeguard to avoid getting the system stuck.