1. устройство подключается к хосту, успешно проходит энумерацию, чтение дескрипторов и т.п. (lsusb -vvv показывает все правильно);
2. в устройстве активируется bulk-in endpoint в режиме double buffer и SW_BUF/DTOG_TX биты ставятся в положение 1/0, настраиваются адреса буферов для передачи в памяти пакетов (два буфера), данные для передачи записываются в область памяти первого буфера и его счетчик передачи устанавливается равным 60. При этом второй буфер в памяти пакетов заполняется характерной сигнатурой и его размер устанавливается равным 11 (это несущественно). Статус endpoint устанавливается равным TX_VALID;
3. на хосте программа в цикле с помощью libusb пытается выполнить передачи блоков данных размером 64 байта (чтение из устройства, bulk in);
4. запускаем программу и получаем два буфера данных, вместо одного (60 и 11 байт). При этом второй буфер передается несмотря на то, что после передачи первого буфера SW_BUF/DTOG_TX == 11, т.е. согласно описанию передача должна приостановиться до момента, когда SW_BUF/DTOG_TX станут равны 01 соответственно.
Получается, что контроллер отправляет второй буфер "авансом", несмотря на состояние специальных разрядов управления потоком передачи. На больших блоках данных, например, при работе с mass storage это незаметно, т.к. второй буфер используется сразу "по делу" и эта паразитная передача не мешает. Однако если, например, выполнять поллинг состояния устройства с помощью bulk-in endpoint, то второй пакет будет содержать неожиданные данные, которые не были еще сформированы программой в микроконтроллере.
Интересно то, что после еще одной отправки, т.е. когда состояние SW_BUF/DTOG в вышеописанном примере перейдет из 01 в 00, передача честно остановится, контроллер будет отправлять NAK при попытке передачи данных через bulk-in и описанный в документации механизм flow control начинает работать согласно описанию. Но это не дает ответа, что делать со вторым блоком данных, который отправляется вопреки всему. В errata на этот счет никаких данных нет. В STM32CubeMX драйвер HAL PCD реализован из рук вон плохо в области работы с double-buffered endpoint и поэтому как источник информации о правильном методе работы в этом режиме служить не может. В других открытых библиотеках этого режима нет.
С другой стороны опыт показывает, что разница в скорости передачи между single-buffered bulk-in endpoint и double-buffered не превышает 10% по нашим замерам (800 кБайт/с против 870 кБайт/с в тесте передачи блоков внутреннего флеша без использования DMA), поэтому применение этого режима трудно назвать критичным. Но все же интересно, у кого-нибудь он работает правильно и согласно описанию производителя?
