У нас на плате контроллер STM32F205VG и память AT45DB321E . Эта плата подключается к ПК и прикидывается флэшкой.
Чтобы понять как работает USBD девайс на STM32 , который эмулирует USB флэш память, придется :
1. Воспользоваться какой-нибудь программой мониторинга USB портов на ПК ( у нас под Windows).
2. Поставить printf (SWO) на всех значимых USB функциях (а еще лучше на всех функциях) типа USBD_LL_Transmit, USBD_Ctl.... SWO похоже все это без труда потянет (без зависаний).
3. Не будем разделять работу с флэш памятью и USB MSD на разные потоки (НЕ используем FreeRTOS), т.к. все-равно HAL реализация USBD MSD девайса не предполагает использование потоковой модели, т.к. USBD работает из прерывания.
Прерывания USB, коллбек функции
Откуда вызываются коллбеки
Коллбеки - это функции , которые нам надо заполнить своим кодом работы с флэш памятью AT45.
STORAGE_Read_FS
Источник,откуда вызывается callback функция - это прерывание от USB канала. Итак все тайное становится явным.
OTG_FS_IRQHandler [stm32f2xx_it.c] первый обработчик прерывания
HAL_PCD_IRQHandler // идет разбор флагов прерывания из USB канала. Далее по коллбекам обрабатываем их раздельно.
HAL_PCD_DataInStageCallback
USBD_LL_DataInStage
USBD_MSC_DataIn (см. указатель на функцию с структуре USBD_MSC)
MSC_BOT_DataIn (MSC_BOT_DataOut|MSC_BOT_CBW_Decode)
SCSI_ProcessCmd
SCSI_Read10
SCSI_ProcessRead
STORAGE_Read_FS = (pdev->pUserData->Read) ----------------- здесь наши коллбеки
SCSI_ProcessRead (MSC_BOT_SendData или MSC_BOT_SendCSW или USBD_CtlSendData или USBD_CtlContinueSendData или USBD_CtlSendStatus)
USBD_LL_Transmit
HAL_PCD_EP_Transmit
USB_EPStartXfer
Коллбек функция STORAGE_Read_FS вызывается из прерывания OTG_FS_IRQHandler .
Нам надо успеть прочитать(записать) из микросхемы памяти AT45 512байт и поскольку делается это естественно в прерывании , то возникает много вопросов.
По любому из прерывания надо выходить как можно быстрее.
Но если STORAGE_Read_FS завершается с любым результатом >=0 , то сразу идет отсылка данных хосту. А мы их еще не прочитали (надо примерно 3мс). А если надо записать, или еще круче стереть. Что все ждем в прерывании?
И как ни странно - ответ - ДА!
Что будет , если в коллбеке STORAGE_Read_FS сделать задержку более 1мс, а точнее 0.960652050 .. 1.465651240 = 0.52 секунды!
Как ни странно все нормально продолжает работать! Не смотря на , то что вызов происходит из прерывания USB.
Главное во всех функциях вызываемых из STORAGE_Read_FS, надо убрать _IT функции , т.е. не использовать функции основанные на прерываниях.
Также НЕ следует выделять работу с микросхемой флэш памяти в отдельный поток , т.к. переключится на этот поток не получится из прерывания (под FreeRTOS).
0.960652050,DATA0,,,,0x55 0x53 0x42 0x43 0xA0 0x19 0x43 0xF6 0x00 0x02 0x00 0x00 0x80 0x00 0x0A 0x28 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00,0x1D03
0.960675990,ACK,,,,,
.....
1.465651240,DATA0,,,,0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF,0x40FE
Почему так работает? Потому,что контроллер продолжает во время (пока мы сидим STORAGE_Read_FS) нормально отвечать NAK-ом (типа : я занят):
0.960517930,IN,0x23,0x01,,,0x0D
0.960521220,NAK,,,,,
....
То есть ответ NAK,,,,, реализуется на аппаратном уровне,как-то еще до контроллера прерываний.
файлы, файлы, файлы
Выбираем спокойный день и ковыряемся в исходниках кода , сгенерированного Cube Mx для STM32F205VG USBD MSD. В каждой функции добавляем printf ().
Все , что нам надо здесь :
Весь код открытый , нам надо просто разобраться в этой каше.
USB Core
usbd_ioreq.c
usbd_core.c
usbd_ctlreq.c
MSC - Mass Storage Controller
usbd_msc_bot.c
usbd_msc.c
usbd_msc_data.c
usbd_msc_scsi.c
Конфигурация и Callbacks функции
usb_device.c
usbd_conf.c
usbd_desc.c
usbd_storage_if.c
еще это
stm32f2xx_hal_pcd.c
stm32f2xx_ll_usb.c
Ищем и читаем даташиты с https://www.usb.org/documents?search=mass&items_per_page=50
И вот теперь становится кое-то явным , что от нас скрыто
А вот тоже маленький , но уже в текстовом представлении из того же LA1010.
0.825396840,OUT,0x20,0x01,,,0x05
0.825400110,DATA0,,,,0x55 0x53 0x42 0x43 0x10 0xDA 0xDA 0x04 0x00 0x02 0x00 0x00 0x80 0x00 0x0A 0x28 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00,0xB1B7
0.825424030,ACK,,,,,
0.825440180,IN,0x20,0x01,,,0x05
... тут повторы IN / NAK
0.829039290,IN,0x20,0x01,,,0x05
0.829042550,DATA0,,,,0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF,0x40FE
0.829095670,ACK,,,,,
все данные переданы
0.829098080,IN,0x20,0x01,,,0x05
0.829101390,NAK,,,,,
... опять повторы IN / NAK
0.830468990,IN,0x20,0x01,,,0x05
0.830472290,NAK,,,,,
0.830474730,IN,0x20,0x01,,,0x05
0.830478030,NAK,,,,,
0.830500410,IN,0x20,0x01,,,0x05
0.830503710,NAK,,,,,
... и далее опять повторы IN / NAK
Получается так :
OUT,0x20,0x01,,,0x05 хост посылает команду
IN,0x20,0x01,,,0x05 - это запрос хоста - ну , что готовы дынные?
NAK - (и их несколько) это ответ девайса, что он принял , но не данные у него еще не готовы
SOF - (иногда) это команда от хоста (просто каждую 1 милисекунду посылается по протоколу)
DATA1 это девайс передает наконец-то данные на очередной запрос IN,0x20,0x01,,,0x05 (FF FF FF ... это флэшка отдает содержание первой своей страницы) это STORAGE_Read_FS
ACK это девайс рапортует, что данные передал
И дальше опять
IN,0x20,0x01,,,0x05
NAK
............ много раз
Почему? - наверное потому , что хосту тоже надо время подумать для передачи следующей команды.
Периоды следования запросов IN,0x20,0x01,,,0x05 - намного меньше 1 милисекунды.
Выводы
Из выше проверенного понятно пока одно : исходники из CubeMX с HAL рабочие , т.е. флэшку мы реализовали.
Она форматируется нормально и туда даже можно записать сразу файл.
Но если все делать в потоках (по взрослому) , то надо все исходники переписывать и работать на уровне регистров USB.
Ниже выкладываю как обычно выстраданный проект на Atollic True Studio.
Файлы для скачивания
*
*
с SWO трассировкой, контроллер STM32 работает как флэшка , которую подключают к ПК