Example Firmware in C


Cypress enCoRe devices

by Stephen Santarelli

November 19, 2003

IMPORTANT NOTE:  A bug was recently uncovered in the firmware. Sometimes commands from the host that set LEDs are not received properly.  Read here  for bugfix information.  A completely updated and improved version of this firmware will be posted within the next few weeks--Please check back in.
sfs 4-15-04

This page describes some simple firmware wrtten in C using the Byte Craft cross-compiler for Cypress USB M8  microcontrollers.  This makes a handy starting point for the firmware developer wishing to use C to develop a wide range of  USB peripherals within the HID class. 


Cypress makes some very functional yet economical single-chip microcontrollers for creating low speed USB peripherals.  The enCoRe (enhanced Component Reduction) series devices are their latest offerings,  numbered CY7C632XXA, and CY7C637XX.  They include these features:

See Choosing the Right Device for your USB Application for a quick comparison between  between these devices and some other low speed MCUs make by Cypress.

Why make a low speed device when you could just choose a high speed chip?  Well, not all USB devices benefit from high speed communication, and the original USB developers were aware that for some devices (e.g. mice and keyboards), it didn't make sense to require a 12Mbps transciever and a  heavy shielded cable.  Imagine wiggling your computer mouse around with the same heavy cable that you connect to your printer or scanner.  Reduced complexity and bandwidth translate to lower cost and easier product development..

Using the serial port for comparison,  a low speed USB peripheral can send and receive 800 bytes per second, roughly comparable in data throughput  to a serial port peripheral sending and receiving data at 9600 bps, with start, stop and parity bits.  USB looks even better than that if you realize that it also includes ACK/NAK handshaking, and CRC checking, which would add more overhead to a serial link.

Going HID

One class, or subset, of  USB devices is the HID (human interface device).  HIDs include things that you would think of as devices to interface humans with computers, such as  keyboards, mice, and joysticks.  Fortunately though, a HID is not limited to these types of tasks.  A USB voltmeter, photometer, or even a Geiger counter could be defined as a HID. 

Perhaps the biggest benefit of defining a device within the HID class is that you can communicate with the device without a custom device driver!  There are API calls in Windows, MacOS, and Linux that allow you to communicate with these devices in user space.

Here's another nice fact about HIDs: standard, predefined devices like mice and keyboards are not platform specific.  You can plug a Macintosh mouse into a Windows PC or  Linux PC, and vice-versa.  Keyboards will work too, though the keys could have some different labelling (command key on Mac vs. Alt key on PC).  You can also connect multiple keyboards and mice to a single computer.

I began working with the enCoRe series in Fall of 2002.  My first projects were pretty simple, so my firmware was written using the assembler.   Stuart Allman's EDN article provides a simple example of a custom HID, and was the basis for my early firmware.  Often the bulk of the firmware for a HID is the bit stuffing required to make the SIE do what it needs to. That code may be reused for different projects.

Programming enCoRe in C

enCoRe devices belong to the M8 family of microcontrollers, which use a RISC instruction set, and only have two useable registers: the accumulator and the index register. Many operations require moving data into the Accumulator, operating on it, then writing back to RAM. The instruction set is very simple, so writing code for these CPUs is not so much difficult as it is monotonous, especially if you want to work with data types larger than 8 bits wide.  Why not use C?  If you already know the language, and the compiler doesn't add too much overhead, you will save time and get the job done right.

If you are using enCoRe chips in your design, you almost certainly own a Cypress CY3654+P05 platform kit.   A C cross-compiler written by Byte Craft is  included with the development kit. 

The compiler is versatile and creates efficient code.   You are free to use the rich selection of operators and constructs available in C.  A wide range of data types, 8, 16, 24, and 32 bit signed and unsigned integers,  plus 24 and 32 bit floating point types .  In addition there are two data types bit and bits that make accessing specific I/O or register bits easier.  

It is not difficult at all to blend assembly code with C code, and the two CPU registers and all the I/O and control registers are accessible directly from within C code.   Listing files generated by the compiler are compatible with Cydb, the debugger included with the Cypress development kit.  You can see the resultant op codes side by side with your C code.

A  library with some neat extras is included, including a software UART, string manipulation functions,  even functions  for communicating with LCD devices based on the ubiquitous Hitachi HD44780 LCD controller.  There are macros and library functions that allow simple reading and writing of external I/O pins.  The linker is efficient, and does not place unused library functions into ROM.

Control of I/O pins is simple.  To read a port, just use something like:

pinstate = PORT0.3;

to read bit 3 of  port 0.   To write to a port, you usually want to use one of the macros provided, as they use shadow registers.  This read/modify/write sequence is an important consideration with these MCUs.  The macros make things easy, for example:


will clear only bit 2 or port 1, leaving the other pins on port 1 unchanged.

Example Firmware in C

When starting a new embedded design, it is usually advantageous to look at a simple working example, particularly with a USB peripheral, as there are stringent requirements for the device to work properly.

It was disappointing to find that there were no complete firmware applications written for enCoRe chips. Cypress has some app notes and sample code for these on their website, but all in assembly code.  The two application examples included with the compiler distribution, mouse.c and keyboard.c, were written for other  M8 devices. The mouse example was written for a '63100A, which has very different  I/O register and bit definitions. 

The keyboard example was written for a '63512.  Fortunately,  this MCU has a  register architecture almost the same as the enCoRe series, particularly registers that control USB SIE functions.  None of the  enCoRe chips have enough I/O pins to implement a real keyboard, but I wasn't interested in building one anyway.  The goal here was to create a device that looked like a keyboard to the host as a starting point for other HIDs. 

The Cypress development system comes with an application board,  the CY3654D500, which has a socket for the MCU, a temperature sensor IC, an EEPROM, a pushbutton, and two LEDs.  My program effectively  turns this development board into a single key keyboard, ignoring the EEPROM and thermal sensor.

Plug this device into a computer, and it thinks you've plugged in a full keyboard.  Press the button, and it thinks you've pressed the 's' key.  It will work with Windows, MacOS, and Linux, provided you are using versions that support USB.  The firmware can easily be modified so any other keycode could be sent, including any key combination you could produce with a real keyboard.  Note that on USB enabled machines you may have more than one keyboard connected simultaneously, so you don't have to unplug your real keyboard to test this device.  You can even connect it to the USB port of a computer that is using a PS/2 keyboard, or a laptop.

Take a look at the Cypress  app note on designing a USB keyboard for a full explanation of the data packet format that a keyboard needs  to send.  Key codes may be found in the HID Usage Tables these are part of the USB specification.

The original keyboard.c program needed some modifications just to compile without errors for my target device, a CY7C63743.  Then the matrix scanning code was removed, and replaced by a simple read of  the  pushbutton, using a 30ms debounce.  When this button is pressed, a keycode is sent (in my example the letter s).  It doesn't send anything else until the button is released.  When that happens, keycode 0x00 is sent to notify the host.  The host's operating system keeps track of how long a key has been pressed, and starts the typematic repeat if it's held down long enough.

The ENUM LED is turned on when the device has been enumerated.  The ACTIVE LED lights when the pushbutton is held down.  The host does tell a keyboard which LEDs (NUM LOCK, SCROLL LOCK, or CAPS LOCK) should be lit via control transfers with Set_Report requests on endpoint 0, but these lights would only be turned on if the host received the appropriate key code (NUMLOCK, CAPS LOCK, etc) from this particular keyboard.  I didn't want to use my one available "key" as one of these keys, I wanted to see the results of my keypress on the computer screen.

I did not take the time to test suspend mode and remote wakeup, which means it is guaranteed not to work.  When I have a chance, that will be fixed.  If someone can take some time and fix it, please send me a copy of the source.  There are unused variables and arrays that should also be removed.  Sorry, please ignore.

Caution: when I was porting this code over, I encountered some problems.  The C63743.h file which defines registers and pin assignments has some missing definitions and errors as of compiler release 1.5.1.  Port.h also has problems.  Nevertheless, encorekbd.c works around these, and will compile and work properly with version 1.5.1 of the compiler, using header files and libraries belonging to that version.   I haven't yet tried V1.20 (the version actually shipped with the development kit), though I suspect there may have been even more header file issues.  You may have to contact Byte Craft directly to get the latest files.

There is a curious bug which cropped up while I was using this compiler.  Once in a while,  during development, the firmware will simply not work right.  After a lot of trial and error, I found that placing one (or sometimes more) NOP() macros in the code will temporarily cure the problem.  Write some more code, and you will have to remove the NOPs, and so forth.  It turns out these NOPs can apparently go anywhere in the program, and they will still cure the problem.  Byte Craft support is currently looking into this issue, and also fixing the header files.

Moving Forward

The idea here was to get a simple example of  a HID as a starting point for a bigger project.  Though a one key keyboard  may not seem very useful,  here are some ideas for projects that could be made with little or no changes to the source.

To use this code as a basis for other USB HIDs, you will need to modify the descriptor reports, the descriptor strings, get your own VID/PID and add some of your own application specific code.  The HID descriptor is the most complex of these, but is explained thorougly in USB Complete, by Jan Axleson. 

Read Using the HID class eases the job of writing device drivers by Stuart Allman for a great example of a user defined HID device, including a simple Windows application written in C.   The firmware is written in assembler, but it isn't hard to modify encorekbd.c to duplicate its functionality.


Download encorekbd

IMPORTANT NOTE:  A bug was recently uncovered in the firmware. Sometimes commands from the host that set LEDs are not received properly.  Read here  for bugfix information.  A completely updated and improved version of this firmware will be posted within the next few weeks--Please check back in. 
sfs 4-15-04

Source code:  encorekbd.c
ROM image, Intel hex format: encorekbd.hex

Requires Byte Craft Optimizing C Compiler for Cypress Semiconductor USB M8 Microcontrollers. This version was built using compiler version 1.5.1, including updated header files and libraries.  Based on example code provide by Byte Craft, see source file for restrictions on use.