element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Freedom development platform
  • Products
  • Dev Tools
  • Freedom development platform
  • More
  • Cancel
Freedom development platform
Documents Codewarrior Tutorial for FRDM-KL25Z: Using the Freedom as an USB Keyboard
  • Blog
  • Forum
  • Documents
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Freedom development platform to participate - click to join for free!
Actions
  • Share
  • More
  • Cancel
Engagement
  • Author Author: FreescaleTools_and_Software
  • Date Created: 9 Aug 2013 8:57 AM Date Created
  • Last Updated Last Updated: 8 Oct 2021 5:34 AM
  • Views 1004 views
  • Likes 0 likes
  • Comments 0 comments
Related
Recommended

Codewarrior Tutorial for FRDM-KL25Z: Using the Freedom as an USB Keyboard

This tutorial was extracted from Erich Styger blog http://mcuoneclipse.wordpress.com with his agreement.

imageimage

    

I miss my old DELL laptop. Ok, the new one I received from IT services is not bad. It is faster and has a better screen. But I’m not really happy with the new keyboard. With the previous keyboard I was able to do a ‘PrtnScrn’ with a single key press. With the new one I need to press Fn + PrntScrn. And this is impossible to do with one hand:

  

Impossible to reach Prnt Scrn

Impossible to reach Fn+Prnt Scrn with one hand!

 

Yes, I have two hands ;-) . But many times I need to do ‘print screen’ while having my other hand on the mouse :-( .What else can I do?

 

Exploring Options

Of course there are several options:

  1. Call someone in my office and say “hey, can you give me a helping hand?”. Works, but my co-workers will hate me for this.
  2. Reconfigure my laptop keyboard mapping. Doable, but then the writing on the keyboard does not match the reality any more which can be confusing.
  3. Remapping the print screen functionality in SnagIt (the screen capture tool I’m using). That would be too easy ;-)
  4. Using the FRDM-KL25Z board as USB keyboard

 

As you might have guessed from this post title: I’m going for option 4 :mrgreen: .

This gives me the added value that I can do anything I want: having my own  shortcuts, doing sequences of key press actions, and so on. 

In the next steps I explain how to turn the FRDM-KL25Z into a USB HID Keyboard device with CodeWarrior for MCU10.4 and Processor Expert Components. A link to the project is posted at the end of this article.

 

Processor Expert Components

Make sure you have the latest Processor Expert components loaded (zip file attached to this post). Instructions how to load the components is explained in this post.

 

Creating CodeWarrior KL25Z Project

Create a new Processor Expert project in CodeWarrior using the menu File > New > BareBoard Project:

  1. Provide a name for the project
  2. Select the MKL25Z128 under Kinetis L Series > KL2x > KL25Z
  3. Select OpenSDA as connection
  4. In ‘Language and Build Tools Options’, the No I/O option can be selected for reduced footprint
  5. Select Processor Expert under Rapid Application Development
  6. Finished :-)

USB HID Project Created
USB HID Project Created

 

USB Clock Settings

The USB clock needs to be set at 48 MHz. For this, I open the Inspector on the Cpu:

 

  1. Enable ‘System oscillator 0′. This enables it to use the 8 MHz external crystal: 

      

    System Oscillator Enabled

    System Oscillator Enabled


  2. Set the MCG clock settings to PEE (PLL Engaged External) with 96 MHz: 
     

    PEE with 96 MHz

    PEE with 96 MHz


  3. Set the core clock to 48 MHz and the bus clock to 24 MHz:

    48 MHz Core Clock with 24 MHz Bus Clock

    48 MHz Core Clock with 24 MHz Bus Clock

With this I have properly configured the microcontroller to work for USB.

 

Adding USB Stack

The next step is to add the USB stack. I have created the FSL_USB_Stack Processor Expert component which is a wrapper for the Freescale bare metal USB stack. This USB stack can be used as well with an RTOS like FreeRTOS too. The FSL_USB_Stack component now supports HID, CDC and MSD device classes.

 

 

From the Components Library view, I add the component to my project (double-click on the component):

 

FSL_USB_Stack Component

FSL_USB_Stack Component

 

By default, it is added for CDC. So I need to configure it for USB HID Keyboard device class.

 

I select the FSL_USB_Stack and configure it:

  • USB is using Init_USB_OTG_VAR0: this one is used for Kinetis/ARM.
  • Device Class: HID Keyboard Device.
  • In the HID Keyboard field, I choose FSL_USB_HID_Keyboard_Device.

 

FSL_USB_Stack Configured for USB HID Keyboard
FSL_USB_Stack Configured for USB HID Keyboard

 

 

Next, I select the Init_USB_OTG component and configure it:

  • Enabled clock gate (otherwise the USB module is not clocked).
  • Set PLL/FLL as clock source (has to be 48 MHz, that’s why we configured the CPU clock in the previous step for 48 MHz).

 

Init Component Configured
Init Component Configured

 

 

Finally, configure the FSL_USB_HID_Keyboard_Device CPU:

 

FSL_USB_HID_Keyboard CPU Configured

FSL_USB_HID_Keyboard CPU Configured

 

 

Now all the error markers should disappear as I finished configuring the component.

 

FSL_USB_HID_Keyboard_Device Component

The component has two more settings which are used to report the device to the host:

 

HID Settings

HID Settings

 

 

The name is used in the Windows Device manager:

 

FSL HID Keyboard in the Windows Device Manager 

FSL HID Keyboard in the Windows Device Manager

 

 

The component features a ring buffer which is used to store keyboard events to be sent later:

 

USB HID Keyboard Buffer Settings

USB HID Keyboard Buffer Settings

 

 

The buffer entries are 16bit each (2 bytes), because a keyboard event has one byte for the ‘modifier’ (e.g. SHIFT pressed) and the key itself (e.g. ‘a’). More about this later. By default the buffer is set up for 16 entries: so I can buffer up to 16 items (or key changes). If you always send just one key, then you can reduce this number to a lower number, say 4 (to be safe).

 

 

USB HID Keyboard Protocol

The HID Keyboard device has to send a report to the host. That report is an array of 8 bytes describing the current key status:

  • Byte 0: Modifier byte which encodes CTRL, SHIFT, ALT and GUI keys (8 bits are defined for this)
  • Byte 1: unused
  • Byte 2-7: 6 bytes with key codes. With this it is possible to report up 6 plus the modifier keys pressed at the same time.

 

Typically only Byte 0 and Byte 2 are used. So for example to send a USB HID report that ‘a’ is pressed, I send

 

 

Byte 0: 0x00 (no modifier) Byte 2: 0x04 (is the code for key 'a') all other bytes are 0x00

 
To send the a report that ‘A’ is pressed (which is SHIFT+a):

 

 

Byte 0: 0x02 (left SHIFT key pressed) Byte 2: 0x04 (is the code for key 'a') all other bytes are 0x00

  

It is important to note that these reports are ‘keys are down’ reports. And as long as I do not send a new report, the last sent report is still active (or key pressed). So I need to send a message for the ‘release’ event, which is a report with all bytes zero:

 

Byte 0: 0x00 (no modifier key pressed) Byte 2: 0x00 (no key pressed) all other bytes are 0x00

 

The Key Usage codes are documented in chapter 10 of the HID Usage Tables of the USB Standard Document.

The FSL_USB_HID_Keyboard_Device Processor Expert component I have implemented makes it really easy to use.

 

FSL_USB_HID_Keyboard_Device Interface

The component offers the following methods and events:

 

HID Keyboard Device Interface

HID Keyboard Device Interface

 

  • App_Task() needs be called periodically. With this the elements from the ring buffer are sent to the USB bus. Call this method after you have used any of the Send methods. This routine returns ERR_OK if the device has been enumerated (is connected to the host).
  • SendStr() can be used to send an ASCII string. This method translates the string into USB HID messages and places them into the ring buffer to be processed by App_Task().
  • SendChar() is the same as SendStr(), but sends a single character only.
  • Send() is used to send native USB HID code. As for the other Send routines, it places the item into the buffer to be processed later by App_Task().

 

Examples how to use it:

 

for(;;) {

  if (HIDK1_App_Task()==ERR_OK) { /* run the USB application task: this will send the buffer */

    /* ok: we are connected! */

    (void)HIDK1_SendStr((unsigned char*)"Hello!"); /* send a string */

  }

}

:!: I’m ignoring here the return code of SendStr(). It would return ERR_TXFULL in case the ring buffer is not able to store the string. In that case either increase the buffer size, or send smaller strings and call App_Task() in between.

 

Once the device is connected and has finished enumeration, App_Task() will return ERR_OK. Then the applications places the string “Hello!” in the ring buffer, which is sent to the host in the nextApp_Task() call, as if would have typed it on the keyboard.

 

:!: It happened to me that such test code writes text to my host machine, potentially overwriting my stuff. I recommend to have a notepad window open (with active focus) so the board can write into that space instead overwriting your sources in the editor ;-)

:idea: you might get a ‘+’ character instead of the ‘!’. This is because my driver does not support different keyboard layouts and mappings. Contributions are more than welcome :-)

 

To send a single ASCII character is simple:

(void)HIDK1_SendChar('A'); /* send the A character */

 

Knowing the USB CDC protocol, it cannot send just the ‘A’ character. USB CDC defines the ‘a’ (and ‘A’) keyboard character with the value 0×04:

#define KEY_A                                  0x04

 

The information if it is ‘a’ or ‘A’ is encoded as ‘modifier’: if the SHIFT key is pressed or not. And there are several modifier flags available in the header file of the component:

 

#define MODIFERKEYS_NONE                          0x00

#define MODIFERKEYS_LEFT_CTRL                     0x01

#define MODIFERKEYS_LEFT_SHIFT                    0x02

#define MODIFERKEYS_LEFT_ALT                      0x04

#define MODIFERKEYS_LEFT_GUI                      0x08

#define MODIFERKEYS_RIGHT_CTRL                    0x10

#define MODIFERKEYS_RIGHT_SHIFT                   0x20

#define MODIFERKEYS_RIGHT_ALT                     0x40

#define MODIFERKEYS_RIGHT_GUI                     0x80

 

So to send ‘A’, I need to send MODIFERKEYS_LEFT_SHIFT and KEY_A.
This information is put together by SendChar() using the hidKeyCode table:

 

byte HIDK1_SendChar(byte ch)

{

  if (ch&0x7F) { /* only handle 0x00..0x7F */

    Tx2_Put(hidKeyCode[ch]); /* put 16bit value (modifier|code) into buffer */

  }

  Tx2_Put((MODIFERKEYS_NONE<<8)|KEY_NONE); /* send release message */

  return ERR_OK;

}

 

Note that the above code uses a second Put() with MODIFIERKEYS_NONE and KEY_NONE which is a ‘keys release’ message (actually it says ‘no keys pressed’). The HID protocol sends the actual state of a key. So if I send the information ‘the A key is pressed’ the host assumes that I still have that key pressed until I send another message about the new key. If I would not send that release message, the host assumes that the key ‘A’ is still pressed, and repeats the character. That’s why I send a ‘release’ message right afterwards to tell the host that all keys have been released.

SendChar() and SendStr() perform automatic ASCII to HID code translation. If I want to send HID codes directly, I can use the method Send() of the component:

 

byte HIDK1_Send(byte modifier, byte key)

{

  return Tx2_Put((modifier<<8)|key); /* put 16bit value (modifier|code) into buffer */

}

 

So for example if I want to send my ‘print screen’ action, I do it wit:

 

HIDK1_Send(MODIFERKEYS_NONE, KEY_PRINTSCREEN);

HIDK1_Send(MODIFERKEYS_NONE, KEY_NONE); /* release key */

 

And if I need CTRL+ALT+DELETE, then it is

 

HIDK1_Send(MODIFERKEYS_LEFT_CTRL|MODIFERKEYS_RIGHT_ALT, KEY_DELETE);

HIDK1_Send(MODIFERKEYS_NONE, KEY_NONE); /* release key */

 

Pretty easy :-)
 

The Application

Now I have everything in place. What I want is an application which sends the ‘Print Screen’ key event to the host with a single button press. For this I re-use the reset button of my FRDM-KL25Z (see this post how to do this). Then to add LEDs to show the status of the USB enumeration (see this post how to add LED’s). Adding some mechanics for LED blinking and button debouncing, and voilà:

 

for(;;) {

  WAIT1_Waitms(10);

  cnt++;

  if (SW1_GetVal()==0) { /* button pressed */

    WAIT1_Waitms(100); /* wait for debouncing */

    if (SW1_GetVal()==0) { /* still pressed */

      /* send print screen */

      HIDK1_Send(MODIFERKEYS_NONE, KEY_PRINTSCREEN);

      HIDK1_Send(MODIFERKEYS_NONE, KEY_NONE); /* release key */

    }

    while(SW1_GetVal()==0) {} /* wait until button is released */

  }

  if (HIDK1_App_Task()==ERR_OK) { /* run the USB application task: this will send the buffer */

    if ((cnt%100)==0) {

      LEDR_Off();

      LEDG_Neg(); /* blink green LED if connected */

    }

  } else {

    if ((cnt%200)==0) {

      LEDG_Off();

      LEDR_Neg(); /* blink red LED if not connected */

    }

  }

}

   

The red RGB LED blinks if not connected to the host, and the green one if it is connected as USB HID Keyboard. And when I press the reset button, it sends the ‘Print Screen’ key to the host. Finally I can do ‘print screen’ with my left hand while having my right hand on the (FRDM-KL25Z) keyboard :mrgeen:
 

Summary

With the creation of the USB HID Keyboard Device Processor Expert component, I have turned my FRDM-KL25Z init a generic USB keyboard device. With a simple button press I can send any keyboard actions to my laptop, making such as ‘print screen’ a single button press again. So it makes it a great device even for users with disabilities. And my ‘disability’ is solved now too: I get a print screen with the press of single button :mrgreen: :
  

Using FRDM-KL25Z as USB Keyboard Device

Using FRDM-KL25Z as USB Keyboard Device

  

 

Other ideas I have in mind: I thinking of turning the FRDM board into a wireless presenter. All what I need on top of this is either Bluetooth (but this would need to be a Bluetooth HID Keyboard), or maybe just using two FRDM boards: one is the keyboard dongle, and the other is sending data over the wireless communication channels. Still thinking about the best solution, and ideas are welcome.

The project created above (along with the components) are available in attachement to this post. While it does not support international keyboard mappings, that project has been very useful for me. I hope it is useful for you too.

 

Happy Keyboarding :-)

Attachments:
Freedom_USB_HID_Kbd.zip
0211.ProcessorExpertComponents070813.zip
  • keyboard
  • cortex-m0+
  • freescale
  • freedom_board
  • Cortex-M
  • kinetis
  • usb
  • cortex
  • frdm-kl25z
  • kinetis-l
  • cortex-m0
  • arm
  • freedom
  • Share
  • History
  • More
  • Cancel
  • Sign in to reply
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube