diff --git a/Makefile b/Makefile index 3006988..5b9d65d 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,7 @@ all: main test: testgcm efm8prog: + flashefm8.exe -part EFM8UB10F8G -sn 440105518 -erase flashefm8.exe -part EFM8UB10F8G -sn 440105518 -upload '.\efm8\Keil 8051 v9.53 - Debug\efm8.hex' efm32prog: diff --git a/efm32/.cproject b/efm32/.cproject index 6cc2d33..02bf5c0 100644 --- a/efm32/.cproject +++ b/efm32/.cproject @@ -23,7 +23,7 @@ - + @@ -56,8 +56,8 @@ - + @@ -79,14 +79,15 @@ - + + - + @@ -159,8 +160,8 @@ - + @@ -176,14 +177,15 @@ - + + @@ -170,7 +170,7 @@ - + diff --git a/efm8/.settings/org.eclipse.cdt.codan.core.prefs b/efm8/.settings/org.eclipse.cdt.codan.core.prefs new file mode 100644 index 0000000..2ead633 --- /dev/null +++ b/efm8/.settings/org.eclipse.cdt.codan.core.prefs @@ -0,0 +1,71 @@ +eclipse.preferences.version=1 +org.eclipse.cdt.codan.checkers.errnoreturn=Warning +org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} +org.eclipse.cdt.codan.checkers.errreturnvalue=Error +org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nocommentinside=-Error +org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.nolinecomment=-Error +org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.noreturn=Error +org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} +org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error +org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error +org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning +org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning +org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} +org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error +org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=Warning +org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},skip\=>true} +org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.InvalidArguments=Error +org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error +org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=Error +org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=Error +org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info +org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},pattern\=>"^[a-z]",macro\=>true,exceptions\=>()} +org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning +org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error +org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error +org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error +org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning +org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>()} +org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning +org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},paramNot\=>false} +org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning +org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},else\=>false,afterelse\=>false} +org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning +org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true} +org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning +org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true} +org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning +org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>("@(\#)","$Id")} +org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error +org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +useParentScope=false diff --git a/efm8/efm8.hwconf b/efm8/efm8.hwconf index bab7c7b..7189f40 100644 --- a/efm8/efm8.hwconf +++ b/efm8/efm8.hwconf @@ -12,6 +12,9 @@ + + + @@ -20,21 +23,20 @@ + + - - - - - + + - + @@ -42,19 +44,17 @@ - - - - - - - + + + + - + + + + - - diff --git a/efm8/inc/InitDevice.h b/efm8/inc/InitDevice.h index fa302f2..a326614 100644 --- a/efm8/inc/InitDevice.h +++ b/efm8/inc/InitDevice.h @@ -19,8 +19,8 @@ extern void enter_DefaultMode_from_RESET(void); extern void WDT_0_enter_DefaultMode_from_RESET(void); extern void PORTS_0_enter_DefaultMode_from_RESET(void); extern void PORTS_1_enter_DefaultMode_from_RESET(void); -extern void PORTS_2_enter_DefaultMode_from_RESET(void); extern void PBCFG_0_enter_DefaultMode_from_RESET(void); +extern void LFOSC_0_enter_DefaultMode_from_RESET(void); extern void CIP51_0_enter_DefaultMode_from_RESET(void); extern void CLOCK_0_enter_DefaultMode_from_RESET(void); extern void TIMER01_0_enter_DefaultMode_from_RESET(void); diff --git a/efm8/inc/app.h b/efm8/inc/app.h index 436ee73..26363a3 100644 --- a/efm8/inc/app.h +++ b/efm8/inc/app.h @@ -8,9 +8,14 @@ #ifndef INC_APP_H_ #define INC_APP_H_ -#define USE_PRINTING +//#define USE_PRINTING void usb_transfer_complete(); void spi_transfer_complete(); +#define EFM32_RW_PIN P1_B2 +#define MSG_RDY_INT_PIN P1_B1 + +void delay(int ms); + #endif /* INC_APP_H_ */ diff --git a/efm8/inc/eeprom.h b/efm8/inc/eeprom.h new file mode 100644 index 0000000..deae867 --- /dev/null +++ b/efm8/inc/eeprom.h @@ -0,0 +1,19 @@ +#ifndef EEPROM_H_ +#define EEPROM_H_ + +#include "app.h" + +void eeprom_init(); + +void eeprom_read(uint16_t addr, uint8_t * buf, uint8_t len); + +void _eeprom_write(uint16_t addr, uint8_t * buf, uint8_t len, uint8_t flags); + +extern char __erase_mem[3]; + +#define eeprom_write(a,b,l) _eeprom_write(a,b,l,0x1) +#define eeprom_erase(a) _eeprom_write(a,__erase_mem,1,0x3) + +#define EEPROM_DATA_START 0xF800 + +#endif /* EEPROM_H_ */ diff --git a/efm8/inc/printing.h b/efm8/inc/printing.h index 25c0320..b57fe13 100644 --- a/efm8/inc/printing.h +++ b/efm8/inc/printing.h @@ -36,9 +36,11 @@ #define reboot() (RSTSRC = 1 << 4) +#define millis() ((uint16_t)(TMR3L | (TMR3H << 8))) + void u2f_delay(uint32_t ms); -void usb_write(uint8_t* buf, uint8_t len); +void usb_write(); diff --git a/efm8/lib/c8051f380/efm8_assert/assert.c b/efm8/lib/c8051f380/efm8_assert/assert.c new file mode 100644 index 0000000..b9a65c7 --- /dev/null +++ b/efm8/lib/c8051f380/efm8_assert/assert.c @@ -0,0 +1,12 @@ +/**************************************************************************//** + * Copyright (c) 2015 by Silicon Laboratories Inc. All rights reserved. + * + * http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt + *****************************************************************************/ + +#ifndef NDEBUG +void slab_Assert() +{ + while ( 1 ); +} +#endif diff --git a/efm8/lib/c8051f380/efm8_assert/assert.h b/efm8/lib/c8051f380/efm8_assert/assert.h new file mode 100644 index 0000000..5b951a5 --- /dev/null +++ b/efm8/lib/c8051f380/efm8_assert/assert.h @@ -0,0 +1,60 @@ +/****************************************************************************** + * Copyright (c) 2014 by Silicon Laboratories Inc. All rights reserved. + * + * http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt + *****************************************************************************/ + +#ifndef __ASSERT_H__ + +#include "efm8_config.h" + +/**************************************************************************//** + * @addtogroup efm8_assert + * @{ + * + * @brief Runtime assert for EFM8 + * + * This module contains a runtime assert macro. It can be compiled out by setting + * the NDEBUG flag. + * + *****************************************************************************/ + + +/**************************************************************************//** + * @def NDEBUG + * @brief Controls if the asserts are present. + * + * Asserts are removed if this symbol is defined + * + *****************************************************************************/ + +/**************************************************************************//** + * @def USER_ASSERT + * @brief User implemented assert function. + * + * When asserts are enabled the default handler can be be replaced with a user defined + * function of the form 'void userAssertName( const char * file, int line )' by setting + * the value of USER_ASSERT to the userAssertName. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_ASSERT(expr) + * @brief default implementation of assert_failed. + * + * This function can be replaced by a user defined assert function by setting the USER_ASSERT flag + *****************************************************************************/ + +#ifdef NDEBUG + #define SLAB_ASSERT(expr) +#else + #ifdef USER_ASSERT + #define SLAB_ASSERT(expr) ((expr) ? ((void)0) : USER_ASSERT( __FILE__, __LINE__ )) + #else + void slab_Assert(); + //Yes this is smaller than if(!expr){assert} + #define SLAB_ASSERT(expr) if(expr){}else{slab_Assert();} + #endif +#endif + +#endif //!__ASSERT_H__ diff --git a/efm8/lib/c8051f380/efm8_usb/Readme.txt b/efm8/lib/c8051f380/efm8_usb/Readme.txt new file mode 100644 index 0000000..8bcff83 --- /dev/null +++ b/efm8/lib/c8051f380/efm8_usb/Readme.txt @@ -0,0 +1,63 @@ +------------------------------------------------------------------------------- + Readme.txt +------------------------------------------------------------------------------- + +Copyright 2014 Silicon Laboratories, Inc. +http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt + +Program Description: +------------------- + +This is the generic EFM8 USB Firmware Library. Please see the EFM8 Libraries +Documentation for more information (/doc/EFM8/software/Lib/index.html). + +Known Issues and Limitations: +---------------------------- + +1) The library does not reset its Data Toggle after receiving a SET_INTERFACE + request. + +Target and Tool Chain Information: +--------------------------------- + +Target: EFM8UB1, EFM8UB2, EFM8UB3, EFM8UB4, C8051F320/1, C8051F326/7, C8051F34x, C8051F38x +Tool chain: Keil + +File List: +--------- + +/inc/efm8_usb.h +/src/efm8_usbd.c +/src/efm8_usbdch9.c +/src/efm8_usbdep.c +/src/efm8_usbdint.c + +Release Information: +------------------- + +Version 1.0.0 + - Initial release. + +Version 1.0.1 + - Fixed bug in logic of remote wakeup feature where the device would + attempt to wake the host before enabling its USB transceiver. + - Fixed bug where the device would stall the Data Phase instead of the + Setup Phase when sending a procedural stall on Endpoint 0. + - Fixed bug where a bus-powered device would look at VBUS after a USB Reset + to determine if it should enter the Default or Attached State. VBUS is + always present on a bus-powered device, so it should automatically enter + the Default State. + - Removed code that generated a compiler warning when + USB_PWRSAVE_MODE_FASTWAKE was enabled. + - Improved documentation of USB_PWRSAVE_MODE_FASTWAKE feature. + +Version 1.0.2 + - Added ability to detect short OUT packet in Isochronous mode and + stuff the buffer with zeroes to keep isochronous stream in sync. + +Version 1.0.3 + - Added support for EFM8UB3 and EFM8UB4 devices. + +------------------------------------------------------------------------------- + End Of File +------------------------------------------------------------------------------- diff --git a/efm8/lib/c8051f380/efm8_usb/inc/efm8_usb.h b/efm8/lib/c8051f380/efm8_usb/inc/efm8_usb.h new file mode 100644 index 0000000..fe70a9c --- /dev/null +++ b/efm8/lib/c8051f380/efm8_usb/inc/efm8_usb.h @@ -0,0 +1,2325 @@ +/***************************************************************************//** + * Copyright (c) 2015 by Silicon Laboratories Inc. All rights reserved. + * + * http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt + ******************************************************************************/ + +#ifndef __SILICON_LABS_EFM8_USB_H__ +#define __SILICON_LABS_EFM8_USB_H__ + +#include "si_toolchain.h" +#include "usbconfig.h" +#include +#include +#include +#include + +/***************************************************************************//** + * @addtogroup Efm8_usb + * @brief USB Device Protocol Stack for EFM8 devices + * @{ + * + * @section usb_device_contents Contents + * + * @li @ref usb_device_library_revision + * @li @ref usb_device_intro + * @li @ref usb_device_api + * @li @ref usb_device_conf + * @li @ref usb_device_powersave + * @li @ref usb_device_transfers + * @li @ref usb_device_pitfalls + * + * @n @section usb_device_library_revision EFM8 USB Library Revision + * Library Revision: 1.0.3 + * + * @n @section usb_device_intro Introduction + * + * The USB device protocol stack provides an API which makes it possible to + * create USB devices with a minimum of effort. The device stack supports Control, + * Bulk, Interrupt, and Isochronous transfers. + * + * The stack is highly configurable to suit various needs and includes + * demonstration projects to get you started fast. + * + * We recommend that you read through this documentation, then proceed to build + * and test a few example projects before you start designing your own device. + * + * @n @section usb_library_architecture_diagram Library Architecture Diagram + * + * @image html USB_Library_Architecture.png + * + * @n @section usb_device_api The EFM8 USB Library API + * + * This section contains brief descriptions of the functions in the API. You will + * find detailed information on input and output parameters and return values by + * clicking on the hyper-linked function names. It is also a good idea to study + * the code in the USB demonstration projects. + * + * Your application code must include one header file: @em efm8_usb.h. + * + * All functions defined in the API can be called from within interrupt handlers. + * + * @subsection usb_device_api_functions API Functions + * + * @ref USBD_Init() @n + * This function is called to register your device and all its properties with + * the device stack. The application must fill in a @ref USBD_Init_TypeDef + * structure prior to calling. When this function has been called your device + * is ready to be enumerated by the USB host. + * + * @ref USBD_Read(), @ref USBD_Write() @n + * These functions initiate data transfers. + * @n @htmlonly USBD_Read() @endhtmlonly initiate a transfer of data @em + * from host @em to device (an @em OUT transfer in USB terminology). + * @n @htmlonly USBD_Write() @endhtmlonly initiate a transfer of data @em from + * device @em to host (an @em IN transfer). + * + * When the USB host actually performs the transfer, your application will be + * notified by means of a call to the @ref USBD_XferCompleteCb() callback + * function (optionally). Refer to @ref TransferCallback for details of the + * callback functionality. + * + * @ref USBD_AbortTransfer(), @ref USBD_AbortAllTransfers() @n + * These functions terminate transfers that are initiated with @htmlonly + * USBD_Read() or USBD_Write() @endhtmlonly but that have not completed yet. + * These functions will deactivate the transfer setup to make the USB device + * endpoint hardware ready for new (and potentially) different transfers. + * + * @ref USBD_Connect(), @ref USBD_Disconnect() @n + * These functions turn the data-line (D+ or D-) pull-up on or off. They can + * be used to force re-enumeration. It's good practice to delay at least one + * second between @htmlonly USBD_Disconnect() and USBD_Connect() @endhtmlonly + * to allow the USB host to unload the currently active device driver. + * + * @ref USBD_EpIsBusy() @n + * Checks if an endpoint is busy. + * + * @ref USBD_StallEp(), @ref USBD_UnStallEp() @n + * These functions stall or un-stall an endpoint. This functionality may not + * be needed by your application. They may be useful when implementing some + * USB classes, e.g. a mass storage devices use them extensively. + * + * @ref USBD_Stop() @n + * Removes the data-line (D+ or D-) pull-up and disables the USB block. The + * application should call @htmlonly USBD_Init() after calling + * USBD_Stop() @endhtmlonly to restart USB operation. + * + * @ref USBD_Suspend() @n + * Puts the device in its low-power suspend mode. This function will not exit + * until a wakeup event (resume signaling, VBUS attachment/removal, or remote + * wakeup source interrupt) occurs. The USB Library can be configured to + * automatically call this function by configuring @ref SLAB_USB_PWRSAVE_MODE. + * + * @ref USBD_RemoteWakeup() @n + * Used in SUSPENDED state (see @ref USB_Status_TypeDef) to signal resume to + * host. The function will be called automatically by the library if the + * @ref USBD_RemoteWakeupCb() function returns true. The function will + * also check that the host has sent a SET_FEATURE request to enable Remote + * Wakeup before issuing the resume. + * + * @ref USBD_GetUsbState() @n + * Returns the device USB state (see @ref USBD_State_TypeDef). Refer to + * Figure 9-1. "Device State Diagram" in the USB revision 2.0 specification. + * + * @ref USBD_Run() @n + * When @ref SLAB_USB_POLLED_MODE is set to 1, the USB interrupt is disabled + * and the application must periodically call @htmlonly USBD_Run() + * @endhtmlonly to handle USB events. + * + * @n @subsection usb_device_api_callback Callback Functions + * + * @subsubsection usb_device_api_mandatory_callbacks Mandatory Callback Functions + * + * @n @anchor TransferCallback + * @ref USBD_XferCompleteCb() is called each time a packet is sent or + * received. It is called with three parameters, the status of the transfer, + * the number of bytes transferred and the number of bytes remaining. The + * transfer complete callback can be enabled or disabled by setting the + * callback parameters of @ref USBD_Write() and @ref USBD_Read() to + * true or false. + * @note This callback is called from within the USB interrupt handler if + * @ref SLAB_USB_POLLED_MODE is set to 1. Otherwise, it is called from + * @ref USBD_Run(). + * + * @n + * @subsubsection usb_device_api_optional_callbacks Optional Callback Functions + * + * @n These callbacks are all optional, and it is up to the application + * programmer to decide if the application needs the functionality they + * provide. Each callback is enabled or disabled by setting a constant in + * usbconfig.h. + * @note These callbacks are called from within the USB interrupt handler if + * @ref SLAB_USB_POLLED_MODE is set to 1. Otherwise, they are called + * from @ref USBD_Run(). + * + * @n USBD_ResetCb() is called each time reset signaling is sensed on the USB + * wire. + * + * @n USBD_SofCb() is called with the frame number as a parameter on each SOF + * interrupt. + * + * @n USBD_DeviceStateChangeCb() is called whenever the device state changes. + * Some uses of this include detecting that a USB suspend has been issued + * in order to reduce current consumption or calling USBD_Read() after + * entering the Configured state. The USB HID keyboard example + * project has a good example on how to use this callback. + * + * @n USBD_IsSelfPoweredCb() is called by the device stack when host + * queries the device with a GET_STATUS command to check if the device is + * currently self-powered or bus-powered. This feature is only applicable on + * self-powered devices which can also operate when only bus power is + * available. + * + * @n USBD_SetupCmdCb() is called each time a setup command is received from + * the host. Use this callback to override or extend the default handling of + * standard setup commands, and to implement class- or vendor-specific setup + * commands. The USB HID keyboard example project has a good example of how + * to use this callback. + * + * @n @section usb_device_conf Configuring the Library + * + * Your application must provide a header file named @em usbconfig.h. This file + * must contain the following \#define's. See @ref usb_config for + * documentation of these constants.@n @n + * @code + * // ----------------------------------------------------------------------------- + * // Specify bus- or self-powered + * // ----------------------------------------------------------------------------- + * #define SLAB_USB_BUS_POWERED 0 + * + * // ----------------------------------------------------------------------------- + * // Specify USB speed + * // ----------------------------------------------------------------------------- + * #define SLAB_USB_FULL_SPEED 1 + * + * // ----------------------------------------------------------------------------- + * // Enable or disable the clock recovery + * // ----------------------------------------------------------------------------- + * #define SLAB_USB_CLOCK_RECOVERY_ENABLED 1 + * + * // ----------------------------------------------------------------------------- + * // Enable or disable remote wakeup + * // ----------------------------------------------------------------------------- + * #define SLAB_USB_REMOTE_WAKEUP_ENABLED 0 + * + * // ----------------------------------------------------------------------------- + * // Specify number of interfaces and whether any interfaces support alternate + * // settings + * // ----------------------------------------------------------------------------- + * #define SLAB_USB_NUM_INTERFACES 1 + * #define SLAB_USB_SUPPORT_ALT_INTERFACES 0 + * + * // ----------------------------------------------------------------------------- + * // Enable or disable each endpoint + * // ----------------------------------------------------------------------------- + * #define SLAB_USB_EP1IN_USED 1 + * #define SLAB_USB_EP1OUT_USED 0 + * #define SLAB_USB_EP2IN_USED 0 + * #define SLAB_USB_EP2OUT_USED 0 + * #define SLAB_USB_EP3IN_USED 0 + * #define SLAB_USB_EP3OUT_USED 0 + * + * // ----------------------------------------------------------------------------- + * // Specify the maximum packet size for each endpoint + * // ----------------------------------------------------------------------------- + * #define SLAB_USB_EP1IN_MAX_PACKET_SIZE 64 + * #define SLAB_USB_EP1OUT_MAX_PACKET_SIZE 0 + * #define SLAB_USB_EP2IN_MAX_PACKET_SIZE 0 + * #define SLAB_USB_EP2OUT_MAX_PACKET_SIZE 0 + * #define SLAB_USB_EP3IN_MAX_PACKET_SIZE 0 + * #define SLAB_USB_EP3OUT_MAX_PACKET_SIZE 0 + * + * // ----------------------------------------------------------------------------- + * // Specify transfer type of each endpoint + * // ----------------------------------------------------------------------------- + * #define SLAB_USB_EP1IN_TRANSFER_TYPE USB_EPTYPE_INTR + * #define SLAB_USB_EP1OUT_TRANSFER_TYPE USB_EPTYPE_BULK + * #define SLAB_USB_EP2IN_TRANSFER_TYPE USB_EPTYPE_INTR + * #define SLAB_USB_EP2OUT_TRANSFER_TYPE USB_EPTYPE_BULK + * #define SLAB_USB_EP3IN_TRANSFER_TYPE USB_EPTYPE_ISOC + * #define SLAB_USB_EP3OUT_TRANSFER_TYPE USB_EPTYPE_ISOC + * + * // ----------------------------------------------------------------------------- + * // Enable or disable callback functions + * // ----------------------------------------------------------------------------- + * #define SLAB_USB_RESET_CB 1 + * #define SLAB_USB_SOF_CB 1 + * #define SLAB_USB_STATE_CHANGE_CB 1 + * #define SLAB_USB_IS_SELF_POWERED_CB 1 + * #define SLAB_USB_SETUP_CMD_CB 1 + * #define SLAB_USB_HANDLER_CB 0 + * + * // ----------------------------------------------------------------------------- + * // Specify number of languages supported by string descriptors + * // ----------------------------------------------------------------------------- + * #define SLAB_USB_NUM_LANGUAGES 1 + * + * // ----------------------------------------------------------------------------- + * // If only one descriptor language is supported, specify that language here. + * // If multiple descriptor languages are supported, this value is ignored and + * // the supported languages must listed in the + * // myUsbStringTableLanguageIDsDescriptor structure. + * // ----------------------------------------------------------------------------- + * #define SLAB_USB_LANGUAGE USB_LANGID_ENUS + * + * // ----------------------------------------------------------------------------- + * // Enable use of UTF-8 strings for string descriptors. + * // If this option is enabled then packed string descriptors that are created + * // with UTF8_PACKED_STATIC_CONST_STRING_DESC() can be UTF-8 encoded and they + * // will be decoded into UCS-2 16-bit wide character format used for USB string + * // descriptors. If this feature is not needed then it can be disabled to save + * // some code memory space. + * // ----------------------------------------------------------------------------- + * #define SLAB_USB_UTF8_STRINGS 1 + * + * // ----------------------------------------------------------------------------- + * // Set the power saving mode + * // + * // SLAB_USB_PWRSAVE_MODE configures when the device will automatically enter + * // the USB power-save mode. It is a bitmask constant with bit values: + * // + * // USB_PWRSAVE_MODE_OFF - No energy saving mode selected + * // USB_PWRSAVE_MODE_ONSUSPEND - Enter USB power-save mode on USB suspend + * // USB_PWRSAVE_MODE_ONVBUSOFF - Enter USB power-save mode when not attached + * // to the USB host. + * // USB_PWRSAVE_MODE_FASTWAKE - Exit USB power-save mode more quickly, but + * // consume more power while in USB power-save + * // mode. + * // While the device is in USB power-save mode + * // (typically during USB suspend), the + * // internal voltage regulator stays in normal + * // power mode instead of entering suspend + * // power mode. + * // This is an advanced feature that may be + * // useful in certain applications that support + * // remote wakeup. + * // ----------------------------------------------------------------------------- + * #define SLAB_USB_PWRSAVE_MODE (USB_PWRSAVE_MODE_ONVBUSOFF \ + * | USB_PWRSAVE_MODE_ONSUSPEND) + * + * // ----------------------------------------------------------------------------- + * // Enable or disable polled mode + * // + * // When enabled, the application must call USBD_Run() periodically to process + * // USB events. + * // When disabled, USB events will be handled automatically by an interrupt + * // handler. + * // ----------------------------------------------------------------------------- + * #define SLAB_USB_POLLED_MODE 0 + * @endcode + * + * @n @section usb_device_powersave Energy-saving options + * + * The device stack provides built-in energy saving options.These options + * are configured by setting flags in @ref SLAB_USB_PWRSAVE_MODE in @em + * usbconfig.h. These flags are bitmasks and can be or'd together.@n@n + * + * Energy-Saving Option Flags: + * + * @ref USB_PWRSAVE_MODE_OFF@n The device will not automatically enter its + * low-power suspned mode after detecting a USB suspend. The application + * firmware may still call @ref USBD_Suspend() to manually enter suspend mode. + * + * @ref USB_PWRSAVE_MODE_ONSUSPEND@n Enter a low-power suspend mode + * when a USB suspend is detected. When resume signaling is detected, + * the stack will exit the low-power mode. + * + * @ref USB_PWRSAVE_MODE_ONVBUSOFF@n Enter the low-power suspend + * mode any time the device detects that VBUS is not present. When VBUS is + * attached, the stack will exit the low-power mode. The USB Specification + * does not define the state of the device when VBUS is not present, but it + * may be desirable for some applications to enter suspend mode when in this + * undefined state. + * + * @ref USB_PWRSAVE_MODE_FASTWAKE@n Keep the internal regulator at + * its normal operating state while in the low-power suspend state. This + * allows the device to wake from suspend more quickly than it would from its + * suspend state. This option can be useful in applications that support + * remote wakeup and need to exit suspend in time to recognize some external + * signal (i.e. a byte received on the UART). The device will still consume + * low enough power to meet the USB Suspend Current Specification, but it will + * be slightly higher than it would otherwise be. + * + * The USB HID Keyboard device example project demonstrates some of these + * energy-saving options. + * + * Example: + * Leave all energy saving to the stack, the device enters low-power mode on + * suspend and when detached from host. @n + * In usbconfig.h: + * @code + * #define SLAB_USB_PWRSAVE_MODE (USB_PWRSAVE_MODE_ONSUSPEND | USB_PWRSAVE_MODE_ONVBUSOFF) + * @endcode + * + * @n @section usb_device_transfers Transfer Operation + * + * @subsection usb_device_transfers_overview Overview + * + * A USB transfer consists of one or more packets. For an IN transfer, the + * packets are sent from the device to the host. For an OUT transfer, the + * packets are sent from the host to the device. @ref USBD_Write() initiates + * an IN transfer, while @ref USBD_Read() initiates an OUT transfer. + * + * @subsection usb_device_transfers_types Transfer Types + * + * There are four USB transfer types: @ref usb_device_transfer_types_control, + * @ref usb_device_transfer_types_bulk, @ref usb_device_transfer_types_interrupt, + * and @ref usb_device_transfer_types_isochronous. + * + * @subsubsection usb_device_transfer_types_control Control + * + * Control transfers are used to send configuration and status + * information, and also to send vendor-defined data. The USB Library only + * supports control transfers on Endpoint 0. @n @n + * The application firmware can handle control requests by looking at the + * contents of the setup packet in @ref USBD_SetupCmdCb(). If the application + * supports a particular request, it can call @ref USBD_Read() or @ref + * USBD_Write() with epAddr set to EP0 and return @ref + * USB_STATUS_OK. If it does not need to handle the request, it should return + * @ref USB_STATUS_REQ_UNHANDLED. This will notify the library that it should + * try to handle the setup command. The library will automatically service + * Standard (i.e. Chapter 9) requests, so @ref USBD_SetupCmdCb() should return + * @ref USB_STATUS_REQ_UNHANDLED unless it is a class- or vendor-specific + * request. If neither the library nor the application supports a setup + * request, the library will issue a stall. + * + * @subsubsection usb_device_transfer_types_bulk Bulk + * + * Bulk transfers are used to send large, non-periodic data. Examples include + * sending a file to a Mass Storage Device or a print-job to a printer. A bulk + * transfer may consist of one or more packets. + * + * Endpoints are configured for bulk mode in usbconfig.h. As an + * example: @code + * #define SLAB_USB_EP1OUT_TRANSFER_TYPE USB_EPTYPE_BULK@endcode + * configures Endpout 1 OUT transfers for bulk mode. + * + * The @ref byteCount parameter of @ref USBD_Write() and @ref USBD_Read() + * configures the maximum length for a given bulk transfer. The transfer will + * complete when the device sends or receives either: + * 1. A packet less than its maximum packet size + * 2. Exactly the number of bytes specified in @ref byteCount + * Note that @ref USBD_XferCompleteCb() will be called for each packet sent or + * received for the duration of a transfer. + * + * @subsubsection usb_device_transfer_types_interrupt Interrupt + * + * Interrupt transfers are used to send low-bandwidth, hight-latency data at + * a non-periodic rate. Examples include input devices, such as mice, + * keyboards, and joysticks. An interrupt transfer may consist of one or more + * packets. + * + * Endpoints are configured for interrupt mode in usbconfig.h. As an + * example: @code + * #define SLAB_USB_EP1OUT_TRANSFER_TYPE USB_EPTYPE_INTR@endcode + * configures Endpout 1 OUT transfers for interrupt mode. + * + * Interrupt transfers work identically to bulk transfer in the USB Library. + * Refer to @ref usb_device_transfer_types_bulk for more information. + * + * @subsubsection usb_device_transfer_types_isochronous Isochronous + * + * Isochronous transfers are used to send periodic, continuous data. Automatic + * error-checking is not included with isochronous transfers as it is with all + * other transfer types. Examples include streaming audio and video. As + * isochronous data is sent at a continuous rate, it typically consists of + * one IN and/or OUT packet per frame. + * + * Endpoint 3 is the only endpoint in the USB Library that supports + * isochronous transfers. Endpoints are configured for isochronous mode in + * usbconfig.h. As an example: @code + * #define SLAB_USB_EP3OUT_TRANSFER_TYPE USB_EPTYPE_ISOC@endcode + * configures Endpout 3 OUT transfers for isochronous mode. + * + * The library works differently for isochronous transfers. The application + * must define a circular buffer to hold isochronous data. When calling + * USBD_Read() or USBD_Write(), dat is the first address of this + * buffer and byteCount is its length. The library will read from or + * write to this buffer as soon as the host issues a request, so it is the + * responsibility of the application firmware to ensure that this buffer is + * fed or consumed at the correct rate to prevent an underrun/overrun + * condition. + * + * The parameters of @ref USBD_XferCompleteCb() take on a different meaning in + * isochronous mode. For OUT transfers, xferred is the number of + * bute received in the last packet and remaining is the current + * index into the circular buffer. For IN transfers, xferred is + * ignored, remaining is the current index into the circular buffer, + * and the return value is the number of bytes to transmit in the next + * packet. + * + * @n @section usb_device_pitfalls Pitfalls + * + * @subsection usb_device_pitfalls_nonreentrancy Non-Reentrancy + * + * Due to the non-reentrant architecture of the 8051, it is recommended + * that all calls to a particular API function be made from functions of the + * same interrupt priority (main loop, low priority, or high priority). + * + * The interrupt priority of the USB callback functions is determined by the + * constant @ref SLAB_USB_POLLED_MODE. When 0, the callbacks are called from + * the USB Interrupt Handler. When 1, the callbacks are called from + * USBD_Run(), which is typically called from the main loop. + * If an API function must be called from functions of differing interrupt + * priorities, there are a number of ways to ensure that the calls are made + * safely: + * + * 1. Disable the interrupt source of the higher-priority function before + * making the call. Restore the interrupt enable setting after the call + * returns: + * + * (Assuming @htmlonly USBD_Write() is called from main() and + * USBD_XferCompleteCb() @endhtmlonly, the call from main() should + * disable and restore the USB interrupt): + * @code + * bool usbIntsEnabled = USB_GetIntsEnabled(); + * + * USB_DisableInts(); + * + * USBD_Write(EP1IN, myBuf, 1, true); + * + * if (usbIntsEnabled) + * { + * USB_EnableInts(); + * } + * @endcode + * + * 2. Add the compiler-specific reentrant keyword to the function + * definition(s) in efm8_usbd.c: + * @code + * int8_t USBD_AbortTransfer(uint8_t epAddr) reentrant + * @endcode + * and to the function prototype definition(s) in efm8_usb.h: + * @code + * int8_t USBD_AbortTransfer(uint8_t epAddr) reentrant; + * @endcode + * Using the reentrant keyword may require the application to provide + * a heap for local variable allocation. Additionally, it will reduce + * the performance and increase the code size of the modified function. + * 3. Make a copy of the function(s) and rename it. Call the original + * function in once context, and the renamed version in another. + * + * @subsection usb_device_pitfalls_buffer_allocation Buffer Allocation + * + * Dynamically allocated buffers passed to @ref USBD_Write() and @ref + * USBD_Read() must not be freed until the transfer completes. + * + ******************************************************************************/ + +/***************************************************************************//** + * @addtogroup efm8_usb_constants Constants + * @{ + ******************************************************************************/ + +// ----------------------------------------------------------------------------- +// Global Constants + +// SETUP request, direction of data stage +#define USB_SETUP_DIR_OUT 0 ///< Setup request data stage OUT direction value. +#define USB_SETUP_DIR_IN 1 ///< Setup request data stage IN direction value. +#define USB_SETUP_DIR_MASK 0x80 ///< Setup request data stage direction mask. +#define USB_SETUP_DIR_D2H 0x80 ///< Setup request data stage IN direction mask. +#define USB_SETUP_DIR_H2D 0x00 ///< Setup request data stage OUT direction mask. + +// SETUP request type +#define USB_SETUP_TYPE_STANDARD 0 ///< Standard setup request value. +#define USB_SETUP_TYPE_CLASS 1 ///< Class setup request value. +#define USB_SETUP_TYPE_VENDOR 2 ///< Vendor setup request value. +#define USB_SETUP_TYPE_STANDARD_MASK 0x00 ///< Standard setup request mask. +#define USB_SETUP_TYPE_CLASS_MASK 0x20 ///< Class setup request mask. +#define USB_SETUP_TYPE_VENDOR_MASK 0x40 ///< Vendor setup request mask. + +// SETUP request recipient +#define USB_SETUP_RECIPIENT_DEVICE 0 ///< Setup request device recipient value. +#define USB_SETUP_RECIPIENT_INTERFACE 1 ///< Setup request interface recipient value. +#define USB_SETUP_RECIPIENT_ENDPOINT 2 ///< Setup request endpoint recipient value. +#define USB_SETUP_RECIPIENT_OTHER 3 ///< Setup request other recipient value. + +// bmRequestType bitmasks +#define USB_BMREQUESTTYPE_RECIPIENT 0x1F ///< Recipient is bmRequestType[4:0] +#define USB_BMREQUESTTYPE_TYPE 0x60 ///< Type is bmRequestType[6:5] +#define USB_BMREQUESTTYPE_DIRECTION 0x80 ///< Recipient is bmRequestType[7] + +// SETUP standard request codes for Full Speed devices +#define GET_STATUS 0 ///< Standard setup request GET_STATUS. +#define CLEAR_FEATURE 1 ///< Standard setup request CLEAR_FEATURE. +#define SET_FEATURE 3 ///< Standard setup request SET_FEATURE. +#define SET_ADDRESS 5 ///< Standard setup request SET_ADDRESS. +#define GET_DESCRIPTOR 6 ///< Standard setup request GET_DESCRIPTOR. +#define SET_DESCRIPTOR 7 ///< Standard setup request SET_DESCRIPTOR. +#define GET_CONFIGURATION 8 ///< Standard setup request GET_CONFIGURATION. +#define SET_CONFIGURATION 9 ///< Standard setup request SET_CONFIGURATION. +#define GET_INTERFACE 10 ///< Standard setup request GET_INTERFACE. +#define SET_INTERFACE 11 ///< Standard setup request SET_INTERFACE. +#define SYNCH_FRAME 12 ///< Standard setup request SYNCH_FRAME. + +// SETUP class request codes +#define USB_HID_GET_REPORT 0x01 ///< HID class setup request GET_REPORT. +#define USB_HID_GET_IDLE 0x02 ///< HID class setup request GET_IDLE. +#define USB_HID_SET_REPORT 0x09 ///< HID class setup request SET_REPORT. +#define USB_HID_SET_IDLE 0x0A ///< HID class setup request SET_IDLE. +#define USB_HID_SET_PROTOCOL 0x0B ///< HID class setup request SET_PROTOCOL. +#define USB_CDC_SETLINECODING 0x20 ///< CDC class setup request SET_LINE_CODING. +#define USB_CDC_GETLINECODING 0x21 ///< CDC class setup request GET_LINE_CODING. +#define USB_CDC_SETCTRLLINESTATE 0x22 ///< CDC class setup request SET_CONTROL_LINE_STATE. +#define USB_MSD_BOTRESET 0xFF ///< MSD class setup request Bulk only transfer reset. +#define USB_MSD_GETMAXLUN 0xFE ///< MSD class setup request Get Max LUN. + +// SETUP command GET/SET_DESCRIPTOR descriptor types +#define USB_DEVICE_DESCRIPTOR 1 ///< DEVICE descriptor value. +#define USB_CONFIG_DESCRIPTOR 2 ///< CONFIGURATION descriptor value. +#define USB_STRING_DESCRIPTOR 3 ///< STRING descriptor value. +#define USB_INTERFACE_DESCRIPTOR 4 ///< INTERFACE descriptor value. +#define USB_ENDPOINT_DESCRIPTOR 5 ///< ENDPOINT descriptor value. +#define USB_DEVICE_QUALIFIER_DESCRIPTOR 6 ///< DEVICE_QUALIFIER descriptor value. +#define USB_OTHER_SPEED_CONFIG_DESCRIPTOR 7 ///< OTHER_SPEED_CONFIGURATION descriptor value. +#define USB_INTERFACE_POWER_DESCRIPTOR 8 ///< INTERFACE_POWER descriptor value. +#define USB_HUB_DESCRIPTOR 0x29 ///< HUB descriptor value. +#define USB_HID_DESCRIPTOR 0x21 ///< HID descriptor value. +#define USB_HID_REPORT_DESCRIPTOR 0x22 ///< HID REPORT descriptor value. +#define USB_CS_INTERFACE_DESCRIPTOR 0x24 ///< Audio Class-specific Descriptor Type. + +#define USB_DEVICE_DESCSIZE 18 ///< Device descriptor size. +#define USB_CONFIG_DESCSIZE 9 ///< Configuration descriptor size. +#define USB_INTERFACE_DESCSIZE 9 ///< Interface descriptor size. +#define USB_ENDPOINT_DESCSIZE 7 ///< Endpoint descriptor size. +#define USB_DEVICE_QUALIFIER_DESCSIZE 10 ///< Device qualifier descriptor size. +#define USB_OTHER_SPEED_CONFIG_DESCSIZE 9 ///< Device other speed configuration descriptor size. +#define USB_HID_DESCSIZE 9 ///< HID descriptor size. +#define USB_CDC_HEADER_FND_DESCSIZE 5 ///< CDC Header functional descriptor size. +#define USB_CDC_CALLMNG_FND_DESCSIZE 5 ///< CDC Call Management functional descriptor size. +#define USB_CDC_ACM_FND_DESCSIZE 4 ///< CDC Abstract Control Management functional descriptor size. + +// String descriptor locations +#define USB_STRING_DESCRIPTOR_ENCODING 0 ///< Denotes whether string descriptor is UTF-8 or binary +#define USB_STRING_DESCRIPTOR_LENGTH 1 ///< Length of string descriptor +#define USB_STRING_DESCRIPTOR_TYPE 2 ///< Type of string descriptor (USB_STRING_DESCRIPTOR) +#define USB_STRING_DESCRIPTOR_NAME 3 ///< The string encoded as per USB_STRING_DESCRIPTOR_PACKED + +// String descriptor encoding types +#define USB_STRING_DESCRIPTOR_UTF16LE 0 ///< The string is in UTF-16LE encoding +#define USB_STRING_DESCRIPTOR_UTF16LE_PACKED 1 ///< The string is in packed UTF-16LE encoding (the 0x00 + /// characters between ASCII characters are omitted) +#define USB_STRING_DESCRIPTOR_UTF8 2 ///< The string is in UTF-8 encoding + +// Misc. USB definitions +#define USB_FULL_EP0_SIZE 64 ///< The size of endpoint 0 at full speed. +#define USB_FULL_INT_BULK_MAX_EP_SIZE 64 ///< The max size of any full speed bulk/interrupt endpoint. +#define USB_FULL_ISOC_MAX_EP_SIZE 1023 ///< The max size of any full speed isochronous endpoint. +#define USB_LOW_EP0_SIZE 8 ///< The size of endpoint 0 at low speed. +#define USB_LOW_INT_BULK_MAX_EP_SIZE 8 ///< The max size of any low speed bulk/interrupt endpoint. +#define USB_LOW_ISOC_MAX_EP_SIZE 0 ///< The max size of any low speed isochronous endpoint. +#define USB_EPTYPE_CTRL 0 ///< Endpoint type control. +#define USB_EPTYPE_ISOC 1 ///< Endpoint type isochronous. +#define USB_EPTYPE_BULK 2 ///< Endpoint type bulk. +#define USB_EPTYPE_INTR 3 ///< Endpoint type interrupt. +#define USB_EP_DIR_IN 0x80 ///< Endpoint IN direction mask. +#define USB_EP_DIR_OUT 0x00 ///< Endponit OUT direction mask. +#define USB_SETUP_PKT_SIZE 8 ///< Setup request packet size. +#define USB_EPNUM_MASK 0x0F ///< Endpoint number mask. +#define USB_LANGID_ENUS 0x0409 ///< English-United States language id. +#define USB_LANGID_NOBO 0x0414 ///< Norwegian-Bokmal language id. +#define USB_MAX_DEVICE_ADDRESS 127 ///< Maximum allowable device address. +#define MAX_USB_EP_NUM 15 ///< Limit imposed by the USB standard +#define USB_VENDOR_ID_SILICON_LABS 0x10C4 ///< Silicon Labs VID + +#define CONFIG_DESC_BM_REMOTEWAKEUP 0x20 ///< Configuration descriptor attribute macro. +#define CONFIG_DESC_BM_SELFPOWERED 0x40 ///< Configuration descriptor attribute macro. +#define CONFIG_DESC_BM_RESERVED_D7 0x80 ///< Configuration descriptor attribute macro. +#define CONFIG_DESC_BM_TRANSFERTYPE 0x03 ///< Configuration descriptor transfer type bitmask. +#define CONFIG_DESC_MAXPOWER_mA(x) (((x)+1)/2) ///< Configuration descriptor power macro. + +#define DEVICE_IS_SELFPOWERED 0x0001 ///< Standard request GET_STATUS bitmask. +#define REMOTE_WAKEUP_ENABLED 0x0002 ///< Standard request GET_STATUS bitmask. +#define USB_FEATURE_ENDPOINT_HALT 0 ///< Standard request CLEAR/SET_FEATURE bitmask. +#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1 ///< Standard request CLEAR/SET_FEATURE bitmask. + +#define HUB_FEATURE_PORT_RESET 4 ///< HUB class request CLEAR/SET_PORT_FEATURE feature selector. +#define HUB_FEATURE_PORT_POWER 8 ///< HUB class request CLEAR/SET_PORT_FEATURE feature selector. +#define HUB_FEATURE_C_PORT_CONNECTION 16 ///< HUB class request CLEAR/SET_PORT_FEATURE feature selector. +#define HUB_FEATURE_C_PORT_RESET 20 ///< HUB class request CLEAR/SET_PORT_FEATURE feature selector. +#define HUB_FEATURE_PORT_INDICATOR 22 ///< HUB class request CLEAR/SET_PORT_FEATURE feature selector. + +#define USB_CLASS_CDC 2 ///< CDC device/interface class code. +#define USB_CLASS_CDC_DATA 0x0A ///< CDC Data interface class code. +#define USB_CLASS_CDC_ACM 2 ///< CDC Abstract Control Model interface subclass code. +#define USB_CLASS_CDC_HFN 0 ///< CDC class Header Functional Descriptor subtype. +#define USB_CLASS_CDC_CMNGFN 1 ///< CDC class Call Management Functional Descriptor subtype. +#define USB_CLASS_CDC_ACMFN 2 ///< CDC class Abstract Control Management Functional Descriptor subtype. +#define USB_CLASS_CDC_UNIONFN 6 ///< CDC class Union Functional Descriptor subtype. + +#define USB_CLASS_HID 3 ///< HID device/interface class code. +#define USB_CLASS_HID_KEYBOARD 1 ///< HID keyboard interface protocol code. +#define USB_CLASS_HID_MOUSE 2 ///< HID mouse interface protocol code. + +#define USB_CLASS_HUB 9 ///< HUB device/interface class code. + +#define USB_CLASS_MSD 8 ///< MSD device/interface class code. +#define USB_CLASS_MSD_BOT_TRANSPORT 0x50 ///< MSD Bulk Only Transport protocol. +#define USB_CLASS_MSD_SCSI_CMDSET 6 ///< MSD Subclass SCSI transparent command set. +#define USB_CLASS_MSD_CSW_CMDPASSED 0 ///< MSD BOT Command status wrapper command passed code. +#define USB_CLASS_MSD_CSW_CMDFAILED 1 ///< MSD BOT Command status wrapper command failed code. +#define USB_CLASS_MSD_CSW_PHASEERROR 2 ///< MSD BOT Command status wrapper cmd phase error code. + +#define USB_CLASS_VENDOR_SPECIFIC 0xFF ///< Vendor Specific class +#define USB_SUBCLASS_VENDOR_SPECIFIC 0xFF ///< Vendor Specific sub-class + +/// @brief USB power save modes +#define USB_PWRSAVE_MODE_OFF 0 ///< No energy saving option selected. +#define USB_PWRSAVE_MODE_ONSUSPEND 1 ///< Enter USB power-save mode on suspend. +#define USB_PWRSAVE_MODE_ONVBUSOFF 2 ///< Enter USB power-save mode when not attached to the USB host. +#define USB_PWRSAVE_MODE_FASTWAKE 4 ///< Exit USB power-save mode more quickly. This is useful for + ///< some applications that support remote wakeup. + +/// @brief Endpoint 0 packet size +#if SLAB_USB_FULL_SPEED +#define USB_EP0_SIZE USB_FULL_EP0_SIZE +#else +#define USB_EP0_SIZE USB_LOW_EP0_SIZE +#endif // SLABS_USB_FULL_SPEED + +/// @brief Total number of USB endpoints used by the device +#define SLAB_USB_NUM_EPS_USED (SLAB_USB_EP1IN_USED \ + + SLAB_USB_EP1OUT_USED \ + + SLAB_USB_EP2IN_USED \ + + SLAB_USB_EP2OUT_USED \ + + SLAB_USB_EP3IN_USED \ + + SLAB_USB_EP3OUT_USED \ + + 1) +/** @} (end addtogroup efm8_usb_constants Constants) */ + +/***************************************************************************//** + * @addtogroup efm8_usb_macros Macros + * @{ + ******************************************************************************/ + +// ----------------------------------------------------------------------------- +// Global Macros + +/// Macro for getting minimum value. +#ifndef EFM8_MIN +#define EFM8_MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +/// Macro for getting maximum value. +#ifndef EFM8_MAX +#define EFM8_MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef UNREFERENCED_ARGUMENT +#if defined __C51__ +/// Macro for removing unreferenced arguments from compiler warnings +#define UNREFERENCED_ARGUMENT(arg) (0, arg) +#elif defined __ICC8051__ +/// Macro for removing unreferenced arguments from compiler warnings +#define UNREFERENCED_ARGUMENT(arg) ((void)arg) +#endif +#endif + +/***************************************************************************//** + * @brief Macro for creating USB-compliant UTF-16LE UNICODE string + * descriptor from a C string. + * @details This macro should be used for ASCII strings in which all + * characters are represented by a single ASCII byte (i.e. + * U.S. English strings). + * The USB Library will expand variables created with this macro + * by inserting a 0x00 between each character. This allows the + * string to be stored in a "packed", or compressed, format. + * @n@n This example sends "Silicon Labs" as the Manufacturer String: + * + * #define MFR_STRING "Silicon Labs" + * + * UTF16LE_PACKED_STATIC_CONST_STRING_DESC(manufacturer[], \ + * MFR_STRING); + * @param __name + * The name of the variable that holds the string descriptor + * @param __val + * The value of the string descriptor + ******************************************************************************/ +#define UTF16LE_PACKED_STATIC_CONST_STRING_DESC(__name, __val, __size) \ + SI_SEGMENT_VARIABLE(__name, static const USB_StringDescriptor_TypeDef, SI_SEG_CODE) = \ + { USB_STRING_DESCRIPTOR_UTF16LE_PACKED, __size * 2, USB_STRING_DESCRIPTOR, __val } + +/***************************************************************************//** + * @brief Macro for creating USB-compliant UTF-16LE UNICODE string + * descriptor from a UTF-8 string. + * @details This macro should be used for UTF-8 strings in which all + * characters are represented by a valid UTF-8 byte sequence + * of 1-3 bytes per character. The USB library will expand + * variables created with this macro by decoding the UTF-8 + * sequence into 16-bit wide UCS-2 characters required for USB + * string descriptors. + * @n@n This example set an array named _manufacturer[]_ to a + * series of symbols: an anchor, a lightning bolt, and a + * fußball as the Manufacturer String: + * + * #define MFR_STRING "⚓⚡⚽" + * + * // This string has 3 Unicode characters so the __len + * // parameter is 3, even though it will take 3 bytes to + * // represent each character + * UTF8_PACKED_STATIC_CONST_STRING_DESC(manufacturer[], 3, \ + * MFR_STRING); + * @param __name + * The name of the variable that holds the string descriptor + * @param __len + * Number of Unicode characters (or codepoints) in the string + * @param __val + * The value of the string descriptor + ******************************************************************************/ +#define UTF8_PACKED_STATIC_CONST_STRING_DESC(__name, __len, __val) \ + SI_SEGMENT_VARIABLE(__name, static const USB_StringDescriptor_TypeDef, SI_SEG_CODE) = \ + { USB_STRING_DESCRIPTOR_UTF8, (__len) * 2, USB_STRING_DESCRIPTOR, __val } + +/***************************************************************************//** + * @brief Macro for creating USB-compliant UTF-16LE UNICODE string + * descriptor from a UTF-8 string. + * @details This macro should be used for UTF-8 strings in which all + * characters are represented by a valid UTF-8 byte sequence + * of 1-3 bytes per character. The USB library will expand + * variables created with this macro by decoding the UTF-8 + * sequence into 16-bit wide UCS-2 characters required for USB + * string descriptors. + * @n@n This example set an array named _manufacturer[]_ to a + * series of symbols: an anchor, a lightning bolt, and a + * fußball as the Manufacturer String: + * + * #define MFR_STRING "⚓⚡⚽" + * + * // This string has 3 Unicode characters so the __len + * // parameter is 3, even though it will take 3 bytes to + * // represent each character + * UTF8_PACKED_STATIC_CONST_STRING_DESC(manufacturer[], 3, \ + * MFR_STRING); + * @param __name + * The name of the variable that holds the string descriptor + * @param __len + * Number of Unicode characters (or codepoints) in the string + * @param __val + * The value of the string descriptor + ******************************************************************************/ +#define UTF8_PACKED_STATIC_CONST_STRING_DESC(__name, __len, __val) \ + SI_SEGMENT_VARIABLE(__name, static const USB_StringDescriptor_TypeDef, SI_SEG_CODE) = \ + { USB_STRING_DESCRIPTOR_UTF8, (__len) * 2, USB_STRING_DESCRIPTOR, __val } + +/***************************************************************************//** + * @brief Macro for creating USB-compliant UTF-16LE UNICODE string + * descriptor from a C array initializer. + * @details This macro should be used for converting an array initializer + * into a string descriptor. Unlike @ref + * UTF16LE_PACKED_STATIC_CONST_STRING_DESC(), the library will not + * attempt to unpack variables created with this macro, so the + * array will be sent exactly as it is defined. + * @n@n This example sends "Mouse" as the Product String: + * + * #define PROD_STRING 'M',0,'o',0,'u',0,'s',0,'e',0 + * + * ARRAY_STATIC_CONST_STRING_DESC(product[], \ + * 10, \ + * PROD_STRING); + * @param __name + * The name of the variable that holds the string descriptor + * @param __len + * Number of characters (including nulls) in the string to send + * @param __val + * The array initializer. + ******************************************************************************/ +#define ARRAY_STATIC_CONST_STRING_DESC(__name, __len, __val) \ + SI_SEGMENT_VARIABLE(__name, static const USB_StringDescriptor_TypeDef, SI_SEG_CODE) = \ + { USB_STRING_DESCRIPTOR_UTF16LE, __len + 2, USB_STRING_DESCRIPTOR, __val } + +/***************************************************************************//** + * @brief Macro for creating USB-compliant UTF-16LE UNICODE string + * descriptor from a UTF-16 C string. + * @details This macro should be used for strings which are already + * represented in UTF-16. This is an advanced option that should + * only be used for some foreign languages. + * @param __name + * The name of the variable that holds the string descriptor + * @param __val + * The value of the string descriptor + ******************************************************************************/ +#define UTF16LE_STATIC_CONST_STRING_DESC(__name, __val) \ + SI_SEGMENT_VARIABLE(__name, static const USB_StringDescriptor_TypeDef, SI_SEG_CODE) = \ + { USB_STRING_DESCRIPTOR_UTF16LE, sizeof(__val) + 2, USB_STRING_DESCRIPTOR, __val } + +/***************************************************************************//** + * @brief Macro for creating Language ID's String Descriptor (String + * Descriptor 0) + * @details This macro should be used to create the Language ID String + * Descriptor. + * @n@n This example USB device only support U.S. English: + * + * #define LANG_STRING htole16(SLAB_USB_LANGUAGE) + * + * LANGID_STATIC_CONST_STRING_DESC(langDesc[], LANG_STRING); + * + * This example USB device support Norwegian U.S. English: + * + * #define LANG_STRING htole16(USB_LANGID_NOBO), \ + * htole16(USB_LANGID_ENUS) + * + * LANGID_STATIC_CONST_STRING_DESC(langDesc[], LANG_STRING); + * + * @param __name + * The name of the variable that holds the string descriptor + * @param __val + * The value of the string descriptor + ******************************************************************************/ +#define LANGID_STATIC_CONST_STRING_DESC(__name, __val) \ + SI_SEGMENT_VARIABLE(__name, static const USB_LangId_StringDescriptor_Typedef, SI_SEG_CODE) = \ + { htole16(((SLAB_USB_NUM_LANGUAGES * 2) + 2) + (USB_STRING_DESCRIPTOR << 8)), __val } + +/** @} (end addtogroup efm8_usb_macros Macros) */ + +/***************************************************************************//** + * @addtogroup efm8_usb_typedefs Typedefs + * @{ + ******************************************************************************/ + +// ----------------------------------------------------------------------------- +// Typedefs + +/// @brief USB transfer status enumerator. +typedef enum +{ + USB_STATUS_OK = 0, ///< No errors detected. + USB_STATUS_REQ_ERR = -1, ///< Setup request error. + USB_STATUS_EP_BUSY = -2, ///< Endpoint is busy. + USB_STATUS_REQ_UNHANDLED = -3, ///< Setup request not handled. + USB_STATUS_ILLEGAL = -4, ///< Illegal operation attempted. + USB_STATUS_EP_STALLED = -5, ///< Endpoint is stalled. + USB_STATUS_EP_ABORTED = -6, ///< Endpoint transfer was aborted. + USB_STATUS_EP_ERROR = -7, ///< Endpoint transfer error. + USB_STATUS_EP_NAK = -8, ///< Endpoint NAK'ed transfer request. + USB_STATUS_DEVICE_UNCONFIGURED = -9, ///< Device is unconfigured. + USB_STATUS_DEVICE_SUSPENDED = -10, ///< Device is suspended. + USB_STATUS_DEVICE_RESET = -11, ///< Device is/was reset. + USB_STATUS_TIMEOUT = -12, ///< Transfer timeout. + USB_STATUS_DEVICE_REMOVED = -13, ///< Device was removed. + USB_STATUS_EP_RX_BUFFER_OVERRUN = -14, ///< Not enough data in the Rx buffer to hold the + USB_STATUS_DATA_ERROR = -15, ///< OUT packet had CRC or bit-stuffing error + ///< last received packet +} USB_Status_TypeDef; + +/// @brief USB device state enumerator. +typedef enum +{ + USBD_STATE_NONE = 0, ///< Device state is undefined/unknown. + USBD_STATE_ATTACHED = 1, ///< Device state is ATTACHED. + USBD_STATE_POWERED = 2, ///< Device state is POWERED. + USBD_STATE_DEFAULT = 3, ///< Device state is DEFAULT. + USBD_STATE_ADDRESSED = 4, ///< Device state is ADDRESSED. + USBD_STATE_SUSPENDED = 5, ///< Device state is SUSPENDED. + USBD_STATE_CONFIGURED = 6, ///< Device state is CONFIGURED. + USBD_STATE_LASTMARKER = 7, ///< Device state enum end marker. +} USBD_State_TypeDef; + +/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN +/// @brief Endpoint states +typedef enum +{ + D_EP_DISABLED = 0, ///< Endpoint is disabled + D_EP_IDLE = 1, ///< Endpoint is idle + D_EP_TRANSMITTING = 2, ///< Endpoint is transmitting data + D_EP_RECEIVING = 3, ///< Endpoint is receiving data + D_EP_STATUS = 4, ///< Endpoint is in status stage + D_EP_STALL = 5, ///< Endpoint is stalling + D_EP_HALT = 6, ///< Endpoint is halted + D_EP_LASTMARKER = 7 ///< End of EpState enum +} USBD_EpState_TypeDef; +/// @endcond DO_NOT_INCLUDE_WITH_DOXYGEN + +/// @brief Endpoint access address +typedef enum +{ + EP0, +#if (SLAB_USB_EP1IN_USED) + EP1IN, +#endif +#if (SLAB_USB_EP2IN_USED) + EP2IN, +#endif +#if (SLAB_USB_EP3IN_USED) + EP3IN, +#endif +#if (SLAB_USB_EP1OUT_USED) + EP1OUT, +#endif +#if (SLAB_USB_EP2OUT_USED) + EP2OUT, +#endif +#if (SLAB_USB_EP3OUT_USED) + EP3OUT, +#endif +} USB_EP_Index_TypeDef; + +/// @brief USB Setup type. +typedef struct +{ + struct + { + uint8_t Recipient : 5; ///< Request recipient (device, interface, endpoint, other) + uint8_t Type : 2; ///< Request type (standard, class or vendor). + uint8_t Direction : 1; ///< Transfer direction of SETUP data phase. + } bmRequestType; + + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} USB_Setup_TypeDef; + +/// @brief USB Setup Union type. +typedef union +{ + USB_Setup_TypeDef setup; + uint8_t c[8]; + uint16_t i[4]; +} USB_Setup_UnionDef; + +/// @brief USB Device Descriptor. +typedef struct +{ + uint8_t bLength; ///< Size of this descriptor in bytes + uint8_t bDescriptorType; ///< Constant DEVICE Descriptor Type + uint16_t bcdUSB; ///< USB Specification Release Number in BCD + uint8_t bDeviceClass; ///< Class code (assigned by the USB-IF) + uint8_t bDeviceSubClass; ///< Subclass code (assigned by the USB-IF) + uint8_t bDeviceProtocol; ///< Protocol code (assigned by the USB-IF) + uint8_t bMaxPacketSize0; ///< Maximum packet size for endpoint zero + uint16_t idVendor; ///< Vendor ID (assigned by the USB-IF) + uint16_t idProduct; ///< Product ID (assigned by the manufacturer) + uint16_t bcdDevice; ///< Device release number in binary-coded decimal + uint8_t iManufacturer; ///< Index of string descriptor describing manufacturer + uint8_t iProduct; ///< Index of string descriptor describing product + uint8_t iSerialNumber; ///< Index of string descriptor describing the serial number + uint8_t bNumConfigurations; ///< Number of possible configurations +} USB_DeviceDescriptor_TypeDef; + + +/// @brief USB Configuration Descriptor. +typedef struct +{ + uint8_t bLength; ///< Size of this descriptor in bytes + uint8_t bDescriptorType; ///< Constant CONFIGURATION Descriptor Type + uint16_t wTotalLength; ///< Total length of data returned for this + ///< configuration. Includes the combined length of all + ///< descriptors (configuration, interface, endpoint, + ///< and class- or vendor-specific) returned for this + ///< configuration. + uint8_t bNumInterfaces; ///< Number of interfaces supported by this + ///< configuration + uint8_t bConfigurationValue; ///< Value to use as an argument to the + ///< SetConfiguration request to select this + ///< configuration. + uint8_t iConfiguration; ///< Index of string descriptor describing this + ///< configuration. + uint8_t bmAttributes; ///< Configuration characteristics. + ///< @n D7: Reserved (set to one) + ///< @n D6: Self-powered + ///< @n D5: Remote Wakeup + ///< @n D4...0: Reserved (reset to zero) + uint8_t bMaxPower; ///< Maximum power consumption of the USB device, unit + ///< is 2mA per LSB +} USB_ConfigurationDescriptor_TypeDef; + + +/// @brief USB Interface Descriptor. +typedef struct +{ + uint8_t bLength; ///< Size of this descriptor in bytes. + uint8_t bDescriptorType; ///< Constant INTERFACE Descriptor Type. + uint8_t bInterfaceNumber; ///< Number of this interface. Zero-based value + ///< identifying the index in the array of concurrent + ///< interfaces supported by this configuration. + uint8_t bAlternateSetting; ///< Value used to select this alternate setting for + ///< the interface identified in the prior field. + uint8_t bNumEndpoints; ///< Number of endpoints used by this interface + ///< (excluding endpoint zero). If this value is zero, + ///< this interface only uses the Default Control Pipe. + uint8_t bInterfaceClass; ///< Class code (assigned by the USB-IF). A value + ///< of zero is reserved for future standardization. If + ///< this field is set to FFH, the interface class is + ///< vendor-specific. All other values are reserved for + ///< assignment by the USB-IF. + uint8_t bInterfaceSubClass; ///< Subclass code (assigned by the USB-IF). These codes + ///< are qualified by the value of the bInterfaceClass + ///< field. If the bInterfaceClass field is reset to + ///< zero, this field must also be reset to zero. If + ///< the bInterfaceClass field is not set to FFH, all + ///< values are reserved for assignment by the USB-IF. + uint8_t bInterfaceProtocol; ///< Protocol code (assigned by the USB). These codes + ///< are qualified by the value of the bInterfaceClass + ///< and the bInterfaceSubClass fields. If an interface + ///< supports class-specific requests, this code + ///< identifies the protocols that the device uses as + ///< defined by the specification of the device class. + ///< If this field is reset to zero, the device does + ///< not use a class-specific protocol on this + ///< interface. If this field is set to FFH, the device + ///< uses a vendor-specific protocol for this interface + uint8_t iInterface; ///< Index of string descriptor describing this + ///< interface. +} USB_InterfaceDescriptor_TypeDef; + + +/// @brief USB Endpoint Descriptor. +typedef struct +{ + uint8_t bLength; ///< Size of this descriptor in bytes + uint8_t bDescriptorType; ///< Constant ENDPOINT Descriptor Type + uint8_t bEndpointAddress; ///< The address of the endpoint + uint8_t bmAttributes; ///< This field describes the endpoint attributes + uint16_t wMaxPacketSize; ///< Maximum packet size for the endpoint + uint8_t bInterval; ///< Interval for polling EP for data transfers +} USB_EndpointDescriptor_TypeDef; + +/// @brief USB String Descriptor. +typedef uint8_t USB_StringDescriptor_TypeDef; ///< The string descriptor + +/// @brief USB Language ID String Descriptor. +typedef uint16_t USB_LangId_StringDescriptor_Typedef; ///< The language ID string descriptor + +#if (SLAB_USB_NUM_LANGUAGES == 1) +/// @brief USB String Table Structure. +typedef SI_VARIABLE_SEGMENT_POINTER(, USB_StringDescriptor_TypeDef, SI_SEG_GENERIC) USB_StringTable_TypeDef; +#elif (SLAB_USB_NUM_LANGUAGES > 1) +typedef struct +{ + uint16_t *languageIDs; + USB_StringDescriptor_TypeDef * * *languageArray; +} USB_StringTable_TypeDef; +#endif // ( SLAB_USB_NUM_LANGUAGES == 1 ) + +/// @brief USB Device stack initialization structure. +/// @details This structure is passed to @ref USBD_Init() when starting up +/// the device. +typedef struct +{ + SI_VARIABLE_SEGMENT_POINTER(deviceDescriptor, USB_DeviceDescriptor_TypeDef, SI_SEG_GENERIC); ///< Pointer to the device descriptor + SI_VARIABLE_SEGMENT_POINTER(configDescriptor, USB_ConfigurationDescriptor_TypeDef, SI_SEG_GENERIC); ///< Pointer to the configuration descriptor + SI_VARIABLE_SEGMENT_POINTER(stringDescriptors, USB_StringTable_TypeDef, SI_SEG_GENERIC); ///< Pointer to an array of string descriptor pointers + uint8_t numberOfStrings; ///< Number of strings in string descriptor array +} USBD_Init_TypeDef; + +/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN +// Endpoint structure +typedef struct +{ + SI_VARIABLE_SEGMENT_POINTER(buf, uint8_t, SI_SEG_GENERIC); + uint16_t remaining; + USBD_EpState_TypeDef state; + union + { + struct + { + uint8_t callback : 1; + uint8_t outPacketPending : 1; + uint8_t inPacketPending : 1; + uint8_t waitForRead : 1; + } bits; + uint8_t c; + } misc; +} USBD_Ep_TypeDef; + +// USB Device structure +typedef struct +{ + uint8_t configurationValue; +#if SLAB_USB_REMOTE_WAKEUP_ENABLED + uint8_t remoteWakeupEnabled; +#endif + uint8_t numberOfStrings; + USBD_State_TypeDef state; + USBD_State_TypeDef savedState; + USB_Setup_TypeDef setup; + union + { + struct + { + uint8_t type : 7; + uint8_t init : 1; + } encoding; + uint8_t c; + } ep0String; + USBD_Ep_TypeDef ep0; +#if SLAB_USB_EP1IN_USED + USBD_Ep_TypeDef ep1in; +#endif +#if SLAB_USB_EP2IN_USED + USBD_Ep_TypeDef ep2in; +#endif +#if SLAB_USB_EP3IN_USED + USBD_Ep_TypeDef ep3in; +#endif +#if SLAB_USB_EP1OUT_USED + USBD_Ep_TypeDef ep1out; +#endif +#if SLAB_USB_EP2OUT_USED + USBD_Ep_TypeDef ep2out; +#endif +#if SLAB_USB_EP3OUT_USED + USBD_Ep_TypeDef ep3out; +#endif +#if ((SLAB_USB_EP3IN_USED) && (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC)) + uint16_t ep3inIsoIdx; +#endif +#if ((SLAB_USB_EP3OUT_USED) && (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC)) + uint16_t ep3outIsoIdx; +#endif +#if SLAB_USB_SUPPORT_ALT_INTERFACES + uint8_t interfaceAltSetting[SLAB_USB_NUM_INTERFACES]; +#endif + SI_VARIABLE_SEGMENT_POINTER(deviceDescriptor, USB_DeviceDescriptor_TypeDef, SI_SEG_GENERIC); + SI_VARIABLE_SEGMENT_POINTER(configDescriptor, USB_ConfigurationDescriptor_TypeDef, SI_SEG_GENERIC); + SI_VARIABLE_SEGMENT_POINTER(stringDescriptors, USB_StringTable_TypeDef, SI_SEG_GENERIC); +} USBD_Device_TypeDef; +/// @endcond DO_NOT_INCLUDE_WITH_DOXYGEN + +/** @} (end addtogroup efm8_usb_typedefs Typedefs) */ + +/***************************************************************************//** + * @addtogroup efm8_usb_constants Constants + * @{ + ******************************************************************************/ + +// ----------------------------------------------------------------------------- +// Compiler-specific memory segment definitions + +#ifndef MEM_MODEL_SEG + +// ----------------------------------------------------------------------------- +// Memory Model-Specific Location +// +// MEM_MODEL_SEG is the default memory segment used for a given +// memory model. Some variables use this symbol in order to reduce the amount +// of code space and number of cycles it takes to access them. +// The user can override this value by defining it in his usbconfig.h file. +// For example: +// +// #define MEM_MODEL_LOC SI_SEG_XDATA +// +// will place these variables in XRAM regardless of the memory model used to +// build the project. +// ----------------------------------------------------------------------------- + +#if (defined SDCC) || (defined __SDCC) + +#if (__SDCC_MODEL_SMALL) +#define MEM_MODEL_SEG SI_SEG_IDATA +#elif defined __SDCC_MODEL_MEDIUM +#define MEM_MODEL_SEG SI_SEG_PDATA +#elif (defined __SDCC_MODEL_LARGE) || (defined __SDCC_MODEL_HUGE) +#define MEM_MODEL_SEG SI_SEG_XDATA +#else +#error "Illegal memory model setting." +#endif + +#elif defined __RC51__ + +#if (__MEMORY_MODEL__ == 0) // TINY +#define MEM_MODEL_SEG SI_SEG_IDATA +#elif (__MEMORY_MODEL__ == 1) // SMALL +#define MEM_MODEL_SEG SI_SEG_IDATA +#elif (__MEMORY_MODEL__ == 2) // COMPACT +#define MEM_MODEL_SEG SI_SEG_PDATA +#elif (__MEMORY_MODEL__ == 3) // LARGE +#define MEM_MODEL_SEG SI_SEG_XDATA +#elif (__MEMORY_MODEL__ == 4) // HUGE +#define MEM_MODEL_SEG SI_SEG_PDATA +#else +#error "Illegal memory model setting." +#endif + +#elif defined __C51__ + +#if (__MODEL__ == 0) // SMALL +#define MEM_MODEL_SEG SI_SEG_IDATA +#elif (__MODEL__ == 1) // COMPACT +#define MEM_MODEL_SEG SI_SEG_PDATA +#elif (__MODEL__ == 2) // LARGE +#define MEM_MODEL_SEG SI_SEG_XDATA +#else +#error "Illegal memory model setting." +#endif + +#elif defined _CC51 + +#if (_MODEL == 's') // SMALL +#define MEM_MODEL_SEG SI_SEG_IDATA +#elif (_MODEL == 'a') // AUXPAGE +#define MEM_MODEL_SEG SI_SEG_PDATA +#elif (_MODEL == 'l') // LARGE +#define MEM_MODEL_SEG SI_SEG_XDATA +#elif (_MODEL == 'r') // REENTRANT +#define MEM_MODEL_SEG SI_SEG_XDATA +#else +#error "Illegal memory model setting." +#endif + +#elif defined __ICC8051__ +#if (__DATA_MODEL__ == 0) // TINY +#define MEM_MODEL_SEG SI_SEG_IDATA +#elif (__DATA_MODEL__ == 1) // SMALL +#define MEM_MODEL_SEG SI_SEG_IDATA +#elif (__DATA_MODEL__ == 2) // LARGE +#define MEM_MODEL_SEG SI_SEG_XDATA +#elif (__DATA_MODEL__ == 3) // GENERIC +#define MEM_MODEL_SEG SI_SEG_XDATA +#elif (__DATA_MODEL__ == 4) // FAR +#define MEM_MODEL_SEG SI_SEG_XDATA +#else +#error "Illegal memory model setting." +#endif + +#endif +#endif // #ifndef MEM_MODEL_SEG + +/** @} (end addtogroup efm8_usb_constants Constants) */ + +/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN +void USBD_SetUsbState(USBD_State_TypeDef newState); +USB_Status_TypeDef USBDCH9_SetupCmd(void); +/// @endcond DO_NOT_INCLUDE_WITH_DOXYGEN + +// ----------------------------------------------------------------------------- +// Library Configuration Definitions + +/**************************************************************************//** + * @addtogroup efm8_usb_config Library Configuration + * @{ + * + * @details Library configuration constants read from usbconfig.h. + * + * This library will look for configuration constants in **usbconfig.h**. + * This file is provided/written by the user and should be + * located in a directory that is part of the include path. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_BUS_POWERED + * @brief Configures the USB device for bus-powered or self-powered mode. + * @details + * When '1' the USB device is bus-powered. + * When '0' the USB device is self-powered. + * + * Default setting is '1' and may be overridden by defining in 'usbconfig.h'. + * + * @note The EFM8UB1, EFM8UB3, and EFM8UB4 devices can be configured to ignore + * the voltage on the VBUS pin and to instead use that pin as GPIO. If + * this feature is used, SLAB_USB_BUS_POWERED should be set to '1' even if + * the device is not drawing its power from the VBUS line. + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_FULL_SPEED + * @brief Configures the USB device for full-speed or low-speed operation. + * @details + * When '1' the USB device is full-speed + * When '0' the USB device is low-speed + * + * Default setting is '1' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_CLOCK_RECOVERY_ENABLED + * @brief Enables/disables the USB Clock Recovery + * @details USB Clock Recovery uses the incoming USB dat stream to adjust the + * internal oscillator. This allows the internal oscillator to meet the + * requirements for USB clock tolerance. + * + * When '1' the USB clock recovery is enabled + * When '0' the USB clock recovery is disabled + * + * Default setting is '1' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_REMOTE_WAKEUP_ENABLED + * @brief Enables/disables remote wakeup capability + * @details Remote wakeup allow the USB device to wake the host from suspend. + * When enabled, the library will call @ref USBD_RemoteWakeupCb() to determine + * if the remote wakeup source caused the device to wake up. If it did, the + * library will exit suspend mode and call @ref USBD_RemoteWakeup() to wake + * up the host. + * + * When '1' remote wakeup is enabled + * When '0' remote wakeup is disabled + * + * Default setting is '0' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_NUM_INTERFACES + * @brief The number of interfaces available in the configuration + * @details + * Default setting is '1' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_SUPPORT_ALT_INTERFACES + * @brief Enables/disables alternate interface settings + * @details If any of the interfaces support alternate settings, this should be + * set to '1'. Upon receiveing a SET_INTERFACE request, the library will call + * @ref USBD_SetInterfaceCb(), which should return @ref USB_STATUS_OK if the + * alternate setting is valid or @ref USB_STATUS_REQ_ERR if it is not. + * + * When '1' alternate inteface settings are supported + * When '0' alternate interface settings are not supported, and the library will + * respond to any SET_INTERFACE request with a procedural stall + * + * Default setting is '0' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_EP1IN_USED + * @brief Enables/disables Endpoint 1 IN + * @details + * When '1' Endpoint 1 IN is enabled + * When '0' Endpoint 1 IN is disabled + * + * Default setting is '0' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_EP1OUT_USED + * @brief Enables/disables Endpoint 1 OUT + * @details + * When '1' Endpoint 1 OUT is enabled + * When '0' Endpoint 1 OUT is disabled + * + * Default setting is '0' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_EP2IN_USED + * @brief Enables/disables Endpoint 2 IN + * @details + * When '1' Endpoint 2 IN is enabled + * When '0' Endpoint 2 IN is disabled + * + * Default setting is '0' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_EP2OUT_USED + * @brief Enables/disables Endpoint 2 OUT + * @details + * When '1' Endpoint 2 OUT is enabled + * When '0' Endpoint 2 OUT is disabled + * + * Default setting is '0' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_EP3IN_USED + * @brief Enables/disables Endpoint 3 IN + * @details + * When '1' Endpoint 3 IN is enabled + * When '0' Endpoint 3 IN is disabled + * + * Default setting is '0' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_EP3OUT_USED + * @brief Enables/disables Endpoint 3 OUT + * @details + * When '1' Endpoint 3 OUT is enabled + * When '0' Endpoint 3 OUT is disabled + * + * Default setting is '0' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_EP1IN_MAX_PACKET_SIZE + * @brief The maximum packet size that can be received on Endpoint 1 IN + * @details + * Default setting is '64' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_EP1OUT_MAX_PACKET_SIZE + * @brief The maximum packet size that can be transmitted on Endpoint 1 OUT + * @details + * Default setting is '64' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_EP2IN_MAX_PACKET_SIZE + * @brief The maximum packet size that can be received on Endpoint 2 IN + * @details + * Default setting is '64' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_EP2OUT_MAX_PACKET_SIZE + * @brief The maximum packet size that can be transmitted on Endpoint 2 OUT + * @details + * Default setting is '64' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_EP3IN_MAX_PACKET_SIZE + * @brief The maximum packet size that can be received on Endpoint 3 IN + * @details + * Default setting is '64' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_EP3OUT_MAX_PACKET_SIZE + * @brief The maximum packet size that can be transmitted on Endpoint 3 OUT + * @details + * Default setting is '64' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_EP1IN_TRANSFER_TYPE + * @brief Transfer type on Endpoint 1 IN + * @details + * May take one of the following values: + * USB_EPTYPE_INTR - Interrupt + * USB_EPTYPE_BULK - Bulk + * + * Default setting is @ref USB_EPTYPE_INTR and may be overridden by defining in + * 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_EP1OUT_TRANSFER_TYPE + * @brief Transfer type on Endpoint 1 OUT + * @details + * May take one of the following values: + * USB_EPTYPE_INTR - Interrupt + * USB_EPTYPE_BULK - Bulk + * + * Default setting is @ref USB_EPTYPE_INTR and may be overridden by defining in + * 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_EP2IN_TRANSFER_TYPE + * @brief Transfer type on Endpoint 2 IN + * @details + * May take one of the following values: + * USB_EPTYPE_INTR - Interrupt + * USB_EPTYPE_BULK - Bulk + * + * Default setting is @ref USB_EPTYPE_INTR and may be overridden by defining in + * 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_EP2OUT_TRANSFER_TYPE + * @brief Transfer type on Endpoint 2 OUT + * @details + * May take one of the following values: + * USB_EPTYPE_INTR - Interrupt + * USB_EPTYPE_BULK - Bulk + * + * Default setting is @ref USB_EPTYPE_INTR and may be overridden by defining in + * 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_EP3IN_TRANSFER_TYPE + * @brief Transfer type on Endpoint 3 IN + * @details + * May take one of the following values: + * USB_EPTYPE_INTR - Interrupt + * USB_EPTYPE_BULK - Bulk + * USB_EPTYPE_ISOC - Isochronous + * + * Default setting is @ref USB_EPTYPE_INTR and may be overridden by defining in + * 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_EP3OUT_TRANSFER_TYPE + * @brief Transfer type on Endpoint 3 OUT + * @details + * May take one of the following values: + * USB_EPTYPE_INTR - Interrupt + * USB_EPTYPE_BULK - Bulk + * USB_EPTYPE_ISOC - Isochronous + * + * Default setting is @ref USB_EPTYPE_INTR and may be overridden by defining in + * 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_RESET_CB + * @brief Enables/disables the USB Reset callback function + * @details + * When '1' @ref USBD_ResetCb() is called upon reception of a USB Reset + * When '0' @ref USBD_ResetCb() is not called upon reception of a USB Reset + * + * Default setting is '0' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_SOF_CB + * @brief Enables/disables the USB Start-Of-Frame callback function + * @details + * When '1' @ref USBD_SofCb() is called upon reception of a Start-of-Frame + * packet + * When '0' @ref USBD_SofCb() is not called upon reception of a Start-of-Frame + * packet + * + * Default setting is '0' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_STATE_CHANGE_CB + * @brief Enables/disables the USB State Change callback function + * @details + * When '1' @ref USBD_DeviceStateChangeCb() is called when the USB device state + * changes + * When '0' @ref USBD_DeviceStateChangeCb() is not called when the USB device + * state changes + * + * Default setting is '0' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_IS_SELF_POWERED_CB + * @brief Enables/disables the USB Self-Powered callback function + * @details + * When '1' @ref USBD_IsSelfPoweredCb() is called upon reception of a + * GET_STATUS (Self-Powered) request + * When '0' @ref USBD_IsSelfPoweredCb() is not called upon reception of a + * GET_STATUS (Self-Powered) request + * + * Default setting is '0' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_SETUP_CMD_CB + * @brief Enables/disables the USB Setup Command callback function + * @details + * When '1' @ref USBD_SetupCmdCb() is called upon reception of a Setup Request + * When '0' @ref USBD_SetupCmdCb() is not called upon reception of a Setup + * Request + * + * Default setting is '0' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_HANDLER_CB + * @brief Enables/disables the USB Handler Entry and Exit callback functions + * @details + * When '1' @ref USBD_EnterHandler() will be called before the USB handler + * executes and @ref USBD_ExitHandler() will be called after the USB handler + * completes + * When '0' @ref USBD_EnterHandler() and @ref USBD_ExitHandler() will not be + * called + * + * Default setting is '0' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_NUM_LANGUAGES + * @brief Number of languages supported by the USB string descriptors + * @details + * Default setting is '1' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_LANGUAGE + * @brief + * Defines the language of the USB string descriptors when + * @ref SLAB_USB_NUM_LANGUAGES is '1'. + * + * @details + * When @ref SLAB_USB_NUM_LANGUAGES is greater than '1', the supported languages + * must be defined in a separate table, and a structure of type + * @ref USB_StringDescriptor_TypeDef must be defined for each supported + * language + * + * Default setting is @ref USB_LANGID_ENUS and may be overridden by defining in + * 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_UTF8_STRINGS + * @brief + * Enables UTF-8 string decoding for USB string descriptors that are created + * using @ref UTF8_PACKED_STATIC_CONST_STRING_DESC. + * + * @details + * If this option is enabled, USB descriptor strings that are created using + * @ref UTF8_PACKED_STATIC_CONST_STRING_DESC can be encoded as UTF-8 which + * allows for Unicode characters (up to 16-bits wide) to be used for USB + * string descriptors. The UTF-8 strings will be decoded into UCS-2 16-bit + * wide character format required by USB. If this feature is not needed then + * this option can be disabled to save code memory space. If this option is + * disabled, then @ref UTF8_PACKED_STATIC_CONST_STRING_DESC should not be used. + * + * Default setting is '0' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_PWRSAVE_MODE + * @brief Configures the power-saving options supported by the device + * + * @details + * Default setting is @ref USB_PWRSAVE_MODE_ONSUSPEND and may be overridden by + * defining in 'usbconfig.h'. + * + * SLAB_USB_PWRSAVE_MODE configures when the device will automatically enter + * the USB power-save mode. It is a bitmask constant with bit values: + * + * @ref USB_PWRSAVE_MODE_OFF - No energy saving option selected + * @ref USB_PWRSAVE_MODE_ONSUSPEND - Enter USB power-save mode on USB suspend + * @ref USB_PWRSAVE_MODE_ONVBUSOFF - Enter USB power-save mode when not + * attached to the USB host. + * @ref USB_PWRSAVE_MODE_FASTWAKE - Exit USB power-save mode more quickly. + * This is useful for some applications that + * support remote wakeup. + *****************************************************************************/ + +/**************************************************************************//** + * @def SLAB_USB_POLLED_MODE + * @brief Enables/disables USB library polled mode + * @details + * When '1' the library will run in polled mode + * When '0' the library will run in interrupt mode + * + * Default setting is '0' and may be overridden by defining in 'usbconfig.h'. + * + *****************************************************************************/ + +/** @} (end addtogroup efm8_usb_config Library Configuration) */ + +// Set default USB library configurations if the value is not configured in +// usbconfig.h + +#ifndef SLAB_USB_BUS_POWERED +#define SLAB_USB_BUS_POWERED 1 +#endif + +#ifndef SLAB_USB_FULL_SPEED +#define SLAB_USB_FULL_SPEED 1 +#endif + +#ifndef SLAB_USB_CLOCK_RECOVERY_ENABLED +#define SLAB_USB_CLOCK_RECOVERY_ENABLED 1 +#endif + +#ifndef SLAB_USB_REMOTE_WAKEUP_ENABLED +#define SLAB_USB_REMOTE_WAKEUP_ENABLED 0 +#endif + +#ifndef SLAB_USB_NUM_INTERFACES +#define SLAB_USB_NUM_INTERFACES 1 +#endif + +#ifndef SLAB_USB_SUPPORT_ALT_INTERFACES +#define SLAB_USB_SUPPORT_ALT_INTERFACES 0 +#endif + +#ifndef SLAB_USB_EP1IN_USED +#define SLAB_USB_EP1IN_USED 0 +#endif + +#ifndef SLAB_USB_EP1OUT_USED +#define SLAB_USB_EP1OUT_USED 0 +#endif + +#ifndef SLAB_USB_EP2IN_USED +#define SLAB_USB_EP2IN_USED 0 +#endif + +#ifndef SLAB_USB_EP2OUT_USED +#define SLAB_USB_EP2OUT_USED 0 +#endif + +#ifndef SLAB_USB_EP3IN_USED +#define SLAB_USB_EP3IN_USED 0 +#endif + +#ifndef SLAB_USB_EP3OUT_USED +#define SLAB_USB_EP3OUT_USED 0 +#endif + +#ifndef SLAB_USB_EP1IN_MAX_PACKET_SIZE +#define SLAB_USB_EP1IN_MAX_PACKET_SIZE 64 +#endif + +#ifndef SLAB_USB_EP1OUT_MAX_PACKET_SIZE +#define SLAB_USB_EP1OUT_MAX_PACKET_SIZE 64 +#endif + +#ifndef SLAB_USB_EP2IN_MAX_PACKET_SIZE +#define SLAB_USB_EP2IN_MAX_PACKET_SIZE 64 +#endif + +#ifndef SLAB_USB_EP2OUT_MAX_PACKET_SIZE +#define SLAB_USB_EP2OUT_MAX_PACKET_SIZE 64 +#endif + +#ifndef SLAB_USB_EP3IN_MAX_PACKET_SIZE +#define SLAB_USB_EP3IN_MAX_PACKET_SIZE 64 +#endif + +#ifndef SLAB_USB_EP3OUT_MAX_PACKET_SIZE +#define SLAB_USB_EP3OUT_MAX_PACKET_SIZE 64 +#endif + +#ifndef SLAB_USB_EP1IN_TRANSFER_TYPE +#define SLAB_USB_EP1IN_TRANSFER_TYPE USB_EPTYPE_INTR +#endif + +#ifndef SLAB_USB_EP1OUT_TRANSFER_TYPE +#define SLAB_USB_EP1OUT_TRANSFER_TYPE USB_EPTYPE_INTR +#endif + +#ifndef SLAB_USB_EP2IN_TRANSFER_TYPE +#define SLAB_USB_EP2IN_TRANSFER_TYPE USB_EPTYPE_INTR +#endif + +#ifndef SLAB_USB_EP2OUT_TRANSFER_TYPE +#define SLAB_USB_EP2OUT_TRANSFER_TYPE USB_EPTYPE_INTR +#endif + +#ifndef SLAB_USB_EP3IN_TRANSFER_TYPE +#define SLAB_USB_EP3IN_TRANSFER_TYPE USB_EPTYPE_INTR +#endif + +#ifndef SLAB_USB_EP3OUT_TRANSFER_TYPE +#define SLAB_USB_EP3OUT_TRANSFER_TYPE USB_EPTYPE_INTR +#endif + +#ifndef SLAB_USB_RESET_CB +#define SLAB_USB_RESET_CB 0 +#endif + +#ifndef SLAB_USB_SOF_CB +#define SLAB_USB_SOF_CB 0 +#endif + +#ifndef SLAB_USB_STATE_CHANGE_CB +#define SLAB_USB_STATE_CHANGE_CB 0 +#endif + +#ifndef SLAB_USB_IS_SELF_POWERED_CB +#define SLAB_USB_IS_SELF_POWERED_CB 0 +#endif + +#ifndef SLAB_USB_SETUP_CMD_CB +#define SLAB_USB_SETUP_CMD_CB 0 +#endif + +#ifndef SLAB_USB_HANDLER_CB +#define SLAB_USB_HANDLER_CB 0 +#endif + +#ifndef SLAB_USB_NUM_LANGUAGES +#define SLAB_USB_NUM_LANGUAGES 1 +#endif + +#ifndef SLAB_USB_LANGUAGE +#define SLAB_USB_LANGUAGE USB_LANGID_ENUS +#endif + +#ifndef SLAB_USB_UTF8_STRINGS +#define SLAB_USB_UTF8_STRINGS 0 +#endif + +#ifndef SLAB_USB_PWRSAVE_MODE +#define SLAB_USB_PWRSAVE_MODE USB_PWRSAVE_MODE_ONSUSPEND +#endif + +#ifndef SLAB_USB_POLLED_MODE +#define SLAB_USB_POLLED_MODE 0 +#endif + +#if SLAB_USB_POLLED_MODE +void usbIrqHandler(void); +#endif + +/***************************************************************************//** + * @addtogroup efm8_api API Functions + * @{ + ******************************************************************************/ + +/***************************************************************************//** + * @brief + * Abort all pending transfers. + * + * @details + * Aborts transfers for all endpoints currently in use. Pending + * transfers on the default endpoint (EP0) are not aborted. + ******************************************************************************/ +void USBD_AbortAllTransfers(void); + +/***************************************************************************//** + * @brief + * Abort a pending transfer on a specific endpoint. + * + * @param epAddr + * The address of the endpoint to abort. + * @return + * @ref USB_STATUS_OK is the transfer aborted, @ref USB_STATUS_ILLEGAL + * otherwise + ******************************************************************************/ +int8_t USBD_AbortTransfer(uint8_t epAddr); + +/***************************************************************************//** + * @brief + * Start USB device operation. + * + * @details + * Device operation is started by connecting a pull-up resistor on the + * appropriate USB data line. + ******************************************************************************/ +void USBD_Connect(void); + +/***************************************************************************//** + * @brief + * Stop USB device operation. + * + * @details + * Device operation is stopped by disconnecting the pull-up resistor from the + * appropriate USB data line. Often referred to as a "soft" disconnect. + ******************************************************************************/ +void USBD_Disconnect(void); + +/***************************************************************************//** + * @brief + * Check if an endpoint is busy doing a transfer. + * + * @param epAddr + * The address of the endpoint to check. + * + * @return + * True if endpoint is busy, false otherwise. + ******************************************************************************/ +bool USBD_EpIsBusy(uint8_t epAddr); + +/***************************************************************************//** + * @brief + * Get current USB device state. + * + * @return + * Device USB state. See @ref USBD_State_TypeDef. + ******************************************************************************/ +USBD_State_TypeDef USBD_GetUsbState(void); + +/***************************************************************************//** + * @brief + * Initializes USB device hardware and internal protocol stack data structures, + * then connects the data-line (D+ or D-) pullup resistor to signal host that + * enumeration can begin. + * + * @note + * You may later use @ref USBD_Disconnect() and @ref USBD_Connect() to force + * reenumeration. + * + * @param p + * Pointer to device initialization struct. See @ref USBD_Init_TypeDef. + * + * @return + * @ref USB_STATUS_OK on success, else an appropriate error code. + ******************************************************************************/ +int8_t USBD_Init(SI_VARIABLE_SEGMENT_POINTER(p, const USBD_Init_TypeDef, SI_SEG_GENERIC)); + +/***************************************************************************//** + * @brief + * Start a read (OUT) transfer on an endpoint. + * + * @note + * If it is possible that the host will send more data than your device + * expects, round buffer size up to the next multiple of maxpacket size. + * + * @param epAddr + * Endpoint address. + * + * @param dat + * Pointer to transfer data buffer. + * + * @param byteCount + * Transfer length. + * + * @param callback + * Boolean to determine if USB_XferCompleteCb should be called for this + * transfer. + * + * @return + * @ref USB_STATUS_OK on success, else an appropriate error code. + ******************************************************************************/ +int8_t USBD_Read(uint8_t epAddr, + SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), + uint16_t byteCount, + bool callback); + +/***************************************************************************//** + * @brief + * Perform a remote wakeup signaling sequence. + * + * @note + * This function is typically called by the library if @ref + * USBD_RemoteWakeupCb() returns true, so it does not need to be called by + * application code. + * + * @return + * @ref USB_STATUS_OK on success, else an appropriate error code. + ******************************************************************************/ +int8_t USBD_RemoteWakeup(void); + +/***************************************************************************//** + * @brief + * Processes USB events when the library is configured for polled mode + * + * @details + * The USB library can be configured for interrupt (SLAB_USB_POLLED_MODE == 0) + * or polled (SLAB_USB_POLLED_MODE == 1) mode. + * + * When in interrupt mode, the USB interrupt handler will trigger + * when a USB event occurs. Callback functions will be called as needed. + * + * When in polled mode, the application must call USBD_Run() periodically to + * check for and process USB events. This may be useful in complex systems or + * when using an RTOS to perform all USB processing in the main loop instead + * of in the interrupt context. + * + ******************************************************************************/ +void USBD_Run(void); + +/***************************************************************************//** + * @brief + * Set an endpoint in the stalled (halted) state. + * + * @param epAddr + * The address of the endpoint to stall. + * + * @return + * @ref USB_STATUS_OK on success, else an appropriate error code. + ******************************************************************************/ +int8_t USBD_StallEp(uint8_t epAddr); + +/***************************************************************************//** + * @brief + * Stop USB device stack operation. + * + * @details + * The data-line pullup resistor is turned off, USB interrupts are disabled, + * and finally the USB pins are disabled. + ******************************************************************************/ +void USBD_Stop(void); + +/***************************************************************************//** + * @brief + * Enters USB suspend mode + * + * @details + * Disables USB transceiver, VDD Monitor, and prefetch engine. Suspends the + * internal regulator and internal oscillator. + * This function will not exit until the device recognizes resume signaling, + * VBUS attachment/removal, or a remote wakeup source interrupt. + * Before exiting, restores the states of the USB transceiver, + * VDD Monitor, prefetch engine, and internal regulator. + ******************************************************************************/ +void USBD_Suspend(void); + +/***************************************************************************//** + * @brief + * Reset stall state on a stalled (halted) endpoint. + * + * @param epAddr + * The address of the endpoint to un-stall. + * + * @return + * @ref USB_STATUS_OK on success, else an appropriate error code. + ******************************************************************************/ +int8_t USBD_UnStallEp(uint8_t epAddr); + +/***************************************************************************//** + * @brief + * Start a write (IN) transfer on an endpoint. + * + * @param epAddr + * Endpoint address. + * + * @param dat + * Pointer to transfer data buffer. This buffer must be WORD (4 byte) aligned. + * + * @param byteCount + * Transfer length. + * + * @param callback + * Boolean to determine if USB_XferCompleteCb should be called for this + * transfer. + * + * @return + * @ref USB_STATUS_OK on success, else an appropriate error code. + ******************************************************************************/ +int8_t USBD_Write(uint8_t epAddr, + SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), + uint16_t byteCount, + bool callback); + +/** @} (end addtogroup efm8_api API Functions) */ + +/***************************************************************************//** + * @addtogroup efm8_callbacks Callback Functions + * @{ + ******************************************************************************/ + +/***************************************************************************//** + * @brief + * USB Handler Entry callback function. + * @details + * Some systems may wish to be in a low-power state when between USB events. + * This low-power state may configure the system clock to a very low + * frequency. In order to reduce the execution time of the USB handler, this + * function is called before the handler executes to allow the system to switch + * to a higher clock source. When all USB processing is complete, + * @ref USBD_ExitHandler() will be called to allow the system to return + * to the low-power state. + * This callback function is optionally enabled by setting + * @ref SLAB_USB_HANDLER_CB to 1. + ******************************************************************************/ +void USBD_EnterHandler(void); + +/***************************************************************************//** + * @brief + * USB Handler Exit callback function. + * @details + * Some systems may wish to be in a low-power state when between USB events. + * This low-power state may configure the system clock to a very low + * frequency. This function is called after all USB processing is finished + * to allow a system that was previously configured by + * @ref USBD_EnterHandler() for high power to return to a low power state. + * This callback function is optionally enabled by setting + * @ref SLAB_USB_HANDLER_CB to 1. + ******************************************************************************/ +void USBD_ExitHandler(void); + +/***************************************************************************//** + * @brief + * USB Reset callback function. + * @details + * Called whenever USB reset signaling is detected on the USB port. + ******************************************************************************/ +void USBD_ResetCb(void); + +/***************************************************************************//** + * @brief + * USB Start Of Frame (SOF) interrupt callback function. + * + * @details + * Called at each SOF interrupt (if enabled), + * + * @param sofNr + * Current frame number. The value rolls over to 0 after 16383 (0x3FFF). + ******************************************************************************/ +void USBD_SofCb(uint16_t sofNr); + +/***************************************************************************//** + * @brief + * USB State change callback function. + * + * @details + * Called whenever the USB state of the device changes + * + * @param oldState + * The device USB state just left. See @ref USBD_State_TypeDef. + * + * @param newState + * New (the current) USB device state. See @ref USBD_State_TypeDef. + ******************************************************************************/ +void USBD_DeviceStateChangeCb(USBD_State_TypeDef oldState, + USBD_State_TypeDef newState); + +/***************************************************************************//** + * @brief + * USB power mode callback function. + * + * @details + * Called whenever the device stack needs to know if the device is currently + * self- or bus-powered. Typically when host has issued a @ref GET_STATUS + * setup command. + * + * @return + * True if self-powered, false otherwise. + ******************************************************************************/ +bool USBD_IsSelfPoweredCb(void); + +/***************************************************************************//** + * @brief + * USB setup request callback function. + * + * @details + * Called on each setup request received from host. This gives the system a + * possibility to extend or override standard requests, and to implement class + * or vendor specific requests. Return @ref USB_STATUS_OK if the request is + * handled, return @ref USB_STATUS_REQ_ERR if it is an illegal request or + * return @ref USB_STATUS_REQ_UNHANDLED to pass the request on to the default + * request handler. + * + * @param setup + * Pointer to a USB setup packet. See @ref USB_Setup_TypeDef. + * + * @return + * An appropriate status/error code. See @ref USB_Status_TypeDef. + ******************************************************************************/ +USB_Status_TypeDef USBD_SetupCmdCb(SI_VARIABLE_SEGMENT_POINTER(setup, + USB_Setup_TypeDef, + MEM_MODEL_SEG)); + +/***************************************************************************//** + * @brief + * USB set interface callback function. + * + * @details + * Called each time the SET_INTERFACE request is made. + * + * @param interface + * Number of the interface to set. + * + * @param altSetting + * Alternate setting for the interface + * + * @return + * @ref USB_STATUS_OK if the alternate interface is valid and can be set, + * @ref USB_STATUS_REQ_ERR otherwise + ******************************************************************************/ +USB_Status_TypeDef USBD_SetInterfaceCb(uint8_t interface, uint8_t altSetting); + +/***************************************************************************//** + * @brief + * Queries the application to see if a remote wakeup occurred. + * @details + * If remote wakeup is enabled via @ref SLAB_USB_REMOTE_WAKEUP_ENABLED, the + * USB library will query the application after waking from suspend to see if + * the remote wakeup source was the reason for the wakeup. If this function + * returns True, the library will call @ref USBD_RemoteWakeup() to wake up the + * host and exit suspend mode. + * @return + * True if the remote wakeup source was the reason the device woke from + * suspend, false otherwise. + * + ******************************************************************************/ +bool USBD_RemoteWakeupCb(void); + +/***************************************************************************//** + * @brief + * Delays 10 - 15 ms while resume signaling is active during a remote + * wakeup event + * + ******************************************************************************/ +void USBD_RemoteWakeupDelay(void); + +/***************************************************************************//** + * @brief + * Processes USB events when the library is configured for polled mode + * + * @ details + * The USB library can be configured for interrupt + * (@ref SLAB_USB_POLLED_MODE == 0) or polled (@ref SLAB_USB_POLLED_MODE == 1) + * mode. + * + * When in interrupt mode, the USB interrupt handler will trigger + * when a USB event occurs. Callback functions will be called as needed. + * + * When in polled mode, the application must call USBD_Run() periodically to + * check for and process USB events. This may be useful in complex systems or + * when using an RTOS to perform all USB processing in the main loop instead + * of in the interrupt context. + * + ******************************************************************************/ +void USBD_Run(void); + +/***************************************************************************//** + * @brief + * USB transfer complete callback function. + * + * @details + * Called each time a packet is sent on an IN endpoint or received on an + * OUT endpoint. + * + * @param epAddr + * Endpoint on which the transfer occurred + * + * @param status + * Status of the endpoint + * + * @param xferred + * For bulk, interrupt, and control transfers: + * Number of bytes transferred since the last USBD_Write() or USBD_Read() + * call. + * For isochronous IN transfers: + * This parameter is not used + * For isochronous OUT transfers: + * the number of bytes received in the last packet + * + * @param remaining + * For bulk, interrupt, and control transfers: + * Number of bytes left to send or receive on the endpoint + * For isochronous transfers: + * The current index into the circular buffer holding isochronous data + * + * @return + * For bulk, interrupt, and control transfers: + * '0' + * For isochronous IN transfers: + * the number of bytes to transmit in the next packet + * For isochronous OUT ransfers: + * '0' + ******************************************************************************/ +uint16_t USBD_XferCompleteCb(uint8_t epAddr, \ + USB_Status_TypeDef status, \ + uint16_t xferred, \ + uint16_t remaining); + +/** @} (end addtogroup efm8_callbacks Callback Functions) */ + +/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN +// -------------------- FIFO Access Functions --------------------------------- +void USB_ReadFIFO(uint8_t fifoNum, uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC)); +void USB_WriteFIFO(uint8_t fifoNum, uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), bool txPacket); +/// @endcond DO_NOT_INCLUDE_WITH_DOXYGEN + +// -------------------- Include Files ------------------------------------------ + + // Error if peripheral driver not in use + #include "usb_0.h" + +/** @} (end addtogroup Efm8_usb) */ + +#endif // __SILICON_LABS_EFM8_USB_H__ diff --git a/efm8/lib/c8051f380/efm8_usb/src/efm8_usbd.c b/efm8/lib/c8051f380/efm8_usb/src/efm8_usbd.c new file mode 100644 index 0000000..34f94e4 --- /dev/null +++ b/efm8/lib/c8051f380/efm8_usb/src/efm8_usbd.c @@ -0,0 +1,780 @@ +/**************************************************************************//** + * Copyright (c) 2015 by Silicon Laboratories Inc. All rights reserved. + * + * http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt + *****************************************************************************/ + +#include "si_toolchain.h" +#include "efm8_usb.h" +#include "assert.h" +#include + +// ----------------------------------------------------------------------------- +// Global Variables + +/// Tracks the state of the USB device and endpoints and contains pointers +/// to all descriptors. +SI_SEGMENT_VARIABLE(myUsbDevice, USBD_Device_TypeDef, MEM_MODEL_SEG); + +// ----------------------------------------------------------------------------- +// Macros + +/// Returns the requested endpoint object of type USBD_Ep_TypeDef +/// This macro does not check that epAddr is valid, so the calling function +/// should verify epAddr before using the macro. +#define GetEp(epAddr) (&myUsbDevice.ep0 + epAddr) + + +#if SLAB_USB_POLLED_MODE +#define DISABLE_USB_INTS {} +#define ENABLE_USB_INTS {} + +#else +/// Saves the current state of the USB Interrupt Enable to a variable called +/// usbIntsEnabled, then disables USB interrupts. +#define DISABLE_USB_INTS { usbIntsEnabled = USB_GetIntsEnabled(); USB_DisableInts(); } + +/// Sets the USB Interrupt Enable bit to the value of usbIntsEnabled. +/// @ref DISABLE_USB_INTS must be used before this macro is used. +#define ENABLE_USB_INTS { if (usbIntsEnabled) {USB_EnableInts(); } } +#endif // SLAB_USB_POLLED_MODE + +// Function in efm8_usbdint.c to force load the module for libraries +extern void forceModuleLoad_usbint(void); + +// ----------------------------------------------------------------------------- +// USB API Functions + +void USBD_AbortAllTransfers(void) +{ + uint8_t i; + bool usbIntsEnabled; + + USB_SaveSfrPage(); + DISABLE_USB_INTS; + + // Call USBD_AbortTransfer() for each endpoint + for (i = 1; i < SLAB_USB_NUM_EPS_USED; i++) + { + USBD_AbortTransfer(i); + } + + ENABLE_USB_INTS; + USB_RestoreSfrPage(); +} + +int8_t USBD_AbortTransfer(uint8_t epAddr) +{ + SI_VARIABLE_SEGMENT_POINTER(ep, USBD_Ep_TypeDef, MEM_MODEL_SEG); + int8_t retVal = USB_STATUS_OK; + bool usbIntsEnabled; + + USB_SaveSfrPage(); + + // Verify this is a valid endpoint address and is not Endpoint 0. + if ((epAddr == EP0) || (epAddr >= SLAB_USB_NUM_EPS_USED)) + { + SLAB_ASSERT(false); + retVal = USB_STATUS_ILLEGAL; + } + else + { + DISABLE_USB_INTS; + ep = GetEp(epAddr); + + // If the state of the endpoint is already idle, there is not need to abort + // a transfer + if (ep->state != D_EP_IDLE) + { + switch (epAddr) + { + #if SLAB_USB_EP1IN_USED + case EP1IN: + USB_AbortInEp(1); + break; + #endif + #if SLAB_USB_EP2IN_USED + case EP2IN: + USB_AbortInEp(2); + break; + #endif + #if SLAB_USB_EP3IN_USED + case EP3IN: + USB_AbortInEp(3); + break; + #endif + #if SLAB_USB_EP1OUT_USED + case EP1OUT: + USB_AbortOutEp(1); + break; + #endif + #if SLAB_USB_EP2OUT_USED + case EP2OUT: + USB_AbortOutEp(2); + break; + #endif + #if SLAB_USB_EP3OUT_USED + case EP3OUT: + USB_AbortOutEp(3); + break; + #endif + } + + // Set the endpoint state to idle and clear out endpoint state variables + ep->state = D_EP_IDLE; + ep->misc.c = 0; + } + } + + ENABLE_USB_INTS; + USB_RestoreSfrPage(); + + return retVal; +} + +void USBD_Connect(void) +{ + USB_SaveSfrPage(); + myUsbDevice.ep0.state = D_EP_IDLE; + USB_EnablePullUpResistor(); + USB_EnableTransceiver(); + USB_RestoreSfrPage(); +} + +void USBD_Disconnect(void) +{ + USB_SaveSfrPage(); + USB_DisablePullUpResistor(); + USB_RestoreSfrPage(); +} + +bool USBD_EpIsBusy(uint8_t epAddr) +{ + SI_VARIABLE_SEGMENT_POINTER(ep, USBD_Ep_TypeDef, MEM_MODEL_SEG); + + // Verify this is a valid endpoint address + if (epAddr >= SLAB_USB_NUM_EPS_USED) + { + SLAB_ASSERT(false); + return true; + } + + ep = GetEp(epAddr); + + if (ep->state == D_EP_IDLE) + { + return false; + } + + return true; +} + +USBD_State_TypeDef USBD_GetUsbState(void) +{ + return myUsbDevice.state; +} + +int8_t USBD_Init(SI_VARIABLE_SEGMENT_POINTER(p, const USBD_Init_TypeDef, SI_SEG_GENERIC)) +{ + uint8_t i; + + USB_SaveSfrPage(); + USB_DisableInts(); + + // This forces the liner to bring in the contents efm8_usbdint + // It is place here since all users MUST call this function + // for the library to work properly + forceModuleLoad_usbint(); + + + // Zero out the myUsbDevice struct, then initialize all non-zero members + for (i = 0; i < sizeof(myUsbDevice); i++) + { + *((SI_VARIABLE_SEGMENT_POINTER(, uint8_t, MEM_MODEL_SEG))&myUsbDevice + i) = 0; + } + + // Get the USB descriptors from p + myUsbDevice.deviceDescriptor = p->deviceDescriptor; + myUsbDevice.configDescriptor = p->configDescriptor; + myUsbDevice.stringDescriptors = p->stringDescriptors; + myUsbDevice.numberOfStrings = p->numberOfStrings; + + // Enable USB clock +#if SLAB_USB_FULL_SPEED + USB_SetClockIntOsc(); + USB_SelectFullSpeed(); +#else + USB_SetClockIntOscDiv8(); + USB_SelectLowSpeed(); +#endif // SLAB_USB_FULL_SPEED + + // Enable or disable VBUS detection +#if SLAB_USB_BUS_POWERED + USB_VbusDetectDisable(); +#else + USB_VbusDetectEnable(); +#endif + + USB_ForceReset(); + USB_EnableDeviceInts(); + USBD_Connect(); + + // If VBUS is present, the state should be Default. + // Otherwise, it is Attached. +#if SLAB_USB_BUS_POWERED + myUsbDevice.state = USBD_STATE_DEFAULT; +#else + if (USB_IsVbusOn()) + { + myUsbDevice.state = USBD_STATE_DEFAULT; + } + else + { + myUsbDevice.state = USBD_STATE_ATTACHED; + } +#endif + + // Only enable USB interrupts when not in polled mode +#if (SLAB_USB_POLLED_MODE == 0) + USB_EnableInts(); +#endif + + USB_RestoreSfrPage(); + USB_DisableInhibit(); + + return USB_STATUS_OK; +} + +int8_t USBD_Read(uint8_t epAddr, + SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), + uint16_t byteCount, + bool callback) +{ + bool usbIntsEnabled; + SI_VARIABLE_SEGMENT_POINTER(ep, USBD_Ep_TypeDef, MEM_MODEL_SEG); + + USB_SaveSfrPage(); + + // Verify the endpoint address is valid. + switch (epAddr) + { + case EP0: +#if SLAB_USB_EP1OUT_USED + case EP1OUT: +#endif +#if SLAB_USB_EP2OUT_USED + case EP2OUT: +#endif +#if SLAB_USB_EP3OUT_USED + case EP3OUT: +#endif + break; +#if SLAB_USB_EP1IN_USED + case EP1IN: +#endif +#if SLAB_USB_EP2IN_USED + case EP2IN: +#endif +#if SLAB_USB_EP3IN_USED + case EP3IN: +#endif + default: + SLAB_ASSERT(false); + return USB_STATUS_ILLEGAL; + } + + // If the device has not been configured, we cannot start a transfer. + if ((epAddr != EP0) && (myUsbDevice.state != USBD_STATE_CONFIGURED)) + { + return USB_STATUS_DEVICE_UNCONFIGURED; + } + + ep = GetEp(epAddr); + + // If the endpoint is not idle, we cannot start a new transfer. + // Return the appropriate error code. + if (ep->state != D_EP_IDLE) + { + if (ep->state == D_EP_STALL) + { + return USB_STATUS_EP_STALLED; + } + else + { + return USB_STATUS_EP_BUSY; + } + } + + DISABLE_USB_INTS; + + ep->buf = dat; + ep->remaining = byteCount; + ep->state = D_EP_RECEIVING; + ep->misc.bits.callback = callback; + ep->misc.bits.waitForRead = false; + + // If isochronous, set the buffer index to 0 +#if ((SLAB_USB_EP3OUT_USED) && (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC)) + if (epAddr == EP3OUT) + { + myUsbDevice.ep3outIsoIdx = 0; + } +#endif + + ENABLE_USB_INTS; + USB_RestoreSfrPage(); + + return USB_STATUS_OK; +} + +#if SLAB_USB_REMOTE_WAKEUP_ENABLED +int8_t USBD_RemoteWakeup(void) +{ + // The device must be suspended and Remote Wakeup must have been previously + // configured with a SET_FEATURE (Remote Wakeup) command. + if ((myUsbDevice.state != USBD_STATE_SUSPENDED) || + (myUsbDevice.remoteWakeupEnabled == false)) + { + return USB_STATUS_ILLEGAL; + } + + USB_ForceResume(); + USBD_RemoteWakeupDelay(); // Application will provide the delay between + // starting and stopping the resume signal. + USB_ClearResume(); + + return USB_STATUS_OK; +} +#endif // SLAB_USB_REMOTE_WAKEUP_ENABLED + +#if SLAB_USB_POLLED_MODE +void USBD_Run(void) +{ + usbIrqHandler(); +} +#endif // SLAB_USB_POLLED_MODE + +int8_t USBD_StallEp(uint8_t epAddr) +{ + bool usbIntsEnabled; + + USB_SaveSfrPage(); + + // Verify the endpoint address is valid and not Endpoint 0. + if ((epAddr == EP0) || (epAddr >= SLAB_USB_NUM_EPS_USED)) + { + SLAB_ASSERT(false); + return USB_STATUS_ILLEGAL; + } + + DISABLE_USB_INTS; + + // Halt the appropriate endpoint by sending a stall and setting the endpoint + // state to Halted (D_EP_HALT). + switch (epAddr) + { +#if SLAB_USB_EP1IN_USED + case (EP1IN): + myUsbDevice.ep1in.state = D_EP_HALT; + USB_SetIndex(1); + USB_EpnInStall(); + break; +#endif +#if SLAB_USB_EP2IN_USED + case (EP2IN): + myUsbDevice.ep2in.state = D_EP_HALT; + USB_SetIndex(2); + USB_EpnInStall(); + break; +#endif +#if SLAB_USB_EP3IN_USED + case (EP3IN): + myUsbDevice.ep3in.state = D_EP_HALT; + USB_SetIndex(3); + USB_EpnInStall(); + break; +#endif +#if SLAB_USB_EP1OUT_USED + case (EP1OUT): + myUsbDevice.ep1out.state = D_EP_HALT; + USB_SetIndex(1); + USB_EpnOutStall(); + break; +#endif +#if SLAB_USB_EP2OUT_USED + case (EP2OUT): + myUsbDevice.ep2out.state = D_EP_HALT; + USB_SetIndex(2); + USB_EpnOutStall(); + break; +#endif +#if SLAB_USB_EP3OUT_USED + case (EP3OUT): + myUsbDevice.ep3out.state = D_EP_HALT; + USB_SetIndex(3); + USB_EpnOutStall(); + break; +#endif + } + + ENABLE_USB_INTS; + USB_RestoreSfrPage(); + + return USB_STATUS_OK; +} + +void USBD_Stop(void) +{ + USB_DisableInts(); + USBD_Disconnect(); + USBD_SetUsbState(USBD_STATE_NONE); +} + +void USBD_Suspend(void) +{ +#if (!(SLAB_USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_FASTWAKE)) + uint8_t i; +#endif + bool regulatorEnabled, prefetchEnabled; +#if SLAB_USB_REMOTE_WAKEUP_ENABLED + bool remoteWakeup = false; +#endif + + USB_SaveSfrPage(); + + // If the USB_PWRSAVE_MODE_ONVBUSOFF is enabled, we can enter suspend if VBUS + // is not present even if the USB has not detected a suspend event. +#if ((!(SLAB_USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF)) || \ + (SLAB_USB_BUS_POWERED)) + if (USB_IsSuspended() == true) +#else + if ((USB_IsSuspended() == true) || (USB_IsVbusOn() == false)) +#endif + { + USB_SuspendTransceiver(); + +#if SLAB_USB_FULL_SPEED + USB_SetSuspendClock(); +#endif + + // Get the state of the prefetch engine enable bit and disable the prefetch + // engine + prefetchEnabled = USB_IsPrefetchEnabled(); + USB_DisablePrefetch(); + + // Get the state of the internal regulator before suspending it. + if (USB_IsRegulatorEnabled() == true) + { + regulatorEnabled = true; + +#if (SLAB_USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_FASTWAKE) + USB_SuspendRegulatorFastWake(); +#else + USB_SuspendRegulator(); + + // Wait at least 12 clock instructions before halting the internal oscillator + for (i = 0; i < 3; i++) + { + } +#endif + } + else + { + regulatorEnabled = false; + } + + do + { + USB_SuspendOscillator(); + + // When we arrive here, the device has waked from suspend mode. + +#if SLAB_USB_REMOTE_WAKEUP_ENABLED + // If remote wakeup is enabled, query the application if the remote + // wakeup event occurred. If so, exit USBD_Suspend(). + if (USB_IsSuspended() == true) + { + remoteWakeup = USBD_RemoteWakeupCb(); + if (remoteWakeup == true) + { + break; + } + } +#endif +#if ((!(SLAB_USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF)) && \ + (SLAB_USB_BUS_POWERED == 0)) + // If the USB_PWRSAVE_MODE_ONVBUSOFF mode is disabled, VBUS has been + // removed, so exit USBD_Suspend(). + if (USB_IsVbusOn() == false) + { + break; + } +#endif + +#if ((!(SLAB_USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF)) || \ + (SLAB_USB_BUS_POWERED)) + } while (USB_IsSuspended() == true); +#else + } while ((USB_IsSuspended() == true) || (USB_IsVbusOn() == false)); +#endif + // Restore the internal regulator + if (regulatorEnabled == true) + { + USB_UnsuspendRegulator(); + } + + // Restore the prefetch engine + if (prefetchEnabled == true) + { + USB_EnablePrefetch(); + } + +#if SLAB_USB_FULL_SPEED + // Restore the clock + USB_SetNormalClock(); +#endif + USB_EnableTransceiver(); + +#if SLAB_USB_REMOTE_WAKEUP_ENABLED + // If the device woke from suspend due to a remote wakeup source, call + // USBD_RemoteWakeup() here to wake up the host. + if (remoteWakeup == true) + { + // Wake up the host + if (USBD_RemoteWakeup() == USB_STATUS_OK) + { + // If the remote wakeup succeeded, transition out of USB suspend state + USBD_SetUsbState(myUsbDevice.savedState); + } + } +#endif + } + + USB_RestoreSfrPage(); +} + +int8_t USBD_UnStallEp(uint8_t epAddr) +{ + bool usbIntsEnabled; + + USB_SaveSfrPage(); + + // Verify the endpoint address is valid and not Endpoint 0. + if ((epAddr == EP0) || (epAddr >= SLAB_USB_NUM_EPS_USED)) + { + SLAB_ASSERT(false); + return USB_STATUS_ILLEGAL; + } + else + { + DISABLE_USB_INTS; + + // End the stall condition and set the endpoint state to idle. + switch (epAddr) + { +#if SLAB_USB_EP1IN_USED + case (EP1IN): + myUsbDevice.ep1in.state = D_EP_IDLE; + USB_SetIndex(1); + USB_EpnInEndStall(); + break; +#endif +#if SLAB_USB_EP2IN_USED + case (EP2IN): + myUsbDevice.ep2in.state = D_EP_IDLE; + USB_SetIndex(2); + USB_EpnInEndStall(); + break; +#endif +#if SLAB_USB_EP3IN_USED + case (EP3IN): + myUsbDevice.ep3in.state = D_EP_IDLE; + USB_SetIndex(3); + USB_EpnInEndStall(); + break; +#endif +#if SLAB_USB_EP1OUT_USED + case (EP1OUT): + myUsbDevice.ep1out.state = D_EP_IDLE; + USB_SetIndex(1); + USB_EpnOutEndStall(); + break; +#endif +#if SLAB_USB_EP2OUT_USED + case (EP2OUT): + myUsbDevice.ep2out.state = D_EP_IDLE; + USB_SetIndex(2); + USB_EpnOutEndStall(); + break; +#endif +#if SLAB_USB_EP3OUT_USED + case (EP3OUT): + myUsbDevice.ep3out.state = D_EP_IDLE; + USB_SetIndex(3); + USB_EpnOutEndStall(); + break; +#endif + } + + ENABLE_USB_INTS; + USB_RestoreSfrPage(); + } + + return USB_STATUS_OK; +} + +int8_t USBD_Write(uint8_t epAddr, + SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), + uint16_t byteCount, + bool callback) +{ + bool usbIntsEnabled; + SI_VARIABLE_SEGMENT_POINTER(ep, USBD_Ep_TypeDef, MEM_MODEL_SEG); + + USB_SaveSfrPage(); + + // Verify the endpoint address is valid. + switch (epAddr) + { + case EP0: +#if SLAB_USB_EP1IN_USED + case EP1IN: +#endif +#if SLAB_USB_EP2IN_USED + case EP2IN: +#endif +#if SLAB_USB_EP3IN_USED + case EP3IN: +#endif + break; +#if SLAB_USB_EP1OUT_USED + case EP1OUT: +#endif +#if SLAB_USB_EP2OUT_USED + case EP2OUT: +#endif +#if SLAB_USB_EP3OUT_USED + case EP3OUT: +#endif + default: + SLAB_ASSERT(false); + return USB_STATUS_ILLEGAL; + } + + // If the device is not configured and it is not Endpoint 0, we cannot begin + // a transfer. + if ((epAddr != EP0) && (myUsbDevice.state != USBD_STATE_CONFIGURED)) + { + return USB_STATUS_DEVICE_UNCONFIGURED; + } + + ep = GetEp(epAddr); + + // If the endpoint is not idle, we cannot start a new transfer. + // Return the appropriate error code. + if (ep->state != D_EP_IDLE) + { + if (ep->state == D_EP_STALL) + { + return USB_STATUS_EP_STALLED; + } + else + { + return USB_STATUS_EP_BUSY; + } + } + + DISABLE_USB_INTS; + + ep->buf = dat; + ep->remaining = byteCount; + ep->state = D_EP_TRANSMITTING; + ep->misc.bits.callback = callback; + + switch (epAddr) + { + // For Endpoint 0, set the inPacketPending flag to true. The USB handler + // will see this on the next SOF and begin the transfer. + case (EP0): + myUsbDevice.ep0.misc.bits.inPacketPending = true; + break; + + // For data endpoints, we will call USB_WriteFIFO here to reduce latency + // between the call to USBD_Write() and the first packet being sent. +#if SLAB_USB_EP1IN_USED + case (EP1IN): + USB_WriteFIFO(1, + (byteCount > SLAB_USB_EP1IN_MAX_PACKET_SIZE) ? SLAB_USB_EP1IN_MAX_PACKET_SIZE : byteCount, + myUsbDevice.ep1in.buf, + true); + break; +#endif // SLAB_USB_EP1IN_USED +#if SLAB_USB_EP2IN_USED + case (EP2IN): + USB_WriteFIFO(2, + (byteCount > SLAB_USB_EP2IN_MAX_PACKET_SIZE) ? SLAB_USB_EP2IN_MAX_PACKET_SIZE : byteCount, + myUsbDevice.ep2in.buf, + true); + break; +#endif // SLAB_USB_EP2IN_USED +#if SLAB_USB_EP3IN_USED + case (EP3IN): +#if ((SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_INTR)) + USB_WriteFIFO(3, + (byteCount > SLAB_USB_EP3IN_MAX_PACKET_SIZE) ? SLAB_USB_EP3IN_MAX_PACKET_SIZE : byteCount, + myUsbDevice.ep3in.buf, + true); +#elif (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC) + myUsbDevice.ep3in.misc.bits.inPacketPending = true; + myUsbDevice.ep3inIsoIdx = 0; +#endif + break; +#endif // SLAB_USB_EP3IN_USED + } + + ENABLE_USB_INTS; + USB_RestoreSfrPage(); + + return USB_STATUS_OK; +} + +// ----------------------------------------------------------------------------- +// UtilityFunctions + +void USBD_SetUsbState(USBD_State_TypeDef newState) +{ +#if (SLAB_USB_SUPPORT_ALT_INTERFACES) + uint8_t i; +#endif + USBD_State_TypeDef currentState; + + currentState = myUsbDevice.state; + + // If the device is un-configuring, disable the data endpoints and clear out + // alternate interface settings + if ((currentState >= USBD_STATE_SUSPENDED) + && (newState < USBD_STATE_SUSPENDED)) + { + USBD_AbortAllTransfers(); + +#if (SLAB_USB_SUPPORT_ALT_INTERFACES) + for (i = 0; i < SLAB_USB_NUM_INTERFACES; i++) + { + myUsbDevice.interfaceAltSetting[i] = 0; + } +#endif + } + if (newState == USBD_STATE_SUSPENDED) + { + myUsbDevice.savedState = currentState; + } + + myUsbDevice.state = newState; + +#if SLAB_USB_STATE_CHANGE_CB + if (currentState != newState) + { + USBD_DeviceStateChangeCb(currentState, newState); + } +#endif +} diff --git a/efm8/lib/c8051f380/efm8_usb/src/efm8_usbdch9.c b/efm8/lib/c8051f380/efm8_usb/src/efm8_usbdch9.c new file mode 100644 index 0000000..6bb2a47 --- /dev/null +++ b/efm8/lib/c8051f380/efm8_usb/src/efm8_usbdch9.c @@ -0,0 +1,870 @@ +/**************************************************************************//** + * Copyright (c) 2015 by Silicon Laboratories Inc. All rights reserved. + * + * http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt + *****************************************************************************/ + +#include "si_toolchain.h" +#include "efm8_usb.h" +#include +#include + +// ----------------------------------------------------------------------------- +// Function Prototypes + +static USB_Status_TypeDef ClearFeature(void); +static USB_Status_TypeDef GetConfiguration(void); +static USB_Status_TypeDef GetDescriptor(void); +static USB_Status_TypeDef GetInterface(void); +static USB_Status_TypeDef GetStatus(void); +static USB_Status_TypeDef SetAddress(void); +static USB_Status_TypeDef SetConfiguration(void); +static USB_Status_TypeDef SetFeature(void); +static USB_Status_TypeDef SetInterface(void); +static void USBD_ActivateAllEps(bool forceIdle); +static void EP0_Write(SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), uint16_t numBytes); + +// ----------------------------------------------------------------------------- +// Global Variables + +extern SI_SEGMENT_VARIABLE(myUsbDevice, USBD_Device_TypeDef, MEM_MODEL_SEG); +const SI_SEGMENT_VARIABLE(txZero[2], uint8_t, SI_SEG_CODE); + +// ----------------------------------------------------------------------------- +// Static Global Variables + +static uint16_t pStatus; + +// ----------------------------------------------------------------------------- +// Chapter 9 Functions + +/***************************************************************************//** + * @brief Processes Standard Request (Chapter 9 Command) + * @return Status of request (type @ref USB_Status_TypeDef) + * @note This function takes no parameters, but it uses the setup command + * stored in @ref myUsbDevice.setup. + ******************************************************************************/ +USB_Status_TypeDef USBDCH9_SetupCmd(void) +{ + USB_Status_TypeDef status = USB_STATUS_OK; + + switch (myUsbDevice.setup.bRequest) + { + case GET_STATUS: + status = GetStatus(); + break; + + case CLEAR_FEATURE: + status = ClearFeature(); + break; + + case SET_FEATURE: + status = SetFeature(); + break; + + case SET_ADDRESS: + status = SetAddress(); + break; + + case GET_DESCRIPTOR: + status = GetDescriptor(); + break; + + case GET_CONFIGURATION: + status = GetConfiguration(); + break; + + case SET_CONFIGURATION: + status = SetConfiguration(); + break; + + case GET_INTERFACE: + status = GetInterface(); + break; + + case SET_INTERFACE: + status = SetInterface(); + break; + + default: + status = USB_STATUS_REQ_ERR; + break; + } + + return status; +} + +/***************************************************************************//** + * @brief Clears the requested feature + * @details Supports CLEAR_FEATURE for Remote Wakeup and Endpoint Halt + * @return Status of request (type @ref USB_Status_TypeDef) + * @note This function takes no parameters, but it uses the setup command + * stored in @ref myUsbDevice.setup. + ******************************************************************************/ +static USB_Status_TypeDef ClearFeature(void) +{ + USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR; + + if (myUsbDevice.setup.wLength == 0) + { + switch (myUsbDevice.setup.bmRequestType.Recipient) + { + #if SLAB_USB_REMOTE_WAKEUP_ENABLED + case USB_SETUP_RECIPIENT_DEVICE: + if ((myUsbDevice.setup.wIndex == 0) + && (myUsbDevice.setup.wValue == USB_FEATURE_DEVICE_REMOTE_WAKEUP) + && (myUsbDevice.state >= USBD_STATE_ADDRESSED)) + { + // Remote wakeup feature clear + myUsbDevice.remoteWakeupEnabled = false; + retVal = USB_STATUS_OK; + } + break; + #endif // SLAB_USB_REMOTE_WAKEUP_ENABLED + case USB_SETUP_RECIPIENT_ENDPOINT: + if (myUsbDevice.setup.wValue == USB_FEATURE_ENDPOINT_HALT) + { + // Device does not support halting endpoint 0, but do not return + // an error as this is a valid request + if (((myUsbDevice.setup.wIndex & ~USB_EP_DIR_IN) == 0) + && (myUsbDevice.state >= USBD_STATE_ADDRESSED)) + { + retVal = USB_STATUS_OK; + } + else if (((myUsbDevice.setup.wIndex & ~USB_SETUP_DIR_D2H) < SLAB_USB_NUM_EPS_USED) + && (myUsbDevice.state == USBD_STATE_CONFIGURED)) + { + retVal = USB_STATUS_OK; + USB_SetIndex((myUsbDevice.setup.wIndex & 0xFF) & ~USB_SETUP_DIR_D2H); + +#if (SLAB_USB_EP1IN_USED || SLAB_USB_EP2IN_USED || SLAB_USB_EP3IN_USED) + if ((myUsbDevice.setup.wIndex & 0xFF) & USB_EP_DIR_IN) + { + USB_EpnInEndStallAndClearDataToggle(); + } +#endif +#if (SLAB_USB_EP1OUT_USED || SLAB_USB_EP2OUT_USED || SLAB_USB_EP3OUT_USED) + if (((myUsbDevice.setup.wIndex & 0xFF) & USB_EP_DIR_IN) == 0) + { + USB_EpnOutEndStallAndClearDataToggle(); + } +#endif + + switch (myUsbDevice.setup.wIndex & 0xFF) + { +#if SLAB_USB_EP1OUT_USED + case (USB_EP_DIR_OUT | 1): + if (myUsbDevice.ep1out.state != D_EP_RECEIVING) + { + myUsbDevice.ep1out.state = D_EP_IDLE; + } + break; +#endif +#if SLAB_USB_EP2OUT_USED + case (USB_EP_DIR_OUT | 2): + if (myUsbDevice.ep2out.state != D_EP_RECEIVING) + { + myUsbDevice.ep2out.state = D_EP_IDLE; + } + break; +#endif +#if SLAB_USB_EP3OUT_USED + case (USB_EP_DIR_OUT | 3): + if (myUsbDevice.ep3out.state != D_EP_RECEIVING) + { + myUsbDevice.ep3out.state = D_EP_IDLE; + } + break; +#endif +#if SLAB_USB_EP1IN_USED + case (USB_EP_DIR_IN | 1): + if (myUsbDevice.ep1in.state != D_EP_TRANSMITTING) + { + myUsbDevice.ep1in.state = D_EP_IDLE; + } + break; +#endif +#if SLAB_USB_EP2IN_USED + case (USB_EP_DIR_IN | 2): + if (myUsbDevice.ep2in.state != D_EP_TRANSMITTING) + { + myUsbDevice.ep2in.state = D_EP_IDLE; + } + break; +#endif +#if SLAB_USB_EP3IN_USED + case (USB_EP_DIR_IN | 3): + if (myUsbDevice.ep3in.state != D_EP_TRANSMITTING) + { + myUsbDevice.ep3in.state = D_EP_IDLE; + } + break; +#endif + } + } + } + } + } + return retVal; +} + +/***************************************************************************//** + * @brief Gets the current configuration value + * @details Zero means the device is not configured, a non-zero value + * is the configuration value of the configured device. + * @return Status of request (type @ref USB_Status_TypeDef) + * @note This function takes no parameters, but it uses the setup command + * stored in @ref myUsbDevice.setup. + ******************************************************************************/ +static USB_Status_TypeDef GetConfiguration(void) +{ + USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR; + + if ((myUsbDevice.setup.wIndex == 0) + && (myUsbDevice.setup.wValue == 0) + && (myUsbDevice.setup.wLength == 1) + && (myUsbDevice.setup.bmRequestType.Direction == USB_SETUP_DIR_IN) + && (myUsbDevice.setup.bmRequestType.Recipient == USB_SETUP_RECIPIENT_DEVICE)) + { + if (myUsbDevice.state == USBD_STATE_ADDRESSED) + { + EP0_Write((SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))txZero, 1); + retVal = USB_STATUS_OK; + } + else if (myUsbDevice.state == USBD_STATE_CONFIGURED) + { + EP0_Write(&myUsbDevice.configurationValue, 1); + retVal = USB_STATUS_OK; + } + } + return retVal; +} + +/***************************************************************************//** + * @brief Sends the requested USB Descriptor + * @details Supports single or multiple languages (configured by + * @ref SLAB_USB_NUM_LANGUAGES). + * @return Status of request (type @ref USB_Status_TypeDef) + * @note This function takes no parameters, but it uses the setup command + * stored in @ref myUsbDevice.setup. + ******************************************************************************/ +static USB_Status_TypeDef GetDescriptor(void) +{ +#if (SLAB_USB_NUM_LANGUAGES > 1) + bool langSupported; + uint8_t lang; +#endif + + uint8_t index; + uint16_t length = 0; + SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC); + USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR; + + if (*((uint8_t *)&myUsbDevice.setup.bmRequestType) == + (USB_SETUP_DIR_D2H | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_DEVICE)) + { + index = myUsbDevice.setup.wValue & 0xFF; + + switch (myUsbDevice.setup.wValue >> 8) + { + case USB_DEVICE_DESCRIPTOR: + if (index != 0) + { + break; + } + dat = (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))myUsbDevice.deviceDescriptor; + length = myUsbDevice.deviceDescriptor->bLength; + break; + + case USB_CONFIG_DESCRIPTOR: + if (index != 0) + { + break; + } + dat = (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))myUsbDevice.configDescriptor; + length = le16toh(myUsbDevice.configDescriptor->wTotalLength); + break; + + case USB_STRING_DESCRIPTOR: + #if (SLAB_USB_NUM_LANGUAGES == 1) + + dat = (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))myUsbDevice.stringDescriptors[index]; + + // Index 0 is the language string. If SLAB_USB_NUM_LANGUAGES == 1, we + // know the length will be 4 and the format will be UTF16LE. + if (index == 0) + { + length = 4; + myUsbDevice.ep0String.encoding.type = USB_STRING_DESCRIPTOR_UTF16LE; + } + // Otherwise, verify the language is correct (either the value set as + // SLAB_USB_LANGUAGE in usbconfig.h, or 0). + else if ((myUsbDevice.setup.wIndex == 0) || (myUsbDevice.setup.wIndex == SLAB_USB_LANGUAGE)) + { + // Verify the index is valid + if (index < myUsbDevice.numberOfStrings) + { + length = *(dat + USB_STRING_DESCRIPTOR_LENGTH); + myUsbDevice.ep0String.encoding.type = *(dat + USB_STRING_DESCRIPTOR_ENCODING); + dat += USB_STRING_DESCRIPTOR_LENGTH; + myUsbDevice.ep0String.encoding.init = true; + } + } + #elif (SLAB_USB_NUM_LANGUAGES > 1) + + langSupported = false; + + // Index 0 is the language. + if (index == 0) + { + dat = ((SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))myUsbDevice.stringDescriptors->languageArray[0][index]); + length = *((uint8_t *)dat); + myUsbDevice.ep0String.encoding.type = USB_STRING_DESCRIPTOR_UTF16LE; + } + else + { + // Otherwise, verify the language is one of the supported languages or 0. + for (lang = 0; lang < SLAB_USB_NUM_LANGUAGES; lang++) + { + if ((myUsbDevice.stringDescriptors->languageIDs[lang] == myUsbDevice.setup.wIndex) + || (myUsbDevice.stringDescriptors->languageIDs[lang] == 0)) + { + langSupported = true; + break; + } + } + if ((langSupported == true) && (index < myUsbDevice.numberOfStrings)) + { + dat = ((SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))myUsbDevice.stringDescriptors->languageArray[lang][index]); + length = *(dat + USB_STRING_DESCRIPTOR_LENGTH); + myUsbDevice.ep0String.encoding.type = *(dat + USB_STRING_DESCRIPTOR_ENCODING); + dat += USB_STRING_DESCRIPTOR_LENGTH; + + if (myUsbDevice.ep0String.encoding.type == USB_STRING_DESCRIPTOR_UTF16LE_PACKED) + { + myUsbDevice.ep0String.encoding.init = true; + } + else + { + myUsbDevice.ep0String.encoding.init = false; + } + } + } + #endif // ( SLAB_USB_NUM_LANGUAGES == 1 ) + } + + // If there is a descriptor to send, get the proper length, then call + // EP0_Write() to send. + if (length) + { + if (length > myUsbDevice.setup.wLength) + { + length = myUsbDevice.setup.wLength; + } + + EP0_Write(dat, length); + + retVal = USB_STATUS_OK; + } + } + + return retVal; +} + +/***************************************************************************//** + * @brief Sends the current interface alternate setting + * @details Sends 0x0000 if alternate interfaces are not supported. + * @return Status of request (type @ref USB_Status_TypeDef) + * @note This function takes no parameters, but it uses the setup command + * stored in @ref myUsbDevice.setup. + ******************************************************************************/ +static USB_Status_TypeDef GetInterface(void) +{ + uint16_t interface = myUsbDevice.setup.wIndex; + USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR; + + if ((interface < SLAB_USB_NUM_INTERFACES) + && (myUsbDevice.setup.wLength == 1) + && (myUsbDevice.setup.wValue == 0) + && (*((uint8_t *)&myUsbDevice.setup.bmRequestType) == + (USB_SETUP_DIR_D2H | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_INTERFACE))) + { + if (myUsbDevice.state == USBD_STATE_CONFIGURED) + { +#if (SLAB_USB_SUPPORT_ALT_INTERFACES) + // Return the alternate setting for the specified interface + EP0_Write((SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))&myUsbDevice.interfaceAltSetting[interface], 1); +#else + // Alternate interfaces are not supported, so return 0x0000. + EP0_Write((SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))&txZero, 1); +#endif + retVal = USB_STATUS_OK; + } + } + return retVal; +} + +/***************************************************************************//** + * @brief Sends the requested Remote Wakeup, Self-Powered, or + * Endpoint Status + * @return Status of request (type @ref USB_Status_TypeDef) + * @note This function takes no parameters, but it uses the setup command + * stored in @ref myUsbDevice.setup. + ******************************************************************************/ +static USB_Status_TypeDef GetStatus(void) +{ + USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR; + + if ((myUsbDevice.setup.wLength == 2) + && (myUsbDevice.setup.wValue == 0) + && (myUsbDevice.setup.bmRequestType.Direction == USB_SETUP_DIR_IN) + && (myUsbDevice.state >= USBD_STATE_ADDRESSED)) + { + pStatus = htole16(0); // Default return value is 0x0000 + + switch (myUsbDevice.setup.bmRequestType.Recipient) + { + case USB_SETUP_RECIPIENT_DEVICE: + if (myUsbDevice.setup.wIndex == 0) + { + #if SLAB_USB_REMOTE_WAKEUP_ENABLED + // Remote wakeup feature status + if (myUsbDevice.remoteWakeupEnabled) + { + pStatus |= htole16(REMOTE_WAKEUP_ENABLED); + } + #endif // SLAB_USB_REMOTE_WAKEUP_ENABLED + + #if SLAB_USB_IS_SELF_POWERED_CB + // Current self/bus power status + if (USBD_IsSelfPoweredCb()) + { + pStatus |= htole16(DEVICE_IS_SELFPOWERED); + } + #elif (SLAB_USB_BUS_POWERED == 0) + pStatus |= htole16(DEVICE_IS_SELFPOWERED); + #endif // SLAB_USB_IS_SELF_POWERED_CB + + retVal = USB_STATUS_OK; + } + break; + + case USB_SETUP_RECIPIENT_INTERFACE: + if (myUsbDevice.setup.wIndex < SLAB_USB_NUM_INTERFACES) + { + retVal = USB_STATUS_OK; + } + break; + + + case USB_SETUP_RECIPIENT_ENDPOINT: + // Device does not support halting endpoint 0, but do not give + // an error as this is a valid request + if (((myUsbDevice.setup.wIndex & ~USB_EP_DIR_IN) == 0) + && (myUsbDevice.state == USBD_STATE_ADDRESSED)) + { + retVal = USB_STATUS_OK; + } + else if (myUsbDevice.state == USBD_STATE_CONFIGURED) + { + switch (myUsbDevice.setup.wIndex & 0xFF) + { + #if SLAB_USB_EP1OUT_USED + case (USB_EP_DIR_OUT | 1): + if (myUsbDevice.ep1out.state == D_EP_HALT) + { + pStatus = htole16(1); + } + retVal = USB_STATUS_OK; + break; + #endif + #if SLAB_USB_EP2OUT_USED + case (USB_EP_DIR_OUT | 2): + if (myUsbDevice.ep2out.state == D_EP_HALT) + { + pStatus = htole16(1); + } + retVal = USB_STATUS_OK; + break; + #endif + #if SLAB_USB_EP3OUT_USED + case (USB_EP_DIR_OUT | 3): + if (myUsbDevice.ep3out.state == D_EP_HALT) + { + pStatus = htole16(1); + } + retVal = USB_STATUS_OK; + break; + #endif + #if SLAB_USB_EP1IN_USED + case (USB_EP_DIR_IN | 1): + if (myUsbDevice.ep1in.state == D_EP_HALT) + { + pStatus = htole16(1); + } + retVal = USB_STATUS_OK; + break; + #endif + #if SLAB_USB_EP2IN_USED + case (USB_EP_DIR_IN | 2): + if (myUsbDevice.ep2in.state == D_EP_HALT) + { + pStatus = htole16(1); + } + retVal = USB_STATUS_OK; + break; + #endif + #if SLAB_USB_EP3IN_USED + case (USB_EP_DIR_IN | 3): + if (myUsbDevice.ep3in.state == D_EP_HALT) + { + pStatus = htole16(1); + } + retVal = USB_STATUS_OK; + break; + #endif + } + } + break; + } + + // If the command was valid, send the requested status. + if (retVal == USB_STATUS_OK) + { + EP0_Write((SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))&pStatus, 2); + } + } + + return retVal; +} + +/***************************************************************************//** + * @brief Sets the Address + * @return Status of request (type @ref USB_Status_TypeDef) + * @note This function takes no parameters, but it uses the setup command + * stored in @ref myUsbDevice.setup. + ******************************************************************************/ +static USB_Status_TypeDef SetAddress(void) +{ + USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR; + + if ((myUsbDevice.setup.wValue < 128) + && (myUsbDevice.setup.wLength == 0) + && (myUsbDevice.setup.bmRequestType.Recipient == USB_SETUP_RECIPIENT_DEVICE) + && (myUsbDevice.setup.wIndex == 0)) + { + // If the device is in the Default state and the address is non-zero, put + // the device in the Addressed state. + if (myUsbDevice.state == USBD_STATE_DEFAULT) + { + if (myUsbDevice.setup.wValue != 0) + { + USBD_SetUsbState(USBD_STATE_ADDRESSED); + } + retVal = USB_STATUS_OK; + } + // If the device is already addressed and the address is zero, put the + // device in the Default state. + else if (myUsbDevice.state == USBD_STATE_ADDRESSED) + { + if (myUsbDevice.setup.wValue == 0) + { + USBD_SetUsbState(USBD_STATE_DEFAULT); + } + retVal = USB_STATUS_OK; + } + + // Set the new address if the request was valid. + if (retVal == USB_STATUS_OK) + { + USB_SetAddress(myUsbDevice.setup.wValue); + } + } + + return retVal; +} + +/***************************************************************************//** + * @brief Sets the Configuration + * @return Status of request (type @ref USB_Status_TypeDef) + * @note This function takes no parameters, but it uses the setup command + * stored in @ref myUsbDevice.setup. + ******************************************************************************/ +static USB_Status_TypeDef SetConfiguration(void) +{ + USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR; + + if (((myUsbDevice.setup.wValue >> 8) == 0) + && (myUsbDevice.setup.bmRequestType.Recipient == USB_SETUP_RECIPIENT_DEVICE) + && (myUsbDevice.setup.wLength == 0) + && (myUsbDevice.setup.wIndex == 0)) + { + // If the device is in the Addressed state and a valid Configuration value + // was sent, enter the Configured state. + if (myUsbDevice.state == USBD_STATE_ADDRESSED) + { + if ((myUsbDevice.setup.wValue == 0) + || (myUsbDevice.setup.wValue == myUsbDevice.configDescriptor->bConfigurationValue)) + { + myUsbDevice.configurationValue = myUsbDevice.setup.wValue; + if (myUsbDevice.setup.wValue == myUsbDevice.configDescriptor->bConfigurationValue) + { + USBD_ActivateAllEps(true); + USBD_SetUsbState(USBD_STATE_CONFIGURED); + } + retVal = USB_STATUS_OK; + } + } + // If the device is in the Configured state and Configuration zero is sent, + // abort all transfer and enter the Addressed state. + else if (myUsbDevice.state == USBD_STATE_CONFIGURED) + { + if ((myUsbDevice.setup.wValue == 0) + || (myUsbDevice.setup.wValue == myUsbDevice.configDescriptor->bConfigurationValue)) + { + myUsbDevice.configurationValue = myUsbDevice.setup.wValue; + if (myUsbDevice.setup.wValue == 0) + { + USBD_SetUsbState(USBD_STATE_ADDRESSED); + USBD_AbortAllTransfers(); + } + else + { + // Reenable device endpoints, will reset data toggles + USBD_ActivateAllEps(false); + } + retVal = USB_STATUS_OK; + } + } + } + + return retVal; +} + +/***************************************************************************//** + * @brief Sets the Remote Wakeup or Endpoint Halt Feature + * @return Status of request (type @ref USB_Status_TypeDef) + * @note This function takes no parameters, but it uses the setup command + * stored in @ref myUsbDevice.setup. + ******************************************************************************/ +static USB_Status_TypeDef SetFeature(void) +{ + USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR; + + if (myUsbDevice.setup.wLength == 0) + { + switch (myUsbDevice.setup.bmRequestType.Recipient) + { + #if SLAB_USB_REMOTE_WAKEUP_ENABLED + case USB_SETUP_RECIPIENT_DEVICE: + if ((myUsbDevice.setup.wIndex == 0) // ITF no. 0 + && (myUsbDevice.setup.wValue == USB_FEATURE_DEVICE_REMOTE_WAKEUP) + && (myUsbDevice.state == USBD_STATE_CONFIGURED)) + { + myUsbDevice.remoteWakeupEnabled = true; + retVal = USB_STATUS_OK; + } + break; + #endif // SLAB_USB_REMOTE_WAKEUP_ENABLED + case USB_SETUP_RECIPIENT_ENDPOINT: + // Device does not support halting endpoint 0, but do not return + // an error as this is a valid request + if (((myUsbDevice.setup.wIndex & ~USB_EP_DIR_IN) == 0) + && (myUsbDevice.state >= USBD_STATE_ADDRESSED)) + { + retVal = USB_STATUS_OK; + } + else if ((((myUsbDevice.setup.wIndex) & ~USB_SETUP_DIR_D2H) < SLAB_USB_NUM_EPS_USED) + && (myUsbDevice.setup.wValue == USB_FEATURE_ENDPOINT_HALT) + && (myUsbDevice.state == USBD_STATE_CONFIGURED)) + { + retVal = USB_STATUS_OK; + USB_SetIndex((myUsbDevice.setup.wIndex & 0xFF) & ~USB_SETUP_DIR_D2H); + + // Enable Stalls on the specified endpoint. +#if (SLAB_USB_EP1IN_USED || SLAB_USB_EP2IN_USED || SLAB_USB_EP3IN_USED) + if ((myUsbDevice.setup.wIndex & 0xFF) & USB_EP_DIR_IN) + { + USB_EpnInStall(); + } +#endif +#if (SLAB_USB_EP1OUT_USED || SLAB_USB_EP2OUT_USED || SLAB_USB_EP3OUT_USED) + if (((myUsbDevice.setup.wIndex & 0xFF) & USB_EP_DIR_IN) == 0) + { + USB_EpnOutStall(); + } +#endif + + // Put the specified endpoint in the Halted state. + switch (myUsbDevice.setup.wIndex & 0xFF) + { + #if SLAB_USB_EP1OUT_USED + case (USB_EP_DIR_OUT | 1): + myUsbDevice.ep1out.state = D_EP_HALT; + break; + #endif + #if SLAB_USB_EP2OUT_USED + case (USB_EP_DIR_OUT | 2): + myUsbDevice.ep2out.state = D_EP_HALT; + break; + #endif + #if SLAB_USB_EP3OUT_USED + case (USB_EP_DIR_OUT | 3): + myUsbDevice.ep3out.state = D_EP_HALT; + break; + #endif + #if SLAB_USB_EP1IN_USED + case (USB_EP_DIR_IN | 1): + myUsbDevice.ep1in.state = D_EP_HALT; + break; + #endif + #if SLAB_USB_EP2IN_USED + case (USB_EP_DIR_IN | 2): + myUsbDevice.ep2in.state = D_EP_HALT; + break; + #endif + #if SLAB_USB_EP3IN_USED + case (USB_EP_DIR_IN | 3): + myUsbDevice.ep3in.state = D_EP_HALT; + break; + #endif + } + } + } + } + + return retVal; +} + +/***************************************************************************//** + * @brief Sets the Interface and Alternate Interface (if supported) + * @return Status of request (type @ref USB_Status_TypeDef) + * @note This function takes no parameters, but it uses the setup command + * stored in @ref myUsbDevice.setup. + ******************************************************************************/ +static USB_Status_TypeDef SetInterface(void) +{ + USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR; + uint8_t interface = (uint8_t)myUsbDevice.setup.wIndex; + uint8_t altSetting = (uint8_t)myUsbDevice.setup.wValue; + + if ((interface < SLAB_USB_NUM_INTERFACES) + && (myUsbDevice.state == USBD_STATE_CONFIGURED) + && (myUsbDevice.setup.wLength == 0) +#if (SLAB_USB_SUPPORT_ALT_INTERFACES == 0) + && (altSetting == 0) +#endif + && (myUsbDevice.setup.bmRequestType.Recipient == USB_SETUP_RECIPIENT_INTERFACE)) + { +#if (SLAB_USB_SUPPORT_ALT_INTERFACES) + if (USBD_SetInterfaceCb(interface, altSetting) == USB_STATUS_OK) + { + myUsbDevice.interfaceAltSetting[interface] = altSetting; + retVal = USB_STATUS_OK; + } +#else +#if (SLAB_USB_NUM_INTERFACES == 1) + // Reset data toggles on EP's + USBD_ActivateAllEps(false); +#endif // ( SLAB_USB_NUM_INTERFACES == 1 ) + retVal = USB_STATUS_OK; +#endif // ( SLAB_USB_SUPPORT_ALT_INTERFACES ) + } + + return retVal; +} + +// ----------------------------------------------------------------------------- +// Utility Functions + +/***************************************************************************//** + * @brief Enables all endpoints for data transfers + * @return Status of request (type @ref USB_Status_TypeDef) + * @note This function takes no parameters, but it uses the setup command + * stored in @ref myUsbDevice.setup. + ******************************************************************************/ +static void USBD_ActivateAllEps(bool forceIdle) +{ + if (forceIdle == true) + { +#if SLAB_USB_EP1IN_USED + myUsbDevice.ep1in.state = D_EP_IDLE; +#endif +#if SLAB_USB_EP2IN_USED + myUsbDevice.ep2in.state = D_EP_IDLE; +#endif +#if SLAB_USB_EP3IN_USED + myUsbDevice.ep3in.state = D_EP_IDLE; +#endif +#if SLAB_USB_EP1OUT_USED + myUsbDevice.ep1out.state = D_EP_IDLE; +#endif +#if SLAB_USB_EP2OUT_USED + myUsbDevice.ep2out.state = D_EP_IDLE; +#endif +#if SLAB_USB_EP3OUT_USED + myUsbDevice.ep3out.state = D_EP_IDLE; +#endif + } + +#if SLAB_USB_EP1IN_USED + USB_ActivateEp(1, // ep + SLAB_USB_EP1IN_MAX_PACKET_SIZE, // packetSize + 1, // inDir + SLAB_USB_EP1OUT_USED, // splitMode + 0); // isoMod +#endif // SLAB_USB_EP1IN_USED +#if SLAB_USB_EP2IN_USED + USB_ActivateEp(2, // ep + SLAB_USB_EP2IN_MAX_PACKET_SIZE, // packetSize + 1, // inDir + SLAB_USB_EP2OUT_USED, // splitMode + 0); // isoMod +#endif // SLAB_USB_EP2IN_USED +#if SLAB_USB_EP3IN_USED + USB_ActivateEp(3, // ep + SLAB_USB_EP3IN_MAX_PACKET_SIZE, // packetSize + 1, // inDir + SLAB_USB_EP3OUT_USED, // splitMode + (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC)); // isoMod +#endif // SLAB_USB_EP3IN_USED +#if SLAB_USB_EP1OUT_USED + USB_ActivateEp(1, // ep + SLAB_USB_EP1OUT_MAX_PACKET_SIZE, // packetSize + 0, // inDir + SLAB_USB_EP1IN_USED, // splitMode + 0); // isoMod +#endif // SLAB_USB_EP1OUT_USED +#if SLAB_USB_EP2OUT_USED + USB_ActivateEp(2, // ep + SLAB_USB_EP2OUT_MAX_PACKET_SIZE, // packetSize + 0, // inDir + SLAB_USB_EP2IN_USED, // splitMode + 0); // isoMod +#endif // SLAB_USB_EP2OUT_USED +#if SLAB_USB_EP3OUT_USED + USB_ActivateEp(3, // ep + SLAB_USB_EP3OUT_MAX_PACKET_SIZE, // packetSize + 0, // inDir + SLAB_USB_EP3IN_USED, // splitMode + (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC)); // isoMod +#endif // SLAB_USB_EP1OUT_USED +} + +/***************************************************************************//** + * @brief Sets up an Endpoint 0 Write + * @param dat + * Data to transmit on Endpoint 0 + * @param numBytes + * Number of bytes to transmit on Endpoint 0 + ******************************************************************************/ +static void EP0_Write(SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), uint16_t numBytes) +{ + if (myUsbDevice.ep0.state == D_EP_IDLE) + { + myUsbDevice.ep0.buf = dat; + myUsbDevice.ep0.remaining = numBytes; + myUsbDevice.ep0.state = D_EP_TRANSMITTING; + myUsbDevice.ep0.misc.c = 0; + } +} diff --git a/efm8/lib/c8051f380/efm8_usb/src/efm8_usbdep.c b/efm8/lib/c8051f380/efm8_usb/src/efm8_usbdep.c new file mode 100644 index 0000000..2982658 --- /dev/null +++ b/efm8/lib/c8051f380/efm8_usb/src/efm8_usbdep.c @@ -0,0 +1,1028 @@ +/**************************************************************************//** + * Copyright (c) 2015 by Silicon Laboratories Inc. All rights reserved. + * + * http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt + *****************************************************************************/ + +#include "si_toolchain.h" +#include "efm8_usb.h" +#include +#include + +extern SI_SEGMENT_VARIABLE(myUsbDevice, USBD_Device_TypeDef, MEM_MODEL_SEG); + +// ----------------------------------------------------------------------------- +// Function Prototypes + +// ------------------------------- +// Memory-specific FIFO access functions +#ifdef SI_GPTR + +static void USB_ReadFIFO_Idata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_IDATA), uint8_t fifoNum); +static void USB_WriteFIFO_Idata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_IDATA)); + +static void USB_ReadFIFO_Xdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_XDATA), uint8_t fifoNum); +static void USB_WriteFIFO_Xdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_XDATA)); + +#if SI_GPTR_MTYPE_PDATA != SI_GPTR_MTYPE_XDATA +static void USB_ReadFIFO_Pdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_PDATA), uint8_t fifoNum); +static void USB_WriteFIFO_Pdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_PDATA)); +#endif + +#if SI_GPTR_MTYPE_DATA != SI_GPTR_MTYPE_IDATA +static void USB_ReadFIFO_Data(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_DATA), uint8_t fifoNum); +static void USB_WriteFIFO_Data(uint8_t numBytes, uint8_t SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_DATA)); +#endif + +static void USB_WriteFIFO_Code(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_CODE)); + +#else + +// ------------------------------- +// Generic FIFO access functions +static void USB_ReadFIFO_Generic(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), uint8_t fifoNum); +static void USB_WriteFIFO_Generic(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC)); + +#endif // #ifdef SI_GPTR + +#if (SLAB_USB_EP3OUT_USED && (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC)) +static void memclearXdata(SI_VARIABLE_SEGMENT_POINTER(s, uint8_t, SI_SEG_XDATA), + uint16_t n); +#endif + +// ----------------------------------------------------------------------------- +// Functions + +/***************************************************************************//** + * @brief Reads Isochronous data from the Endpoint FIFO + * @param fifoNum + * USB Endpoint FIFO to read + * @param numBytes + * Number of bytes to read from the FIFO + * @param dat + * Pointer to buffer to hold data read from the FIFO + ******************************************************************************/ +#if (SLAB_USB_EP3OUT_USED && (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC) && (SLAB_USB_EP3OUT_MAX_PACKET_SIZE > 255)) +// ---------------------------------------------------------------------------- +// If Isochronous mode is enabled and the max packet size is greater than 255, +// break the FIFO reads up into multiple reads of 255 or less bytes. +// ---------------------------------------------------------------------------- +void USB_ReadFIFOIso(uint8_t fifoNum, uint16_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC)) +{ + uint8_t numBytesRead; + + // USB_ReadFIFO() accepts a maximum of 255 bytes. If the number of bytes to + // send is greated than 255, call USB_ReadFIFO() multiple times. + while (numBytes > 0) + { + numBytesRead = (numBytes > 255) ? 255 : numBytes; + USB_ReadFIFO(fifoNum, numBytesRead, dat); + numBytes -= numBytesRead; + dat += numBytesRead; + } +} +#else +#define USB_ReadFIFOIso(a, b, c) USB_ReadFIFO(a, b, c) +#endif + +/***************************************************************************//** + * @brief Writes Isochronous data to the Endpoint FIFO + * @param fifoNum + * USB Endpoint FIFO to write + * @param numBytes + * Number of bytes to write to the FIFO + * @param dat + * Pointer to buffer hoding data to write to the FIFO + ******************************************************************************/ +#if (SLAB_USB_EP3IN_USED && (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC) && (SLAB_USB_EP3IN_MAX_PACKET_SIZE > 255)) +// ---------------------------------------------------------------------------- +// If Isochronous mode is enabled and the max packet size is greater than 255, +// break the FIFO writes up into multiple writes of 255 or less bytes. +// ---------------------------------------------------------------------------- +void USB_WriteFIFOIso(uint8_t fifoNum, uint16_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC)) +{ + uint8_t numBytesWrite; + + // USB_WriteFIFO() accepts a maximum of 255 bytes. If the number of bytes to + // send is greated than 255, call USB_WriteFIFO() multiple times. + while (numBytes > 0) + { + numBytesWrite = (numBytes > 255) ? 255 : numBytes; + numBytes -= numBytesWrite; + USB_WriteFIFO(fifoNum, numBytesWrite, dat, (numBytes == 0)); + dat += numBytesWrite; + } +} +#else +#define USB_WriteFIFOIso(a, b, c) USB_WriteFIFO(a, b, c, true) +#endif + +#if SLAB_USB_EP1IN_USED +/***************************************************************************//** + * @brief Handle Endpoint 1 IN transfer interrupt + * @note This function takes no parameters, but it uses the EP1IN status + * variables stored in @ref myUsbDevice.ep1in. + ******************************************************************************/ +void handleUsbIn1Int(void) +{ + uint8_t xferred; + bool callback; + + USB_SetIndex(1); + + if (USB_EpnInGetSentStall()) + { + USB_EpnInClearSentStall(); + } + else if (myUsbDevice.ep1in.state == D_EP_TRANSMITTING) + { + xferred = (myUsbDevice.ep1in.remaining > SLAB_USB_EP1IN_MAX_PACKET_SIZE) + ? SLAB_USB_EP1IN_MAX_PACKET_SIZE : myUsbDevice.ep1in.remaining; + myUsbDevice.ep1in.remaining -= xferred; + myUsbDevice.ep1in.buf += xferred; + + callback = myUsbDevice.ep1in.misc.bits.callback; + + // Load more data + if (myUsbDevice.ep1in.remaining > 0) + { + USB_WriteFIFO(1, + (myUsbDevice.ep1in.remaining > SLAB_USB_EP1IN_MAX_PACKET_SIZE) + ? SLAB_USB_EP1IN_MAX_PACKET_SIZE + : myUsbDevice.ep1in.remaining, + myUsbDevice.ep1in.buf, + true); + } + else + { + myUsbDevice.ep1in.misc.bits.callback = false; + myUsbDevice.ep1in.state = D_EP_IDLE; + } + + if (callback == true) + { + USBD_XferCompleteCb(EP1IN, USB_STATUS_OK, xferred, myUsbDevice.ep1in.remaining); + } + + } +} +#endif // SLAB_USB_EP1IN_USED + +#if SLAB_USB_EP2IN_USED +/***************************************************************************//** + * @brief Handle Endpoint 2 IN transfer interrupt + * @note This function takes no parameters, but it uses the EP2IN status + * variables stored in @ref myUsbDevice.ep2in. + ******************************************************************************/ +void handleUsbIn2Int(void) +{ + uint8_t xferred; + bool callback; + + USB_SetIndex(2); + + if (USB_EpnInGetSentStall()) + { + USB_EpnInClearSentStall(); + } + else if (myUsbDevice.ep2in.state == D_EP_TRANSMITTING) + { + xferred = (myUsbDevice.ep2in.remaining > SLAB_USB_EP2IN_MAX_PACKET_SIZE) + ? SLAB_USB_EP2IN_MAX_PACKET_SIZE : myUsbDevice.ep2in.remaining; + myUsbDevice.ep2in.remaining -= xferred; + myUsbDevice.ep2in.buf += xferred; + + callback = myUsbDevice.ep2in.misc.bits.callback; + + // Load more data + if (myUsbDevice.ep2in.remaining > 0) + { + USB_WriteFIFO(2, + (myUsbDevice.ep2in.remaining > SLAB_USB_EP2IN_MAX_PACKET_SIZE) + ? SLAB_USB_EP2IN_MAX_PACKET_SIZE + : myUsbDevice.ep2in.remaining, + myUsbDevice.ep2in.buf, + true); + } + else + { + myUsbDevice.ep2in.misc.bits.callback = false; + myUsbDevice.ep2in.state = D_EP_IDLE; + } + + if (callback == true) + { + USBD_XferCompleteCb(EP2IN, USB_STATUS_OK, xferred, myUsbDevice.ep2in.remaining); + } + + } +} +#endif // SLAB_USB_EP2IN_USED + +#if SLAB_USB_EP3IN_USED +/***************************************************************************//** + * @brief Handle Endpoint 3 IN transfer interrupt + * @details Endpoint 3 IN is the only IN endpoint that supports isochronous + * transfers. + * @note This function takes no parameters, but it uses the EP3IN status + * variables stored in @ref myUsbDevice.ep3in. + ******************************************************************************/ +void handleUsbIn3Int(void) +{ +#if SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC + uint16_t xferred, nextIdx; +#else + uint8_t xferred; + bool callback; +#endif + + USB_SetIndex(3); + + if (USB_EpnInGetSentStall()) + { + USB_EpnInClearSentStall(); + } + else if (myUsbDevice.ep3in.state == D_EP_TRANSMITTING) + { +#if ((SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_INTR)) + xferred = (myUsbDevice.ep3in.remaining > SLAB_USB_EP3IN_MAX_PACKET_SIZE) + ? SLAB_USB_EP3IN_MAX_PACKET_SIZE : myUsbDevice.ep3in.remaining; + myUsbDevice.ep3in.remaining -= xferred; + myUsbDevice.ep3in.buf += xferred; +#endif + +#if ((SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_INTR)) + + callback = myUsbDevice.ep3in.misc.bits.callback; + +#elif (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC) + if (myUsbDevice.ep3in.misc.bits.callback == true) + { + // In Isochronous mode, the meaning of the USBD_XferCompleteCb parameters changes: + // xferred is ignored + // remaining is the current index into the circular buffer + // the return value is the number of bytes to transmit in the next packet + xferred = USBD_XferCompleteCb(EP3IN, USB_STATUS_OK, 0, myUsbDevice.ep3inIsoIdx); + if (xferred == 0) + { + myUsbDevice.ep3in.misc.bits.inPacketPending = true; + return; + } + } +#endif + // Load more data +#if ((SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_INTR)) + if (myUsbDevice.ep3in.remaining > 0) + { + USB_WriteFIFO(3, + (myUsbDevice.ep3in.remaining > SLAB_USB_EP3IN_MAX_PACKET_SIZE) + ? SLAB_USB_EP3IN_MAX_PACKET_SIZE + : myUsbDevice.ep3in.remaining, + myUsbDevice.ep3in.buf, + true); + } + else + { + myUsbDevice.ep3in.misc.bits.callback = false; + myUsbDevice.ep3in.state = D_EP_IDLE; + } + + if (callback == true) + { + USBD_XferCompleteCb(EP3IN, USB_STATUS_OK, xferred, myUsbDevice.ep3in.remaining); + } +#elif (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC) + nextIdx = xferred + myUsbDevice.ep3inIsoIdx; + myUsbDevice.ep3in.misc.bits.inPacketPending = false; + + // Check if the next index is past the end of the circular buffer. + // If so, break the write up into two calls to USB_WriteFIFOIso() + if (nextIdx > myUsbDevice.ep3in.remaining) + { + USB_WriteFIFOIso(3, myUsbDevice.ep3in.remaining - myUsbDevice.ep3inIsoIdx, &myUsbDevice.ep3in.buf[myUsbDevice.ep3inIsoIdx]); + myUsbDevice.ep3inIsoIdx = nextIdx - myUsbDevice.ep3in.remaining; + USB_WriteFIFOIso(3, myUsbDevice.ep3inIsoIdx, myUsbDevice.ep3in.buf); + } + else + { + USB_WriteFIFOIso(3, xferred, &myUsbDevice.ep3in.buf[myUsbDevice.ep3inIsoIdx]); + myUsbDevice.ep3inIsoIdx = nextIdx; + } +#endif // ( ( SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_BULK ) || ( SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_INTR ) ) + } +} +#endif // SLAB_USB_EP3IN_USED + +#if SLAB_USB_EP1OUT_USED +/***************************************************************************//** + * @brief Handle Endpoint 1 OUT transfer interrupt + * @note This function takes no parameters, but it uses the EP1OUT status + * variables stored in @ref myUsbDevice.ep1out. + ******************************************************************************/ +void handleUsbOut1Int(void) +{ + uint8_t count; + USB_Status_TypeDef status; + bool xferComplete = false; + + USB_SetIndex(1); + + if (USB_EpnOutGetSentStall()) + { + USB_EpnOutClearSentStall(); + } + else if (USB_EpnGetOutPacketReady()) + { + count = USB_EpOutGetCount(); + + // If USBD_Read() has not been called, return an error + if (myUsbDevice.ep1out.state != D_EP_RECEIVING) + { + myUsbDevice.ep1out.misc.bits.outPacketPending = true; + status = USB_STATUS_EP_ERROR; + } + // Check for overrun of user buffer + else if (myUsbDevice.ep1out.remaining < count) + { + myUsbDevice.ep1out.state = D_EP_IDLE; + myUsbDevice.ep1out.misc.bits.outPacketPending = true; + status = USB_STATUS_EP_RX_BUFFER_OVERRUN; + } + else + { + USB_ReadFIFO(1, count, myUsbDevice.ep1out.buf); + + myUsbDevice.ep1out.misc.bits.outPacketPending = false; + myUsbDevice.ep1out.remaining -= count; + myUsbDevice.ep1out.buf += count; + + if ((myUsbDevice.ep1out.remaining == 0) || (count != SLAB_USB_EP1OUT_MAX_PACKET_SIZE)) + { + myUsbDevice.ep1out.state = D_EP_IDLE; + xferComplete = true; + } + + status = USB_STATUS_OK; + USB_EpnClearOutPacketReady(); + } + if (myUsbDevice.ep1out.misc.bits.callback == true) + { + if (xferComplete == true) + { + myUsbDevice.ep1out.misc.bits.callback = false; + } + + USBD_XferCompleteCb(EP1OUT, status, count, myUsbDevice.ep1out.remaining); + } + } +} +#endif // EP1OUT_USED + +#if SLAB_USB_EP2OUT_USED +/***************************************************************************//** + * @brief Handle Endpoint 2 OUT transfer interrupt + * @note This function takes no parameters, but it uses the EP2OUT status + * variables stored in @ref myUsbDevice.ep2out. + ******************************************************************************/ +void handleUsbOut2Int(void) +{ + uint8_t count; + USB_Status_TypeDef status; + bool xferComplete = false; + + USB_SetIndex(2); + + if (USB_EpnOutGetSentStall()) + { + USB_EpnOutClearSentStall(); + } + else if (USB_EpnGetOutPacketReady()) + { + count = USB_EpOutGetCount(); + + // If USBD_Read() has not been called, return an error + if (myUsbDevice.ep2out.state != D_EP_RECEIVING) + { + myUsbDevice.ep2out.misc.bits.outPacketPending = true; + status = USB_STATUS_EP_ERROR; + } + // Check for overrun of user buffer + else if (myUsbDevice.ep2out.remaining < count) + { + myUsbDevice.ep2out.state = D_EP_IDLE; + myUsbDevice.ep2out.misc.bits.outPacketPending = true; + status = USB_STATUS_EP_RX_BUFFER_OVERRUN; + } + else + { + USB_ReadFIFO(2, count, myUsbDevice.ep2out.buf); + + myUsbDevice.ep2out.misc.bits.outPacketPending = false; + myUsbDevice.ep2out.remaining -= count; + myUsbDevice.ep2out.buf += count; + + if ((myUsbDevice.ep2out.remaining == 0) || (count != SLAB_USB_EP2OUT_MAX_PACKET_SIZE)) + { + myUsbDevice.ep2out.state = D_EP_IDLE; + xferComplete = true; + } + + status = USB_STATUS_OK; + USB_EpnClearOutPacketReady(); + } + if (myUsbDevice.ep2out.misc.bits.callback == true) + { + if (xferComplete == true) + { + myUsbDevice.ep2out.misc.bits.callback = false; + } + + USBD_XferCompleteCb(EP2OUT, status, count, myUsbDevice.ep2out.remaining); + } + } +} +#endif // EP2OUT_USED + +#if SLAB_USB_EP3OUT_USED +/***************************************************************************//** + * @brief Handle Endpoint 3 OUT transfer interrupt + * @details Endpoint 3 OUT is the only OUT endpoint that supports + * isochronous transfers. + * @note This function takes no parameters, but it uses the EP3OUT status + * variables stored in @ref myUsbDevice.ep3out. + ******************************************************************************/ +#if ((SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_INTR)) +void handleUsbOut3Int(void) +{ + uint8_t count; + USB_Status_TypeDef status; + bool xferComplete = false; + + USB_SetIndex(3); + + if (USB_EpnOutGetSentStall()) + { + USB_EpnOutClearSentStall(); + } + else if (USB_EpnGetOutPacketReady()) + { + count = USB_EpOutGetCount(); + + // If USBD_Read() has not been called, return an error + if (myUsbDevice.ep3out.state != D_EP_RECEIVING) + { + myUsbDevice.ep3out.misc.bits.outPacketPending = true; + status = USB_STATUS_EP_ERROR; + } + // Check for overrun of user buffer + else if (myUsbDevice.ep3out.remaining < count) + { + myUsbDevice.ep3out.state = D_EP_IDLE; + myUsbDevice.ep3out.misc.bits.outPacketPending = true; + status = USB_STATUS_EP_RX_BUFFER_OVERRUN; + } + else + { + USB_ReadFIFO(3, count, myUsbDevice.ep3out.buf); + + myUsbDevice.ep3out.misc.bits.outPacketPending = false; + myUsbDevice.ep3out.remaining -= count; + myUsbDevice.ep3out.buf += count; + + if ((myUsbDevice.ep3out.remaining == 0) || (count != SLAB_USB_EP3OUT_MAX_PACKET_SIZE)) + { + myUsbDevice.ep3out.state = D_EP_IDLE; + xferComplete = true; + } + + status = USB_STATUS_OK; + USB_EpnClearOutPacketReady(); + } + if (myUsbDevice.ep3out.misc.bits.callback == true) + { + if (xferComplete == true) + { + myUsbDevice.ep3out.misc.bits.callback = false; + } + + USBD_XferCompleteCb(EP3OUT, status, count, myUsbDevice.ep3out.remaining); + } + } +} + +#elif (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC) +void handleUsbOut3Int(void) +{ + uint16_t nextIdx; + uint16_t numZeroBytesFromCb; +#if (SLAB_USB_EP3OUT_MAX_PACKET_SIZE > 255) + uint16_t count; +#else + uint8_t count; +#endif + USB_Status_TypeDef status = USB_STATUS_OK; + bool xferComplete = false; + + USB_SetIndex(3); + + if (USB_EpnOutGetSentStall()) + { + USB_EpnOutClearSentStall(); + } + else if (USB_EpnGetOutPacketReady()) + { + count = USB_EpOutGetCount(); + + // If USBD_Read() has not been called, return an error + if (myUsbDevice.ep3out.state != D_EP_RECEIVING) + { + myUsbDevice.ep3out.misc.bits.outPacketPending = true; + status = USB_STATUS_EP_ERROR; + } + else + { + // DATERR bit set (i.e. CRC/bit-stuffing error) + if (USB_EpnGetDataError() + #ifdef SLAB_USB_ISOC_OUT_MIN_PACKET_SIZE + || (count < SLAB_USB_ISOC_OUT_MIN_PACKET_SIZE) + #endif + #ifdef SLAB_USB_ISOC_OUT_MAX_PACKET_SIZE + || (count > SLAB_USB_ISOC_OUT_MAX_PACKET_SIZE) + #endif + ) + { + status = USB_STATUS_DATA_ERROR; + } + +#ifdef SLAB_USB_ISOC_OUT_PACKETSIZE_MOD2 + if ((count % 2) != 0) + { + status = USB_STATUS_DATA_ERROR; + } +#elif defined SLAB_USB_ISOC_OUT_PACKETSIZE_MOD4 + if (( count % 4) != 0) + { + status = USB_STATUS_DATA_ERROR; + } +#elif defined SLAB_USB_ISOC_OUT_PACKETSIZE_MOD6 + if (count % 6) != 0) + { + status = USB_STATUS_DATA_ERROR; + } +#endif + + if (status == USB_STATUS_DATA_ERROR) + { + count = 0; + // Flush FIFO to get rid of bad packet + USB_EpnOutFlush(); + myUsbDevice.ep3out.misc.bits.outPacketPending = false; + // Flush clears OPRDY, so no need to call USB_EpnClearOutPacketReady() now + } + else // No data error + { + nextIdx = count + myUsbDevice.ep3outIsoIdx; + + // In isochronous mode, a circular buffer is used to hold the data + // If the next index into the circular buffer passes the end of the + // buffer, make two calls to USB_ReadFIFOIso() + if (nextIdx > myUsbDevice.ep3out.remaining) + { + USB_ReadFIFOIso(3, myUsbDevice.ep3out.remaining - myUsbDevice.ep3outIsoIdx, &myUsbDevice.ep3out.buf[myUsbDevice.ep3outIsoIdx]); + myUsbDevice.ep3outIsoIdx = nextIdx - myUsbDevice.ep3out.remaining; + USB_ReadFIFOIso(3, myUsbDevice.ep3outIsoIdx, myUsbDevice.ep3out.buf); + } + else + { + USB_ReadFIFOIso(3, count, &myUsbDevice.ep3out.buf[myUsbDevice.ep3outIsoIdx]); + myUsbDevice.ep3outIsoIdx = nextIdx; + } + + myUsbDevice.ep3out.misc.bits.outPacketPending = false; + USB_EpnClearOutPacketReady(); + } + } + + if (myUsbDevice.ep3out.misc.bits.callback == true) + { + if (xferComplete == true) + { + myUsbDevice.ep3out.misc.bits.callback = false; + } + + // In Isochronous mode, the meaning of the USBD_XferCompleteCb parameters changes: + // xferred is the number of bytes received in the last packet + // remaining is the current index into the circular buffer + numZeroBytesFromCb = USBD_XferCompleteCb(EP3OUT, status, count, myUsbDevice.ep3outIsoIdx); + + // If data error occurred, the callback return value specifies how many zero-valued bytes to queue + if (numZeroBytesFromCb && (status == USB_STATUS_DATA_ERROR)) + { + uint16_t numZeroBytesToWrite; + SI_SEGMENT_VARIABLE_SEGMENT_POINTER(bufPtr, + uint8_t, + SI_SEG_XDATA, + SI_SEG_DATA); + + // Clear status after calling USBD_XferCompleteCb() + status = USB_STATUS_OK; + + // Add the specified number of zero-value bytes + nextIdx = numZeroBytesFromCb + myUsbDevice.ep3outIsoIdx; + + // Next index is past the end of the buffer (requires two writes) + if (nextIdx > myUsbDevice.ep3out.remaining) + { + // Write up to the end of the buffer + numZeroBytesToWrite = myUsbDevice.ep3out.remaining - myUsbDevice.ep3outIsoIdx; + bufPtr = &myUsbDevice.ep3out.buf[myUsbDevice.ep3outIsoIdx]; + memclearXdata(bufPtr, numZeroBytesToWrite); + + // Write the rest, starting at beginning of buffer + myUsbDevice.ep3outIsoIdx = nextIdx - myUsbDevice.ep3out.remaining; + numZeroBytesToWrite = myUsbDevice.ep3outIsoIdx; + bufPtr = &myUsbDevice.ep3out.buf[0]; + memclearXdata(bufPtr, numZeroBytesToWrite); + } + // Next index is not past the end of the buffer + else + { + bufPtr = &myUsbDevice.ep3out.buf[myUsbDevice.ep3outIsoIdx]; + memclearXdata(bufPtr, numZeroBytesFromCb); + myUsbDevice.ep3outIsoIdx = nextIdx; + } + } + } + } +} + +/***************************************************************************//** + * @brief Sets all elements in a contiguous array of XDATA to zero + * @param s + * Pointer to the block of memory to fill + * @param n + * Number of bytes to be set to the value + ******************************************************************************/ +static void memclearXdata(SI_VARIABLE_SEGMENT_POINTER(s, uint8_t, SI_SEG_XDATA), + uint16_t n) +{ + while (n) + { + *s++ = 0; + n--; + } +} + +#endif // #if ((SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_INTR)) +#endif // EP3OUT_USED + +/***************************************************************************//** + * @brief Reads data from the USB FIFO + * @param fifoNum + * USB Endpoint FIFO to read + * @param numBytes + * Number of bytes to read from the FIFO + * @param dat + * Pointer to buffer to hold data read from the FIFO + ******************************************************************************/ +void USB_ReadFIFO(uint8_t fifoNum, uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC)) +{ + if (numBytes > 0) + { + USB_EnableReadFIFO(fifoNum); + + // Convert generic pointer to memory-specific pointer and call the + // the corresponding memory-specific function, if possible. + // The memory-specific functions are much faster than the generic functions. +#ifdef SI_GPTR + + switch (((SI_GEN_PTR_t *)&dat)->gptr.memtype) + { + case SI_GPTR_MTYPE_IDATA: + USB_ReadFIFO_Idata(numBytes, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_IDATA))dat, fifoNum); + break; + + // For some compilers, IDATA and DATA are treated the same. + // Only call the USB_ReadFIFO_Data() if the compiler differentiates + // between DATA and IDATA. +#if (SI_GPTR_MTYPE_DATA != SI_GPTR_MTYPE_IDATA) + case SI_GPTR_MTYPE_DATA: + USB_ReadFIFO_Data(numBytes, dat, fifoNum); + break; +#endif + + case SI_GPTR_MTYPE_XDATA: + USB_ReadFIFO_Xdata(numBytes, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_XDATA))dat, fifoNum); + break; + + // For some compilers, XDATA and PDATA are treated the same. + // Only call the USB_ReadFIFO_Pdata() if the compiler differentiates + // between XDATA and PDATA. +#if (SI_GPTR_MTYPE_PDATA != SI_GPTR_MTYPE_XDATA) + case SI_GPTR_MTYPE_PDATA: + USB_ReadFIFO_Pdata(numBytes, dat, fifoNum); + break; +#endif + + default: + break; + } + +#else + USB_ReadFIFO_Generic(numBytes, dat, fifoNum); +#endif // #ifdef SI_GPTR + + USB_DisableReadFIFO(fifoNum); + } +} + +/***************************************************************************//** + * @brief Writes data to the USB FIFO + * @param fifoNum + * USB Endpoint FIFO to write + * @param numBytes + * Number of bytes to write to the FIFO + * @param dat + * Pointer to buffer hoding data to write to the FIFO + * @param txPacket + * If TRUE, the packet will be sent immediately after loading the + * FIFO + * If FALSE, the packet will be stored in the FIFO and the + * transmission must be started at a later time + ******************************************************************************/ +void USB_WriteFIFO(uint8_t fifoNum, uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), bool txPacket) +{ + USB_EnableWriteFIFO(fifoNum); + + // Convert generic pointer to memory-specific pointer and call the + // the corresponding memory-specific function, if possible. + // The memory-specific functions are much faster than the generic functions. +#ifdef SI_GPTR + + switch (((SI_GEN_PTR_t *)&dat)->gptr.memtype) + { + case SI_GPTR_MTYPE_IDATA: + USB_WriteFIFO_Idata(numBytes, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_IDATA))dat); + break; + + // For some compilers, IDATA and DATA are treated the same. + // Only call the USB_WriteFIFO_Data() if the compiler differentiates between + // DATA and IDATA. +#if (SI_GPTR_MTYPE_DATA != SI_GPTR_MTYPE_IDATA) + case SI_GPTR_MTYPE_DATA: + USB_WriteFIFO_Data(numBytes, dat); + break; +#endif + + case SI_GPTR_MTYPE_XDATA: + USB_WriteFIFO_Xdata(numBytes, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_XDATA))dat); + break; + + // For some compilers, XDATA and PDATA are treated the same. + // Only call the USB_WriteFIFO_Pdata() if the compiler differentiates + // between XDATA and PDATA. +#if (SI_GPTR_MTYPE_PDATA != SI_GPTR_MTYPE_XDATA) + case SI_GPTR_MTYPE_PDATA: + USB_WriteFIFO_Pdata(numBytes, dat); + break; +#endif + + case SI_GPTR_MTYPE_CODE: + USB_WriteFIFO_Code(numBytes, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_CODE))dat); + break; + + default: + break; + } + +#else + USB_WriteFIFO_Generic(numBytes, dat); +#endif // #ifdef SI_GPTR + + USB_DisableWriteFIFO(fifoNum); + + if ((txPacket == true) && (fifoNum > 0)) + { + USB_SetIndex(fifoNum); + USB_EpnSetInPacketReady(); + } +} + +// ----------------------------------------------------------------------------- +// Memory-Specific FIFO Access Functions +// +// Memory-specific functions are much faster (more than 2x) than generic +// generic functions, so we will use memory-specific functions if possible. +// ----------------------------------------------------------------------------- + +#ifdef SI_GPTR +/***************************************************************************//** + * @brief Reads data from the USB FIFO to a buffer in IRAM + * @param numBytes + * Number of bytes to read from the FIFO + * @param dat + * Pointer to IDATA buffer to hold data read from the FIFO + * @param fifoNum + * USB FIFO to read + ******************************************************************************/ +static void USB_ReadFIFO_Idata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_IDATA), uint8_t fifoNum) +{ + while (--numBytes) + { + USB_GetFIFOByte(dat); + dat++; + } + USB_GetLastFIFOByte(dat, fifoNum); +} + +/***************************************************************************//** + * @brief Writes data held in IRAM to the USB FIFO + * @details The FIFO to write must be set before calling the function with + * @ref USB_EnableWriteFIFO(). + * @param numBytes + * Number of bytes to write to the FIFO + * @param dat + * Pointer to IDATA buffer holding data to write to the FIFO + ******************************************************************************/ +static void USB_WriteFIFO_Idata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_IDATA)) +{ + while (numBytes--) + { + USB_SetFIFOByte(*dat); + dat++; + } +} + +/***************************************************************************//** + * @brief Reads data from the USB FIFO to a buffer in XRAM + * @param numBytes + * Number of bytes to read from the FIFO + * @param dat + * Pointer to XDATA buffer to hold data read from the FIFO + * @param fifoNum + * USB FIFO to read + ******************************************************************************/ +static void USB_ReadFIFO_Xdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_XDATA), uint8_t fifoNum) +{ + while (--numBytes) + { + USB_GetFIFOByte(dat); + dat++; + } + USB_GetLastFIFOByte(dat, fifoNum); +} + +/***************************************************************************//** + * @brief Writes data held in XRAM to the USB FIFO + * @details The FIFO to write must be set before calling the function with + * @ref USB_EnableWriteFIFO(). + * @param numBytes + * Number of bytes to write to the FIFO + * @param dat + * Pointer to XDATA buffer holding data to write to the FIFO + ******************************************************************************/ +static void USB_WriteFIFO_Xdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_XDATA)) +{ + while (numBytes--) + { + USB_SetFIFOByte(*dat); + dat++; + } +} + +#if SI_GPTR_MTYPE_PDATA != SI_GPTR_MTYPE_XDATA +/***************************************************************************//** + * @brief Reads data from the USB FIFO to a buffer in paged XRAM + * @param numBytes + * Number of bytes to read from the FIFO + * @param dat + * Pointer to PDATA buffer to hold data read from the FIFO + * @param fifoNum + * USB FIFO to read + ******************************************************************************/ +static void USB_ReadFIFO_Pdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_PDATA), uint8_t fifoNum) +{ + while (--numBytes) + { + USB_GetFIFOByte(dat); + dat++; + } + USB_GetLastFIFOByte(dat, fifoNum); +} + +/***************************************************************************//** + * @brief Writes data held in paged XRAM to the USB FIFO + * @details The FIFO to write must be set before calling the function with + * @ref USB_EnableWriteFIFO(). + * @param numBytes + * Number of bytes to write to the FIFO + * @param dat + * Pointer to PDATA buffer holding data to write to the FIFO + ******************************************************************************/ +static void USB_WriteFIFO_Pdata(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_PDATA)) +{ + while (numBytes--) + { + USB_SetFIFOByte(*dat); + dat++; + } +} + +#endif + +#if SI_GPTR_MTYPE_DATA != SI_GPTR_MTYPE_IDATA +/***************************************************************************//** + * @brief Reads data from the USB FIFO to a buffer in DRAM + * @param numBytes + * Number of bytes to read from the FIFO + * @param dat + * Pointer to DATA buffer to hold data read from the FIFO + * @param fifoNum + * USB FIFO to read + ******************************************************************************/ +static void USB_ReadFIFO_Data(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_DATA), uint8_t fifoNum) +{ + while (--numBytes) + { + USB_GetFIFOByte(dat); + dat++; + } + USB_GetLastFIFOByte(dat, fifoNum); +} + +/***************************************************************************//** + * @brief Writes data held in DRAM to the USB FIFO + * @details The FIFO to write must be set before calling the function with + * @ref USB_EnableWriteFIFO(). + * @param numBytes + * Number of bytes to write to the FIFO + * @param dat + * Pointer to DATA buffer to hold data read from the FIFO + ******************************************************************************/ +static void USB_WriteFIFO_Data(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_DATA)) +{ + while (numBytes--) + { + USB_SetFIFOByte(*dat); + dat++; + } +} +#endif + +/***************************************************************************//** + * @brief Writes data held in code space to the USB FIFO + * @details The FIFO to write must be set before calling the function with + * @ref USB_EnableWriteFIFO(). + * @param numBytes + * Number of bytes to write to the FIFO + * @param dat + * Pointer to CODE buffer holding data to write to the FIFO + ******************************************************************************/ +static void USB_WriteFIFO_Code(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_CODE)) +{ + while (numBytes--) + { + USB_SetFIFOByte(*dat); + dat++; + } +} + +#else +/***************************************************************************//** + * @brief Reads data from the USB FIFO to a buffer in generic memory space + * @param numBytes + * Number of bytes to read from the FIFO + * @param dat + * Pointer to generic buffer to hold data read from the FIFO + * @param fifoNum + * USB FIFO to read + ******************************************************************************/ +static void USB_ReadFIFO_Generic(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), uint8_t fifoNum) +{ + while (--numBytes) + { + USB_GetFIFOByte(dat); + dat++; + } + USB_GetLastFIFOByte(dat, fifoNum); +} + +/***************************************************************************//** + * @brief Writes data held in generic memory space to the USB FIFO + * @details The FIFO to write must be set before calling the function with + * @ref USB_EnableWriteFIFO(). + * @param numBytes + * Number of bytes to write to the FIFO + * @param dat + * Pointer to generic buffer holding data to write to the FIFO + ******************************************************************************/ +static void USB_WriteFIFO_Generic(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC)) +{ + while (numBytes--) + { + USB_SetFIFOByte(*dat); + dat++; + } +} + +#endif // #ifdef SI_GPTR diff --git a/efm8/lib/c8051f380/efm8_usb/src/efm8_usbdint.c b/efm8/lib/c8051f380/efm8_usb/src/efm8_usbdint.c new file mode 100644 index 0000000..39d744f --- /dev/null +++ b/efm8/lib/c8051f380/efm8_usb/src/efm8_usbdint.c @@ -0,0 +1,687 @@ +/**************************************************************************//** + * Copyright (c) 2015 by Silicon Laboratories Inc. All rights reserved. + * + * http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt + *****************************************************************************/ + +#include "si_toolchain.h" +#include "efm8_usb.h" +#include +#include + +// ----------------------------------------------------------------------------- +// Global variables + +extern SI_SEGMENT_VARIABLE(myUsbDevice, USBD_Device_TypeDef, MEM_MODEL_SEG); +extern SI_SEGMENT_VARIABLE(txZero[2], const uint8_t, SI_SEG_CODE); + +// ----------------------------------------------------------------------------- +// Function prototypes + +static void handleUsbEp0Int(void); +static void handleUsbResetInt(void); +static void handleUsbSuspendInt(void); +static void handleUsbResumeInt(void); +static void handleUsbEp0Tx(void); +static void handleUsbEp0Rx(void); +static void USB_ReadFIFOSetup(void); + +#if (SLAB_USB_EP1IN_USED) +void handleUsbIn1Int(void); +#endif // SLAB_USB_EP1IN_USED +#if (SLAB_USB_EP2IN_USED) +void handleUsbIn2Int(void); +#endif // SLAB_USB_EP2IN_USED +#if (SLAB_USB_EP3IN_USED) +void handleUsbIn3Int(void); +#endif // SLAB_USB_EP3IN_USED + +#if (SLAB_USB_EP1OUT_USED) +void handleUsbOut1Int(void); +#endif // SLAB_USB_EP1OUT_USED +#if (SLAB_USB_EP2OUT_USED) +void handleUsbOut2Int(void); +#endif // SLAB_USB_EP2OUT_USED +#if (SLAB_USB_EP3OUT_USED) +void handleUsbOut3Int(void); +#endif // SLAB_USB_EP3OUT_USED + +void SendEp0Stall(void); + +#if SLAB_USB_UTF8_STRINGS == 1 +static uint8_t decodeUtf8toUcs2( + const uint8_t *pUtf8in, + SI_VARIABLE_SEGMENT_POINTER(pUcs2out, uint16_t, MEM_MODEL_SEG)); +#endif + +// ----------------------------------------------------------------------------- +// Functions + +/***************************************************************************//** + * @brief First-level handler for USB peripheral interrupt + * @details If @ref SLAB_USB_POLLED_MODE is 1, this becomes a regular + * function instead of an ISR and must be called by the application + * periodically. + ******************************************************************************/ +#if (SLAB_USB_POLLED_MODE == 0) +SI_INTERRUPT(usbIrqHandler, USB0_IRQn) +#else +void usbIrqHandler(void) +#endif +{ + uint8_t statusCommon, statusIn, statusOut, indexSave; + +#if SLAB_USB_HANDLER_CB + // Callback to user before processing + USBD_EnterHandler(); +#endif + + // Get the interrupt sources + statusCommon = USB_GetCommonInts(); + statusIn = USB_GetInInts(); + statusOut = USB_GetOutInts(); + +#if SLAB_USB_POLLED_MODE + if ((statusCommon == 0) && (statusIn == 0) && (statusOut == 0)) + { + return; + } +#endif + + // Save the current index + indexSave = USB_GetIndex(); + + // Check Common USB Interrupts + if (USB_IsSofIntActive(statusCommon)) + { +#if SLAB_USB_SOF_CB + USBD_SofCb(USB_GetSofNumber()); +#endif // SLAB_USB_SOF_CB + + // Check for unhandled USB packets on EP0 and set the corresponding IN or + // OUT interrupt active flag if necessary. + if (((myUsbDevice.ep0.misc.bits.outPacketPending == true) && (myUsbDevice.ep0.state == D_EP_RECEIVING)) || + ((myUsbDevice.ep0.misc.bits.inPacketPending == true) && (myUsbDevice.ep0.state == D_EP_TRANSMITTING))) + { + USB_SetEp0IntActive(statusIn); + } + // Check for unhandled USB OUT packets and set the corresponding OUT + // interrupt active flag if necessary. +#if SLAB_USB_EP1OUT_USED + if ((myUsbDevice.ep1out.misc.bits.outPacketPending == true) && (myUsbDevice.ep1out.state == D_EP_RECEIVING)) + { + USB_SetOut1IntActive(statusOut); + } +#endif +#if SLAB_USB_EP2OUT_USED + if ((myUsbDevice.ep2out.misc.bits.outPacketPending == true) && (myUsbDevice.ep2out.state == D_EP_RECEIVING)) + { + USB_SetOut2IntActive(statusOut); + } +#endif +#if SLAB_USB_EP3OUT_USED + if ((myUsbDevice.ep3out.misc.bits.outPacketPending == true) && (myUsbDevice.ep3out.state == D_EP_RECEIVING)) + { + USB_SetOut3IntActive(statusOut); + } +#endif +#if (SLAB_USB_EP3IN_USED && (SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC)) + if ((myUsbDevice.ep3in.misc.bits.inPacketPending == true) && (myUsbDevice.ep3in.state == D_EP_TRANSMITTING)) + { + USB_SetIn3IntActive(statusIn); + } +#endif + } + + if (USB_IsResetIntActive(statusCommon)) + { + handleUsbResetInt(); + + // If VBUS is not present on detection of a USB reset, enter suspend mode. +#if (SLAB_USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF) + if (USB_IsVbusOn() == false) + { + USB_SetSuspendIntActive(statusCommon); + } +#endif + } + + if (USB_IsResumeIntActive(statusCommon)) + { + handleUsbResumeInt(); + } + + if (USB_IsSuspendIntActive(statusCommon)) + { + handleUsbSuspendInt(); + } + +#if SLAB_USB_EP3IN_USED + if (USB_IsIn3IntActive(statusIn)) + { + handleUsbIn3Int(); + } +#endif // EP3IN_USED + +#if SLAB_USB_EP3OUT_USED + if (USB_IsOut3IntActive(statusOut)) + { + handleUsbOut3Int(); + } +#endif // EP3OUT_USED + +#if SLAB_USB_EP2IN_USED + if (USB_IsIn2IntActive(statusIn)) + { + handleUsbIn2Int(); + } +#endif // EP2IN_USED + +#if SLAB_USB_EP1IN_USED + if (USB_IsIn1IntActive(statusIn)) + { + handleUsbIn1Int(); + } +#endif // EP1IN_USED + +#if SLAB_USB_EP2OUT_USED + if (USB_IsOut2IntActive(statusOut)) + { + handleUsbOut2Int(); + } +#endif // EP2OUT_USED + +#if SLAB_USB_EP1OUT_USED + if (USB_IsOut1IntActive(statusOut)) + { + handleUsbOut1Int(); + } +#endif // EP1OUT_USED + + // Check USB Endpoint 0 Interrupt + if (USB_IsEp0IntActive(statusIn)) + { + handleUsbEp0Int(); + } + + // Restore index + USB_SetIndex(indexSave); + +#if SLAB_USB_HANDLER_CB + // Callback to user before exiting + USBD_ExitHandler(); +#endif +} + +/***************************************************************************//** + * @brief Handles Endpoint 0 transfer interrupt + ******************************************************************************/ +static void handleUsbEp0Int(void) +{ + USB_Status_TypeDef retVal = USB_STATUS_REQ_UNHANDLED; + + USB_SetIndex(0); + + if (USB_Ep0SentStall() || USB_GetSetupEnd()) + { + USB_Ep0ClearSentStall(); + USB_ServicedSetupEnd(); + myUsbDevice.ep0.state = D_EP_IDLE; + myUsbDevice.ep0.misc.c = 0; + } + if (USB_Ep0OutPacketReady()) + { + if (myUsbDevice.ep0.misc.bits.waitForRead == true) + { + myUsbDevice.ep0.misc.bits.outPacketPending = true; + } + else if (myUsbDevice.ep0.state == D_EP_IDLE) + { + myUsbDevice.ep0String.c = USB_STRING_DESCRIPTOR_UTF16LE; + USB_ReadFIFOSetup(); + + // Vendor unique, Class or Standard setup commands override? +#if SLAB_USB_SETUP_CMD_CB + retVal = USBD_SetupCmdCb(&myUsbDevice.setup); + + if (retVal == USB_STATUS_REQ_UNHANDLED) + { +#endif + if (myUsbDevice.setup.bmRequestType.Type == USB_SETUP_TYPE_STANDARD) + { + retVal = USBDCH9_SetupCmd(); + } +#if SLAB_USB_SETUP_CMD_CB + } +#endif + + // Reset index to 0 in case the call to USBD_SetupCmdCb() or + // USBDCH9_SetupCmd() changed it. + USB_SetIndex(0); + + // Put the Enpoint 0 hardware into the correct state here. + if (retVal == USB_STATUS_OK) + { + // If wLength is 0, there is no Data Phase + // Set both the Serviced Out Packet Ready and Data End bits + if (myUsbDevice.setup.wLength == 0) + { + USB_Ep0SetLastOutPacketReady(); + } + // If wLength is non-zero, there is a Data Phase. + // Set only the Serviced Out Packet Ready bit. + else + { + USB_Ep0ServicedOutPacketReady(); + +#if SLAB_USB_SETUP_CMD_CB + // If OUT packet but callback didn't set up a USBD_Read and we are expecting a + // data byte then we need to wait for the read to be setup and NACK packets until + // USBD_Read is called. + if ((myUsbDevice.setup.bmRequestType.Direction == USB_SETUP_DIR_OUT) + && (myUsbDevice.ep0.state != D_EP_RECEIVING)) + { + myUsbDevice.ep0.misc.bits.waitForRead = true; + } +#endif + } + } + // If the setup transaction detected an error, send a stall + else + { + SendEp0Stall(); + } + } + else if (myUsbDevice.ep0.state == D_EP_RECEIVING) + { + handleUsbEp0Rx(); + } + else + { + myUsbDevice.ep0.misc.bits.outPacketPending = true; + } + } + if ((myUsbDevice.ep0.state == D_EP_TRANSMITTING) && (USB_Ep0InPacketReady() == 0)) + { + handleUsbEp0Tx(); + } +} + +/***************************************************************************//** + * @brief Reads and formats a setup packet + ******************************************************************************/ +static void USB_ReadFIFOSetup(void) +{ + SI_VARIABLE_SEGMENT_POINTER(ptr, uint16_t, MEM_MODEL_SEG) = (SI_VARIABLE_SEGMENT_POINTER(, uint16_t, MEM_MODEL_SEG))&myUsbDevice.setup; + + USB_ReadFIFO(0, 8, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))ptr); + + // Modify for Endian-ness of the compiler + ptr[1] = le16toh(ptr[1]); + ptr[2] = le16toh(ptr[2]); + ptr[3] = le16toh(ptr[3]); +} + +/***************************************************************************//** + * @brief Handles USB port reset interrupt + * @details After receiving a USB reset, halt all endpoints except for + * Endpoint 0, set the device state, and configure USB hardware. + ******************************************************************************/ +static void handleUsbResetInt(void) +{ + // Setup EP0 to receive SETUP packets + myUsbDevice.ep0.state = D_EP_IDLE; + + // Halt all other endpoints +#if SLAB_USB_EP1IN_USED + myUsbDevice.ep1in.state = D_EP_HALT; +#endif +#if SLAB_USB_EP2IN_USED + myUsbDevice.ep2in.state = D_EP_HALT; +#endif +#if SLAB_USB_EP3IN_USED + myUsbDevice.ep3in.state = D_EP_HALT; +#endif +#if SLAB_USB_EP1OUT_USED + myUsbDevice.ep1out.state = D_EP_HALT; +#endif +#if SLAB_USB_EP2OUT_USED + myUsbDevice.ep2out.state = D_EP_HALT; +#endif +#if SLAB_USB_EP3OUT_USED + myUsbDevice.ep3out.state = D_EP_HALT; +#endif + + // After a USB reset, some USB hardware configurations will be reset and must + // be reconfigured. + + // Re-enable clock recovery +#if SLAB_USB_CLOCK_RECOVERY_ENABLED +#if SLAB_USB_FULL_SPEED + USB_EnableFullSpeedClockRecovery(); +#else + USB_EnableLowSpeedClockRecovery(); +#endif +#endif + + // Re-enable USB interrupts + USB_EnableSuspendDetection(); + USB_EnableDeviceInts(); + + // If the device is bus-powered, always put it in the Default state. + // If the device is self-powered and VBUS is present, put the device in the + // Default state. Otherwise, put it in the Attached state. +#if (!SLAB_USB_BUS_POWERED) && \ + (!(SLAB_USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF)) + if (USB_IsVbusOn()) + { + USBD_SetUsbState(USBD_STATE_DEFAULT); + } + else + { + USBD_SetUsbState(USBD_STATE_ATTACHED); + } +#else + USBD_SetUsbState(USBD_STATE_DEFAULT); +#endif // (!(SLAB_USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF)) + +#if SLAB_USB_RESET_CB + // Make the USB Reset Callback + USBD_ResetCb(); +#endif +} + +/***************************************************************************//** + * @brief Handle USB port suspend interrupt + * @details After receiving a USB reset, set the device state and + * call @ref USBD_Suspend() if configured to do so in + * @ref SLAB_USB_PWRSAVE_MODE + ******************************************************************************/ +static void handleUsbSuspendInt(void) +{ + if (myUsbDevice.state >= USBD_STATE_POWERED) + { + USBD_SetUsbState(USBD_STATE_SUSPENDED); + +#if (SLAB_USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONSUSPEND) + USBD_Suspend(); +#endif + } +} + +/***************************************************************************//** + * @brief Handles USB port resume interrupt + * @details Restore the device state to its previous value. + ******************************************************************************/ +static void handleUsbResumeInt(void) +{ + USBD_SetUsbState(myUsbDevice.savedState); +} + +/***************************************************************************//** + * @brief Handles transmit data phase on Endpoint 0 + ******************************************************************************/ +static void handleUsbEp0Tx(void) +{ + uint8_t count, count_snapshot, i; + bool callback = myUsbDevice.ep0.misc.bits.callback; + + // The number of bytes to send in the next packet must be less than or equal + // to the maximum EP0 packet size. + count = (myUsbDevice.ep0.remaining >= USB_EP0_SIZE) ? + USB_EP0_SIZE : myUsbDevice.ep0.remaining; + + // Save the packet size for future use. + count_snapshot = count; + + // Strings can use the USB_STRING_DESCRIPTOR_UTF16LE_PACKED type to pack + // UTF16LE data without the zero's between each character. + // If the current string is of type USB_STRING_DESCRIPTOR_UTF16LE_PACKED, + // unpack it by inserting a zero between each character in the string. + if ((myUsbDevice.ep0String.encoding.type == USB_STRING_DESCRIPTOR_UTF16LE_PACKED) +#if SLAB_USB_UTF8_STRINGS == 1 + || (myUsbDevice.ep0String.encoding.type == USB_STRING_DESCRIPTOR_UTF8) +#endif + ) + { + // If ep0String.encoding.init is true, this is the beginning of the string. + // The first two bytes of the string are the bLength and bDescriptorType + // fields. These are not packed like the reset of the string, so write them + // to the FIFO and set ep0String.encoding.init to false. + if (myUsbDevice.ep0String.encoding.init == true) + { + USB_WriteFIFO(0, 2, myUsbDevice.ep0.buf, false); + myUsbDevice.ep0.buf += 2; + count -= 2; + myUsbDevice.ep0String.encoding.init = false; + } + + // Insert a 0x00 between each character of the string. + for (i = 0; i < count / 2; i++) + { +#if SLAB_USB_UTF8_STRINGS == 1 + if (myUsbDevice.ep0String.encoding.type == USB_STRING_DESCRIPTOR_UTF8) + { + SI_SEGMENT_VARIABLE(ucs2, uint16_t, MEM_MODEL_SEG); + uint8_t utf8count; + + // decode the utf8 into ucs2 for usb string + utf8count = decodeUtf8toUcs2(myUsbDevice.ep0.buf, &ucs2); + + // if consumed utf8 bytes is 0, it means either null byte was + // input or bad utf8 byte sequence. Either way its an error and + // there's not much we can do. So just advance the input string + // by one character and keep going until count is expired. + if (utf8count == 0) + { + utf8count = 1; + } + + // adjust to next char in utf8 byte sequence + myUsbDevice.ep0.buf += utf8count; + ucs2 = htole16(ucs2); // usb 16-bit chars are little endian + USB_WriteFIFO(0, 2, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))&ucs2, false); + } + else +#endif + { + USB_WriteFIFO(0, 1, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))myUsbDevice.ep0.buf, false); + myUsbDevice.ep0.buf++; + USB_WriteFIFO(0, 1, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))&txZero, false); + } + } + } + // For any data other than USB_STRING_DESCRIPTOR_UTF16LE_PACKED, just send the + // data normally. + else + { + USB_WriteFIFO(0, count, myUsbDevice.ep0.buf, false); + myUsbDevice.ep0.buf += count; + } + + myUsbDevice.ep0.misc.bits.inPacketPending = false; + myUsbDevice.ep0.remaining -= count_snapshot; + + // If the last packet of the transfer is exactly the maximum EP0 packet size, + // we will have to send a ZLP (zero-length packet) after the last data packet + // to signal to the host that the transfer is complete. + // Check for the ZLP packet case here. + if ((myUsbDevice.ep0.remaining == 0) && (count_snapshot != USB_EP0_SIZE)) + { + USB_Ep0SetLastInPacketReady(); + myUsbDevice.ep0.state = D_EP_IDLE; + myUsbDevice.ep0String.c = USB_STRING_DESCRIPTOR_UTF16LE; + myUsbDevice.ep0.misc.c = 0; + } + else + { + // Do not call USB_Ep0SetLastInPacketReady() because we still need to send + // the ZLP. + USB_Ep0SetInPacketReady(); + } + // Make callback if requested + if (callback == true) + { + USBD_XferCompleteCb(EP0, USB_STATUS_OK, count_snapshot, myUsbDevice.ep0.remaining); + } +} + +/***************************************************************************//** + * @brief Handles receive data phase on Endpoint 0 + ******************************************************************************/ +void handleUsbEp0Rx(void) +{ + uint8_t count; + USB_Status_TypeDef status; + bool callback = myUsbDevice.ep0.misc.bits.callback; + + // Get the number of bytes received + count = USB_Ep0GetCount(); + + // If the call to USBD_Read() did not give a large enough buffer to hold this + // data, set the outPacketPending flag and signal an RX overrun. + if (myUsbDevice.ep0.remaining < count) + { + myUsbDevice.ep0.state = D_EP_IDLE; + myUsbDevice.ep0.misc.bits.outPacketPending = true; + status = USB_STATUS_EP_RX_BUFFER_OVERRUN; + } + else + { + USB_ReadFIFO(0, count, myUsbDevice.ep0.buf); + myUsbDevice.ep0.buf += count; + myUsbDevice.ep0.remaining -= count; + status = USB_STATUS_OK; + + // If the last packet of the transfer is exactly the maximum EP0 packet + // size, we will must wait to receive a ZLP (zero-length packet) after the + // last data packet. This signals that the host has completed the transfer. + // Check for the ZLP packet case here. + if ((myUsbDevice.ep0.remaining == 0) && (count != USB_EP0_SIZE)) + { + USB_Ep0SetLastOutPacketReady(); + myUsbDevice.ep0.state = D_EP_IDLE; + myUsbDevice.ep0.misc.bits.callback = false; + } + else + { + // Do not call USB_Ep0SetLastOutPacketReady() until we get the ZLP. + USB_Ep0ServicedOutPacketReady(); + } + } + + // Make callback if requested + if (callback == true) + { + USBD_XferCompleteCb(EP0, status, count, myUsbDevice.ep0.remaining); + } +} + + +/***************************************************************************//** + * @brief Send a procedural stall on Endpoint 0 + ******************************************************************************/ +void SendEp0Stall(void) +{ + USB_SetIndex(0); + myUsbDevice.ep0.state = D_EP_STALL; + USB_Ep0SendStall(); +} + +#if SLAB_USB_UTF8_STRINGS == 1 +/***************************************************************************//** + * Decodes UTF-8 to UCS-2 (16-bit) character encoding that is used + * for USB string descriptors. + * + * @param pUtf8in pointer to next character in UTF-8 string + * @param pUcs2out pointer to location for 16-bit character output + * + * Decodes a UTF-8 byte sequence into a single UCS-2 character. This + * will only decode up to 16-bit code point and will not handle the + * 21-bit case (4 bytes input). + * + * For valid cases, the UTF8 character sequence decoded into a 16-bit + * character and stored at the location pointed at by _pUcs2out_. + * The function will then return the number of input bytes that were + * consumed (1, 2, or 3). The caller can use the return value to find + * the start of the next character sequence in a utf-8 string. + * + * If either of the input pointers are NULL, then 0 is returned. + * + * If the first input character is NULL, then the output 16-bit value + * will be set to NULL and the function will return 0. + * + * If any other invalid sequence is detected, then the 16-bit output + * will be set to the equivalent of the question mark character (0x003F) + * and the return code will be 0. + * + * @return count of UTF8 bytes consumed + ******************************************************************************/ +static uint8_t decodeUtf8toUcs2( + const uint8_t *pUtf8in, + SI_VARIABLE_SEGMENT_POINTER(pUcs2out, uint16_t, MEM_MODEL_SEG)) +{ + uint8_t ret = 0; + + // check the input pointers + if (!pUtf8in || !pUcs2out) + { + return 0; + } + + // set default decode to error '?'; + *pUcs2out = '?'; + + // valid cases: + // 0xxxxxxx (7 bits) + // 110xxxxx 10xxxxxx (11 bits) + // 1110xxxx 10xxxxxx 10xxxxxx (16 bits) + + // null input + if (pUtf8in[0] == 0) + { + *pUcs2out = 0; + ret = 0; + } + + // 7-bit char + else if (pUtf8in[0] < 128) + { + *pUcs2out = pUtf8in[0]; + ret = 1; + } + + // 11-bit char + else if ((pUtf8in[0] & 0xE0) == 0xC0) + { + if ((pUtf8in[1] & 0xC0) == 0x80) + { + *pUcs2out = ((pUtf8in[0] & 0x1F) << 6) | (pUtf8in[1] & 0x3F); + ret = 2; + } + } + + // 16-bit char + else if ((pUtf8in[0] & 0xF0) == 0xE0) + { + if ((pUtf8in[1] & 0xC0) == 0x80) + { + if ((pUtf8in[2] & 0xC0) == 0x80) + { + *pUcs2out = ((pUtf8in[0] & 0x0F) << 12) + | ((pUtf8in[1] & 0x3F) << 6) + | (pUtf8in[2] & 0x3F); + ret = 3; + } + } + } + + return ret; +} +#endif // SLAB_USB_UTF8_STRINGS + +// This function is called from USBD_Init(). It forces the user project to pull +// this module from the library so that the declared ISR can be seen and +// included. If this is not done then this entire module by never be included +// and the ISR will not be present. +void forceModuleLoad_usbint(void){} diff --git a/efm8/lib/c8051f380/efm8ub1/peripheralDrivers/inc/usb_0.h b/efm8/lib/c8051f380/efm8ub1/peripheralDrivers/inc/usb_0.h new file mode 100644 index 0000000..d094fde --- /dev/null +++ b/efm8/lib/c8051f380/efm8ub1/peripheralDrivers/inc/usb_0.h @@ -0,0 +1,2091 @@ +/***************************************************************************//** + * Copyright (c) 2015 by Silicon Laboratories Inc. All rights reserved. + * + * http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt + ******************************************************************************/ + +#ifndef __SILICON_LABS_EFM8_USB_0_H__ +#define __SILICON_LABS_EFM8_USB_0_H__ + +#include "SI_EFM8UB1_Register_Enums.h" +#include +#include + +/******************************************************************************/ + +/** + * + * @addtogroup usb_0_group USB0 Driver + * @{ + * + * @brief Peripheral driver for USB 0 + * + * # Introduction # + * + * This module provides an API for using the USB0 peripheral. + * The API provides access to the USB hardware. A full-featured + * USB stack (EFM8 USB Library) is available in the SDK at "\lib\efm8_usb." + * The primary purpose of this USB peripheral driver is to abstract hardware + * accesses so that the EFM8 USB Library can run on multiple EFM8 devices + * (e.g. EFM8UB1, EFM8UB2). However, this driver can also be used to build + * custom USB stacks and applications in cases where greater optimization or + * performance than what the EFM8 USB Library provides is required. + * + ******************************************************************************/ + +/***************************************************************************//** + * @addtogroup usb_0_runtime USB0 Runtime API + * @brief + * Functions and macros to access the USB hardware. + * @{ + ******************************************************************************/ + +// ------------------------------- +// Macros + +/***************************************************************************//** + * @brief Reads an indirect USB register + * @details Sets USB0ADR and polls on the busy bit. + * When the macro completes, the value can be read from USB0DAT. + * @param addr + * The address of the USB indirect register to read + * @return The value of the USB indirect register is held in USB0DAT. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern uint8_t USB_READ_BYTE(uint8_t addr); +#else +#define USB_READ_BYTE(addr) \ + do \ + { \ + USB0ADR = (USB0ADR_BUSY__SET | (addr)); \ + while (USB0ADR & USB0ADR_BUSY__SET) {} \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Writes an indirect USB register + * @details Sets USB0ADR, writes a value to USB0DAT, and waits for the busy + * bit to clear. + * @param addr + * The address of the USB indirect register to read + * @param dat + * The value to write to the USB indirect register + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_WRITE_BYTE(uint8_t addr, uint8_t dat); +#else +#define USB_WRITE_BYTE(addr, dat) \ + do \ + { \ + USB0ADR = (addr); \ + USB0DAT = (dat); \ + while (USB0ADR & USB0ADR_BUSY__SET) {} \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Sets bits in an indirect USB register + * @details Sets the bits in the bitmask of the indirect USB register + * without disturbing the value of other bits in the indirect + * register. + * @param addr + * The address of the USB indirect register to write + * @param bitmask + * The bits to set + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SET_BITS(uint8_t addr, uint8_t bitmask); +#else +#define USB_SET_BITS(addr, bitmask) \ + do \ + { \ + USB0ADR = (USB0ADR_BUSY__SET | (addr)); \ + while (USB0ADR & USB0ADR_BUSY__SET) {} \ + USB0DAT = (USB0DAT | (bitmask)); \ + while (USB0ADR & USB0ADR_BUSY__SET) {} \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Clears bits in an indirect USB register + * @details Clears the bits in the bitmask of an indirect USB register + * without disturbing the value of other bits in the indirect + * register. + * @param addr + * The address of the USB indirect register to write + * @param bitmask + * The bits to clear + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_CLEAR_BITS(uint8_t addr, uint8_t bitmask); +#else +#define USB_CLEAR_BITS(addr, bitmask) \ + do \ + { \ + USB0ADR = (USB0ADR_BUSY__SET | (addr)); \ + while (USB0ADR & USB0ADR_BUSY__SET) {} \ + USB0DAT = (USB0DAT & ~(bitmask)); \ + while (USB0ADR & USB0ADR_BUSY__SET) {} \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Enables USB interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnableInts(void); +#else +#define USB_EnableInts() \ + do \ + { \ + SFRPAGE = PG2_PAGE; \ + EIE2 |= EIE2_EUSB0__ENABLED; \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Disables USB interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisableInts(void); +#else +#define USB_DisableInts() \ + do \ + { \ + SFRPAGE = PG2_PAGE; \ + EIE2 &= ~EIE2_EUSB0__ENABLED; \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Returns state of USB interrupt enabler + * @return TRUE if USB interrupts are enabled, FALSE otherwise. + ******************************************************************************/ +extern bool USB_GetIntsEnabled(void); + +/***************************************************************************//** + * @brief Enables VBUS detection + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_VbusDetectEnable(void); +#else +#define USB_VbusDetectEnable() \ + do \ + { \ + SFRPAGE = PG3_PAGE; \ + USB0CF |= USB0CF_VBUSEN__ENABLED; \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Disables VBUS detection + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_VbusDetectDisable(void); +#else +#define USB_VbusDetectDisable() \ + do \ + { \ + SFRPAGE = PG3_PAGE; \ + USB0CF &= ~USB0CF_VBUSEN__ENABLED; \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Check status of VBUS signal + * @return TRUE if VBUS signal is present, FALSE otherwise. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern bool USB_IsVbusOn(void); +#else +#define USB_IsVbusOn() ((bool) P3_B1) +#endif + +/***************************************************************************//** + * @brief Enables the USB pull-up resistor + * @details Enables either the D+ or the D- pull-up resistor, depending on + * whether @ref USB_SelectFullSpeed() or @ref USB_SelectLowSpeed() + * was previously called. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnablePullUpResistor(void); +#else +#define USB_EnablePullUpResistor() \ + do \ + { \ + SFRPAGE = PG3_PAGE; \ + USB0XCN |= USB0XCN_PREN__PULL_UP_ENABLED; \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Disables the USB pull-up resistor + * @details Disables either the D+ or the D- pull-up resistor, depending on + * whether @ref USB_SelectFullSpeed() or @ref USB_SelectLowSpeed() + * was previously called. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisablePullUpResistor(void); +#else +#define USB_DisablePullUpResistor() \ + do \ + { \ + SFRPAGE = PG3_PAGE; \ + USB0XCN &= ~USB0XCN_PREN__PULL_UP_ENABLED; \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Enables the USB transceiver + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnableTransceiver(void); +#else +#define USB_EnableTransceiver() \ + do \ + { \ + SFRPAGE = PG3_PAGE; \ + USB0XCN |= USB0XCN_PHYEN__ENABLED; \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Disables the USB transceiver + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisableTransceiver(void); +#else +#define USB_DisableTransceiver() \ + do \ + { \ + SFRPAGE = PG3_PAGE; \ + USB0XCN &= ~USB0XCN_PHYEN__ENABLED; \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Puts the USB in full-speed mode. + * @details Configures the USB to operate as a full-speed device by + * enabling the D+ pull-up resistor. After calling this + * function, the user must call @ref USB_EnablePullUpResistor(). + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SelectFullSpeed(void); +#else +#define USB_SelectFullSpeed() \ + do \ + { \ + SFRPAGE = PG3_PAGE; \ + USB0XCN |= USB0XCN_SPEED__FULL_SPEED; \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Puts the USB in low-speed mode. + * @details Configures the USB to operate as a low-speed device by + * enabling the D- pull-up resistor. After calling this + * function, the user must call @ref USB_EnablePullUpResistor(). + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SelectLowSpeed(void); +#else +#define USB_SelectLowSpeed() \ + do \ + { \ + SFRPAGE = PG3_PAGE; \ + USB0XCN &= ~USB0XCN_SPEED__FULL_SPEED; \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Suspends the transceiver + * @details Puts the USB transceiver in suspend mode. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SuspendTransceiver(void); +#else +#define USB_SuspendTransceiver() \ + do \ + { \ + SFRPAGE = PG3_PAGE; \ + USB0XCN &= ~(USB0XCN_PHYEN__ENABLED | USB0XCN_Dp__HIGH | USB0XCN_Dn__HIGH);\ + } while (0) +#endif + +/***************************************************************************//** + * @brief Selects the internal oscillator as the USB clock + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SetClockIntOsc(void); +#else +#define USB_SetClockIntOsc() \ + do \ + { \ + SFRPAGE = PG3_PAGE; \ + USB0CF &= ~USB0CF_USBCLK__FMASK; \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Selects the internal oscillator / 8 as the USB clock + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SetClockIntOscDiv8(void); +#else +#define USB_SetClockIntOscDiv8() \ + do \ + { \ + SFRPAGE = PG3_PAGE; \ + USB0CF &= ~USB0CF_USBCLK__FMASK; \ + USB0CF |= USB0CF_USBCLK__HFOSC1_DIV_8; \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Selects the external oscillator as the USB clock + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SetClockExtOsc(void); +#else +#define USB_SetClockExtOsc() \ + do \ + { \ + SFRPAGE = PG3_PAGE; \ + USB0CF &= ~USB0CF_USBCLK__FMASK; \ + USB0CF |= USB0CF_USBCLK__EXTOSC; \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Selects the external oscillator / 2 as the USB clock + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SetClockExtOscDiv2(void); +#else +#define USB_SetClockExtOscDiv2() \ + do \ + { \ + SFRPAGE = PG3_PAGE; \ + USB0CF &= ~USB0CF_USBCLK__FMASK; \ + USB0CF |= USB0CF_USBCLK__EXTOSC_DIV_2; \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Selects the external oscillator / 3 as the USB clock + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SetClockExtOscDiv3(void); +#else +#define USB_SetClockExtOscDiv3() \ + do \ + { \ + SFRPAGE = PG3_PAGE; \ + USB0CF &= ~USB0CF_USBCLK__FMASK; \ + USB0CF |= USB0CF_USBCLK__EXTOSC_DIV_3; \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Selects the external oscillator / 4 as the USB clock + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SetClockExtOscDiv4(void); +#else +#define USB_SetClockExtOscDiv4() \ + do \ + { \ + SFRPAGE = PG3_PAGE; \ + USB0CF &= ~USB0CF_USBCLK__FMASK; \ + USB0CF |= USB0CF_USBCLK__EXTOSC_DIV_4; \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Selects the low-frequency oscillator as the USB clock + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SetClockLfo(void); +#else +#define USB_SetClockLfo() \ + do \ + { \ + SFRPAGE = PG3_PAGE; \ + USB0CF &= ~USB0CF_USBCLK__FMASK; \ + USB0CF |= USB0CF_USBCLK__LFOSC; \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Selects the normal setting for the USB clock + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SetNormalClock(void); +#else +#define USB_SetNormalClock() USB_SetClockIntOsc() +#endif + +/***************************************************************************//** + * @brief Selects the low-power setting for the USB clock + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SetSuspendClock(void); +#else +#define USB_SetSuspendClock() USB_SetClockIntOscDiv8() +#endif + +/***************************************************************************//** + * @brief Suspends REG1 + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SuspendRegulator(void); +#else +#define USB_SuspendRegulator() \ + do \ + { \ + SFRPAGE = PG3_PAGE; \ + REG1CN |= REG1CN_SUSEN__SUSPEND; \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Does not use regulator low-power modes + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SuspendRegulatorFastWake(void); +#else +#define USB_SuspendRegulatorFastWake() +#endif + +/***************************************************************************//** + * @brief Takes REG0 and REG1 out of suspend + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_UnsuspendRegulator(void); +#else +#define USB_UnsuspendRegulator() \ + do \ + { \ + SFRPAGE = PG3_PAGE; \ + REG1CN &= ~REG1CN_SUSEN__SUSPEND; \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Determine if the internal regulator is enabled + * @return TRUE if the internal regulator is enabled, FALSE otherwise + ******************************************************************************/ +extern bool USB_IsRegulatorEnabled(void); + +/***************************************************************************//** + * @brief Disable the prefetch engine + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisablePrefetch(void); +#else +#define USB_DisablePrefetch() \ + do \ + { \ + SFRPAGE = PG2_PAGE; \ + PFE0CN &= ~(PFE0CN_PFEN__ENABLED | PFE0CN_FLRT__SYSCLK_BELOW_50_MHZ); \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Enable the prefetch engine + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnablePrefetch(void); +#else +#define USB_EnablePrefetch() \ + do \ + { \ + SFRPAGE = PG2_PAGE; \ + PFE0CN |= (PFE0CN_PFEN__ENABLED | PFE0CN_FLRT__SYSCLK_BELOW_50_MHZ); \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Determine if the prefetch engine is enabled + * @return TRUE if prefetch engine is enabled, FALSE otherwise. + ******************************************************************************/ +extern bool USB_IsPrefetchEnabled(void); + +/***************************************************************************//** + * @brief Suspends internal oscillator + ******************************************************************************/ +extern void USB_SuspendOscillator(void); + +/***************************************************************************//** + * @brief Enables clock recovery in full speed mode + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnableFullSpeedClockRecovery(void); +#else +#define USB_EnableFullSpeedClockRecovery() \ + USB_WRITE_BYTE(CLKREC, (CLKREC_CRE__ENABLED | 0x0F)) +#endif + +/***************************************************************************//** + * @brief Enables clock recovery in low speed mode + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnableLowSpeedClockRecovery(void); +#else +#define USB_EnableLowSpeedClockRecovery() \ + USB_WRITE_BYTE(CLKREC, \ + (CLKREC_CRE__ENABLED \ + | CLKREC_CRLOW__LOW_SPEED \ + | 0x0F)) +#endif + +/***************************************************************************//** + * @brief Disables clock recovery + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisableClockRecovery(void); +#else +#define USB_DisableClockRecovery() USB_WRITE_BYTE(CLKREC, 0x0F) +#endif + +/***************************************************************************//** + * @brief Sets the USB function address + * @param addr + * USB Function Address value + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SetAddress(uint8_t addr); +#else +#define USB_SetAddress(addr) \ + USB_WRITE_BYTE(FADDR, (FADDR_UPDATE__SET | (addr))) +#endif + +/***************************************************************************//** + * @brief Disable the USB Inhibit feature + * @details The USB block is inhibited after a power-on-reset or an + * asynchronous reset. Software should disable the inhibit bit + * after all USB and transceiver initialization is complete. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisableInhibit(void); +#else +#define USB_DisableInhibit() \ + USB_WRITE_BYTE(POWER, (POWER_USBINH__ENABLED | POWER_SUSEN__ENABLED)) +#endif + +/***************************************************************************//** + * @brief Forces a USB reset + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_ForceReset(void); +#else +#define USB_ForceReset() USB_WRITE_BYTE(POWER, POWER_USBRST__SET) +#endif + +/***************************************************************************//** + * @brief Forces USB resume signaling + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_ForceResume(void); +#else +#define USB_ForceResume() \ + USB_WRITE_BYTE(POWER, (POWER_RESUME__START | POWER_SUSEN__ENABLED)) +#endif + +/***************************************************************************//** + * @brief Clears USB resume signaling + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_ClearResume(void); +#else +#define USB_ClearResume() USB_WRITE_BYTE(POWER, POWER_SUSEN__ENABLED) +#endif + +/***************************************************************************//** + * @brief Enables USB suspend detection + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnableSuspendDetection(void); +#else +#define USB_EnableSuspendDetection() USB_WRITE_BYTE(POWER, POWER_SUSEN__ENABLED) +#endif + +/***************************************************************************//** + * @brief Disables USB suspend detection + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisableSuspendDetection(void); +#else +#define USB_DisableSuspendDetection() USB_WRITE_BYTE(POWER, 0) +#endif + +/***************************************************************************//** + * @brief Setup End Serviced + * @details Software should call this function after servicing a Setup End + * event. Setup End is detected by calling usbGetSetupEnd + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_ServicedSetupEnd(void); +#else +#define USB_ServicedSetupEnd() \ + USB_WRITE_BYTE(E0CSR, E0CSR_SSUEND__SET) +#endif + +/***************************************************************************//** + * @brief Out Packet Ready Serviced + * @details Software should call this function after servicing a received + * Endpoint 0 packet. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_Ep0ServicedOutPacketReady(void); +#else +#define USB_Ep0ServicedOutPacketReady() \ + USB_WRITE_BYTE(E0CSR, E0CSR_SOPRDY__SET) +#endif + +/***************************************************************************//** + * @brief Sets In Packet Ready and Data End on Endpoint 0 + * @details This should be called instead of @ref USB_Ep0SetInPacketReady() + * when sending the last packet of a setup data phase. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_Ep0SetLastInPacketReady(void); +#else +#define USB_Ep0SetLastInPacketReady() \ + USB_WRITE_BYTE(E0CSR, (E0CSR_INPRDY__SET | E0CSR_DATAEND__SET)) +#endif + +/***************************************************************************//** + * @brief Sets In Packet Ready and Data End on Endpoint 0 + * @details This should be called instead of @ref USB_Ep0SetInPacketReady() + * when sending a zero-length packet. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_Ep0SetZLPInPacketReady(void); +#else +#define USB_Ep0SetZLPInPacketReady() \ + USB_WRITE_BYTE(E0CSR, (E0CSR_INPRDY__SET | E0CSR_DATAEND__SET)) +#endif + +/***************************************************************************//** + * @brief Serviced Out Packet Ready and Data End on Endpoint 0 + * @details This should be called instead of @ref USB_ServicedSetupEnd() + * after servicing the last incoming data packet. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_Ep0SetLastOutPacketReady(void); +#else +#define USB_Ep0SetLastOutPacketReady() \ + USB_WRITE_BYTE(E0CSR, (E0CSR_SOPRDY__SET | E0CSR_DATAEND__SET)) +#endif + +/***************************************************************************//** + * @brief Sends a stall on Endpoint 0 + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_Ep0SendStall(void); +#else +#define USB_Ep0SendStall() \ + USB_WRITE_BYTE(E0CSR, (E0CSR_SOPRDY__SET | E0CSR_SDSTL__SET)) +#endif + +/***************************************************************************//** + * @brief Clears sent stall condition on Endpoint 0 + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_Ep0ClearSentStall(void); +#else +#define USB_Ep0ClearSentStall() USB_WRITE_BYTE(E0CSR, 0) +#endif + +/***************************************************************************//** + * @brief Sets InPacketReady on Endpoint 0 + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_Ep0SetInPacketReady(void); +#else +#define USB_Ep0SetInPacketReady() USB_WRITE_BYTE(E0CSR, E0CSR_INPRDY__SET) +#endif + +/***************************************************************************//** + * @brief Returns state of USB Start-of-Frame Interrupt + * @param CMINT_snapshot + * Snapshot of the CMINT register taken previously with the + * @ref USB_GetCommonInts() function. + * @return TRUE if Start-of-Frame Interrupt is active, FALSE otherwise. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern bool USB_IsSofIntActive(uint8_t CMINT_snapshot); +#else +#define USB_IsSofIntActive(CMINT_snapshot) ((CMINT_snapshot) & CMINT_SOF__SET) +#endif + +/***************************************************************************//** + * @brief Returns state of USB Reset Interrupt + * @param CMINT_snapshot + * Snapshot of the CMINT register taken previously with the + * @ref USB_GetCommonInts() function. + * @return TRUE if USB Reset Interrupt is active, FALSE otherwise. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern bool USB_IsResetIntActive(uint8_t CMINT_snapshot); +#else +#define USB_IsResetIntActive(CMINT_snapshot) \ + ((CMINT_snapshot) & CMINT_RSTINT__SET) +#endif + +/***************************************************************************//** + * @brief Returns state of USB Resume Interrupt + * @param CMINT_snapshot + * Snapshot of the CMINT register taken previously with the + * @ref USB_GetCommonInts() function. + * @return TRUE if USB Resume Interrupt is active, FALSE otherwise. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern bool USB_IsResumeIntActive(uint8_t CMINT_snapshot); +#else +#define USB_IsResumeIntActive(CMINT_snapshot) \ + ((CMINT_snapshot) & CMINT_RSUINT__SET) +#endif + +/***************************************************************************//** + * @brief Returns state of USB Suspend Interrupt + * @param CMINT_snapshot + * Snapshot of the CMINT register taken previously with the + * @ref USB_GetCommonInts() function. + * @return TRUE if USB Suspend Interrupt is active, FALSE otherwise. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern bool USB_IsSuspendIntActive(uint8_t CMINT_snapshot); +#else +#define USB_IsSuspendIntActive(CMINT_snapshot) \ + ((CMINT_snapshot) & CMINT_SUSINT__SET) +#endif + +/***************************************************************************//** + * @brief Returns state of USB Endpoint 0 Interrupt + * @param IN1INT_snapshot + * Snapshot of the IN1INT register taken previously with the + * @ref USB_GetInInts() function. + * @return TRUE if USB Endpoint 0 Interrupt is active, FALSE otherwise. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern bool USB_IsEp0IntActive(uint8_t IN1INT_snapshot); +#else +#define USB_IsEp0IntActive(IN1INT_snapshot) \ + ((IN1INT_snapshot) & IN1INT_EP0__SET) +#endif + +/***************************************************************************//** + * @brief Returns 1 if any USB IN Interrupt is active + * @param IN1INT_snapshot + * Snapshot of the IN1INT register taken previously with the + * @ref USB_GetInInts() function. + * @return TRUE if any USB IN Interrupt is active, FALSE otherwise. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern bool USB_IsInIntActive(uint8_t IN1INT_snapshot); +#else +#define USB_IsInIntActive(IN1INT_snapshot) \ + ((IN1INT_snapshot) & (IN1INT_IN1__SET | IN1INT_IN2__SET | IN1INT_IN3__SET)) +#endif + +/***************************************************************************//** + * @brief Returns state of USB Endpoint 1 IN Interrupt + * @param IN1INT_snapshot + * Snapshot of the IN1INT register taken previously with the + * @ref USB_GetInInts() function. + * @return TRUE if USB Endpoint 1 IN Interrupt is active, FALSE otherwise. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern bool USB_IsIn1IntActive(uint8_t IN1INT_snapshot); +#else +#define USB_IsIn1IntActive(IN1INT_snapshot) \ + ((IN1INT_snapshot) & IN1INT_IN1__SET) +#endif + +/***************************************************************************//** + * @brief Returns state of USB Endpoint 2 IN Interrupt + * @param IN1INT_snapshot + * Snapshot of the IN1INT register taken previously with the + * @ref USB_GetInInts() function. + * @return TRUE if USB Endpoint 2 IN Interrupt is active, FALSE otherwise. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern bool USB_IsIn2IntActive(uint8_t IN1INT_snapshot); +#else +#define USB_IsIn2IntActive(IN1INT_snapshot) \ + ((IN1INT_snapshot) & IN1INT_IN2__SET) +#endif + +/***************************************************************************//** + * @brief Returns state of USB Endpoint 3 IN Interrupt + * @param IN1INT_snapshot + * Snapshot of the IN1INT register taken previously with the + * @ref USB_GetInInts() function. + * @return TRUE if USB Endpoint 3 IN Interrupt is active, FALSE otherwise. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern bool USB_IsIn3IntActive(uint8_t IN1INT_snapshot); +#else +#define USB_IsIn3IntActive(IN1INT_snapshot) \ + ((IN1INT_snapshot) & IN1INT_IN3__SET) +#endif + +/***************************************************************************//** + * @brief Returns 1 if any USB Endpoint OUT Interrupt is active + * @param OUT1INT_snapshot + * Snapshot of the OUT1INT register taken previously with the + * @ref USB_GetOutInts() function. + * @return TRUE if any USB OUT Interrupt is active, FALSE otherwise. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern bool USB_IsOutIntActive(uint8_t OUT1INT_snapshot); +#else +#define USB_IsOutIntActive(OUT1INT_snapshot) \ + ((OUT1INT_snapshot) \ + & (OUT1INT_OUT1__SET | OUT1INT_OUT2__SET | OUT1INT_OUT3__SET)) +#endif + +/***************************************************************************//** + * @brief Returns state of USB Endpoint 1 OUT Interrupt + * @param OUT1INT_snapshot + * Snapshot of the OUT1INT register taken previously with the + * @ref USB_GetOutInts() function. + * @return TRUE if USB Endpoint 1 OUT Interrupt is active, + * FALSE otherwise. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern bool USB_IsOut1IntActive(uint8_t OUT1INT_snapshot); +#else +#define USB_IsOut1IntActive(OUT1INT_snapshot) \ + ((OUT1INT_snapshot) & OUT1INT_OUT1__SET) +#endif + +/***************************************************************************//** + * @brief Returns state of USB Endpoint 2 OUT Interrupt + * @param OUT1INT_snapshot + * Snapshot of the OUT1INT register taken previously with the + * @ref USB_GetOutInts() function. + * @return TRUE if USB Endpoint 2 OUT Interrupt is active, + * FALSE otherwise. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern bool USB_IsOut2IntActive(uint8_t OUT1INT_snapshot); +#else +#define USB_IsOut2IntActive(OUT1INT_snapshot) \ + ((OUT1INT_snapshot) & OUT1INT_OUT2__SET) +#endif + +/***************************************************************************//** + * @brief Returns state of USB Endpoint 3 OUT Interrupt + * @param OUT1INT_snapshot + * Snapshot of the OUT1INT register taken previously with the + * @ref USB_GetOutInts() function. + * @return TRUE if USB Endpoint 3 OUT Interrupt is active, + * FALSE otherwise. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern bool USB_IsOut3IntActive(uint8_t OUT1INT_snapshot); +#else +#define USB_IsOut3IntActive(OUT1INT_snapshot) \ + ((OUT1INT_snapshot) & OUT1INT_OUT3__SET) +#endif + +/***************************************************************************//** + * @brief Sets the suspend interrupt flag to active + * @param CMINT_snapshot + * Snapshot of the CMINT register taken previously with the + * @ref USB_GetCommonInts() function. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SetSuspendIntActive(uint8_t CMINT_snapshot); +#else +#define USB_SetSuspendIntActive(CMINT_snapshot) \ + ((CMINT_snapshot) |= CMINT_SUSINT__SET) +#endif + +/***************************************************************************//** + * @brief Sets the EP0 interrupt flag to active + * @param IN1INT_snapshot + * Snapshot of the IN1INT register taken previously with the + * @ref USB_GetInInts() function. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SetEp0IntActive(uint8_t IN1INT_snapshot); +#else +#define USB_SetEp0IntActive(IN1INT_snapshot) \ + ((IN1INT_snapshot) |= IN1INT_EP0__SET) +#endif + +/***************************************************************************//** + * @brief Sets the IN 1 interrupt flag to active + * @param IN1INT_snapshot + * Snapshot of the IN1INT register taken previously with the + * @ref USB_GetInInts() function. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SetIn1IntActive(uint8_t IN1INT_snapshot); +#else +#define USB_SetIn1IntActive(IN1INT_snapshot) \ + ((IN1INT_snapshot) |= IN1INT_IN1__SET) +#endif + +/***************************************************************************//** + * @brief Sets the IN 12interrupt flag to active + * @param IN1INT_snapshot + * Snapshot of the IN1INT register taken previously with the + * @ref USB_GetInInts() function. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SetIn2IntActive(uint8_t IN1INT_snapshot); +#else +#define USB_SetIn2IntActive(IN1INT_snapshot) \ + ((IN1INT_snapshot) |= IN1INT_IN2__SET) +#endif + +/***************************************************************************//** + * @brief Sets the IN 3 interrupt flag to active + * @param IN1INT_snapshot + * Snapshot of the IN1INT register taken previously with the + * @ref USB_GetInInts() function. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SetIn3IntActive(uint8_t IN1INT_snapshot); +#else +#define USB_SetIn3IntActive(IN1INT_snapshot) \ + ((IN1INT_snapshot) |= IN1INT_IN3__SET) +#endif + +/***************************************************************************//** + * @brief Sets the OUT 1 interrupt flag to active + * @param OUT1INT_snapshot + * Snapshot of the OUT1INT register taken previously with the + * @ref USB_GetOutInts() function. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SetOut1IntActive(uint8_t OUT1INT_snapshot); +#else +#define USB_SetOut1IntActive(OUT1INT_snapshot) \ + ((OUT1INT_snapshot) |= OUT1INT_OUT1__SET) +#endif + +/***************************************************************************//** + * @brief Sets the OUT 2 interrupt flag to active + * @param OUT1INT_snapshot + * Snapshot of the OUT1INT register taken previously with the + * @ref USB_GetOutInts() function. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SetOut2IntActive(uint8_t OUT1INT_snapshot); +#else +#define USB_SetOut2IntActive(OUT1INT_snapshot) \ + ((OUT1INT_snapshot) |= OUT1INT_OUT2__SET) +#endif + +/***************************************************************************//** + * @brief Sets the OUT 3 interrupt flag to active + * @param OUT1INT_snapshot + * Snapshot of the OUT1INT register taken previously with the + * @ref USB_GetOutInts() function. + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SetOut3IntActive(uint8_t OUT1INT_snapshot); +#else +#define USB_SetOut3IntActive(OUT1INT_snapshot) \ + ((OUT1INT_snapshot) |= OUT1INT_OUT3__SET) +#endif + +/***************************************************************************//** + * @brief Enables USB Start-of-Frame, Reset, Resume, and + * Suspend Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnableDeviceInts(void); +#else +#define USB_EnableDeviceInts() \ + USB_WRITE_BYTE(CMIE, \ + (CMIE_SOFE__ENABLED \ + | CMIE_RSTINTE__ENABLED \ + | CMIE_RSUINTE__ENABLED \ + | CMIE_SUSINTE__ENABLED)) +#endif + +/***************************************************************************//** + * @brief Enables USB Start-of-Frame Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnableSofInt(void); +#else +#define USB_EnableSofInt() USB_SET_BITS(CMIE, CMIE_SOFE__ENABLED) +#endif + +/***************************************************************************//** + * @brief Disables USB Start-of-Frame Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisableSofInt(void); +#else +#define USB_DisableSofInt() USB_CLEAR_BITS(CMIE, CMIE_SOFE__ENABLED) +#endif + +/***************************************************************************//** + * @brief Enables USB Reset Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnableResetInt(void); +#else +#define USB_EnableResetInt() USB_SET_BITS(CMIE, CMIE_RSTINTE__ENABLED) +#endif + +/***************************************************************************//** + * @brief Disables USB Reset Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisableResetInt(void); +#else +#define USB_DisableResetInt() USB_CLEAR_BITS(CMIE, CMIE_RSTINTE__ENABLED) +#endif + +/***************************************************************************//** + * @brief Enables USB Resume Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnableResumeInt(void); +#else +#define USB_EnableResumeInt() USB_SET_BITS(CMIE, CMIE_RSUINTE__ENABLED) +#endif + +/***************************************************************************//** + * @brief Disables USB Resume Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisableResumeInt(void); +#else +#define USB_DisableResumeInt() USB_CLEAR_BITS(CMIE, CMIE_RSUINTE__ENABLED) +#endif + +/***************************************************************************//** + * @brief Enables USB Suspend Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnableSuspendInt(void); +#else +#define USB_EnableSuspendInt() USB_SET_BITS(CMIE, CMIE_SUSINTE__ENABLED) +#endif + +/***************************************************************************//** + * @brief Disables USB Suspend Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisableSuspendInt(void); +#else +#define USB_DisableSuspendInt() USB_CLEAR_BITS(CMIE, CMIE_SUSINTE__ENABLED) +#endif + +/***************************************************************************//** + * @brief Enables USB Endpoint 0 Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnableEp0Int(void); +#else +#define USB_EnableEp0Int() USB_SET_BITS(IN1IE, IN1IE_EP0E__ENABLED) +#endif + +/***************************************************************************//** + * @brief Disables USB Endpoint 0 Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisableEp0Int(void); +#else +#define USB_DisableEp0Int() USB_CLEAR_BITS(IN1IE, IN1IE_EP0E__ENABLED) +#endif + +/***************************************************************************//** + * @brief Enables USB Endpoint 1 IN Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnableIn1Int(void); +#else +#define USB_EnableIn1Int() USB_SET_BITS(IN1IE, IN1IE_IN1E__ENABLED) +#endif + +/***************************************************************************//** + * @brief Disables USB Endpoint 1 IN Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisableIn1Int(void); +#else +#define USB_DisableIn1Int() USB_CLEAR_BITS(IN1IE, IN1IE_IN1E__ENABLED) +#endif + +/***************************************************************************//** + * @brief Enables USB Endpoint 2 IN Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnableIn2Int(void); +#else +#define USB_EnableIn2Int() USB_SET_BITS(IN1IE, IN1IE_IN2E__ENABLED) +#endif + +/***************************************************************************//** + * @brief Disables USB Endpoint 2 IN Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisableIn2Int(void); +#else +#define USB_DisableIn2Int() USB_CLEAR_BITS(IN1IE, IN1IE_IN2E__ENABLED) +#endif + +/***************************************************************************//** + * @brief Enables USB Endpoint 3 IN Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnableIn3Int(void); +#else +#define USB_EnableIn3Int() USB_SET_BITS(IN1IE, IN1IE_IN3E__ENABLED) +#endif + +/***************************************************************************//** + * @brief Disables USB Endpoint 3 IN Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisableIn3Int(void); +#else +#define USB_DisableIn3Int() USB_CLEAR_BITS(IN1IE, IN1IE_IN3E__ENABLED) +#endif + +/***************************************************************************//** + * @brief Enables USB Endpoint 1 OUT Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnableOut1Int(void); +#else +#define USB_EnableOut1Int() USB_SET_BITS(OUT1IE, OUT1IE_OUT1E__ENABLED) +#endif + +/***************************************************************************//** + * @brief Disables USB Endpoint 1 OUT Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisableOut1Int(void); +#else +#define USB_DisableOut1Int() USB_CLEAR_BITS(OUT1IE, OUT1IE_OUT1E__ENABLED) +#endif + +/***************************************************************************//** + * @brief Enables USB Endpoint 2 OUT Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnableOut2Int(void); +#else +#define USB_EnableOut2Int() USB_SET_BITS(OUT1IE, OUT1IE_OUT2E__ENABLED) +#endif + +/***************************************************************************//** + * @brief Disables USB Endpoint 2 OUT Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisableOut2Int(void); +#else +#define USB_DisableOut2Int() USB_CLEAR_BITS(OUT1IE, OUT1IE_OUT2E__ENABLED) +#endif + +/***************************************************************************//** + * @brief Enables USB Endpoint 3 OUT Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnableOut3Int(void); +#else +#define USB_EnableOut3Int() USB_SET_BITS(OUT1IE, OUT1IE_OUT3E__ENABLED) +#endif + +/***************************************************************************//** + * @brief Disables USB Endpoint 3 OUT Interrupts + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisableOut3Int(void); +#else +#define USB_DisableOut3Int() USB_CLEAR_BITS(OUT1IE, OUT1IE_OUT3E__ENABLED) +#endif + +/***************************************************************************//** + * @brief Enables USB Endpoint 1 + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnableEp1(void); +#else +#define USB_EnableEp1() USB_SET_BITS(EENABLE, EENABLE_EEN1__ENABLED) +#endif + +/***************************************************************************//** + * @brief Disables USB Endpoint 1 + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisableEp1(void); +#else +#define USB_DisableEp1() USB_CLEAR_BITS(EENABLE, EENABLE_EEN1__ENABLED) +#endif + +/***************************************************************************//** + * @brief Enables USB Endpoint 2 + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnableEp2(void); +#else +#define USB_EnableEp2() USB_SET_BITS(EENABLE, EENABLE_EEN2__ENABLED) +#endif + +/***************************************************************************//** + * @brief Disables USB Endpoint 2 + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisableEp2(void); +#else +#define USB_DisableEp2() USB_CLEAR_BITS(EENABLE, EENABLE_EEN2__ENABLED) +#endif + +/***************************************************************************//** + * @brief Enables USB Endpoint 3 + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnableEp3(void); +#else +#define USB_EnableEp3() USB_SET_BITS(EENABLE, EENABLE_EEN3__ENABLED) +#endif + +/***************************************************************************//** + * @brief Disables USB Endpoint 3 + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisableEp3(void); +#else +#define USB_DisableEp3() USB_CLEAR_BITS(EENABLE, EENABLE_EEN3__ENABLED) +#endif + +/***************************************************************************//** + * @brief Configures Endpoint N for OUT + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnDirectionOut(void); +#else +#define USB_EpnDirectionOut() USB_CLEAR_BITS(EINCSRH, EINCSRH_DIRSEL__IN) +#endif + +/***************************************************************************//** + * @brief Configures Endpoint N for IN + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnDirectionIn(void); +#else +#define USB_EpnDirectionIn() USB_SET_BITS(EINCSRH, EINCSRH_DIRSEL__IN) +#endif + +/***************************************************************************//** + * @brief Enables split mode on Endpoint N + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnEnableSplitMode(void); +#else +#define USB_EpnEnableSplitMode() \ + USB_SET_BITS(EINCSRH, EINCSRH_SPLIT__ENABLED) +#endif + +/***************************************************************************//** + * @brief Disables split mode Endpoint N + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnDisableSplitMode(void); +#else +#define USB_EpnDisableSplitMode() \ + USB_CLEAR_BITS(EINCSRH, EINCSRH_SPLIT__ENABLED) +#endif + +/***************************************************************************//** + * @brief Resets the IN endpoint data toggle to '0' + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnInClearDataToggle(void); +#else +#define USB_EpnInClearDataToggle() USB_SET_BITS(EINCSRL, EINCSRL_CLRDT__BMASK) +#endif + +/***************************************************************************//** + * @brief Clears sent stall condition on Endpoint N IN + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnInClearSentStall(void); +#else +#define USB_EpnInClearSentStall() USB_WRITE_BYTE(EINCSRL, 0) +#endif + +/***************************************************************************//** + * @brief Sends a stall for each IN token on Endpoint N + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnInStall(void); +#else +#define USB_EpnInStall() USB_WRITE_BYTE(EINCSRL, EINCSRL_SDSTL__SET) +#endif + +/***************************************************************************//** + * @brief Stops stalling for each IN token on Endpoint N + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnInEndStall(void); +#else +#define USB_EpnInEndStall() USB_WRITE_BYTE(EINCSRL, 0) +#endif + +/***************************************************************************//** + * @brief Stops stalling for each IN token on Endpoint N and clears + * the data toggle + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnInEndStallAndClearDataToggle(void); +#else +#define USB_EpnInEndStallAndClearDataToggle() \ + USB_WRITE_BYTE(EINCSRL, EINCSRL_CLRDT__BMASK) +#endif + +/***************************************************************************//** + * @brief Flushes In Endpoint N + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnInFlush(void); +#else +#define USB_EpnInFlush() \ + do \ + { \ + USB_WRITE_BYTE(EINCSRL, EINCSRL_FLUSH__SET); \ + do \ + { \ + USB_READ_BYTE(EINCSRL); \ + } while (USB0DAT & EINCSRL_FLUSH__SET); \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Clears underrun condition on In Endpoint N + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnInClearUnderrun(void); +#else +#define USB_EpnInClearUnderrun() USB_CLEAR_BITS(EINCSRL, EINCSRL_UNDRUN__SET) +#endif + +/***************************************************************************//** + * @brief Sets InPacketReady on In Endpoint N + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnSetInPacketReady(void); +#else +#define USB_EpnSetInPacketReady() USB_SET_BITS(EINCSRL, EINCSRL_INPRDY__SET) +#endif + +/***************************************************************************//** + * @brief Enables double buffering on In Endpoint N + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnInEnableDoubleBuffer(void); +#else +#define USB_EpnInEnableDoubleBuffer() \ + USB_SET_BITS(EINCSRH, EINCSRH_DBIEN__ENABLED) +#endif + +/***************************************************************************//** + * @brief Disables double buffering on In Endpoint N + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnInDisableDoubleBuffer(void); +#else +#define USB_EpnInDisableDoubleBuffer() \ + USB_CLEAR_BITS(EINCSRH, EINCSRH_DBIEN__ENABLED) +#endif + +/***************************************************************************//** + * @brief Configures In Endpoint N for Interrupt/Bulk Mode + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnInEnableInterruptBulkMode(void); +#else +#define USB_EpnInEnableInterruptBulkMode() \ + USB_CLEAR_BITS(EINCSRH, EINCSRH_ISO__ENABLED) +#endif + +/***************************************************************************//** + * @brief Configures In Endpoint N for Isochronous Mode + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnInEnableIsochronousMode(void); +#else +#define USB_EpnInEnableIsochronousMode() \ + USB_SET_BITS(EINCSRH, EINCSRH_ISO__ENABLED) +#endif + +/***************************************************************************//** + * @brief Enables forced data toggle on In Endpoint N + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnInEnableForcedDataToggle(void); +#else +#define USB_EpnInEnableForcedDataToggle() \ + USB_SET_BITS(EINCSRH, EINCSRH_FCDT__ALWAYS_TOGGLE) +#endif + +/***************************************************************************//** + * @brief Disables forced data toggle on In Endpoint N + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnInDisableForcedDataToggle(void); +#else +#define USB_EpnInDisableForcedDataToggle() \ + USB_CLEAR_BITS(EINCSRH, EINCSRH_FCDT__ALWAYS_TOGGLE) +#endif + +/***************************************************************************//** + * @brief Resets the OUT endpoint data toggle to '0' + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnOutClearDataToggle(void); +#else +#define USB_EpnOutClearDataToggle() \ + USB_SET_BITS(EOUTCSRL, EOUTCSRL_CLRDT__BMASK) +#endif + +/***************************************************************************//** + * @brief Clears sent stall condition on Endpoint N OUT + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnOutClearSentStall(void); +#else +#define USB_EpnOutClearSentStall() \ + USB_CLEAR_BITS(EOUTCSRL, EOUTCSRL_STSTL__BMASK) +#endif + +/***************************************************************************//** + * @brief Sends a stall for each OUT token on Endpoint N + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnOutStall(void); +#else +#define USB_EpnOutStall() \ + USB_SET_BITS(EOUTCSRL, EOUTCSRL_SDSTL__SET) +#endif + +/***************************************************************************//** + * @brief Stops stalling for each OUT token on Endpoint N + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnOutEndStall(void); +#else +#define USB_EpnOutEndStall() USB_CLEAR_BITS(EOUTCSRL, EOUTCSRL_SDSTL__SET) +#endif + +/***************************************************************************//** + * @brief Stops stalling for each OUT token on Endpoint N and clears + * the data toggle + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnOutEndStallAndClearDataToggle(void); +#else +#define USB_EpnOutEndStallAndClearDataToggle() \ + do \ + { \ + USB_READ_BYTE(EOUTCSRL); \ + USB0DAT &= ~EOUTCSRL_SDSTL__SET; \ + while (USB0ADR & USB0ADR_BUSY__SET) {} \ + USB0DAT |= EOUTCSRL_CLRDT__BMASK; \ + while (USB0ADR & USB0ADR_BUSY__SET) {} \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Flushes OUT Endpoint N + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnOutFlush(void); +#else +#define USB_EpnOutFlush() \ + do \ + { \ + USB_WRITE_BYTE(EOUTCSRL, EOUTCSRL_FLUSH__SET); \ + do \ + { \ + USB_READ_BYTE(EOUTCSRL); \ + } while (USB0DAT & EOUTCSRL_FLUSH__SET); \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Clears overrun condition on OUT Endpoint N + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnOutClearOverrun(void); +#else +#define USB_EpnOutClearOverrun() USB_CLEAR_BITS(EOUTCSRL, EOUTCSRL_OVRUN__SET) +#endif + +/***************************************************************************//** + * @brief Clears OutPacketReady on Endpoint N + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnClearOutPacketReady(void); +#else +#define USB_EpnClearOutPacketReady() \ + USB_CLEAR_BITS(EOUTCSRL, EOUTCSRL_OPRDY__SET) +#endif + +/***************************************************************************//** + * @brief Enables double buffering on OUT Endpoint N + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnOutEnableDoubleBuffer(void); +#else +#define USB_EpnOutEnableDoubleBuffer() \ + USB_SET_BITS(EOUTCSRH, EOUTCSRH_DBIEN__ENABLED) +#endif + +/***************************************************************************//** + * @brief Disables double buffering on OUT Endpoint N + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnOutDisableDoubleBuffer(void); +#else +#define USB_EpnOutDisableDoubleBuffer() \ + USB_CLEAR_BITS(EOUTCSRH, EOUTCSRH_DBIEN__ENABLED) +#endif + +/***************************************************************************//** + * @brief Configures OUT Endpoint N for Interrupt/Bulk Mode + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnOutEnableInterruptBulkMode(void); +#else +#define USB_EpnOutEnableInterruptBulkMode() \ + USB_CLEAR_BITS(EOUTCSRH, EOUTCSRH_ISO__ENABLED) +#endif + +/***************************************************************************//** + * @brief Configures OUT Endpoint N for Isochronous Mode + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EpnOutEnableIsochronousMode(void); +#else +#define USB_EpnOutEnableIsochronousMode() \ + USB_SET_BITS(EOUTCSRH, EOUTCSRH_ISO__ENABLED) +#endif + +/***************************************************************************//** + * @brief Enables FIFO read + * @param fifoNum + * FIFO to read + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnableReadFIFO(uint8_t fifoNum); +#else +#define USB_EnableReadFIFO(fifoNum) \ + do \ + { \ + while (USB0ADR & USB0ADR_BUSY__SET) {} \ + USB0ADR = (USB0ADR_BUSY__SET \ + | USB0ADR_AUTORD__ENABLED \ + | (FIFO0 | (fifoNum))); \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Disables FIFO read + * @param fifoNum + * FIFO that was read from + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisableReadFIFO(uint8_t fifoNum); +#else +#define USB_DisableReadFIFO(fifoNum) +#endif + +/***************************************************************************//** + * @brief Reads a byte from the FIFO + * @param readDat + * Memory location to write the byte read from the FIFO + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_GetFIFOByte(uint8_t *readDat); +#else +#define USB_GetFIFOByte(readDat) \ + do \ + { \ + while (USB0ADR & USB0ADR_BUSY__SET) {} \ + *(readDat) = USB0DAT; \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Reads the last byte from the FIFO + * @details The last read must be done with the AUTORD bit cleared. + * This prevents the read from triggering another read + * immediately thereafter. + * @param readDat + * Memory location to write the byte read from the FIFO + * @param fifoNum + * FIFO to read + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_GetLastFIFOByte(uint8_t *readDat, uint8_t fifoNum); +#else +#define USB_GetLastFIFOByte(readDat, fifoNum) \ + do \ + { \ + while (USB0ADR & USB0ADR_BUSY__SET) {} \ + USB0ADR = (FIFO0 | (fifoNum));\ + *(readDat) = USB0DAT; \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Enables FIFO write + * @param fifoNum + * FIFO to write + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_EnableWriteFIFO(uint8_t fifoNum); +#else +#define USB_EnableWriteFIFO(fifoNum) \ + do \ + { \ + while (USB0ADR & USB0ADR_BUSY__SET) {} \ + USB0ADR = (FIFO0 | (fifoNum)); \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Disables FIFO write + * @param fifoNum + * FIFO that was written to + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_DisableWriteFIFO(uint8_t fifoNum); +#else +#define USB_DisableWriteFIFO(fifoNum) +#endif + +/***************************************************************************//** + * @brief Writes a byte to the FIFO + * @param writeDat + * Data to write to the FIFO + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SetFIFOByte(uint8_t writeDat); +#else +#define USB_SetFIFOByte(writeDat) \ + do \ + { \ + while (USB0ADR & USB0ADR_BUSY__SET) {} \ + USB0DAT = (writeDat); \ + } while (0) +#endif + +/***************************************************************************//** + * @brief Saves the current SFR page + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_SaveSfrPage(); +#else +#define USB_SaveSfrPage() uint8_t SfrPageSave = SFRPAGE +#endif + +/***************************************************************************//** + * @brief Restores the SFR page + * @note @ref USB_SaveSfrPage() must be called before calling this macro + * @note This function is implemented as a macro. + ******************************************************************************/ +#ifdef IS_DOXYGEN +extern void USB_RestoreSfrPage(); +#else +#define USB_RestoreSfrPage() SFRPAGE = SfrPageSave +#endif + +// ------------------------------- +// Function Prototypes + +/***************************************************************************//** + * @brief Writes a value to INDEX + * @param epsel + * Endpoint index to target + ******************************************************************************/ +extern void USB_SetIndex(uint8_t epsel); + +/***************************************************************************//** + * @brief Reads the USB common interrupt register + * @return Value of CMINT + ******************************************************************************/ +extern uint8_t USB_GetCommonInts(void); + +/***************************************************************************//** + * @brief Reads the USB in interrupt register + * @return Value of IN1INT + ******************************************************************************/ +extern uint8_t USB_GetInInts(void); + +/***************************************************************************//** + * @brief Reads the out interrupt register + * @return Value of OUT1INT + ******************************************************************************/ +extern uint8_t USB_GetOutInts(void); + +/***************************************************************************//** + * @brief Reads the value in INDEX + * @return Value of INDEX + ******************************************************************************/ +extern uint8_t USB_GetIndex(void); + +/***************************************************************************//** + * @brief Determines if the USB is currently suspended + * @return TRUE if USB is in suspend mode + ******************************************************************************/ +extern bool USB_IsSuspended(void); + +/***************************************************************************//** + * @brief Gets Setup End state + * @return TRUE when a control transaction end before software has + * set the DATAEND bit. + ******************************************************************************/ +extern bool USB_GetSetupEnd(void); + +/***************************************************************************//** + * @brief Determines if STALL was send on Endpoint 0 + * @return TRUE after a STALL was sent on Endpoint 0 + ******************************************************************************/ +extern bool USB_Ep0SentStall(void); + +/***************************************************************************//** + * @brief Determines if Out Packet Ready is set on Endpoint 0 + * @return TRUE if Out Packet Ready is set on Endpoint 0 + ******************************************************************************/ +extern bool USB_Ep0InPacketReady(void); + +/***************************************************************************//** + * @brief Determines if In Packet Ready is set on Endpoint 0 + * @return TRUE if In Packet Ready is set on Endpoint 0 + ******************************************************************************/ +extern bool USB_Ep0OutPacketReady(void); + +/***************************************************************************//** + * @brief Gets Endpoint 0 data count + * @return Number of received data bytes in the Endpoint 0 FIFO + ******************************************************************************/ +extern uint8_t USB_Ep0GetCount(void); + +/***************************************************************************//** + * @brief Checks if stall was sent on IN Endpoint N + * @return TRUE if stall was sent on IN Endpoint N, FALSE otherwise + ******************************************************************************/ +extern bool USB_EpnInGetSentStall(void); + +/***************************************************************************//** + * @brief Checks if stall was sent on OUT Endpoint N + * @return TRUE if stall was sent on OUT Endpoint N, FALSE otherwise + ******************************************************************************/ +extern bool USB_EpnGetInPacketReady(void); + +/***************************************************************************//** + * @brief Checks if stall was sent on OUT Endpoint N + * @return TRUE if stall was sent on OUT Endpoint N, FALSE otherwise + ******************************************************************************/ +extern bool USB_EpnOutGetSentStall(void); + +/***************************************************************************//** + * @brief Gets OutPacketReady on OUT Endpoint N + * @return TRUE if OUTPacketReady is set, FALSE otherwise + ******************************************************************************/ +extern bool USB_EpnGetOutPacketReady(void); + +/***************************************************************************//** + * @brief Gets DataError on OUT Endpoint N + * @return TRUE if Data Error bit is set, FALSE otherwise + ******************************************************************************/ +extern bool USB_EpnGetDataError(void); + +/***************************************************************************//** + * @brief Gets number of bytes in the OUT FIFO + * OUT packet + * @return Number of bytes in the FIFO from the last received + * packet + ******************************************************************************/ +extern uint16_t USB_EpOutGetCount(void); + +/***************************************************************************//** + * @brief Reads the USB frame number + * @return The frame number on the most recent SOF packet + ******************************************************************************/ +extern uint16_t USB_GetSofNumber(void); + +/***************************************************************************//** + * @brief Aborts pending IN transactions on the selected endpoint + * @param fifoNum + * Endpoint to abort + ******************************************************************************/ +extern void USB_AbortInEp(uint8_t fifoNum); + +/***************************************************************************//** + * @brief Aborts pending OUT transactions on the selected endpoint + * @param fifoNum + * Endpoint to abort + ******************************************************************************/ +extern void USB_AbortOutEp(uint8_t fifoNum); + +/***************************************************************************//** + * @brief Activates the selected endpoint + * @param ep + * Endpoint to access + * @param packetSize + * Maximum packet size for endpoint + * @param inDir + * Set to 1 if endpoint is IN, 0 if it is OUT + * @param splitMode + * Set to 1 if endpoint is in split mode, 0 if it is not + * @param isoMode + * Set to 1 if endpoint is in isochronous mode, 0 if it is not + ******************************************************************************/ +extern void USB_ActivateEp(uint8_t ep, + uint16_t packetSize, + bool inDir, + bool splitMode, + bool isoMode); + +/** @} (end addtogroup usb_0_runtime USB0 Runtime API) */ +/** @} (end addtogroup usb_0_group USB0 Driver) */ + +// ----------------------------------------------------------------------------- +// Error Checking + +// ------------------------------- +// Verify that the maximum packet size specified for an endpoint is not too +// large for that endpoint + +#ifdef SLAB_USB_EP1IN_USED + #if SLAB_USB_EP1IN_USED + #if SLAB_USB_EP1IN_TRANSFER_TYPE == USB_EPTYPE_ISOC + #error Isochronous transfers are not supported on Endpoint 1. + #else // #if SLAB_USB_EP1IN_TRANSFER_TYPE == USB_EPTYPE_ISOC + #if SLAB_USB_EP1IN_MAX_PACKET_SIZE > 64 + #error EP1IN packet size too large. Interrupt/Bulk packet size must be 64 bytes or less. + #endif // #if SLAB_USB_EP1IN_MAX_PACKET_SIZE > 64 + #endif // #if SLAB_USB_EP1IN_TRANSFER_TYPE == USB_EPTYPE_ISOC + #endif // #if SLAB_USB_EP1IN_USED +#endif // #ifdef SLAB_USB_EP1IN_USED + +#ifdef SLAB_USB_EP1OUT_USED + #if SLAB_USB_EP1OUT_USED + #if SLAB_USB_EP1OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC + #error Isochronous transfers are not supported on Endpoint 1. + #else // #if SLAB_USB_EP1OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC + #if SLAB_USB_EP1OUT_MAX_PACKET_SIZE > 64 + #error EP1OUT packet size too large. Interrupt/Bulk packet size must be 64 bytes or less. + #endif // #if SLAB_USB_EP1OUT_MAX_PACKET_SIZE > 64 + #endif // #if SLAB_USB_EP1OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC + #endif // #if SLAB_USB_EP1OUT_USED +#endif // #ifdef SLAB_USB_EP1OUT_USED + +#ifdef SLAB_USB_EP2IN_USED + #if SLAB_USB_EP2IN_USED + #if SLAB_USB_EP2IN_TRANSFER_TYPE == USB_EPTYPE_ISOC + #error Isochronous transfers are not supported on Endpoint 2. + #else // #if SLAB_USB_EP2IN_TRANSFER_TYPE == USB_EPTYPE_ISOC + #if SLAB_USB_EP2IN_MAX_PACKET_SIZE > 64 + #error EP2IN packet size too large. Interrupt/Bulk packet size must be 64 bytes or less. + #endif // #if SLAB_USB_EP2IN_MAX_PACKET_SIZE > 64 + #endif // #if SLAB_USB_EP2IN_TRANSFER_TYPE == USB_EPTYPE_ISOC + #endif // #if SLAB_USB_EP2IN_USED +#endif // #ifdef SLAB_USB_EP2IN_USED + +#ifdef SLAB_USB_EP2OUT_USED + #if SLAB_USB_EP2OUT_USED + #if SLAB_USB_EP2OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC + #error Isochronous transfers are not supported on Endpoint 2. + #else // #if SLAB_USB_EP2OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC + #if SLAB_USB_EP2OUT_MAX_PACKET_SIZE > 64 + #error EP2OUT packet size too large. Interrupt/Bulk packet size must be 64 bytes or less. + #endif // #if SLAB_USB_EP2OUT_MAX_PACKET_SIZE > 64 + #endif // #if SLAB_USB_EP2OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC + #endif // #if SLAB_USB_EP2OUT_USED +#endif // #ifdef SLAB_USB_EP2OUT_USED + +#ifdef SLAB_USB_EP3IN_USED + #if SLAB_USB_EP3IN_USED + #if SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC + #if SLAB_USB_EP3OUT_USED + #if SLAB_USB_EP3IN_MAX_PACKET_SIZE > 256 + #error EP3IN packet size too large. FIFO 3 split mode packet size must be 256 bytes or less. + #endif // #if SLAB_USB_EP3IN_MAX_PACKET_SIZE > 256 + #else // #if SLAB_USB_EP3OUT_USED + #if SLAB_USB_EP3IN_MAX_PACKET_SIZE > 512 + #error EP3IN packet size too large. FIFO 3 packet size must be 512 bytes or less. + #endif // #if SLAB_USB_EP3IN_MAX_PACKET_SIZE > 512 + #endif // #if SLAB_USB_EP3OUT_USED + #else // #if SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC + #if SLAB_USB_EP3IN_MAX_PACKET_SIZE > 64 + #error EP3IN packet size too large. Interrupt/Bulk packet size must be 64 bytes or less. + #endif // #if SLAB_USB_EP3IN_MAX_PACKET_SIZE > 64 + #endif // #if SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC + #endif // #if SLAB_USB_EP3IN_USED +#endif // #ifdef SLAB_USB_EP3IN_USED + +#ifdef SLAB_USB_EP3OUT_USED + #if SLAB_USB_EP3OUT_USED + #if SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC + #if SLAB_USB_EP3IN_USED + #if SLAB_USB_EP3OUT_MAX_PACKET_SIZE > 256 + #error EP3OUT packet size too large. FIFO 3 split mode packet size must be 256 bytes or less. + #endif // #if SLAB_USB_EP3OUT_MAX_PACKET_SIZE > 256 + #else // #if SLAB_USB_EP3IN_USED + #if SLAB_USB_EP3OUT_MAX_PACKET_SIZE > 512 + #error EP3OUT packet size too large. FIFO 3 packet size must be 512 bytes or less. + #endif // #if SLAB_USB_EP3OUT_MAX_PACKET_SIZE > 512 + #endif // #if SLAB_USB_EP3IN_USED + #else // #if SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC + #if SLAB_USB_EP3OUT_MAX_PACKET_SIZE > 64 + #error EP3OUT packet size too large. Interrupt/Bulk packet size must be 64 bytes or less. + #endif // #if SLAB_USB_EP3OUT_MAX_PACKET_SIZE > 64 + #endif // #if SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC + #endif // #if SLAB_USB_EP3OUT_USED +#endif // #ifdef SLAB_USB_EP3OUT_USED + +#endif // __SILICON_LABS_EFM8_USB_0_H__ diff --git a/efm8/lib/c8051f380/efm8ub1/peripheralDrivers/src/usb_0.c b/efm8/lib/c8051f380/efm8ub1/peripheralDrivers/src/usb_0.c new file mode 100644 index 0000000..91a03ea --- /dev/null +++ b/efm8/lib/c8051f380/efm8ub1/peripheralDrivers/src/usb_0.c @@ -0,0 +1,238 @@ +/**************************************************************************//** + * Copyright (c) 2015 by Silicon Laboratories Inc. All rights reserved. + * + * http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt + *****************************************************************************/ + +#include "usb_0.h" +#include +#include + +/** @addtogroup usb_0_runtime USB0 Runtime API */ + +// ----------------------------------------------------------------------------- +// Functions + +// ------------------------------- +// Utility Functions + +/**************************************************************************//** + * @brief Reads a 16-bit indirect USB register value + * @param [in] regAddr + * Address of high byte of 16-bit USB indirect register to read + * @return 16-bit register value + *****************************************************************************/ +static uint16_t USB_GetShortRegister(uint8_t regAddr) +{ + uint16_t retVal; + + USB_READ_BYTE(regAddr); + retVal = (USB0DAT << 8); + USB_READ_BYTE((regAddr - 1)); + retVal |= USB0DAT; + + return retVal; +} + +// ------------------------------- +// USB0 Peripheral Driver Functions + +void USB_SetIndex(uint8_t epsel) +{ + USB_WRITE_BYTE(INDEX, epsel); +} + +uint8_t USB_GetCommonInts(void) +{ + USB_READ_BYTE(CMINT); + return USB0DAT; +} + +uint8_t USB_GetInInts(void) +{ + USB_READ_BYTE(IN1INT); + return USB0DAT; +} + +uint8_t USB_GetOutInts(void) +{ + USB_READ_BYTE(OUT1INT); + return USB0DAT; +} + +uint8_t USB_GetIndex(void) +{ + USB_READ_BYTE(INDEX); + return USB0DAT; +} + +bool USB_IsSuspended(void) +{ + USB_READ_BYTE(POWER); + return USB0DAT & POWER_SUSMD__SUSPENDED; +} + +bool USB_GetSetupEnd(void) +{ + USB_READ_BYTE(E0CSR); + return USB0DAT & E0CSR_SUEND__SET; +} + +bool USB_Ep0SentStall(void) +{ + USB_READ_BYTE(E0CSR); + return USB0DAT & E0CSR_STSTL__SET; +} + +bool USB_Ep0OutPacketReady(void) +{ + USB_READ_BYTE(E0CSR); + return USB0DAT & E0CSR_OPRDY__SET; +} + +bool USB_Ep0InPacketReady(void) +{ + USB_READ_BYTE(E0CSR); + return USB0DAT & E0CSR_INPRDY__SET; +} + +uint8_t USB_Ep0GetCount(void) +{ + USB_READ_BYTE(E0CNT); + return USB0DAT; +} + +bool USB_EpnInGetSentStall(void) +{ + USB_READ_BYTE(EINCSRL); + return (bool)(USB0DAT & EINCSRL_STSTL__SET); +} + +void USB_AbortInEp(uint8_t fifoNum) +{ + USB_SetIndex(fifoNum); + USB_EpnInFlush(); + USB_EpnInFlush(); +} + +bool USB_EpnOutGetSentStall(void) +{ + USB_READ_BYTE(EOUTCSRL); + return (bool)(USB0DAT & EOUTCSRL_STSTL__SET); +} + +bool USB_EpnGetOutPacketReady(void) +{ + USB_READ_BYTE(EOUTCSRL); + return (bool)(USB0DAT & EOUTCSRL_OPRDY__SET); +} + +bool USB_EpnGetDataError(void) +{ + USB_READ_BYTE(EOUTCSRL); + return (bool)(USB0DAT & EOUTCSRL_DATERR__SET); +} + +uint16_t USB_EpOutGetCount(void) +{ + return USB_GetShortRegister(EOUTCNTH); +} + +void USB_AbortOutEp(uint8_t fifoNum) +{ + USB_SetIndex(fifoNum); + USB_EpnOutFlush(); + USB_EpnOutFlush(); +} + +void USB_ActivateEp(uint8_t ep, + uint16_t packetSize, + bool inDir, + bool splitMode, + bool isoMode) +{ + uint8_t CSRH_mask = 0; + uint16_t fifoSize; + + USB_SetIndex(ep); + + // Determine the available fifoSize for a given endpoint based on the + // splitMode setting + fifoSize = (splitMode == true) ? (16 << ep) : (32 << ep); + + if (packetSize <= fifoSize) + { + CSRH_mask |= EINCSRH_DBIEN__ENABLED; + } + + if (isoMode == true) + { + CSRH_mask |= EINCSRH_ISO__ENABLED; + } + + if (inDir == true) + { + CSRH_mask |= EINCSRH_DIRSEL__IN; + + if (splitMode == true) + { + CSRH_mask |= EINCSRH_SPLIT__ENABLED; + } + USB_WRITE_BYTE(EINCSRL, EINCSRL_CLRDT__BMASK); + USB_WRITE_BYTE(EINCSRH, CSRH_mask); + } + else // OUT + { + USB_WRITE_BYTE(EOUTCSRL, EOUTCSRL_CLRDT__BMASK); + USB_WRITE_BYTE(EOUTCSRH, CSRH_mask); + + if (splitMode == false) + { + USB_WRITE_BYTE(EINCSRH, 0); + } + } +} + +uint16_t USB_GetSofNumber(void) +{ + return USB_GetShortRegister(FRAMEH); +} + +bool USB_GetIntsEnabled(void) +{ + SFRPAGE = PG2_PAGE; + return (bool)(EIE2 & EIE2_EUSB0__ENABLED); +} + +bool USB_IsPrefetchEnabled(void) +{ + SFRPAGE = PG2_PAGE; + return (bool)(PFE0CN & PFE0CN_PFEN__ENABLED); +} + +bool USB_IsRegulatorEnabled(void) +{ + SFRPAGE = PG3_PAGE; + return !(REG1CN & REG1CN_REG1ENB__DISABLED); +} + +void USB_SuspendOscillator(void) +{ + uint8_t clkSelSave = CLKSEL & 0x7F; + + CLKSEL = (CLKSEL_CLKDIV__SYSCLK_DIV_8 | CLKSEL_CLKSL__HFOSC0); + SFRPAGE = LEGACY_PAGE; + PCON1 |= PCON1_SUSPEND__SUSPEND; + CLKSEL = clkSelSave; + + // If the target frequency is over 24MHz, our write to CLKSEL will be ignored. + // If this is the case we need to do two writes: one to 24 MHz followed by the + // actual value. + if ((CLKSEL & 0x7F) != clkSelSave) + { + CLKSEL = (CLKSEL_CLKDIV__SYSCLK_DIV_1 | CLKSEL_CLKSL__HFOSC0); + CLKSEL = clkSelSave; + } +} + +/** @} (end addtogroup usb_0_runtime USB0 Runtime API) */ diff --git a/efm8/lib/efm8_assert/assert.c b/efm8/lib/efm8_assert/assert.c index b9a65c7..e96edfd 100644 --- a/efm8/lib/efm8_assert/assert.c +++ b/efm8/lib/efm8_assert/assert.c @@ -3,10 +3,13 @@ * * http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt *****************************************************************************/ - + #ifndef NDEBUG -void slab_Assert() +void slab_Assert( const char * file, int line ) { + file = file; + line = line; + while ( 1 ); } #endif diff --git a/efm8/lib/efm8_assert/assert.h b/efm8/lib/efm8_assert/assert.h index 5b951a5..d99ef84 100644 --- a/efm8/lib/efm8_assert/assert.h +++ b/efm8/lib/efm8_assert/assert.h @@ -51,9 +51,9 @@ #ifdef USER_ASSERT #define SLAB_ASSERT(expr) ((expr) ? ((void)0) : USER_ASSERT( __FILE__, __LINE__ )) #else - void slab_Assert(); + void slab_Assert( const char * file, int line ); //Yes this is smaller than if(!expr){assert} - #define SLAB_ASSERT(expr) if(expr){}else{slab_Assert();} + #define SLAB_ASSERT(expr) if(expr){}else{slab_Assert( __FILE__, __LINE__ );} #endif #endif diff --git a/efm8/lib/efm8_usb/Readme.txt b/efm8/lib/efm8_usb/Readme.txt index 8bcff83..059e38b 100644 --- a/efm8/lib/efm8_usb/Readme.txt +++ b/efm8/lib/efm8_usb/Readme.txt @@ -20,7 +20,7 @@ Known Issues and Limitations: Target and Tool Chain Information: --------------------------------- -Target: EFM8UB1, EFM8UB2, EFM8UB3, EFM8UB4, C8051F320/1, C8051F326/7, C8051F34x, C8051F38x +Target: EFM8UB1, EFM8UB2, C8051F320/1, C8051F326/7, C8051F34x, C8051F38x Tool chain: Keil File List: @@ -51,13 +51,6 @@ Version 1.0.1 USB_PWRSAVE_MODE_FASTWAKE was enabled. - Improved documentation of USB_PWRSAVE_MODE_FASTWAKE feature. -Version 1.0.2 - - Added ability to detect short OUT packet in Isochronous mode and - stuff the buffer with zeroes to keep isochronous stream in sync. - -Version 1.0.3 - - Added support for EFM8UB3 and EFM8UB4 devices. - ------------------------------------------------------------------------------- End Of File ------------------------------------------------------------------------------- diff --git a/efm8/lib/efm8_usb/inc/efm8_usb.h b/efm8/lib/efm8_usb/inc/efm8_usb.h index fe70a9c..2581ce3 100644 --- a/efm8/lib/efm8_usb/inc/efm8_usb.h +++ b/efm8/lib/efm8_usb/inc/efm8_usb.h @@ -21,7 +21,6 @@ * * @section usb_device_contents Contents * - * @li @ref usb_device_library_revision * @li @ref usb_device_intro * @li @ref usb_device_api * @li @ref usb_device_conf @@ -29,9 +28,6 @@ * @li @ref usb_device_transfers * @li @ref usb_device_pitfalls * - * @n @section usb_device_library_revision EFM8 USB Library Revision - * Library Revision: 1.0.3 - * * @n @section usb_device_intro Introduction * * The USB device protocol stack provides an API which makes it possible to @@ -112,10 +108,11 @@ * * @ref USBD_RemoteWakeup() @n * Used in SUSPENDED state (see @ref USB_Status_TypeDef) to signal resume to - * host. The function will be called automatically by the library if the - * @ref USBD_RemoteWakeupCb() function returns true. The function will - * also check that the host has sent a SET_FEATURE request to enable Remote - * Wakeup before issuing the resume. + * host. It's the applications responsibility to adhere to the USB standard + * which states that a device can not signal resume before it has been + * SUSPENDED for at least 5 ms. The function will also check that the host + * has sent a SET_FEATURE request to enable Remote Wakeup before issuing the + * resume. * * @ref USBD_GetUsbState() @n * Returns the device USB state (see @ref USBD_State_TypeDef). Refer to @@ -263,16 +260,6 @@ * #define SLAB_USB_LANGUAGE USB_LANGID_ENUS * * // ----------------------------------------------------------------------------- - * // Enable use of UTF-8 strings for string descriptors. - * // If this option is enabled then packed string descriptors that are created - * // with UTF8_PACKED_STATIC_CONST_STRING_DESC() can be UTF-8 encoded and they - * // will be decoded into UCS-2 16-bit wide character format used for USB string - * // descriptors. If this feature is not needed then it can be disabled to save - * // some code memory space. - * // ----------------------------------------------------------------------------- - * #define SLAB_USB_UTF8_STRINGS 1 - * - * // ----------------------------------------------------------------------------- * // Set the power saving mode * // * // SLAB_USB_PWRSAVE_MODE configures when the device will automatically enter @@ -282,17 +269,9 @@ * // USB_PWRSAVE_MODE_ONSUSPEND - Enter USB power-save mode on USB suspend * // USB_PWRSAVE_MODE_ONVBUSOFF - Enter USB power-save mode when not attached * // to the USB host. - * // USB_PWRSAVE_MODE_FASTWAKE - Exit USB power-save mode more quickly, but - * // consume more power while in USB power-save - * // mode. - * // While the device is in USB power-save mode - * // (typically during USB suspend), the - * // internal voltage regulator stays in normal - * // power mode instead of entering suspend - * // power mode. - * // This is an advanced feature that may be - * // useful in certain applications that support - * // remote wakeup. + * // USB_PWRSAVE_MODE_FASTWAKE - Exit USB power-save mode more quickly. + * // This is useful for some applications that + * // support remote wakeup. * // ----------------------------------------------------------------------------- * #define SLAB_USB_PWRSAVE_MODE (USB_PWRSAVE_MODE_ONVBUSOFF \ * | USB_PWRSAVE_MODE_ONSUSPEND) @@ -707,19 +686,14 @@ #endif #ifndef UNREFERENCED_ARGUMENT -#if defined __C51__ /// Macro for removing unreferenced arguments from compiler warnings #define UNREFERENCED_ARGUMENT(arg) (0, arg) -#elif defined __ICC8051__ -/// Macro for removing unreferenced arguments from compiler warnings -#define UNREFERENCED_ARGUMENT(arg) ((void)arg) -#endif #endif /***************************************************************************//** * @brief Macro for creating USB-compliant UTF-16LE UNICODE string * descriptor from a C string. - * @details This macro should be used for ASCII strings in which all + * @details This macro should be used for UTF-8 strings in which all * characters are represented by a single ASCII byte (i.e. * U.S. English strings). * The USB Library will expand variables created with this macro @@ -736,71 +710,9 @@ * @param __val * The value of the string descriptor ******************************************************************************/ -#define UTF16LE_PACKED_STATIC_CONST_STRING_DESC(__name, __val, __size) \ +#define UTF16LE_PACKED_STATIC_CONST_STRING_DESC(__name, __val) \ SI_SEGMENT_VARIABLE(__name, static const USB_StringDescriptor_TypeDef, SI_SEG_CODE) = \ - { USB_STRING_DESCRIPTOR_UTF16LE_PACKED, __size * 2, USB_STRING_DESCRIPTOR, __val } - -/***************************************************************************//** - * @brief Macro for creating USB-compliant UTF-16LE UNICODE string - * descriptor from a UTF-8 string. - * @details This macro should be used for UTF-8 strings in which all - * characters are represented by a valid UTF-8 byte sequence - * of 1-3 bytes per character. The USB library will expand - * variables created with this macro by decoding the UTF-8 - * sequence into 16-bit wide UCS-2 characters required for USB - * string descriptors. - * @n@n This example set an array named _manufacturer[]_ to a - * series of symbols: an anchor, a lightning bolt, and a - * fußball as the Manufacturer String: - * - * #define MFR_STRING "⚓⚡⚽" - * - * // This string has 3 Unicode characters so the __len - * // parameter is 3, even though it will take 3 bytes to - * // represent each character - * UTF8_PACKED_STATIC_CONST_STRING_DESC(manufacturer[], 3, \ - * MFR_STRING); - * @param __name - * The name of the variable that holds the string descriptor - * @param __len - * Number of Unicode characters (or codepoints) in the string - * @param __val - * The value of the string descriptor - ******************************************************************************/ -#define UTF8_PACKED_STATIC_CONST_STRING_DESC(__name, __len, __val) \ - SI_SEGMENT_VARIABLE(__name, static const USB_StringDescriptor_TypeDef, SI_SEG_CODE) = \ - { USB_STRING_DESCRIPTOR_UTF8, (__len) * 2, USB_STRING_DESCRIPTOR, __val } - -/***************************************************************************//** - * @brief Macro for creating USB-compliant UTF-16LE UNICODE string - * descriptor from a UTF-8 string. - * @details This macro should be used for UTF-8 strings in which all - * characters are represented by a valid UTF-8 byte sequence - * of 1-3 bytes per character. The USB library will expand - * variables created with this macro by decoding the UTF-8 - * sequence into 16-bit wide UCS-2 characters required for USB - * string descriptors. - * @n@n This example set an array named _manufacturer[]_ to a - * series of symbols: an anchor, a lightning bolt, and a - * fußball as the Manufacturer String: - * - * #define MFR_STRING "⚓⚡⚽" - * - * // This string has 3 Unicode characters so the __len - * // parameter is 3, even though it will take 3 bytes to - * // represent each character - * UTF8_PACKED_STATIC_CONST_STRING_DESC(manufacturer[], 3, \ - * MFR_STRING); - * @param __name - * The name of the variable that holds the string descriptor - * @param __len - * Number of Unicode characters (or codepoints) in the string - * @param __val - * The value of the string descriptor - ******************************************************************************/ -#define UTF8_PACKED_STATIC_CONST_STRING_DESC(__name, __len, __val) \ - SI_SEGMENT_VARIABLE(__name, static const USB_StringDescriptor_TypeDef, SI_SEG_CODE) = \ - { USB_STRING_DESCRIPTOR_UTF8, (__len) * 2, USB_STRING_DESCRIPTOR, __val } + { USB_STRING_DESCRIPTOR_UTF16LE_PACKED, sizeof(__val) * 2, USB_STRING_DESCRIPTOR, __val } /***************************************************************************//** * @brief Macro for creating USB-compliant UTF-16LE UNICODE string @@ -867,8 +779,8 @@ * The value of the string descriptor ******************************************************************************/ #define LANGID_STATIC_CONST_STRING_DESC(__name, __val) \ - SI_SEGMENT_VARIABLE(__name, static const USB_LangId_StringDescriptor_Typedef, SI_SEG_CODE) = \ - { htole16(((SLAB_USB_NUM_LANGUAGES * 2) + 2) + (USB_STRING_DESCRIPTOR << 8)), __val } + SI_SEGMENT_VARIABLE(__name, static const USB_LangId_StringDescriptor_Typedef, __code) = \ + { (((SLAB_USB_NUM_LANGUAGES * 2) + 2) << 8) + USB_STRING_DESCRIPTOR, __val } /** @} (end addtogroup efm8_usb_macros Macros) */ @@ -897,8 +809,7 @@ typedef enum USB_STATUS_DEVICE_RESET = -11, ///< Device is/was reset. USB_STATUS_TIMEOUT = -12, ///< Transfer timeout. USB_STATUS_DEVICE_REMOVED = -13, ///< Device was removed. - USB_STATUS_EP_RX_BUFFER_OVERRUN = -14, ///< Not enough data in the Rx buffer to hold the - USB_STATUS_DATA_ERROR = -15, ///< OUT packet had CRC or bit-stuffing error + USB_STATUS_EP_RX_BUFFER_OVERRUN = -14 ///< Not enough data in the Rx buffer to hold the ///< last received packet } USB_Status_TypeDef; @@ -952,7 +863,7 @@ typedef enum #if (SLAB_USB_EP3OUT_USED) EP3OUT, #endif -} USB_EP_Index_TypeDef; +}USB_EP_Index_TypeDef; /// @brief USB Setup type. typedef struct @@ -1083,7 +994,7 @@ typedef uint16_t USB_LangId_StringDescriptor_Typedef; ///< The language ID strin #if (SLAB_USB_NUM_LANGUAGES == 1) /// @brief USB String Table Structure. -typedef SI_VARIABLE_SEGMENT_POINTER(, USB_StringDescriptor_TypeDef, SI_SEG_GENERIC) USB_StringTable_TypeDef; +typedef USB_StringDescriptor_TypeDef * *USB_StringTable_TypeDef; #elif (SLAB_USB_NUM_LANGUAGES > 1) typedef struct { @@ -1097,17 +1008,17 @@ typedef struct /// the device. typedef struct { - SI_VARIABLE_SEGMENT_POINTER(deviceDescriptor, USB_DeviceDescriptor_TypeDef, SI_SEG_GENERIC); ///< Pointer to the device descriptor - SI_VARIABLE_SEGMENT_POINTER(configDescriptor, USB_ConfigurationDescriptor_TypeDef, SI_SEG_GENERIC); ///< Pointer to the configuration descriptor - SI_VARIABLE_SEGMENT_POINTER(stringDescriptors, USB_StringTable_TypeDef, SI_SEG_GENERIC); ///< Pointer to an array of string descriptor pointers - uint8_t numberOfStrings; ///< Number of strings in string descriptor array + USB_DeviceDescriptor_TypeDef *deviceDescriptor; ///< Pointer to the device descriptor + uint8_t *configDescriptor; ///< Pointer to the configuration descriptor + USB_StringTable_TypeDef *stringDescriptors; ///< Pointer to an array of string descriptor pointers + uint8_t numberOfStrings; ///< Number of strings in string descriptor array } USBD_Init_TypeDef; /// @cond DO_NOT_INCLUDE_WITH_DOXYGEN // Endpoint structure typedef struct { - SI_VARIABLE_SEGMENT_POINTER(buf, uint8_t, SI_SEG_GENERIC); + uint8_t *buf; uint16_t remaining; USBD_EpState_TypeDef state; union @@ -1171,9 +1082,9 @@ typedef struct #if SLAB_USB_SUPPORT_ALT_INTERFACES uint8_t interfaceAltSetting[SLAB_USB_NUM_INTERFACES]; #endif - SI_VARIABLE_SEGMENT_POINTER(deviceDescriptor, USB_DeviceDescriptor_TypeDef, SI_SEG_GENERIC); - SI_VARIABLE_SEGMENT_POINTER(configDescriptor, USB_ConfigurationDescriptor_TypeDef, SI_SEG_GENERIC); - SI_VARIABLE_SEGMENT_POINTER(stringDescriptors, USB_StringTable_TypeDef, SI_SEG_GENERIC); + USB_DeviceDescriptor_TypeDef *deviceDescriptor; + USB_ConfigurationDescriptor_TypeDef *configDescriptor; + USB_StringTable_TypeDef *stringDescriptors; } USBD_Device_TypeDef; /// @endcond DO_NOT_INCLUDE_WITH_DOXYGEN @@ -1307,10 +1218,6 @@ USB_Status_TypeDef USBDCH9_SetupCmd(void); * * Default setting is '1' and may be overridden by defining in 'usbconfig.h'. * - * @note The EFM8UB1, EFM8UB3, and EFM8UB4 devices can be configured to ignore - * the voltage on the VBUS pin and to instead use that pin as GPIO. If - * this feature is used, SLAB_USB_BUS_POWERED should be set to '1' even if - * the device is not drawing its power from the VBUS line. *****************************************************************************/ /**************************************************************************//** @@ -1343,9 +1250,9 @@ USB_Status_TypeDef USBDCH9_SetupCmd(void); * @brief Enables/disables remote wakeup capability * @details Remote wakeup allow the USB device to wake the host from suspend. * When enabled, the library will call @ref USBD_RemoteWakeupCb() to determine - * if the remote wakeup source caused the device to wake up. If it did, the - * library will exit suspend mode and call @ref USBD_RemoteWakeup() to wake - * up the host. + * if the remote wakeup source caused the device to wake up. If it was, the + * library will exit suspend mode and the application should call + * @ref USBD_RemoteWakeup() to wake up the host. * * When '1' remote wakeup is enabled * When '0' remote wakeup is disabled @@ -1673,25 +1580,6 @@ USB_Status_TypeDef USBDCH9_SetupCmd(void); * *****************************************************************************/ -/**************************************************************************//** - * @def SLAB_USB_UTF8_STRINGS - * @brief - * Enables UTF-8 string decoding for USB string descriptors that are created - * using @ref UTF8_PACKED_STATIC_CONST_STRING_DESC. - * - * @details - * If this option is enabled, USB descriptor strings that are created using - * @ref UTF8_PACKED_STATIC_CONST_STRING_DESC can be encoded as UTF-8 which - * allows for Unicode characters (up to 16-bits wide) to be used for USB - * string descriptors. The UTF-8 strings will be decoded into UCS-2 16-bit - * wide character format required by USB. If this feature is not needed then - * this option can be disabled to save code memory space. If this option is - * disabled, then @ref UTF8_PACKED_STATIC_CONST_STRING_DESC should not be used. - * - * Default setting is '0' and may be overridden by defining in 'usbconfig.h'. - * - *****************************************************************************/ - /**************************************************************************//** * @def SLAB_USB_PWRSAVE_MODE * @brief Configures the power-saving options supported by the device @@ -1856,10 +1744,6 @@ USB_Status_TypeDef USBDCH9_SetupCmd(void); #define SLAB_USB_LANGUAGE USB_LANGID_ENUS #endif -#ifndef SLAB_USB_UTF8_STRINGS -#define SLAB_USB_UTF8_STRINGS 0 -#endif - #ifndef SLAB_USB_PWRSAVE_MODE #define SLAB_USB_PWRSAVE_MODE USB_PWRSAVE_MODE_ONSUSPEND #endif @@ -1956,7 +1840,7 @@ USBD_State_TypeDef USBD_GetUsbState(void); * @return * @ref USB_STATUS_OK on success, else an appropriate error code. ******************************************************************************/ -int8_t USBD_Init(SI_VARIABLE_SEGMENT_POINTER(p, const USBD_Init_TypeDef, SI_SEG_GENERIC)); +int8_t USBD_Init(const USBD_Init_TypeDef *p); /***************************************************************************//** * @brief @@ -1982,8 +1866,8 @@ int8_t USBD_Init(SI_VARIABLE_SEGMENT_POINTER(p, const USBD_Init_TypeDef, SI_SEG_ * @return * @ref USB_STATUS_OK on success, else an appropriate error code. ******************************************************************************/ -int8_t USBD_Read(uint8_t epAddr, - SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), +int8_t USBD_Read(uint8_t epAddr, + uint8_t *dat, uint16_t byteCount, bool callback); @@ -1992,9 +1876,10 @@ int8_t USBD_Read(uint8_t epAddr, * Perform a remote wakeup signaling sequence. * * @note - * This function is typically called by the library if @ref - * USBD_RemoteWakeupCb() returns true, so it does not need to be called by - * application code. + * It is the responsibility of the application to ensure that remote wakeup + * is not attempted before the device has been suspended for at least 5 + * miliseconds. This function should not be called from within an interrupt + * handler. * * @return * @ref USB_STATUS_OK on success, else an appropriate error code. @@ -2030,7 +1915,7 @@ void USBD_Run(void); * @return * @ref USB_STATUS_OK on success, else an appropriate error code. ******************************************************************************/ -int8_t USBD_StallEp(uint8_t epAddr); +int8_t USBD_StallEp(int8_t epAddr); /***************************************************************************//** * @brief @@ -2089,7 +1974,7 @@ int8_t USBD_UnStallEp(uint8_t epAddr); * @ref USB_STATUS_OK on success, else an appropriate error code. ******************************************************************************/ int8_t USBD_Write(uint8_t epAddr, - SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), + uint8_t *dat, uint16_t byteCount, bool callback); @@ -2228,8 +2113,8 @@ USB_Status_TypeDef USBD_SetInterfaceCb(uint8_t interface, uint8_t altSetting); * If remote wakeup is enabled via @ref SLAB_USB_REMOTE_WAKEUP_ENABLED, the * USB library will query the application after waking from suspend to see if * the remote wakeup source was the reason for the wakeup. If this function - * returns True, the library will call @ref USBD_RemoteWakeup() to wake up the - * host and exit suspend mode. + * returns True, the library will exit suspend mode and the application should + * call @ref USBD_RemoteWakeup() to wake up the host. * @return * True if the remote wakeup source was the reason the device woke from * suspend, false otherwise. @@ -2311,8 +2196,8 @@ uint16_t USBD_XferCompleteCb(uint8_t epAddr, \ /// @cond DO_NOT_INCLUDE_WITH_DOXYGEN // -------------------- FIFO Access Functions --------------------------------- -void USB_ReadFIFO(uint8_t fifoNum, uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC)); -void USB_WriteFIFO(uint8_t fifoNum, uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), bool txPacket); +void USB_ReadFIFO(uint8_t fifoNum, uint8_t numBytes, uint8_t *dat); +void USB_WriteFIFO(uint8_t fifoNum, uint8_t numBytes, uint8_t *dat, bool txPacket); /// @endcond DO_NOT_INCLUDE_WITH_DOXYGEN // -------------------- Include Files ------------------------------------------ diff --git a/efm8/lib/efm8_usb/src/efm8_usbd.c b/efm8/lib/efm8_usb/src/efm8_usbd.c index 34f94e4..24e2d8d 100644 --- a/efm8/lib/efm8_usb/src/efm8_usbd.c +++ b/efm8/lib/efm8_usb/src/efm8_usbd.c @@ -6,9 +6,9 @@ #include "si_toolchain.h" #include "efm8_usb.h" -#include "assert.h" +//#include "assert.h" #include - +#define SLAB_ASSERT(x) // ----------------------------------------------------------------------------- // Global Variables @@ -65,8 +65,8 @@ void USBD_AbortAllTransfers(void) int8_t USBD_AbortTransfer(uint8_t epAddr) { - SI_VARIABLE_SEGMENT_POINTER(ep, USBD_Ep_TypeDef, MEM_MODEL_SEG); - int8_t retVal = USB_STATUS_OK; + USBD_Ep_TypeDef MEM_MODEL_SEG *ep; + uint8_t retVal = USB_STATUS_OK; bool usbIntsEnabled; USB_SaveSfrPage(); @@ -150,7 +150,7 @@ void USBD_Disconnect(void) bool USBD_EpIsBusy(uint8_t epAddr) { - SI_VARIABLE_SEGMENT_POINTER(ep, USBD_Ep_TypeDef, MEM_MODEL_SEG); + USBD_Ep_TypeDef MEM_MODEL_SEG *ep; // Verify this is a valid endpoint address if (epAddr >= SLAB_USB_NUM_EPS_USED) @@ -174,7 +174,7 @@ USBD_State_TypeDef USBD_GetUsbState(void) return myUsbDevice.state; } -int8_t USBD_Init(SI_VARIABLE_SEGMENT_POINTER(p, const USBD_Init_TypeDef, SI_SEG_GENERIC)) +int8_t USBD_Init(const USBD_Init_TypeDef *p) { uint8_t i; @@ -190,12 +190,12 @@ int8_t USBD_Init(SI_VARIABLE_SEGMENT_POINTER(p, const USBD_Init_TypeDef, SI_SEG_ // Zero out the myUsbDevice struct, then initialize all non-zero members for (i = 0; i < sizeof(myUsbDevice); i++) { - *((SI_VARIABLE_SEGMENT_POINTER(, uint8_t, MEM_MODEL_SEG))&myUsbDevice + i) = 0; + *((uint8_t MEM_MODEL_SEG *)&myUsbDevice + i) = 0; } // Get the USB descriptors from p myUsbDevice.deviceDescriptor = p->deviceDescriptor; - myUsbDevice.configDescriptor = p->configDescriptor; + myUsbDevice.configDescriptor = (USB_ConfigurationDescriptor_TypeDef *)p->configDescriptor; myUsbDevice.stringDescriptors = p->stringDescriptors; myUsbDevice.numberOfStrings = p->numberOfStrings; @@ -246,12 +246,12 @@ int8_t USBD_Init(SI_VARIABLE_SEGMENT_POINTER(p, const USBD_Init_TypeDef, SI_SEG_ } int8_t USBD_Read(uint8_t epAddr, - SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), + uint8_t *dat, uint16_t byteCount, bool callback) { bool usbIntsEnabled; - SI_VARIABLE_SEGMENT_POINTER(ep, USBD_Ep_TypeDef, MEM_MODEL_SEG); + USBD_Ep_TypeDef MEM_MODEL_SEG *ep; USB_SaveSfrPage(); @@ -432,13 +432,8 @@ void USBD_Stop(void) void USBD_Suspend(void) { -#if (!(SLAB_USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_FASTWAKE)) uint8_t i; -#endif bool regulatorEnabled, prefetchEnabled; -#if SLAB_USB_REMOTE_WAKEUP_ENABLED - bool remoteWakeup = false; -#endif USB_SaveSfrPage(); @@ -494,9 +489,8 @@ void USBD_Suspend(void) // wakeup event occurred. If so, exit USBD_Suspend(). if (USB_IsSuspended() == true) { - remoteWakeup = USBD_RemoteWakeupCb(); - if (remoteWakeup == true) - { + if (USBD_RemoteWakeupCb() == true) + { break; } } @@ -510,13 +504,8 @@ void USBD_Suspend(void) break; } #endif - -#if ((!(SLAB_USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF)) || \ - (SLAB_USB_BUS_POWERED)) } while (USB_IsSuspended() == true); -#else - } while ((USB_IsSuspended() == true) || (USB_IsVbusOn() == false)); -#endif + // Restore the internal regulator if (regulatorEnabled == true) { @@ -534,20 +523,6 @@ void USBD_Suspend(void) USB_SetNormalClock(); #endif USB_EnableTransceiver(); - -#if SLAB_USB_REMOTE_WAKEUP_ENABLED - // If the device woke from suspend due to a remote wakeup source, call - // USBD_RemoteWakeup() here to wake up the host. - if (remoteWakeup == true) - { - // Wake up the host - if (USBD_RemoteWakeup() == USB_STATUS_OK) - { - // If the remote wakeup succeeded, transition out of USB suspend state - USBD_SetUsbState(myUsbDevice.savedState); - } - } -#endif } USB_RestoreSfrPage(); @@ -624,12 +599,12 @@ int8_t USBD_UnStallEp(uint8_t epAddr) } int8_t USBD_Write(uint8_t epAddr, - SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), + uint8_t *dat, uint16_t byteCount, bool callback) { bool usbIntsEnabled; - SI_VARIABLE_SEGMENT_POINTER(ep, USBD_Ep_TypeDef, MEM_MODEL_SEG); + USBD_Ep_TypeDef MEM_MODEL_SEG *ep; USB_SaveSfrPage(); diff --git a/efm8/lib/efm8_usb/src/efm8_usbdch9.c b/efm8/lib/efm8_usb/src/efm8_usbdch9.c index 6bb2a47..c0afa23 100644 --- a/efm8/lib/efm8_usb/src/efm8_usbdch9.c +++ b/efm8/lib/efm8_usb/src/efm8_usbdch9.c @@ -22,13 +22,14 @@ static USB_Status_TypeDef SetConfiguration(void); static USB_Status_TypeDef SetFeature(void); static USB_Status_TypeDef SetInterface(void); static void USBD_ActivateAllEps(bool forceIdle); -static void EP0_Write(SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), uint16_t numBytes); +static void EP0_Write(uint8_t *dat, uint16_t numBytes); +void SendEp0Stall(void); // ----------------------------------------------------------------------------- // Global Variables extern SI_SEGMENT_VARIABLE(myUsbDevice, USBD_Device_TypeDef, MEM_MODEL_SEG); -const SI_SEGMENT_VARIABLE(txZero[2], uint8_t, SI_SEG_CODE); +SI_SEGMENT_VARIABLE(txZero[2], uint8_t, SI_SEG_CODE); // ----------------------------------------------------------------------------- // Static Global Variables @@ -91,6 +92,15 @@ USB_Status_TypeDef USBDCH9_SetupCmd(void) break; } + // Reset index to 0 in case one of the above commands modified it + USB_SetIndex(0); + + // If the command resulted in an error, send a procedural stall + if (status == USB_STATUS_REQ_ERR) + { + SendEp0Stall(); + } + return status; } @@ -228,7 +238,7 @@ static USB_Status_TypeDef GetConfiguration(void) { if (myUsbDevice.state == USBD_STATE_ADDRESSED) { - EP0_Write((SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))txZero, 1); + EP0_Write(txZero, 1); retVal = USB_STATUS_OK; } else if (myUsbDevice.state == USBD_STATE_CONFIGURED) @@ -257,7 +267,7 @@ static USB_Status_TypeDef GetDescriptor(void) uint8_t index; uint16_t length = 0; - SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC); + uint8_t *dat; USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR; if (*((uint8_t *)&myUsbDevice.setup.bmRequestType) == @@ -272,7 +282,7 @@ static USB_Status_TypeDef GetDescriptor(void) { break; } - dat = (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))myUsbDevice.deviceDescriptor; + dat = (uint8_t *)myUsbDevice.deviceDescriptor; length = myUsbDevice.deviceDescriptor->bLength; break; @@ -281,14 +291,14 @@ static USB_Status_TypeDef GetDescriptor(void) { break; } - dat = (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))myUsbDevice.configDescriptor; + dat = (uint8_t *)myUsbDevice.configDescriptor; length = le16toh(myUsbDevice.configDescriptor->wTotalLength); break; case USB_STRING_DESCRIPTOR: #if (SLAB_USB_NUM_LANGUAGES == 1) - dat = (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))myUsbDevice.stringDescriptors[index]; + dat = (uint8_t *)myUsbDevice.stringDescriptors[index]; // Index 0 is the language string. If SLAB_USB_NUM_LANGUAGES == 1, we // know the length will be 4 and the format will be UTF16LE. @@ -317,7 +327,7 @@ static USB_Status_TypeDef GetDescriptor(void) // Index 0 is the language. if (index == 0) { - dat = ((SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))myUsbDevice.stringDescriptors->languageArray[0][index]); + dat = ((uint8_t *)myUsbDevice.stringDescriptors->languageArray[0][index]); length = *((uint8_t *)dat); myUsbDevice.ep0String.encoding.type = USB_STRING_DESCRIPTOR_UTF16LE; } @@ -335,7 +345,7 @@ static USB_Status_TypeDef GetDescriptor(void) } if ((langSupported == true) && (index < myUsbDevice.numberOfStrings)) { - dat = ((SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))myUsbDevice.stringDescriptors->languageArray[lang][index]); + dat = ((uint8_t *)myUsbDevice.stringDescriptors->languageArray[lang][index]); length = *(dat + USB_STRING_DESCRIPTOR_LENGTH); myUsbDevice.ep0String.encoding.type = *(dat + USB_STRING_DESCRIPTOR_ENCODING); dat += USB_STRING_DESCRIPTOR_LENGTH; @@ -393,10 +403,10 @@ static USB_Status_TypeDef GetInterface(void) { #if (SLAB_USB_SUPPORT_ALT_INTERFACES) // Return the alternate setting for the specified interface - EP0_Write((SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))&myUsbDevice.interfaceAltSetting[interface], 1); + EP0_Write(&myUsbDevice.interfaceAltSetting[interface], 1); #else // Alternate interfaces are not supported, so return 0x0000. - EP0_Write((SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))&txZero, 1); + EP0_Write(&txZero, 1); #endif retVal = USB_STATUS_OK; } @@ -531,7 +541,7 @@ static USB_Status_TypeDef GetStatus(void) // If the command was valid, send the requested status. if (retVal == USB_STATUS_OK) { - EP0_Write((SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))&pStatus, 2); + EP0_Write((uint8_t *)&pStatus, 2); } } @@ -858,11 +868,11 @@ static void USBD_ActivateAllEps(bool forceIdle) * @param numBytes * Number of bytes to transmit on Endpoint 0 ******************************************************************************/ -static void EP0_Write(SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), uint16_t numBytes) +static void EP0_Write(uint8_t *dat, uint16_t numBytes) { if (myUsbDevice.ep0.state == D_EP_IDLE) { - myUsbDevice.ep0.buf = dat; + myUsbDevice.ep0.buf = (uint8_t *)dat; myUsbDevice.ep0.remaining = numBytes; myUsbDevice.ep0.state = D_EP_TRANSMITTING; myUsbDevice.ep0.misc.c = 0; diff --git a/efm8/lib/efm8_usb/src/efm8_usbdep.c b/efm8/lib/efm8_usb/src/efm8_usbdep.c index 2982658..ec8721a 100644 --- a/efm8/lib/efm8_usb/src/efm8_usbdep.c +++ b/efm8/lib/efm8_usb/src/efm8_usbdep.c @@ -40,16 +40,11 @@ static void USB_WriteFIFO_Code(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat // ------------------------------- // Generic FIFO access functions -static void USB_ReadFIFO_Generic(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), uint8_t fifoNum); -static void USB_WriteFIFO_Generic(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC)); +static void USB_ReadFIFO_Generic(uint8_t numBytes, uint8_t *dat, uint8_t fifoNum); +static void USB_WriteFIFO_Generic(uint8_t numBytes, uint8_t *dat); #endif // #ifdef SI_GPTR -#if (SLAB_USB_EP3OUT_USED && (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC)) -static void memclearXdata(SI_VARIABLE_SEGMENT_POINTER(s, uint8_t, SI_SEG_XDATA), - uint16_t n); -#endif - // ----------------------------------------------------------------------------- // Functions @@ -67,7 +62,7 @@ static void memclearXdata(SI_VARIABLE_SEGMENT_POINTER(s, uint8_t, SI_SEG_XDATA), // If Isochronous mode is enabled and the max packet size is greater than 255, // break the FIFO reads up into multiple reads of 255 or less bytes. // ---------------------------------------------------------------------------- -void USB_ReadFIFOIso(uint8_t fifoNum, uint16_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC)) +void USB_ReadFIFOIso(uint8_t fifoNum, uint16_t numBytes, uint8_t *dat) { uint8_t numBytesRead; @@ -99,7 +94,7 @@ void USB_ReadFIFOIso(uint8_t fifoNum, uint16_t numBytes, SI_VARIABLE_SEGMENT_POI // If Isochronous mode is enabled and the max packet size is greater than 255, // break the FIFO writes up into multiple writes of 255 or less bytes. // ---------------------------------------------------------------------------- -void USB_WriteFIFOIso(uint8_t fifoNum, uint16_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC)) +void USB_WriteFIFOIso(uint8_t fifoNum, uint16_t numBytes, uint8_t *dat) { uint8_t numBytesWrite; @@ -322,6 +317,7 @@ void handleUsbIn3Int(void) void handleUsbOut1Int(void) { uint8_t count; + USB_Status_TypeDef status; bool xferComplete = false; @@ -361,7 +357,6 @@ void handleUsbOut1Int(void) myUsbDevice.ep1out.state = D_EP_IDLE; xferComplete = true; } - status = USB_STATUS_OK; USB_EpnClearOutPacketReady(); } @@ -371,7 +366,6 @@ void handleUsbOut1Int(void) { myUsbDevice.ep1out.misc.bits.callback = false; } - USBD_XferCompleteCb(EP1OUT, status, count, myUsbDevice.ep1out.remaining); } } @@ -387,6 +381,7 @@ void handleUsbOut1Int(void) void handleUsbOut2Int(void) { uint8_t count; + USB_Status_TypeDef status; bool xferComplete = false; @@ -451,10 +446,19 @@ void handleUsbOut2Int(void) * @note This function takes no parameters, but it uses the EP3OUT status * variables stored in @ref myUsbDevice.ep3out. ******************************************************************************/ -#if ((SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_INTR)) void handleUsbOut3Int(void) { +#if (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC) + uint16_t nextIdx; +#if (SLAB_USB_EP3OUT_MAX_PACKET_SIZE > 255) + uint16_t count; +#else uint8_t count; +#endif // ( SLAB_USB_EP3OUT_MAX_PACKET_SIZE > 255 ) +#else + uint8_t count; +#endif // ( SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC ) + USB_Status_TypeDef status; bool xferComplete = false; @@ -474,6 +478,7 @@ void handleUsbOut3Int(void) myUsbDevice.ep3out.misc.bits.outPacketPending = true; status = USB_STATUS_EP_ERROR; } +#if ((SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_INTR)) // Check for overrun of user buffer else if (myUsbDevice.ep3out.remaining < count) { @@ -481,11 +486,12 @@ void handleUsbOut3Int(void) myUsbDevice.ep3out.misc.bits.outPacketPending = true; status = USB_STATUS_EP_RX_BUFFER_OVERRUN; } +#endif else { +#if ((SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_INTR)) USB_ReadFIFO(3, count, myUsbDevice.ep3out.buf); - myUsbDevice.ep3out.misc.bits.outPacketPending = false; myUsbDevice.ep3out.remaining -= count; myUsbDevice.ep3out.buf += count; @@ -494,7 +500,26 @@ void handleUsbOut3Int(void) myUsbDevice.ep3out.state = D_EP_IDLE; xferComplete = true; } +#elif (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC) + nextIdx = count + myUsbDevice.ep3outIsoIdx; + // In isochronous mode, a circular buffer is used to hold the data + // If the next index into the circular buffer passes the end of the + // buffer, make two calls to USB_ReadFIFOIso() + if (nextIdx > myUsbDevice.ep3out.remaining) + { + USB_ReadFIFOIso(3, myUsbDevice.ep3out.remaining - myUsbDevice.ep3outIsoIdx, &myUsbDevice.ep3out.buf[myUsbDevice.ep3outIsoIdx]); + myUsbDevice.ep3outIsoIdx = nextIdx - myUsbDevice.ep3out.remaining; + USB_ReadFIFOIso(3, myUsbDevice.ep3outIsoIdx, myUsbDevice.ep3out.buf); + } + else + { + USB_ReadFIFOIso(3, count, &myUsbDevice.ep3out.buf[myUsbDevice.ep3outIsoIdx]); + myUsbDevice.ep3outIsoIdx = nextIdx; + } +#endif // ( ( SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_BULK ) || ( SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_INTR ) ) + + myUsbDevice.ep3out.misc.bits.outPacketPending = false; status = USB_STATUS_OK; USB_EpnClearOutPacketReady(); } @@ -505,175 +530,18 @@ void handleUsbOut3Int(void) myUsbDevice.ep3out.misc.bits.callback = false; } +#if ((SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_INTR)) USBD_XferCompleteCb(EP3OUT, status, count, myUsbDevice.ep3out.remaining); - } - } -} - #elif (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC) -void handleUsbOut3Int(void) -{ - uint16_t nextIdx; - uint16_t numZeroBytesFromCb; -#if (SLAB_USB_EP3OUT_MAX_PACKET_SIZE > 255) - uint16_t count; -#else - uint8_t count; -#endif - USB_Status_TypeDef status = USB_STATUS_OK; - bool xferComplete = false; - - USB_SetIndex(3); - - if (USB_EpnOutGetSentStall()) - { - USB_EpnOutClearSentStall(); - } - else if (USB_EpnGetOutPacketReady()) - { - count = USB_EpOutGetCount(); - - // If USBD_Read() has not been called, return an error - if (myUsbDevice.ep3out.state != D_EP_RECEIVING) - { - myUsbDevice.ep3out.misc.bits.outPacketPending = true; - status = USB_STATUS_EP_ERROR; - } - else - { - // DATERR bit set (i.e. CRC/bit-stuffing error) - if (USB_EpnGetDataError() - #ifdef SLAB_USB_ISOC_OUT_MIN_PACKET_SIZE - || (count < SLAB_USB_ISOC_OUT_MIN_PACKET_SIZE) - #endif - #ifdef SLAB_USB_ISOC_OUT_MAX_PACKET_SIZE - || (count > SLAB_USB_ISOC_OUT_MAX_PACKET_SIZE) - #endif - ) - { - status = USB_STATUS_DATA_ERROR; - } - -#ifdef SLAB_USB_ISOC_OUT_PACKETSIZE_MOD2 - if ((count % 2) != 0) - { - status = USB_STATUS_DATA_ERROR; - } -#elif defined SLAB_USB_ISOC_OUT_PACKETSIZE_MOD4 - if (( count % 4) != 0) - { - status = USB_STATUS_DATA_ERROR; - } -#elif defined SLAB_USB_ISOC_OUT_PACKETSIZE_MOD6 - if (count % 6) != 0) - { - status = USB_STATUS_DATA_ERROR; - } -#endif - - if (status == USB_STATUS_DATA_ERROR) - { - count = 0; - // Flush FIFO to get rid of bad packet - USB_EpnOutFlush(); - myUsbDevice.ep3out.misc.bits.outPacketPending = false; - // Flush clears OPRDY, so no need to call USB_EpnClearOutPacketReady() now - } - else // No data error - { - nextIdx = count + myUsbDevice.ep3outIsoIdx; - - // In isochronous mode, a circular buffer is used to hold the data - // If the next index into the circular buffer passes the end of the - // buffer, make two calls to USB_ReadFIFOIso() - if (nextIdx > myUsbDevice.ep3out.remaining) - { - USB_ReadFIFOIso(3, myUsbDevice.ep3out.remaining - myUsbDevice.ep3outIsoIdx, &myUsbDevice.ep3out.buf[myUsbDevice.ep3outIsoIdx]); - myUsbDevice.ep3outIsoIdx = nextIdx - myUsbDevice.ep3out.remaining; - USB_ReadFIFOIso(3, myUsbDevice.ep3outIsoIdx, myUsbDevice.ep3out.buf); - } - else - { - USB_ReadFIFOIso(3, count, &myUsbDevice.ep3out.buf[myUsbDevice.ep3outIsoIdx]); - myUsbDevice.ep3outIsoIdx = nextIdx; - } - - myUsbDevice.ep3out.misc.bits.outPacketPending = false; - USB_EpnClearOutPacketReady(); - } - } - - if (myUsbDevice.ep3out.misc.bits.callback == true) - { - if (xferComplete == true) - { - myUsbDevice.ep3out.misc.bits.callback = false; - } // In Isochronous mode, the meaning of the USBD_XferCompleteCb parameters changes: // xferred is the number of bytes received in the last packet // remaining is the current index into the circular buffer - numZeroBytesFromCb = USBD_XferCompleteCb(EP3OUT, status, count, myUsbDevice.ep3outIsoIdx); - - // If data error occurred, the callback return value specifies how many zero-valued bytes to queue - if (numZeroBytesFromCb && (status == USB_STATUS_DATA_ERROR)) - { - uint16_t numZeroBytesToWrite; - SI_SEGMENT_VARIABLE_SEGMENT_POINTER(bufPtr, - uint8_t, - SI_SEG_XDATA, - SI_SEG_DATA); - - // Clear status after calling USBD_XferCompleteCb() - status = USB_STATUS_OK; - - // Add the specified number of zero-value bytes - nextIdx = numZeroBytesFromCb + myUsbDevice.ep3outIsoIdx; - - // Next index is past the end of the buffer (requires two writes) - if (nextIdx > myUsbDevice.ep3out.remaining) - { - // Write up to the end of the buffer - numZeroBytesToWrite = myUsbDevice.ep3out.remaining - myUsbDevice.ep3outIsoIdx; - bufPtr = &myUsbDevice.ep3out.buf[myUsbDevice.ep3outIsoIdx]; - memclearXdata(bufPtr, numZeroBytesToWrite); - - // Write the rest, starting at beginning of buffer - myUsbDevice.ep3outIsoIdx = nextIdx - myUsbDevice.ep3out.remaining; - numZeroBytesToWrite = myUsbDevice.ep3outIsoIdx; - bufPtr = &myUsbDevice.ep3out.buf[0]; - memclearXdata(bufPtr, numZeroBytesToWrite); - } - // Next index is not past the end of the buffer - else - { - bufPtr = &myUsbDevice.ep3out.buf[myUsbDevice.ep3outIsoIdx]; - memclearXdata(bufPtr, numZeroBytesFromCb); - myUsbDevice.ep3outIsoIdx = nextIdx; - } - } + USBD_XferCompleteCb(EP3OUT, status, count, myUsbDevice.ep3outIsoIdx); +#endif } } } - -/***************************************************************************//** - * @brief Sets all elements in a contiguous array of XDATA to zero - * @param s - * Pointer to the block of memory to fill - * @param n - * Number of bytes to be set to the value - ******************************************************************************/ -static void memclearXdata(SI_VARIABLE_SEGMENT_POINTER(s, uint8_t, SI_SEG_XDATA), - uint16_t n) -{ - while (n) - { - *s++ = 0; - n--; - } -} - -#endif // #if ((SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_BULK) || (SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_INTR)) #endif // EP3OUT_USED /***************************************************************************//** @@ -685,7 +553,7 @@ static void memclearXdata(SI_VARIABLE_SEGMENT_POINTER(s, uint8_t, SI_SEG_XDATA), * @param dat * Pointer to buffer to hold data read from the FIFO ******************************************************************************/ -void USB_ReadFIFO(uint8_t fifoNum, uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC)) +void USB_ReadFIFO(uint8_t fifoNum, uint8_t numBytes, uint8_t *dat) { if (numBytes > 0) { @@ -699,7 +567,7 @@ void USB_ReadFIFO(uint8_t fifoNum, uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER switch (((SI_GEN_PTR_t *)&dat)->gptr.memtype) { case SI_GPTR_MTYPE_IDATA: - USB_ReadFIFO_Idata(numBytes, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_IDATA))dat, fifoNum); + USB_ReadFIFO_Idata(numBytes, dat, fifoNum); break; // For some compilers, IDATA and DATA are treated the same. @@ -712,7 +580,7 @@ void USB_ReadFIFO(uint8_t fifoNum, uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER #endif case SI_GPTR_MTYPE_XDATA: - USB_ReadFIFO_Xdata(numBytes, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_XDATA))dat, fifoNum); + USB_ReadFIFO_Xdata(numBytes, dat, fifoNum); break; // For some compilers, XDATA and PDATA are treated the same. @@ -750,7 +618,7 @@ void USB_ReadFIFO(uint8_t fifoNum, uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER * If FALSE, the packet will be stored in the FIFO and the * transmission must be started at a later time ******************************************************************************/ -void USB_WriteFIFO(uint8_t fifoNum, uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), bool txPacket) +void USB_WriteFIFO(uint8_t fifoNum, uint8_t numBytes, uint8_t *dat, bool txPacket) { USB_EnableWriteFIFO(fifoNum); @@ -762,7 +630,7 @@ void USB_WriteFIFO(uint8_t fifoNum, uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTE switch (((SI_GEN_PTR_t *)&dat)->gptr.memtype) { case SI_GPTR_MTYPE_IDATA: - USB_WriteFIFO_Idata(numBytes, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_IDATA))dat); + USB_WriteFIFO_Idata(numBytes, dat); break; // For some compilers, IDATA and DATA are treated the same. @@ -775,7 +643,7 @@ void USB_WriteFIFO(uint8_t fifoNum, uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTE #endif case SI_GPTR_MTYPE_XDATA: - USB_WriteFIFO_Xdata(numBytes, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_XDATA))dat); + USB_WriteFIFO_Xdata(numBytes, dat); break; // For some compilers, XDATA and PDATA are treated the same. @@ -788,7 +656,7 @@ void USB_WriteFIFO(uint8_t fifoNum, uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTE #endif case SI_GPTR_MTYPE_CODE: - USB_WriteFIFO_Code(numBytes, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_CODE))dat); + USB_WriteFIFO_Code(numBytes, dat); break; default: @@ -944,10 +812,10 @@ static void USB_ReadFIFO_Data(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, { while (--numBytes) { - USB_GetFIFOByte(dat); + USB_GetFIFOByte(*dat); dat++; } - USB_GetLastFIFOByte(dat, fifoNum); + USB_GetLastFIFOByte(*dat, fifoNum); } /***************************************************************************//** @@ -997,14 +865,14 @@ static void USB_WriteFIFO_Code(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat * @param fifoNum * USB FIFO to read ******************************************************************************/ -static void USB_ReadFIFO_Generic(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC), uint8_t fifoNum) +static void USB_ReadFIFO_Generic(uint8_t numBytes, uint8_t *dat, uint8_t fifoNum) { while (--numBytes) { - USB_GetFIFOByte(dat); + USB_GetFIFOByte(*dat); dat++; } - USB_GetLastFIFOByte(dat, fifoNum); + USB_GetLastFIFOByte(*dat, fifoNum); } /***************************************************************************//** @@ -1016,7 +884,7 @@ static void USB_ReadFIFO_Generic(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(d * @param dat * Pointer to generic buffer holding data to write to the FIFO ******************************************************************************/ -static void USB_WriteFIFO_Generic(uint8_t numBytes, SI_VARIABLE_SEGMENT_POINTER(dat, uint8_t, SI_SEG_GENERIC)) +static void USB_WriteFIFO_Generic(uint8_t numBytes, uint8_t *dat) { while (numBytes--) { diff --git a/efm8/lib/efm8_usb/src/efm8_usbdint.c b/efm8/lib/efm8_usb/src/efm8_usbdint.c index 39d744f..f00c9ed 100644 --- a/efm8/lib/efm8_usb/src/efm8_usbdint.c +++ b/efm8/lib/efm8_usb/src/efm8_usbdint.c @@ -13,7 +13,7 @@ // Global variables extern SI_SEGMENT_VARIABLE(myUsbDevice, USBD_Device_TypeDef, MEM_MODEL_SEG); -extern SI_SEGMENT_VARIABLE(txZero[2], const uint8_t, SI_SEG_CODE); +extern SI_SEGMENT_VARIABLE(txZero[2], uint8_t, SI_SEG_CODE); // ----------------------------------------------------------------------------- // Function prototypes @@ -48,12 +48,6 @@ void handleUsbOut3Int(void); void SendEp0Stall(void); -#if SLAB_USB_UTF8_STRINGS == 1 -static uint8_t decodeUtf8toUcs2( - const uint8_t *pUtf8in, - SI_VARIABLE_SEGMENT_POINTER(pUcs2out, uint16_t, MEM_MODEL_SEG)); -#endif - // ----------------------------------------------------------------------------- // Functions @@ -218,8 +212,6 @@ void usbIrqHandler(void) ******************************************************************************/ static void handleUsbEp0Int(void) { - USB_Status_TypeDef retVal = USB_STATUS_REQ_UNHANDLED; - USB_SetIndex(0); if (USB_Ep0SentStall() || USB_GetSetupEnd()) @@ -242,55 +234,32 @@ static void handleUsbEp0Int(void) // Vendor unique, Class or Standard setup commands override? #if SLAB_USB_SETUP_CMD_CB - retVal = USBD_SetupCmdCb(&myUsbDevice.setup); - - if (retVal == USB_STATUS_REQ_UNHANDLED) + if (USBD_SetupCmdCb(&myUsbDevice.setup) == USB_STATUS_REQ_UNHANDLED) { #endif - if (myUsbDevice.setup.bmRequestType.Type == USB_SETUP_TYPE_STANDARD) - { - retVal = USBDCH9_SetupCmd(); - } -#if SLAB_USB_SETUP_CMD_CB - } -#endif - - // Reset index to 0 in case the call to USBD_SetupCmdCb() or - // USBDCH9_SetupCmd() changed it. - USB_SetIndex(0); - - // Put the Enpoint 0 hardware into the correct state here. - if (retVal == USB_STATUS_OK) + if (myUsbDevice.setup.bmRequestType.Type == USB_SETUP_TYPE_STANDARD) { - // If wLength is 0, there is no Data Phase - // Set both the Serviced Out Packet Ready and Data End bits - if (myUsbDevice.setup.wLength == 0) - { - USB_Ep0SetLastOutPacketReady(); - } - // If wLength is non-zero, there is a Data Phase. - // Set only the Serviced Out Packet Ready bit. - else - { - USB_Ep0ServicedOutPacketReady(); - -#if SLAB_USB_SETUP_CMD_CB - // If OUT packet but callback didn't set up a USBD_Read and we are expecting a - // data byte then we need to wait for the read to be setup and NACK packets until - // USBD_Read is called. - if ((myUsbDevice.setup.bmRequestType.Direction == USB_SETUP_DIR_OUT) - && (myUsbDevice.ep0.state != D_EP_RECEIVING)) - { - myUsbDevice.ep0.misc.bits.waitForRead = true; - } -#endif - } + USBDCH9_SetupCmd(); } - // If the setup transaction detected an error, send a stall else { SendEp0Stall(); } +#if SLAB_USB_SETUP_CMD_CB + } + else + { + // If in-packet but callback didn't setup a USBD_Read and we are expecting a data byte then + // we need to wait for the read to be setup and nack packets till USBD_Read is called. + if ((myUsbDevice.setup.bmRequestType.Direction == USB_SETUP_DIR_OUT) + && (myUsbDevice.ep0.state != D_EP_RECEIVING) + && (myUsbDevice.setup.wLength) + ) + { + myUsbDevice.ep0.misc.bits.waitForRead = true; + } + } +#endif } else if (myUsbDevice.ep0.state == D_EP_RECEIVING) { @@ -312,9 +281,11 @@ static void handleUsbEp0Int(void) ******************************************************************************/ static void USB_ReadFIFOSetup(void) { - SI_VARIABLE_SEGMENT_POINTER(ptr, uint16_t, MEM_MODEL_SEG) = (SI_VARIABLE_SEGMENT_POINTER(, uint16_t, MEM_MODEL_SEG))&myUsbDevice.setup; + uint16_t MEM_MODEL_SEG *ptr = &myUsbDevice.setup; - USB_ReadFIFO(0, 8, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))ptr); + USB_ReadFIFO(0, 8, (uint8_t *)ptr); + + USB_Ep0ServicedOutPacketReady(); // Modify for Endian-ness of the compiler ptr[1] = le16toh(ptr[1]); @@ -368,11 +339,9 @@ static void handleUsbResetInt(void) USB_EnableSuspendDetection(); USB_EnableDeviceInts(); - // If the device is bus-powered, always put it in the Default state. - // If the device is self-powered and VBUS is present, put the device in the - // Default state. Otherwise, put it in the Attached state. -#if (!SLAB_USB_BUS_POWERED) && \ - (!(SLAB_USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF)) + // If VBUS is preset, put the device in the Default state. + // Otherwise, put it in the Attached state. +#if (!(SLAB_USB_PWRSAVE_MODE & USB_PWRSAVE_MODE_ONVBUSOFF)) if (USB_IsVbusOn()) { USBD_SetUsbState(USBD_STATE_DEFAULT); @@ -437,16 +406,12 @@ static void handleUsbEp0Tx(void) // Strings can use the USB_STRING_DESCRIPTOR_UTF16LE_PACKED type to pack // UTF16LE data without the zero's between each character. // If the current string is of type USB_STRING_DESCRIPTOR_UTF16LE_PACKED, - // unpack it by inserting a zero between each character in the string. - if ((myUsbDevice.ep0String.encoding.type == USB_STRING_DESCRIPTOR_UTF16LE_PACKED) -#if SLAB_USB_UTF8_STRINGS == 1 - || (myUsbDevice.ep0String.encoding.type == USB_STRING_DESCRIPTOR_UTF8) -#endif - ) + // unpacket it by inserting a zero between each character in the string. + if (myUsbDevice.ep0String.encoding.type == USB_STRING_DESCRIPTOR_UTF16LE_PACKED) { // If ep0String.encoding.init is true, this is the beginning of the string. // The first two bytes of the string are the bLength and bDescriptorType - // fields. These are not packed like the reset of the string, so write them + // fields. These are no packed like the reset of the string, so write them // to the FIFO and set ep0String.encoding.init to false. if (myUsbDevice.ep0String.encoding.init == true) { @@ -459,36 +424,9 @@ static void handleUsbEp0Tx(void) // Insert a 0x00 between each character of the string. for (i = 0; i < count / 2; i++) { -#if SLAB_USB_UTF8_STRINGS == 1 - if (myUsbDevice.ep0String.encoding.type == USB_STRING_DESCRIPTOR_UTF8) - { - SI_SEGMENT_VARIABLE(ucs2, uint16_t, MEM_MODEL_SEG); - uint8_t utf8count; - - // decode the utf8 into ucs2 for usb string - utf8count = decodeUtf8toUcs2(myUsbDevice.ep0.buf, &ucs2); - - // if consumed utf8 bytes is 0, it means either null byte was - // input or bad utf8 byte sequence. Either way its an error and - // there's not much we can do. So just advance the input string - // by one character and keep going until count is expired. - if (utf8count == 0) - { - utf8count = 1; - } - - // adjust to next char in utf8 byte sequence - myUsbDevice.ep0.buf += utf8count; - ucs2 = htole16(ucs2); // usb 16-bit chars are little endian - USB_WriteFIFO(0, 2, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))&ucs2, false); - } - else -#endif - { - USB_WriteFIFO(0, 1, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))myUsbDevice.ep0.buf, false); - myUsbDevice.ep0.buf++; - USB_WriteFIFO(0, 1, (SI_VARIABLE_SEGMENT_POINTER(, uint8_t, SI_SEG_GENERIC))&txZero, false); - } + USB_WriteFIFO(0, 1, myUsbDevice.ep0.buf, false); + myUsbDevice.ep0.buf++; + USB_WriteFIFO(0, 1, &txZero, false); } } // For any data other than USB_STRING_DESCRIPTOR_UTF16LE_PACKED, just send the @@ -588,98 +526,6 @@ void SendEp0Stall(void) USB_Ep0SendStall(); } -#if SLAB_USB_UTF8_STRINGS == 1 -/***************************************************************************//** - * Decodes UTF-8 to UCS-2 (16-bit) character encoding that is used - * for USB string descriptors. - * - * @param pUtf8in pointer to next character in UTF-8 string - * @param pUcs2out pointer to location for 16-bit character output - * - * Decodes a UTF-8 byte sequence into a single UCS-2 character. This - * will only decode up to 16-bit code point and will not handle the - * 21-bit case (4 bytes input). - * - * For valid cases, the UTF8 character sequence decoded into a 16-bit - * character and stored at the location pointed at by _pUcs2out_. - * The function will then return the number of input bytes that were - * consumed (1, 2, or 3). The caller can use the return value to find - * the start of the next character sequence in a utf-8 string. - * - * If either of the input pointers are NULL, then 0 is returned. - * - * If the first input character is NULL, then the output 16-bit value - * will be set to NULL and the function will return 0. - * - * If any other invalid sequence is detected, then the 16-bit output - * will be set to the equivalent of the question mark character (0x003F) - * and the return code will be 0. - * - * @return count of UTF8 bytes consumed - ******************************************************************************/ -static uint8_t decodeUtf8toUcs2( - const uint8_t *pUtf8in, - SI_VARIABLE_SEGMENT_POINTER(pUcs2out, uint16_t, MEM_MODEL_SEG)) -{ - uint8_t ret = 0; - - // check the input pointers - if (!pUtf8in || !pUcs2out) - { - return 0; - } - - // set default decode to error '?'; - *pUcs2out = '?'; - - // valid cases: - // 0xxxxxxx (7 bits) - // 110xxxxx 10xxxxxx (11 bits) - // 1110xxxx 10xxxxxx 10xxxxxx (16 bits) - - // null input - if (pUtf8in[0] == 0) - { - *pUcs2out = 0; - ret = 0; - } - - // 7-bit char - else if (pUtf8in[0] < 128) - { - *pUcs2out = pUtf8in[0]; - ret = 1; - } - - // 11-bit char - else if ((pUtf8in[0] & 0xE0) == 0xC0) - { - if ((pUtf8in[1] & 0xC0) == 0x80) - { - *pUcs2out = ((pUtf8in[0] & 0x1F) << 6) | (pUtf8in[1] & 0x3F); - ret = 2; - } - } - - // 16-bit char - else if ((pUtf8in[0] & 0xF0) == 0xE0) - { - if ((pUtf8in[1] & 0xC0) == 0x80) - { - if ((pUtf8in[2] & 0xC0) == 0x80) - { - *pUcs2out = ((pUtf8in[0] & 0x0F) << 12) - | ((pUtf8in[1] & 0x3F) << 6) - | (pUtf8in[2] & 0x3F); - ret = 3; - } - } - } - - return ret; -} -#endif // SLAB_USB_UTF8_STRINGS - // This function is called from USBD_Init(). It forces the user project to pull // this module from the library so that the declared ISR can be seen and // included. If this is not done then this entire module by never be included diff --git a/efm8/lib/efm8ub1/peripheralDrivers/inc/usb_0.h b/efm8/lib/efm8ub1/peripheralDrivers/inc/usb_0.h index d094fde..be32bad 100644 --- a/efm8/lib/efm8ub1/peripheralDrivers/inc/usb_0.h +++ b/efm8/lib/efm8ub1/peripheralDrivers/inc/usb_0.h @@ -10,6 +10,7 @@ #include "SI_EFM8UB1_Register_Enums.h" #include #include +#include "efm8_config.h" /******************************************************************************/ @@ -167,7 +168,7 @@ extern void USB_DisableInts(void); * @brief Returns state of USB interrupt enabler * @return TRUE if USB interrupts are enabled, FALSE otherwise. ******************************************************************************/ -extern bool USB_GetIntsEnabled(void); +bool USB_GetIntsEnabled(void); /***************************************************************************//** * @brief Enables VBUS detection @@ -324,7 +325,9 @@ extern void USB_SuspendTransceiver(void); do \ { \ SFRPAGE = PG3_PAGE; \ - USB0XCN &= ~(USB0XCN_PHYEN__ENABLED | USB0XCN_Dp__HIGH | USB0XCN_Dn__HIGH);\ + USB0XCN &= ~(USB0XCN_PHYEN__ENABLED \ + | USB0XCN_Dp__HIGH \ + | USB0XCN_Dn__HIGH); \ } while (0) #endif @@ -503,14 +506,14 @@ extern void USB_UnsuspendRegulator(void); * @brief Determine if the internal regulator is enabled * @return TRUE if the internal regulator is enabled, FALSE otherwise ******************************************************************************/ -extern bool USB_IsRegulatorEnabled(void); +bool USB_IsRegulatorEnabled(void); /***************************************************************************//** * @brief Disable the prefetch engine * @note This function is implemented as a macro. ******************************************************************************/ #ifdef IS_DOXYGEN -extern void USB_DisablePrefetch(void); +void USB_DisablePrefetch(void); #else #define USB_DisablePrefetch() \ do \ @@ -525,7 +528,7 @@ extern void USB_DisablePrefetch(void); * @note This function is implemented as a macro. ******************************************************************************/ #ifdef IS_DOXYGEN -extern void USB_EnablePrefetch(void); +void USB_EnablePrefetch(void); #else #define USB_EnablePrefetch() \ do \ @@ -539,12 +542,12 @@ extern void USB_EnablePrefetch(void); * @brief Determine if the prefetch engine is enabled * @return TRUE if prefetch engine is enabled, FALSE otherwise. ******************************************************************************/ -extern bool USB_IsPrefetchEnabled(void); +bool USB_IsPrefetchEnabled(void); /***************************************************************************//** * @brief Suspends internal oscillator ******************************************************************************/ -extern void USB_SuspendOscillator(void); +void USB_SuspendOscillator(void); /***************************************************************************//** * @brief Enables clock recovery in full speed mode @@ -731,8 +734,7 @@ extern void USB_Ep0SetLastOutPacketReady(void); #ifdef IS_DOXYGEN extern void USB_Ep0SendStall(void); #else -#define USB_Ep0SendStall() \ - USB_WRITE_BYTE(E0CSR, (E0CSR_SOPRDY__SET | E0CSR_SDSTL__SET)) +#define USB_Ep0SendStall() USB_WRITE_BYTE(E0CSR, E0CSR_SDSTL__SET) #endif /***************************************************************************//** @@ -964,7 +966,7 @@ extern bool USB_IsOut3IntActive(uint8_t OUT1INT_snapshot); extern void USB_SetSuspendIntActive(uint8_t CMINT_snapshot); #else #define USB_SetSuspendIntActive(CMINT_snapshot) \ - ((CMINT_snapshot) |= CMINT_SUSINT__SET) + (CMINT_snapshot |= CMINT_SUSINT__SET) #endif /***************************************************************************//** @@ -978,7 +980,7 @@ extern void USB_SetSuspendIntActive(uint8_t CMINT_snapshot); extern void USB_SetEp0IntActive(uint8_t IN1INT_snapshot); #else #define USB_SetEp0IntActive(IN1INT_snapshot) \ - ((IN1INT_snapshot) |= IN1INT_EP0__SET) + (IN1INT_snapshot |= IN1INT_EP0__SET) #endif /***************************************************************************//** @@ -992,7 +994,7 @@ extern void USB_SetEp0IntActive(uint8_t IN1INT_snapshot); extern void USB_SetIn1IntActive(uint8_t IN1INT_snapshot); #else #define USB_SetIn1IntActive(IN1INT_snapshot) \ - ((IN1INT_snapshot) |= IN1INT_IN1__SET) + (IN1INT_snapshot |= IN1INT_IN1__SET) #endif /***************************************************************************//** @@ -1006,7 +1008,7 @@ extern void USB_SetIn1IntActive(uint8_t IN1INT_snapshot); extern void USB_SetIn2IntActive(uint8_t IN1INT_snapshot); #else #define USB_SetIn2IntActive(IN1INT_snapshot) \ - ((IN1INT_snapshot) |= IN1INT_IN2__SET) + (IN1INT_snapshot |= IN1INT_IN2__SET) #endif /***************************************************************************//** @@ -1020,7 +1022,7 @@ extern void USB_SetIn2IntActive(uint8_t IN1INT_snapshot); extern void USB_SetIn3IntActive(uint8_t IN1INT_snapshot); #else #define USB_SetIn3IntActive(IN1INT_snapshot) \ - ((IN1INT_snapshot) |= IN1INT_IN3__SET) + (IN1INT_snapshot |= IN1INT_IN3__SET) #endif /***************************************************************************//** @@ -1034,7 +1036,7 @@ extern void USB_SetIn3IntActive(uint8_t IN1INT_snapshot); extern void USB_SetOut1IntActive(uint8_t OUT1INT_snapshot); #else #define USB_SetOut1IntActive(OUT1INT_snapshot) \ - ((OUT1INT_snapshot) |= OUT1INT_OUT1__SET) + (OUT1INT_snapshot |= OUT1INT_OUT1__SET) #endif /***************************************************************************//** @@ -1048,7 +1050,7 @@ extern void USB_SetOut1IntActive(uint8_t OUT1INT_snapshot); extern void USB_SetOut2IntActive(uint8_t OUT1INT_snapshot); #else #define USB_SetOut2IntActive(OUT1INT_snapshot) \ - ((OUT1INT_snapshot) |= OUT1INT_OUT2__SET) + (OUT1INT_snapshot |= OUT1INT_OUT2__SET) #endif /***************************************************************************//** @@ -1062,7 +1064,7 @@ extern void USB_SetOut2IntActive(uint8_t OUT1INT_snapshot); extern void USB_SetOut3IntActive(uint8_t OUT1INT_snapshot); #else #define USB_SetOut3IntActive(OUT1INT_snapshot) \ - ((OUT1INT_snapshot) |= OUT1INT_OUT3__SET) + (OUT1INT_snapshot |= OUT1INT_OUT3__SET) #endif /***************************************************************************//** @@ -1078,7 +1080,7 @@ extern void USB_EnableDeviceInts(void); (CMIE_SOFE__ENABLED \ | CMIE_RSTINTE__ENABLED \ | CMIE_RSUINTE__ENABLED \ - | CMIE_SUSINTE__ENABLED)) + | CMIE_SUSINTE__ENABLED)); #endif /***************************************************************************//** @@ -1088,7 +1090,7 @@ extern void USB_EnableDeviceInts(void); #ifdef IS_DOXYGEN extern void USB_EnableSofInt(void); #else -#define USB_EnableSofInt() USB_SET_BITS(CMIE, CMIE_SOFE__ENABLED) +#define USB_EnableSofInt() USB_SET_BITS(CMIE, CMIE_SOFE__ENABLED); #endif /***************************************************************************//** @@ -1098,7 +1100,7 @@ extern void USB_EnableSofInt(void); #ifdef IS_DOXYGEN extern void USB_DisableSofInt(void); #else -#define USB_DisableSofInt() USB_CLEAR_BITS(CMIE, CMIE_SOFE__ENABLED) +#define USB_DisableSofInt() USB_CLEAR_BITS(CMIE, CMIE_SOFE__ENABLED); #endif /***************************************************************************//** @@ -1108,7 +1110,7 @@ extern void USB_DisableSofInt(void); #ifdef IS_DOXYGEN extern void USB_EnableResetInt(void); #else -#define USB_EnableResetInt() USB_SET_BITS(CMIE, CMIE_RSTINTE__ENABLED) +#define USB_EnableResetInt() USB_SET_BITS(CMIE, CMIE_RSTINTE__ENABLED); #endif /***************************************************************************//** @@ -1118,7 +1120,7 @@ extern void USB_EnableResetInt(void); #ifdef IS_DOXYGEN extern void USB_DisableResetInt(void); #else -#define USB_DisableResetInt() USB_CLEAR_BITS(CMIE, CMIE_RSTINTE__ENABLED) +#define USB_DisableResetInt() USB_CLEAR_BITS(CMIE, CMIE_RSTINTE__ENABLED); #endif /***************************************************************************//** @@ -1128,7 +1130,7 @@ extern void USB_DisableResetInt(void); #ifdef IS_DOXYGEN extern void USB_EnableResumeInt(void); #else -#define USB_EnableResumeInt() USB_SET_BITS(CMIE, CMIE_RSUINTE__ENABLED) +#define USB_EnableResumeInt() USB_SET_BITS(CMIE, CMIE_RSUINTE__ENABLED); #endif /***************************************************************************//** @@ -1138,7 +1140,7 @@ extern void USB_EnableResumeInt(void); #ifdef IS_DOXYGEN extern void USB_DisableResumeInt(void); #else -#define USB_DisableResumeInt() USB_CLEAR_BITS(CMIE, CMIE_RSUINTE__ENABLED) +#define USB_DisableResumeInt() USB_CLEAR_BITS(CMIE, CMIE_RSUINTE__ENABLED); #endif /***************************************************************************//** @@ -1148,7 +1150,7 @@ extern void USB_DisableResumeInt(void); #ifdef IS_DOXYGEN extern void USB_EnableSuspendInt(void); #else -#define USB_EnableSuspendInt() USB_SET_BITS(CMIE, CMIE_SUSINTE__ENABLED) +#define USB_EnableSuspendInt() USB_SET_BITS(CMIE, CMIE_SUSINTE__ENABLED); #endif /***************************************************************************//** @@ -1158,7 +1160,7 @@ extern void USB_EnableSuspendInt(void); #ifdef IS_DOXYGEN extern void USB_DisableSuspendInt(void); #else -#define USB_DisableSuspendInt() USB_CLEAR_BITS(CMIE, CMIE_SUSINTE__ENABLED) +#define USB_DisableSuspendInt() USB_CLEAR_BITS(CMIE, CMIE_SUSINTE__ENABLED); #endif /***************************************************************************//** @@ -1168,7 +1170,7 @@ extern void USB_DisableSuspendInt(void); #ifdef IS_DOXYGEN extern void USB_EnableEp0Int(void); #else -#define USB_EnableEp0Int() USB_SET_BITS(IN1IE, IN1IE_EP0E__ENABLED) +#define USB_EnableEp0Int() USB_SET_BITS(IN1IE, IN1IE_EP0E__ENABLED); #endif /***************************************************************************//** @@ -1178,7 +1180,7 @@ extern void USB_EnableEp0Int(void); #ifdef IS_DOXYGEN extern void USB_DisableEp0Int(void); #else -#define USB_DisableEp0Int() USB_CLEAR_BITS(IN1IE, IN1IE_EP0E__ENABLED) +#define USB_DisableEp0Int() USB_CLEAR_BITS(IN1IE, IN1IE_EP0E__ENABLED); #endif /***************************************************************************//** @@ -1188,7 +1190,7 @@ extern void USB_DisableEp0Int(void); #ifdef IS_DOXYGEN extern void USB_EnableIn1Int(void); #else -#define USB_EnableIn1Int() USB_SET_BITS(IN1IE, IN1IE_IN1E__ENABLED) +#define USB_EnableIn1Int() USB_SET_BITS(IN1IE, IN1IE_IN1E__ENABLED); #endif /***************************************************************************//** @@ -1198,7 +1200,7 @@ extern void USB_EnableIn1Int(void); #ifdef IS_DOXYGEN extern void USB_DisableIn1Int(void); #else -#define USB_DisableIn1Int() USB_CLEAR_BITS(IN1IE, IN1IE_IN1E__ENABLED) +#define USB_DisableIn1Int() USB_CLEAR_BITS(IN1IE, IN1IE_IN1E__ENABLED); #endif /***************************************************************************//** @@ -1208,7 +1210,7 @@ extern void USB_DisableIn1Int(void); #ifdef IS_DOXYGEN extern void USB_EnableIn2Int(void); #else -#define USB_EnableIn2Int() USB_SET_BITS(IN1IE, IN1IE_IN2E__ENABLED) +#define USB_EnableIn2Int() USB_SET_BITS(IN1IE, IN1IE_IN2E__ENABLED); #endif /***************************************************************************//** @@ -1218,7 +1220,7 @@ extern void USB_EnableIn2Int(void); #ifdef IS_DOXYGEN extern void USB_DisableIn2Int(void); #else -#define USB_DisableIn2Int() USB_CLEAR_BITS(IN1IE, IN1IE_IN2E__ENABLED) +#define USB_DisableIn2Int() USB_CLEAR_BITS(IN1IE, IN1IE_IN2E__ENABLED); #endif /***************************************************************************//** @@ -1228,7 +1230,7 @@ extern void USB_DisableIn2Int(void); #ifdef IS_DOXYGEN extern void USB_EnableIn3Int(void); #else -#define USB_EnableIn3Int() USB_SET_BITS(IN1IE, IN1IE_IN3E__ENABLED) +#define USB_EnableIn3Int() USB_SET_BITS(IN1IE, IN1IE_IN3E__ENABLED); #endif /***************************************************************************//** @@ -1238,7 +1240,7 @@ extern void USB_EnableIn3Int(void); #ifdef IS_DOXYGEN extern void USB_DisableIn3Int(void); #else -#define USB_DisableIn3Int() USB_CLEAR_BITS(IN1IE, IN1IE_IN3E__ENABLED) +#define USB_DisableIn3Int() USB_CLEAR_BITS(IN1IE, IN1IE_IN3E__ENABLED); #endif /***************************************************************************//** @@ -1248,7 +1250,7 @@ extern void USB_DisableIn3Int(void); #ifdef IS_DOXYGEN extern void USB_EnableOut1Int(void); #else -#define USB_EnableOut1Int() USB_SET_BITS(OUT1IE, OUT1IE_OUT1E__ENABLED) +#define USB_EnableOut1Int() USB_SET_BITS(OUT1IE, OUT1IE_OUT1E__ENABLED); #endif /***************************************************************************//** @@ -1258,7 +1260,7 @@ extern void USB_EnableOut1Int(void); #ifdef IS_DOXYGEN extern void USB_DisableOut1Int(void); #else -#define USB_DisableOut1Int() USB_CLEAR_BITS(OUT1IE, OUT1IE_OUT1E__ENABLED) +#define USB_DisableOut1Int() USB_CLEAR_BITS(OUT1IE, OUT1IE_OUT1E__ENABLED); #endif /***************************************************************************//** @@ -1268,7 +1270,7 @@ extern void USB_DisableOut1Int(void); #ifdef IS_DOXYGEN extern void USB_EnableOut2Int(void); #else -#define USB_EnableOut2Int() USB_SET_BITS(OUT1IE, OUT1IE_OUT2E__ENABLED) +#define USB_EnableOut2Int() USB_SET_BITS(OUT1IE, OUT1IE_OUT2E__ENABLED); #endif /***************************************************************************//** @@ -1278,7 +1280,7 @@ extern void USB_EnableOut2Int(void); #ifdef IS_DOXYGEN extern void USB_DisableOut2Int(void); #else -#define USB_DisableOut2Int() USB_CLEAR_BITS(OUT1IE, OUT1IE_OUT2E__ENABLED) +#define USB_DisableOut2Int() USB_CLEAR_BITS(OUT1IE, OUT1IE_OUT2E__ENABLED); #endif /***************************************************************************//** @@ -1288,7 +1290,7 @@ extern void USB_DisableOut2Int(void); #ifdef IS_DOXYGEN extern void USB_EnableOut3Int(void); #else -#define USB_EnableOut3Int() USB_SET_BITS(OUT1IE, OUT1IE_OUT3E__ENABLED) +#define USB_EnableOut3Int() USB_SET_BITS(OUT1IE, OUT1IE_OUT3E__ENABLED); #endif /***************************************************************************//** @@ -1298,7 +1300,7 @@ extern void USB_EnableOut3Int(void); #ifdef IS_DOXYGEN extern void USB_DisableOut3Int(void); #else -#define USB_DisableOut3Int() USB_CLEAR_BITS(OUT1IE, OUT1IE_OUT3E__ENABLED) +#define USB_DisableOut3Int() USB_CLEAR_BITS(OUT1IE, OUT1IE_OUT3E__ENABLED); #endif /***************************************************************************//** @@ -1308,7 +1310,7 @@ extern void USB_DisableOut3Int(void); #ifdef IS_DOXYGEN extern void USB_EnableEp1(void); #else -#define USB_EnableEp1() USB_SET_BITS(EENABLE, EENABLE_EEN1__ENABLED) +#define USB_EnableEp1() USB_SET_BITS(EENABLE, EENABLE_EEN1__ENABLED); #endif /***************************************************************************//** @@ -1318,7 +1320,7 @@ extern void USB_EnableEp1(void); #ifdef IS_DOXYGEN extern void USB_DisableEp1(void); #else -#define USB_DisableEp1() USB_CLEAR_BITS(EENABLE, EENABLE_EEN1__ENABLED) +#define USB_DisableEp1() USB_CLEAR_BITS(EENABLE, EENABLE_EEN1__ENABLED); #endif /***************************************************************************//** @@ -1328,7 +1330,7 @@ extern void USB_DisableEp1(void); #ifdef IS_DOXYGEN extern void USB_EnableEp2(void); #else -#define USB_EnableEp2() USB_SET_BITS(EENABLE, EENABLE_EEN2__ENABLED) +#define USB_EnableEp2() USB_SET_BITS(EENABLE, EENABLE_EEN2__ENABLED); #endif /***************************************************************************//** @@ -1338,7 +1340,7 @@ extern void USB_EnableEp2(void); #ifdef IS_DOXYGEN extern void USB_DisableEp2(void); #else -#define USB_DisableEp2() USB_CLEAR_BITS(EENABLE, EENABLE_EEN2__ENABLED) +#define USB_DisableEp2() USB_CLEAR_BITS(EENABLE, EENABLE_EEN2__ENABLED); #endif /***************************************************************************//** @@ -1348,7 +1350,7 @@ extern void USB_DisableEp2(void); #ifdef IS_DOXYGEN extern void USB_EnableEp3(void); #else -#define USB_EnableEp3() USB_SET_BITS(EENABLE, EENABLE_EEN3__ENABLED) +#define USB_EnableEp3() USB_SET_BITS(EENABLE, EENABLE_EEN3__ENABLED); #endif /***************************************************************************//** @@ -1358,7 +1360,7 @@ extern void USB_EnableEp3(void); #ifdef IS_DOXYGEN extern void USB_DisableEp3(void); #else -#define USB_DisableEp3() USB_CLEAR_BITS(EENABLE, EENABLE_EEN3__ENABLED) +#define USB_DisableEp3() USB_CLEAR_BITS(EENABLE, EENABLE_EEN3__ENABLED); #endif /***************************************************************************//** @@ -1368,7 +1370,7 @@ extern void USB_DisableEp3(void); #ifdef IS_DOXYGEN extern void USB_EpnDirectionOut(void); #else -#define USB_EpnDirectionOut() USB_CLEAR_BITS(EINCSRH, EINCSRH_DIRSEL__IN) +#define USB_EpnDirectionOut() USB_CLEAR_BITS(EINCSRH, EINCSRH_DIRSEL__IN); #endif /***************************************************************************//** @@ -1378,7 +1380,7 @@ extern void USB_EpnDirectionOut(void); #ifdef IS_DOXYGEN extern void USB_EpnDirectionIn(void); #else -#define USB_EpnDirectionIn() USB_SET_BITS(EINCSRH, EINCSRH_DIRSEL__IN) +#define USB_EpnDirectionIn() USB_SET_BITS(EINCSRH, EINCSRH_DIRSEL__IN); #endif /***************************************************************************//** @@ -1389,7 +1391,7 @@ extern void USB_EpnDirectionIn(void); extern void USB_EpnEnableSplitMode(void); #else #define USB_EpnEnableSplitMode() \ - USB_SET_BITS(EINCSRH, EINCSRH_SPLIT__ENABLED) + USB_SET_BITS(EINCSRH, EINCSRH_SPLIT__ENABLED); #endif /***************************************************************************//** @@ -1400,7 +1402,7 @@ extern void USB_EpnEnableSplitMode(void); extern void USB_EpnDisableSplitMode(void); #else #define USB_EpnDisableSplitMode() \ - USB_CLEAR_BITS(EINCSRH, EINCSRH_SPLIT__ENABLED) + USB_CLEAR_BITS(EINCSRH, EINCSRH_SPLIT__ENABLED); #endif /***************************************************************************//** @@ -1410,7 +1412,7 @@ extern void USB_EpnDisableSplitMode(void); #ifdef IS_DOXYGEN extern void USB_EpnInClearDataToggle(void); #else -#define USB_EpnInClearDataToggle() USB_SET_BITS(EINCSRL, EINCSRL_CLRDT__BMASK) +#define USB_EpnInClearDataToggle() USB_SET_BITS(EINCSRL, EINCSRL_CLRDT__BMASK); #endif /***************************************************************************//** @@ -1420,7 +1422,7 @@ extern void USB_EpnInClearDataToggle(void); #ifdef IS_DOXYGEN extern void USB_EpnInClearSentStall(void); #else -#define USB_EpnInClearSentStall() USB_WRITE_BYTE(EINCSRL, 0) +#define USB_EpnInClearSentStall() USB_WRITE_BYTE(EINCSRL, 0); #endif /***************************************************************************//** @@ -1430,7 +1432,7 @@ extern void USB_EpnInClearSentStall(void); #ifdef IS_DOXYGEN extern void USB_EpnInStall(void); #else -#define USB_EpnInStall() USB_WRITE_BYTE(EINCSRL, EINCSRL_SDSTL__SET) +#define USB_EpnInStall() USB_WRITE_BYTE(EINCSRL, EINCSRL_SDSTL__SET); #endif /***************************************************************************//** @@ -1440,7 +1442,7 @@ extern void USB_EpnInStall(void); #ifdef IS_DOXYGEN extern void USB_EpnInEndStall(void); #else -#define USB_EpnInEndStall() USB_WRITE_BYTE(EINCSRL, 0) +#define USB_EpnInEndStall() USB_WRITE_BYTE(EINCSRL, 0); #endif /***************************************************************************//** @@ -1452,7 +1454,7 @@ extern void USB_EpnInEndStall(void); extern void USB_EpnInEndStallAndClearDataToggle(void); #else #define USB_EpnInEndStallAndClearDataToggle() \ - USB_WRITE_BYTE(EINCSRL, EINCSRL_CLRDT__BMASK) + USB_WRITE_BYTE(EINCSRL, EINCSRL_CLRDT__BMASK); #endif /***************************************************************************//** @@ -1470,7 +1472,7 @@ extern void USB_EpnInFlush(void); { \ USB_READ_BYTE(EINCSRL); \ } while (USB0DAT & EINCSRL_FLUSH__SET); \ - } while (0) + } while (0); #endif /***************************************************************************//** @@ -1480,7 +1482,7 @@ extern void USB_EpnInFlush(void); #ifdef IS_DOXYGEN extern void USB_EpnInClearUnderrun(void); #else -#define USB_EpnInClearUnderrun() USB_CLEAR_BITS(EINCSRL, EINCSRL_UNDRUN__SET) +#define USB_EpnInClearUnderrun() USB_CLEAR_BITS(EINCSRL, EINCSRL_UNDRUN__SET); #endif /***************************************************************************//** @@ -1490,7 +1492,7 @@ extern void USB_EpnInClearUnderrun(void); #ifdef IS_DOXYGEN extern void USB_EpnSetInPacketReady(void); #else -#define USB_EpnSetInPacketReady() USB_SET_BITS(EINCSRL, EINCSRL_INPRDY__SET) +#define USB_EpnSetInPacketReady() USB_SET_BITS(EINCSRL, EINCSRL_INPRDY__SET); #endif /***************************************************************************//** @@ -1501,7 +1503,7 @@ extern void USB_EpnSetInPacketReady(void); extern void USB_EpnInEnableDoubleBuffer(void); #else #define USB_EpnInEnableDoubleBuffer() \ - USB_SET_BITS(EINCSRH, EINCSRH_DBIEN__ENABLED) + USB_SET_BITS(EINCSRH, EINCSRH_DBIEN__ENABLED); #endif /***************************************************************************//** @@ -1512,7 +1514,7 @@ extern void USB_EpnInEnableDoubleBuffer(void); extern void USB_EpnInDisableDoubleBuffer(void); #else #define USB_EpnInDisableDoubleBuffer() \ - USB_CLEAR_BITS(EINCSRH, EINCSRH_DBIEN__ENABLED) + USB_CLEAR_BITS(EINCSRH, EINCSRH_DBIEN__ENABLED); #endif /***************************************************************************//** @@ -1523,7 +1525,7 @@ extern void USB_EpnInDisableDoubleBuffer(void); extern void USB_EpnInEnableInterruptBulkMode(void); #else #define USB_EpnInEnableInterruptBulkMode() \ - USB_CLEAR_BITS(EINCSRH, EINCSRH_ISO__ENABLED) + USB_CLEAR_BITS(EINCSRH, EINCSRH_ISO__ENABLED); #endif /***************************************************************************//** @@ -1534,7 +1536,7 @@ extern void USB_EpnInEnableInterruptBulkMode(void); extern void USB_EpnInEnableIsochronousMode(void); #else #define USB_EpnInEnableIsochronousMode() \ - USB_SET_BITS(EINCSRH, EINCSRH_ISO__ENABLED) + USB_SET_BITS(EINCSRH, EINCSRH_ISO__ENABLED); #endif /***************************************************************************//** @@ -1545,7 +1547,7 @@ extern void USB_EpnInEnableIsochronousMode(void); extern void USB_EpnInEnableForcedDataToggle(void); #else #define USB_EpnInEnableForcedDataToggle() \ - USB_SET_BITS(EINCSRH, EINCSRH_FCDT__ALWAYS_TOGGLE) + USB_SET_BITS(EINCSRH, EINCSRH_FCDT__ALWAYS_TOGGLE); #endif /***************************************************************************//** @@ -1556,7 +1558,7 @@ extern void USB_EpnInEnableForcedDataToggle(void); extern void USB_EpnInDisableForcedDataToggle(void); #else #define USB_EpnInDisableForcedDataToggle() \ - USB_CLEAR_BITS(EINCSRH, EINCSRH_FCDT__ALWAYS_TOGGLE) + USB_CLEAR_BITS(EINCSRH, EINCSRH_FCDT__ALWAYS_TOGGLE); #endif /***************************************************************************//** @@ -1567,7 +1569,7 @@ extern void USB_EpnInDisableForcedDataToggle(void); extern void USB_EpnOutClearDataToggle(void); #else #define USB_EpnOutClearDataToggle() \ - USB_SET_BITS(EOUTCSRL, EOUTCSRL_CLRDT__BMASK) + USB_SET_BITS(EOUTCSRL, EOUTCSRL_CLRDT__BMASK); #endif /***************************************************************************//** @@ -1578,7 +1580,7 @@ extern void USB_EpnOutClearDataToggle(void); extern void USB_EpnOutClearSentStall(void); #else #define USB_EpnOutClearSentStall() \ - USB_CLEAR_BITS(EOUTCSRL, EOUTCSRL_STSTL__BMASK) + USB_CLEAR_BITS(EOUTCSRL, EOUTCSRL_STSTL__BMASK); #endif /***************************************************************************//** @@ -1589,7 +1591,7 @@ extern void USB_EpnOutClearSentStall(void); extern void USB_EpnOutStall(void); #else #define USB_EpnOutStall() \ - USB_SET_BITS(EOUTCSRL, EOUTCSRL_SDSTL__SET) + USB_SET_BITS(EOUTCSRL, EOUTCSRL_SDSTL__SET); #endif /***************************************************************************//** @@ -1599,7 +1601,7 @@ extern void USB_EpnOutStall(void); #ifdef IS_DOXYGEN extern void USB_EpnOutEndStall(void); #else -#define USB_EpnOutEndStall() USB_CLEAR_BITS(EOUTCSRL, EOUTCSRL_SDSTL__SET) +#define USB_EpnOutEndStall() USB_CLEAR_BITS(EOUTCSRL, EOUTCSRL_SDSTL__SET); #endif /***************************************************************************//** @@ -1618,7 +1620,7 @@ extern void USB_EpnOutEndStallAndClearDataToggle(void); while (USB0ADR & USB0ADR_BUSY__SET) {} \ USB0DAT |= EOUTCSRL_CLRDT__BMASK; \ while (USB0ADR & USB0ADR_BUSY__SET) {} \ - } while (0) + } while (0); #endif /***************************************************************************//** @@ -1636,7 +1638,7 @@ extern void USB_EpnOutFlush(void); { \ USB_READ_BYTE(EOUTCSRL); \ } while (USB0DAT & EOUTCSRL_FLUSH__SET); \ - } while (0) + } while (0); #endif /***************************************************************************//** @@ -1646,7 +1648,7 @@ extern void USB_EpnOutFlush(void); #ifdef IS_DOXYGEN extern void USB_EpnOutClearOverrun(void); #else -#define USB_EpnOutClearOverrun() USB_CLEAR_BITS(EOUTCSRL, EOUTCSRL_OVRUN__SET) +#define USB_EpnOutClearOverrun() USB_CLEAR_BITS(EOUTCSRL, EOUTCSRL_OVRUN__SET); #endif /***************************************************************************//** @@ -1657,7 +1659,7 @@ extern void USB_EpnOutClearOverrun(void); extern void USB_EpnClearOutPacketReady(void); #else #define USB_EpnClearOutPacketReady() \ - USB_CLEAR_BITS(EOUTCSRL, EOUTCSRL_OPRDY__SET) + USB_CLEAR_BITS(EOUTCSRL, EOUTCSRL_OPRDY__SET); #endif /***************************************************************************//** @@ -1668,7 +1670,7 @@ extern void USB_EpnClearOutPacketReady(void); extern void USB_EpnOutEnableDoubleBuffer(void); #else #define USB_EpnOutEnableDoubleBuffer() \ - USB_SET_BITS(EOUTCSRH, EOUTCSRH_DBIEN__ENABLED) + USB_SET_BITS(EOUTCSRH, EOUTCSRH_DBIEN__ENABLED); #endif /***************************************************************************//** @@ -1679,7 +1681,7 @@ extern void USB_EpnOutEnableDoubleBuffer(void); extern void USB_EpnOutDisableDoubleBuffer(void); #else #define USB_EpnOutDisableDoubleBuffer() \ - USB_CLEAR_BITS(EOUTCSRH, EOUTCSRH_DBIEN__ENABLED) + USB_CLEAR_BITS(EOUTCSRH, EOUTCSRH_DBIEN__ENABLED); #endif /***************************************************************************//** @@ -1690,7 +1692,7 @@ extern void USB_EpnOutDisableDoubleBuffer(void); extern void USB_EpnOutEnableInterruptBulkMode(void); #else #define USB_EpnOutEnableInterruptBulkMode() \ - USB_CLEAR_BITS(EOUTCSRH, EOUTCSRH_ISO__ENABLED) + USB_CLEAR_BITS(EOUTCSRH, EOUTCSRH_ISO__ENABLED); #endif /***************************************************************************//** @@ -1701,7 +1703,7 @@ extern void USB_EpnOutEnableInterruptBulkMode(void); extern void USB_EpnOutEnableIsochronousMode(void); #else #define USB_EpnOutEnableIsochronousMode() \ - USB_SET_BITS(EOUTCSRH, EOUTCSRH_ISO__ENABLED) + USB_SET_BITS(EOUTCSRH, EOUTCSRH_ISO__ENABLED); #endif /***************************************************************************//** @@ -1719,7 +1721,7 @@ extern void USB_EnableReadFIFO(uint8_t fifoNum); while (USB0ADR & USB0ADR_BUSY__SET) {} \ USB0ADR = (USB0ADR_BUSY__SET \ | USB0ADR_AUTORD__ENABLED \ - | (FIFO0 | (fifoNum))); \ + | (FIFO0 | fifoNum)); \ } while (0) #endif @@ -1742,13 +1744,13 @@ extern void USB_DisableReadFIFO(uint8_t fifoNum); * @note This function is implemented as a macro. ******************************************************************************/ #ifdef IS_DOXYGEN -extern void USB_GetFIFOByte(uint8_t *readDat); +extern void USB_GetFIFOByte(uint8_t * readDat); #else #define USB_GetFIFOByte(readDat) \ do \ { \ while (USB0ADR & USB0ADR_BUSY__SET) {} \ - *(readDat) = USB0DAT; \ + readDat = USB0DAT; \ } while (0) #endif @@ -1764,14 +1766,14 @@ extern void USB_GetFIFOByte(uint8_t *readDat); * @note This function is implemented as a macro. ******************************************************************************/ #ifdef IS_DOXYGEN -extern void USB_GetLastFIFOByte(uint8_t *readDat, uint8_t fifoNum); +extern void USB_GetLastFIFOByte(uint8_t * readDat, uint8_t fifoNum); #else #define USB_GetLastFIFOByte(readDat, fifoNum) \ do \ { \ while (USB0ADR & USB0ADR_BUSY__SET) {} \ - USB0ADR = (FIFO0 | (fifoNum));\ - *(readDat) = USB0DAT; \ + USB0ADR = (FIFO0 | fifoNum);\ + readDat = USB0DAT; \ } while (0) #endif @@ -1788,7 +1790,7 @@ extern void USB_EnableWriteFIFO(uint8_t fifoNum); do \ { \ while (USB0ADR & USB0ADR_BUSY__SET) {} \ - USB0ADR = (FIFO0 | (fifoNum)); \ + USB0ADR = (FIFO0 | fifoNum); \ } while (0) #endif @@ -1817,7 +1819,7 @@ extern void USB_SetFIFOByte(uint8_t writeDat); do \ { \ while (USB0ADR & USB0ADR_BUSY__SET) {} \ - USB0DAT = (writeDat); \ + USB0DAT = writeDat; \ } while (0) #endif @@ -1850,98 +1852,92 @@ extern void USB_RestoreSfrPage(); * @param epsel * Endpoint index to target ******************************************************************************/ -extern void USB_SetIndex(uint8_t epsel); +void USB_SetIndex(uint8_t epsel); /***************************************************************************//** * @brief Reads the USB common interrupt register * @return Value of CMINT ******************************************************************************/ -extern uint8_t USB_GetCommonInts(void); +uint8_t USB_GetCommonInts(void); /***************************************************************************//** * @brief Reads the USB in interrupt register * @return Value of IN1INT ******************************************************************************/ -extern uint8_t USB_GetInInts(void); +uint8_t USB_GetInInts(void); /***************************************************************************//** * @brief Reads the out interrupt register * @return Value of OUT1INT ******************************************************************************/ -extern uint8_t USB_GetOutInts(void); +uint8_t USB_GetOutInts(void); /***************************************************************************//** * @brief Reads the value in INDEX * @return Value of INDEX ******************************************************************************/ -extern uint8_t USB_GetIndex(void); +uint8_t USB_GetIndex(void); /***************************************************************************//** * @brief Determines if the USB is currently suspended * @return TRUE if USB is in suspend mode ******************************************************************************/ -extern bool USB_IsSuspended(void); +bool USB_IsSuspended(void); /***************************************************************************//** * @brief Gets Setup End state * @return TRUE when a control transaction end before software has * set the DATAEND bit. ******************************************************************************/ -extern bool USB_GetSetupEnd(void); +bool USB_GetSetupEnd(void); /***************************************************************************//** * @brief Determines if STALL was send on Endpoint 0 * @return TRUE after a STALL was sent on Endpoint 0 ******************************************************************************/ -extern bool USB_Ep0SentStall(void); +bool USB_Ep0SentStall(void); /***************************************************************************//** * @brief Determines if Out Packet Ready is set on Endpoint 0 * @return TRUE if Out Packet Ready is set on Endpoint 0 ******************************************************************************/ -extern bool USB_Ep0InPacketReady(void); +bool USB_Ep0InPacketReady(void); /***************************************************************************//** * @brief Determines if In Packet Ready is set on Endpoint 0 * @return TRUE if In Packet Ready is set on Endpoint 0 ******************************************************************************/ -extern bool USB_Ep0OutPacketReady(void); +bool USB_Ep0OutPacketReady(void); /***************************************************************************//** * @brief Gets Endpoint 0 data count * @return Number of received data bytes in the Endpoint 0 FIFO ******************************************************************************/ -extern uint8_t USB_Ep0GetCount(void); +uint8_t USB_Ep0GetCount(void); /***************************************************************************//** * @brief Checks if stall was sent on IN Endpoint N * @return TRUE if stall was sent on IN Endpoint N, FALSE otherwise ******************************************************************************/ -extern bool USB_EpnInGetSentStall(void); +bool USB_EpnInGetSentStall(void); /***************************************************************************//** * @brief Checks if stall was sent on OUT Endpoint N * @return TRUE if stall was sent on OUT Endpoint N, FALSE otherwise ******************************************************************************/ -extern bool USB_EpnGetInPacketReady(void); +bool USB_EpnGetInPacketReady(void); /***************************************************************************//** * @brief Checks if stall was sent on OUT Endpoint N * @return TRUE if stall was sent on OUT Endpoint N, FALSE otherwise ******************************************************************************/ -extern bool USB_EpnOutGetSentStall(void); +bool USB_EpnOutGetSentStall(void); /***************************************************************************//** * @brief Gets OutPacketReady on OUT Endpoint N * @return TRUE if OUTPacketReady is set, FALSE otherwise ******************************************************************************/ -extern bool USB_EpnGetOutPacketReady(void); - -/***************************************************************************//** - * @brief Gets DataError on OUT Endpoint N - * @return TRUE if Data Error bit is set, FALSE otherwise - ******************************************************************************/ -extern bool USB_EpnGetDataError(void); +bool USB_EpnGetOutPacketReady(void); /***************************************************************************//** * @brief Gets number of bytes in the OUT FIFO @@ -1949,27 +1945,27 @@ extern bool USB_EpnGetDataError(void); * @return Number of bytes in the FIFO from the last received * packet ******************************************************************************/ -extern uint16_t USB_EpOutGetCount(void); +uint16_t USB_EpOutGetCount(void); /***************************************************************************//** * @brief Reads the USB frame number * @return The frame number on the most recent SOF packet ******************************************************************************/ -extern uint16_t USB_GetSofNumber(void); +uint16_t USB_GetSofNumber(void); /***************************************************************************//** * @brief Aborts pending IN transactions on the selected endpoint * @param fifoNum * Endpoint to abort ******************************************************************************/ -extern void USB_AbortInEp(uint8_t fifoNum); +void USB_AbortInEp(uint8_t fifoNum); /***************************************************************************//** * @brief Aborts pending OUT transactions on the selected endpoint * @param fifoNum * Endpoint to abort ******************************************************************************/ -extern void USB_AbortOutEp(uint8_t fifoNum); +void USB_AbortOutEp(uint8_t fifoNum); /***************************************************************************//** * @brief Activates the selected endpoint @@ -1984,11 +1980,11 @@ extern void USB_AbortOutEp(uint8_t fifoNum); * @param isoMode * Set to 1 if endpoint is in isochronous mode, 0 if it is not ******************************************************************************/ -extern void USB_ActivateEp(uint8_t ep, - uint16_t packetSize, - bool inDir, - bool splitMode, - bool isoMode); +void USB_ActivateEp(uint8_t ep, + uint16_t packetSize, + bool inDir, + bool splitMode, + bool isoMode); /** @} (end addtogroup usb_0_runtime USB0 Runtime API) */ /** @} (end addtogroup usb_0_group USB0 Driver) */ diff --git a/efm8/lib/efm8ub1/peripheralDrivers/src/usb_0.c b/efm8/lib/efm8ub1/peripheralDrivers/src/usb_0.c index 91a03ea..9c44e3f 100644 --- a/efm8/lib/efm8ub1/peripheralDrivers/src/usb_0.c +++ b/efm8/lib/efm8ub1/peripheralDrivers/src/usb_0.c @@ -18,7 +18,7 @@ /**************************************************************************//** * @brief Reads a 16-bit indirect USB register value - * @param [in] regAddr + * @param regAddr * Address of high byte of 16-bit USB indirect register to read * @return 16-bit register value *****************************************************************************/ @@ -127,12 +127,6 @@ bool USB_EpnGetOutPacketReady(void) return (bool)(USB0DAT & EOUTCSRL_OPRDY__SET); } -bool USB_EpnGetDataError(void) -{ - USB_READ_BYTE(EOUTCSRL); - return (bool)(USB0DAT & EOUTCSRL_DATERR__SET); -} - uint16_t USB_EpOutGetCount(void) { return USB_GetShortRegister(EOUTCNTH); diff --git a/efm8/src/InitDevice.c b/efm8/src/InitDevice.c index 1c75b3c..2f86874 100644 --- a/efm8/src/InitDevice.c +++ b/efm8/src/InitDevice.c @@ -29,8 +29,8 @@ extern void enter_DefaultMode_from_RESET(void) { WDT_0_enter_DefaultMode_from_RESET(); PORTS_0_enter_DefaultMode_from_RESET(); PORTS_1_enter_DefaultMode_from_RESET(); - PORTS_2_enter_DefaultMode_from_RESET(); PBCFG_0_enter_DefaultMode_from_RESET(); + LFOSC_0_enter_DefaultMode_from_RESET(); CIP51_0_enter_DefaultMode_from_RESET(); CLOCK_0_enter_DefaultMode_from_RESET(); TIMER01_0_enter_DefaultMode_from_RESET(); @@ -184,14 +184,14 @@ extern void TIMER_SETUP_0_enter_DefaultMode_from_RESET(void) { - System clock divided by 4 - Counter/Timer 0 uses the clock defined by the prescale field, SCA - Timer 2 high byte uses the clock defined by T2XCLK in TMR2CN0 - - Timer 2 low byte uses the system clock + - Timer 2 low byte uses the clock defined by T2XCLK in TMR2CN0 - Timer 3 high byte uses the clock defined by T3XCLK in TMR3CN0 - - Timer 3 low byte uses the system clock + - Timer 3 low byte uses the clock defined by T3XCLK in TMR3CN0 - Timer 1 uses the system clock ***********************************************************************/ CKCON0 = CKCON0_SCA__SYSCLK_DIV_4 | CKCON0_T0M__PRESCALE - | CKCON0_T2MH__EXTERNAL_CLOCK | CKCON0_T2ML__SYSCLK - | CKCON0_T3MH__EXTERNAL_CLOCK | CKCON0_T3ML__SYSCLK + | CKCON0_T2MH__EXTERNAL_CLOCK | CKCON0_T2ML__EXTERNAL_CLOCK + | CKCON0_T3MH__EXTERNAL_CLOCK | CKCON0_T3ML__EXTERNAL_CLOCK | CKCON0_T1M__SYSCLK; // [CKCON0 - Clock Control 0]$ @@ -288,23 +288,19 @@ extern void TIMER16_2_enter_DefaultMode_from_RESET(void) { // $[TMR2RLH - Timer 2 Reload High Byte] /*********************************************************************** - - Timer 2 Reload High Byte = 0x44 + - Timer 2 Reload High Byte = 0x63 ***********************************************************************/ - TMR2RLH = (0x44 << TMR2RLH_TMR2RLH__SHIFT); + TMR2RLH = (0x63 << TMR2RLH_TMR2RLH__SHIFT); // [TMR2RLH - Timer 2 Reload High Byte]$ // $[TMR2RLL - Timer 2 Reload Low Byte] /*********************************************************************** - - Timer 2 Reload Low Byte = 0x80 + - Timer 2 Reload Low Byte = 0xC0 ***********************************************************************/ - TMR2RLL = (0x80 << TMR2RLL_TMR2RLL__SHIFT); + TMR2RLL = (0xC0 << TMR2RLL_TMR2RLL__SHIFT); // [TMR2RLL - Timer 2 Reload Low Byte]$ // $[TMR2CN0] - /*********************************************************************** - - Start Timer 2 running - ***********************************************************************/ - TMR2CN0 |= TMR2CN0_TR2__RUN; // [TMR2CN0]$ // $[Timer Restoration] @@ -327,6 +323,10 @@ extern void TIMER16_3_enter_DefaultMode_from_RESET(void) { // [TMR3CN1 - Timer 3 Control 1]$ // $[TMR3CN0 - Timer 3 Control] + /*********************************************************************** + - Timer 3 clock is the low-frequency oscillator divided by 8 + ***********************************************************************/ + TMR3CN0 |= TMR3CN0_T3XCLK__LFOSC_DIV_8; // [TMR3CN0 - Timer 3 Control]$ // $[TMR3H - Timer 3 High Byte] @@ -342,6 +342,10 @@ extern void TIMER16_3_enter_DefaultMode_from_RESET(void) { // [TMR3RLL - Timer 3 Reload Low Byte]$ // $[TMR3CN0] + /*********************************************************************** + - Start Timer 3 running + ***********************************************************************/ + TMR3CN0 |= TMR3CN0_TR3__RUN; // [TMR3CN0]$ // $[Timer Restoration] @@ -408,7 +412,7 @@ extern void PORTS_1_enter_DefaultMode_from_RESET(void) { // $[P1MDOUT - Port 1 Output Mode] /*********************************************************************** - P1.0 output is open-drain - - P1.1 output is open-drain + - P1.1 output is push-pull - P1.2 output is open-drain - P1.3 output is open-drain - P1.4 output is push-pull @@ -416,7 +420,7 @@ extern void PORTS_1_enter_DefaultMode_from_RESET(void) { - P1.6 output is push-pull - P1.7 output is open-drain ***********************************************************************/ - P1MDOUT = P1MDOUT_B0__OPEN_DRAIN | P1MDOUT_B1__OPEN_DRAIN + P1MDOUT = P1MDOUT_B0__OPEN_DRAIN | P1MDOUT_B1__PUSH_PULL | P1MDOUT_B2__OPEN_DRAIN | P1MDOUT_B3__OPEN_DRAIN | P1MDOUT_B4__PUSH_PULL | P1MDOUT_B5__PUSH_PULL | P1MDOUT_B6__PUSH_PULL | P1MDOUT_B7__OPEN_DRAIN; @@ -520,9 +524,9 @@ extern void UART_0_enter_DefaultMode_from_RESET(void) { extern void SPI_0_enter_DefaultMode_from_RESET(void) { // $[SPI0CKR - SPI0 Clock Rate] /*********************************************************************** - - SPI0 Clock Rate = 0x17 + - SPI0 Clock Rate = 0x0B ***********************************************************************/ - SPI0CKR = (0x17 << SPI0CKR_SPI0CKR__SHIFT); + SPI0CKR = (0x0B << SPI0CKR_SPI0CKR__SHIFT); // [SPI0CKR - SPI0 Clock Rate]$ // $[SPI0FCN0 - SPI0 FIFO Control 0] @@ -545,3 +549,20 @@ extern void SPI_0_enter_DefaultMode_from_RESET(void) { } +extern void LFOSC_0_enter_DefaultMode_from_RESET(void) { + // $[LFO0CN - Low Frequency Oscillator Control] + /*********************************************************************** + - Internal L-F Oscillator Enabled + - Divide by 8 selected + ***********************************************************************/ + LFO0CN &= ~LFO0CN_OSCLD__FMASK; + LFO0CN |= LFO0CN_OSCLEN__ENABLED; + // [LFO0CN - Low Frequency Oscillator Control]$ + + // $[Wait for LFOSC Ready] + while ((LFO0CN & LFO0CN_OSCLRDY__BMASK) != LFO0CN_OSCLRDY__SET) + ; + // [Wait for LFOSC Ready]$ + +} + diff --git a/efm8/src/callback.c b/efm8/src/callback.c index cf9008f..968e4b2 100644 --- a/efm8/src/callback.c +++ b/efm8/src/callback.c @@ -38,6 +38,7 @@ uint8_t tmpBuffer; void USBD_ResetCb(void) { +// cprints("USBD_ResetCb\r\n"); // u2f_print_ev("USBD_ResetCb\r\n"); } @@ -45,6 +46,7 @@ void USBD_ResetCb(void) { void USBD_DeviceStateChangeCb(USBD_State_TypeDef oldState, USBD_State_TypeDef newState) { +// cprints("USBD_DeviceStateChangeCb\r\n"); UNUSED(oldState); UNUSED(newState); @@ -52,6 +54,7 @@ void USBD_DeviceStateChangeCb(USBD_State_TypeDef oldState, } bool USBD_IsSelfPoweredCb(void) { +// cprints("USBD_IsSelfPoweredCb\r\n"); return false; } @@ -60,19 +63,22 @@ USB_Status_TypeDef USBD_SetupCmdCb( SI_VARIABLE_SEGMENT_POINTER(setup, USB_Setup_TypeDef, MEM_MODEL_SEG)) { USB_Status_TypeDef retVal = USB_STATUS_REQ_UNHANDLED; - +// USB_Status_TypeDef retVal = USB_STATUS_OK; +// cprints("USBD_SetupCmdCb\r\n"); if ((setup->bmRequestType.Type == USB_SETUP_TYPE_STANDARD) && (setup->bmRequestType.Direction == USB_SETUP_DIR_IN) && (setup->bmRequestType.Recipient == USB_SETUP_RECIPIENT_INTERFACE)) { // A HID device must extend the standard GET_DESCRIPTOR command // with support for HID descriptors. - +// cprints("USB_SETUP_TYPE_STANDARD\r\n"); switch (setup->bRequest) { case GET_DESCRIPTOR: +// cprints("GET_DESCRIPTOR\r\n"); if (setup->wIndex == 0) { if ((setup->wValue >> 8) == USB_HID_REPORT_DESCRIPTOR) { +// cprints("1\r\n"); USBD_Write(EP0, ReportDescriptor0, EFM8_MIN(sizeof(ReportDescriptor0), setup->wLength), @@ -80,7 +86,7 @@ USB_Status_TypeDef USBD_SetupCmdCb( retVal = USB_STATUS_OK; } else if ((setup->wValue >> 8) == USB_HID_DESCRIPTOR) { - +// cprints("2\r\n"); USBD_Write(EP0, (&configDesc[18]), EFM8_MIN(USB_HID_DESCSIZE, setup->wLength), false); retVal = USB_STATUS_OK; @@ -94,10 +100,12 @@ USB_Status_TypeDef USBD_SetupCmdCb( && (setup->bmRequestType.Recipient == USB_SETUP_RECIPIENT_INTERFACE) && (setup->wIndex == HID_INTERFACE_INDEX)) { +// cprints("USB_SETUP_TYPE_CLASS\r\n"); // Implement the necessary HID class specific commands. switch (setup->bRequest) { case USB_HID_SET_IDLE: +// cprints("USB_HID_SET_IDLE\r\n"); if (((setup->wValue & 0xFF) == 0) // Report ID && (setup->wLength == 0) && (setup->bmRequestType.Direction != USB_SETUP_DIR_IN)) @@ -107,6 +115,7 @@ USB_Status_TypeDef USBD_SetupCmdCb( break; case USB_HID_GET_IDLE: +// cprints("USB_HID_GET_IDLE\r\n"); if ((setup->wValue == 0) // Report ID && (setup->wLength == 1) && (setup->bmRequestType.Direction == USB_SETUP_DIR_IN)) @@ -120,6 +129,10 @@ USB_Status_TypeDef USBD_SetupCmdCb( break; } } + else + { +// cprints("nothing\r\n"); + } return retVal; } diff --git a/efm8/src/eeprom.c b/efm8/src/eeprom.c new file mode 100644 index 0000000..80ff675 --- /dev/null +++ b/efm8/src/eeprom.c @@ -0,0 +1,79 @@ +#include +#include + +#include "eeprom.h" +#include "printing.h" + +char __erase_mem[3]; + +static void erase_ram() +{ + data uint16_t i; + data uint8_t xdata * clear = 0; + for (i=0; i<0x400;i++) + { + *(clear++) = 0x0; + } +} + + +void eeprom_init() +{ + uint8_t secbyte; + eeprom_read(0xFBFF,&secbyte,1); + if (secbyte == 0xff) + { + eeprom_erase(0xFBC0); + secbyte = -32; + eeprom_write(0xFBFF, &secbyte, 1); + erase_ram(); + // Reboot + cprints("rebooting\r\n"); + RSTSRC = (1<<4); + } + else + { +// cprints("no reboot\r\n"); + } +} + +void eeprom_read(uint16_t addr, uint8_t * buf, uint8_t len) +{ + uint8_t code * eepaddr = (uint8_t code *) addr; + bit old_int; + + while(len--) + { + old_int = IE_EA; + IE_EA = 0; + *buf++ = *eepaddr++; + IE_EA = old_int; + } +} + +void _eeprom_write(uint16_t addr, uint8_t * buf, uint8_t len, uint8_t flags) +{ + uint8_t xdata * data eepaddr = (uint8_t xdata *) addr; + bit old_int; + + while(len--) + { + old_int = IE_EA; + IE_EA = 0; + // Enable VDD monitor + VDM0CN = 0x80; + RSTSRC = 0x02; + + // unlock key + FLKEY = 0xA5; + FLKEY = 0xF1; + PSCTL |= flags; + + *eepaddr = *buf; + PSCTL &= ~flags; + IE_EA = old_int; + + eepaddr++; + buf++; + } +} diff --git a/efm8/src/main.c b/efm8/src/main.c index c1d075a..575e0b3 100644 --- a/efm8/src/main.c +++ b/efm8/src/main.c @@ -4,13 +4,16 @@ #include "uart_1.h" #include "printing.h" -#define BUFFER_SIZE 10 +#define BUFFER_SIZE 13 -uint8_t write_ptr = 0; -uint8_t read_ptr = 0; -uint8_t count = 0; +data uint8_t write_ptr = 0; +data uint8_t read_ptr = 0; +data uint8_t i_ptr = 0; +data uint8_t count = 0; +data uint8_t writebackbuf_count = 0; uint8_t hidmsgbuf[64][BUFFER_SIZE]; +data uint8_t writebackbuf[64]; void usb_transfer_complete() { @@ -20,81 +23,129 @@ void usb_transfer_complete() { write_ptr = 0; } - cprints("read hid msg\r\n"); + if (count == 1 && i_ptr == 0) + { + SPI0DAT = hidmsgbuf[read_ptr][i_ptr++]; + } + + +// MSG_RDY_INT_PIN = 0; +// MSG_RDY_INT_PIN = 1; + } void spi_transfer_complete() { count--; + i_ptr = 0; + SPI0FCN0 |= (1<<2); // Flush rx fifo buffer + if (count) + { + SPI0DAT = hidmsgbuf[read_ptr][i_ptr++]; + } read_ptr++; + if (read_ptr == BUFFER_SIZE) { read_ptr = 0; } - cprints("sent hid msg\r\n"); + +// cprints("sent hid msg\r\n"); } SI_INTERRUPT (SPI0_ISR, SPI0_IRQn) { - - static unsigned char command; - static unsigned char array_index = 0; - static unsigned char state = 0; - char arr[2]; - if (SPI0CN0_WCOL == 1) { - // Write collision occurred - SPI0CN0_WCOL = 0; // Clear the Write collision flag + // Write collision occurred + SPI0CN0_WCOL = 0; +// cprints("SPI0CN0_WCOL\r\n"); } else if(SPI0CN0_RXOVRN == 1) { - // Receive overrun occurred - SPI0CN0_RXOVRN = 0; // Clear the Receive Overrun flag + // Receive overrun occurred + SPI0CN0_RXOVRN = 0; +// cprints("SPI0CN0_RXOVRN\r\n"); } else { - // SPI0CN0_SPIF caused the interrupt + if (EFM32_RW_PIN) + { + if (writebackbuf_count < 64) writebackbuf[writebackbuf_count++] = SPI0DAT; + else cprints("overflow\r\n"); + } + else + { + if (count) + { + if (i_ptr < 64) + { + SPI0DAT = hidmsgbuf[read_ptr][i_ptr++]; - arr[0] = SPI0DAT; // Read the command - arr[1] = 0; - - cprints("got data: "); - cprints(arr); - cprints("\n\r"); - - - - SPI0CN0_SPIF = 0; // Clear the SPIF0 flag + } + else + { + spi_transfer_complete(); + } + } + } + SPI0CN0_SPIF = 0; } } +void usb_write() +{ + data uint8_t errors = 0; + while (USB_STATUS_OK != (USBD_Write(EP1IN, writebackbuf, 64, false))) + { + delay(2); + if (errors++ > 30) + { + cprints("ERROR USB WRITE\r\n"); + break; + } + } +} + int main(void) { - volatile int xdata i,j,k; + uint8_t k; + uint16_t t1 = 0; uint8_t lastcount = count; + + int reset; + data int lastwritecount = writebackbuf_count; + enter_DefaultMode_from_RESET(); - IE_EA = 1; + + eeprom_init(); + SCON0_TI = 1; P2_B0 = 1; + + MSG_RDY_INT_PIN = 1; + + // enable SPI interrupts + SPI0FCN1 = SPI0FCN1 | (1<<4); + IE_EA = 1; + IE_ESPI0 = 1; + cprints("hello,world\r\n"); - + reset = RSTSRC; + cprintx("reset source: ", 1, reset); while (1) { - k++; - for (i = 0; i < 1000; i++) +// delay(1500); + if (millis() - t1 > 1500) { - for (j = 0; j < 100; j++) - { - - } - P1_B4 = i&1; + P1_B5 = k++&1; + t1 = millis(); } - P1_B5 = k&1; if (!USBD_EpIsBusy(EP1OUT) && !USBD_EpIsBusy(EP1IN)) { +// cprintd("sched read to ",1,reset); if (count == BUFFER_SIZE) { cprints("Warning, USB buffer full\r\n"); @@ -104,9 +155,32 @@ int main(void) { USBD_Read(EP1OUT, hidmsgbuf[write_ptr], 64, true); } } - if (count != lastcount) + + if (writebackbuf_count == 64) { - cprints("+1 to count \r\n"); +// cprints("<< "); +// dump_hex(writebackbuf,64); + writebackbuf_count = 0; +// while (USBD_EpIsBusy(EP1IN)) +// ; + usb_write(); + } + + if (lastcount != count) + { + if (count > lastcount) + { +// cprints(">> "); +// dump_hex(writebackbuf,64); + + MSG_RDY_INT_PIN = 0; + MSG_RDY_INT_PIN = 1; + } + else + { +// cprints("efm32 read hid msg\r\n>> "); +// dump_hex(debug,64); + } lastcount = count; } diff --git a/efm8/src/printing.c b/efm8/src/printing.c index 48d4e61..d5edd85 100644 --- a/efm8/src/printing.c +++ b/efm8/src/printing.c @@ -11,6 +11,13 @@ #include #include "printing.h" +void delay(uint16_t ms) +{ + uint16_t m1 = millis(); + while (millis() - m1 < ms) + ; +} +#ifdef USE_PRINTING void putf(char c) { uint8_t i; @@ -19,20 +26,23 @@ void putf(char c) for (i=0; i<200; i++){} for (i=0; i<200; i++){} for (i=0; i<190; i++){} -// watchdog(); } + + void dump_hex(uint8_t* hex, uint8_t len) { uint8_t i; + uint8_t b; + const char lut[] = "0123456789abcdef"; for (i=0 ; i < len ; i++) { - if (hex[i]<0x10) - { - putf('0'); - } - cputb(hex[i]); + b = ((*hex) & 0xf0)>>4; + putf(lut[b]); + b = ((*hex) & 0x0f); + putf(lut[b]); + hex++; } cprints("\r\n"); } @@ -169,3 +179,4 @@ void cprintlx(const char * tag, uint8_t c, ...) put_line(); va_end(args); } +#endif diff --git a/fido2/main.c b/fido2/main.c index 5c2c02f..074388f 100644 --- a/fido2/main.c +++ b/fido2/main.c @@ -23,12 +23,12 @@ int main(int argc, char * argv[]) set_logging_mask( /*0*/ - /*TAG_GEN|*/ + TAG_GEN| /*TAG_MC |*/ /*TAG_GA |*/ /*TAG_CP |*/ TAG_CTAP| - /*TAG_HID|*/ + TAG_HID| /*TAG_U2F|*/ /*TAG_PARSE |*/ /*TAG_TIME|*/ diff --git a/tools/ctap_test.py b/tools/ctap_test.py index 0330470..467b8ed 100644 --- a/tools/ctap_test.py +++ b/tools/ctap_test.py @@ -547,13 +547,24 @@ class Tester(): print('PASS') +def test_find_brute_force(): + i = 0 + while 1: + t1 = time.time() * 1000 + t = Tester() + t.find_device() + t2 = time.time() * 1000 + print('connected %d (%d ms)' % (i, t2-t1)) + i += 1 + time.sleep(0.01) + if __name__ == '__main__': t = Tester() t.find_device() #t.test_hid() #t.test_fido2() - #t.test_fido2_simple() + t.test_fido2_simple() #t.test_fido2_brute_force()