Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32CubeMX и USB CDC
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
ViKo
Уже появилась в CubeMX поддержка STM32F3. Сделал проект для STM32F3Discovery. Подключаю к компьютеру - обнаруживается Virtual COM Port. Но как его использовать? В main программе на месте пользовательского кода - пустые места. Наверное, где-то описаны пара функций для работы - принять, послать. И буферы создать нужно. Не вижу ни в документации, ни в примерах. Поможите, люди добрые!
Integro
посмотрите в файле usbd_cdc_if.c,
CDC_Transmit_FS и callback CDC_Receive_FS
ViKo
Цитата(Integro @ Jul 15 2014, 14:38) *
посмотрите в файле usbd_cdc_if.c,
CDC_Transmit_FS и callback CDC_Receive_FS

Пробовал эти функции, но ... их не видит проект.
Кое-что получается с
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf_Ch, 4);
USBD_CDC_TransmitPacket(&hUsbDeviceFS);
Integro
Цитата(ViKo @ Jul 15 2014, 23:01) *
Пробовал эти функции, но ... их не видит проект.
Кое-что получается с
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf_Ch, 4);
USBD_CDC_TransmitPacket(&hUsbDeviceFS);

Что значит не видит проект?
Файл исключен из сборки?
Самый простой способ проверить работу, поставить брекпоинт в функцию CDC_Receive_FS, затем в терминале на PC что либо отправить
ViKo
Из мейн функции не видны. Можно инклюдами заголовок добавить. Но, если этого не сделано, значит их использовать не нужно.
Integro
Цитата(ViKo @ Jul 16 2014, 11:19) *
Из мейн функции не видны. Можно инклюдами заголовок добавить. Но, если этого не сделано, значит их использовать не нужно.

Если это не сделано значит это нужно сделать.) Не стоит доверять сырым либам от ST, мы в мае месяце не один баг у них нашли, благо обновления основную часть устранили.

Для работы с Виртуальным портом необходимо использовать функции описанные выше.
1. Проверить приходят ли данные в CDC_Receive_FS для этого просто ставим бряк, как я писал выше, если приходят в данной функции вызываем вашу реализация функции обработки принятых данных.
2. Сделать обертку для CDC_Transmit_FS в каком ни-будь вашем файле ("Platform.c" или "hal_DeviceName.c" не суть что там у вас) CDC_Write.

А вообще на данный момент не рекомендовал бы использовать Cube, подождите пару месяцев, а текущий проект доделайте на CMSIS.
ViKo
Кабы я умел программировать USB в STM32, стал бы я связываться с Кубами, Либами, Миддлеварами и пр.
Мой путь обратный - от вышеперечисленного к своему.
Те функции, что я использовал (см. выше), позволили передавать массив символов. Вокруг них и буду танцевать.
Integro
Цитата(ViKo @ Jul 16 2014, 19:18) *
Кабы я умел программировать USB в STM32, стал бы я связываться с Кубами, Либами, Миддлеварами и пр.
Мой путь обратный - от вышеперечисленного к своему.
Те функции, что я использовал (см. выше), позволили передавать массив символов. Вокруг них и буду танцевать.

Посмотрите на реализацию функции CDC_Transmit_FS а затем на ваш вариант, да! это одно и тоже.
Теперь, с точки зрения работоспособности кода... можно писать говнокод. Но можно сделать красивее, практичнее и тд...
ViKo
Вот функция из usbd_cdc_if.c
Код
/**
  * @brief  CDC_Transmit_FS
  *         Data send over USB IN endpoint are sent over CDC interface
  *         through this function.          
  *         @note
  *        
  *                
  * @param  Buf: Buffer of data to be send
  * @param  Len: Number of data to be send (in bytes)
  * @retval Result of the opeartion: USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY
  */
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
  uint8_t result = USBD_OK;
  /* USER CODE BEGIN 8 */
  USBD_CDC_SetTxBuffer(hUsbDevice_0, UserTxBufferFS, Len);  
  result = USBD_CDC_TransmitPacket(hUsbDevice_0);
  /* USER CODE END 8 */
  return result;
}

Вопрос - как?! Как используется параметр Buf?

А вот еще один шедевр оттуда же.
Код
/**
  * @brief  CDC_Receive_FS
  *         Data received over USB OUT endpoint are sent over CDC interface
  *         through this function.
  *          
  *         @note
  *         This function will block any OUT packet reception on USB endpoint
  *         untill exiting this function. If you exit this function before transfer
  *         is complete on CDC interface (ie. using DMA controller) it will result
  *         in receiving more data while previous ones are still not sent.
  *                
  * @param  Buf: Buffer of data to be received
  * @param  Len: Number of data received (in bytes)
  * @retval Result of the opeartion: USBD_OK if all operations are OK else USBD_FAIL
  */
static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len)
{
  /* USER CODE BEGIN 7 */
  return (USBD_OK);
  /* USER CODE END 7 */
}

Это означает, что мне нужно поработать там своей головой?
Integro
Цитата(ViKo @ Jul 20 2014, 13:14) *
...

Ха, ща разберемся, у меня не так) это последняя версия Cube? Говорю сырой этот куб еще....
ViKo
Цитата(Integro @ Jul 23 2014, 11:12) *
Ха, ща разберемся, у меня не так) это последняя версия Cube? Говорю сырой этот куб еще....

Крайняя (не последняя, надеюсь rolleyes.gif)
Я тут решил взяться за изучение всех функций по-порядку, закопался...

Пытался отладчик запустить, трассировку - ничего не видит. Пытался другой проект запустить - тоже самое. И логический анализатор ничего не показывает. А ведь показывал. Обновил Keil - не помогло. Обновил прошивку ST-Link на Discovery - вообще не программируется, не отлаживается. Вернул назад Keil, и ST-Link. По-прежнему, трассировка не работает.
Кто сбил мой ераплан прицел? Горячие дни.
Golikov A.
а галочки дебуг и трейс информация, 0 оптимизация (по умолчанию в кейле не 0, default - это -2 вроде) и прочая фигня стоят?
ViKo
Цитата(Golikov A. @ Jul 24 2014, 15:25) *
а галочки дебуг и трейс информация, 0 оптимизация (по умолчанию в кейле не 0, default - это -2 вроде) и прочая фигня стоят?

Стоят. Достану из-под стола осциллограф, посмотрю на выводах...
Tahoe
Цитата(ViKo @ Jul 24 2014, 16:19) *
Пытался отладчик запустить, трассировку - ничего не видит.

Ну да, колбэки - они такие, прямолинейный подход не поможет. wink.gif
ViKo
Цитата(Tahoe @ Jul 24 2014, 17:32) *
Ну да, колбэки - они такие, прямолинейный подход не поможет. wink.gif

Нет, я другой проектик запустил, там нет таких страхов. Но все равно ЛА не работает. В окне "Watch 1" вижу, что переменная меняется, а в окне Logic Analyzer - нет. Она по разным цепям попадает. Хотя на SWO вижу, что-то выдается.
P.S. не ползет время в ЛА.
P.P.S. Да, и перемычку SB10 на F3Discovery я давно запаял. И что-то видел раньше, не помню, то ли, что хочу сейчас, или другое...
Golikov A.
совсем недавно кто-то запускал тут ЛА и прочую фигню, ему там много советов давали)...
ViKo
Цитата(Golikov A. @ Jul 24 2014, 22:02) *
совсем недавно кто-то запускал тут ЛА и прочую фигню, ему там много советов давали)...

Я давал. rolleyes.gif
Терзают смутные сомненья, что перегрузил я микроконтроллер работой. Программа в ОЗУ работает, быстрее, чем из флэш-памяти. Может, перекрыл какой-нибудь отладочный путь... Попробую из флэш.
ViKo
Вдруг взяло и заработало. laughing.gif ЛА показывает. Ничего, вроде не делал, не считая того, что перепробовал все свои платы и проекты. rolleyes.gif
Теперь пойду в USB. В нем тоже что-то ЛА показывает, но как-то пинка все ждет.
ViKo
Опять не работает ЛА. Чувствую, дело в температуре, влажности, и частоте. Вечером проверю.

Еще одним чудом поделюсь, по теме. Не могу выключить компьютер, пока подключена плата F3Discivery с запущенным проектом CDC.
Golikov A.
драйвер CDC - вещь суровая, у меня есть RS485 - виртуальный ком порт через USB, ну то есть CDC. Помехи вешают его так, что ноутбук треба выключать жестким сбросом через удержание кнопки питания, ничего не помогает, даже снять задачу и прочее, выключить тоже нельзя, стоит с черным экраном и жужит хоть всю ночь.... А еще плюсом идут БИОСы с пробуждением по USB, в винде много накрутить можно...
ViKo
По поводу логического анализатора вырисовывается следующая картина. У меня Дискавери висит на USB проводе постоянно, и включается вместе с компьютером. Так вот, чтобы ЛА заработал, нужно переткнуть USB кабель в Дискавери (убрать питание на короткое время). После этого ЛА показывает сигналы. laughing.gif
den_po
Цитата(ViKo @ Jul 20 2014, 14:14) *
Вот функция из usbd_cdc_if.c
Код
/**
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
...

Вопрос - как?! Как используется параметр Buf?

А вот еще один шедевр оттуда же.
Код
static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len)
...

Это означает, что мне нужно поработать там своей головой?

Если кому ещё интересно, то вот:
Внутри CDC_Transmit_FS нужно самостоятельно выполнить нужные действия. Например, скопировать или дописать содержимое Buf в UserTxBufferFS.
Внутри CDC_Receive_FS нужно обработать пришедшие по USB данные. Чтобы следующий пакет успешно принялся, нужно после обработки данных (в главном цикле либо тут же в CDC_Receive_FS) вызвать USBD_CDC_ReceivePacket(hUsbDevice_0)
Atlantis-
Цитата(den_po @ Jul 31 2014, 00:37) *
Если кому ещё интересно, то вот:
Внутри CDC_Transmit_FS нужно самостоятельно выполнить нужные действия. Например, скопировать или дописать содержимое Buf в UserTxBufferFS.
Внутри CDC_Receive_FS нужно обработать пришедшие по USB данные. Чтобы следующий пакет успешно принялся, нужно после обработки данных (в главном цикле либо тут же в CDC_Receive_FS) вызвать USBD_CDC_ReceivePacket(hUsbDevice_0)

очень интересно!
с передачей более менее понятно, а вот с приемом данных не совсем. где у Вас вызывается CDC_Receive_FS? у меня в проекте, например, эта функция вызывается один раз - при инициализации, в функии MX_USB_DEVICE_Init.
den_po
Её не нужно самостоятельно вызывать, это колбэк, он вызывается при поступлении данных. А вот сообщать, что мы готовы принимать очередной пакет, нужно уже самому с помощью USBD_CDC_ReceivePacket.
ViKo
У меня внутри бесконечного цикла работает такой код. User - это кнопка. По нажатию кнопки принимается последовательность символов, и выдается обратно.
Код
    User_old = User;
    User = GPIOA->IDR & 0x0001;
    if (!User_old && User) {
      USBD_CDC_SetRxBuffer(&hUsbDeviceFS, Buf_Ch);
      USBD_CDC_ReceivePacket(&hUsbDeviceFS);
      USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf_Ch, 8);
      USBD_CDC_TransmitPacket(&hUsbDeviceFS);
      do {
        User_old = User;
    User = GPIOA->IDR & 0x0001;
      } while (!User_old && !User);
    }

Это - чисто экспериментальный проект, попытка разобраться с USB в STM32. Но как-то слишком накручено в этом Cube, уж не с целью ли запутать простое.
Atlantis-
Цитата(den_po @ Jul 31 2014, 11:33) *
Её не нужно самостоятельно вызывать, это колбэк, он вызывается при поступлении данных. А вот сообщать, что мы готовы принимать очередной пакет, нужно уже самому с помощью USBD_CDC_ReceivePacket.

так я и спрашиваю, где она у Вас вызывается? весь путь по которому CDC_Transmit_FS вызывается, он ведь должен вести в конце концов к OTG_HS_IRQHandler? там обрабатывается флаг прихода данных, вызывается куча функций и в конце концов CDC_Transmit_FS, так ведь должно быть? у меня CDC_Transmit_FS из OTG_FS_IRQHandler не вызывается.
den_po
Цитата(Atlantis- @ Jul 31 2014, 11:49) *
так я и спрашиваю, где она у Вас вызывается? весь путь по которому CDC_Transmit_FS вызывается, он ведь должен вести в конце концов к OTG_HS_IRQHandler? там обрабатывается флаг прихода данных, вызывается куча функций и в конце концов CDC_Transmit_FS, так ведь должно быть? у меня CDC_Transmit_FS из OTG_FS_IRQHandler не вызывается.

Давайте для начала определимся, CDC_Transmit_FS или CDC_Receive_FS.
CDC_Transmit_FS вызывается по желанию. Я пробовал и из главного цикла, и из CDC_Receive_FS.
CDC_Receive_FS в моём случае (stm32f072) вызывается по такой цепочке:
USB_IRQHandler -> HAL_PCD_IRQHandler -> PCD_EP_ISR_Handler -> HAL_PCD_DataOutStageCallback -> USBD_LL_DataOutStage -> USBD_CDC_DataOut -> CDC_Receive_FS.
Вызывается колбэк не напрямую, а через табличку указателей, которая регистрируется в функции MX_USB_DEVICE_Init (usb_device.c)
Atlantis-
Цитата(den_po @ Jul 31 2014, 12:08) *
Давайте для начала определимся, CDC_Transmit_FS или CDC_Receive_FS.
CDC_Transmit_FS вызывается по желанию. Я пробовал и из главного цикла, и из CDC_Receive_FS.
CDC_Receive_FS в моём случае (stm32f072) вызывается по такой цепочке:
USB_IRQHandler -> HAL_PCD_IRQHandler -> PCD_EP_ISR_Handler -> HAL_PCD_DataOutStageCallback -> USBD_LL_DataOutStage -> USBD_CDC_DataOut -> CDC_Receive_FS.
Вызывается колбэк не напрямую, а через табличку указателей, которая регистрируется в функции MX_USB_DEVICE_Init (usb_device.c)

извините перепутал, CDC_Receive_FS конечно. у меня проект для STM32F429ZI (точнее для платы Discovery с ним), так вот там CDC_Receive_FS вызывается только при инициализации, а в прерывании - нет. теперь, зная Вашу цепочку, я наверное смогу прописать вызов CDC_Receive_FS куда надо))

Цитата(den_po @ Jul 31 2014, 12:08) *
Вызывается колбэк не напрямую, а через табличку указателей, которая регистрируется в функции MX_USB_DEVICE_Init (usb_device.c)

что за табличка кстати?
den_po
Цитата(Atlantis- @ Jul 31 2014, 12:29) *
извините перепутал, CDC_Receive_FS конечно. у меня проект для STM32F429ZI (точнее для платы Discovery с ним), так вот там CDC_Receive_FS вызывается только при инициализации, а в прерывании - нет. теперь, зная Вашу цепочку, я наверное смогу прописать вызов CDC_Receive_FS куда надо))

А может, при инициализации срабатывает прерывание? Данные в МК чем посылаются?
Я писал уже, после вызова CDC_Receive_FS нужно вызывать USBD_CDC_ReceivePacket, иначе следующий пакет не примется. Точно дело не в этом?

Цитата(Atlantis- @ Jul 31 2014, 12:29) *
что за табличка кстати?

Код
USBD_CDC_ItfTypeDef USBD_Interface_fops_FS =
{
  CDC_Init_FS,
  CDC_DeInit_FS,
  CDC_Control_FS,  
  CDC_Receive_FS
};
Atlantis-
Цитата(den_po @ Jul 31 2014, 14:05) *
А может, при инициализации срабатывает прерывание? Данные в МК чем посылаются?

хм, может, ну и что. данные посылаю из фирменной тестовой программы

Цитата(den_po @ Jul 31 2014, 14:05) *
Я писал уже, после вызова CDC_Receive_FS нужно вызывать USBD_CDC_ReceivePacket, иначе следующий пакет не примется. Точно дело не в этом?

я прикрутил прием данных в USBD_LL_DataOutStage, после отправки второго пакета тестовая программа виснет, видимо нет подтверждения или еще чего. причем USBD_CDC_ReceivePacket меня не спас. ой, сейчас поробовал - уже не виснет=)))
можете показать содержимое функции USBD_LL_DataOutStage, а то у меня там никакой
USBD_CDC_DataOut нет, она фигурирует только в структуре
Код
/* CDC interface class callbacks structure */
USBD_ClassTypeDef  USBD_CDC =
{
  USBD_CDC_Init,
  USBD_CDC_DeInit,
  USBD_CDC_Setup,
  NULL,                 /* EP0_TxSent, */
  USBD_CDC_EP0_RxReady,
  USBD_CDC_DataIn,
  USBD_CDC_DataOut,
  NULL,
  NULL,
  NULL,    
  USBD_CDC_GetHSCfgDesc,  
  USBD_CDC_GetFSCfgDesc,    
  USBD_CDC_GetOtherSpeedCfgDesc,
  USBD_CDC_GetDeviceQualifierDescriptor,
};

причем USBD_CDC опять нигде не фигурирует, только в
Код
#define USBD_CDC_CLASS    &USBD_CDC
, а USBD_CDC_CLASS нигде больше нет

Цитата(den_po @ Jul 31 2014, 14:05) *
Код
USBD_CDC_ItfTypeDef USBD_Interface_fops_FS =
{
  CDC_Init_FS,
  CDC_DeInit_FS,
  CDC_Control_FS,  
  CDC_Receive_FS
};

такая табличка у меня есть
den_po
Цитата(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            */

Из-за этого херится чужая память.
Atlantis-
Цитата(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 пробовал вставлять обработку данных, но чуда не произошло. если она нигде не вызывается, что поделаешь
den_po
Цитата(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 байт, на комп приходит мусор.
Atlantis-
Цитата(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, хм все работает blink.gif
Atlantis-
Цитата
Проверьте свежесгенерированный кубом код, измените только эти две функции:

Цитата
В процитированном вами коде строчка 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;
  }
}
den_po
CDC_Transmit_FS нужно вызывать самостоятельно, когда нужно передать что-то компьютеру.
А USBD_CDC_DataIn просто делает отметку, мол данные переданы.

А у меня всё равно данные портятся. Энное количество работает, а потом от МК приходит мусор =( Причём отправляются нормальные данные.
Atlantis-
Цитата(den_po @ Aug 1 2014, 15:29) *
CDC_Transmit_FS нужно вызывать самостоятельно, когда нужно передать что-то компьютеру.
А USBD_CDC_DataIn просто делает отметку, мол данные переданы.

в библиотеке STM32F103 был колбэк, который вызывался каждые 1 мс, я в нем проверял есть ли данные и отправлял если они были. а свой счетчик отправлял каждые 1 мс

для чего вот этот вызов?
Код
memcpy(UserTxBufferFS,Buf,Len);

у меня если его использовать, тоже ерунда приходит
den_po
Думаю, ерунда может приходить, если отправляются данные раньше, чем успевают передаться прошлые.
Можно решить это например так:
Код
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 пробовать.
den_po
Баг с мусором в 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
Последняя проблема - моя ошибка. Просто драйвер на компе иногда отдаёт не пакет полностью, а один байт. А я, дурак, читал в тот же буфер и не глядел длину прочитанного.
Vsevolod Gromov
Цитата
(Предыдущий баг - должно быть 15, а не 5)


Ну, по моему не 15 там должно быть, а просто перепутано 5 и 8 местами. Т.е. МК поддерживает 8 endpoints, а для CDC используется 5.
control in out
bulk data in out
command in

Я тут по ходу пиесы прикручиваю плюсовые классы-адаптеры кубовых драйверов для freertos, ну и приходится разбираться с этими внутренностями.
den_po
Цитата(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, но кто-то случайно удалил символ.
Atlantis-
Цитата(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 прописать?
Vsevolod Gromov
Цитата(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 килобод.
rudy_b
Вопрос на ту же тему. Поднял 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. Да, сейчас прерывания "плоские", т.е. все на одном уровне приоритета. Может тут можно поиграться?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.