cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 HID with HALL

megahercas6
Senior
Posted on December 27, 2015 at 21:37

Hello, i am creating car headunit from tablet, and USB OTG functionality allows to control tablet with STM

I would like to get few commands, like SLEEP, WAKE, volume up/down, pause, play, next song, preview song.

/**
******************************************************************************
* @file USB_Device/HID_Standalone/Src/main.c
* @author MCD Application Team
* @version V1.0.2
* @date 18-November-2015 
* @brief USB device HID demo main file
******************************************************************************
* @attention
*
* <
h2
><
center
>© COPYRIGHT(c) 2015 STMicroelectronics</
center
></
h2
>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the ''License'');
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software 
* distributed under the License is distributed on an ''AS IS'' BASIS, 
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include ''main.h''
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define CURSOR_STEP 1
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
USBD_HandleTypeDef USBD_Device;
uint8_t HID_Buffer[4];
/* Private function prototypes -----------------------------------------------*/
static void SystemClock_Config(void);
static void Error_Handler(void);
static void CPU_CACHE_Enable(void);
static void GetPointerData(uint8_t *pbuf);
/* Private functions ---------------------------------------------------------*/
/**
* @brief Main program
* @param None
* @retval None
*/
int main(void)
{
/* Enable the CPU Cache */
CPU_CACHE_Enable();
/* STM32F7xx HAL library initialization:
- Configure the Flash ART accelerator on ITCM interface
- Configure the Systick to generate an interrupt each 1 msec
- Set NVIC Group Priority to 4
- Low Level Initialization
*/
HAL_Init();
/* Configure the System clock to have a frequency of 216 MHz */
SystemClock_Config();
/* Configure LED1 */
BSP_LED_Init(LED1);
/* Configure Key button for remote wakeup */
BSP_PB_Init(BUTTON_TAMPER, BUTTON_MODE_EXTI);
/* Init Device Library */
USBD_Init(&USBD_Device, &HID_Desc, 0);
/* Add Supported Class */
USBD_RegisterClass(&USBD_Device, USBD_HID_CLASS);
/* Start Device Process */
USBD_Start(&USBD_Device);
/* Run Application (Interrupt mode) */
while (1)
{
HAL_Delay(5); 
BSP_LED_Toggle(LED1);
HAL_Delay(5); 
GetPointerData(HID_Buffer);
USBD_HID_SendReport(&USBD_Device, HID_Buffer, 4);
}
}
/**
* @brief Gets Pointer Data.
* @param pbuf: Pointer to report
* @retval None
*/
static void GetPointerData(uint8_t *pbuf)
{
static int8_t cnt = 0;
int8_t x = 0, y = 0 ;
if(cnt++ > 0)
{
x = CURSOR_STEP;
}
else
{
x = -CURSOR_STEP;
}
pbuf[0] = 0;
pbuf[1] = x;
pbuf[2] = y;
pbuf[3] = 0;
}
/**
* @brief This function provides accurate delay (in milliseconds) based 
* on SysTick counter flag.
* @note This function is declared as __weak to be overwritten in case of other
* implementations in user file.
* @param Delay: specifies the delay time length, in milliseconds.
* @retval None
*/
void HAL_Delay(__IO uint32_t Delay)
{
while(Delay) 
{
if (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) 
{
Delay--;
}
}
}
/**
* @brief System Clock Configuration
* The system Clock is configured as follow :
* System Clock source = PLL (HSE)
* SYSCLK(Hz) = 216000000
* HCLK(Hz) = 216000000
* AHB Prescaler = 1
* APB1 Prescaler = 4
* APB2 Prescaler = 2
* HSE Frequency(Hz) = 25000000
* PLL_M = 25
* PLL_N = 432
* PLL_P = 2
* VDD(V) = 3.3
* Main regulator output voltage = Scale1 mode
* Flash Latency(WS) = 7
* @param None
* @retval None
*/
void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 432; 
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 9;
if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/* Activate the OverDrive to reach the 216 Mhz Frequency */
if(HAL_PWREx_EnableOverDrive() != HAL_OK)
{
Error_Handler();
}
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 
clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7) != HAL_OK)
{
Error_Handler();
}
}

static void CPU_CACHE_Enable(void)
{
/* Enable I-Cache */
SCB_EnableICache();
/* Enable D-Cache */
SCB_EnableDCache();
}

For me is a bit hard to figureout, how to let say, send ''play'' command, could any one help me ? #usb-hid
4 REPLIES 4
tsuneo
Senior
Posted on December 28, 2015 at 03:51

> I would like to get few commands, like SLEEP, WAKE, volume up/down, pause, play, next song, preview song.

Listed features belong to two HID categories • System control - SLEEP, WAKE • Consumer control - volume up/down, pause, play, next song, preview song. There are two ways to implement them all into single HID device, a) Multi-TLCs (Top-Level Collections) b) Composite HID device (HID + HID) I'll show you simpler one, multi-TLCs, here. Assumed you are working on STM32Cube FW_F7 v1.3.1 library. [ Report descriptor ] A typical report descriptor for this purpose is shown in this example on MSDN HIDUSBFX2

https://msdn.microsoft.com/ja-jp/library/ff543309%28v=vs.85%aspx

Here is customized one for your listed features. Copy usbd_hid.c and usbd_hid.h to your project folder, and replace report descriptor definition.

STM32Cube_FW_F7_V1.3.0\Middlewares\ST\STM32_USB_Device_Library\Class\HID\Src\usbd_hid.c

// Line 217
__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
{
// system control collection
0x85, 0x01, // REPORT_ID
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x80, // USAGE (System Control)
0xa1, 0x01, // COLLECTION (Application)
0x19, 0x82, // USAGE_MINIMUM (System Sleep)
0x29, 0x83, // USAGE_MAXIMUM (System Wake Up)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x06, // INPUT (Data,Var,Rel)
// -------------------- padding bits
0x95, 0x06, // REPORT_COUNT (6)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
0xc0, // END_COLLECTION
// Consumer control collection
0x85, 0x02, // REPORT_ID
0x05, 0x0c, // USAGE_PAGE (Consumer Devices)
0x09, 0x01, // USAGE (Consumer Control)
0xa1, 0x01, // COLLECTION (Application)
// -------------------- common global items
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1) 

// -------------------- misc bits
0x95, 0x05, // REPORT_COUNT (5)
0x09, 0xb5, // USAGE (Scan Next Track)
0x09, 0xb6, // USAGE (Scan Previous Track)
0x09, 0xb7, // USAGE (Stop)
0x09, 0xcd, // USAGE (Play/Pause)
0x09, 0xe2, // USAGE (Mute)
0x81, 0x06, // INPUT (Data,Var,Rel) - relative inputs
// -------------------- volume up/down bits
0x95, 0x02, // REPORT_COUNT (2)
0x09, 0xe9, // USAGE (Volume Up)
0x09, 0xea, // USAGE (Volume Down)
0x81, 0x02, // INPUT (Data,Var,Abs) - absolute inputs
// -------------------- padding bit
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x01, // INPUT (Cnst,Ary,Abs)
0xc0 // END_COLLECTION
};

STM32Cube_FW_F7_V1.3.0\Middlewares\ST\STM32_USB_Device_Library\Class\HID\Inc\usbd_hid.h
#define HID_EPIN_SIZE 0x02
#define HID_MOUSE_REPORT_DESC_SIZE 68

[ Send Input report ] Above report descriptor declares these two input reports

Report format of system controls
first byte (report ID) - 0x01
second byte (bitmap)
bit
0 : Sleep
1 : Wake up
2-7 : 0 (padding)
Report format for consumer controls
first byte (report ID) - 0x02
second byte (bitmap)
bit
0 : Next
1 : Previous
2 : Stop
3 : Play/Pause
4 : Mute
5 : Volume Up
6 : Volume Down
7 : 0 (padding)

Send one of these reports using USBD_HID_SendReport(), when corresponding event occurs (ex. key push etc) [ VID/PID ] Change VID/PID, so that your new HID device is identified by Windows as different one.

usbd_desc.c
#define USBD_VID 0x0483
#define USBD_PID 0x5710 // <-- any one, like 0xFFFF

You may assign any VID/PID to your device, unless it escapes from your desktop. When you would release your custom device into public, get unique valid VID/PID for your device. Tsuneo
megahercas6
Senior
Posted on December 28, 2015 at 10:39

Sir, that works ! Don't know correct saying, but you are superstar 🙂

This worked first time, and now gives me soooo much flexibility and cool feutures with my project !

Only strange problem, volume up/down just makes slide volume to maximum/minimum, not like single tap, like with volume up button. Strange. other than that, works soooooo great 🙂

Me happy

( This project is to convert Lenovo Phab Plus into Subaru BRZ headunit, and HID controls lets STM32 to figure out what car is doing, and send correct HID messages, to weak up, sleep, and so on )

Only think i don't know is it possible to launch correct application by HID message, like when i shift into reverse, launch USB camera application, but this topic if for other forum)

megahercas6
Senior
Posted on December 28, 2015 at 15:01

Since i am big fan of SPL, rewriting code for STM32F4

Was able to get HID example working, but i can't this line

#define HID_EPIN_SIZE 0x02

 Assuming every thing else is the same 

tsuneo
Senior
Posted on December 28, 2015 at 15:05

> Only strange problem, volume up/down just makes slide volume to maximum/minimum, not like single tap, like with volume up button.

Auu sorry, I didn't explain the way how the HID controls are supposed to send the ''trigger'' reports.

Volume up/down controls are RTC (Re-Trigger Control)type, which accepts repeated events. When your device sends ''1'' (push) to these bits first, but if it doesn't send following ''0'' (release), host driver regards this behavior as ''repeated'' event - up/down button is continuously pushed. To up/down volume stepwise, your device should send ''1'' and following ''0'' to these bits.

The other controls are OSC (One-Shot Control) type, in which transition from ''0'' to ''1''  triggers event just once.

After first USBD_HID_SendReport() call, poll ''state'' variable to know the completion of the transfer,

(USBD_HID_HandleTypeDef*)(USBD_Device.pClassData)->state == HID_IDLE

While ''state'' variable is kept in HID_BUSY, the transfer is pending. When the transfer finishes, ''state'' returns to HID_IDLE. And then, it is able to send another report to host by calling USBD_HID_SendReport(), again.

Tsuneo