|
STM32CubeMX и USB CDC, какие функции использовать? |
|
|
3 страниц
< 1 2 3
|
 |
Ответов
(30 - 44)
|
Jul 31 2014, 12:18
|
Частый гость
 
Группа: Участник
Сообщений: 139
Регистрация: 9-11-12
Из: Санкт-Петербург
Пользователь №: 74 315

|
Цитата(Atlantis- @ Jul 31 2014, 14:42)  я прикрутил прием данных в USBD_LL_DataOutStage Вот этого не понял Цитата(Atlantis- @ Jul 31 2014, 14:42)  можете показать содержимое функции USBD_LL_DataOutStage, а то у меня там никакой USBD_CDC_DataOut нет, она фигурирует только в структуре Так там тоже через таблички всё идёт. Предложение. Проверьте свежесгенерированный кубом код, измените только эти две функции: Код static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len) { /* USER CODE BEGIN 7 */ CDC_Transmit_FS(Buf, *Len); USBD_CDC_ReceivePacket(hUsbDevice_0); return (USBD_OK); /* USER CODE END 7 */ } uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) { uint8_t result = USBD_OK; /* USER CODE BEGIN 8 */ memcpy(UserTxBufferFS,Buf,Len); USBD_CDC_SetTxBuffer(hUsbDevice_0, UserTxBufferFS, Len); result = USBD_CDC_TransmitPacket(hUsbDevice_0); /* USER CODE END 8 */ return result; } Должно эхом возвращать то, что принимает. Хе, сейчас вот наткнулся на баг в F0 Код USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev) { ... hpcd_USB_FS.Init.dev_endpoints = 8; Код PCD_EPTypeDef IN_ep[5]; /*!< IN endpoint parameters */ PCD_EPTypeDef OUT_ep[5]; /*!< OUT endpoint parameters */ Из-за этого херится чужая память.
|
|
|
|
|
Jul 31 2014, 12:33
|
Местный
  
Группа: Участник
Сообщений: 491
Регистрация: 18-05-11
Пользователь №: 65 102

|
Цитата(den_po @ Jul 31 2014, 16:18)  Вот этого не понял вот так CODE USBD_StatusTypeDef USBD_LL_DataOutStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata) { USBD_EndpointTypeDef *pep; if(epnum == 0) { pep = &pdev->ep_out[0]; if ( pdev->ep0_state == USBD_EP0_DATA_OUT) { if(pep->rem_length > pep->maxpacket) { pep->rem_length -= pep->maxpacket; USBD_CtlContinueRx (pdev, pdata, MIN(pep->rem_length ,pep->maxpacket)); } else { if((pdev->pClass->EP0_RxReady != NULL)&& (pdev->dev_state == USBD_STATE_CONFIGURED)) { pdev->pClass->EP0_RxReady(pdev); }
USBD_CtlSendStatus(pdev); } } } else if((pdev->pClass->DataOut != NULL)&& (pdev->dev_state == USBD_STATE_CONFIGURED)) { pdev->pClass->DataOut(pdev, epnum); //my code if (UserRxBufferHS[1] == 3) { HAL_GPIO_WritePin(GPIOG, GPIO_PIN_14, GPIO_PIN_SET); UserRxBufferHS[1] = 0; USBD_CDC_ReceivePacket(hUsbDevice_1); } //end my code } return USBD_OK; } Цитата Так там тоже через таблички всё идёт. у меня - нет Цитата Предложение. Проверьте свежесгенерированный кубом код, измените только эти две функции: CDC_Transmit_FS - не знаю, по моему она у меня тоже нигде не вызывается. в принципе то она и не нужна в CDC_Receive_FS пробовал вставлять обработку данных, но чуда не произошло. если она нигде не вызывается, что поделаешь
Сообщение отредактировал IgorKossak - Jul 31 2014, 12:34
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
|
|
|
|
|
Jul 31 2014, 13:53
|
Частый гость
 
Группа: Участник
Сообщений: 139
Регистрация: 9-11-12
Из: Санкт-Петербург
Пользователь №: 74 315

|
Цитата(Atlantis- @ Jul 31 2014, 16:33)  вот так Почему так? Цитата(Atlantis- @ Jul 31 2014, 16:33)  у меня - нет Неправда. В процитированном вами коде строчка pdev->pClass->DataOut(pdev, epnum); - это вызов функции из таблички и есть. Вызывает USBD_CDC_DataOut. В USBD_CDC_DataOut строчка ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Receive(hcdc->RxBuffer, &hcdc->RxLength); вызывает CDC_Receive_FS. Цитата(Atlantis- @ Jul 31 2014, 16:33)  CDC_Transmit_FS - не знаю, по моему она у меня тоже нигде не вызывается. в принципе то она и не нужна в CDC_Receive_FS пробовал вставлять обработку данных, но чуда не произошло. если она нигде не вызывается, что поделаешь Конкретно предложенный мной вариант не работает? Очень неприятный баг. Когда отправляю в МК данные из программы, написанной на c#, если за раз отправлено больше 6 байт, то на МК они приходят нормально, но в ответ от МК начинаю получать мусор. То же самое, если с МК передаю больше 8 байт, на комп приходит мусор.
Сообщение отредактировал den_po - Jul 31 2014, 19:13
|
|
|
|
|
Aug 1 2014, 05:55
|
Местный
  
Группа: Участник
Сообщений: 491
Регистрация: 18-05-11
Пользователь №: 65 102

|
Цитата(den_po @ Jul 31 2014, 16:18)  Хе, сейчас вот наткнулся на баг в F0 Код USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev) { ... hpcd_USB_FS.Init.dev_endpoints = 8; Код PCD_EPTypeDef IN_ep[5]; /*!< IN endpoint parameters */ PCD_EPTypeDef OUT_ep[5]; /*!< OUT endpoint parameters */ Из-за этого херится чужая память. у меня так Код hpcd_USB_OTG_HS.Init.dev_endpoints = 11; Код PCD_EPTypeDef IN_ep[15]; /*!< IN endpoint parameters */ PCD_EPTypeDef OUT_ep[15]; /*!< OUT endpoint parameters */ Цитата Конкретно предложенный мной вариант не работает? сейчас перетащил свою обработку в CDC_Receive_HS, хм все работает
|
|
|
|
|
Aug 1 2014, 11:08
|
Местный
  
Группа: Участник
Сообщений: 491
Регистрация: 18-05-11
Пользователь №: 65 102

|
Цитата Проверьте свежесгенерированный кубом код, измените только эти две функции: Цитата В процитированном вами коде строчка pdev->pClass->DataOut(pdev, epnum); - это вызов функции из таблички и есть. Вызывает USBD_CDC_DataOut. В USBD_CDC_DataOut строчка ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Receive(hcdc->RxBuffer, &hcdc->RxLength); вызывает CDC_Receive_FS. это я понял, а вот CDC_Transmit_FS точно вроде не вызывается нигде, HAL_PCD_DataInStageCallback -> USBD_LL_DataInStage -> (pdev->pClass->DataIn(pdev, epnum)) -> USBD_CDC_DataIn и все Код static uint8_t USBD_CDC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum) { USBD_CDC_HandleTypeDef *hcdc = pdev->pClassData; if(pdev->pClassData != NULL) { hcdc->TxState = 0;
return USBD_OK; } else { return USBD_FAIL; } }
Сообщение отредактировал Atlantis- - Aug 1 2014, 11:09
|
|
|
|
|
Aug 1 2014, 12:02
|
Местный
  
Группа: Участник
Сообщений: 491
Регистрация: 18-05-11
Пользователь №: 65 102

|
Цитата(den_po @ Aug 1 2014, 15:29)  CDC_Transmit_FS нужно вызывать самостоятельно, когда нужно передать что-то компьютеру. А USBD_CDC_DataIn просто делает отметку, мол данные переданы. в библиотеке STM32F103 был колбэк, который вызывался каждые 1 мс, я в нем проверял есть ли данные и отправлял если они были. а свой счетчик отправлял каждые 1 мс для чего вот этот вызов? Код memcpy(UserTxBufferFS,Buf,Len); у меня если его использовать, тоже ерунда приходит
|
|
|
|
|
Aug 2 2014, 13:01
|
Частый гость
 
Группа: Участник
Сообщений: 139
Регистрация: 9-11-12
Из: Санкт-Петербург
Пользователь №: 74 315

|
Думаю, ерунда может приходить, если отправляются данные раньше, чем успевают передаться прошлые. Можно решить это например так: Код uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) { uint8_t result = USBD_OK; /* USER CODE BEGIN 8 */ USBD_CDC_HandleTypeDef *hcdc = hUsbDevice_0->pClassData; if(!hcdc) return USBD_FAIL; if(hcdc->TxState) return USBD_BUSY; memcpy(UserTxBufferFS,Buf,Len); USBD_CDC_SetTxBuffer(hUsbDevice_0, UserTxBufferFS, Len); result = USBD_CDC_TransmitPacket(hUsbDevice_0); /* USER CODE END 8 */ return result; } Ну и в обязательном порядке проверять результат выполнения функции: если она возвращает USBD_BUSY, нужно передать данные повторно. У меня же на F0 мусор так и шёл, пока я не ограничил передачу 1 байтом за раз. Медленно получается. Буду ещё на F2 пробовать.
|
|
|
|
|
Aug 3 2014, 00:16
|
Частый гость
 
Группа: Участник
Сообщений: 139
Регистрация: 9-11-12
Из: Санкт-Петербург
Пользователь №: 74 315

|
Баг с мусором в F0 почти убрал. В функции usbd_conf.c/USBD_LL_Init заменил Код HAL_PCDEx_PMAConfig(pdev->pData , 0x00 , PCD_SNG_BUF, 0x18); HAL_PCDEx_PMAConfig(pdev->pData , 0x80 , PCD_SNG_BUF, 0x58); на Код //0x10 == 2*CDC_CMD_PACKET_SIZE? HAL_PCDEx_PMAConfig(pdev->pData , 0x00 , PCD_SNG_BUF, 0x10+0*USB_FS_MAX_PACKET_SIZE); HAL_PCDEx_PMAConfig(pdev->pData , 0x80 , PCD_SNG_BUF, 0x10+1*USB_FS_MAX_PACKET_SIZE); HAL_PCDEx_PMAConfig(pdev->pData , 0x01 , PCD_SNG_BUF, 0x10+2*USB_FS_MAX_PACKET_SIZE); HAL_PCDEx_PMAConfig(pdev->pData , 0x81 , PCD_SNG_BUF, 0x10+3*USB_FS_MAX_PACKET_SIZE); Почти - потому что в среднем через 20-30 пакетов от МК к компу приходит пакет, который со второго байта хранит содержимое буфера приёма МК. Тестовая программа передаёт кучу буковок, МК меняет их регистр на противоположный и передаёт обратно. Результат (вывод данных, пришедших с МК) получается примерно такой: Код fghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklm ghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmn hijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmno ijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnop jKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQ Ошибка в пакете №35 должно быть: jklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopq Но в целом прогресс заметный. Можно передавать данные кусками до 63 байт длиной (CDC_DATA_FS_MAX_PACKET_SIZE == 64). ( Предыдущий баг - должно быть 15, а не 5)
Сообщение отредактировал den_po - Aug 3 2014, 00:18
|
|
|
|
|
Oct 15 2014, 16:29
|
Группа: Новичок
Сообщений: 2
Регистрация: 15-10-14
Пользователь №: 83 154

|
Цитата ( Предыдущий баг - должно быть 15, а не 5) Ну, по моему не 15 там должно быть, а просто перепутано 5 и 8 местами. Т.е. МК поддерживает 8 endpoints, а для CDC используется 5. control in out bulk data in out command in Я тут по ходу пиесы прикручиваю плюсовые классы-адаптеры кубовых драйверов для freertos, ну и приходится разбираться с этими внутренностями.
|
|
|
|
|
Oct 17 2014, 20:26
|
Частый гость
 
Группа: Участник
Сообщений: 139
Регистрация: 9-11-12
Из: Санкт-Петербург
Пользователь №: 74 315

|
Цитата(Vsevolod Gromov @ Oct 15 2014, 20:29)  Ну, по моему не 15 там должно быть, а просто перепутано 5 и 8 местами. Т.е. МК поддерживает 8 endpoints, а для CDC используется 5. control in out bulk data in out command in
Я тут по ходу пиесы прикручиваю плюсовые классы-адаптеры кубовых драйверов для freertos, ну и приходится разбираться с этими внутренностями. Там должно быть не меньше, чем hpcd_USB_FS.Init.dev_endpoints. В коде от других серий микроконтроллеров везде 15. И тут по форматированию текста понятно, что было 15, но кто-то случайно удалил символ.
|
|
|
|
|
Oct 20 2014, 08:12
|
Местный
  
Группа: Участник
Сообщений: 491
Регистрация: 18-05-11
Пользователь №: 65 102

|
Цитата(den_po @ Jul 31 2014, 00:37)  Если кому ещё интересно, то вот: Внутри CDC_Transmit_FS нужно самостоятельно выполнить нужные действия. Например, скопировать или дописать содержимое Buf в UserTxBufferFS. Внутри CDC_Receive_FS нужно обработать пришедшие по USB данные. Чтобы следующий пакет успешно принялся, нужно после обработки данных (в главном цикле либо тут же в CDC_Receive_FS) вызвать USBD_CDC_ReceivePacket(hUsbDevice_0) я прописал в дескрипторах еще один Endpoint (0x83), инициализировал его в USBD_CDC_Init и загружаю 0x83 в USBD_LL_Transmit - ничего не передает! USBTrace показывает, что EP у меня 2 (0x81 и 0x83), но 0x83 не передает. что-то еще надо для второго EP прописать?
|
|
|
|
|
Oct 20 2014, 10:23
|
Группа: Новичок
Сообщений: 2
Регистрация: 15-10-14
Пользователь №: 83 154

|
Цитата(den_po @ Oct 18 2014, 00:26)  Там должно быть не меньше, чем hpcd_USB_FS.Init.dev_endpoints. Точнее, в hpcd_USB_FS.Init.dev_endpoints д.б. не больше, чем xx в Код PCD_EPTypeDef IN_ep[xx]; /*!< IN endpoint parameters */ PCD_EPTypeDef OUT_ep[xx]; /*!< OUT endpoint parameters */ Если смотреть код инициализации ендпоинтов, то видим, что там используется два цикла - по одному для EP_IN и EP_OUT. Индекс пробегает от 0 до hpcd_USB_FS.Init.dev_endpoints Например, у меня семейство МК stm32f37x. Оно поддерживает до 5 endpoints (т.о., xx=5) Для устройства CDC используем 3 точки - *контрольная (д. б. всегда, адреса 0x00 и 0x80) *блоковая передача данных (адреса 0х01 и 0х81 ) *управление линией (входная, адрес 0х82) В коде инициализации ставим: Init.dev_endpoints = 3; Кроме того, останется еще правильно настроить пакетный буфер, у меня используется низкоприоритетная конфигурация, с простыми буферами: Код // Offet from the beginning of PM memory, to actual packet buffers // The math is as follows: num of endpoints used * 2 (reserved for in and out pipes) * 2 (2 descriptors per pipe) * 2 (2 byte per descriptor) size_t pmaOffs = m_h.Init.dev_endpoints * 8;
HAL_PCDEx_PMAConfig(&m_h, 0x00, PCD_SNG_BUF, pmaOffs ); // EP0 (control in) - always must be there, for USB to function properly pmaOffs += USB_FS_MAX_PACKET_SIZE; HAL_PCDEx_PMAConfig(&m_h, 0x80, PCD_SNG_BUF, pmaOffs ); // EP0 (control out) - always must be there, for USB to function properly pmaOffs += USB_FS_MAX_PACKET_SIZE;
HAL_PCDEx_PMAConfig(&m_h, CDC_IN_EP, PCD_SNG_BUF, pmaOffs ); // CDC commuinication IN pmaOffs += CDC_DATA_FS_MAX_PACKET_SIZE; HAL_PCDEx_PMAConfig(&m_h, CDC_OUT_EP, PCD_SNG_BUF, pmaOffs ); // CDC commuinication OUT pmaOffs += CDC_DATA_FS_MAX_PACKET_SIZE; HAL_PCDEx_PMAConfig(&m_h, CDC_CMD_EP, PCD_SNG_BUF, pmaOffs ); // CDC command EP Прогнал CDC драйвер в FreeRTOS под стрессом, в отдельном треде запустил прием+передачу принятого, через терминал, выставил бодрейт 921600, и заслал файло на 20 мегов. Все ОК, скорость ориентировочно получается 700 килобод.
|
|
|
|
|
Nov 14 2015, 16:43
|
Знающий
   
Группа: Свой
Сообщений: 888
Регистрация: 25-09-08
Из: Питер
Пользователь №: 40 458

|
Вопрос на ту же тему. Поднял Midware USB CDC (HAL) пришедшее с Stm32 CubeMX v1.0 (version 4.6.0) (Device), процессор Stm32f207. На всякий случай некоторые подробности. 1. При получении пакета CDC вызывается пользовательская (callback) функция CDC_Receive_FS (uint8_t* Buf, uint32_t *Len). Вызов идет на уровне прерываний. В ней я считываю данные и, обязательно, вызываю USBD_CDC_ReceivePacket(hUsbDevice_0), иначе следующий пакет не будет принят. Изначально, для контроля по Эхо, в ней же вызывалась функция посылки ответа CDC_Transmit_FS(...). Затем стал устанавливать флаг и вызывать ее в MainLoop. 2. Для отправки ответных данных служит пользовательская функция CDC_Transmit_FS(...) вызываемая из любого места, в частности из MainLoop. В ней сначала заполняется буфер, затем вызывается функция USBD_CDC_SetTxBuffer(hUsbDevice_0, UserTxBufferFS, Len), затем собственно отправка пакета USBD_CDC_TransmitPacket(hUsbDevice_0) (внутренняя функция HAL).
Сначала CDC_Transmit_FS вызывалась прямо в CDC_Receive_FS (т.е. на уровне прерываний) для контроля эхо и все работало идеально. Затем, для анализа и формирования ответного пакета, перенес CDC_Transmit_FS в MainLoop. И вот тут начались проблемы.
Т.е. все (эхо) работает нормально до какого-то момента, а, затем, затыкается навсегда из-за того, что передача пакета зависает навсегда - при попытке вызова USBD_CDC_TransmitPacket она возвращает USBD_BUSY.
Всякие эксперименты дали следующее - все начинает работать прекрасно, если перед вызовом USBD_CDC_TransmitPacket запретить прерывания, а, потом, снова разрешить. Но это как-то слишком криво получается.
Т.е. похоже, что если при выполнении USBD_CDC_TransmitPacket происходит прерывание, то HALовская система обалдевает.
Никто с подобным не сталкивался?
P.S. Да, сейчас прерывания "плоские", т.е. все на одном уровне приоритета. Может тут можно поиграться?
|
|
|
|
3 чел. читают эту тему (гостей: 3, скрытых пользователей: 0)
Пользователей: 0
|
|
|