Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HID Keyboard + Audio Microphone #19

Open
pitman75 opened this issue Jul 19, 2022 · 7 comments
Open

HID Keyboard + Audio Microphone #19

pitman75 opened this issue Jul 19, 2022 · 7 comments

Comments

@pitman75
Copy link

Need do working USB composite device USB keyboard and USB microphone. I did it for CubeMX standalone devices, it works well.

The MCU is STM32L476
STM32CubeMX 1.9.0

Software Pack Componet Selector marked:

  • Core
  • HID_KEYBOARD
  • UAC_MIC
  • COMPOSITE

Software Packs Parameter Settings marked:

  • USBD_USE_HID_KEYBOARD
  • USBD_USE_UAC_MIC

Also configured FreeRTOS, MX_USB_DEVICE_Init() called at once when default task started.

Build process break on:

#if(!STM32F1_DEVICE) else if (hpcd->Init.speed == PCD_SPEED_HIGH) { speed = USBD_SPEED_HIGH; } #endif

PCD_SPEED_HIGH undeclared.

After remove this #if....#endif build process is success. PC Windows/Linux found composite USB device keyboard + microphone. But when I send key like keyboard via function USBD_HID_Keyboard_SendReport keys not typed on console. I used wireshark in Linux and see that MCU send ISO IN packet like in worked standalone solution. But no any key on console.

Also I see error in USB description by Thesicon USB Descriptor Dumper

`AC Interface Header Descriptor:

0x09 bLength
0x24 bDescriptorType
0x01 bDescriptorSubtype
0x0100 bcdADC
0x0026 wTotalLength (38 bytes)

  • ERROR: Invalid wTotalLength 0x0026, should be 0x0027.
    0x01 bInCollection
    0x02 baInterfaceNr(1)`

usb_composite_not_wrk.txt

What is wrong?

@pitman75
Copy link
Author

Dump USB data transfer for STM32 HID Keyboard standalone and for composite HID Keyboard + UAC MIC

2022-07-20-213846_1920x1080_scrot

Looks like for composite device host doesn't read some config data and device for host is in wrong state. Data goes but rejected.

RAW dump data
usb_composite-1-2022-07-20.zip
usb_keyboard-2-2022-07-20.zip

@pitman75
Copy link
Author

After some changes my composite device works well. Thanks a lot of your huge work!

@alambe94
Copy link
Owner

alambe94 commented Sep 5, 2022

That is nice!! Do you mind sharing your changes? If so, please send a pull request.

@pitman75
Copy link
Author

pitman75 commented Sep 6, 2022

I can explain my changes and test it on STM32L475. Now I have hardware USB protocol analyzer and can debug USB communications on low-level.

General:

  • The STM32L475 has FS USB only. In headers of the project don't exist define for PCD_SPEED_HIGH and when I tried build sources I had error on line

if(!STM32F1_DEVICE) else if (hpcd->Init.speed == PCD_SPEED_HIGH) { speed = USBD_SPEED_HIGH; }

  • USB descriptor in this case I think should have USB version as 1.1 not 2.0

I'll resume later. Your plugin is very helpfull I can help you to do it better.

@pitman75
Copy link
Author

pitman75 commented Oct 23, 2022

Also for HID keyboard I replaced report descriptor

In the file usbd_hid_keyboard.h change size of report descriptor

#define HID_KEYBOARD_REPORT_DESC_SIZE 63U

In the file usbd_hid_keyboard.c replace report descriptor

/* HID keyboard report descriptor */
__ALIGN_BEGIN static uint8_t HID_KEYBOARD_ReportDesc[HID_KEYBOARD_REPORT_DESC_SIZE] __ALIGN_END =
{
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x06, // USAGE (Keyboard)
0xa1, 0x01, // COLLECTION (Application)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x08, // REPORT_COUNT (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
0x95, 0x05, // REPORT_COUNT (5)
0x75, 0x01, // REPORT_SIZE (1)
0x05, 0x08, // USAGE_PAGE (LEDs)
0x19, 0x01, // USAGE_MINIMUM (Num Lock)
0x29, 0x05, // USAGE_MAXIMUM (Kana)
0x91, 0x02, // OUTPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x03, // REPORT_SIZE (3)
0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
0x95, 0x06, // REPORT_COUNT (6)
0x75, 0x08, // REPORT_SIZE (8)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x65, // LOGICAL_MAXIMUM (101)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
0x81, 0x00, // INPUT (Data,Ary,Abs)
0xc0 // END_COLLECTION
};

@pitman75
Copy link
Author

After this changes for keyboard it works well.

@pitman75
Copy link
Author

Generic changes for usb microphone:

  1. In the file usbd_audio_mic.c fix incorrect size of section:

     /* USB Microphone Audio Feature Unit Descriptor */
     0x07 + AUDIO_MIC_CHANNELS + 1,   /* bLength */
    
  2. In the file usbd_audio_mic.h change value for MIN, MAX, RES of audio control

#define AUDIO_MIC_VOL_MIN 0x0000
#define AUDIO_MIC_VOL_RES 0x0001
#define AUDIO_MIC_VOL_MAX 0x0064

After this changes Windows 10 read its without any problem.

Dirty solution for send audio data

  1. Disable any code in the function USBD_AUDIO_MIC_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum)
  2. Add callback to start/stop fill data to

case USB_REQ_SET_INTERFACE:
if (pdev->dev_state == USBD_STATE_CONFIGURED)
{
if ((uint8_t)(req->wValue) <= USBD_MAX_NUM_INTERFACES)
{
haudio->alt_setting = (uint8_t)(req->wValue);
//printf("Set interface USB command: %lu for EP 0x%02X\r\n", haudio->alt_setting, AUDIO_MIC_EP);
if (haudio->alt_setting)
{
printf("%lu start\r\n", HAL_GetTick());
audio_play_start();
}
else
{
printf("%lu stop\r\n", HAL_GetTick());
audio_play_stop();
}

      USBD_LL_FlushEP(pdev, AUDIO_MIC_EP);
    }
    else
    {
    	printf("wVal wrong 0x%02X\r\n", req->wValue);
      /* Call the error management function (command will be NAKed */
      USBD_CtlError(pdev, req);
      ret = USBD_FAIL;
    }
  }
  else
  {
	  printf("USB_REQ_GET_INTERFACE wrong 0x%02X\r\n", pdev->dev_state);
    USBD_CtlError(pdev, req);
    ret = USBD_FAIL;
  }
  break;
  1. Add flush MIC IN to
    static uint8_t USBD_AUDIO_MIC_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum)
    {
    UNUSED(pdev);
    UNUSED(epnum);
    USBD_LL_FlushEP (pdev, AUDIO_MIC_EP);
    return (uint8_t)USBD_OK;
    }

  2. When capture audio started -> enable 1ms timer with interrupt to fill audio data to TX buffer.

Very important that when capture started to fill any data to output buffer. Without data after few rejected IN requests in Windows and 5000 IN requests in Linux -> the MIC IN pipe will be stopped without notification on application side. I added play silent white noise before and after played prerecorded audio all time while capture exist.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants