Перейти к содержанию
    

я прикрутил прием данных в USBD_LL_DataOutStage

Вот этого не понял

 

можете показать содержимое функции 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            */

Из-за этого херится чужая память.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот этого не понял

вот так

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
[codebox] для длинного кода, [code] - для короткого!!!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

вот так

Почему так?

 

у меня - нет

Неправда.

В процитированном вами коде строчка 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 - не знаю, по моему она у меня тоже нигде не вызывается. в принципе то она и не нужна

в CDC_Receive_FS пробовал вставлять обработку данных, но чуда не произошло. если она нигде не вызывается, что поделаешь

Конкретно предложенный мной вариант не работает?

 

 

Очень неприятный баг. Когда отправляю в МК данные из программы, написанной на c#, если за раз отправлено больше 6 байт, то на МК они приходят нормально, но в ответ от МК начинаю получать мусор. То же самое, если с МК передаю больше 8 байт, на комп приходит мусор.

Изменено пользователем den_po

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Хе, сейчас вот наткнулся на баг в 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:

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проверьте свежесгенерированный кубом код, измените только эти две функции:

В процитированном вами коде строчка 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-

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

CDC_Transmit_FS нужно вызывать самостоятельно, когда нужно передать что-то компьютеру.

А USBD_CDC_DataIn просто делает отметку, мол данные переданы.

 

А у меня всё равно данные портятся. Энное количество работает, а потом от МК приходит мусор =( Причём отправляются нормальные данные.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

CDC_Transmit_FS нужно вызывать самостоятельно, когда нужно передать что-то компьютеру.

А USBD_CDC_DataIn просто делает отметку, мол данные переданы.

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

 

для чего вот этот вызов?

memcpy(UserTxBufferFS,Buf,Len);

у меня если его использовать, тоже ерунда приходит

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Думаю, ерунда может приходить, если отправляются данные раньше, чем успевают передаться прошлые.

Можно решить это например так:

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 пробовать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Баг с мусором в 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Последняя проблема - моя ошибка. Просто драйвер на компе иногда отдаёт не пакет полностью, а один байт. А я, дурак, читал в тот же буфер и не глядел длину прочитанного.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

(Предыдущий баг - должно быть 15, а не 5)

 

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

control in out

bulk data in out

command in

 

Я тут по ходу пиесы прикручиваю плюсовые классы-адаптеры кубовых драйверов для freertos, ну и приходится разбираться с этими внутренностями.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну, по моему не 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, но кто-то случайно удалил символ.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если кому ещё интересно, то вот:

Внутри 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 прописать?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Там должно быть не меньше, чем 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 килобод.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вопрос на ту же тему. Поднял 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. Да, сейчас прерывания "плоские", т.е. все на одном уровне приоритета. Может тут можно поиграться?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...