Custom ethernet device does not reconnect on M4 iPad Pro

We are experiencing problems with the USB port on iPad Pro 11 inch (M4) model number MVW13NF/A. Our custom peripheral device (based on Raspberry Pi Pico + tinyUSB stack, is configured as a network adapter class and has communication with our App over UDP protocol. Our device also acts as a DHCP server, providing the IP address for iPad.

The problem can be described as a “bus stall” or "bus hold" after sleep mode. To reproduce it we just send the iPad into sleep mode using a power button, the USB bus on M4 goes to the suspended state and won’t resume anymore when we wake the iPad up.

The problem has occurred since the upgrade to iOS 18.2.1 and has not been observed before on the previously installed iOS 17 on the same iPad Pro M4.

Also, the problem does not happen on the iPad Pro 11 inch (3rd gen with M1) model number MHW73FD/A, with the same iOS 18.2.1 installed. The problem also does not arise, if we connect our device via USB hub to the same iPad Pro M4.

We have tested different versions of tinyUSB stack (either included in RPi Pico SDK or native unpatched). The problem is independent of the library version. It occurs always if our device is connected directly to the USB port of iPad Pro (M4) with iOS 18. It also stays after upgrading to the latest iOS 18.3 (beta)

In the attached logs is (reduced for clarity) debug output from tinyUSB library about events on the USB bus. These logs were captured via RTT debugging output, using Segger J-Link debugger, so logging process does not affect the timings on the USB bus.

There are three logs attached, for cases 1: "iPad Pro M4 + iOS18" (i.e. problematic case), 2: "iPad Pro M1 + iOS18", and 3: "iPad Pro M4 + iOS18 + external USB hub" (they are non-problematic cases).

CASE 1: USB communications on the bus (iPadPro M4 + iOS 18.3), until the bus stalled.


00> USBD Setup Received 00 05 02 00 00 00 00 00 
00>   Set Address
00>   Prepare BufCtrl: [0] = 0xf400  [1] = 0x0000
00> buf_status = 0x00000001
00>   Sync BufCtrl: [0] = 0x6000  [1] = 0x0000
00>   Short packet on buffer 0 with 0 bytes
00> Completed transfer of 0 bytes on ep 80
00> USBD Xfer Complete on EP 80 with 0 bytes
00> 
00> USBD Setup Received 80 06 00 01 00 00 08 00 
00>   Get Descriptor Device
00>   Queue EP 80 with 8 bytes ...
00>   Prepare BufCtrl: [0] = 0xf408  [1] = 0x0000
00> buf_status = 0x00000001
00>   Sync BufCtrl: [0] = 0x6008  [1] = 0x0000
00>   Short packet on buffer 0 with 8 bytes
00> Completed transfer of 8 bytes on ep 80
00> USBD Xfer Complete on EP 80 with 8 bytes
00>   Queue EP 00 with 0 bytes ...
00>   Prepare BufCtrl: [0] = 0x7400  [1] = 0x0000
00> buf_status = 0x00000002
00>   Sync BufCtrl: [0] = 0xe000  [1] = 0x0000
00>   Short packet on buffer 0 with 0 bytes
00> Completed transfer of 0 bytes on ep 00
00> USBD Xfer Complete on EP 00 with 0 bytes
00> 
00> USBD Setup Received 80 06 00 01 00 00 12 00 
00>  Device
00> 
00> 
00>   Queue EP 82 with 42 bytes ...
00>   Prepare BufCtrl: [0] = 0xf42a  [1] = 0x0000
00> buf_status = 0x00000010
00>   Sync BufCtrl: [0] = 0x602a  [1] = 0x0000
00>   Short packet on buffer 0 with 42 bytes
00> Completed transfer of 42 bytes on ep 82
00> USBD Xfer Complete buf_status = 0x00000020
00>   Sync BufCtrl: [0] = 0xa02a  [1] = 0x0000
00>   Short packet on buffer 0 with 42 bytes
00> Completed transfer of 42 bytes on ep 02
00> on EP 82 with 42 bytes
00>   NET xfer callback
<----CUTOUT-FOR-REGULAR-TRAFFIC-ON-THE-BUS----------------->

00>   NET xfer callback
00> USBD Xfer Complete on EP 80 with 0 bytes
00> buf_status = 0x00000004
00>   Sync BufCtrl: [0] = 0x4008  [1] = 0x0000
00>   Short packet on buffer 0 with 8 bytes
00> Completed transfer of 8 bytes on ep 81
00> USBD Xfer Complete on EP 81 with 8 bytes
00>   NET xfer callback
00>   Queue EP 81 with 16 bytes ...
00> Prepare BufCtrl: [0] = 0xf410  [1] = 0x0000

5 SECONDS AFTER ENTER INTO SLEEP MODE! (M4 iPad + iOS 18)

00> USBD Suspend : Remote Wakeup = 0
00> BUS RESET
00> USBD Bus Reset: Full Speed


SINCE THIS MOMENT THE USB BUS STALLS!

CASE 2: SAME TEST BUT FOR M1 iPadPro + iOS18.2.1


START  of INIT

00> USBD Setup Received 00 05 01 00 00 00 00 00 
00>   Set Address
00>   Prepare BufCtrl: [0] = 0xf400  [1] = 0x0000
00> buf_status = 0x00000001
00>   Sync BufCtrl: [0] = 0x6000  [1] = 0x0000
00>   Short packet on buffer 0 with 0 bytes
00> Completed transfer of 0 bytes on ep 80
00> USBD Xfer Complete on EP 80 with 0 bytes
00> USBD Setup Received 00 09 02 00 00 00 00 00 
00>   Set Configuration
00>   Open EP 81 with Size = 64
00>   Allocated 64 bytes at offset 0x180 (0x50100180)
00>   NET opened
00>   Bind EP 81 to driver id 0
00>   Bind EP 82 to driver id 0
00>   Bind EP 02 to driver id 0
00>   Queue EP 80 with 0 bytes ...
00>   Prepare BufCtrl: [0] = 0xf400  [1] = 0x0000
00> buf_status = 0x00000001
00>   Sync BufCtrl: [0] = 0x6000  [1] = 0x0000
00>   Short packet on buffer 0 with 0 bytes
00> Completed transfer of 0 bytes on ep 80
00> USBD Xfer Complete on EP 80 with 0 bytes
00> 
00> USBD Setup Received 80 06 04 03 09 04 02 00 
00>   Get Descriptor String[4]
00>   Queue EP 80 with 2 bytes ...
00>   Prepare BufCtrl: [0] = 0xf402  [1] = 0x0000
00> buf_status = 0x00000001
00>   Sync BufCtrl: [0] = 0x6002  [1] = 0x0000
00>   Short packet on buffer 0 with 2 bytes
00> Completed transfer of 2 bytes on ep 80
00> USBD Xfer Complete on EP 80 with 2 bytes
00>   Queue EP 00 with 0 bytes ...
00>   Prepare BufCtrl: [0] = 0x7400  [1] = 0x0000
00> buf_status = 0x00000002
00>   Sync BufCtrl: [0] = 0xe000  [1] = 0x0000
00>   Short packet on buffer 0 with 0 bytes
00> Completed transfer of 0 bytes on ep 00
00> USBD Xfer Complete on EP 00 with 0 bytes
00> 
00> USBD Setup Received 80 06 04 03 09 04 34 00 
00>   Get Descriptor String[4]
00>   Queue EP 80 with 52 bytes ...
00>   Prepare BufCtrl: [0] = 0xf434  [1] = 0x0000
00> buf_status = 0x00000001
00>   Sync BufCtrl: [0] = 0x6034  [1] = 0x0000
00>   Short packet on buffer 0 with 52 bytes
00> Completed transfer of 52 bytes on ep 80
00> USBD Xfer Complete on EP 80 with 52 bytes
00>   Queue EP 00 with 0 bytes ...
00>   Prepare BufCtrl: [0] = 0x7400  [1] = 0x0000
00> buf_status = 0x00000002
00>   Sync BufCtrl: [0] = 0xe000  [1] = 0x0000
00>   Short packet on buffer 0 with 0 bytes
00> Completed transfer of 0 bytes on ep 00
00> USBD Xfer Complete on EP 00 with 0 bytes
00> 
00> USBD Setup Received 01 0B 00 00 01 00 00 00 
00>   Set Interface
00>   NET control request
00>   Queue EP 80 with 0 bytes ...
00>   Prepare BufCtrl: [0] = 0xf400  [1] = 0x0000
00> buf_status = 0x00000001
00>   Sync BufCtrl: [0] = 0x6000  [1] = 0x0000
00>   Short packet on buffer 0 with 0 bytes
00> Completed transfer of 0 bytes on ep 80
00> USBD Xfer Complete on EP 80 with 0 bytes
00> 
00> USBD Setup Received 01 0B 01 00 01 00 00 00 
00>   Set Interface
00>   NET control request
00>   Open EP 82 with Size = 64
00>   Allocated 128 bytes at offset 0x1c0 (0x501001C0)
00>   Open EP 02 with Size = 64
00>   Allocated 128 bytes at offset 0x240 (0x50100240)
00>   Queue EP 02 with 1602 bytes ...
00>   Prepare BufCtrl: [0] = 0x1440  [1] = 0x0000
00>   Queue EP 80 with 0 bytes ...
00>   Prepare BufCtrl: [0] = 0xf400  [1] = 0x0000
00> buf_status = 0x00000001
00>   Sync BufCtrl: [0] = 0x6000  [1] = 0x0000
00>   Short packet on buffer 0 with 0 bytes
00> Completed transfer of 0 bytes on ep 80
00> USBD Xfer Complete on EP 80 with 0 bytes
00> 
00> USBD Setup Received 21 43 00 00 00 00 00 00 
00>   NET control request
00>   Queue EP 80 with 0 bytes ...
00>   Prepare BufCtrl: [0] = 0xf400  [1] = 0x0000
00>   Queue EP 81 with 8 bytes ...
00>   Prepare BufCtrl: [0] = 0xd408  [1] = 0x0000
00> buf_status = 0x00000001
00>   Sync BufCtrl: [0] = 0x6000  [1] = 0x0000
00>   Short packet on buffer 0 with 0 bytes
00> Completed transfer of 0 bytes on ep 80
00> USBD Xfer Complete on EP 80 with 0 bytes
00> 
00> USBD Setup Received 80 06 05 03 09 04 02 00 
00>   Get Descriptor String[5]
00>   Queue EP 80 with 2 bytes ...
00>   Prepare BufCtrl: [0] = 0xf402  [1] = 0x0000
00> buf_status = 0x00000001
00>   Sync BufCtrl: [0] = 0x6002  [1] = 0x0000
00>   Short packet on buffer 0 with 2 bytes
00> Completed transfer of 2 bytes on ep 80
00> buf_status = 0x00000010
00>   Sync BufCtrl: [0] = 0x0040  [1] = 0x2040
00>   Prepare BufCtrl: [0] = 0x9440  [1] = 0xa440
00> buf_status = 0x00000010
00>   Sync BufCtrl: [0] = 0x0040  [1] = 0x2040
00>   Prepare BufCtrl: [0] = 0xd42e  [1] = 0x0000
00> USBD Xfer Complete buf_status = 0x00000010
00>   Sync BufCtrl: [0] = 0x402e  [1] = 0x0000
00>   Short packet on buffer 0 with 46 bytes
00> Completed transfer of 558 bytes on ep 82
00> on EP 02 with 62 bytes
00>   NET xfer callback
00> USBD Xfer Complete buf_status = 0x00000004
00>   Sync BufCtrl: [0] = 0x6010  [1] = 0x0000
00>   Short packet on buffer 0 with 16 bytes
00> Completed transfer of 16 bytes on ep 81
00> USBD Xfer Complete on EP 81 with 16 bytes
00>   NET xfer callback

<----CUTOUT-OF-REGULAR-TRAFFIC-ON-THE-BUS----------------->

00> Completed transfer of 8 bytes on ep 81
00> USBD Xfer Complete on EP 81 with 8 bytes
00>   NET xfer callback
00>   Queue EP 81 with 16 bytes ...
00> Prepare BufCtrl: [0] = 0xf410  [1] = 0x0000

ON M1 iPAD � WENT ONTO SLEEP MODE

00> USBD Suspend : Remote Wakeup = 0

NO BUS RESET! THEN, THE CORRECT WAKE-UP WAS PERFORMED AND DEVICE FUNCTIONS WERE RESTORED

00>   Queue EP 82 with 42 bytes ...
00>   Prepare BufCtrl: [0] = 0xd42a  [1] = 0x0000
      
      00> USBD Resume 

Correct resuming of the bus.

00> buf_status = 0x00000010
00>   Sync BufCtrl: [0] = 0x402a  [1] = 0x0000
00>   Short packet on buffer 0 with 42 bytes
00> Completed transfer of 42 bytes on ep 82
00> USBD Xfer Complete on EP 82 with 42 bytes
00>   NET xfer callback
00> 
00> USBD Setup Received 21 43 0E 00 00 00 00 00 



00>   NET control request
00>   Queue EP 80 with 0 bytes ...
00>   Prepare BufCtrl: [0] = 0xf400  [1] = 0x0000
00> buf_status = 0x00000001

CASE 3 : 

The iPad Pro is the same M4-based model as in case 1 + USB HUB. Our device connected via a USB hub. 

00> USBD Setup Received 00 05 06 00 00 00 00 00 
00>   Set Address
00>   Prepare BufCtrl: [0] = 0xf400  [1] = 0x0000
00> buf_status = 0x00000001
00>   Sync BufCtrl: [0] = 0x6000  [1] = 0x0000
00>   Short packet on buffer 0 with 0 bytes
00> Completed transfer of 0 bytes on ep 80
00> USBD Xfer Complete on EP 80 with 0 bytes
00> 
00> USBD Setup Received 80 06 00 01 00 00 08 00 
00>   Get Descriptor Device
00>   Queue EP 80 with 8 bytes ...
00>   Prepare BufCtrl: [0] = 0xf408  [1] = 0x0000
00> buf_status = 0x00000001
00>   Sync BufCtrl: [0] = 0x6008  [1] = 0x0000
00>   Short packet on buffer 0 with 8 bytes
00> Completed transfer of 8 bytes on ep 80
00> USBD Xfer Complete on EP 80 with 8 bytes
00>   Queue EP 00 with 0 bytes ...
00>   Prepare BufCtrl: [0] = 0x7400  [1] = 0x0000
00> buf_status = 0x00000002
00>   Sync BufCtrl: [0] = 0xe000  [1] = 0x0000
00>   Short packet on buffer 0 with 0 bytes
00> Completed transfer of 0 bytes on ep 00
00> USBD Xfer Complete on EP 00 with 0 bytes
00> 
00> USBD Setup Received 80 06 00 01 00 00 12 00 
00> 
00> 
00> buf_status = 0x00000020
00>   Sync BufCtrl: [0] = 0xa040  [1] = 0x0000
00>   Prepare BufCtrl: [0] = 0x1440  [1] = 0x0000
00> buf_status = 0x00000020
00>   Sync BufCtrl: [0] = 0x8040  [1] = 0x0000
00>   Prepare BufCtrl: [0] = 0x3440  [1] = 0x0000
00> buf_status = 0x00000020
00>   Sync BufCtrl: [0] = 0xa010  [1] = 0x0000
00>   Short packet on buffer 0 with 16 bytes
00> Completed transfer of 144 bytes on ep 02
00>   Queue EP 82 with 42 bytes ...
00>   Prepare BufCtrl: [0] = 0xf42a  [1] = 0x0000
00> USBD Xfer Complete on EP 02 with 144 bytes
00> buf_status = 0x00000010
00>   Sync BufCtrl: [0] = 0x602a  [1] = 0x0000
00>   Short packet on buffer 0 with 42 bytes
00> Completed transfer of 42 bytes on ep 82
00>   NET xfer callback

<----CUTOUT-FOR-REGULAR-TRAFFIC-ON-THE-BUS----------------->

00>   NET xfer callback
00> USBD Xfer Complete on EP 80 with 0 bytes
00> buf_status = 0x00000004
00>   Sync BufCtrl: [0] = 0x4008  [1] = 0x0000
00>   Short packet on buffer 0 with 8 bytes
00> Completed transfer of 8 bytes on ep 81
00> USBD Xfer Complete on EP 81 with 8 bytes
00>   NET xfer callback
00>   Queue EP 81 with 16 bytes ...
00>   Prepare BufCtrl: [0] = 0xf410  [1] = 0x0000

WENT INTO SLEEP MODE on M4 + HUB.

00> USBD Suspend : Remote Wakeup = 0
00>   Queue EP 82 with 42 bytes ...
00>   Prepare BufCtrl: [0] = 0xd42a  [1] = 0x0000

00> USBD Resume 

And the bus woke up, as expected

00> buf_status = 0x00000010
00>   Sync BufCtrl: [0] = 0x402a  [1] = 0x0000
00>   Short packet on buffer 0 with 42 bytes
00> Completed transfer of 42 bytes on ep 82
00> USBD Xfer Complete on EP 82 with 42 bytes
00>   NET xfer callback
00> 
00> USBD Setup Received 21 43 0E 00 00 00 00 00 
00>   NET control request
00>   Queue EP 80 with 0 bytes ...
00>   Prepare BufCtrl: [0] = 0xf400  [1] = 0x0000
00> buf_status = 0x00000001
00>   Sync BufCtrl: [0] = 0x6000  [1] = 0x0000
00>   Short packet on buffer 0 with 0 bytes
00> Completed transfer of 0 bytes on ep 80
00> USBD Xfer Complete on EP 80 with 0 bytes
00> 
00> USBD Setup Received 21 43 0E 00 00 00 00 00 
00>   NET control request
00>   Queue EP 80 with 0 bytes ...
00> buf_status = 0x00000004
00>   Sync BufCtrl: [0] = 0x6010  [1] = 0x0000
00>   Short packet on buffer 0 with 16 bytes
00> Completed transfer of 16 bytes on ep 81
00>   Prepare BufCtrl: [0] = 0xf400  [1] = 0x0000
00> buf_status = 0x00000001
00>   Sync BufCtrl: [0] = 0x6000  [1] = 0x0000
00>   Short packet on buffer 0 with 0 bytes
00> Completed transfer of 0 bytes on ep 80
00> buf_status = 0x00000020
00>   Sync BufCtrl: [0] = 0xa02a  [1] = 0x0000
00>   Short packet on buffer 0 with 42 bytes
00> Completed transfer of 42 bytes on ep 02
00> USBD Xfer Complete 
00> 21 43 0E 
00>   Short packet on buffer 0 with 0 bytes
00> Completed transfer of 0 bytes on ep 80
00> buf_status = 0x00000020
00>   Sync BufCtrl: [0] = 0x8040  [1] = 0x0000
00>   Prepare BufCtrl: [0] = 0x3440  [1] = 0x0000
00> buf_status = 0x00000020
00>   Sync BufCtrl: [0] = 0xa040  [1] = 0x0000
00>   Prepare BufCtrl: [0] = 0x1440  [1] = 0x0000
00>   Queue EP 81 with 8 bytes ...
00> buf_status = 0x00000020
00>   Sync BufCtrl: [0] = 0x8040  [1] = 0x0000
00> buf_status = 0x00000020
00> USBD Xfer Complete   Prepare BufCtrl: [0] = 0xf42e  [1] = 0x0000
00> buf_status = 0x00000010
00>   Sync BufCtrl: [0] = 0x602e  [1] = 0x0000
00>   Short packet on buffer 0 with 46 bytes
00> Completed transfer of 558 bytes on ep 82
00> USBD Xfer Complete on EP 82 with 558 bytes
00>   NET xfer callback
00> buf_status = 0x00000004
00>   Sync BufCtrl: [0] = 0x4008  [1] = 0x0000
00>   Short packet on buffer 0 with 8 bytes
00> Completed transfer of 8 bytes on ep 81
00> USBD Xfer Complete on EP 81 with 8 bytes
00>   NET xfer callback

So, on the same iPad but with the external USB Hub communications we can observe the correct behavior of the USB bus in sleep mode.

This was already posted as feedback with id FB16366509

This was already posted as feedback with id FB16366509

Thank you, that's the most important step with something like this. Poking at a few details from you description:

The problem also does not arise, if we connect our device via USB hub to the same iPad Pro M4.

Is the USB hub powered? If the hub is providing power, then that ends up creating an entirely different scenario, as the device is going to keep the USB bus relatively "active" so that it can continue to pull power.

The problem can be described as a “bus stall” or "bus hold" after sleep mode. To reproduce it we just send the iPad into sleep mode using a power button, the USB bus on M4 goes to the suspended state and won’t resume anymore when we wake the iPad up.

I haven't dug into the logs, but are you seeing any activity on the bus when the iPad wakes up again? Similarly, did the working device fully power down the bus durring sleep?

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

No we did not. You can find the latest activity reported in the logs in the case1_usbd_log.txt after 5 seconds of sleep: USBD Suspend : Remote Wakeup = 0 BUS RESET USBD Bus Reset: Full Speed

Huh. Have you tried using a bus analyzer to compare the two cases, particularly the hub vs. no hub case?

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Written by DTS Engineer in 827025022
Have you tried using a bus analyzer

No, as we do not have access to one. We are considering getting the Cynthion USB Protocol Analyzer. Do you think it does the job?

Custom ethernet device does not reconnect on M4 iPad Pro
 
 
Q