dart-archive / sdk

The Dartino project was an experiment seeking to improve productivity when writing application code for embedded devices.
https://dartino.org
Other
332 stars 36 forks source link

The STM32F7 UART device driver can get stuck sending #573

Closed sgjesse closed 8 years ago

sgjesse commented 8 years ago

While debugging https://github.com/dartino/sdk/issues/522 the connected screen to the STM32F746G Discovery board could stop getting UART data. The output could stop like this:

Hello Dartino!

Making HTTP request 30385...
Message from server:

Hello Dartino!

Making HTTP request 30386...
Message from server:

Hello Dartino!

M

while the test kept running until 100000+ requests.

Turned out that the sending should be in progress and the write buffer is full.

$1 = {size = 0x712000, remaining = 0xb40e8, free_lists = {0xc07faf08,
    0xc07faf68, 0xc07f94c8, 0xc07fbf80, 0x0, 0x0, 0x0, 0x0, 0xc07fafa8,
    0xc07fb420, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc07fb270,
    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc07fb020, 0x0, 0x0, 0x0, 0x0,
    0x2001a418, 0x0 <repeats 28 times>, 0xc07fd0c8, 0x0 <repeats 73 times>},
  free_list_bits = {0xf0c00808, 0x40000002, 0x0, 0x0, 0x0}}
(gdb) p/x *uart1
$2 = {error_ = 0x0, static kTxBlockSize = 0xa, read_data_ = 0x99,
  read_buffer_ = 0x2000cfe0, write_buffer_ = 0x2000ec70, uart_ = 0x20007924,
  device_id_ = 0x0, tx_mutex_ = 0x2000ee90, tx_data_ = {0x4d, 0x61, 0x72, 
    0x74, 0x69, 0x6e, 0x6f, 0x21, 0xd, 0xa}, tx_progress_ = 0x1,
  tx_length_ = 0x1, tx_pending_ = 0x1, signalThread_ = 0x2000f218}
(gdb) p/x *uart1->read_buffer_
$3 = {buffer_ = 0x2000ea68, capacity_ = 0x200, head_ = 0x0, tail_ = 0x0}
(gdb) p/x *uart1->write_buffer_
$4 = {buffer_ = 0x2000ec88, capacity_ = 0x200, head_ = 0x11d, tail_ = 0x11e}

Looking at the USART1 registers:

(gdb) x/11x 0x40011000
0x40011000:     0x0000012d      0x00000000      0x00000001      0x00000364
0x40011010:     0x00000000      0x00000000      0x00000000      0x006000d0
0x40011020:     0x00000000      0x00000000      0x0000004d
USART_CR1: 0x0000012d 100101101 (PS|RXNEIE|TE|RE|UE)
USART_CR2: 0x00000000
USART_CR3: 0x00000001
USART_BRR: 0x00000364
USART_GTPR: 0x00000000
USART_RTOR: 0x00000000
USART_RQR: 0x00000000
USART_ISR: 0x006000d0 (TEACK|TXE|TC|IDLE)
USART_ICR: 0x00000000
USART_RDR: 0x00000000
USART_TDR: 0x0000004d

The USART_CR1 register is missing the TXEIE flag (bit 7).

Turning it on in the debugger:

(gdb) set *((int *) 0x40011000) = 0x000001ad

Caused more output on screen

ello Dartino!

Making HTTP request 30387...
Message from server:

Hello Dartino!

Making HTTP request 30388...
Message from server:

Hello Dartino!

Making HTTP request 30389...
Message from server:

Hello Dartino!

Making HTTP request 30390...
Message from server:

Hello Dartino!

Making HTTP request 30391...
Message from server:

Hello Dartino!

Making HTTP request 30392...
Message from server:

Hello Dartino!

Making HTTP request 30393...
Message from server:

Hello Dartino!

Making H

Emptying the write buffer

(gdb) p/x *uart1
$5 = {error_ = 0x0, static kTxBlockSize = 0xa, read_data_ = 0x99,
  read_buffer_ = 0x2000cfe0, write_buffer_ = 0x2000ec70, uart_ = 0x20007924,
  device_id_ = 0x0, tx_mutex_ = 0x2000ee90, tx_data_ = {0x48, 0xd, 0xa, 0x4d,
    0x61, 0x6b, 0x69, 0x6e, 0x67, 0x20}, tx_progress_ = 0x1, tx_length_ = 0x0,
  tx_pending_ = 0x0, signalThread_ = 0x2000f218}
(gdb) p/x *uart1->write_buffer_
$6 = {buffer_ = 0x2000ec88, capacity_ = 0x200, head_ = 0x11d, tail_ = 0x11d}

Somehow the TXEIE flag gets cleared and not set again. Looking at the code the only place TXEIE is disabled is also setting tx_pending_ to false. However tx_pending_ is true so there is a race.