00001 /* ---------------------------------------------------------------------------- */ 00002 /* Atmel Microcontroller Software Support */ 00003 /* SAM Software Package License */ 00004 /* ---------------------------------------------------------------------------- */ 00005 /* Copyright (c) 2015, Atmel Corporation */ 00006 /* */ 00007 /* All rights reserved. */ 00008 /* */ 00009 /* Redistribution and use in source and binary forms, with or without */ 00010 /* modification, are permitted provided that the following condition is met: */ 00011 /* */ 00012 /* - Redistributions of source code must retain the above copyright notice, */ 00013 /* this list of conditions and the disclaimer below. */ 00014 /* */ 00015 /* Atmel's name may not be used to endorse or promote products derived from */ 00016 /* this software without specific prior written permission. */ 00017 /* */ 00018 /* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR */ 00019 /* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ 00020 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE */ 00021 /* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, */ 00022 /* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ 00023 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */ 00024 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF */ 00025 /* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */ 00026 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */ 00027 /* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 00028 /* ---------------------------------------------------------------------------- */ 00029 00030 /** \cond usb_hid_keyboard 00031 * \page usb_hid_keyboard USB HID Keyboard Example 00032 * 00033 * \section Purpose 00034 * 00035 * The USB HID Keyboard Example will help you to get familiar with the 00036 * USB Device Port(UDP) and PIO interface on SAMV7/E7 Microcontrollers. Also 00037 * it can help you to be familiar with the USB Framework that is used for 00038 * rapid development of USB-compliant class drivers such as USB human 00039 * Interface Device class (HID). 00040 * 00041 * \section Requirements 00042 * 00043 * This package can be used with SAMV71 Xplained Ultra board or SAME70 Xplained board. 00044 * 00045 * \section Description 00046 * 00047 * The demo simulates a simple keyboard with a caps lock and 'a' on it. 00048 * 00049 * When a board running this program connected to a host (PC for 00050 * example), with USB cable, the board appears as a HID Keyboard for 00051 * the host. Then you can use the push buttons on the board to input 00052 * letter to the host. E.g, to open a editor and input a letter 'a'. 00053 * 00054 * \section Usage 00055 * 00056 * -# Build the program and download it inside the board. 00057 * Please refer to the Getting Started with SAM V71/E70 Microcontrollers.pdf 00058 * -# On the computer, open and configure a terminal application 00059 * (e.g. HyperTerminal on Microsoft Windows) with these settings: 00060 * - 115200 baud rate 00061 * - 8 bits of data 00062 * - No parity 00063 * - 1 stop bit 00064 * - No flow control 00065 * -# Start the application. 00066 * -# In the terminal window, the following text should appear: 00067 * \code 00068 * -- USB Device HID Keyboard Project xxx -- 00069 * -- SAMxxxxx-xx 00070 * -- Compiled: xxx xx xxxx xx:xx:xx -- 00071 * \endcode 00072 * -# When connecting USB cable to windows, the 00073 * new "HID Keyboard Device" appears in the 00074 * hardware %device list. 00075 * -# Once the device is connected and configured, pressing any of the board 00076 * buttons should send characters to the host PC. Pressing num. lock should 00077 * also make the third LED toggle its state (on/off). 00078 * 00079 * \section References 00080 * - usb_hid_keyboard/main.c 00081 * - pio: PIO interface driver 00082 * - pio.h 00083 * - pio_it.h 00084 * - usb: USB Framework, USB HID driver and UDP interface driver 00085 * - \ref usbd_framework 00086 * - \ref usbd_api 00087 * - \ref usbd_hid_kbd_drv 00088 */ 00089 00090 /** 00091 * \file 00092 * 00093 * This file contains all the specific code for the 00094 * usb_hid_keyboard 00095 * 00096 * \section Contents 00097 * 00098 * The code can be roughly broken down as follows: 00099 * - Configuration functions 00100 * - VBus_Configure 00101 * - ConfigurePit 00102 * - ConfigureWakeUp 00103 * - PIO & Timer configurations in start of main 00104 * - Interrupt handlers 00105 * - ISR_Vbus 00106 * - ISR_Pit 00107 * - WakeUpHandler 00108 * - Callback functions 00109 * - HIDDKeyboardCallbacks_LedsChanged 00110 * - The main function, which implements the program behavior 00111 * 00112 */ 00113 00114 /*----------------------------------------------------------------------------- 00115 * Headers 00116 *-----------------------------------------------------------------------------*/ 00117 00118 #include "board.h" 00119 00120 #include "USBD.h" 00121 #include "HIDDKeyboardDriver.h" 00122 #include "USBD_LEDs.h" 00123 00124 #include <string.h> 00125 #include <stdbool.h> 00126 #include <stdint.h> 00127 00128 00129 /*----------------------------------------------------------------------------- 00130 * Definitions 00131 *-----------------------------------------------------------------------------*/ 00132 #define NO_PUSHBUTTON 00133 00134 /** Number of keys used in the example. */ 00135 #define NUM_KEYS 2 00136 00137 /** Number of non-modifiers keys. */ 00138 #define NUM_NORMAL_KEYS 1 00139 00140 /** Number of modifier keys. */ 00141 #define NUM_MODIFIER_KEYS (NUM_KEYS - NUM_NORMAL_KEYS) 00142 00143 /** NumLock LED index. */ 00144 #define LED_NUMLOCK USBD_LEDOTHER 00145 00146 /*--------------------------------------------------------------------------- 00147 * External variables 00148 *---------------------------------------------------------------------------*/ 00149 00150 /** Descriptor list for HID keyboard device */ 00151 extern USBDDriverDescriptors hiddKeyboardDriverDescriptors; 00152 00153 /*--------------------------------------------------------------------------- 00154 * Internal variables 00155 *---------------------------------------------------------------------------*/ 00156 00157 #ifdef NO_PUSHBUTTON 00158 #else 00159 /** List of pinsPushButtons to configure for the application. */ 00160 static Pin pinsPushButtons[] = {PINS_PUSHBUTTONS}; 00161 #endif 00162 00163 /** Array of key codes produced by each button. */ 00164 static uint8_t keyCodes[NUM_KEYS] = { 00165 HIDKeypad_A, 00166 HIDKeypad_NUMLOCK, 00167 }; 00168 00169 /** Current status (pressed or not) for each key. */ 00170 static uint8_t keyStatus[NUM_KEYS]; 00171 00172 /*--------------------------------------------------------------------------- 00173 * Callbacks re-implementation 00174 *---------------------------------------------------------------------------*/ 00175 00176 /** 00177 * Invoked whenever a SETUP request is received from the host. Forwards the 00178 * request to the standard handler. 00179 */ 00180 void USBDCallbacks_RequestReceived(const USBGenericRequest *request) 00181 { 00182 HIDDKeyboardDriver_RequestHandler(request); 00183 } 00184 00185 /** 00186 * Invoked when the configuration of the device changes. Start reading 00187 * output reports. 00188 * \param cfgnum New configuration number. 00189 */ 00190 void USBDDriverCallbacks_ConfigurationChanged(uint8_t cfgnum) 00191 { 00192 HIDDKeyboardDriver_ConfigurationChangedHandler(cfgnum); 00193 } 00194 00195 /** 00196 * Invoked when the status of the keyboard LEDs changes. Turns the num. lock 00197 * LED on or off. 00198 * \param numLockStatus Indicates the current status of the num. lock key. 00199 * \param capsLockStatus Indicates the current status of the caps lock key. 00200 * \param scrollLockStatus Indicates the current status of the scroll lock key. 00201 */ 00202 void HIDDKeyboardCallbacks_LedsChanged( 00203 uint8_t numLockStatus, 00204 uint8_t capsLockStatus, 00205 uint8_t scrollLockStatus) 00206 { 00207 printf("%c %c %c\n\r", 00208 numLockStatus ? 'N' : '_', 00209 capsLockStatus ? 'C' : '_', 00210 scrollLockStatus ? 'S' : '_' 00211 ); 00212 00213 /* Num. lock */ 00214 if (numLockStatus) 00215 LED_Set(LED_NUMLOCK); 00216 else 00217 LED_Clear(LED_NUMLOCK); 00218 } 00219 00220 /*---------------------------------------------------------------------------- 00221 * Internal functions 00222 *----------------------------------------------------------------------------*/ 00223 /** 00224 * Configure USB settings for USB device 00225 */ 00226 static void _ConfigureUotghs(void) 00227 { 00228 00229 /* UTMI parallel mode, High/Full/Low Speed */ 00230 /* UUSBCK not used in this configuration (High Speed) */ 00231 PMC->PMC_SCDR = PMC_SCDR_USBCLK; 00232 /* USB clock register: USB Clock Input is UTMI PLL */ 00233 PMC->PMC_USB = PMC_USB_USBS; 00234 /* Enable peripheral clock for USBHS */ 00235 PMC_EnablePeripheral(ID_USBHS); 00236 USBHS->USBHS_CTRL = USBHS_CTRL_UIMOD_DEVICE; 00237 /* Enable PLL 480 MHz */ 00238 PMC->CKGR_UCKR = CKGR_UCKR_UPLLEN | CKGR_UCKR_UPLLCOUNT(0xF); 00239 00240 /* Wait that PLL is considered locked by the PMC */ 00241 while (!(PMC->PMC_SR & PMC_SR_LOCKU)); 00242 00243 /* IRQ */ 00244 NVIC_EnableIRQ(USBHS_IRQn); 00245 } 00246 00247 00248 /*--------------------------------------------------------------------------- 00249 * Exported function 00250 *---------------------------------------------------------------------------*/ 00251 00252 /** 00253 * Initializes the system and then monitors buttons, sending the 00254 * corresponding character when one is pressed. 00255 * \callgraph 00256 */ 00257 int main(void) 00258 { 00259 uint32_t i; 00260 00261 /* Disable watchdog */ 00262 WDT_Disable(WDT); 00263 00264 printf("-- USB Device HID Keyboard Project %s --\n\r", SOFTPACK_VERSION); 00265 printf("-- %s\n\r", BOARD_NAME); 00266 printf("-- Compiled: %s %s With %s--\n\r", __DATE__, __TIME__ , 00267 COMPILER_NAME); 00268 00269 SCB_EnableICache(); 00270 SCB_EnableDCache(); 00271 00272 /* If they are present, configure Vbus & Wake-up pins */ 00273 PIO_InitializeInterrupts(0); 00274 00275 _ConfigureUotghs(); 00276 00277 #ifdef NO_PUSHBUTTON 00278 printf("-- : DBG key 1 2 used as buttons\n\r"); 00279 printf("-- : 1st press to push, 2nd press to release\n\r"); 00280 #else 00281 /* Initialize key statuses and configure push buttons */ 00282 PIO_Configure(pinsPushButtons, PIO_LISTSIZE(pinsPushButtons)); 00283 #endif 00284 memset(keyStatus, 1, NUM_KEYS); 00285 00286 /* Configure LEDs */ 00287 LED_Configure(LED_NUMLOCK); 00288 00289 /* HID driver initialization */ 00290 HIDDKeyboardDriver_Initialize(&hiddKeyboardDriverDescriptors); 00291 00292 // Start USB stack to authorize VBus monitoring 00293 USBD_Connect(); 00294 00295 00296 /* Infinite loop */ 00297 while (1) { 00298 uint8_t pressedKeys[NUM_KEYS]; 00299 uint8_t pressedKeysSize = 0; 00300 uint8_t releasedKeys[NUM_KEYS]; 00301 uint8_t releasedKeysSize = 0; 00302 00303 if (USBD_GetState() < USBD_STATE_CONFIGURED) 00304 continue; 00305 00306 /* Monitor buttons */ 00307 #ifdef NO_PUSHBUTTON 00308 00309 if (DBG_IsRxReady()) { 00310 uint8_t key = DBG_GetChar(); 00311 00312 switch (key) { 00313 case '1': case '2': 00314 i = key - '1'; 00315 00316 if (keyStatus[i]) { 00317 /* Key press simulation */ 00318 TRACE_INFO("Key %u pressed\n\r", (unsigned int)i); 00319 keyStatus[i] = 0; 00320 pressedKeys[pressedKeysSize] = keyCodes[i]; 00321 pressedKeysSize ++; 00322 HIDDKeyboard_RemoteWakeUp(); 00323 } else { 00324 /* Key release simulation */ 00325 TRACE_INFO("Key %u released\n\r", (unsigned int)i); 00326 keyStatus[i] = 1; 00327 releasedKeys[releasedKeysSize] = keyCodes[i]; 00328 releasedKeysSize++; 00329 } 00330 00331 break; 00332 00333 default: DBG_PutChar(key); 00334 } 00335 } 00336 00337 #else 00338 00339 for (i = 0; i < PIO_LISTSIZE(pinsPushButtons); i++) { 00340 /* Check if button state has changed */ 00341 uint8_t isButtonPressed = PIO_Get(&(pinsPushButtons[i])); 00342 00343 if (isButtonPressed != keyStatus[i]) { 00344 /* Update button state */ 00345 if (!isButtonPressed) { 00346 /* Key has been pressed */ 00347 printf("BP %u pressed\n\r", (unsigned int)i); 00348 keyStatus[i] = 0; 00349 pressedKeys[pressedKeysSize] = keyCodes[i]; 00350 pressedKeysSize++; 00351 HIDDKeyboardDriver_RemoteWakeUp(); 00352 } else { 00353 /* Key has been released */ 00354 printf("BP %u released\n\r", (unsigned int)i); 00355 keyStatus[i] = 1; 00356 releasedKeys[releasedKeysSize] = keyCodes[i]; 00357 releasedKeysSize++; 00358 } 00359 } 00360 } 00361 00362 #endif 00363 00364 /* Update key status in the HID driver if necessary */ 00365 if ((pressedKeysSize != 0) || (releasedKeysSize != 0)) { 00366 uint8_t status; 00367 00368 do { 00369 status = HIDDKeyboardDriver_ChangeKeys(pressedKeys, 00370 pressedKeysSize, 00371 releasedKeys, 00372 releasedKeysSize); 00373 } while (status != USBD_STATUS_SUCCESS); 00374 } 00375 } 00376 } 00377 /** \endcond */