HID Multimedia Dial

Supplements old keyboards that lack media keys or to provides a more natural interface.

Similar projects worth following
This is a USB HID with a rotatory encoder. This is used to supplement old keyboard layouts or to provide a more natural alternative.

I am also trying to give a go at a software USB for the STM8S003. If all else fail, I'll fall back to EFM8UB1.

In this project, I tried to make use of recycled materials in the construction while trying for a more polished look.

This project was initially inspired by the Microsoft Surface Dial, but has evolved towards supplementing a dial for multimedia purposes. Sometime Youtube video or new video game default volume setting is set too high. In Windows, the access to the volume control on the menu bar can takes seconds. I have implement an automatic attenuation to deal with excessive volume in my Automatic audio source switching, but it would still be nice to have a physical interface that is accessible at all time.

Control Mapping

The idea is to map the media keys functions into the very few controls for a rotatory encoder in an intuitive manner. The LED provides visual clue to the operating mode of the device while doubling clicking is used to switch between them.

USB Communication

The dial acts as a USB HID, so there are operating system level device driver support in place. There are additional plug-in/key mapper for media players which are outside of the scope of this project.

The dial communicates with the PC using HID reports. The USB standard defines device Usage Tables that describes the formatting of the data packets for the device that the operating system use for parsing.


I am going to be using the low cost EFM8UB1 series microcontroller as it has native USB 1.1 hardware and comes with a free compiler/debugger suite and USB library.

GPIO Port Match interrupts are used to read the rotatory encoder. The switch is mapped to a different port for its own Port Match interrupt. Hardware timer will be used to determine double clicking/hold timing.


The hardware will be released under CC BY-4.0 and firmware under GPL 3.0.

"HID Usage Tables - USB org"
HID Descriptor Tool - create, edit and validate HID Report Descriptors
"Enhanced Keyboards and Windows"

  • USB protocol issue

    K.C. Lee04/08/2017 at 04:45 0 comments

    I captured some packets. This is the device descriptor sent from device to the host.

    Each of the data packets starts off alternating PID between DATA0 or DATA1, follows by 8 bytes of payload, CRC16 checksum and end of packet SE0 (Single Ended 0 - both D+/D- are at '0'). Packets are split into 8 bytes chunks of data which is max size for low speed USB. The host responded with ACK meaning the packet is healthy.

    The last packet is sent as a 8 byte packet which is incorrect. What it should have done is send a 2 bytes packet + CRC16 following USB specs

    The host expected more data, but the device has none. Eventually, the host gives up on getting the descriptor and unable to recognize the device.

    It turns out that it wasn't an issue with the last packet. It was sending additional descriptors.

    Some of the setup packets from the host are not handled correctly. Windows just don't know what to do with the device. The upper level code needs to be rewritten.

  • STM8 USB low level operations

    K.C. Lee04/06/2017 at 14:25 7 comments

    I have been trying to understand the low level assembly bit banging code. Due to the pipeline architecture, it gets a bit trick to count CPU cycles when the code includes branches.

    TIM1 is used for synchronization. The timer support advanced trigger synchronization and programmable digital filters. The first rising edge at the USB data line to start the timer. The same input passes a digital filter too look for stable signal level for input capture.

    USB signal looks like this: (for illustratuions only)

    The digital filter ignores the synchronization pulses and finds the first stable point. The delta is used to correct for the phase difference between the PC USB and the sampling clock on the STM8 by means of an address offset into a jump table for delays.

      ldw	x, #L_Delay_Begin	; start address of the L_Delay_Begin table
      addw	x, TIM1_CNTR		; + timer Offset (TIM1->CNTR)
      cpw	x, #L_Delay_End		; Boundary check  (zaschita!)
      jruge	L_Error
      jp	(x)			; Jump delay table
    	iret 			; Emergency exit

    Once synchronized, the receive code reads the GPIO input to capture the packet a bit at a time. The main logic is an unrolled loop, so it doesn't have any branches to affect the cycles count. (There are branches that look for end of packet condition, but the branches do not require accurate cycle count.)

    Unfortunately it is not as flexible as the AVR V-USB implementation. Here are some of the limitations I can see so far:
    • TIM1 is the only timer with these features.
    • The entire GPIO C is unavailable as the receive code does not attempt to extract the USB port bits.

    To be honest, there are bits and piece of receive code that are beyond me to understand why it would work. (Or does it?)

      cpl		($14,y)		; Synchronize signal
      srl		($01, SP)
      ld		a,(y)           ; Reads GPIO C inputs
      jreq	        L_End_Rx	; exit if input = 0 (end of packet)
      xor		a, ($01, SP)
      ld		($01, SP),a
    • cpl ($14,y) has no effects here as it is trying to complement a Read Only input port for GPIO G that isn't even available on this part. It affects flags N, Z and set C=1. The srl (Shift Right Logical) after it isn't affected by flags and it overwrites flags N, Z and C. i.e. The GPIO port cannot be written nor are the flags the cpl instruction changed get propagated.
    • ($01,SP) is a variable with single set bit pattern that starts out as 0x80 that is shifted to the right. The xor is just weird. What happen when the USB data is '0'. i.e. D+ = '0' and D- = '1'? GPIO C IDR would read 0x40. For bit 0, the xor would have fixed that as ($01,SP) will be 0X40. The problem is that this same trick doesn't work on bit 1 to 7.

    Use that cpl nop cycles to extract the MSB and it can free up the rest of GPIO C for other use.

  • Fixing STM8 USB source code comments

    K.C. Lee04/05/2017 at 16:52 0 comments

    I have to clean up some of the garbled unicode comments in the code.

    The editor somehow garbled the unicode. Thankfully the viewer on github is good.

    A bit of google translate:

    Decimal to hex conversion and some lazy address looking up inside the debugger:

    Clean up version of comment

  • Debugging STM8 VUSB code?

    K.C. Lee04/03/2017 at 22:58 0 comments

    Originally I was going to use the STM8S003 with the V-USB port but it turns out that it isn't working for me. I read in the Chinese forum that there were some problems with the bit-banging code and at some point it was supposed to be fixed by the original Russian author. There wasn't much news shortly that. Someone picked up the project, but then nothing since last year.

    The low level timing sensitive bit-bang assembly code have no documentation other than a few scattered single line English, Russian and Chinese comments. So I thought that was the cause and I went towards the EFM8UB1. Messing around point and click generated code doesn't suit my style either.

    Today I was playing around with the STM8 again. I have decided to look at the raw USB signals on my logic analyzer. It seems that some USB messages were being passed before it hangs. This means that the bit banging code was working and the problem is in the C code. That's something I might be able to fix.

    I don't read raw hex, so I looked for some USB packet level tool. I installed Free but limited version of Perisoft's BusHound to get a feel on what's going on.

    This is the point where the whole thing hangs. Now I have a lead.

    Test setup:

    I took a quick peak at the STM8 code. Looks like it doesn't look anything like the V-USB at all. I'll have to look at the message handling code to see if something is missing.

View all 4 project logs

View all 3 instructions

Enjoy this project?



Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates