diff --git a/.gitignore b/.gitignore
index 3be0b88..a059597 100644
--- a/.gitignore
+++ b/.gitignore
@@ -61,3 +61,6 @@ tools/attest
sdk_15.0.0/
_build/
+
+GNU\ *
+Keil\ *
diff --git a/crypto/aes_gcm.c b/crypto/aes-gcm/aes_gcm.c
similarity index 100%
rename from crypto/aes_gcm.c
rename to crypto/aes-gcm/aes_gcm.c
diff --git a/crypto/sha256.c b/crypto/sha256/sha256.c
similarity index 100%
rename from crypto/sha256.c
rename to crypto/sha256/sha256.c
diff --git a/crypto/sha256.h b/crypto/sha256/sha256.h
similarity index 100%
rename from crypto/sha256.h
rename to crypto/sha256/sha256.h
diff --git a/device.h b/device.h
deleted file mode 100644
index cb1e2d7..0000000
--- a/device.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef _DEVICE_H
-#define _DEVICE_H
-
-void device_init();
-
-uint64_t millis();
-
-// HID message size in bytes
-#define HID_MESSAGE_SIZE 64
-
-void usbhid_init();
-
-int usbhid_recv(uint8_t * msg);
-
-void usbhid_send(uint8_t * msg);
-
-void usbhid_close();
-
-void main_loop_delay();
-
-void heartbeat();
-
-#endif
diff --git a/efm32/.cproject b/efm32/.cproject
new file mode 100644
index 0000000..6cc2d33
--- /dev/null
+++ b/efm32/.cproject
@@ -0,0 +1,229 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/efm32/.project b/efm32/.project
new file mode 100644
index 0000000..513394f
--- /dev/null
+++ b/efm32/.project
@@ -0,0 +1,39 @@
+
+
+ EFM32
+
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.genmakebuilder
+ clean,full,incremental,
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
+ full,incremental,
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ com.silabs.ss.framework.ide.project.sls.core.SLSProjectNature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
+
+
+
+ crypto
+ 2
+ C:/Users/conor/Desktop/u2f-one/crypto/
+
+
+ fido2
+ 2
+ C:/Users/conor/Desktop/u2f-one/fido2/
+
+
+
diff --git a/efm32/.settings/com.silabs.ss.framework.ide.project.sls.core.prefs b/efm32/.settings/com.silabs.ss.framework.ide.project.sls.core.prefs
new file mode 100644
index 0000000..b4554b4
--- /dev/null
+++ b/efm32/.settings/com.silabs.ss.framework.ide.project.sls.core.prefs
@@ -0,0 +1,2 @@
+copiedFilesOriginState={}
+eclipse.preferences.version=1
diff --git a/efm32/.settings/org.eclipse.cdt.codan.core.prefs b/efm32/.settings/org.eclipse.cdt.codan.core.prefs
new file mode 100644
index 0000000..75be390
--- /dev/null
+++ b/efm32/.settings/org.eclipse.cdt.codan.core.prefs
@@ -0,0 +1,70 @@
+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}}
diff --git a/efm32/CMSIS/EFM32PG1B/startup_gcc_efm32pg1b.s b/efm32/CMSIS/EFM32PG1B/startup_gcc_efm32pg1b.s
new file mode 100644
index 0000000..2a683c7
--- /dev/null
+++ b/efm32/CMSIS/EFM32PG1B/startup_gcc_efm32pg1b.s
@@ -0,0 +1,317 @@
+/* @file startup_efm32pg1b.S
+ * @brief startup file for Silicon Labs EFM32PG1B devices.
+ * For use with GCC for ARM Embedded Processors
+ * @version 5.2.2
+ * Date: 12 June 2014
+ *
+ */
+/* Copyright (c) 2011 - 2014 ARM LIMITED
+
+ All rights reserved.
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ - Neither the name of ARM nor the names of its contributors may be used
+ to endorse or promote products derived from this software without
+ specific prior written permission.
+ *
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+ ---------------------------------------------------------------------------*/
+
+ .syntax unified
+ .arch armv7-m
+ .section .stack
+ .align 3
+#ifdef __STACK_SIZE
+ .equ Stack_Size, __STACK_SIZE
+#else
+ .equ Stack_Size, 0x00000400
+#endif
+ .globl __StackTop
+ .globl __StackLimit
+__StackLimit:
+ .space Stack_Size
+ .size __StackLimit, . - __StackLimit
+__StackTop:
+ .size __StackTop, . - __StackTop
+
+ .section .heap
+ .align 3
+#ifdef __HEAP_SIZE
+ .equ Heap_Size, __HEAP_SIZE
+#else
+ .equ Heap_Size, 0x00000C00
+#endif
+ .globl __HeapBase
+ .globl __HeapLimit
+__HeapBase:
+ .if Heap_Size
+ .space Heap_Size
+ .endif
+ .size __HeapBase, . - __HeapBase
+__HeapLimit:
+ .size __HeapLimit, . - __HeapLimit
+
+ .section .vectors
+ .align 2
+ .globl __Vectors
+__Vectors:
+ .long __StackTop /* Top of Stack */
+ .long Reset_Handler /* Reset Handler */
+ .long NMI_Handler /* NMI Handler */
+ .long HardFault_Handler /* Hard Fault Handler */
+ .long MemManage_Handler /* MPU Fault Handler */
+ .long BusFault_Handler /* Bus Fault Handler */
+ .long UsageFault_Handler /* Usage Fault Handler */
+ .long Default_Handler /* Reserved */
+ .long Default_Handler /* Reserved */
+ .long Default_Handler /* Reserved */
+ .long Default_Handler /* Reserved */
+ .long SVC_Handler /* SVCall Handler */
+ .long DebugMon_Handler /* Debug Monitor Handler */
+ .long Default_Handler /* Reserved */
+ .long PendSV_Handler /* PendSV Handler */
+ .long SysTick_Handler /* SysTick Handler */
+
+ /* External interrupts */
+ .long EMU_IRQHandler /* 0 - EMU */
+ .long Default_Handler /* 1 - Reserved */
+ .long WDOG0_IRQHandler /* 2 - WDOG0 */
+ .long Default_Handler /* 3 - Reserved */
+ .long Default_Handler /* 4 - Reserved */
+ .long Default_Handler /* 5 - Reserved */
+ .long Default_Handler /* 6 - Reserved */
+ .long Default_Handler /* 7 - Reserved */
+ .long LDMA_IRQHandler /* 8 - LDMA */
+ .long GPIO_EVEN_IRQHandler /* 9 - GPIO_EVEN */
+ .long TIMER0_IRQHandler /* 10 - TIMER0 */
+ .long USART0_RX_IRQHandler /* 11 - USART0_RX */
+ .long USART0_TX_IRQHandler /* 12 - USART0_TX */
+ .long ACMP0_IRQHandler /* 13 - ACMP0 */
+ .long ADC0_IRQHandler /* 14 - ADC0 */
+ .long IDAC0_IRQHandler /* 15 - IDAC0 */
+ .long I2C0_IRQHandler /* 16 - I2C0 */
+ .long GPIO_ODD_IRQHandler /* 17 - GPIO_ODD */
+ .long TIMER1_IRQHandler /* 18 - TIMER1 */
+ .long USART1_RX_IRQHandler /* 19 - USART1_RX */
+ .long USART1_TX_IRQHandler /* 20 - USART1_TX */
+ .long LEUART0_IRQHandler /* 21 - LEUART0 */
+ .long PCNT0_IRQHandler /* 22 - PCNT0 */
+ .long CMU_IRQHandler /* 23 - CMU */
+ .long MSC_IRQHandler /* 24 - MSC */
+ .long CRYPTO_IRQHandler /* 25 - CRYPTO */
+ .long LETIMER0_IRQHandler /* 26 - LETIMER0 */
+ .long Default_Handler /* 27 - Reserved */
+ .long Default_Handler /* 28 - Reserved */
+ .long RTCC_IRQHandler /* 29 - RTCC */
+ .long Default_Handler /* 30 - Reserved */
+ .long CRYOTIMER_IRQHandler /* 31 - CRYOTIMER */
+ .long Default_Handler /* 32 - Reserved */
+ .long FPUEH_IRQHandler /* 33 - FPUEH */
+
+
+ .size __Vectors, . - __Vectors
+
+ .text
+ .thumb
+ .thumb_func
+ .align 2
+ .globl Reset_Handler
+ .type Reset_Handler, %function
+Reset_Handler:
+#ifndef __NO_SYSTEM_INIT
+ ldr r0, =SystemInit
+ blx r0
+#endif
+
+/* Firstly it copies data from read only memory to RAM. There are two schemes
+ * to copy. One can copy more than one sections. Another can only copy
+ * one section. The former scheme needs more instructions and read-only
+ * data to implement than the latter.
+ * Macro __STARTUP_COPY_MULTIPLE is used to choose between two schemes. */
+
+#ifdef __STARTUP_COPY_MULTIPLE
+/* Multiple sections scheme.
+ *
+ * Between symbol address __copy_table_start__ and __copy_table_end__,
+ * there are array of triplets, each of which specify:
+ * offset 0: LMA of start of a section to copy from
+ * offset 4: VMA of start of a section to copy to
+ * offset 8: size of the section to copy. Must be multiply of 4
+ *
+ * All addresses must be aligned to 4 bytes boundary.
+ */
+ ldr r4, =__copy_table_start__
+ ldr r5, =__copy_table_end__
+
+.L_loop0:
+ cmp r4, r5
+ bge .L_loop0_done
+ ldr r1, [r4]
+ ldr r2, [r4, #4]
+ ldr r3, [r4, #8]
+
+.L_loop0_0:
+ subs r3, #4
+ ittt ge
+ ldrge r0, [r1, r3]
+ strge r0, [r2, r3]
+ bge .L_loop0_0
+
+ adds r4, #12
+ b .L_loop0
+
+.L_loop0_done:
+#else
+/* Single section scheme.
+ *
+ * The ranges of copy from/to are specified by following symbols
+ * __etext: LMA of start of the section to copy from. Usually end of text
+ * __data_start__: VMA of start of the section to copy to
+ * __data_end__: VMA of end of the section to copy to
+ *
+ * All addresses must be aligned to 4 bytes boundary.
+ */
+ ldr r1, =__etext
+ ldr r2, =__data_start__
+ ldr r3, =__data_end__
+
+.L_loop1:
+ cmp r2, r3
+ ittt lt
+ ldrlt r0, [r1], #4
+ strlt r0, [r2], #4
+ blt .L_loop1
+#endif /*__STARTUP_COPY_MULTIPLE */
+
+/* This part of work usually is done in C library startup code. Otherwise,
+ * define this macro to enable it in this startup.
+ *
+ * There are two schemes too. One can clear multiple BSS sections. Another
+ * can only clear one section. The former is more size expensive than the
+ * latter.
+ *
+ * Define macro __STARTUP_CLEAR_BSS_MULTIPLE to choose the former.
+ * Otherwise efine macro __STARTUP_CLEAR_BSS to choose the later.
+ */
+#ifdef __STARTUP_CLEAR_BSS_MULTIPLE
+/* Multiple sections scheme.
+ *
+ * Between symbol address __zero_table_start__ and __zero_table_end__,
+ * there are array of tuples specifying:
+ * offset 0: Start of a BSS section
+ * offset 4: Size of this BSS section. Must be multiply of 4
+ */
+ ldr r3, =__zero_table_start__
+ ldr r4, =__zero_table_end__
+
+.L_loop2:
+ cmp r3, r4
+ bge .L_loop2_done
+ ldr r1, [r3]
+ ldr r2, [r3, #4]
+ movs r0, 0
+
+.L_loop2_0:
+ subs r2, #4
+ itt ge
+ strge r0, [r1, r2]
+ bge .L_loop2_0
+ adds r3, #8
+ b .L_loop2
+.L_loop2_done:
+#elif defined (__STARTUP_CLEAR_BSS)
+/* Single BSS section scheme.
+ *
+ * The BSS section is specified by following symbols
+ * __bss_start__: start of the BSS section.
+ * __bss_end__: end of the BSS section.
+ *
+ * Both addresses must be aligned to 4 bytes boundary.
+ */
+ ldr r1, =__bss_start__
+ ldr r2, =__bss_end__
+
+ movs r0, 0
+.L_loop3:
+ cmp r1, r2
+ itt lt
+ strlt r0, [r1], #4
+ blt .L_loop3
+#endif /* __STARTUP_CLEAR_BSS_MULTIPLE || __STARTUP_CLEAR_BSS */
+
+#ifndef __START
+#define __START _start
+#endif
+ bl __START
+
+ .pool
+ .size Reset_Handler, . - Reset_Handler
+
+ .align 1
+ .thumb_func
+ .weak Default_Handler
+ .type Default_Handler, %function
+Default_Handler:
+ b .
+ .size Default_Handler, . - Default_Handler
+
+/* Macro to define default handlers. Default handler
+ * will be weak symbol and just dead loops. They can be
+ * overwritten by other handlers */
+ .macro def_irq_handler handler_name
+ .weak \handler_name
+ .set \handler_name, Default_Handler
+ .endm
+
+ def_irq_handler NMI_Handler
+ def_irq_handler HardFault_Handler
+ def_irq_handler MemManage_Handler
+ def_irq_handler BusFault_Handler
+ def_irq_handler UsageFault_Handler
+ def_irq_handler SVC_Handler
+ def_irq_handler DebugMon_Handler
+ def_irq_handler PendSV_Handler
+ def_irq_handler SysTick_Handler
+
+
+ def_irq_handler EMU_IRQHandler
+ def_irq_handler WDOG0_IRQHandler
+ def_irq_handler LDMA_IRQHandler
+ def_irq_handler GPIO_EVEN_IRQHandler
+ def_irq_handler TIMER0_IRQHandler
+ def_irq_handler USART0_RX_IRQHandler
+ def_irq_handler USART0_TX_IRQHandler
+ def_irq_handler ACMP0_IRQHandler
+ def_irq_handler ADC0_IRQHandler
+ def_irq_handler IDAC0_IRQHandler
+ def_irq_handler I2C0_IRQHandler
+ def_irq_handler GPIO_ODD_IRQHandler
+ def_irq_handler TIMER1_IRQHandler
+ def_irq_handler USART1_RX_IRQHandler
+ def_irq_handler USART1_TX_IRQHandler
+ def_irq_handler LEUART0_IRQHandler
+ def_irq_handler PCNT0_IRQHandler
+ def_irq_handler CMU_IRQHandler
+ def_irq_handler MSC_IRQHandler
+ def_irq_handler CRYPTO_IRQHandler
+ def_irq_handler LETIMER0_IRQHandler
+ def_irq_handler RTCC_IRQHandler
+ def_irq_handler CRYOTIMER_IRQHandler
+ def_irq_handler FPUEH_IRQHandler
+
+ .end
diff --git a/efm32/CMSIS/EFM32PG1B/system_efm32pg1b.c b/efm32/CMSIS/EFM32PG1B/system_efm32pg1b.c
new file mode 100644
index 0000000..c52e3e1
--- /dev/null
+++ b/efm32/CMSIS/EFM32PG1B/system_efm32pg1b.c
@@ -0,0 +1,389 @@
+/***************************************************************************//**
+ * @file system_efm32pg1b.c
+ * @brief CMSIS Cortex-M3/M4 System Layer for EFM32 devices.
+ * @version 5.2.2
+ ******************************************************************************
+ * # License
+ * Copyright 2017 Silicon Laboratories, Inc. http://www.silabs.com
+ ******************************************************************************
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software.@n
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.@n
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Laboratories, Inc.
+ * has no obligation to support this Software. Silicon Laboratories, Inc. is
+ * providing the Software "AS IS", with no express or implied warranties of any
+ * kind, including, but not limited to, any implied warranties of
+ * merchantability or fitness for any particular purpose or warranties against
+ * infringement of any proprietary rights of a third party.
+ *
+ * Silicon Laboratories, Inc. will not be liable for any consequential,
+ * incidental, or special damages, or any other relief, or for any claim by
+ * any third party, arising from your use of this Software.
+ *
+ *****************************************************************************/
+
+#include
+#include "em_device.h"
+
+/*******************************************************************************
+ ****************************** DEFINES ************************************
+ ******************************************************************************/
+
+/** LFRCO frequency, tuned to below frequency during manufacturing. */
+#define EFM32_LFRCO_FREQ (32768UL)
+/** ULFRCO frequency */
+#define EFM32_ULFRCO_FREQ (1000UL)
+
+/*******************************************************************************
+ ************************** LOCAL VARIABLES ********************************
+ ******************************************************************************/
+
+/* System oscillator frequencies. These frequencies are normally constant */
+/* for a target, but they are made configurable in order to allow run-time */
+/* handling of different boards. The crystal oscillator clocks can be set */
+/* compile time to a non-default value by defining respective EFM_nFXO_FREQ */
+/* values according to board design. By defining the EFM_nFXO_FREQ to 0, */
+/* one indicates that the oscillator is not present, in order to save some */
+/* SW footprint. */
+
+#ifndef EFM32_HFRCO_MAX_FREQ
+/** Maximum HFRCO frequency */
+#define EFM32_HFRCO_MAX_FREQ (38000000UL)
+#endif
+
+#ifndef EFM32_HFXO_FREQ
+/** HFXO frequency */
+#define EFM32_HFXO_FREQ (40000000UL)
+#endif
+
+#ifndef EFM32_HFRCO_STARTUP_FREQ
+/** HFRCO startup frequency */
+#define EFM32_HFRCO_STARTUP_FREQ (19000000UL)
+#endif
+
+
+/* Do not define variable if HF crystal oscillator not present */
+#if (EFM32_HFXO_FREQ > 0UL)
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+/** System HFXO clock. */
+static uint32_t SystemHFXOClock = EFM32_HFXO_FREQ;
+/** @endcond (DO_NOT_INCLUDE_WITH_DOXYGEN) */
+#endif
+
+#ifndef EFM32_LFXO_FREQ
+/** LFXO frequency */
+#define EFM32_LFXO_FREQ (EFM32_LFRCO_FREQ)
+#endif
+/* Do not define variable if LF crystal oscillator not present */
+#if (EFM32_LFXO_FREQ > 0UL)
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+/** System LFXO clock. */
+static uint32_t SystemLFXOClock = 32768UL;
+/** @endcond (DO_NOT_INCLUDE_WITH_DOXYGEN) */
+#endif
+
+
+/*******************************************************************************
+ ************************** GLOBAL VARIABLES *******************************
+ ******************************************************************************/
+
+/**
+ * @brief
+ * System System Clock Frequency (Core Clock).
+ *
+ * @details
+ * Required CMSIS global variable that must be kept up-to-date.
+ */
+uint32_t SystemCoreClock = EFM32_HFRCO_STARTUP_FREQ;
+
+
+/**
+ * @brief
+ * System HFRCO frequency
+ *
+ * @note
+ * This is an EFM32 proprietary variable, not part of the CMSIS definition.
+ *
+ * @details
+ * Frequency of the system HFRCO oscillator
+ */
+uint32_t SystemHfrcoFreq = EFM32_HFRCO_STARTUP_FREQ;
+
+
+/*******************************************************************************
+ ************************** GLOBAL FUNCTIONS *******************************
+ ******************************************************************************/
+
+/***************************************************************************//**
+ * @brief
+ * Get the current core clock frequency.
+ *
+ * @details
+ * Calculate and get the current core clock frequency based on the current
+ * configuration. Assuming that the SystemCoreClock global variable is
+ * maintained, the core clock frequency is stored in that variable as well.
+ * This function will however calculate the core clock based on actual HW
+ * configuration. It will also update the SystemCoreClock global variable.
+ *
+ * @note
+ * This is an EFM32 proprietary function, not part of the CMSIS definition.
+ *
+ * @return
+ * The current core clock frequency in Hz.
+ ******************************************************************************/
+uint32_t SystemCoreClockGet(void)
+{
+ uint32_t ret;
+ uint32_t presc;
+
+ ret = SystemHFClockGet();
+ presc = (CMU->HFCOREPRESC & _CMU_HFCOREPRESC_PRESC_MASK) >>
+ _CMU_HFCOREPRESC_PRESC_SHIFT;
+ ret /= (presc + 1);
+
+ /* Keep CMSIS system clock variable up-to-date */
+ SystemCoreClock = ret;
+
+ return ret;
+}
+
+
+/***************************************************************************//**
+ * @brief
+ * Get the maximum core clock frequency.
+ *
+ * @note
+ * This is an EFM32 proprietary function, not part of the CMSIS definition.
+ *
+ * @return
+ * The maximum core clock frequency in Hz.
+ ******************************************************************************/
+uint32_t SystemMaxCoreClockGet(void)
+{
+ return (EFM32_HFRCO_MAX_FREQ > EFM32_HFXO_FREQ ? \
+ EFM32_HFRCO_MAX_FREQ : EFM32_HFXO_FREQ);
+}
+
+
+/***************************************************************************//**
+ * @brief
+ * Get the current HFCLK frequency.
+ *
+ * @note
+ * This is an EFM32 proprietary function, not part of the CMSIS definition.
+ *
+ * @return
+ * The current HFCLK frequency in Hz.
+ ******************************************************************************/
+uint32_t SystemHFClockGet(void)
+{
+ uint32_t ret;
+
+ switch (CMU->HFCLKSTATUS & _CMU_HFCLKSTATUS_SELECTED_MASK)
+ {
+ case CMU_HFCLKSTATUS_SELECTED_LFXO:
+#if (EFM32_LFXO_FREQ > 0)
+ ret = SystemLFXOClock;
+#else
+ /* We should not get here, since core should not be clocked. May */
+ /* be caused by a misconfiguration though. */
+ ret = 0;
+#endif
+ break;
+
+ case CMU_HFCLKSTATUS_SELECTED_LFRCO:
+ ret = EFM32_LFRCO_FREQ;
+ break;
+
+ case CMU_HFCLKSTATUS_SELECTED_HFXO:
+#if (EFM32_HFXO_FREQ > 0)
+ ret = SystemHFXOClock;
+#else
+ /* We should not get here, since core should not be clocked. May */
+ /* be caused by a misconfiguration though. */
+ ret = 0;
+#endif
+ break;
+
+ default: /* CMU_HFCLKSTATUS_SELECTED_HFRCO */
+ ret = SystemHfrcoFreq;
+ break;
+ }
+
+ return ret / (1U + ((CMU->HFPRESC & _CMU_HFPRESC_PRESC_MASK)
+ >> _CMU_HFPRESC_PRESC_SHIFT));
+}
+
+
+/**************************************************************************//**
+ * @brief
+ * Get high frequency crystal oscillator clock frequency for target system.
+ *
+ * @note
+ * This is an EFM32 proprietary function, not part of the CMSIS definition.
+ *
+ * @return
+ * HFXO frequency in Hz.
+ *****************************************************************************/
+uint32_t SystemHFXOClockGet(void)
+{
+ /* External crystal oscillator present? */
+#if (EFM32_HFXO_FREQ > 0)
+ return SystemHFXOClock;
+#else
+ return 0;
+#endif
+}
+
+
+/**************************************************************************//**
+ * @brief
+ * Set high frequency crystal oscillator clock frequency for target system.
+ *
+ * @note
+ * This function is mainly provided for being able to handle target systems
+ * with different HF crystal oscillator frequencies run-time. If used, it
+ * should probably only be used once during system startup.
+ *
+ * @note
+ * This is an EFM32 proprietary function, not part of the CMSIS definition.
+ *
+ * @param[in] freq
+ * HFXO frequency in Hz used for target.
+ *****************************************************************************/
+void SystemHFXOClockSet(uint32_t freq)
+{
+ /* External crystal oscillator present? */
+#if (EFM32_HFXO_FREQ > 0)
+ SystemHFXOClock = freq;
+
+ /* Update core clock frequency if HFXO is used to clock core */
+ if ((CMU->HFCLKSTATUS & _CMU_HFCLKSTATUS_SELECTED_MASK) == CMU_HFCLKSTATUS_SELECTED_HFXO)
+ {
+ /* The function will update the global variable */
+ SystemCoreClockGet();
+ }
+#else
+ (void)freq; /* Unused parameter */
+#endif
+}
+
+
+/**************************************************************************//**
+ * @brief
+ * Initialize the system.
+ *
+ * @details
+ * Do required generic HW system init.
+ *
+ * @note
+ * This function is invoked during system init, before the main() routine
+ * and any data has been initialized. For this reason, it cannot do any
+ * initialization of variables etc.
+ *****************************************************************************/
+void SystemInit(void)
+{
+#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
+ /* Set floating point coprosessor access mode. */
+ SCB->CPACR |= ((3UL << 10*2) | /* set CP10 Full Access */
+ (3UL << 11*2) ); /* set CP11 Full Access */
+#endif
+}
+
+
+/**************************************************************************//**
+ * @brief
+ * Get low frequency RC oscillator clock frequency for target system.
+ *
+ * @note
+ * This is an EFM32 proprietary function, not part of the CMSIS definition.
+ *
+ * @return
+ * LFRCO frequency in Hz.
+ *****************************************************************************/
+uint32_t SystemLFRCOClockGet(void)
+{
+ /* Currently we assume that this frequency is properly tuned during */
+ /* manufacturing and is not changed after reset. If future requirements */
+ /* for re-tuning by user, we can add support for that. */
+ return EFM32_LFRCO_FREQ;
+}
+
+
+/**************************************************************************//**
+ * @brief
+ * Get ultra low frequency RC oscillator clock frequency for target system.
+ *
+ * @note
+ * This is an EFM32 proprietary function, not part of the CMSIS definition.
+ *
+ * @return
+ * ULFRCO frequency in Hz.
+ *****************************************************************************/
+uint32_t SystemULFRCOClockGet(void)
+{
+ /* The ULFRCO frequency is not tuned, and can be very inaccurate */
+ return EFM32_ULFRCO_FREQ;
+}
+
+
+/**************************************************************************//**
+ * @brief
+ * Get low frequency crystal oscillator clock frequency for target system.
+ *
+ * @note
+ * This is an EFM32 proprietary function, not part of the CMSIS definition.
+ *
+ * @return
+ * LFXO frequency in Hz.
+ *****************************************************************************/
+uint32_t SystemLFXOClockGet(void)
+{
+ /* External crystal oscillator present? */
+#if (EFM32_LFXO_FREQ > 0)
+ return SystemLFXOClock;
+#else
+ return 0;
+#endif
+}
+
+
+/**************************************************************************//**
+ * @brief
+ * Set low frequency crystal oscillator clock frequency for target system.
+ *
+ * @note
+ * This function is mainly provided for being able to handle target systems
+ * with different HF crystal oscillator frequencies run-time. If used, it
+ * should probably only be used once during system startup.
+ *
+ * @note
+ * This is an EFM32 proprietary function, not part of the CMSIS definition.
+ *
+ * @param[in] freq
+ * LFXO frequency in Hz used for target.
+ *****************************************************************************/
+void SystemLFXOClockSet(uint32_t freq)
+{
+ /* External crystal oscillator present? */
+#if (EFM32_LFXO_FREQ > 0)
+ SystemLFXOClock = freq;
+
+ /* Update core clock frequency if LFXO is used to clock core */
+ if ((CMU->HFCLKSTATUS & _CMU_HFCLKSTATUS_SELECTED_MASK) == CMU_HFCLKSTATUS_SELECTED_LFXO)
+ {
+ /* The function will update the global variable */
+ SystemCoreClockGet();
+ }
+#else
+ (void)freq; /* Unused parameter */
+#endif
+}
diff --git a/efm32/EFM32.hwconf b/efm32/EFM32.hwconf
new file mode 100644
index 0000000..15d21ae
--- /dev/null
+++ b/efm32/EFM32.hwconf
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/efm32/Makefile b/efm32/Makefile
new file mode 100644
index 0000000..4b9558a
--- /dev/null
+++ b/efm32/Makefile
@@ -0,0 +1,23 @@
+
+CC=arm-none-eabi-gcc
+
+all:
+ cd 'GNU ARM v7.2.1 - Debug' && make all
+
+
+#arm-none-eabi-gcc -g -gdwarf-2 -mcpu=cortex-m4 -mthumb -std=c99 '-DDEBUG=1' '-DEFM32PG1B200F256GM48=1' -IC:/Users/conor/Desktop/u2f-one/crypto/sha256 -IC:/Users/conor/Desktop/u2f-one/crypto/micro-ecc -IC:/Users/conor/Desktop/u2f-one/crypto/tiny-AES-c -I"C:\Users\conor\Desktop\u2f-one\efm32\inc" -IC:/Users/conor/Desktop/u2f-one/fido2 -IC:/Users/conor/Desktop/u2f-one/tinycbor/src -I"C:/SiliconLabs/SimplicityStudio/v4/developer/sdks/gecko_sdk_suite/v1.1//platform/CMSIS/Include" -I"C:/SiliconLabs/SimplicityStudio/v4/developer/sdks/gecko_sdk_suite/v1.1//hardware/kit/common/drivers" -I"C:/SiliconLabs/SimplicityStudio/v4/developer/sdks/gecko_sdk_suite/v1.1//hardware/kit/SLSTK3401A_EFM32PG/config" -I"C:/SiliconLabs/SimplicityStudio/v4/developer/sdks/gecko_sdk_suite/v1.1//platform/Device/SiliconLabs/EFM32PG1B/Include" -I"C:/SiliconLabs/SimplicityStudio/v4/developer/sdks/gecko_sdk_suite/v1.1//platform/emlib/inc" -I"C:/SiliconLabs/SimplicityStudio/v4/developer/sdks/gecko_sdk_suite/v1.1//hardware/kit/common/bsp" -O0 -Wall -c -fmessage-length=0 -mno-sched-prolog -fno-builtin -ffunction-sections -fdata-sections -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -MMD -MP -MF"src/device.d" -MT"src/device.o" -o "src/device.o" "../src/device.c"
+
+
+#arm-none-eabi-gcc -g -gdwarf-2 -mcpu=cortex-m4 -mthumb -T "EFM32.ld" -Xlinker --gc-sections -Xlinker -Map="EFM32.map" -mfpu=fpv4-sp-d16 -mfloat-abi=softfp --specs=nano.specs -o EFM32.axf "./CMSIS/EFM32PG1B/startup_gcc_efm32pg1b.o" "./CMSIS/EFM32PG1B/system_efm32pg1b.o" "./crypto/micro-ecc/uECC.o" "./crypto/sha256/sha256.o" "./crypto/tiny-AES-c/aes.o" "./emlib/em_assert.o" "./emlib/em_cmu.o" "./emlib/em_emu.o" "./emlib/em_gpio.o" "./emlib/em_system.o" "./emlib/em_usart.o" "./fido2/crypto.o" "./fido2/ctap.o" "./fido2/ctap_parse.o" "./fido2/ctaphid.o" "./fido2/log.o" "./fido2/main.o" "./fido2/stubs.o" "./fido2/test_power.o" "./fido2/u2f.o" "./fido2/util.o" "./src/InitDevice.o" "./src/device.o" "./src/main.o" "./src/printing.o" "./src/retargetio.o" -Wl,--start-group -lgcc -lc -lnosys -Wl,--end-group
+
+
+cbor:
+ cd ../tinycbor/ && make clean
+ cd ../tinycbor/ && make CC="$(CC)" \
+LDFLAGS="-lgcc -lc -lnosys --specs=nosys.specs -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -mthumb " \
+CFLAGS="-g -gdwarf-2 -mcpu=cortex-m4 -mthumb -std=c99 -DEFM32PG1B200F256GM48=1 -O3 -Wall -c -fmessage-length=0 -mno-sched-prolog -fno-builtin -ffunction-sections -fdata-sections -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -MMD -MP "
+
+
+
+clean:
+ cd 'GNU ARM v7.2.1 - Debug' && make clean
diff --git a/efm32/emlib/em_assert.c b/efm32/emlib/em_assert.c
new file mode 100644
index 0000000..71225e0
--- /dev/null
+++ b/efm32/emlib/em_assert.c
@@ -0,0 +1,81 @@
+/***************************************************************************//**
+ * @file em_assert.c
+ * @brief Assert API
+ * @version 5.2.2
+ *******************************************************************************
+ * # License
+ * Copyright 2016 Silicon Laboratories, Inc. http://www.silabs.com
+ *******************************************************************************
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
+ * obligation to support this Software. Silicon Labs is providing the
+ * Software "AS IS", with no express or implied warranties of any kind,
+ * including, but not limited to, any implied warranties of merchantability
+ * or fitness for any particular purpose or warranties against infringement
+ * of any proprietary rights of a third party.
+ *
+ * Silicon Labs will not be liable for any consequential, incidental, or
+ * special damages, or any other relief, or for any claim by any third party,
+ * arising from your use of this Software.
+ *
+ ******************************************************************************/
+
+#include "em_assert.h"
+#include
+
+/***************************************************************************//**
+ * @addtogroup emlib
+ * @{
+ ******************************************************************************/
+
+/***************************************************************************//**
+ * @addtogroup ASSERT
+ * @{
+ ******************************************************************************/
+
+#if defined(DEBUG_EFM)
+/***************************************************************************//**
+ * @brief
+ * EFM internal assert handling.
+ *
+ * This function is invoked through EFM_ASSERT() macro usage only, it should
+ * not be used explicitly.
+ *
+ * This implementation simply enters an indefinite loop, allowing
+ * the use of a debugger to determine cause of failure. By defining
+ * DEBUG_EFM_USER to the preprocessor for all files, a user defined version
+ * of this function must be defined and will be invoked instead, possibly
+ * providing output of assertion location.
+ *
+ * @note
+ * This function is not used unless @ref DEBUG_EFM is defined
+ * during preprocessing of EFM_ASSERT() usage.
+ *
+ * @param[in] file
+ * Name of source file where assertion failed.
+ *
+ * @param[in] line
+ * Line number in source file where assertion failed.
+ ******************************************************************************/
+void assertEFM(const char *file, int line)
+{
+ (void)file; /* Unused parameter */
+ (void)line; /* Unused parameter */
+
+ while (true) {
+ }
+}
+#endif /* DEBUG_EFM */
+
+/** @} (end addtogroup ASSERT) */
+/** @} (end addtogroup emlib) */
diff --git a/efm32/emlib/em_cmu.c b/efm32/emlib/em_cmu.c
new file mode 100644
index 0000000..96316ff
--- /dev/null
+++ b/efm32/emlib/em_cmu.c
@@ -0,0 +1,5310 @@
+/***************************************************************************//**
+ * @file em_cmu.c
+ * @brief Clock management unit (CMU) Peripheral API
+ * @version 5.2.2
+ *******************************************************************************
+ * # License
+ * Copyright 2016 Silicon Laboratories, Inc. http://www.silabs.com
+ *******************************************************************************
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
+ * obligation to support this Software. Silicon Labs is providing the
+ * Software "AS IS", with no express or implied warranties of any kind,
+ * including, but not limited to, any implied warranties of merchantability
+ * or fitness for any particular purpose or warranties against infringement
+ * of any proprietary rights of a third party.
+ *
+ * Silicon Labs will not be liable for any consequential, incidental, or
+ * special damages, or any other relief, or for any claim by any third party,
+ * arising from your use of this Software.
+ *
+ ******************************************************************************/
+
+#include "em_cmu.h"
+#if defined(CMU_PRESENT)
+
+#include
+#include
+#include "em_assert.h"
+#include "em_bus.h"
+#include "em_emu.h"
+#include "em_cmu.h"
+#include "em_system.h"
+#include "em_common.h"
+
+/***************************************************************************//**
+ * @addtogroup emlib
+ * @{
+ ******************************************************************************/
+
+/***************************************************************************//**
+ * @addtogroup CMU
+ * @brief Clock management unit (CMU) Peripheral API
+ * @details
+ * This module contains functions to control the CMU peripheral of Silicon
+ * Labs 32-bit MCUs and SoCs. The CMU controls oscillators and clocks.
+ * @{
+ ******************************************************************************/
+
+/*******************************************************************************
+ ****************************** DEFINES ************************************
+ ******************************************************************************/
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+
+#if defined(_SILICON_LABS_32B_SERIES_1)
+/** Maximum allowed core frequency when using 0 wait-states on flash access. */
+#define CMU_MAX_FREQ_0WS 26000000
+/** Maximum allowed core frequency when using 1 wait-states on flash access */
+#define CMU_MAX_FREQ_1WS 40000000
+/** Maximum allowed core frequency when using 2 wait-states on flash access */
+#define CMU_MAX_FREQ_2WS 54000000
+/** Maximum allowed core frequency when using 3 wait-states on flash access */
+#define CMU_MAX_FREQ_3WS 72000000
+#elif defined(_SILICON_LABS_32B_SERIES_0)
+/** Maximum allowed core frequency when using 0 wait-states on flash access. */
+#define CMU_MAX_FREQ_0WS 16000000
+/** Maximum allowed core frequency when using 1 wait-states on flash access */
+#define CMU_MAX_FREQ_1WS 32000000
+#else
+#error "Max Flash wait-state frequencies are not defined for this platform."
+#endif
+
+/** Maximum frequency for HFLE interface */
+#if defined(CMU_CTRL_HFLE)
+/** Maximum HFLE frequency for series 0 EFM32 and EZR32 Wonder Gecko. */
+#if defined(_SILICON_LABS_32B_SERIES_0) \
+ && (defined(_EFM32_WONDER_FAMILY) \
+ || defined(_EZR32_WONDER_FAMILY))
+#define CMU_MAX_FREQ_HFLE 24000000
+/** Maximum HFLE frequency for other series 0 parts with maximum core clock
+ higher than 32MHz. */
+#elif defined(_SILICON_LABS_32B_SERIES_0) \
+ && (defined(_EFM32_GIANT_FAMILY) \
+ || defined(_EZR32_LEOPARD_FAMILY))
+#define CMU_MAX_FREQ_HFLE maxFreqHfle()
+#endif
+#elif defined(CMU_CTRL_WSHFLE)
+/** Maximum HFLE frequency for series 1 parts */
+#define CMU_MAX_FREQ_HFLE 32000000
+#endif
+
+#if defined(CMU_STATUS_HFXOSHUNTOPTRDY)
+#define HFXO_TUNING_READY_FLAGS (CMU_STATUS_HFXOPEAKDETRDY | CMU_STATUS_HFXOSHUNTOPTRDY)
+#define HFXO_TUNING_MODE_AUTO (_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_AUTOCMD)
+#define HFXO_TUNING_MODE_CMD (_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_CMD)
+#elif defined(CMU_STATUS_HFXOPEAKDETRDY)
+#define HFXO_TUNING_READY_FLAGS (CMU_STATUS_HFXOPEAKDETRDY)
+#define HFXO_TUNING_MODE_AUTO (_CMU_HFXOCTRL_PEAKDETMODE_AUTOCMD)
+#define HFXO_TUNING_MODE_CMD (_CMU_HFXOCTRL_PEAKDETMODE_CMD)
+#endif
+
+#if defined(CMU_HFXOCTRL_MODE_EXTCLK)
+/** HFXO external clock mode is renamed from EXTCLK to DIGEXTCLK. */
+#define CMU_HFXOCTRL_MODE_DIGEXTCLK CMU_HFXOCTRL_MODE_EXTCLK
+#endif
+
+#if defined(_EMU_CMD_EM01VSCALE0_MASK)
+#define VSCALE_DEFAULT (EMU_VScaleGet())
+#else
+#define VSCALE_DEFAULT 0
+#endif
+
+/*******************************************************************************
+ ************************** LOCAL VARIABLES ********************************
+ ******************************************************************************/
+
+#if defined(_CMU_AUXHFRCOCTRL_FREQRANGE_MASK)
+static CMU_AUXHFRCOFreq_TypeDef auxHfrcoFreq = cmuAUXHFRCOFreq_19M0Hz;
+#endif
+#if defined(_CMU_STATUS_HFXOSHUNTOPTRDY_MASK)
+#define HFXO_INVALID_TRIM (~_CMU_HFXOTRIMSTATUS_MASK)
+#endif
+
+#if defined(CMU_OSCENCMD_DPLLEN)
+/** Table of HFRCOCTRL values and their associated min/max frequencies and
+ optional band enumerator. */
+static const struct hfrcoCtrlTableElement{
+ uint32_t minFreq;
+ uint32_t maxFreq;
+ uint32_t value;
+ CMU_HFRCOFreq_TypeDef band;
+} hfrcoCtrlTable[] =
+{
+ // minFreq maxFreq HFRCOCTRL value band
+ { 860000, 1050000, 0xBC601F00, cmuHFRCOFreq_1M0Hz },
+ { 1050000, 1280000, 0xBC611F35, (CMU_HFRCOFreq_TypeDef)0 },
+ { 1280000, 1480000, 0xBCA21F35, (CMU_HFRCOFreq_TypeDef)0 },
+ { 1480000, 1800000, 0xAD231F35, (CMU_HFRCOFreq_TypeDef)0 },
+ { 1800000, 2110000, 0xBA601F00, cmuHFRCOFreq_2M0Hz },
+ { 2110000, 2560000, 0xBA611F35, (CMU_HFRCOFreq_TypeDef)0 },
+ { 2560000, 2970000, 0xBAA21F35, (CMU_HFRCOFreq_TypeDef)0 },
+ { 2970000, 3600000, 0xAB231F35, (CMU_HFRCOFreq_TypeDef)0 },
+ { 3600000, 4220000, 0xB8601F00, cmuHFRCOFreq_4M0Hz },
+ { 4220000, 5120000, 0xB8611F35, (CMU_HFRCOFreq_TypeDef)0 },
+ { 5120000, 5930000, 0xB8A21F35, (CMU_HFRCOFreq_TypeDef)0 },
+ { 5930000, 7520000, 0xA9231F00, cmuHFRCOFreq_7M0Hz },
+ { 7520000, 9520000, 0x99241F35, (CMU_HFRCOFreq_TypeDef)0 },
+ { 9520000, 11800000, 0x99251F35, (CMU_HFRCOFreq_TypeDef)0 },
+ { 11800000, 14400000, 0x99261F00, cmuHFRCOFreq_13M0Hz },
+ { 14400000, 17200000, 0x99271F00, cmuHFRCOFreq_16M0Hz },
+ { 17200000, 19700000, 0x99481F00, cmuHFRCOFreq_19M0Hz },
+ { 19700000, 23800000, 0x99491F35, (CMU_HFRCOFreq_TypeDef)0 },
+ { 23800000, 28700000, 0x994A1F00, cmuHFRCOFreq_26M0Hz },
+ { 28700000, 34800000, 0x996B1F00, cmuHFRCOFreq_32M0Hz },
+#if defined(_DEVINFO_HFRCOCAL16_MASK)
+ { 34800000, 42800000, 0x996C1F00, cmuHFRCOFreq_38M0Hz },
+ { 42800000, 51600000, 0x996D1F00, cmuHFRCOFreq_48M0Hz },
+ { 51600000, 60500000, 0x998E1F00, cmuHFRCOFreq_56M0Hz },
+ { 60500000, 72000000, 0xA98F1F00, cmuHFRCOFreq_64M0Hz }
+#else
+ { 34800000, 40000000, 0x996C1F00, cmuHFRCOFreq_38M0Hz }
+#endif
+};
+
+#define HFRCOCTRLTABLE_ENTRIES (sizeof(hfrcoCtrlTable) \
+ / sizeof(struct hfrcoCtrlTableElement))
+#endif // CMU_OSCENCMD_DPLLEN
+
+#if defined(_SILICON_LABS_32B_SERIES_1) && defined(_EMU_STATUS_VSCALE_MASK)
+/* Devices with Voltage Scaling needs extra handling of wait states. */
+static const struct flashWsTableElement{
+ uint32_t maxFreq;
+ uint8_t vscale;
+ uint8_t ws;
+} flashWsTable[] =
+{
+#if (_SILICON_LABS_GECKO_INTERNAL_SDID == 100)
+ { 18000000, 0, 0 }, /* 0 wait states at max frequency 18 MHz and 1.2V */
+ { 36000000, 0, 1 }, /* 1 wait states at max frequency 36 MHz and 1.2V */
+ { 54000000, 0, 2 }, /* 2 wait states at max frequency 54 MHz and 1.2V */
+ { 72000000, 0, 3 }, /* 3 wait states at max frequency 72 MHz and 1.2V */
+ { 7000000, 2, 0 }, /* 0 wait states at max frequency 7 MHz and 1.0V */
+ { 14000000, 2, 1 }, /* 1 wait states at max frequency 14 MHz and 1.0V */
+ { 21000000, 2, 2 }, /* 2 wait states at max frequency 21 MHz and 1.0V */
+#else
+ { 25000000, 0, 0 }, /* 0 wait states at max frequency 25 MHz and 1.2V */
+ { 40000000, 0, 1 }, /* 1 wait states at max frequency 40 MHz and 1.2V */
+ { 7000000, 2, 0 }, /* 0 wait states at max frequency 7 MHz and 1.0V */
+ { 14000000, 2, 1 }, /* 1 wait states at max frequency 14 MHz and 1.0V */
+ { 21000000, 2, 2 }, /* 2 wait states at max frequency 21 MHz and 1.0V */
+#endif
+};
+
+#define FLASH_WS_TABLE_ENTRIES (sizeof(flashWsTable) / sizeof(flashWsTable[0]))
+#endif
+
+#if defined(_CMU_USHFRCOCTRL_FREQRANGE_MASK) \
+ || defined(_CMU_USHFRCOTUNE_MASK)
+#ifndef EFM32_USHFRCO_STARTUP_FREQ
+#define EFM32_USHFRCO_STARTUP_FREQ (48000000UL)
+#endif
+
+static uint32_t ushfrcoFreq = EFM32_USHFRCO_STARTUP_FREQ;
+#endif
+
+/*******************************************************************************
+ ************************** LOCAL PROTOTYPES *******************************
+ ******************************************************************************/
+#if defined(_CMU_HFRCOCTRL_FREQRANGE_MASK)
+static uint32_t CMU_HFRCODevinfoGet(CMU_HFRCOFreq_TypeDef freq);
+#endif
+
+#if defined(_CMU_USHFRCOCTRL_FREQRANGE_MASK)
+static uint32_t CMU_USHFRCODevinfoGet(CMU_USHFRCOFreq_TypeDef freq);
+#endif
+
+/** @endcond */
+
+/*******************************************************************************
+ ************************** LOCAL FUNCTIONS ********************************
+ ******************************************************************************/
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+
+#if defined(_SILICON_LABS_32B_SERIES_0) \
+ && (defined(_EFM32_GIANT_FAMILY) \
+ || defined(_EZR32_LEOPARD_FAMILY))
+/***************************************************************************//**
+ * @brief
+ * Return max allowed frequency for low energy peripherals.
+ ******************************************************************************/
+static uint32_t maxFreqHfle(void)
+{
+ uint16_t majorMinorRev;
+
+ switch (SYSTEM_GetFamily()) {
+ case systemPartFamilyEfm32Leopard:
+ case systemPartFamilyEzr32Leopard:
+ /* CHIP MAJOR bit [5:0] */
+ majorMinorRev = (((ROMTABLE->PID0 & _ROMTABLE_PID0_REVMAJOR_MASK)
+ >> _ROMTABLE_PID0_REVMAJOR_SHIFT) << 8);
+ /* CHIP MINOR bit [7:4] */
+ majorMinorRev |= (((ROMTABLE->PID2 & _ROMTABLE_PID2_REVMINORMSB_MASK)
+ >> _ROMTABLE_PID2_REVMINORMSB_SHIFT) << 4);
+ /* CHIP MINOR bit [3:0] */
+ majorMinorRev |= ((ROMTABLE->PID3 & _ROMTABLE_PID3_REVMINORLSB_MASK)
+ >> _ROMTABLE_PID3_REVMINORLSB_SHIFT);
+
+ if (majorMinorRev >= 0x0204) {
+ return 24000000;
+ } else {
+ return 32000000;
+ }
+
+ case systemPartFamilyEfm32Giant:
+ return 32000000;
+
+ default:
+ /* Invalid device family. */
+ EFM_ASSERT(false);
+ return 0;
+ }
+}
+#endif
+
+#if defined(CMU_MAX_FREQ_HFLE)
+
+/* Unified definitions for HFLE wait-state and prescaler fields. */
+#if defined(CMU_CTRL_HFLE)
+#define _GENERIC_HFLE_WS_MASK _CMU_CTRL_HFLE_MASK
+#define _GENERIC_HFLE_WS_SHIFT _CMU_CTRL_HFLE_SHIFT
+#define GENERIC_HFLE_PRESC_REG CMU->HFCORECLKDIV
+#define _GENERIC_HFLE_PRESC_MASK _CMU_HFCORECLKDIV_HFCORECLKLEDIV_MASK
+#define _GENERIC_HFLE_PRESC_SHIFT _CMU_HFCORECLKDIV_HFCORECLKLEDIV_SHIFT
+#elif defined(CMU_CTRL_WSHFLE)
+#define _GENERIC_HFLE_WS_MASK _CMU_CTRL_WSHFLE_MASK
+#define _GENERIC_HFLE_WS_SHIFT _CMU_CTRL_WSHFLE_SHIFT
+#define GENERIC_HFLE_PRESC_REG CMU->HFPRESC
+#define _GENERIC_HFLE_PRESC_MASK _CMU_HFPRESC_HFCLKLEPRESC_MASK
+#define _GENERIC_HFLE_PRESC_SHIFT _CMU_HFPRESC_HFCLKLEPRESC_SHIFT
+#endif
+
+/***************************************************************************//**
+ * @brief
+ * Set HFLE wait-states and HFCLKLE prescaler.
+ *
+ * @param[in] maxLeFreq
+ * Max LE frequency
+ ******************************************************************************/
+static void setHfLeConfig(uint32_t hfFreq)
+{
+ unsigned int hfleWs;
+ uint32_t hflePresc;
+
+ /* Check for 1 bit fields. BUS_RegBitWrite() below are going to fail if the
+ fields are changed to more than 1 bit. */
+ EFM_ASSERT((_GENERIC_HFLE_WS_MASK >> _GENERIC_HFLE_WS_SHIFT) == 0x1);
+
+ /* - Enable HFLE wait-state if to allow access to LE peripherals when HFBUSCLK is
+ above maxLeFreq.
+ - Set HFLE prescaler. Allowed HFLE clock frequency is maxLeFreq. */
+
+ hfleWs = 1;
+ if (hfFreq <= CMU_MAX_FREQ_HFLE) {
+ hfleWs = 0;
+ hflePresc = 0;
+ } else if (hfFreq <= (2 * CMU_MAX_FREQ_HFLE)) {
+ hflePresc = 1;
+ } else {
+ hflePresc = 2;
+ }
+ BUS_RegBitWrite(&CMU->CTRL, _GENERIC_HFLE_WS_SHIFT, hfleWs);
+ GENERIC_HFLE_PRESC_REG = (GENERIC_HFLE_PRESC_REG & ~_GENERIC_HFLE_PRESC_MASK)
+ | (hflePresc << _GENERIC_HFLE_PRESC_SHIFT);
+}
+
+#if defined(_CMU_CTRL_HFLE_MASK)
+/***************************************************************************//**
+ * @brief
+ * Get HFLE wait-state configuration.
+ *
+ * @return
+ * Current wait-state configuration.
+ ******************************************************************************/
+static uint32_t getHfLeConfig(void)
+{
+ uint32_t ws = BUS_RegBitRead(&CMU->CTRL, _GENERIC_HFLE_WS_SHIFT);
+ return ws;
+}
+#endif
+#endif
+
+/***************************************************************************//**
+ * @brief
+ * Get the AUX clock frequency. Used by MSC flash programming and LESENSE,
+ * by default also as debug clock.
+ *
+ * @return
+ * AUX Frequency in Hz
+ ******************************************************************************/
+static uint32_t auxClkGet(void)
+{
+ uint32_t ret;
+
+#if defined(_CMU_AUXHFRCOCTRL_FREQRANGE_MASK)
+ ret = auxHfrcoFreq;
+
+#elif defined(_CMU_AUXHFRCOCTRL_BAND_MASK)
+ /* All series 0 families except EFM32G */
+ switch (CMU->AUXHFRCOCTRL & _CMU_AUXHFRCOCTRL_BAND_MASK) {
+ case CMU_AUXHFRCOCTRL_BAND_1MHZ:
+ if ( SYSTEM_GetProdRev() >= 19 ) {
+ ret = 1200000;
+ } else {
+ ret = 1000000;
+ }
+ break;
+
+ case CMU_AUXHFRCOCTRL_BAND_7MHZ:
+ if ( SYSTEM_GetProdRev() >= 19 ) {
+ ret = 6600000;
+ } else {
+ ret = 7000000;
+ }
+ break;
+
+ case CMU_AUXHFRCOCTRL_BAND_11MHZ:
+ ret = 11000000;
+ break;
+
+ case CMU_AUXHFRCOCTRL_BAND_14MHZ:
+ ret = 14000000;
+ break;
+
+ case CMU_AUXHFRCOCTRL_BAND_21MHZ:
+ ret = 21000000;
+ break;
+
+#if defined(_CMU_AUXHFRCOCTRL_BAND_28MHZ)
+ case CMU_AUXHFRCOCTRL_BAND_28MHZ:
+ ret = 28000000;
+ break;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ ret = 0;
+ break;
+ }
+
+#else
+ /* Gecko has a fixed 14Mhz AUXHFRCO clock */
+ ret = 14000000;
+
+#endif
+
+ return ret;
+}
+
+#if defined (_CMU_ADCCTRL_ADC0CLKSEL_HFSRCCLK) \
+ || defined (_CMU_ADCCTRL_ADC1CLKSEL_HFSRCCLK)
+/***************************************************************************//**
+ * @brief
+ * Get the HFSRCCLK frequency.
+ *
+ * @return
+ * HFSRCCLK Frequency in Hz
+ ******************************************************************************/
+static uint32_t hfSrcClkGet(void)
+{
+ uint32_t ret;
+
+ ret = SystemHFClockGet();
+ return ret * (1U + ((CMU->HFPRESC & _CMU_HFPRESC_PRESC_MASK)
+ >> _CMU_HFPRESC_PRESC_SHIFT));
+}
+#endif
+
+/***************************************************************************//**
+ * @brief
+ * Get the Debug Trace clock frequency
+ *
+ * @return
+ * Debug Trace frequency in Hz
+ ******************************************************************************/
+static uint32_t dbgClkGet(void)
+{
+ uint32_t ret;
+ CMU_Select_TypeDef clk;
+
+ /* Get selected clock source */
+ clk = CMU_ClockSelectGet(cmuClock_DBG);
+
+ switch (clk) {
+ case cmuSelect_HFCLK:
+ ret = SystemHFClockGet();
+ break;
+
+ case cmuSelect_AUXHFRCO:
+ ret = auxClkGet();
+ break;
+
+ default:
+ EFM_ASSERT(0);
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+#if defined(_CMU_ADCCTRL_MASK)
+/***************************************************************************//**
+ * @brief
+ * Get the ADC n asynchronous clock frequency
+ *
+ * @return
+ * ADC n asynchronous frequency in Hz
+ ******************************************************************************/
+static uint32_t adcAsyncClkGet(uint32_t adc)
+{
+ uint32_t ret;
+ CMU_Select_TypeDef clk;
+
+ /* Get selected clock source */
+ switch (adc) {
+ case 0:
+ clk = CMU_ClockSelectGet(cmuClock_ADC0ASYNC);
+ break;
+
+#if defined(_CMU_ADCCTRL_ADC1CLKSEL_MASK)
+ case 1:
+ clk = CMU_ClockSelectGet(cmuClock_ADC1ASYNC);
+ break;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ return 0;
+ }
+
+ switch (clk) {
+ case cmuSelect_Disabled:
+ ret = 0;
+ break;
+
+ case cmuSelect_AUXHFRCO:
+ ret = auxClkGet();
+ break;
+
+ case cmuSelect_HFXO:
+ ret = SystemHFXOClockGet();
+ break;
+
+ case cmuSelect_HFSRCCLK:
+ ret = hfSrcClkGet();
+ break;
+
+ default:
+ EFM_ASSERT(0);
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+#endif
+
+#if defined(_CMU_SDIOCTRL_MASK)
+/***************************************************************************//**
+ * @brief
+ * Get the SDIO reference clock frequency
+ *
+ * @return
+ * SDIO reference clock frequency in Hz
+ ******************************************************************************/
+static uint32_t sdioRefClkGet(void)
+{
+ uint32_t ret;
+ CMU_Select_TypeDef clk;
+
+ /* Get selected clock source */
+ clk = CMU_ClockSelectGet(cmuClock_SDIOREF);
+
+ switch (clk) {
+ case cmuSelect_HFRCO:
+ ret = SystemHfrcoFreq;
+ break;
+
+ case cmuSelect_HFXO:
+ ret = SystemHFXOClockGet();
+ break;
+
+ case cmuSelect_AUXHFRCO:
+ ret = auxClkGet();
+ break;
+
+ case cmuSelect_USHFRCO:
+ ret = ushfrcoFreq;
+ break;
+
+ default:
+ EFM_ASSERT(0);
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+#endif
+
+#if defined(_CMU_QSPICTRL_MASK)
+/***************************************************************************//**
+ * @brief
+ * Get the QSPI n reference clock frequency
+ *
+ * @return
+ * QSPI n reference clock frequency in Hz
+ ******************************************************************************/
+static uint32_t qspiRefClkGet(uint32_t qspi)
+{
+ uint32_t ret;
+ CMU_Select_TypeDef clk;
+
+ /* Get selected clock source */
+ switch (qspi) {
+ case 0:
+ clk = CMU_ClockSelectGet(cmuClock_QSPI0REF);
+ break;
+
+ default:
+ EFM_ASSERT(0);
+ return 0;
+ }
+
+ switch (clk) {
+ case cmuSelect_HFRCO:
+ ret = SystemHfrcoFreq;
+ break;
+
+ case cmuSelect_HFXO:
+ ret = SystemHFXOClockGet();
+ break;
+
+ case cmuSelect_AUXHFRCO:
+ ret = auxClkGet();
+ break;
+
+ case cmuSelect_USHFRCO:
+ ret = ushfrcoFreq;
+ break;
+
+ default:
+ EFM_ASSERT(0);
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+#endif
+
+#if defined(USBR_CLOCK_PRESENT)
+/***************************************************************************//**
+ * @brief
+ * Get the USB rate clock frequency
+ *
+ * @return
+ * USB rate clock frequency in Hz
+ ******************************************************************************/
+static uint32_t usbRateClkGet(void)
+{
+ uint32_t ret;
+ CMU_Select_TypeDef clk;
+
+ clk = CMU_ClockSelectGet(cmuClock_USBR);
+
+ switch (clk) {
+ case cmuSelect_USHFRCO:
+ ret = ushfrcoFreq;
+ break;
+
+ case cmuSelect_HFXO:
+ ret = SystemHFXOClockGet();
+ break;
+
+ case cmuSelect_HFXOX2:
+ ret = 2u * SystemHFXOClockGet();
+ break;
+
+ case cmuSelect_HFRCO:
+ ret = SystemHfrcoFreq;
+ break;
+
+ case cmuSelect_LFXO:
+ ret = SystemLFXOClockGet();
+ break;
+
+ case cmuSelect_LFRCO:
+ ret = SystemLFRCOClockGet();
+ break;
+
+ default:
+ EFM_ASSERT(0);
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+#endif
+
+/***************************************************************************//**
+ * @brief
+ * Configure flash access wait states in order to support given core clock
+ * frequency.
+ *
+ * @param[in] coreFreq
+ * Core clock frequency to configure flash wait-states for
+ *
+ * @param[in] vscale
+ * Voltage Scale level. Supported levels are 0 and 2 where 0 is the default.
+ ******************************************************************************/
+static void flashWaitStateControl(uint32_t coreFreq, int vscale)
+{
+ uint32_t mode;
+ bool mscLocked;
+#if defined(MSC_READCTRL_MODE_WS0SCBTP)
+ bool scbtpEn; /* Suppressed Conditional Branch Target Prefetch setting. */
+#endif
+ (void) vscale; /* vscale parameter is only used on some devices */
+
+ /* Make sure the MSC is unlocked */
+ mscLocked = MSC->LOCK;
+ MSC->LOCK = MSC_UNLOCK_CODE;
+
+ /* Get mode and SCBTP enable */
+ mode = MSC->READCTRL & _MSC_READCTRL_MODE_MASK;
+#if defined(MSC_READCTRL_MODE_WS0SCBTP)
+ /* Devices with MODE and SCBTP in same register field */
+ switch (mode) {
+ case MSC_READCTRL_MODE_WS0:
+ case MSC_READCTRL_MODE_WS1:
+#if defined(MSC_READCTRL_MODE_WS2)
+ case MSC_READCTRL_MODE_WS2:
+#endif
+ scbtpEn = false;
+ break;
+
+ default: /* WSxSCBTP */
+ scbtpEn = true;
+ break;
+ }
+
+ /* Set mode based on the core clock frequency and SCBTP enable */
+ if (false) {
+ }
+#if defined(MSC_READCTRL_MODE_WS2)
+ else if (coreFreq > CMU_MAX_FREQ_1WS) {
+ mode = (scbtpEn ? MSC_READCTRL_MODE_WS2SCBTP : MSC_READCTRL_MODE_WS2);
+ }
+#endif
+ else if ((coreFreq <= CMU_MAX_FREQ_1WS) && (coreFreq > CMU_MAX_FREQ_0WS)) {
+ mode = (scbtpEn ? MSC_READCTRL_MODE_WS1SCBTP : MSC_READCTRL_MODE_WS1);
+ } else {
+ mode = (scbtpEn ? MSC_READCTRL_MODE_WS0SCBTP : MSC_READCTRL_MODE_WS0);
+ }
+
+#elif defined(_SILICON_LABS_32B_SERIES_1) && defined(_EMU_STATUS_VSCALE_MASK)
+
+ /* These devices have specific requirements on the supported flash wait state
+ * depending on frequency and voltage scale level. */
+ uint32_t i;
+ for (i = 0; i < FLASH_WS_TABLE_ENTRIES; i++) {
+ if ((flashWsTable[i].vscale == vscale)
+ && (coreFreq <= flashWsTable[i].maxFreq)) {
+ break; // found matching entry
+ }
+ }
+
+ if (i == FLASH_WS_TABLE_ENTRIES) {
+ EFM_ASSERT(false);
+ mode = 3; // worst case flash wait state for unsupported cases
+ } else {
+ mode = flashWsTable[i].ws;
+ }
+ mode = mode << _MSC_READCTRL_MODE_SHIFT;
+
+#else
+ /* Devices where MODE and SCBTP are in separate fields and where the device
+ * either does not support voltage scale or where the voltage scale does
+ * not impact flash wait state configuration. */
+ if (coreFreq <= CMU_MAX_FREQ_0WS) {
+ mode = 0;
+ } else if (coreFreq <= CMU_MAX_FREQ_1WS) {
+ mode = 1;
+ }
+#if defined(MSC_READCTRL_MODE_WS2)
+ else if (coreFreq <= CMU_MAX_FREQ_2WS) {
+ mode = 2;
+ }
+#endif
+#if defined(MSC_READCTRL_MODE_WS3)
+ else if (coreFreq <= CMU_MAX_FREQ_3WS) {
+ mode = 3;
+ }
+#endif
+ mode = mode << _MSC_READCTRL_MODE_SHIFT;
+
+#endif
+
+ /* BUS_RegMaskedWrite cannot be used here as it would temporarily set the
+ mode field to WS0 */
+ MSC->READCTRL = (MSC->READCTRL & ~_MSC_READCTRL_MODE_MASK) | mode;
+
+ if (mscLocked) {
+ MSC->LOCK = 0;
+ }
+}
+
+/***************************************************************************//**
+ * @brief
+ * Configure flash access wait states to most conservative setting for
+ * this target. Retain SCBTP (Suppressed Conditional Branch Target Prefetch)
+ * setting.
+ ******************************************************************************/
+static void flashWaitStateMax(void)
+{
+ flashWaitStateControl(SystemMaxCoreClockGet(), 0);
+}
+
+#if defined(_MSC_RAMCTRL_RAMWSEN_MASK)
+/***************************************************************************//**
+ * @brief
+ * Configure RAM access wait states in order to support given core clock
+ * frequency.
+ *
+ * @param[in] coreFreq
+ * Core clock frequency to configure RAM wait-states for
+ *
+ * @param[in] vscale
+ * Voltage Scale level. Supported levels are 0 and 2 where 0 is the default.
+ ******************************************************************************/
+static void setRamWaitState(uint32_t coreFreq, int vscale)
+{
+ uint32_t limit = 38000000;
+ if (vscale == 2) {
+ limit = 16000000;
+ }
+
+ if (coreFreq > limit) {
+ BUS_RegMaskedSet(&MSC->RAMCTRL, (MSC_RAMCTRL_RAMWSEN
+ | MSC_RAMCTRL_RAM1WSEN
+ | MSC_RAMCTRL_RAM2WSEN));
+ } else {
+ BUS_RegMaskedClear(&MSC->RAMCTRL, (MSC_RAMCTRL_RAMWSEN
+ | MSC_RAMCTRL_RAM1WSEN
+ | MSC_RAMCTRL_RAM2WSEN));
+ }
+}
+#endif
+
+#if defined(_MSC_CTRL_WAITMODE_MASK)
+/***************************************************************************//**
+ * @brief
+ * Configure wait state for peripheral accesses over the bus to support
+ * given bus clock frequency.
+ *
+ * @param[in] busFreq
+ * peripheral bus clock frequency to configure wait-states for
+ *
+ * @param[in] vscale
+ * The voltage scale to configure wait-states for. Expected values are
+ * 0 or 2.
+ *
+ * @li 0 = 1.2 V (VSCALE2)
+ * @li 2 = 1.0 V (VSCALE0)
+ * ******************************************************************************/
+static void setBusWaitState(uint32_t busFreq, int vscale)
+{
+ if ((busFreq > 50000000) && (vscale == 0)) {
+ BUS_RegMaskedSet(&MSC->CTRL, MSC_CTRL_WAITMODE_WS1);
+ } else {
+ BUS_RegMaskedClear(&MSC->CTRL, MSC_CTRL_WAITMODE_WS1);
+ }
+}
+#endif
+
+/***************************************************************************//**
+ * @brief
+ * Configure various wait states necessary to switch to a certain frequency
+ * and a certain voltage scale.
+ *
+ * @details
+ * This function will setup the necessary flash, bus and RAM wait states.
+ * Updating the wait state configuration must be done before
+ * increasing the clock frequency, and it must be done after decreasing the
+ * clock frequency. Updating the wait state configuration must be done before
+ * core voltage is decreased, and it must be done after a core voltage is
+ * increased.
+ *
+ * @param[in] coreFreq
+ * Core clock frequency to configure wait-states for.
+ *
+ * @param[in] vscale
+ * The voltage scale to configure wait-states for. Expected values are
+ * 0 or 2, higher number is lower voltage.
+ *
+ * @li 0 = 1.2 V (VSCALE2)
+ * @li 2 = 1.0 V (VSCALE0)
+ *
+ ******************************************************************************/
+void CMU_UpdateWaitStates(uint32_t freq, int vscale)
+{
+ flashWaitStateControl(freq, vscale);
+#if defined(_MSC_RAMCTRL_RAMWSEN_MASK)
+ setRamWaitState(freq, vscale);
+#endif
+#if defined(_MSC_CTRL_WAITMODE_MASK)
+ setBusWaitState(freq, vscale);
+#endif
+}
+
+#if defined(_CMU_HFXOSTEADYSTATECTRL_REGISHUPPER_MASK)
+/***************************************************************************//**
+ * @brief
+ * Return upper value for CMU_HFXOSTEADYSTATECTRL_REGISH
+ ******************************************************************************/
+static uint32_t getRegIshUpperVal(uint32_t steadyStateRegIsh)
+{
+ uint32_t regIshUpper;
+ const uint32_t upperMax = _CMU_HFXOSTEADYSTATECTRL_REGISHUPPER_MASK
+ >> _CMU_HFXOSTEADYSTATECTRL_REGISHUPPER_SHIFT;
+ /* Add 3 as specified in register description for CMU_HFXOSTEADYSTATECTRL_REGISHUPPER. */
+ regIshUpper = SL_MIN(steadyStateRegIsh + 3, upperMax);
+ regIshUpper <<= _CMU_HFXOSTEADYSTATECTRL_REGISHUPPER_SHIFT;
+ return regIshUpper;
+}
+#endif
+
+#if defined(_CMU_HFXOCTRL_MASK)
+/***************************************************************************//**
+ * @brief
+ * Get the HFXO tuning mode
+ *
+ * @return
+ * The current HFXO tuning mode from the HFXOCTRL register.
+ ******************************************************************************/
+__STATIC_INLINE uint32_t getHfxoTuningMode(void)
+{
+#if defined(_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK)
+ return (CMU->HFXOCTRL & _CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK);
+#else
+ return (CMU->HFXOCTRL & _CMU_HFXOCTRL_PEAKDETMODE_MASK);
+#endif
+}
+
+/***************************************************************************//**
+ * @brief
+ * Set the HFXO tuning mode
+ *
+ * @param[in] mode
+ * the new HFXO tuning mode, this can be HFXO_TUNING_MODE_AUTO or
+ * HFXO_TUNING_MODE_CMD.
+ ******************************************************************************/
+__STATIC_INLINE void setHfxoTuningMode(uint32_t mode)
+{
+#if defined(_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK)
+ CMU->HFXOCTRL = (CMU->HFXOCTRL & ~_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK) | mode;
+#else
+ CMU->HFXOCTRL = (CMU->HFXOCTRL & ~_CMU_HFXOCTRL_PEAKDETMODE_MASK) | mode;
+#endif
+}
+#endif
+
+/***************************************************************************//**
+ * @brief
+ * Get the LFnCLK frequency based on current configuration.
+ *
+ * @param[in] lfClkBranch
+ * Selected LF branch
+ *
+ * @return
+ * The LFnCLK frequency in Hz. If no LFnCLK is selected (disabled), 0 is
+ * returned.
+ ******************************************************************************/
+static uint32_t lfClkGet(CMU_Clock_TypeDef lfClkBranch)
+{
+ uint32_t sel;
+ uint32_t ret = 0;
+
+ switch (lfClkBranch) {
+ case cmuClock_LFA:
+ case cmuClock_LFB:
+#if defined(_CMU_LFCCLKEN0_MASK)
+ case cmuClock_LFC:
+#endif
+#if defined(_CMU_LFECLKSEL_MASK)
+ case cmuClock_LFE:
+#endif
+ break;
+
+ default:
+ EFM_ASSERT(0);
+ break;
+ }
+
+ sel = CMU_ClockSelectGet(lfClkBranch);
+
+ /* Get clock select field */
+ switch (lfClkBranch) {
+ case cmuClock_LFA:
+#if defined(_CMU_LFCLKSEL_MASK)
+ sel = (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFA_MASK) >> _CMU_LFCLKSEL_LFA_SHIFT;
+#elif defined(_CMU_LFACLKSEL_MASK)
+ sel = (CMU->LFACLKSEL & _CMU_LFACLKSEL_LFA_MASK) >> _CMU_LFACLKSEL_LFA_SHIFT;
+#else
+ EFM_ASSERT(0);
+#endif
+ break;
+
+ case cmuClock_LFB:
+#if defined(_CMU_LFCLKSEL_MASK)
+ sel = (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFB_MASK) >> _CMU_LFCLKSEL_LFB_SHIFT;
+#elif defined(_CMU_LFBCLKSEL_MASK)
+ sel = (CMU->LFBCLKSEL & _CMU_LFBCLKSEL_LFB_MASK) >> _CMU_LFBCLKSEL_LFB_SHIFT;
+#else
+ EFM_ASSERT(0);
+#endif
+ break;
+
+#if defined(_CMU_LFCCLKEN0_MASK)
+ case cmuClock_LFC:
+#if defined(_CMU_LFCLKSEL_LFC_MASK)
+ sel = (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFC_MASK) >> _CMU_LFCLKSEL_LFC_SHIFT;
+#elif defined(_CMU_LFCCLKSEL_LFC_MASK)
+ sel = (CMU->LFCCLKSEL & _CMU_LFCCLKSEL_LFC_MASK) >> _CMU_LFCCLKSEL_LFC_SHIFT;
+#else
+ EFM_ASSERT(0);
+#endif
+ break;
+#endif
+
+#if defined(_CMU_LFECLKSEL_MASK)
+ case cmuClock_LFE:
+ sel = (CMU->LFECLKSEL & _CMU_LFECLKSEL_LFE_MASK) >> _CMU_LFECLKSEL_LFE_SHIFT;
+ break;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ break;
+ }
+
+ /* Get clock frequency */
+#if defined(_CMU_LFCLKSEL_MASK)
+ switch (sel) {
+ case _CMU_LFCLKSEL_LFA_LFRCO:
+ ret = SystemLFRCOClockGet();
+ break;
+
+ case _CMU_LFCLKSEL_LFA_LFXO:
+ ret = SystemLFXOClockGet();
+ break;
+
+#if defined(_CMU_LFCLKSEL_LFA_HFCORECLKLEDIV2)
+ case _CMU_LFCLKSEL_LFA_HFCORECLKLEDIV2:
+#if defined(CMU_MAX_FREQ_HFLE)
+ /* HFLE bit is or'ed by hardware with HFCORECLKLEDIV to reduce the
+ * frequency of CMU_HFCORECLKLEDIV2. */
+ ret = SystemCoreClockGet() / (1U << (getHfLeConfig() + 1));
+#else
+ ret = SystemCoreClockGet() / 2U;
+#endif
+ break;
+#endif
+
+ case _CMU_LFCLKSEL_LFA_DISABLED:
+ ret = 0;
+#if defined(CMU_LFCLKSEL_LFAE)
+ /* Check LF Extended bit setting for LFA or LFB ULFRCO clock */
+ if ((lfClkBranch == cmuClock_LFA) || (lfClkBranch == cmuClock_LFB)) {
+ if (CMU->LFCLKSEL >> (lfClkBranch == cmuClock_LFA
+ ? _CMU_LFCLKSEL_LFAE_SHIFT
+ : _CMU_LFCLKSEL_LFBE_SHIFT)) {
+ ret = SystemULFRCOClockGet();
+ }
+ }
+#endif
+ break;
+
+ default:
+ EFM_ASSERT(0);
+ ret = 0U;
+ break;
+ }
+#endif /* _CMU_LFCLKSEL_MASK */
+
+#if defined(_CMU_LFACLKSEL_MASK)
+ switch (sel) {
+ case _CMU_LFACLKSEL_LFA_LFRCO:
+ ret = SystemLFRCOClockGet();
+ break;
+
+ case _CMU_LFACLKSEL_LFA_LFXO:
+ ret = SystemLFXOClockGet();
+ break;
+
+ case _CMU_LFACLKSEL_LFA_ULFRCO:
+ ret = SystemULFRCOClockGet();
+ break;
+
+#if defined(CMU_LFACLKSEL_LFA_PLFRCO)
+ case _CMU_LFACLKSEL_LFA_PLFRCO:
+ ret = SystemLFRCOClockGet();
+ break;
+#endif
+
+#if defined(_CMU_LFACLKSEL_LFA_HFCLKLE)
+ case _CMU_LFACLKSEL_LFA_HFCLKLE:
+ ret = SystemCoreClockGet()
+ / CMU_Log2ToDiv(((CMU->HFPRESC & _CMU_HFPRESC_HFCLKLEPRESC_MASK)
+ >> _CMU_HFPRESC_HFCLKLEPRESC_SHIFT) + 1);
+ break;
+#elif defined(_CMU_LFBCLKSEL_LFB_HFCLKLE)
+ case _CMU_LFBCLKSEL_LFB_HFCLKLE:
+ ret = SystemCoreClockGet()
+ / CMU_Log2ToDiv(((CMU->HFPRESC & _CMU_HFPRESC_HFCLKLEPRESC_MASK)
+ >> _CMU_HFPRESC_HFCLKLEPRESC_SHIFT) + 1);
+ break;
+#endif
+
+ case _CMU_LFACLKSEL_LFA_DISABLED:
+ ret = 0;
+ break;
+ }
+#endif
+
+ return ret;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Wait for ongoing sync of register(s) to low frequency domain to complete.
+ *
+ * @param[in] mask
+ * Bitmask corresponding to SYNCBUSY register defined bits, indicating
+ * registers that must complete any ongoing synchronization.
+ ******************************************************************************/
+__STATIC_INLINE void syncReg(uint32_t mask)
+{
+ /* Avoid deadlock if modifying the same register twice when freeze mode is */
+ /* activated. */
+ if (CMU->FREEZE & CMU_FREEZE_REGFREEZE) {
+ return;
+ }
+
+ /* Wait for any pending previous write operation to have been completed */
+ /* in low frequency domain */
+ while (CMU->SYNCBUSY & mask) {
+ }
+}
+
+#if defined(USBC_CLOCK_PRESENT)
+/***************************************************************************//**
+ * @brief
+ * Get the USBC frequency
+ *
+ * @return
+ * USBC frequency in Hz
+ ******************************************************************************/
+static uint32_t usbCClkGet(void)
+{
+ uint32_t ret;
+ CMU_Select_TypeDef clk;
+
+ /* Get selected clock source */
+ clk = CMU_ClockSelectGet(cmuClock_USBC);
+
+ switch (clk) {
+ case cmuSelect_LFXO:
+ ret = SystemLFXOClockGet();
+ break;
+ case cmuSelect_LFRCO:
+ ret = SystemLFRCOClockGet();
+ break;
+#if defined (_CMU_USHFRCOCTRL_MASK)
+ case cmuSelect_USHFRCO:
+ ret = ushfrcoFreq;
+ break;
+#endif
+ case cmuSelect_HFCLK:
+ ret = SystemHFClockGet();
+ break;
+ default:
+ /* Clock is not enabled */
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+#endif
+
+/** @endcond */
+
+/*******************************************************************************
+ ************************** GLOBAL FUNCTIONS *******************************
+ ******************************************************************************/
+
+#if defined(_CMU_AUXHFRCOCTRL_BAND_MASK)
+/***************************************************************************//**
+ * @brief
+ * Get AUXHFRCO band in use.
+ *
+ * @return
+ * AUXHFRCO band in use.
+ ******************************************************************************/
+CMU_AUXHFRCOBand_TypeDef CMU_AUXHFRCOBandGet(void)
+{
+ return (CMU_AUXHFRCOBand_TypeDef)((CMU->AUXHFRCOCTRL
+ & _CMU_AUXHFRCOCTRL_BAND_MASK)
+ >> _CMU_AUXHFRCOCTRL_BAND_SHIFT);
+}
+#endif /* _CMU_AUXHFRCOCTRL_BAND_MASK */
+
+#if defined(_CMU_AUXHFRCOCTRL_BAND_MASK)
+/***************************************************************************//**
+ * @brief
+ * Set AUXHFRCO band and the tuning value based on the value in the
+ * calibration table made during production.
+ *
+ * @param[in] band
+ * AUXHFRCO band to activate.
+ ******************************************************************************/
+void CMU_AUXHFRCOBandSet(CMU_AUXHFRCOBand_TypeDef band)
+{
+ uint32_t tuning;
+
+ /* Read tuning value from calibration table */
+ switch (band) {
+ case cmuAUXHFRCOBand_1MHz:
+ tuning = (DEVINFO->AUXHFRCOCAL0 & _DEVINFO_AUXHFRCOCAL0_BAND1_MASK)
+ >> _DEVINFO_AUXHFRCOCAL0_BAND1_SHIFT;
+ break;
+
+ case cmuAUXHFRCOBand_7MHz:
+ tuning = (DEVINFO->AUXHFRCOCAL0 & _DEVINFO_AUXHFRCOCAL0_BAND7_MASK)
+ >> _DEVINFO_AUXHFRCOCAL0_BAND7_SHIFT;
+ break;
+
+ case cmuAUXHFRCOBand_11MHz:
+ tuning = (DEVINFO->AUXHFRCOCAL0 & _DEVINFO_AUXHFRCOCAL0_BAND11_MASK)
+ >> _DEVINFO_AUXHFRCOCAL0_BAND11_SHIFT;
+ break;
+
+ case cmuAUXHFRCOBand_14MHz:
+ tuning = (DEVINFO->AUXHFRCOCAL0 & _DEVINFO_AUXHFRCOCAL0_BAND14_MASK)
+ >> _DEVINFO_AUXHFRCOCAL0_BAND14_SHIFT;
+ break;
+
+ case cmuAUXHFRCOBand_21MHz:
+ tuning = (DEVINFO->AUXHFRCOCAL1 & _DEVINFO_AUXHFRCOCAL1_BAND21_MASK)
+ >> _DEVINFO_AUXHFRCOCAL1_BAND21_SHIFT;
+ break;
+
+#if defined(_CMU_AUXHFRCOCTRL_BAND_28MHZ)
+ case cmuAUXHFRCOBand_28MHz:
+ tuning = (DEVINFO->AUXHFRCOCAL1 & _DEVINFO_AUXHFRCOCAL1_BAND28_MASK)
+ >> _DEVINFO_AUXHFRCOCAL1_BAND28_SHIFT;
+ break;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ return;
+ }
+
+ /* Set band/tuning */
+ CMU->AUXHFRCOCTRL = (CMU->AUXHFRCOCTRL
+ & ~(_CMU_AUXHFRCOCTRL_BAND_MASK
+ | _CMU_AUXHFRCOCTRL_TUNING_MASK))
+ | (band << _CMU_AUXHFRCOCTRL_BAND_SHIFT)
+ | (tuning << _CMU_AUXHFRCOCTRL_TUNING_SHIFT);
+}
+#endif /* _CMU_AUXHFRCOCTRL_BAND_MASK */
+
+#if defined(_CMU_AUXHFRCOCTRL_FREQRANGE_MASK)
+/**************************************************************************//**
+ * @brief
+ * Get the AUXHFRCO frequency calibration word in DEVINFO
+ *
+ * @param[in] freq
+ * Frequency in Hz
+ *
+ * @return
+ * AUXHFRCO calibration word for a given frequency
+ *****************************************************************************/
+static uint32_t CMU_AUXHFRCODevinfoGet(CMU_AUXHFRCOFreq_TypeDef freq)
+{
+ switch (freq) {
+ /* 1, 2 and 4MHz share the same calibration word */
+ case cmuAUXHFRCOFreq_1M0Hz:
+ case cmuAUXHFRCOFreq_2M0Hz:
+ case cmuAUXHFRCOFreq_4M0Hz:
+ return DEVINFO->AUXHFRCOCAL0;
+
+ case cmuAUXHFRCOFreq_7M0Hz:
+ return DEVINFO->AUXHFRCOCAL3;
+
+ case cmuAUXHFRCOFreq_13M0Hz:
+ return DEVINFO->AUXHFRCOCAL6;
+
+ case cmuAUXHFRCOFreq_16M0Hz:
+ return DEVINFO->AUXHFRCOCAL7;
+
+ case cmuAUXHFRCOFreq_19M0Hz:
+ return DEVINFO->AUXHFRCOCAL8;
+
+ case cmuAUXHFRCOFreq_26M0Hz:
+ return DEVINFO->AUXHFRCOCAL10;
+
+ case cmuAUXHFRCOFreq_32M0Hz:
+ return DEVINFO->AUXHFRCOCAL11;
+
+ case cmuAUXHFRCOFreq_38M0Hz:
+ return DEVINFO->AUXHFRCOCAL12;
+
+#if defined(DEVINFO_AUXHFRCOCAL14)
+ case cmuAUXHFRCOFreq_48M0Hz:
+ return DEVINFO->AUXHFRCOCAL13;
+
+ case cmuAUXHFRCOFreq_50M0Hz:
+ return DEVINFO->AUXHFRCOCAL14;
+#endif
+
+ default: /* cmuAUXHFRCOFreq_UserDefined */
+ return 0;
+ }
+}
+#endif /* _CMU_AUXHFRCOCTRL_FREQRANGE_MASK */
+
+#if defined(_CMU_AUXHFRCOCTRL_FREQRANGE_MASK)
+/***************************************************************************//**
+ * @brief
+ * Get current AUXHFRCO frequency.
+ *
+ * @return
+ * AUXHFRCO frequency
+ ******************************************************************************/
+CMU_AUXHFRCOFreq_TypeDef CMU_AUXHFRCOBandGet(void)
+{
+ return auxHfrcoFreq;
+}
+#endif /* _CMU_AUXHFRCOCTRL_FREQRANGE_MASK */
+
+#if defined(_CMU_AUXHFRCOCTRL_FREQRANGE_MASK)
+/***************************************************************************//**
+ * @brief
+ * Set AUXHFRCO calibration for the selected target frequency.
+ *
+ * @param[in] setFreq
+ * AUXHFRCO frequency to set
+ ******************************************************************************/
+void CMU_AUXHFRCOBandSet(CMU_AUXHFRCOFreq_TypeDef setFreq)
+{
+ uint32_t freqCal;
+
+ /* Get DEVINFO index, set global auxHfrcoFreq */
+ freqCal = CMU_AUXHFRCODevinfoGet(setFreq);
+ EFM_ASSERT((freqCal != 0) && (freqCal != UINT_MAX));
+ auxHfrcoFreq = setFreq;
+
+ /* Wait for any previous sync to complete, and then set calibration data
+ for the selected frequency. */
+ while (BUS_RegBitRead(&CMU->SYNCBUSY, _CMU_SYNCBUSY_AUXHFRCOBSY_SHIFT)) ;
+
+ /* Set divider in AUXHFRCOCTRL for 1, 2 and 4MHz */
+ switch (setFreq) {
+ case cmuAUXHFRCOFreq_1M0Hz:
+ freqCal = (freqCal & ~_CMU_AUXHFRCOCTRL_CLKDIV_MASK)
+ | CMU_AUXHFRCOCTRL_CLKDIV_DIV4;
+ break;
+
+ case cmuAUXHFRCOFreq_2M0Hz:
+ freqCal = (freqCal & ~_CMU_AUXHFRCOCTRL_CLKDIV_MASK)
+ | CMU_AUXHFRCOCTRL_CLKDIV_DIV2;
+ break;
+
+ case cmuAUXHFRCOFreq_4M0Hz:
+ freqCal = (freqCal & ~_CMU_AUXHFRCOCTRL_CLKDIV_MASK)
+ | CMU_AUXHFRCOCTRL_CLKDIV_DIV1;
+ break;
+
+ default:
+ break;
+ }
+ CMU->AUXHFRCOCTRL = freqCal;
+}
+#endif /* _CMU_AUXHFRCOCTRL_FREQRANGE_MASK */
+
+/***************************************************************************//**
+ * @brief
+ * Calibrate clock.
+ *
+ * @details
+ * Run a calibration for HFCLK against a selectable reference clock. Please
+ * refer to the reference manual, CMU chapter, for further details.
+ *
+ * @note
+ * This function will not return until calibration measurement is completed.
+ *
+ * @param[in] HFCycles
+ * The number of HFCLK cycles to run calibration. Increasing this number
+ * increases precision, but the calibration will take more time.
+ *
+ * @param[in] ref
+ * The reference clock used to compare HFCLK with.
+ *
+ * @return
+ * The number of ticks the reference clock after HFCycles ticks on the HF
+ * clock.
+ ******************************************************************************/
+uint32_t CMU_Calibrate(uint32_t HFCycles, CMU_Osc_TypeDef ref)
+{
+ EFM_ASSERT(HFCycles <= (_CMU_CALCNT_CALCNT_MASK >> _CMU_CALCNT_CALCNT_SHIFT));
+
+ /* Set reference clock source */
+ switch (ref) {
+ case cmuOsc_LFXO:
+ CMU->CALCTRL = CMU_CALCTRL_UPSEL_LFXO;
+ break;
+
+ case cmuOsc_LFRCO:
+ CMU->CALCTRL = CMU_CALCTRL_UPSEL_LFRCO;
+ break;
+
+ case cmuOsc_HFXO:
+ CMU->CALCTRL = CMU_CALCTRL_UPSEL_HFXO;
+ break;
+
+ case cmuOsc_HFRCO:
+ CMU->CALCTRL = CMU_CALCTRL_UPSEL_HFRCO;
+ break;
+
+ case cmuOsc_AUXHFRCO:
+ CMU->CALCTRL = CMU_CALCTRL_UPSEL_AUXHFRCO;
+ break;
+
+#if defined (_CMU_USHFRCOCTRL_MASK)
+ case cmuOsc_USHFRCO:
+ CMU->CALCTRL = CMU_CALCTRL_UPSEL_USHFRCO;
+ break;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ return 0;
+ }
+
+ /* Set top value */
+ CMU->CALCNT = HFCycles;
+
+ /* Start calibration */
+ CMU->CMD = CMU_CMD_CALSTART;
+
+#if defined(CMU_STATUS_CALRDY)
+ /* Wait until calibration completes */
+ while (!BUS_RegBitRead(&CMU->STATUS, _CMU_STATUS_CALRDY_SHIFT)) {
+ }
+#else
+ /* Wait until calibration completes */
+ while (BUS_RegBitRead(&CMU->STATUS, _CMU_STATUS_CALBSY_SHIFT)) {
+ }
+#endif
+
+ return CMU->CALCNT;
+}
+
+#if defined(_CMU_CALCTRL_UPSEL_MASK) && defined(_CMU_CALCTRL_DOWNSEL_MASK)
+/***************************************************************************//**
+ * @brief
+ * Configure clock calibration
+ *
+ * @details
+ * Configure a calibration for a selectable clock source against another
+ * selectable reference clock.
+ * Refer to the reference manual, CMU chapter, for further details.
+ *
+ * @note
+ * After configuration, a call to CMU_CalibrateStart() is required, and
+ * the resulting calibration value can be read out with the
+ * CMU_CalibrateCountGet() function call.
+ *
+ * @param[in] downCycles
+ * The number of downSel clock cycles to run calibration. Increasing this
+ * number increases precision, but the calibration will take more time.
+ *
+ * @param[in] downSel
+ * The clock which will be counted down downCycles
+ *
+ * @param[in] upSel
+ * The reference clock, the number of cycles generated by this clock will
+ * be counted and added up, the result can be given with the
+ * CMU_CalibrateCountGet() function call.
+ ******************************************************************************/
+void CMU_CalibrateConfig(uint32_t downCycles, CMU_Osc_TypeDef downSel,
+ CMU_Osc_TypeDef upSel)
+{
+ /* Keep untouched configuration settings */
+ uint32_t calCtrl = CMU->CALCTRL
+ & ~(_CMU_CALCTRL_UPSEL_MASK | _CMU_CALCTRL_DOWNSEL_MASK);
+
+ /* 20 bits of precision to calibration count register */
+ EFM_ASSERT(downCycles <= (_CMU_CALCNT_CALCNT_MASK >> _CMU_CALCNT_CALCNT_SHIFT));
+
+ /* Set down counting clock source - down counter */
+ switch (downSel) {
+ case cmuOsc_LFXO:
+ calCtrl |= CMU_CALCTRL_DOWNSEL_LFXO;
+ break;
+
+ case cmuOsc_LFRCO:
+ calCtrl |= CMU_CALCTRL_DOWNSEL_LFRCO;
+ break;
+
+ case cmuOsc_HFXO:
+ calCtrl |= CMU_CALCTRL_DOWNSEL_HFXO;
+ break;
+
+ case cmuOsc_HFRCO:
+ calCtrl |= CMU_CALCTRL_DOWNSEL_HFRCO;
+ break;
+
+ case cmuOsc_AUXHFRCO:
+ calCtrl |= CMU_CALCTRL_DOWNSEL_AUXHFRCO;
+ break;
+
+#if defined (_CMU_USHFRCOCTRL_MASK)
+ case cmuOsc_USHFRCO:
+ calCtrl |= CMU_CALCTRL_DOWNSEL_USHFRCO;
+ break;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ break;
+ }
+
+ /* Set top value to be counted down by the downSel clock */
+ CMU->CALCNT = downCycles;
+
+ /* Set reference clock source - up counter */
+ switch (upSel) {
+ case cmuOsc_LFXO:
+ calCtrl |= CMU_CALCTRL_UPSEL_LFXO;
+ break;
+
+ case cmuOsc_LFRCO:
+ calCtrl |= CMU_CALCTRL_UPSEL_LFRCO;
+ break;
+
+ case cmuOsc_HFXO:
+ calCtrl |= CMU_CALCTRL_UPSEL_HFXO;
+ break;
+
+ case cmuOsc_HFRCO:
+ calCtrl |= CMU_CALCTRL_UPSEL_HFRCO;
+ break;
+
+ case cmuOsc_AUXHFRCO:
+ calCtrl |= CMU_CALCTRL_UPSEL_AUXHFRCO;
+ break;
+
+#if defined (_CMU_USHFRCOCTRL_MASK)
+ case cmuOsc_USHFRCO:
+ calCtrl |= CMU_CALCTRL_UPSEL_USHFRCO;
+ break;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ break;
+ }
+
+ CMU->CALCTRL = calCtrl;
+}
+#endif
+
+/***************************************************************************//**
+ * @brief
+ * Get calibration count register
+ * @note
+ * If continuous calibrartion mode is active, calibration busy will almost
+ * always be off, and we just need to read the value, where the normal case
+ * would be that this function call has been triggered by the CALRDY
+ * interrupt flag.
+ * @return
+ * Calibration count, the number of UPSEL clocks (see CMU_CalibrateConfig)
+ * in the period of DOWNSEL oscillator clock cycles configured by a previous
+ * write operation to CMU->CALCNT
+ ******************************************************************************/
+uint32_t CMU_CalibrateCountGet(void)
+{
+ /* Wait until calibration completes, UNLESS continuous calibration mode is */
+ /* active */
+#if defined(CMU_CALCTRL_CONT)
+ if (!BUS_RegBitRead(&CMU->CALCTRL, _CMU_CALCTRL_CONT_SHIFT)) {
+#if defined(CMU_STATUS_CALRDY)
+ /* Wait until calibration completes */
+ while (!BUS_RegBitRead(&CMU->STATUS, _CMU_STATUS_CALRDY_SHIFT)) {
+ }
+#else
+ /* Wait until calibration completes */
+ while (BUS_RegBitRead(&CMU->STATUS, _CMU_STATUS_CALBSY_SHIFT)) {
+ }
+#endif
+ }
+#else
+ while (BUS_RegBitRead(&CMU->STATUS, _CMU_STATUS_CALBSY_SHIFT)) {
+ }
+#endif
+ return CMU->CALCNT;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Get clock divisor/prescaler.
+ *
+ * @param[in] clock
+ * Clock point to get divisor/prescaler for. Notice that not all clock points
+ * have a divisor/prescaler. Please refer to CMU overview in reference manual.
+ *
+ * @return
+ * The current clock point divisor/prescaler. 1 is returned
+ * if @p clock specifies a clock point without a divisor/prescaler.
+ ******************************************************************************/
+CMU_ClkDiv_TypeDef CMU_ClockDivGet(CMU_Clock_TypeDef clock)
+{
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ return 1 + (uint32_t)CMU_ClockPrescGet(clock);
+
+#elif defined(_SILICON_LABS_32B_SERIES_0)
+ uint32_t divReg;
+ CMU_ClkDiv_TypeDef ret;
+
+ /* Get divisor reg id */
+ divReg = (clock >> CMU_DIV_REG_POS) & CMU_DIV_REG_MASK;
+
+ switch (divReg) {
+#if defined(_CMU_CTRL_HFCLKDIV_MASK)
+ case CMU_HFCLKDIV_REG:
+ ret = 1 + ((CMU->CTRL & _CMU_CTRL_HFCLKDIV_MASK)
+ >> _CMU_CTRL_HFCLKDIV_SHIFT);
+ break;
+#endif
+
+ case CMU_HFPERCLKDIV_REG:
+ ret = (CMU_ClkDiv_TypeDef)((CMU->HFPERCLKDIV
+ & _CMU_HFPERCLKDIV_HFPERCLKDIV_MASK)
+ >> _CMU_HFPERCLKDIV_HFPERCLKDIV_SHIFT);
+ ret = CMU_Log2ToDiv(ret);
+ break;
+
+ case CMU_HFCORECLKDIV_REG:
+ ret = (CMU_ClkDiv_TypeDef)((CMU->HFCORECLKDIV
+ & _CMU_HFCORECLKDIV_HFCORECLKDIV_MASK)
+ >> _CMU_HFCORECLKDIV_HFCORECLKDIV_SHIFT);
+ ret = CMU_Log2ToDiv(ret);
+ break;
+
+ case CMU_LFAPRESC0_REG:
+ switch (clock) {
+ case cmuClock_RTC:
+ ret = (CMU_ClkDiv_TypeDef)((CMU->LFAPRESC0 & _CMU_LFAPRESC0_RTC_MASK)
+ >> _CMU_LFAPRESC0_RTC_SHIFT);
+ ret = CMU_Log2ToDiv(ret);
+ break;
+
+#if defined(_CMU_LFAPRESC0_LETIMER0_MASK)
+ case cmuClock_LETIMER0:
+ ret = (CMU_ClkDiv_TypeDef)((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LETIMER0_MASK)
+ >> _CMU_LFAPRESC0_LETIMER0_SHIFT);
+ ret = CMU_Log2ToDiv(ret);
+ break;
+#endif
+
+#if defined(_CMU_LFAPRESC0_LCD_MASK)
+ case cmuClock_LCDpre:
+ ret = (CMU_ClkDiv_TypeDef)(((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LCD_MASK)
+ >> _CMU_LFAPRESC0_LCD_SHIFT)
+ + CMU_DivToLog2(cmuClkDiv_16));
+ ret = CMU_Log2ToDiv(ret);
+ break;
+#endif
+
+#if defined(_CMU_LFAPRESC0_LESENSE_MASK)
+ case cmuClock_LESENSE:
+ ret = (CMU_ClkDiv_TypeDef)((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LESENSE_MASK)
+ >> _CMU_LFAPRESC0_LESENSE_SHIFT);
+ ret = CMU_Log2ToDiv(ret);
+ break;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ ret = cmuClkDiv_1;
+ break;
+ }
+ break;
+
+ case CMU_LFBPRESC0_REG:
+ switch (clock) {
+#if defined(_CMU_LFBPRESC0_LEUART0_MASK)
+ case cmuClock_LEUART0:
+ ret = (CMU_ClkDiv_TypeDef)((CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART0_MASK)
+ >> _CMU_LFBPRESC0_LEUART0_SHIFT);
+ ret = CMU_Log2ToDiv(ret);
+ break;
+#endif
+
+#if defined(_CMU_LFBPRESC0_LEUART1_MASK)
+ case cmuClock_LEUART1:
+ ret = (CMU_ClkDiv_TypeDef)((CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART1_MASK)
+ >> _CMU_LFBPRESC0_LEUART1_SHIFT);
+ ret = CMU_Log2ToDiv(ret);
+ break;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ ret = cmuClkDiv_1;
+ break;
+ }
+ break;
+
+ default:
+ EFM_ASSERT(0);
+ ret = cmuClkDiv_1;
+ break;
+ }
+
+ return ret;
+#endif
+}
+
+/***************************************************************************//**
+ * @brief
+ * Set clock divisor/prescaler.
+ *
+ * @note
+ * If setting a LF clock prescaler, synchronization into the low frequency
+ * domain is required. If the same register is modified before a previous
+ * update has completed, this function will stall until the previous
+ * synchronization has completed. Please refer to CMU_FreezeEnable() for
+ * a suggestion on how to reduce stalling time in some use cases.
+ *
+ * @param[in] clock
+ * Clock point to set divisor/prescaler for. Notice that not all clock points
+ * have a divisor/prescaler, please refer to CMU overview in the reference
+ * manual.
+ *
+ * @param[in] div
+ * The clock divisor to use (<= cmuClkDiv_512).
+ ******************************************************************************/
+void CMU_ClockDivSet(CMU_Clock_TypeDef clock, CMU_ClkDiv_TypeDef div)
+{
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ CMU_ClockPrescSet(clock, (CMU_ClkPresc_TypeDef)(div - 1));
+
+#elif defined(_SILICON_LABS_32B_SERIES_0)
+ uint32_t freq;
+ uint32_t divReg;
+
+ /* Get divisor reg id */
+ divReg = (clock >> CMU_DIV_REG_POS) & CMU_DIV_REG_MASK;
+
+ switch (divReg) {
+#if defined(_CMU_CTRL_HFCLKDIV_MASK)
+ case CMU_HFCLKDIV_REG:
+ EFM_ASSERT((div >= cmuClkDiv_1) && (div <= cmuClkDiv_8));
+
+ /* Configure worst case wait states for flash access before setting divisor */
+ flashWaitStateMax();
+
+ /* Set divider */
+ CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_HFCLKDIV_MASK)
+ | ((div - 1) << _CMU_CTRL_HFCLKDIV_SHIFT);
+
+ /* Update CMSIS core clock variable */
+ /* (The function will update the global variable) */
+ freq = SystemCoreClockGet();
+
+ /* Optimize flash access wait state setting for current core clk */
+ CMU_UpdateWaitStates(freq, VSCALE_DEFAULT);
+ break;
+#endif
+
+ case CMU_HFPERCLKDIV_REG:
+ EFM_ASSERT((div >= cmuClkDiv_1) && (div <= cmuClkDiv_512));
+ /* Convert to correct scale */
+ div = CMU_DivToLog2(div);
+ CMU->HFPERCLKDIV = (CMU->HFPERCLKDIV & ~_CMU_HFPERCLKDIV_HFPERCLKDIV_MASK)
+ | (div << _CMU_HFPERCLKDIV_HFPERCLKDIV_SHIFT);
+ break;
+
+ case CMU_HFCORECLKDIV_REG:
+ EFM_ASSERT((div >= cmuClkDiv_1) && (div <= cmuClkDiv_512));
+
+ /* Configure worst case wait states for flash access before setting divisor */
+ flashWaitStateMax();
+
+#if defined(CMU_MAX_FREQ_HFLE)
+ setHfLeConfig(SystemHFClockGet() / div);
+#endif
+
+ /* Convert to correct scale */
+ div = CMU_DivToLog2(div);
+
+ CMU->HFCORECLKDIV = (CMU->HFCORECLKDIV
+ & ~_CMU_HFCORECLKDIV_HFCORECLKDIV_MASK)
+ | (div << _CMU_HFCORECLKDIV_HFCORECLKDIV_SHIFT);
+
+ /* Update CMSIS core clock variable */
+ /* (The function will update the global variable) */
+ freq = SystemCoreClockGet();
+
+ /* Optimize wait state setting for current core clk */
+ CMU_UpdateWaitStates(freq, VSCALE_DEFAULT);
+ break;
+
+ case CMU_LFAPRESC0_REG:
+ switch (clock) {
+ case cmuClock_RTC:
+ EFM_ASSERT(div <= cmuClkDiv_32768);
+
+ /* LF register about to be modified require sync. busy check */
+ syncReg(CMU_SYNCBUSY_LFAPRESC0);
+
+ /* Convert to correct scale */
+ div = CMU_DivToLog2(div);
+
+ CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_RTC_MASK)
+ | (div << _CMU_LFAPRESC0_RTC_SHIFT);
+ break;
+
+#if defined(_CMU_LFAPRESC0_LETIMER0_MASK)
+ case cmuClock_LETIMER0:
+ EFM_ASSERT(div <= cmuClkDiv_32768);
+
+ /* LF register about to be modified require sync. busy check */
+ syncReg(CMU_SYNCBUSY_LFAPRESC0);
+
+ /* Convert to correct scale */
+ div = CMU_DivToLog2(div);
+
+ CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LETIMER0_MASK)
+ | (div << _CMU_LFAPRESC0_LETIMER0_SHIFT);
+ break;
+#endif
+
+#if defined(LCD_PRESENT)
+ case cmuClock_LCDpre:
+ EFM_ASSERT((div >= cmuClkDiv_16) && (div <= cmuClkDiv_128));
+
+ /* LF register about to be modified require sync. busy check */
+ syncReg(CMU_SYNCBUSY_LFAPRESC0);
+
+ /* Convert to correct scale */
+ div = CMU_DivToLog2(div);
+
+ CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LCD_MASK)
+ | ((div - CMU_DivToLog2(cmuClkDiv_16))
+ << _CMU_LFAPRESC0_LCD_SHIFT);
+ break;
+#endif /* defined(LCD_PRESENT) */
+
+#if defined(LESENSE_PRESENT)
+ case cmuClock_LESENSE:
+ EFM_ASSERT(div <= cmuClkDiv_8);
+
+ /* LF register about to be modified require sync. busy check */
+ syncReg(CMU_SYNCBUSY_LFAPRESC0);
+
+ /* Convert to correct scale */
+ div = CMU_DivToLog2(div);
+
+ CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LESENSE_MASK)
+ | (div << _CMU_LFAPRESC0_LESENSE_SHIFT);
+ break;
+#endif /* defined(LESENSE_PRESENT) */
+
+ default:
+ EFM_ASSERT(0);
+ break;
+ }
+ break;
+
+ case CMU_LFBPRESC0_REG:
+ switch (clock) {
+#if defined(_CMU_LFBPRESC0_LEUART0_MASK)
+ case cmuClock_LEUART0:
+ EFM_ASSERT(div <= cmuClkDiv_8);
+
+ /* LF register about to be modified require sync. busy check */
+ syncReg(CMU_SYNCBUSY_LFBPRESC0);
+
+ /* Convert to correct scale */
+ div = CMU_DivToLog2(div);
+
+ CMU->LFBPRESC0 = (CMU->LFBPRESC0 & ~_CMU_LFBPRESC0_LEUART0_MASK)
+ | (((uint32_t)div) << _CMU_LFBPRESC0_LEUART0_SHIFT);
+ break;
+#endif
+
+#if defined(_CMU_LFBPRESC0_LEUART1_MASK)
+ case cmuClock_LEUART1:
+ EFM_ASSERT(div <= cmuClkDiv_8);
+
+ /* LF register about to be modified require sync. busy check */
+ syncReg(CMU_SYNCBUSY_LFBPRESC0);
+
+ /* Convert to correct scale */
+ div = CMU_DivToLog2(div);
+
+ CMU->LFBPRESC0 = (CMU->LFBPRESC0 & ~_CMU_LFBPRESC0_LEUART1_MASK)
+ | (((uint32_t)div) << _CMU_LFBPRESC0_LEUART1_SHIFT);
+ break;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ break;
+ }
+ break;
+
+ default:
+ EFM_ASSERT(0);
+ break;
+ }
+#endif
+}
+
+/***************************************************************************//**
+ * @brief
+ * Enable/disable a clock.
+ *
+ * @details
+ * In general, module clocking is disabled after a reset. If a module
+ * clock is disabled, the registers of that module are not accessible and
+ * reading from such registers may return undefined values. Writing to
+ * registers of clock disabled modules have no effect. One should normally
+ * avoid accessing module registers of a module with a disabled clock.
+ *
+ * @note
+ * If enabling/disabling a LF clock, synchronization into the low frequency
+ * domain is required. If the same register is modified before a previous
+ * update has completed, this function will stall until the previous
+ * synchronization has completed. Please refer to CMU_FreezeEnable() for
+ * a suggestion on how to reduce stalling time in some use cases.
+ *
+ * @param[in] clock
+ * The clock to enable/disable. Notice that not all defined clock
+ * points have separate enable/disable control, please refer to CMU overview
+ * in reference manual.
+ *
+ * @param[in] enable
+ * @li true - enable specified clock.
+ * @li false - disable specified clock.
+ ******************************************************************************/
+void CMU_ClockEnable(CMU_Clock_TypeDef clock, bool enable)
+{
+ volatile uint32_t *reg;
+ uint32_t bit;
+ uint32_t sync = 0;
+
+ /* Identify enable register */
+ switch ((clock >> CMU_EN_REG_POS) & CMU_EN_REG_MASK) {
+#if defined(_CMU_CTRL_HFPERCLKEN_MASK)
+ case CMU_CTRL_EN_REG:
+ reg = &CMU->CTRL;
+ break;
+#endif
+
+#if defined(_CMU_HFCORECLKEN0_MASK)
+ case CMU_HFCORECLKEN0_EN_REG:
+ reg = &CMU->HFCORECLKEN0;
+#if defined(CMU_MAX_FREQ_HFLE)
+ setHfLeConfig(CMU_ClockFreqGet(cmuClock_HFLE));
+#endif
+ break;
+#endif
+
+#if defined(_CMU_HFBUSCLKEN0_MASK)
+ case CMU_HFBUSCLKEN0_EN_REG:
+ reg = &CMU->HFBUSCLKEN0;
+ break;
+#endif
+
+#if defined(_CMU_HFPERCLKDIV_MASK)
+ case CMU_HFPERCLKDIV_EN_REG:
+ reg = &CMU->HFPERCLKDIV;
+ break;
+#endif
+
+ case CMU_HFPERCLKEN0_EN_REG:
+ reg = &CMU->HFPERCLKEN0;
+ break;
+
+#if defined(_CMU_HFPERCLKEN1_MASK)
+ case CMU_HFPERCLKEN1_EN_REG:
+ reg = &CMU->HFPERCLKEN1;
+ break;
+#endif
+
+ case CMU_LFACLKEN0_EN_REG:
+ reg = &CMU->LFACLKEN0;
+ sync = CMU_SYNCBUSY_LFACLKEN0;
+ break;
+
+ case CMU_LFBCLKEN0_EN_REG:
+ reg = &CMU->LFBCLKEN0;
+ sync = CMU_SYNCBUSY_LFBCLKEN0;
+ break;
+
+#if defined(_CMU_LFCCLKEN0_MASK)
+ case CMU_LFCCLKEN0_EN_REG:
+ reg = &CMU->LFCCLKEN0;
+ sync = CMU_SYNCBUSY_LFCCLKEN0;
+ break;
+#endif
+
+#if defined(_CMU_LFECLKEN0_MASK)
+ case CMU_LFECLKEN0_EN_REG:
+ reg = &CMU->LFECLKEN0;
+ sync = CMU_SYNCBUSY_LFECLKEN0;
+ break;
+#endif
+
+#if defined(_CMU_SDIOCTRL_MASK)
+ case CMU_SDIOREF_EN_REG:
+ reg = &CMU->SDIOCTRL;
+ enable = !enable;
+ break;
+#endif
+
+#if defined(_CMU_QSPICTRL_MASK)
+ case CMU_QSPI0REF_EN_REG:
+ reg = &CMU->QSPICTRL;
+ enable = !enable;
+ break;
+#endif
+#if defined(_CMU_USBCTRL_MASK)
+ case CMU_USBRCLK_EN_REG:
+ reg = &CMU->USBCTRL;
+ break;
+#endif
+
+ case CMU_PCNT_EN_REG:
+ reg = &CMU->PCNTCTRL;
+ break;
+
+ default: /* Cannot enable/disable clock point */
+ EFM_ASSERT(0);
+ return;
+ }
+
+ /* Get bit position used to enable/disable */
+ bit = (clock >> CMU_EN_BIT_POS) & CMU_EN_BIT_MASK;
+
+ /* LF synchronization required? */
+ if (sync) {
+ syncReg(sync);
+ }
+
+ /* Set/clear bit as requested */
+ BUS_RegBitWrite(reg, bit, enable);
+}
+
+/***************************************************************************//**
+ * @brief
+ * Get clock frequency for a clock point.
+ *
+ * @param[in] clock
+ * Clock point to fetch frequency for.
+ *
+ * @return
+ * The current frequency in Hz.
+ ******************************************************************************/
+uint32_t CMU_ClockFreqGet(CMU_Clock_TypeDef clock)
+{
+ uint32_t ret;
+
+ switch (clock & (CMU_CLK_BRANCH_MASK << CMU_CLK_BRANCH_POS)) {
+ case (CMU_HF_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = SystemHFClockGet();
+ break;
+
+ case (CMU_HFPER_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = SystemHFClockGet();
+ /* Calculate frequency after HFPER divider. */
+#if defined(_CMU_HFPERCLKDIV_HFPERCLKDIV_MASK)
+ ret >>= (CMU->HFPERCLKDIV & _CMU_HFPERCLKDIV_HFPERCLKDIV_MASK)
+ >> _CMU_HFPERCLKDIV_HFPERCLKDIV_SHIFT;
+#endif
+#if defined(_CMU_HFPERPRESC_PRESC_MASK)
+ ret /= 1U + ((CMU->HFPERPRESC & _CMU_HFPERPRESC_PRESC_MASK)
+ >> _CMU_HFPERPRESC_PRESC_SHIFT);
+#endif
+ break;
+
+#if defined(_SILICON_LABS_32B_SERIES_1)
+#if defined(CRYPTO_PRESENT) \
+ || defined(LDMA_PRESENT) \
+ || defined(GPCRC_PRESENT) \
+ || defined(PRS_PRESENT) \
+ || defined(GPIO_PRESENT)
+ case (CMU_HFBUS_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = SystemHFClockGet();
+ break;
+#endif
+
+ case (CMU_HFCORE_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = SystemHFClockGet();
+ ret /= 1U + ((CMU->HFCOREPRESC & _CMU_HFCOREPRESC_PRESC_MASK)
+ >> _CMU_HFCOREPRESC_PRESC_SHIFT);
+ break;
+
+ case (CMU_HFEXP_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = SystemHFClockGet();
+ ret /= 1U + ((CMU->HFEXPPRESC & _CMU_HFEXPPRESC_PRESC_MASK)
+ >> _CMU_HFEXPPRESC_PRESC_SHIFT);
+ break;
+#endif
+
+#if defined(_SILICON_LABS_32B_SERIES_0)
+#if defined(AES_PRESENT) \
+ || defined(DMA_PRESENT) \
+ || defined(EBI_PRESENT) \
+ || defined(USB_PRESENT)
+ case (CMU_HFCORE_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ {
+ ret = SystemCoreClockGet();
+ } break;
+#endif
+#endif
+
+ case (CMU_LFA_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = lfClkGet(cmuClock_LFA);
+ break;
+
+#if defined(_CMU_LFACLKEN0_RTC_MASK)
+ case (CMU_RTC_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = lfClkGet(cmuClock_LFA);
+ ret >>= (CMU->LFAPRESC0 & _CMU_LFAPRESC0_RTC_MASK)
+ >> _CMU_LFAPRESC0_RTC_SHIFT;
+ break;
+#endif
+
+#if defined(_CMU_LFECLKEN0_RTCC_MASK)
+ case (CMU_RTCC_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = lfClkGet(cmuClock_LFE);
+ break;
+#endif
+
+#if defined(_CMU_LFACLKEN0_LETIMER0_MASK)
+ case (CMU_LETIMER0_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = lfClkGet(cmuClock_LFA);
+#if defined(_SILICON_LABS_32B_SERIES_0)
+ ret >>= (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LETIMER0_MASK)
+ >> _CMU_LFAPRESC0_LETIMER0_SHIFT;
+#else
+ ret /= CMU_Log2ToDiv((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LETIMER0_MASK)
+ >> _CMU_LFAPRESC0_LETIMER0_SHIFT);
+#endif
+ break;
+#endif
+
+#if defined(_CMU_LFACLKEN0_LCD_MASK)
+ case (CMU_LCDPRE_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = lfClkGet(cmuClock_LFA);
+#if defined(_SILICON_LABS_32B_SERIES_0)
+ ret >>= ((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LCD_MASK)
+ >> _CMU_LFAPRESC0_LCD_SHIFT)
+ + CMU_DivToLog2(cmuClkDiv_16);
+#else
+ ret /= CMU_Log2ToDiv((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LCD_MASK)
+ >> _CMU_LFAPRESC0_LCD_SHIFT);
+#endif
+ break;
+
+#if defined(_CMU_LCDCTRL_MASK)
+ case (CMU_LCD_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = lfClkGet(cmuClock_LFA);
+ ret >>= (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LCD_MASK)
+ >> _CMU_LFAPRESC0_LCD_SHIFT;
+ ret /= 1U + ((CMU->LCDCTRL & _CMU_LCDCTRL_FDIV_MASK)
+ >> _CMU_LCDCTRL_FDIV_SHIFT);
+ break;
+#endif
+#endif
+
+#if defined(_CMU_LFACLKEN0_LESENSE_MASK)
+ case (CMU_LESENSE_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = lfClkGet(cmuClock_LFA);
+ ret >>= (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LESENSE_MASK)
+ >> _CMU_LFAPRESC0_LESENSE_SHIFT;
+ break;
+#endif
+
+ case (CMU_LFB_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = lfClkGet(cmuClock_LFB);
+ break;
+
+#if defined(_CMU_LFBCLKEN0_LEUART0_MASK)
+ case (CMU_LEUART0_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = lfClkGet(cmuClock_LFB);
+#if defined(_SILICON_LABS_32B_SERIES_0)
+ ret >>= (CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART0_MASK)
+ >> _CMU_LFBPRESC0_LEUART0_SHIFT;
+#else
+ ret /= CMU_Log2ToDiv((CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART0_MASK)
+ >> _CMU_LFBPRESC0_LEUART0_SHIFT);
+#endif
+ break;
+#endif
+
+#if defined(_CMU_LFBCLKEN0_LEUART1_MASK)
+ case (CMU_LEUART1_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = lfClkGet(cmuClock_LFB);
+#if defined(_SILICON_LABS_32B_SERIES_0)
+ ret >>= (CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART1_MASK)
+ >> _CMU_LFBPRESC0_LEUART1_SHIFT;
+#else
+ ret /= CMU_Log2ToDiv((CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART1_MASK)
+ >> _CMU_LFBPRESC0_LEUART1_SHIFT);
+#endif
+ break;
+#endif
+
+#if defined(_CMU_LFBCLKEN0_CSEN_MASK)
+ case (CMU_CSEN_LF_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = lfClkGet(cmuClock_LFB);
+ ret /= CMU_Log2ToDiv(((CMU->LFBPRESC0 & _CMU_LFBPRESC0_CSEN_MASK)
+ >> _CMU_LFBPRESC0_CSEN_SHIFT) + 4);
+ break;
+#endif
+
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ case (CMU_LFE_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = lfClkGet(cmuClock_LFE);
+ break;
+#endif
+
+ case (CMU_DBG_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = dbgClkGet();
+ break;
+
+ case (CMU_AUX_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = auxClkGet();
+ break;
+
+#if defined(USBC_CLOCK_PRESENT)
+ case (CMU_USBC_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = usbCClkGet();
+ break;
+#endif
+
+#if defined(_CMU_ADCCTRL_ADC0CLKSEL_MASK)
+ case (CMU_ADC0ASYNC_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = adcAsyncClkGet(0);
+#if defined(_CMU_ADCCTRL_ADC0CLKDIV_MASK)
+ ret /= 1U + ((CMU->ADCCTRL & _CMU_ADCCTRL_ADC0CLKDIV_MASK)
+ >> _CMU_ADCCTRL_ADC0CLKDIV_SHIFT);
+#endif
+ break;
+#endif
+
+#if defined(_CMU_ADCCTRL_ADC1CLKSEL_MASK)
+ case (CMU_ADC1ASYNC_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = adcAsyncClkGet(1);
+#if defined(_CMU_ADCCTRL_ADC1CLKDIV_MASK)
+ ret /= 1U + ((CMU->ADCCTRL & _CMU_ADCCTRL_ADC1CLKDIV_MASK)
+ >> _CMU_ADCCTRL_ADC1CLKDIV_SHIFT);
+#endif
+ break;
+#endif
+
+#if defined(_CMU_SDIOCTRL_SDIOCLKSEL_MASK)
+ case (CMU_SDIOREF_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = sdioRefClkGet();
+ break;
+#endif
+
+#if defined(_CMU_QSPICTRL_QSPI0CLKSEL_MASK)
+ case (CMU_QSPI0REF_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = qspiRefClkGet(0);
+ break;
+#endif
+
+#if defined(USBR_CLOCK_PRESENT)
+ case (CMU_USBR_CLK_BRANCH << CMU_CLK_BRANCH_POS):
+ ret = usbRateClkGet();
+ break;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+#if defined(_SILICON_LABS_32B_SERIES_1)
+/***************************************************************************//**
+ * @brief
+ * Get clock prescaler.
+ *
+ * @param[in] clock
+ * Clock point to get the prescaler for. Notice that not all clock points
+ * have a prescaler. Please refer to CMU overview in reference manual.
+ *
+ * @return
+ * The prescaler value of the current clock point. 0 is returned
+ * if @p clock specifies a clock point without a prescaler.
+ ******************************************************************************/
+uint32_t CMU_ClockPrescGet(CMU_Clock_TypeDef clock)
+{
+ uint32_t prescReg;
+ uint32_t ret;
+
+ /* Get prescaler register id. */
+ prescReg = (clock >> CMU_PRESC_REG_POS) & CMU_PRESC_REG_MASK;
+
+ switch (prescReg) {
+ case CMU_HFPRESC_REG:
+ ret = (CMU->HFPRESC & _CMU_HFPRESC_PRESC_MASK)
+ >> _CMU_HFPRESC_PRESC_SHIFT;
+ break;
+
+ case CMU_HFEXPPRESC_REG:
+ ret = (CMU->HFEXPPRESC & _CMU_HFEXPPRESC_PRESC_MASK)
+ >> _CMU_HFEXPPRESC_PRESC_SHIFT;
+ break;
+
+ case CMU_HFCLKLEPRESC_REG:
+ ret = (CMU->HFPRESC & _CMU_HFPRESC_HFCLKLEPRESC_MASK)
+ >> _CMU_HFPRESC_HFCLKLEPRESC_SHIFT;
+ break;
+
+ case CMU_HFPERPRESC_REG:
+ ret = (CMU->HFPERPRESC & _CMU_HFPERPRESC_PRESC_MASK)
+ >> _CMU_HFPERPRESC_PRESC_SHIFT;
+ break;
+
+ case CMU_HFCOREPRESC_REG:
+ ret = (CMU->HFCOREPRESC & _CMU_HFCOREPRESC_PRESC_MASK)
+ >> _CMU_HFCOREPRESC_PRESC_SHIFT;
+ break;
+
+ case CMU_LFAPRESC0_REG:
+ switch (clock) {
+#if defined(_CMU_LFAPRESC0_LETIMER0_MASK)
+ case cmuClock_LETIMER0:
+ ret = (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LETIMER0_MASK)
+ >> _CMU_LFAPRESC0_LETIMER0_SHIFT;
+ /* Convert the exponent to prescaler value. */
+ ret = CMU_Log2ToDiv(ret) - 1U;
+ break;
+#endif
+
+#if defined(_CMU_LFAPRESC0_LESENSE_MASK)
+ case cmuClock_LESENSE:
+ ret = (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LESENSE_MASK)
+ >> _CMU_LFAPRESC0_LESENSE_SHIFT;
+ /* Convert the exponent to prescaler value. */
+ ret = CMU_Log2ToDiv(ret) - 1U;
+ break;
+#endif
+
+#if defined(_CMU_LFAPRESC0_LETIMER1_MASK)
+ case cmuClock_LETIMER1:
+ ret = (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LETIMER1_MASK)
+ >> _CMU_LFAPRESC0_LETIMER1_SHIFT;
+ ret = CMU_Log2ToDiv(ret) - 1U;
+ break;
+#endif
+
+#if defined(_CMU_LFAPRESC0_LCD_MASK)
+ case cmuClock_LCD:
+ case cmuClock_LCDpre:
+ ret = (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LCD_MASK)
+ >> _CMU_LFAPRESC0_LCD_SHIFT;
+ ret = CMU_Log2ToDiv(ret) - 1U;
+ break;
+#endif
+
+#if defined(_CMU_LFAPRESC0_RTC_MASK)
+ case cmuClock_RTC:
+ ret = (CMU->LFAPRESC0 & _CMU_LFAPRESC0_RTC_MASK)
+ >> _CMU_LFAPRESC0_RTC_SHIFT;
+ ret = CMU_Log2ToDiv(ret) - 1U;
+ break;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ ret = 0U;
+ break;
+ }
+ break;
+
+ case CMU_LFBPRESC0_REG:
+ switch (clock) {
+#if defined(_CMU_LFBPRESC0_LEUART0_MASK)
+ case cmuClock_LEUART0:
+ ret = (CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART0_MASK)
+ >> _CMU_LFBPRESC0_LEUART0_SHIFT;
+ /* Convert the exponent to prescaler value. */
+ ret = CMU_Log2ToDiv(ret) - 1U;
+ break;
+#endif
+
+#if defined(_CMU_LFBPRESC0_LEUART1_MASK)
+ case cmuClock_LEUART1:
+ ret = (CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART1_MASK)
+ >> _CMU_LFBPRESC0_LEUART1_SHIFT;
+ /* Convert the exponent to prescaler value. */
+ ret = CMU_Log2ToDiv(ret) - 1U;
+ break;
+#endif
+
+#if defined(_CMU_LFBPRESC0_CSEN_MASK)
+ case cmuClock_CSEN_LF:
+ ret = (CMU->LFBPRESC0 & _CMU_LFBPRESC0_CSEN_MASK)
+ >> _CMU_LFBPRESC0_CSEN_SHIFT;
+ /* Convert the exponent to prescaler value. */
+ ret = CMU_Log2ToDiv(ret + 4) - 1U;
+ break;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ ret = 0U;
+ break;
+ }
+ break;
+
+ case CMU_LFEPRESC0_REG:
+ switch (clock) {
+#if defined(RTCC_PRESENT)
+ case cmuClock_RTCC:
+ /* No need to compute with LFEPRESC0_RTCC - DIV1 is the only */
+ /* allowed value. Convert the exponent to prescaler value. */
+ ret = _CMU_LFEPRESC0_RTCC_DIV1;
+ break;
+
+ default:
+ EFM_ASSERT(0);
+ ret = 0U;
+ break;
+#endif
+ }
+ break;
+
+ case CMU_ADCASYNCDIV_REG:
+ switch (clock) {
+#if defined(_CMU_ADCCTRL_ADC0CLKDIV_MASK)
+ case cmuClock_ADC0ASYNC:
+ ret = (CMU->ADCCTRL & _CMU_ADCCTRL_ADC0CLKDIV_MASK)
+ >> _CMU_ADCCTRL_ADC0CLKDIV_SHIFT;
+ break;
+#endif
+#if defined(_CMU_ADCCTRL_ADC1CLKDIV_MASK)
+ case cmuClock_ADC1ASYNC:
+ ret = (CMU->ADCCTRL & _CMU_ADCCTRL_ADC1CLKDIV_MASK)
+ >> _CMU_ADCCTRL_ADC1CLKDIV_SHIFT;
+ break;
+#endif
+ default:
+ EFM_ASSERT(0);
+ ret = 0U;
+ break;
+ }
+ break;
+
+ default:
+ EFM_ASSERT(0);
+ ret = 0U;
+ break;
+ }
+
+ return ret;
+}
+#endif
+
+#if defined(_SILICON_LABS_32B_SERIES_1)
+/***************************************************************************//**
+ * @brief
+ * Set clock prescaler.
+ *
+ * @note
+ * If setting a LF clock prescaler, synchronization into the low frequency
+ * domain is required. If the same register is modified before a previous
+ * update has completed, this function will stall until the previous
+ * synchronization has completed. Please refer to CMU_FreezeEnable() for
+ * a suggestion on how to reduce stalling time in some use cases.
+ *
+ * @param[in] clock
+ * Clock point to set prescaler for. Notice that not all clock points
+ * have a prescaler, please refer to CMU overview in the reference manual.
+ *
+ * @param[in] presc
+ * The clock prescaler to use.
+ ******************************************************************************/
+void CMU_ClockPrescSet(CMU_Clock_TypeDef clock, CMU_ClkPresc_TypeDef presc)
+{
+ uint32_t freq;
+ uint32_t prescReg;
+
+ /* Get divisor reg id */
+ prescReg = (clock >> CMU_PRESC_REG_POS) & CMU_PRESC_REG_MASK;
+
+ switch (prescReg) {
+ case CMU_HFPRESC_REG:
+ EFM_ASSERT(presc < 32U);
+
+ /* Configure worst case wait-states for flash and HFLE. */
+ flashWaitStateMax();
+ setHfLeConfig(CMU_MAX_FREQ_HFLE + 1);
+
+ CMU->HFPRESC = (CMU->HFPRESC & ~_CMU_HFPRESC_PRESC_MASK)
+ | (presc << _CMU_HFPRESC_PRESC_SHIFT);
+
+ /* Update CMSIS core clock variable (this function updates the global variable).
+ Optimize flash and HFLE wait states. */
+ freq = SystemCoreClockGet();
+ CMU_UpdateWaitStates(freq, VSCALE_DEFAULT);
+
+ setHfLeConfig(CMU_ClockFreqGet(cmuClock_HFLE));
+ break;
+
+ case CMU_HFEXPPRESC_REG:
+ EFM_ASSERT(presc < 32U);
+
+ CMU->HFEXPPRESC = (CMU->HFEXPPRESC & ~_CMU_HFEXPPRESC_PRESC_MASK)
+ | (presc << _CMU_HFEXPPRESC_PRESC_SHIFT);
+ break;
+
+ case CMU_HFCLKLEPRESC_REG:
+#if defined (CMU_HFPRESC_HFCLKLEPRESC_DIV8)
+ EFM_ASSERT(presc < 3U);
+#else
+ EFM_ASSERT(presc < 2U);
+#endif
+
+ /* Specifies the clock divider for HFCLKLE. This clock divider must be set
+ * high enough for the divided clock frequency to be at or below the max
+ * frequency allowed for the HFCLKLE clock. */
+ CMU->HFPRESC = (CMU->HFPRESC & ~_CMU_HFPRESC_HFCLKLEPRESC_MASK)
+ | (presc << _CMU_HFPRESC_HFCLKLEPRESC_SHIFT);
+ break;
+
+ case CMU_HFPERPRESC_REG:
+ EFM_ASSERT(presc < 512U);
+
+ CMU->HFPERPRESC = (CMU->HFPERPRESC & ~_CMU_HFPERPRESC_PRESC_MASK)
+ | (presc << _CMU_HFPERPRESC_PRESC_SHIFT);
+ break;
+
+ case CMU_HFCOREPRESC_REG:
+ EFM_ASSERT(presc < 512U);
+
+ /* Configure worst case wait-states for flash and HFLE. */
+ flashWaitStateMax();
+ setHfLeConfig(CMU_MAX_FREQ_HFLE + 1);
+
+ CMU->HFCOREPRESC = (CMU->HFCOREPRESC & ~_CMU_HFCOREPRESC_PRESC_MASK)
+ | (presc << _CMU_HFCOREPRESC_PRESC_SHIFT);
+
+ /* Update CMSIS core clock variable (this function updates the global variable).
+ Optimize flash and HFLE wait states. */
+ freq = SystemCoreClockGet();
+ CMU_UpdateWaitStates(freq, VSCALE_DEFAULT);
+ setHfLeConfig(CMU_ClockFreqGet(cmuClock_HFLE));
+ break;
+
+ case CMU_LFAPRESC0_REG:
+ switch (clock) {
+#if defined(RTC_PRESENT)
+ case cmuClock_RTC:
+ EFM_ASSERT(presc <= 32768U);
+
+ /* Convert prescaler value to DIV exponent scale. */
+ presc = CMU_PrescToLog2(presc);
+
+ /* LF register about to be modified require sync. Busy check. */
+ syncReg(CMU_SYNCBUSY_LFAPRESC0);
+
+ CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_RTC_MASK)
+ | (presc << _CMU_LFAPRESC0_RTC_SHIFT);
+ break;
+#endif
+
+#if defined(RTCC_PRESENT)
+ case cmuClock_RTCC:
+#if defined(_CMU_LFEPRESC0_RTCC_MASK)
+ /* DIV1 is the only accepted value. */
+ EFM_ASSERT(presc <= 0U);
+
+ /* LF register about to be modified require sync. Busy check.. */
+ syncReg(CMU_SYNCBUSY_LFEPRESC0);
+
+ CMU->LFEPRESC0 = (CMU->LFEPRESC0 & ~_CMU_LFEPRESC0_RTCC_MASK)
+ | (presc << _CMU_LFEPRESC0_RTCC_SHIFT);
+#else
+ EFM_ASSERT(presc <= 32768U);
+
+ /* Convert prescaler value to DIV exponent scale. */
+ presc = CMU_PrescToLog2(presc);
+
+ /* LF register about to be modified require sync. Busy check. */
+ syncReg(CMU_SYNCBUSY_LFAPRESC0);
+
+ CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_RTCC_MASK)
+ | (presc << _CMU_LFAPRESC0_RTCC_SHIFT);
+#endif
+ break;
+#endif
+
+#if defined(_CMU_LFAPRESC0_LETIMER0_MASK)
+ case cmuClock_LETIMER0:
+ EFM_ASSERT(presc <= 32768U);
+
+ /* Convert prescaler value to DIV exponent scale. */
+ presc = CMU_PrescToLog2(presc);
+
+ /* LF register about to be modified require sync. Busy check. */
+ syncReg(CMU_SYNCBUSY_LFAPRESC0);
+
+ CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LETIMER0_MASK)
+ | (presc << _CMU_LFAPRESC0_LETIMER0_SHIFT);
+ break;
+#endif
+
+#if defined(_CMU_LFAPRESC0_LESENSE_MASK)
+ case cmuClock_LESENSE:
+ EFM_ASSERT(presc <= 8);
+
+ /* Convert prescaler value to DIV exponent scale. */
+ presc = CMU_PrescToLog2(presc);
+
+ /* LF register about to be modified require sync. Busy check. */
+ syncReg(CMU_SYNCBUSY_LFAPRESC0);
+
+ CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LESENSE_MASK)
+ | (presc << _CMU_LFAPRESC0_LESENSE_SHIFT);
+ break;
+#endif
+
+#if defined(_CMU_LFAPRESC0_LCD_MASK)
+ case cmuClock_LCDpre:
+ case cmuClock_LCD:
+ {
+ EFM_ASSERT(presc <= 32768U);
+
+ /* Convert prescaler value to DIV exponent scale. */
+ presc = CMU_PrescToLog2(presc);
+
+ /* LF register about to be modified require sync. Busy check. */
+ syncReg(CMU_SYNCBUSY_LFAPRESC0);
+
+ CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LCD_MASK)
+ | (presc << _CMU_LFAPRESC0_LCD_SHIFT);
+ } break;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ break;
+ }
+ break;
+
+ case CMU_LFBPRESC0_REG:
+ switch (clock) {
+#if defined(_CMU_LFBPRESC0_LEUART0_MASK)
+ case cmuClock_LEUART0:
+ EFM_ASSERT(presc <= 8U);
+
+ /* Convert prescaler value to DIV exponent scale. */
+ presc = CMU_PrescToLog2(presc);
+
+ /* LF register about to be modified require sync. Busy check. */
+ syncReg(CMU_SYNCBUSY_LFBPRESC0);
+
+ CMU->LFBPRESC0 = (CMU->LFBPRESC0 & ~_CMU_LFBPRESC0_LEUART0_MASK)
+ | (presc << _CMU_LFBPRESC0_LEUART0_SHIFT);
+ break;
+#endif
+
+#if defined(_CMU_LFBPRESC0_LEUART1_MASK)
+ case cmuClock_LEUART1:
+ EFM_ASSERT(presc <= 8U);
+
+ /* Convert prescaler value to DIV exponent scale. */
+ presc = CMU_PrescToLog2(presc);
+
+ /* LF register about to be modified require sync. Busy check. */
+ syncReg(CMU_SYNCBUSY_LFBPRESC0);
+
+ CMU->LFBPRESC0 = (CMU->LFBPRESC0 & ~_CMU_LFBPRESC0_LEUART1_MASK)
+ | (presc << _CMU_LFBPRESC0_LEUART1_SHIFT);
+ break;
+#endif
+
+#if defined(_CMU_LFBPRESC0_CSEN_MASK)
+ case cmuClock_CSEN_LF:
+ EFM_ASSERT((presc <= 127U) && (presc >= 15U));
+
+ /* Convert prescaler value to DIV exponent scale.
+ * DIV16 is the lowest supported prescaler. */
+ presc = CMU_PrescToLog2(presc) - 4;
+
+ /* LF register about to be modified require sync. Busy check. */
+ syncReg(CMU_SYNCBUSY_LFBPRESC0);
+
+ CMU->LFBPRESC0 = (CMU->LFBPRESC0 & ~_CMU_LFBPRESC0_CSEN_MASK)
+ | (presc << _CMU_LFBPRESC0_CSEN_SHIFT);
+ break;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ break;
+ }
+ break;
+
+ case CMU_LFEPRESC0_REG:
+ switch (clock) {
+#if defined(_CMU_LFEPRESC0_RTCC_MASK)
+ case cmuClock_RTCC:
+ EFM_ASSERT(presc <= 0U);
+
+ /* LF register about to be modified require sync. Busy check. */
+ syncReg(CMU_SYNCBUSY_LFEPRESC0);
+
+ CMU->LFEPRESC0 = (CMU->LFEPRESC0 & ~_CMU_LFEPRESC0_RTCC_MASK)
+ | (presc << _CMU_LFEPRESC0_RTCC_SHIFT);
+ break;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ break;
+ }
+ break;
+
+ case CMU_ADCASYNCDIV_REG:
+ switch (clock) {
+#if defined(_CMU_ADCCTRL_ADC0CLKDIV_MASK)
+ case cmuClock_ADC0ASYNC:
+ EFM_ASSERT(presc <= 3);
+ CMU->ADCCTRL = (CMU->ADCCTRL & ~_CMU_ADCCTRL_ADC0CLKDIV_MASK)
+ | (presc << _CMU_ADCCTRL_ADC0CLKDIV_SHIFT);
+ break;
+#endif
+
+#if defined(_CMU_ADCCTRL_ADC1CLKDIV_MASK)
+ case cmuClock_ADC1ASYNC:
+ EFM_ASSERT(presc <= 3);
+ CMU->ADCCTRL = (CMU->ADCCTRL & ~_CMU_ADCCTRL_ADC1CLKDIV_MASK)
+ | (presc << _CMU_ADCCTRL_ADC1CLKDIV_SHIFT);
+ break;
+#endif
+ default:
+ EFM_ASSERT(0);
+ break;
+ }
+ break;
+
+ default:
+ EFM_ASSERT(0);
+ break;
+ }
+}
+#endif
+
+/***************************************************************************//**
+ * @brief
+ * Get currently selected reference clock used for a clock branch.
+ *
+ * @param[in] clock
+ * Clock branch to fetch selected ref. clock for. One of:
+ * @li #cmuClock_HF
+ * @li #cmuClock_LFA
+ * @li #cmuClock_LFB @if _CMU_LFCLKSEL_LFAE_ULFRCO
+ * @li #cmuClock_LFC
+ * @endif @if _SILICON_LABS_32B_SERIES_1
+ * @li #cmuClock_LFE
+ * @endif
+ * @li #cmuClock_DBG @if DOXYDOC_USB_PRESENT
+ * @li #cmuClock_USBC
+ * @endif
+ *
+ * @return
+ * Reference clock used for clocking selected branch, #cmuSelect_Error if
+ * invalid @p clock provided.
+ ******************************************************************************/
+CMU_Select_TypeDef CMU_ClockSelectGet(CMU_Clock_TypeDef clock)
+{
+ CMU_Select_TypeDef ret = cmuSelect_Disabled;
+ uint32_t selReg;
+
+ selReg = (clock >> CMU_SEL_REG_POS) & CMU_SEL_REG_MASK;
+
+ switch (selReg) {
+ case CMU_HFCLKSEL_REG:
+#if defined(_CMU_HFCLKSTATUS_MASK)
+ switch (CMU->HFCLKSTATUS & _CMU_HFCLKSTATUS_SELECTED_MASK) {
+ case CMU_HFCLKSTATUS_SELECTED_LFXO:
+ ret = cmuSelect_LFXO;
+ break;
+
+ case CMU_HFCLKSTATUS_SELECTED_LFRCO:
+ ret = cmuSelect_LFRCO;
+ break;
+
+ case CMU_HFCLKSTATUS_SELECTED_HFXO:
+ ret = cmuSelect_HFXO;
+ break;
+
+ default:
+ ret = cmuSelect_HFRCO;
+ break;
+ }
+#else
+ switch (CMU->STATUS
+ & (CMU_STATUS_HFRCOSEL
+ | CMU_STATUS_HFXOSEL
+ | CMU_STATUS_LFRCOSEL
+#if defined(CMU_STATUS_USHFRCODIV2SEL)
+ | CMU_STATUS_USHFRCODIV2SEL
+#endif
+ | CMU_STATUS_LFXOSEL)) {
+ case CMU_STATUS_LFXOSEL:
+ ret = cmuSelect_LFXO;
+ break;
+
+ case CMU_STATUS_LFRCOSEL:
+ ret = cmuSelect_LFRCO;
+ break;
+
+ case CMU_STATUS_HFXOSEL:
+ ret = cmuSelect_HFXO;
+ break;
+
+#if defined(CMU_STATUS_USHFRCODIV2SEL)
+ case CMU_STATUS_USHFRCODIV2SEL:
+ ret = cmuSelect_USHFRCODIV2;
+ break;
+#endif
+
+ default:
+ ret = cmuSelect_HFRCO;
+ break;
+ }
+#endif
+ break;
+
+#if defined(_CMU_LFCLKSEL_MASK) || defined(_CMU_LFACLKSEL_MASK)
+ case CMU_LFACLKSEL_REG:
+#if defined(_CMU_LFCLKSEL_MASK)
+ switch (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFA_MASK) {
+ case CMU_LFCLKSEL_LFA_LFRCO:
+ ret = cmuSelect_LFRCO;
+ break;
+
+ case CMU_LFCLKSEL_LFA_LFXO:
+ ret = cmuSelect_LFXO;
+ break;
+
+#if defined(CMU_LFCLKSEL_LFA_HFCORECLKLEDIV2)
+ case CMU_LFCLKSEL_LFA_HFCORECLKLEDIV2:
+ ret = cmuSelect_HFCLKLE;
+ break;
+#endif
+
+ default:
+#if defined(CMU_LFCLKSEL_LFAE)
+ if (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFAE_MASK) {
+ ret = cmuSelect_ULFRCO;
+ break;
+ }
+#else
+ ret = cmuSelect_Disabled;
+#endif
+ break;
+ }
+
+#elif defined(_CMU_LFACLKSEL_MASK)
+ switch (CMU->LFACLKSEL & _CMU_LFACLKSEL_LFA_MASK) {
+ case CMU_LFACLKSEL_LFA_LFRCO:
+ ret = cmuSelect_LFRCO;
+ break;
+
+ case CMU_LFACLKSEL_LFA_LFXO:
+ ret = cmuSelect_LFXO;
+ break;
+
+ case CMU_LFACLKSEL_LFA_ULFRCO:
+ ret = cmuSelect_ULFRCO;
+ break;
+
+#if defined(_CMU_LFACLKSEL_LFA_HFCLKLE)
+ case CMU_LFACLKSEL_LFA_HFCLKLE:
+ ret = cmuSelect_HFCLKLE;
+ break;
+#endif
+
+#if defined(CMU_LFACLKSEL_LFA_PLFRCO)
+ case CMU_LFACLKSEL_LFA_PLFRCO:
+ ret = cmuSelect_PLFRCO;
+ break;
+#endif
+
+ default:
+ ret = cmuSelect_Disabled;
+ break;
+ }
+#endif
+ break;
+#endif /* _CMU_LFCLKSEL_MASK || _CMU_LFACLKSEL_MASK */
+
+#if defined(_CMU_LFCLKSEL_MASK) || defined(_CMU_LFBCLKSEL_MASK)
+ case CMU_LFBCLKSEL_REG:
+#if defined(_CMU_LFCLKSEL_MASK)
+ switch (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFB_MASK) {
+ case CMU_LFCLKSEL_LFB_LFRCO:
+ ret = cmuSelect_LFRCO;
+ break;
+
+ case CMU_LFCLKSEL_LFB_LFXO:
+ ret = cmuSelect_LFXO;
+ break;
+
+#if defined(CMU_LFCLKSEL_LFB_HFCORECLKLEDIV2)
+ case CMU_LFCLKSEL_LFB_HFCORECLKLEDIV2:
+ ret = cmuSelect_HFCLKLE;
+ break;
+#endif
+
+#if defined(CMU_LFCLKSEL_LFB_HFCLKLE)
+ case CMU_LFCLKSEL_LFB_HFCLKLE:
+ ret = cmuSelect_HFCLKLE;
+ break;
+#endif
+
+ default:
+#if defined(CMU_LFCLKSEL_LFBE)
+ if (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFBE_MASK) {
+ ret = cmuSelect_ULFRCO;
+ break;
+ }
+#else
+ ret = cmuSelect_Disabled;
+#endif
+ break;
+ }
+
+#elif defined(_CMU_LFBCLKSEL_MASK)
+ switch (CMU->LFBCLKSEL & _CMU_LFBCLKSEL_LFB_MASK) {
+ case CMU_LFBCLKSEL_LFB_LFRCO:
+ ret = cmuSelect_LFRCO;
+ break;
+
+ case CMU_LFBCLKSEL_LFB_LFXO:
+ ret = cmuSelect_LFXO;
+ break;
+
+ case CMU_LFBCLKSEL_LFB_ULFRCO:
+ ret = cmuSelect_ULFRCO;
+ break;
+
+ case CMU_LFBCLKSEL_LFB_HFCLKLE:
+ ret = cmuSelect_HFCLKLE;
+ break;
+
+#if defined(CMU_LFBCLKSEL_LFB_PLFRCO)
+ case CMU_LFBCLKSEL_LFB_PLFRCO:
+ ret = cmuSelect_PLFRCO;
+ break;
+#endif
+
+ default:
+ ret = cmuSelect_Disabled;
+ break;
+ }
+#endif
+ break;
+#endif /* _CMU_LFCLKSEL_MASK || _CMU_LFBCLKSEL_MASK */
+
+#if defined(_CMU_LFCLKSEL_LFC_MASK)
+ case CMU_LFCCLKSEL_REG:
+ switch (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFC_MASK) {
+ case CMU_LFCLKSEL_LFC_LFRCO:
+ ret = cmuSelect_LFRCO;
+ break;
+
+ case CMU_LFCLKSEL_LFC_LFXO:
+ ret = cmuSelect_LFXO;
+ break;
+
+ default:
+ ret = cmuSelect_Disabled;
+ break;
+ }
+ break;
+#endif
+
+#if defined(_CMU_LFECLKSEL_LFE_MASK)
+ case CMU_LFECLKSEL_REG:
+ switch (CMU->LFECLKSEL & _CMU_LFECLKSEL_LFE_MASK) {
+ case CMU_LFECLKSEL_LFE_LFRCO:
+ ret = cmuSelect_LFRCO;
+ break;
+
+ case CMU_LFECLKSEL_LFE_LFXO:
+ ret = cmuSelect_LFXO;
+ break;
+
+ case CMU_LFECLKSEL_LFE_ULFRCO:
+ ret = cmuSelect_ULFRCO;
+ break;
+
+#if defined (_CMU_LFECLKSEL_LFE_HFCLKLE)
+ case CMU_LFECLKSEL_LFE_HFCLKLE:
+ ret = cmuSelect_HFCLKLE;
+ break;
+#endif
+
+#if defined(CMU_LFECLKSEL_LFE_PLFRCO)
+ case CMU_LFECLKSEL_LFE_PLFRCO:
+ ret = cmuSelect_PLFRCO;
+ break;
+#endif
+
+ default:
+ ret = cmuSelect_Disabled;
+ break;
+ }
+ break;
+#endif /* CMU_LFECLKSEL_REG */
+
+ case CMU_DBGCLKSEL_REG:
+#if defined(_CMU_DBGCLKSEL_DBG_MASK)
+ switch (CMU->DBGCLKSEL & _CMU_DBGCLKSEL_DBG_MASK) {
+ case CMU_DBGCLKSEL_DBG_HFCLK:
+ ret = cmuSelect_HFCLK;
+ break;
+
+ case CMU_DBGCLKSEL_DBG_AUXHFRCO:
+ ret = cmuSelect_AUXHFRCO;
+ break;
+ }
+
+#elif defined(_CMU_CTRL_DBGCLK_MASK)
+ switch (CMU->CTRL & _CMU_CTRL_DBGCLK_MASK) {
+ case CMU_CTRL_DBGCLK_AUXHFRCO:
+ ret = cmuSelect_AUXHFRCO;
+ break;
+
+ case CMU_CTRL_DBGCLK_HFCLK:
+ ret = cmuSelect_HFCLK;
+ break;
+ }
+#else
+ ret = cmuSelect_AUXHFRCO;
+#endif
+ break;
+
+#if defined(USBC_CLOCK_PRESENT)
+ case CMU_USBCCLKSEL_REG:
+ switch (CMU->STATUS
+ & (CMU_STATUS_USBCLFXOSEL
+#if defined(_CMU_STATUS_USBCHFCLKSEL_MASK)
+ | CMU_STATUS_USBCHFCLKSEL
+#endif
+#if defined(_CMU_STATUS_USBCUSHFRCOSEL_MASK)
+ | CMU_STATUS_USBCUSHFRCOSEL
+#endif
+ | CMU_STATUS_USBCLFRCOSEL)) {
+#if defined(_CMU_STATUS_USBCHFCLKSEL_MASK)
+ case CMU_STATUS_USBCHFCLKSEL:
+ ret = cmuSelect_HFCLK;
+ break;
+#endif
+
+#if defined(_CMU_STATUS_USBCUSHFRCOSEL_MASK)
+ case CMU_STATUS_USBCUSHFRCOSEL:
+ ret = cmuSelect_USHFRCO;
+ break;
+#endif
+
+ case CMU_STATUS_USBCLFXOSEL:
+ ret = cmuSelect_LFXO;
+ break;
+
+ case CMU_STATUS_USBCLFRCOSEL:
+ ret = cmuSelect_LFRCO;
+ break;
+
+ default:
+ ret = cmuSelect_Disabled;
+ break;
+ }
+ break;
+#endif
+
+#if defined(_CMU_ADCCTRL_ADC0CLKSEL_MASK)
+ case CMU_ADC0ASYNCSEL_REG:
+ switch (CMU->ADCCTRL & _CMU_ADCCTRL_ADC0CLKSEL_MASK) {
+ case CMU_ADCCTRL_ADC0CLKSEL_DISABLED:
+ ret = cmuSelect_Disabled;
+ break;
+
+ case CMU_ADCCTRL_ADC0CLKSEL_AUXHFRCO:
+ ret = cmuSelect_AUXHFRCO;
+ break;
+
+ case CMU_ADCCTRL_ADC0CLKSEL_HFXO:
+ ret = cmuSelect_HFXO;
+ break;
+
+ case CMU_ADCCTRL_ADC0CLKSEL_HFSRCCLK:
+ ret = cmuSelect_HFSRCCLK;
+ break;
+ }
+ break;
+#endif
+
+#if defined(_CMU_ADCCTRL_ADC1CLKSEL_MASK)
+ case CMU_ADC1ASYNCSEL_REG:
+ switch (CMU->ADCCTRL & _CMU_ADCCTRL_ADC1CLKSEL_MASK) {
+ case CMU_ADCCTRL_ADC1CLKSEL_DISABLED:
+ ret = cmuSelect_Disabled;
+ break;
+
+ case CMU_ADCCTRL_ADC1CLKSEL_AUXHFRCO:
+ ret = cmuSelect_AUXHFRCO;
+ break;
+
+ case CMU_ADCCTRL_ADC1CLKSEL_HFXO:
+ ret = cmuSelect_HFXO;
+ break;
+
+ case CMU_ADCCTRL_ADC1CLKSEL_HFSRCCLK:
+ ret = cmuSelect_HFSRCCLK;
+ break;
+ }
+ break;
+#endif
+
+#if defined(_CMU_SDIOCTRL_SDIOCLKSEL_MASK)
+ case CMU_SDIOREFSEL_REG:
+ switch (CMU->SDIOCTRL & _CMU_SDIOCTRL_SDIOCLKSEL_MASK) {
+ case CMU_SDIOCTRL_SDIOCLKSEL_HFRCO:
+ ret = cmuSelect_HFRCO;
+ break;
+
+ case CMU_SDIOCTRL_SDIOCLKSEL_HFXO:
+ ret = cmuSelect_HFXO;
+ break;
+
+ case CMU_SDIOCTRL_SDIOCLKSEL_AUXHFRCO:
+ ret = cmuSelect_AUXHFRCO;
+ break;
+
+ case CMU_SDIOCTRL_SDIOCLKSEL_USHFRCO:
+ ret = cmuSelect_USHFRCO;
+ break;
+ }
+ break;
+#endif
+
+#if defined(_CMU_QSPICTRL_QSPI0CLKSEL_MASK)
+ case CMU_QSPI0REFSEL_REG:
+ switch (CMU->QSPICTRL & _CMU_QSPICTRL_QSPI0CLKSEL_MASK) {
+ case CMU_QSPICTRL_QSPI0CLKSEL_HFRCO:
+ ret = cmuSelect_HFRCO;
+ break;
+
+ case CMU_QSPICTRL_QSPI0CLKSEL_HFXO:
+ ret = cmuSelect_HFXO;
+ break;
+
+ case CMU_QSPICTRL_QSPI0CLKSEL_AUXHFRCO:
+ ret = cmuSelect_AUXHFRCO;
+ break;
+
+ case CMU_QSPICTRL_QSPI0CLKSEL_USHFRCO:
+ ret = cmuSelect_USHFRCO;
+ break;
+ }
+ break;
+#endif
+
+#if defined(_CMU_USBCTRL_USBCLKSEL_MASK)
+ case CMU_USBRCLKSEL_REG:
+ switch (CMU->USBCTRL & _CMU_USBCTRL_USBCLKSEL_MASK) {
+ case CMU_USBCTRL_USBCLKSEL_USHFRCO:
+ ret = cmuSelect_USHFRCO;
+ break;
+
+ case CMU_USBCTRL_USBCLKSEL_HFXO:
+ ret = cmuSelect_HFXO;
+ break;
+
+ case CMU_USBCTRL_USBCLKSEL_HFXOX2:
+ ret = cmuSelect_HFXOX2;
+ break;
+
+ case CMU_USBCTRL_USBCLKSEL_HFRCO:
+ ret = cmuSelect_HFRCO;
+ break;
+
+ case CMU_USBCTRL_USBCLKSEL_LFXO:
+ ret = cmuSelect_LFXO;
+ break;
+
+ case CMU_USBCTRL_USBCLKSEL_LFRCO:
+ ret = cmuSelect_LFRCO;
+ break;
+ }
+ break;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ ret = cmuSelect_Error;
+ break;
+ }
+
+ return ret;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Select reference clock/oscillator used for a clock branch.
+ *
+ * @details
+ * Notice that if a selected reference is not enabled prior to selecting its
+ * use, it will be enabled, and this function will wait for the selected
+ * oscillator to be stable. It will however NOT be disabled if another
+ * reference clock is selected later.
+ *
+ * This feature is particularly important if selecting a new reference
+ * clock for the clock branch clocking the core, otherwise the system
+ * may halt.
+ *
+ * @param[in] clock
+ * Clock branch to select reference clock for. One of:
+ * @li #cmuClock_HF
+ * @li #cmuClock_LFA
+ * @li #cmuClock_LFB
+ * @if _CMU_LFCCLKEN0_MASK
+ * @li #cmuClock_LFC
+ * @endif
+ * @if _CMU_LFECLKEN0_MASK
+ * @li #cmuClock_LFE
+ * @endif
+ * @li #cmuClock_DBG
+ * @if _CMU_CMD_USBCLKSEL_MASK
+ * @li #cmuClock_USBC
+ * @endif
+ * @if _CMU_USBCTRL_MASK
+ * @li #cmuClock_USBR
+ * @endif
+ *
+ * @param[in] ref
+ * Reference selected for clocking, please refer to reference manual for
+ * for details on which reference is available for a specific clock branch.
+ * @li #cmuSelect_HFRCO
+ * @li #cmuSelect_LFRCO
+ * @li #cmuSelect_HFXO
+ * @if _CMU_HFXOCTRL_HFXOX2EN_MASK
+ * @li #cmuSelect_HFXOX2
+ * @endif
+ * @li #cmuSelect_LFXO
+ * @li #cmuSelect_HFCLKLE
+ * @li #cmuSelect_AUXHFRCO
+ * @if _CMU_USHFRCOCTRL_MASK
+ * @li #cmuSelect_USHFRCO
+ * @endif
+ * @li #cmuSelect_HFCLK
+ * @ifnot DOXYDOC_EFM32_GECKO_FAMILY
+ * @li #cmuSelect_ULFRCO
+ * @li #cmuSelect_PLFRCO
+ * @endif
+ ******************************************************************************/
+void CMU_ClockSelectSet(CMU_Clock_TypeDef clock, CMU_Select_TypeDef ref)
+{
+ uint32_t select = cmuOsc_HFRCO;
+ CMU_Osc_TypeDef osc = cmuOsc_HFRCO;
+ uint32_t freq;
+ uint32_t tmp;
+ uint32_t selRegId;
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ volatile uint32_t *selReg = NULL;
+#endif
+#if defined(CMU_LFCLKSEL_LFAE_ULFRCO)
+ uint32_t lfExtended = 0;
+#endif
+
+#if defined(_EMU_CMD_EM01VSCALE0_MASK)
+ uint32_t vScaleFrequency = 0; /* Use default */
+
+ /* Start voltage upscaling before clock is set. */
+ if (clock == cmuClock_HF) {
+ if (ref == cmuSelect_HFXO) {
+ vScaleFrequency = SystemHFXOClockGet();
+ } else if ((ref == cmuSelect_HFRCO)
+ && (CMU_HFRCOBandGet() > CMU_VSCALEEM01_LOWPOWER_VOLTAGE_CLOCK_MAX)) {
+ vScaleFrequency = CMU_HFRCOBandGet();
+ }
+ if (vScaleFrequency != 0) {
+ EMU_VScaleEM01ByClock(vScaleFrequency, false);
+ }
+ }
+#endif
+
+ selRegId = (clock >> CMU_SEL_REG_POS) & CMU_SEL_REG_MASK;
+
+ switch (selRegId) {
+ case CMU_HFCLKSEL_REG:
+ switch (ref) {
+ case cmuSelect_LFXO:
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ select = CMU_HFCLKSEL_HF_LFXO;
+#elif defined(_SILICON_LABS_32B_SERIES_0)
+ select = CMU_CMD_HFCLKSEL_LFXO;
+#endif
+ osc = cmuOsc_LFXO;
+ break;
+
+ case cmuSelect_LFRCO:
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ select = CMU_HFCLKSEL_HF_LFRCO;
+#elif defined(_SILICON_LABS_32B_SERIES_0)
+ select = CMU_CMD_HFCLKSEL_LFRCO;
+#endif
+ osc = cmuOsc_LFRCO;
+ break;
+
+ case cmuSelect_HFXO:
+#if defined(CMU_HFCLKSEL_HF_HFXO)
+ select = CMU_HFCLKSEL_HF_HFXO;
+#elif defined(CMU_CMD_HFCLKSEL_HFXO)
+ select = CMU_CMD_HFCLKSEL_HFXO;
+#endif
+ osc = cmuOsc_HFXO;
+#if defined(CMU_MAX_FREQ_HFLE)
+ /* Set 1 HFLE wait-state until the new HFCLKLE frequency is known.
+ This is known after 'select' is written below. */
+ setHfLeConfig(CMU_MAX_FREQ_HFLE + 1);
+#endif
+#if defined(CMU_CTRL_HFXOBUFCUR_BOOSTABOVE32MHZ)
+ /* Adjust HFXO buffer current for frequencies above 32MHz */
+ if (SystemHFXOClockGet() > 32000000) {
+ CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_HFXOBUFCUR_MASK)
+ | CMU_CTRL_HFXOBUFCUR_BOOSTABOVE32MHZ;
+ } else {
+ CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_HFXOBUFCUR_MASK)
+ | CMU_CTRL_HFXOBUFCUR_BOOSTUPTO32MHZ;
+ }
+#endif
+ break;
+
+ case cmuSelect_HFRCO:
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ select = CMU_HFCLKSEL_HF_HFRCO;
+#elif defined(_SILICON_LABS_32B_SERIES_0)
+ select = CMU_CMD_HFCLKSEL_HFRCO;
+#endif
+ osc = cmuOsc_HFRCO;
+#if defined(CMU_MAX_FREQ_HFLE)
+ /* Set 1 HFLE wait-state until the new HFCLKLE frequency is known.
+ This is known after 'select' is written below. */
+ setHfLeConfig(CMU_MAX_FREQ_HFLE + 1);
+#endif
+ break;
+
+#if defined(CMU_CMD_HFCLKSEL_USHFRCODIV2)
+ case cmuSelect_USHFRCODIV2:
+ select = CMU_CMD_HFCLKSEL_USHFRCODIV2;
+ osc = cmuOsc_USHFRCO;
+ break;
+#endif
+
+#if defined(CMU_LFCLKSEL_LFAE_ULFRCO) || defined(CMU_LFACLKSEL_LFA_ULFRCO)
+ case cmuSelect_ULFRCO:
+ /* ULFRCO cannot be used as HFCLK */
+ EFM_ASSERT(0);
+ return;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ return;
+ }
+
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(osc, true, true);
+
+ /* Configure worst case wait states for flash access before selecting */
+ flashWaitStateMax();
+
+#if defined(_EMU_CMD_EM01VSCALE0_MASK)
+ /* Wait for voltage upscaling to complete before clock is set. */
+ if (vScaleFrequency != 0) {
+ EMU_VScaleWait();
+ }
+#endif
+
+ /* Switch to selected oscillator */
+#if defined(_CMU_HFCLKSEL_MASK)
+ CMU->HFCLKSEL = select;
+#else
+ CMU->CMD = select;
+#endif
+#if defined(CMU_MAX_FREQ_HFLE)
+ /* Update HFLE configuration after 'select' is set.
+ Note that the HFCLKLE clock is connected differently on planform 1 and 2 */
+ setHfLeConfig(CMU_ClockFreqGet(cmuClock_HFLE));
+#endif
+
+ /* Update CMSIS core clock variable */
+ /* (The function will update the global variable) */
+ freq = SystemCoreClockGet();
+
+ /* Optimize flash access wait state setting for currently selected core clk */
+ CMU_UpdateWaitStates(freq, VSCALE_DEFAULT);
+
+#if defined(_EMU_CMD_EM01VSCALE0_MASK)
+ /* Keep EMU module informed on source HF clock frequency. This will apply voltage
+ downscaling after clock is set if downscaling is configured. */
+ if (vScaleFrequency == 0) {
+ EMU_VScaleEM01ByClock(0, true);
+ }
+#endif
+ break;
+
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ case CMU_LFACLKSEL_REG:
+ selReg = (selReg == NULL) ? &CMU->LFACLKSEL : selReg;
+#if !defined(_CMU_LFACLKSEL_LFA_HFCLKLE)
+ /* HFCLKCLE can not be used as LFACLK */
+ EFM_ASSERT(ref != cmuSelect_HFCLKLE);
+#endif
+ /* Fall through and select clock source */
+
+#if defined(_CMU_LFCCLKSEL_MASK)
+ case CMU_LFCCLKSEL_REG:
+ selReg = (selReg == NULL) ? &CMU->LFCCLKSEL : selReg;
+#if !defined(_CMU_LFCCLKSEL_LFC_HFCLKLE)
+ /* HFCLKCLE can not be used as LFCCLK */
+ EFM_ASSERT(ref != cmuSelect_HFCLKLE);
+#endif
+#endif
+ /* Fall through and select clock source */
+
+ case CMU_LFECLKSEL_REG:
+ selReg = (selReg == NULL) ? &CMU->LFECLKSEL : selReg;
+#if !defined(_CMU_LFECLKSEL_LFE_HFCLKLE)
+ /* HFCLKCLE can not be used as LFECLK */
+ EFM_ASSERT(ref != cmuSelect_HFCLKLE);
+#endif
+ /* Fall through and select clock source */
+
+ case CMU_LFBCLKSEL_REG:
+ selReg = (selReg == NULL) ? &CMU->LFBCLKSEL : selReg;
+ switch (ref) {
+ case cmuSelect_Disabled:
+ tmp = _CMU_LFACLKSEL_LFA_DISABLED;
+ break;
+
+ case cmuSelect_LFXO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
+ tmp = _CMU_LFACLKSEL_LFA_LFXO;
+ break;
+
+ case cmuSelect_LFRCO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);
+ tmp = _CMU_LFACLKSEL_LFA_LFRCO;
+ break;
+
+ case cmuSelect_HFCLKLE:
+ /* Ensure correct HFLE wait-states and enable HFCLK to LE */
+ setHfLeConfig(SystemCoreClockGet());
+ BUS_RegBitWrite(&CMU->HFBUSCLKEN0, _CMU_HFBUSCLKEN0_LE_SHIFT, 1);
+ tmp = _CMU_LFBCLKSEL_LFB_HFCLKLE;
+ break;
+
+ case cmuSelect_ULFRCO:
+ /* ULFRCO is always on, there is no need to enable it. */
+ tmp = _CMU_LFACLKSEL_LFA_ULFRCO;
+ break;
+
+#if defined(_CMU_STATUS_PLFRCOENS_MASK)
+ case cmuSelect_PLFRCO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_PLFRCO, true, true);
+ tmp = _CMU_LFACLKSEL_LFA_PLFRCO;
+ break;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ return;
+ }
+ *selReg = tmp;
+ break;
+
+#elif defined(_SILICON_LABS_32B_SERIES_0)
+ case CMU_LFACLKSEL_REG:
+ case CMU_LFBCLKSEL_REG:
+ switch (ref) {
+ case cmuSelect_Disabled:
+ tmp = _CMU_LFCLKSEL_LFA_DISABLED;
+ break;
+
+ case cmuSelect_LFXO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
+ tmp = _CMU_LFCLKSEL_LFA_LFXO;
+ break;
+
+ case cmuSelect_LFRCO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);
+ tmp = _CMU_LFCLKSEL_LFA_LFRCO;
+ break;
+
+ case cmuSelect_HFCLKLE:
+#if defined(CMU_MAX_FREQ_HFLE)
+ /* Set HFLE wait-state and divider */
+ freq = SystemCoreClockGet();
+ setHfLeConfig(freq);
+#endif
+ /* Ensure HFCORE to LE clocking is enabled */
+ BUS_RegBitWrite(&CMU->HFCORECLKEN0, _CMU_HFCORECLKEN0_LE_SHIFT, 1);
+ tmp = _CMU_LFCLKSEL_LFA_HFCORECLKLEDIV2;
+ break;
+
+#if defined(CMU_LFCLKSEL_LFAE_ULFRCO)
+ case cmuSelect_ULFRCO:
+ /* ULFRCO is always enabled */
+ tmp = _CMU_LFCLKSEL_LFA_DISABLED;
+ lfExtended = 1;
+ break;
+#endif
+
+ default:
+ /* Illegal clock source for LFA/LFB selected */
+ EFM_ASSERT(0);
+ return;
+ }
+
+ /* Apply select */
+ if (selRegId == CMU_LFACLKSEL_REG) {
+#if defined(_CMU_LFCLKSEL_LFAE_MASK)
+ CMU->LFCLKSEL = (CMU->LFCLKSEL
+ & ~(_CMU_LFCLKSEL_LFA_MASK | _CMU_LFCLKSEL_LFAE_MASK))
+ | (tmp << _CMU_LFCLKSEL_LFA_SHIFT)
+ | (lfExtended << _CMU_LFCLKSEL_LFAE_SHIFT);
+#else
+ CMU->LFCLKSEL = (CMU->LFCLKSEL & ~_CMU_LFCLKSEL_LFA_MASK)
+ | (tmp << _CMU_LFCLKSEL_LFA_SHIFT);
+#endif
+ } else {
+#if defined(_CMU_LFCLKSEL_LFBE_MASK)
+ CMU->LFCLKSEL = (CMU->LFCLKSEL
+ & ~(_CMU_LFCLKSEL_LFB_MASK | _CMU_LFCLKSEL_LFBE_MASK))
+ | (tmp << _CMU_LFCLKSEL_LFB_SHIFT)
+ | (lfExtended << _CMU_LFCLKSEL_LFBE_SHIFT);
+#else
+ CMU->LFCLKSEL = (CMU->LFCLKSEL & ~_CMU_LFCLKSEL_LFB_MASK)
+ | (tmp << _CMU_LFCLKSEL_LFB_SHIFT);
+#endif
+ }
+ break;
+
+#if defined(_CMU_LFCLKSEL_LFC_MASK)
+ case CMU_LFCCLKSEL_REG:
+ switch (ref) {
+ case cmuSelect_Disabled:
+ tmp = _CMU_LFCLKSEL_LFA_DISABLED;
+ break;
+
+ case cmuSelect_LFXO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
+ tmp = _CMU_LFCLKSEL_LFC_LFXO;
+ break;
+
+ case cmuSelect_LFRCO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);
+ tmp = _CMU_LFCLKSEL_LFC_LFRCO;
+ break;
+
+ default:
+ /* Illegal clock source for LFC selected */
+ EFM_ASSERT(0);
+ return;
+ }
+
+ /* Apply select */
+ CMU->LFCLKSEL = (CMU->LFCLKSEL & ~_CMU_LFCLKSEL_LFC_MASK)
+ | (tmp << _CMU_LFCLKSEL_LFC_SHIFT);
+ break;
+#endif
+#endif
+
+#if defined(_CMU_DBGCLKSEL_DBG_MASK) || defined(CMU_CTRL_DBGCLK)
+ case CMU_DBGCLKSEL_REG:
+ switch (ref) {
+#if defined(_CMU_DBGCLKSEL_DBG_MASK)
+ case cmuSelect_AUXHFRCO:
+ /* Select AUXHFRCO as debug clock */
+ CMU->DBGCLKSEL = CMU_DBGCLKSEL_DBG_AUXHFRCO;
+ break;
+
+ case cmuSelect_HFCLK:
+ /* Select divided HFCLK as debug clock */
+ CMU->DBGCLKSEL = CMU_DBGCLKSEL_DBG_HFCLK;
+ break;
+#endif
+
+#if defined(CMU_CTRL_DBGCLK)
+ case cmuSelect_AUXHFRCO:
+ /* Select AUXHFRCO as debug clock */
+ CMU->CTRL = (CMU->CTRL & ~(_CMU_CTRL_DBGCLK_MASK))
+ | CMU_CTRL_DBGCLK_AUXHFRCO;
+ break;
+
+ case cmuSelect_HFCLK:
+ /* Select divided HFCLK as debug clock */
+ CMU->CTRL = (CMU->CTRL & ~(_CMU_CTRL_DBGCLK_MASK))
+ | CMU_CTRL_DBGCLK_HFCLK;
+ break;
+#endif
+
+ default:
+ /* Illegal clock source for debug selected */
+ EFM_ASSERT(0);
+ return;
+ }
+ break;
+#endif
+
+#if defined(USBC_CLOCK_PRESENT)
+ case CMU_USBCCLKSEL_REG:
+ switch (ref) {
+ case cmuSelect_LFXO:
+ /* Select LFXO as clock source for USB, can only be used in sleep mode */
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
+
+ /* Switch oscillator */
+ CMU->CMD = CMU_CMD_USBCCLKSEL_LFXO;
+
+ /* Wait until clock is activated */
+ while ((CMU->STATUS & CMU_STATUS_USBCLFXOSEL) == 0) {
+ }
+ break;
+
+ case cmuSelect_LFRCO:
+ /* Select LFRCO as clock source for USB, can only be used in sleep mode */
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);
+
+ /* Switch oscillator */
+ CMU->CMD = CMU_CMD_USBCCLKSEL_LFRCO;
+
+ /* Wait until clock is activated */
+ while ((CMU->STATUS & CMU_STATUS_USBCLFRCOSEL) == 0) {
+ }
+ break;
+
+#if defined(CMU_STATUS_USBCHFCLKSEL)
+ case cmuSelect_HFCLK:
+ /* Select undivided HFCLK as clock source for USB */
+ /* Oscillator must already be enabled to avoid a core lockup */
+ CMU->CMD = CMU_CMD_USBCCLKSEL_HFCLKNODIV;
+ /* Wait until clock is activated */
+ while ((CMU->STATUS & CMU_STATUS_USBCHFCLKSEL) == 0) {
+ }
+ break;
+#endif
+
+#if defined(CMU_CMD_USBCCLKSEL_USHFRCO)
+ case cmuSelect_USHFRCO:
+ /* Select USHFRCO as clock source for USB */
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_USHFRCO, true, true);
+
+ /* Switch oscillator */
+ CMU->CMD = CMU_CMD_USBCCLKSEL_USHFRCO;
+
+ /* Wait until clock is activated */
+ while ((CMU->STATUS & CMU_STATUS_USBCUSHFRCOSEL) == 0) {
+ }
+ break;
+#endif
+
+ default:
+ /* Illegal clock source for USB */
+ EFM_ASSERT(0);
+ return;
+ }
+ break;
+#endif
+
+#if defined(_CMU_ADCCTRL_ADC0CLKSEL_MASK)
+ case CMU_ADC0ASYNCSEL_REG:
+ switch (ref) {
+ case cmuSelect_Disabled:
+ tmp = _CMU_ADCCTRL_ADC0CLKSEL_DISABLED;
+ break;
+
+ case cmuSelect_AUXHFRCO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_AUXHFRCO, true, true);
+ tmp = _CMU_ADCCTRL_ADC0CLKSEL_AUXHFRCO;
+ break;
+
+ case cmuSelect_HFXO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
+ tmp = _CMU_ADCCTRL_ADC0CLKSEL_HFXO;
+ break;
+
+ case cmuSelect_HFSRCCLK:
+ tmp = _CMU_ADCCTRL_ADC0CLKSEL_HFSRCCLK;
+ break;
+
+ default:
+ /* Illegal clock source for ADC0ASYNC selected */
+ EFM_ASSERT(0);
+ return;
+ }
+
+ /* Apply select */
+ CMU->ADCCTRL = (CMU->ADCCTRL & ~_CMU_ADCCTRL_ADC0CLKSEL_MASK)
+ | (tmp << _CMU_ADCCTRL_ADC0CLKSEL_SHIFT);
+ break;
+#endif
+
+#if defined(_CMU_ADCCTRL_ADC1CLKSEL_MASK)
+ case CMU_ADC1ASYNCSEL_REG:
+ switch (ref) {
+ case cmuSelect_Disabled:
+ tmp = _CMU_ADCCTRL_ADC1CLKSEL_DISABLED;
+ break;
+
+ case cmuSelect_AUXHFRCO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_AUXHFRCO, true, true);
+ tmp = _CMU_ADCCTRL_ADC1CLKSEL_AUXHFRCO;
+ break;
+
+ case cmuSelect_HFXO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
+ tmp = _CMU_ADCCTRL_ADC1CLKSEL_HFXO;
+ break;
+
+ case cmuSelect_HFSRCCLK:
+ tmp = _CMU_ADCCTRL_ADC1CLKSEL_HFSRCCLK;
+ break;
+
+ default:
+ /* Illegal clock source for ADC1ASYNC selected */
+ EFM_ASSERT(0);
+ return;
+ }
+
+ /* Apply select */
+ CMU->ADCCTRL = (CMU->ADCCTRL & ~_CMU_ADCCTRL_ADC1CLKSEL_MASK)
+ | (tmp << _CMU_ADCCTRL_ADC1CLKSEL_SHIFT);
+ break;
+#endif
+
+#if defined(_CMU_SDIOCTRL_SDIOCLKSEL_MASK)
+ case CMU_SDIOREFSEL_REG:
+ switch (ref) {
+ case cmuSelect_HFRCO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_HFRCO, true, true);
+ tmp = _CMU_SDIOCTRL_SDIOCLKSEL_HFRCO;
+ break;
+
+ case cmuSelect_HFXO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
+ tmp = _CMU_SDIOCTRL_SDIOCLKSEL_HFXO;
+ break;
+
+ case cmuSelect_AUXHFRCO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_AUXHFRCO, true, true);
+ tmp = _CMU_SDIOCTRL_SDIOCLKSEL_AUXHFRCO;
+ break;
+
+ case cmuSelect_USHFRCO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_USHFRCO, true, true);
+ tmp = _CMU_SDIOCTRL_SDIOCLKSEL_USHFRCO;
+ break;
+
+ default:
+ /* Illegal clock source for SDIOREF selected */
+ EFM_ASSERT(0);
+ return;
+ }
+
+ /* Apply select */
+ CMU->SDIOCTRL = (CMU->SDIOCTRL & ~_CMU_SDIOCTRL_SDIOCLKSEL_MASK)
+ | (tmp << _CMU_SDIOCTRL_SDIOCLKSEL_SHIFT);
+ break;
+#endif
+
+#if defined(_CMU_QSPICTRL_QSPI0CLKSEL_MASK)
+ case CMU_QSPI0REFSEL_REG:
+ switch (ref) {
+ case cmuSelect_HFRCO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_HFRCO, true, true);
+ tmp = _CMU_QSPICTRL_QSPI0CLKSEL_HFRCO;
+ break;
+
+ case cmuSelect_HFXO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
+ tmp = _CMU_QSPICTRL_QSPI0CLKSEL_HFXO;
+ break;
+
+ case cmuSelect_AUXHFRCO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_AUXHFRCO, true, true);
+ tmp = _CMU_QSPICTRL_QSPI0CLKSEL_AUXHFRCO;
+ break;
+
+ case cmuSelect_USHFRCO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_USHFRCO, true, true);
+ tmp = _CMU_QSPICTRL_QSPI0CLKSEL_USHFRCO;
+ break;
+
+ default:
+ /* Illegal clock source for QSPI0REF selected */
+ EFM_ASSERT(0);
+ return;
+ }
+
+ /* Apply select */
+ CMU->QSPICTRL = (CMU->QSPICTRL & ~_CMU_QSPICTRL_QSPI0CLKSEL_MASK)
+ | (tmp << _CMU_QSPICTRL_QSPI0CLKSEL_SHIFT);
+ break;
+#endif
+
+#if defined(_CMU_USBCTRL_USBCLKSEL_MASK)
+ case CMU_USBRCLKSEL_REG:
+ switch (ref) {
+ case cmuSelect_USHFRCO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_USHFRCO, true, true);
+ tmp = _CMU_USBCTRL_USBCLKSEL_USHFRCO;
+ break;
+
+ case cmuSelect_HFXO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
+ tmp = _CMU_USBCTRL_USBCLKSEL_HFXO;
+ break;
+
+ case cmuSelect_HFXOX2:
+ /* Only allowed for HFXO frequencies up to 25 MHz */
+ EFM_ASSERT(SystemHFXOClockGet() <= 25000000u);
+
+ /* Enable HFXO X2 */
+ CMU->HFXOCTRL |= CMU_HFXOCTRL_HFXOX2EN;
+
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
+
+ tmp = _CMU_USBCTRL_USBCLKSEL_HFXOX2;
+ break;
+
+ case cmuSelect_HFRCO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_HFRCO, true, true);
+ tmp = _CMU_USBCTRL_USBCLKSEL_HFRCO;
+ break;
+
+ case cmuSelect_LFXO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
+ tmp = _CMU_USBCTRL_USBCLKSEL_LFXO;
+ break;
+
+ case cmuSelect_LFRCO:
+ /* Ensure selected oscillator is enabled, waiting for it to stabilize */
+ CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);
+ tmp = _CMU_USBCTRL_USBCLKSEL_LFRCO;
+ break;
+
+ default:
+ /* Illegal clock source for USBR selected */
+ EFM_ASSERT(0);
+ return;
+ }
+
+ /* Apply select */
+ CMU->USBCTRL = (CMU->USBCTRL & ~_CMU_USBCTRL_USBCLKSEL_MASK)
+ | (tmp << _CMU_USBCTRL_USBCLKSEL_SHIFT);
+ break;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ break;
+ }
+}
+
+#if defined(CMU_OSCENCMD_DPLLEN)
+/**************************************************************************//**
+ * @brief
+ * Lock the DPLL to a given frequency.
+ *
+ * The frequency is given by: Fout = Fref * (N+1) / (M+1).
+ *
+ * @note
+ * This function does not check if the given N & M values will actually
+ * produce the desired target frequency.
+ * Any peripheral running off HFRCO should be switched to HFRCODIV2 prior to
+ * calling this function to avoid over-clocking.
+ *
+ * @param[in] init
+ * DPLL setup parameters.
+ *
+ * @return
+ * Returns false on invalid target frequency or DPLL locking error.
+ *****************************************************************************/
+bool CMU_DPLLLock(CMU_DPLLInit_TypeDef *init)
+{
+ int index = 0;
+ unsigned int i;
+ bool hfrcoDiv2 = false;
+ uint32_t hfrcoCtrlVal, lockStatus, sysFreq;
+
+ EFM_ASSERT(init->frequency >= hfrcoCtrlTable[0].minFreq);
+ EFM_ASSERT(init->frequency
+ <= hfrcoCtrlTable[HFRCOCTRLTABLE_ENTRIES - 1].maxFreq);
+ EFM_ASSERT(init->n >= 32);
+ EFM_ASSERT(init->n <= (_CMU_DPLLCTRL1_N_MASK >> _CMU_DPLLCTRL1_N_SHIFT));
+ EFM_ASSERT(init->m <= (_CMU_DPLLCTRL1_M_MASK >> _CMU_DPLLCTRL1_M_SHIFT));
+ EFM_ASSERT(init->ssInterval <= (_CMU_HFRCOSS_SSINV_MASK
+ >> _CMU_HFRCOSS_SSINV_SHIFT));
+ EFM_ASSERT(init->ssAmplitude <= (_CMU_HFRCOSS_SSAMP_MASK
+ >> _CMU_HFRCOSS_SSAMP_SHIFT));
+
+#if defined(_EMU_STATUS_VSCALE_MASK)
+ if ((EMU_VScaleGet() == emuVScaleEM01_LowPower)
+ && (init->frequency > CMU_VSCALEEM01_LOWPOWER_VOLTAGE_CLOCK_MAX)) {
+ EFM_ASSERT(false);
+ return false;
+ }
+#endif
+
+ // Find correct HFRCO band, and retrieve a HFRCOCTRL value.
+ for (i = 0; i < HFRCOCTRLTABLE_ENTRIES; i++) {
+ if ((init->frequency >= hfrcoCtrlTable[i].minFreq)
+ && (init->frequency <= hfrcoCtrlTable[i].maxFreq)) {
+ index = i; // Correct band found
+ break;
+ }
+ }
+ if (index == HFRCOCTRLTABLE_ENTRIES) {
+ EFM_ASSERT(false);
+ return false; // Target frequency out of spec.
+ }
+ hfrcoCtrlVal = hfrcoCtrlTable[index].value;
+
+ // Check if we have a calibrated HFRCOCTRL.TUNING value in device DI page.
+ if (hfrcoCtrlTable[index].band != (CMU_HFRCOFreq_TypeDef)0) {
+ uint32_t tuning;
+
+ tuning = (CMU_HFRCODevinfoGet(hfrcoCtrlTable[index].band)
+ & _CMU_HFRCOCTRL_TUNING_MASK)
+ >> _CMU_HFRCOCTRL_TUNING_SHIFT;
+
+ // When HFRCOCTRL.FINETUNINGEN is enabled, the center frequency
+ // of the band shifts down by 5.8%. We subtract 9 to compensate.
+ if (tuning > 9) {
+ tuning -= 9;
+ } else {
+ tuning = 0;
+ }
+
+ hfrcoCtrlVal |= tuning << _CMU_HFRCOCTRL_TUNING_SHIFT;
+ }
+
+ // Update CMSIS frequency SystemHfrcoFreq value.
+ SystemHfrcoFreq = init->frequency;
+
+ // Set max wait-states while changing core clock.
+ if (CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCO) {
+ flashWaitStateMax();
+ }
+
+ // Update HFLE configuration before updating HFRCO, use new DPLL frequency.
+ if (CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCO) {
+ setHfLeConfig(init->frequency);
+
+ // Switch to HFRCO/2 before setting DPLL to avoid over-clocking.
+ hfrcoDiv2 = (CMU->HFCLKSTATUS & _CMU_HFCLKSTATUS_SELECTED_MASK)
+ == CMU_HFCLKSTATUS_SELECTED_HFRCODIV2;
+ CMU->HFCLKSEL = CMU_HFCLKSEL_HF_HFRCODIV2;
+ }
+
+ CMU->OSCENCMD = CMU_OSCENCMD_DPLLDIS;
+ while ((CMU->STATUS & (CMU_STATUS_DPLLENS | CMU_STATUS_DPLLRDY)) != 0) ;
+ CMU->IFC = CMU_IFC_DPLLRDY | CMU_IFC_DPLLLOCKFAILLOW
+ | CMU_IFC_DPLLLOCKFAILHIGH;
+ CMU->DPLLCTRL1 = (init->n << _CMU_DPLLCTRL1_N_SHIFT)
+ | (init->m << _CMU_DPLLCTRL1_M_SHIFT);
+ CMU->HFRCOCTRL = hfrcoCtrlVal;
+ CMU->DPLLCTRL = (init->refClk << _CMU_DPLLCTRL_REFSEL_SHIFT)
+ | (init->autoRecover << _CMU_DPLLCTRL_AUTORECOVER_SHIFT)
+ | (init->edgeSel << _CMU_DPLLCTRL_EDGESEL_SHIFT)
+ | (init->lockMode << _CMU_DPLLCTRL_MODE_SHIFT);
+ CMU->OSCENCMD = CMU_OSCENCMD_DPLLEN;
+ while ((lockStatus = (CMU->IF & (CMU_IF_DPLLRDY
+ | CMU_IF_DPLLLOCKFAILLOW
+ | CMU_IF_DPLLLOCKFAILHIGH))) == 0) ;
+
+ if ((CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCO)
+ && (hfrcoDiv2 == false)) {
+ CMU->HFCLKSEL = CMU_HFCLKSEL_HF_HFRCO;
+ }
+
+ // If HFRCO is selected as HF clock, optimize flash access wait-state
+ // configuration for this frequency and update CMSIS core clock variable.
+ if (CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCO) {
+ // Call SystemCoreClockGet() to update CMSIS core clock variable.
+ sysFreq = SystemCoreClockGet();
+ EFM_ASSERT(sysFreq <= init->frequency);
+ EFM_ASSERT(sysFreq <= SystemHfrcoFreq);
+ EFM_ASSERT(init->frequency == SystemHfrcoFreq);
+ CMU_UpdateWaitStates(sysFreq, VSCALE_DEFAULT);
+ }
+
+ // Reduce HFLE frequency if possible.
+ setHfLeConfig(CMU_ClockFreqGet(cmuClock_HFLE));
+
+#if defined(_EMU_CMD_EM01VSCALE0_MASK)
+ // Update voltage scaling.
+ EMU_VScaleEM01ByClock(0, true);
+#endif
+
+ if (lockStatus == CMU_IF_DPLLRDY) {
+ return true;
+ }
+ return false;
+}
+#endif // CMU_OSCENCMD_DPLLEN
+
+/**************************************************************************//**
+ * @brief
+ * CMU low frequency register synchronization freeze control.
+ *
+ * @details
+ * Some CMU registers requires synchronization into the low frequency (LF)
+ * domain. The freeze feature allows for several such registers to be
+ * modified before passing them to the LF domain simultaneously (which
+ * takes place when the freeze mode is disabled).
+ *
+ * Another usage scenario of this feature, is when using an API (such
+ * as the CMU API) for modifying several bit fields consecutively in the
+ * same register. If freeze mode is enabled during this sequence, stalling
+ * can be avoided.
+ *
+ * @note
+ * When enabling freeze mode, this function will wait for all current
+ * ongoing CMU synchronization to LF domain to complete (Normally
+ * synchronization will not be in progress.) However for this reason, when
+ * using freeze mode, modifications of registers requiring LF synchronization
+ * should be done within one freeze enable/disable block to avoid unecessary
+ * stalling.
+ *
+ * @param[in] enable
+ * @li true - enable freeze, modified registers are not propagated to the
+ * LF domain
+ * @li false - disable freeze, modified registers are propagated to LF
+ * domain
+ *****************************************************************************/
+void CMU_FreezeEnable(bool enable)
+{
+ if (enable) {
+ /* Wait for any ongoing LF synchronization to complete. This is just to */
+ /* protect against the rare case when a user */
+ /* - modifies a register requiring LF sync */
+ /* - then enables freeze before LF sync completed */
+ /* - then modifies the same register again */
+ /* since modifying a register while it is in sync progress should be */
+ /* avoided. */
+ while (CMU->SYNCBUSY) {
+ }
+
+ CMU->FREEZE = CMU_FREEZE_REGFREEZE;
+ } else {
+ CMU->FREEZE = 0;
+ }
+}
+
+#if defined(_CMU_HFRCOCTRL_BAND_MASK)
+/***************************************************************************//**
+ * @brief
+ * Get HFRCO band in use.
+ *
+ * @return
+ * HFRCO band in use.
+ ******************************************************************************/
+CMU_HFRCOBand_TypeDef CMU_HFRCOBandGet(void)
+{
+ return (CMU_HFRCOBand_TypeDef)((CMU->HFRCOCTRL & _CMU_HFRCOCTRL_BAND_MASK)
+ >> _CMU_HFRCOCTRL_BAND_SHIFT);
+}
+#endif /* _CMU_HFRCOCTRL_BAND_MASK */
+
+#if defined(_CMU_HFRCOCTRL_BAND_MASK)
+/***************************************************************************//**
+ * @brief
+ * Set HFRCO band and the tuning value based on the value in the calibration
+ * table made during production.
+ *
+ * @param[in] band
+ * HFRCO band to activate.
+ ******************************************************************************/
+void CMU_HFRCOBandSet(CMU_HFRCOBand_TypeDef band)
+{
+ uint32_t tuning;
+ uint32_t freq;
+ CMU_Select_TypeDef osc;
+
+ /* Read tuning value from calibration table */
+ switch (band) {
+ case cmuHFRCOBand_1MHz:
+ tuning = (DEVINFO->HFRCOCAL0 & _DEVINFO_HFRCOCAL0_BAND1_MASK)
+ >> _DEVINFO_HFRCOCAL0_BAND1_SHIFT;
+ break;
+
+ case cmuHFRCOBand_7MHz:
+ tuning = (DEVINFO->HFRCOCAL0 & _DEVINFO_HFRCOCAL0_BAND7_MASK)
+ >> _DEVINFO_HFRCOCAL0_BAND7_SHIFT;
+ break;
+
+ case cmuHFRCOBand_11MHz:
+ tuning = (DEVINFO->HFRCOCAL0 & _DEVINFO_HFRCOCAL0_BAND11_MASK)
+ >> _DEVINFO_HFRCOCAL0_BAND11_SHIFT;
+ break;
+
+ case cmuHFRCOBand_14MHz:
+ tuning = (DEVINFO->HFRCOCAL0 & _DEVINFO_HFRCOCAL0_BAND14_MASK)
+ >> _DEVINFO_HFRCOCAL0_BAND14_SHIFT;
+ break;
+
+ case cmuHFRCOBand_21MHz:
+ tuning = (DEVINFO->HFRCOCAL1 & _DEVINFO_HFRCOCAL1_BAND21_MASK)
+ >> _DEVINFO_HFRCOCAL1_BAND21_SHIFT;
+ break;
+
+#if defined(_CMU_HFRCOCTRL_BAND_28MHZ)
+ case cmuHFRCOBand_28MHz:
+ tuning = (DEVINFO->HFRCOCAL1 & _DEVINFO_HFRCOCAL1_BAND28_MASK)
+ >> _DEVINFO_HFRCOCAL1_BAND28_SHIFT;
+ break;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ return;
+ }
+
+ /* If HFRCO is used for core clock, we have to consider flash access WS. */
+ osc = CMU_ClockSelectGet(cmuClock_HF);
+ if (osc == cmuSelect_HFRCO) {
+ /* Configure worst case wait states for flash access before setting divider */
+ flashWaitStateMax();
+ }
+
+ /* Set band/tuning */
+ CMU->HFRCOCTRL = (CMU->HFRCOCTRL
+ & ~(_CMU_HFRCOCTRL_BAND_MASK | _CMU_HFRCOCTRL_TUNING_MASK))
+ | (band << _CMU_HFRCOCTRL_BAND_SHIFT)
+ | (tuning << _CMU_HFRCOCTRL_TUNING_SHIFT);
+
+ /* If HFRCO is used for core clock, optimize flash WS */
+ if (osc == cmuSelect_HFRCO) {
+ /* Call SystemCoreClockGet() to update CMSIS core clock variable. */
+ freq = SystemCoreClockGet();
+ CMU_UpdateWaitStates(freq, VSCALE_DEFAULT);
+ }
+
+#if defined(CMU_MAX_FREQ_HFLE)
+ /* Reduce HFLE frequency if possible. */
+ setHfLeConfig(CMU_ClockFreqGet(cmuClock_HFLE));
+#endif
+}
+#endif /* _CMU_HFRCOCTRL_BAND_MASK */
+
+#if defined(_CMU_HFRCOCTRL_FREQRANGE_MASK)
+/**************************************************************************//**
+ * @brief
+ * Get the HFRCO frequency calibration word in DEVINFO
+ *
+ * @param[in] freq
+ * Frequency in Hz
+ *
+ * @return
+ * HFRCO calibration word for a given frequency
+ *****************************************************************************/
+static uint32_t CMU_HFRCODevinfoGet(CMU_HFRCOFreq_TypeDef freq)
+{
+ switch (freq) {
+ /* 1, 2 and 4MHz share the same calibration word */
+ case cmuHFRCOFreq_1M0Hz:
+ case cmuHFRCOFreq_2M0Hz:
+ case cmuHFRCOFreq_4M0Hz:
+ return DEVINFO->HFRCOCAL0;
+
+ case cmuHFRCOFreq_7M0Hz:
+ return DEVINFO->HFRCOCAL3;
+
+ case cmuHFRCOFreq_13M0Hz:
+ return DEVINFO->HFRCOCAL6;
+
+ case cmuHFRCOFreq_16M0Hz:
+ return DEVINFO->HFRCOCAL7;
+
+ case cmuHFRCOFreq_19M0Hz:
+ return DEVINFO->HFRCOCAL8;
+
+ case cmuHFRCOFreq_26M0Hz:
+ return DEVINFO->HFRCOCAL10;
+
+ case cmuHFRCOFreq_32M0Hz:
+ return DEVINFO->HFRCOCAL11;
+
+ case cmuHFRCOFreq_38M0Hz:
+ return DEVINFO->HFRCOCAL12;
+
+#if defined(_DEVINFO_HFRCOCAL16_MASK)
+ case cmuHFRCOFreq_48M0Hz:
+ return DEVINFO->HFRCOCAL13;
+
+ case cmuHFRCOFreq_56M0Hz:
+ return DEVINFO->HFRCOCAL14;
+
+ case cmuHFRCOFreq_64M0Hz:
+ return DEVINFO->HFRCOCAL15;
+
+ case cmuHFRCOFreq_72M0Hz:
+ return DEVINFO->HFRCOCAL16;
+#endif
+
+ default: /* cmuHFRCOFreq_UserDefined */
+ return 0;
+ }
+}
+
+/***************************************************************************//**
+ * @brief
+ * Get current HFRCO frequency.
+ *
+ * @return
+ * HFRCO frequency
+ ******************************************************************************/
+CMU_HFRCOFreq_TypeDef CMU_HFRCOBandGet(void)
+{
+ return (CMU_HFRCOFreq_TypeDef)SystemHfrcoFreq;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Set HFRCO calibration for the selected target frequency.
+ *
+ * @param[in] setFreq
+ * HFRCO frequency to set
+ ******************************************************************************/
+void CMU_HFRCOBandSet(CMU_HFRCOFreq_TypeDef setFreq)
+{
+ uint32_t freqCal;
+ uint32_t sysFreq;
+ uint32_t prevFreq;
+
+ /* Get DEVINFO index, set CMSIS frequency SystemHfrcoFreq */
+ freqCal = CMU_HFRCODevinfoGet(setFreq);
+ EFM_ASSERT((freqCal != 0) && (freqCal != UINT_MAX));
+ prevFreq = SystemHfrcoFreq;
+ SystemHfrcoFreq = (uint32_t)setFreq;
+
+ /* Set max wait-states while changing core clock */
+ if (CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCO) {
+ flashWaitStateMax();
+ }
+
+ /* Wait for any previous sync to complete, and then set calibration data
+ for the selected frequency. */
+ while (BUS_RegBitRead(&CMU->SYNCBUSY, _CMU_SYNCBUSY_HFRCOBSY_SHIFT)) ;
+
+ /* Check for valid calibration data */
+ EFM_ASSERT(freqCal != UINT_MAX);
+
+ /* Set divider in HFRCOCTRL for 1, 2 and 4MHz */
+ switch (setFreq) {
+ case cmuHFRCOFreq_1M0Hz:
+ freqCal = (freqCal & ~_CMU_HFRCOCTRL_CLKDIV_MASK)
+ | CMU_HFRCOCTRL_CLKDIV_DIV4;
+ break;
+
+ case cmuHFRCOFreq_2M0Hz:
+ freqCal = (freqCal & ~_CMU_HFRCOCTRL_CLKDIV_MASK)
+ | CMU_HFRCOCTRL_CLKDIV_DIV2;
+ break;
+
+ case cmuHFRCOFreq_4M0Hz:
+ freqCal = (freqCal & ~_CMU_HFRCOCTRL_CLKDIV_MASK)
+ | CMU_HFRCOCTRL_CLKDIV_DIV1;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Update HFLE configuration before updating HFRCO.
+ Use the new set frequency. */
+ if (CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCO) {
+ /* setFreq is worst-case as dividers may reduce the HFLE frequency. */
+ setHfLeConfig(setFreq);
+ }
+
+ if (setFreq > prevFreq) {
+#if defined(_EMU_CMD_EM01VSCALE0_MASK)
+ /* When increasing frequency we need to voltage scale before the change */
+ EMU_VScaleEM01ByClock(setFreq, true);
+#endif
+ }
+
+ CMU->HFRCOCTRL = freqCal;
+
+ /* If HFRCO is selected as HF clock, optimize flash access wait-state configuration
+ for this frequency and update CMSIS core clock variable. */
+ if (CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCO) {
+ /* Call SystemCoreClockGet() to update CMSIS core clock variable. */
+ sysFreq = SystemCoreClockGet();
+ EFM_ASSERT(sysFreq <= (uint32_t)setFreq);
+ EFM_ASSERT(sysFreq <= SystemHfrcoFreq);
+ EFM_ASSERT(setFreq == SystemHfrcoFreq);
+ CMU_UpdateWaitStates(sysFreq, VSCALE_DEFAULT);
+ }
+
+ /* Reduce HFLE frequency if possible. */
+ setHfLeConfig(CMU_ClockFreqGet(cmuClock_HFLE));
+
+ if (setFreq <= prevFreq) {
+#if defined(_EMU_CMD_EM01VSCALE0_MASK)
+ /* When decreasing frequency we need to voltage scale after the change */
+ EMU_VScaleEM01ByClock(0, true);
+#endif
+ }
+}
+#endif /* _CMU_HFRCOCTRL_FREQRANGE_MASK */
+
+#if defined(_CMU_HFRCOCTRL_SUDELAY_MASK)
+/***************************************************************************//**
+ * @brief
+ * Get the HFRCO startup delay.
+ *
+ * @details
+ * Please refer to the reference manual for further details.
+ *
+ * @return
+ * The startup delay in use.
+ ******************************************************************************/
+uint32_t CMU_HFRCOStartupDelayGet(void)
+{
+ return (CMU->HFRCOCTRL & _CMU_HFRCOCTRL_SUDELAY_MASK)
+ >> _CMU_HFRCOCTRL_SUDELAY_SHIFT;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Set the HFRCO startup delay.
+ *
+ * @details
+ * Please refer to the reference manual for further details.
+ *
+ * @param[in] delay
+ * The startup delay to set (<= 31).
+ ******************************************************************************/
+void CMU_HFRCOStartupDelaySet(uint32_t delay)
+{
+ EFM_ASSERT(delay <= 31);
+
+ delay &= _CMU_HFRCOCTRL_SUDELAY_MASK >> _CMU_HFRCOCTRL_SUDELAY_SHIFT;
+ CMU->HFRCOCTRL = (CMU->HFRCOCTRL & ~(_CMU_HFRCOCTRL_SUDELAY_MASK))
+ | (delay << _CMU_HFRCOCTRL_SUDELAY_SHIFT);
+}
+#endif
+
+#if defined(_CMU_USHFRCOCTRL_FREQRANGE_MASK)
+/**************************************************************************//**
+ * @brief
+ * Get the USHFRCO frequency calibration word in DEVINFO
+ *
+ * @param[in] freq
+ * Frequency in Hz
+ *
+ * @return
+ * USHFRCO calibration word for a given frequency
+ *****************************************************************************/
+static uint32_t CMU_USHFRCODevinfoGet(CMU_USHFRCOFreq_TypeDef freq)
+{
+ switch (freq) {
+ case cmuUSHFRCOFreq_16M0Hz:
+ return DEVINFO->USHFRCOCAL7;
+
+ case cmuUSHFRCOFreq_32M0Hz:
+ return DEVINFO->USHFRCOCAL11;
+
+ case cmuUSHFRCOFreq_48M0Hz:
+ return DEVINFO->USHFRCOCAL13;
+
+ case cmuUSHFRCOFreq_50M0Hz:
+ return DEVINFO->USHFRCOCAL14;
+
+ default: /* cmuUSHFRCOFreq_UserDefined */
+ return 0;
+ }
+}
+
+/***************************************************************************//**
+ * @brief
+ * Get current USHFRCO frequency.
+ *
+ * @return
+ * HFRCO frequency
+ ******************************************************************************/
+CMU_USHFRCOFreq_TypeDef CMU_USHFRCOBandGet(void)
+{
+ return (CMU_USHFRCOFreq_TypeDef) ushfrcoFreq;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Set USHFRCO calibration for the selected target frequency.
+ *
+ * @param[in] setFreq
+ * USHFRCO frequency to set
+ ******************************************************************************/
+void CMU_USHFRCOBandSet(CMU_USHFRCOFreq_TypeDef setFreq)
+{
+ uint32_t freqCal;
+
+ /* Get DEVINFO calibration values */
+ freqCal = CMU_USHFRCODevinfoGet(setFreq);
+ EFM_ASSERT((freqCal != 0) && (freqCal != UINT_MAX));
+ ushfrcoFreq = (uint32_t)setFreq;
+
+ /* Wait for any previous sync to complete, and then set calibration data
+ for the selected frequency. */
+ while (BUS_RegBitRead(&CMU->SYNCBUSY, _CMU_SYNCBUSY_USHFRCOBSY_SHIFT)) ;
+
+ CMU->USHFRCOCTRL = freqCal;
+}
+#endif /* _CMU_USHFRCOCTRL_FREQRANGE_MASK */
+
+#if defined(_CMU_HFXOCTRL_AUTOSTARTEM0EM1_MASK)
+/***************************************************************************//**
+ * @brief
+ * Enable or disable HFXO autostart
+ *
+ * @param[in] userSel
+ * Additional user specified enable bit.
+ *
+ * @param[in] enEM0EM1Start
+ * If true, HFXO is automatically started upon entering EM0/EM1 entry from
+ * EM2/EM3. HFXO selection has to be handled by the user.
+ * If false, HFXO is not started automatically when entering EM0/EM1.
+ *
+ * @param[in] enEM0EM1StartSel
+ * If true, HFXO is automatically started and immediately selected upon
+ * entering EM0/EM1 entry from EM2/EM3. Note that this option stalls the use of
+ * HFSRCCLK until HFXO becomes ready.
+ * If false, HFXO is not started or selected automatically when entering
+ * EM0/EM1.
+ ******************************************************************************/
+void CMU_HFXOAutostartEnable(uint32_t userSel,
+ bool enEM0EM1Start,
+ bool enEM0EM1StartSel)
+{
+ uint32_t hfxoFreq;
+ uint32_t hfxoCtrl;
+
+ /* Mask supported enable bits. */
+#if defined(_CMU_HFXOCTRL_AUTOSTARTRDYSELRAC_MASK)
+ userSel &= _CMU_HFXOCTRL_AUTOSTARTRDYSELRAC_MASK;
+#else
+ userSel = 0;
+#endif
+
+ hfxoCtrl = CMU->HFXOCTRL & ~(userSel
+ | _CMU_HFXOCTRL_AUTOSTARTEM0EM1_MASK
+ | _CMU_HFXOCTRL_AUTOSTARTSELEM0EM1_MASK);
+
+ hfxoCtrl |= userSel
+ | (enEM0EM1Start ? CMU_HFXOCTRL_AUTOSTARTEM0EM1 : 0)
+ | (enEM0EM1StartSel ? CMU_HFXOCTRL_AUTOSTARTSELEM0EM1 : 0);
+
+ /* Set wait-states for HFXO if automatic start and select is configured. */
+ if (userSel || enEM0EM1StartSel) {
+ hfxoFreq = SystemHFXOClockGet();
+ CMU_UpdateWaitStates(hfxoFreq, VSCALE_DEFAULT);
+ setHfLeConfig(hfxoFreq);
+ }
+
+ /* Update HFXOCTRL after wait-states are updated as HF may automatically switch
+ to HFXO when automatic select is enabled . */
+ CMU->HFXOCTRL = hfxoCtrl;
+}
+#endif
+
+/**************************************************************************//**
+ * @brief
+ * Set HFXO control registers
+ *
+ * @note
+ * HFXO configuration should be obtained from a configuration tool,
+ * app note or xtal datasheet. This function disables the HFXO to ensure
+ * a valid state before update.
+ *
+ * @param[in] hfxoInit
+ * HFXO setup parameters
+ *****************************************************************************/
+void CMU_HFXOInit(const CMU_HFXOInit_TypeDef *hfxoInit)
+{
+ /* Do not disable HFXO if it is currently selected as HF/Core clock */
+ EFM_ASSERT(CMU_ClockSelectGet(cmuClock_HF) != cmuSelect_HFXO);
+
+ /* HFXO must be disabled before reconfiguration */
+ CMU_OscillatorEnable(cmuOsc_HFXO, false, true);
+
+#if defined(_SILICON_LABS_32B_SERIES_1) && (_SILICON_LABS_GECKO_INTERNAL_SDID >= 100)
+ uint32_t tmp = CMU_HFXOCTRL_MODE_XTAL;
+
+ switch (hfxoInit->mode) {
+ case cmuOscMode_Crystal:
+ tmp = CMU_HFXOCTRL_MODE_XTAL;
+ break;
+ case cmuOscMode_External:
+ tmp = CMU_HFXOCTRL_MODE_DIGEXTCLK;
+ break;
+ case cmuOscMode_AcCoupled:
+ tmp = CMU_HFXOCTRL_MODE_ACBUFEXTCLK;
+ break;
+ default:
+ EFM_ASSERT(false); /* Unsupported configuration */
+ }
+
+ /* HFXO Doubler can only be enabled on crystals up to max 25 MHz */
+ if (SystemHFXOClockGet() <= 25000000) {
+ tmp |= CMU_HFXOCTRL_HFXOX2EN;
+ }
+
+ CMU->HFXOCTRL = (CMU->HFXOCTRL & ~(_CMU_HFXOCTRL_MODE_MASK
+ | _CMU_HFXOCTRL_HFXOX2EN_MASK))
+ | tmp;
+
+ /* Set tuning for startup and steady state */
+ CMU->HFXOSTARTUPCTRL = (hfxoInit->ctuneStartup << _CMU_HFXOSTARTUPCTRL_CTUNE_SHIFT)
+ | (hfxoInit->xoCoreBiasTrimStartup << _CMU_HFXOSTARTUPCTRL_IBTRIMXOCORE_SHIFT);
+
+ CMU->HFXOSTEADYSTATECTRL = (CMU->HFXOSTEADYSTATECTRL & ~(_CMU_HFXOSTEADYSTATECTRL_CTUNE_MASK
+ | _CMU_HFXOSTEADYSTATECTRL_IBTRIMXOCORE_MASK))
+ | (hfxoInit->ctuneSteadyState << _CMU_HFXOSTEADYSTATECTRL_CTUNE_SHIFT)
+ | (hfxoInit->xoCoreBiasTrimSteadyState << _CMU_HFXOSTEADYSTATECTRL_IBTRIMXOCORE_SHIFT);
+
+ /* Set timeouts */
+ CMU->HFXOTIMEOUTCTRL = (hfxoInit->timeoutPeakDetect << _CMU_HFXOTIMEOUTCTRL_PEAKDETTIMEOUT_SHIFT)
+ | (hfxoInit->timeoutSteady << _CMU_HFXOTIMEOUTCTRL_STEADYTIMEOUT_SHIFT)
+ | (hfxoInit->timeoutStartup << _CMU_HFXOTIMEOUTCTRL_STARTUPTIMEOUT_SHIFT);
+
+#elif defined(_CMU_HFXOCTRL_MASK)
+ /* Verify that the deprecated autostart fields are not used,
+ * @ref CMU_HFXOAutostartEnable must be used instead. */
+ EFM_ASSERT(!(hfxoInit->autoStartEm01
+ || hfxoInit->autoSelEm01
+ || hfxoInit->autoStartSelOnRacWakeup));
+
+ uint32_t tmp = CMU_HFXOCTRL_MODE_XTAL;
+
+ /* AC coupled external clock not supported */
+ EFM_ASSERT(hfxoInit->mode != cmuOscMode_AcCoupled);
+ if (hfxoInit->mode == cmuOscMode_External) {
+ tmp = CMU_HFXOCTRL_MODE_DIGEXTCLK;
+ }
+
+ /* Apply control settings */
+ CMU->HFXOCTRL = (CMU->HFXOCTRL & ~_CMU_HFXOCTRL_MODE_MASK)
+ | tmp;
+ BUS_RegBitWrite(&CMU->HFXOCTRL, _CMU_HFXOCTRL_LOWPOWER_SHIFT, hfxoInit->lowPowerMode);
+
+ /* Set XTAL tuning parameters */
+
+#if defined(_CMU_HFXOCTRL1_PEAKDETTHR_MASK)
+ /* Set peak detection threshold */
+ CMU->HFXOCTRL1 = (CMU->HFXOCTRL1 & ~_CMU_HFXOCTRL1_PEAKDETTHR_MASK)
+ | (hfxoInit->thresholdPeakDetect << _CMU_HFXOCTRL1_PEAKDETTHR_SHIFT);
+#endif
+ /* Set tuning for startup and steady state */
+ CMU->HFXOSTARTUPCTRL = (hfxoInit->ctuneStartup << _CMU_HFXOSTARTUPCTRL_CTUNE_SHIFT)
+ | (hfxoInit->xoCoreBiasTrimStartup << _CMU_HFXOSTARTUPCTRL_IBTRIMXOCORE_SHIFT);
+
+ CMU->HFXOSTEADYSTATECTRL = (CMU->HFXOSTEADYSTATECTRL & ~(_CMU_HFXOSTEADYSTATECTRL_CTUNE_MASK
+ | _CMU_HFXOSTEADYSTATECTRL_IBTRIMXOCORE_MASK
+ | _CMU_HFXOSTEADYSTATECTRL_REGISH_MASK
+ | _CMU_HFXOSTEADYSTATECTRL_REGISHUPPER_MASK))
+ | (hfxoInit->ctuneSteadyState << _CMU_HFXOSTEADYSTATECTRL_CTUNE_SHIFT)
+ | (hfxoInit->xoCoreBiasTrimSteadyState << _CMU_HFXOSTEADYSTATECTRL_IBTRIMXOCORE_SHIFT)
+ | (hfxoInit->regIshSteadyState << _CMU_HFXOSTEADYSTATECTRL_REGISH_SHIFT)
+ | getRegIshUpperVal(hfxoInit->regIshSteadyState);
+
+ /* Set timeouts */
+ CMU->HFXOTIMEOUTCTRL = (hfxoInit->timeoutPeakDetect << _CMU_HFXOTIMEOUTCTRL_PEAKDETTIMEOUT_SHIFT)
+ | (hfxoInit->timeoutSteady << _CMU_HFXOTIMEOUTCTRL_STEADYTIMEOUT_SHIFT)
+ | (hfxoInit->timeoutStartup << _CMU_HFXOTIMEOUTCTRL_STARTUPTIMEOUT_SHIFT)
+ | (hfxoInit->timeoutShuntOptimization << _CMU_HFXOTIMEOUTCTRL_SHUNTOPTTIMEOUT_SHIFT);
+
+#else
+ CMU->CTRL = (CMU->CTRL & ~(_CMU_CTRL_HFXOTIMEOUT_MASK
+ | _CMU_CTRL_HFXOBOOST_MASK
+ | _CMU_CTRL_HFXOMODE_MASK
+ | _CMU_CTRL_HFXOGLITCHDETEN_MASK))
+ | (hfxoInit->timeout << _CMU_CTRL_HFXOTIMEOUT_SHIFT)
+ | (hfxoInit->boost << _CMU_CTRL_HFXOBOOST_SHIFT)
+ | (hfxoInit->mode << _CMU_CTRL_HFXOMODE_SHIFT)
+ | (hfxoInit->glitchDetector ? CMU_CTRL_HFXOGLITCHDETEN : 0);
+#endif
+}
+
+/***************************************************************************//**
+ * @brief
+ * Get the LCD framerate divisor (FDIV) setting.
+ *
+ * @return
+ * The LCD framerate divisor.
+ ******************************************************************************/
+uint32_t CMU_LCDClkFDIVGet(void)
+{
+#if defined(LCD_PRESENT) && defined(_CMU_LCDCTRL_MASK)
+ return (CMU->LCDCTRL & _CMU_LCDCTRL_FDIV_MASK) >> _CMU_LCDCTRL_FDIV_SHIFT;
+#else
+ return 0;
+#endif /* defined(LCD_PRESENT) */
+}
+
+/***************************************************************************//**
+ * @brief
+ * Set the LCD framerate divisor (FDIV) setting.
+ *
+ * @note
+ * The FDIV field (CMU LCDCTRL register) should only be modified while the
+ * LCD module is clock disabled (CMU LFACLKEN0.LCD bit is 0). This function
+ * will NOT modify FDIV if the LCD module clock is enabled. Please refer to
+ * CMU_ClockEnable() for disabling/enabling LCD clock.
+ *
+ * @param[in] div
+ * The FDIV setting to use.
+ ******************************************************************************/
+void CMU_LCDClkFDIVSet(uint32_t div)
+{
+#if defined(LCD_PRESENT) && defined(_CMU_LCDCTRL_MASK)
+ EFM_ASSERT(div <= cmuClkDiv_128);
+
+ /* Do not allow modification if LCD clock enabled */
+ if (CMU->LFACLKEN0 & CMU_LFACLKEN0_LCD) {
+ return;
+ }
+
+ div <<= _CMU_LCDCTRL_FDIV_SHIFT;
+ div &= _CMU_LCDCTRL_FDIV_MASK;
+ CMU->LCDCTRL = (CMU->LCDCTRL & ~_CMU_LCDCTRL_FDIV_MASK) | div;
+#else
+ (void)div; /* Unused parameter */
+#endif /* defined(LCD_PRESENT) */
+}
+
+/**************************************************************************//**
+ * @brief
+ * Set LFXO control registers
+ *
+ * @note
+ * LFXO configuration should be obtained from a configuration tool,
+ * app note or xtal datasheet. This function disables the LFXO to ensure
+ * a valid state before update.
+ *
+ * @param[in] lfxoInit
+ * LFXO setup parameters
+ *****************************************************************************/
+void CMU_LFXOInit(const CMU_LFXOInit_TypeDef *lfxoInit)
+{
+ /* Do not disable LFXO if it is currently selected as HF/Core clock */
+ EFM_ASSERT(CMU_ClockSelectGet(cmuClock_HF) != cmuSelect_LFXO);
+
+ /* LFXO must be disabled before reconfiguration */
+ CMU_OscillatorEnable(cmuOsc_LFXO, false, false);
+
+#if defined(_CMU_LFXOCTRL_MASK)
+ BUS_RegMaskedWrite(&CMU->LFXOCTRL,
+ _CMU_LFXOCTRL_TUNING_MASK
+ | _CMU_LFXOCTRL_GAIN_MASK
+ | _CMU_LFXOCTRL_TIMEOUT_MASK
+ | _CMU_LFXOCTRL_MODE_MASK,
+ (lfxoInit->ctune << _CMU_LFXOCTRL_TUNING_SHIFT)
+ | (lfxoInit->gain << _CMU_LFXOCTRL_GAIN_SHIFT)
+ | (lfxoInit->timeout << _CMU_LFXOCTRL_TIMEOUT_SHIFT)
+ | (lfxoInit->mode << _CMU_LFXOCTRL_MODE_SHIFT));
+#else
+ bool cmuBoost = (lfxoInit->boost & 0x2);
+ BUS_RegMaskedWrite(&CMU->CTRL,
+ _CMU_CTRL_LFXOTIMEOUT_MASK
+ | _CMU_CTRL_LFXOBOOST_MASK
+ | _CMU_CTRL_LFXOMODE_MASK,
+ (lfxoInit->timeout << _CMU_CTRL_LFXOTIMEOUT_SHIFT)
+ | ((cmuBoost ? 1 : 0) << _CMU_CTRL_LFXOBOOST_SHIFT)
+ | (lfxoInit->mode << _CMU_CTRL_LFXOMODE_SHIFT));
+#endif
+
+#if defined(_EMU_AUXCTRL_REDLFXOBOOST_MASK)
+ bool emuReduce = (lfxoInit->boost & 0x1);
+ BUS_RegBitWrite(&EMU->AUXCTRL, _EMU_AUXCTRL_REDLFXOBOOST_SHIFT, emuReduce ? 1 : 0);
+#endif
+}
+
+/***************************************************************************//**
+ * @brief
+ * Enable/disable oscillator.
+ *
+ * @note
+ * WARNING: When this function is called to disable either cmuOsc_LFXO or
+ * cmuOsc_HFXO the LFXOMODE or HFXOMODE fields of the CMU_CTRL register
+ * are reset to the reset value. I.e. if external clock sources are selected
+ * in either LFXOMODE or HFXOMODE fields, the configuration will be cleared
+ * and needs to be reconfigured if needed later.
+ *
+ * @param[in] osc
+ * The oscillator to enable/disable.
+ *
+ * @param[in] enable
+ * @li true - enable specified oscillator.
+ * @li false - disable specified oscillator.
+ *
+ * @param[in] wait
+ * Only used if @p enable is true.
+ * @li true - wait for oscillator start-up time to timeout before returning.
+ * @li false - do not wait for oscillator start-up time to timeout before
+ * returning.
+ ******************************************************************************/
+void CMU_OscillatorEnable(CMU_Osc_TypeDef osc, bool enable, bool wait)
+{
+ uint32_t rdyBitPos;
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ uint32_t ensBitPos;
+#endif
+#if defined(_CMU_STATUS_HFXOPEAKDETRDY_MASK)
+ uint32_t hfxoTrimStatus;
+#endif
+
+ uint32_t enBit;
+ uint32_t disBit;
+
+ switch (osc) {
+ case cmuOsc_HFRCO:
+ enBit = CMU_OSCENCMD_HFRCOEN;
+ disBit = CMU_OSCENCMD_HFRCODIS;
+ rdyBitPos = _CMU_STATUS_HFRCORDY_SHIFT;
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ ensBitPos = _CMU_STATUS_HFRCOENS_SHIFT;
+#endif
+ break;
+
+ case cmuOsc_HFXO:
+ enBit = CMU_OSCENCMD_HFXOEN;
+ disBit = CMU_OSCENCMD_HFXODIS;
+ rdyBitPos = _CMU_STATUS_HFXORDY_SHIFT;
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ ensBitPos = _CMU_STATUS_HFXOENS_SHIFT;
+#endif
+ break;
+
+ case cmuOsc_AUXHFRCO:
+ enBit = CMU_OSCENCMD_AUXHFRCOEN;
+ disBit = CMU_OSCENCMD_AUXHFRCODIS;
+ rdyBitPos = _CMU_STATUS_AUXHFRCORDY_SHIFT;
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ ensBitPos = _CMU_STATUS_AUXHFRCOENS_SHIFT;
+#endif
+ break;
+
+ case cmuOsc_LFRCO:
+ enBit = CMU_OSCENCMD_LFRCOEN;
+ disBit = CMU_OSCENCMD_LFRCODIS;
+ rdyBitPos = _CMU_STATUS_LFRCORDY_SHIFT;
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ ensBitPos = _CMU_STATUS_LFRCOENS_SHIFT;
+#endif
+ break;
+
+ case cmuOsc_LFXO:
+ enBit = CMU_OSCENCMD_LFXOEN;
+ disBit = CMU_OSCENCMD_LFXODIS;
+ rdyBitPos = _CMU_STATUS_LFXORDY_SHIFT;
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ ensBitPos = _CMU_STATUS_LFXOENS_SHIFT;
+#endif
+ break;
+
+#if defined(_CMU_STATUS_USHFRCOENS_MASK)
+ case cmuOsc_USHFRCO:
+ enBit = CMU_OSCENCMD_USHFRCOEN;
+ disBit = CMU_OSCENCMD_USHFRCODIS;
+ rdyBitPos = _CMU_STATUS_USHFRCORDY_SHIFT;
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ ensBitPos = _CMU_STATUS_USHFRCOENS_SHIFT;
+#endif
+ break;
+#endif
+
+#if defined(_CMU_STATUS_PLFRCOENS_MASK)
+ case cmuOsc_PLFRCO:
+ enBit = CMU_OSCENCMD_PLFRCOEN;
+ disBit = CMU_OSCENCMD_PLFRCODIS;
+ rdyBitPos = _CMU_STATUS_PLFRCORDY_SHIFT;
+ ensBitPos = _CMU_STATUS_PLFRCOENS_SHIFT;
+ break;
+#endif
+
+ default:
+ /* Undefined clock source or cmuOsc_ULFRCO. ULFRCO is always enabled,
+ and cannot be disabled. Ie. the definition of cmuOsc_ULFRCO is primarely
+ intended for information: the ULFRCO is always on. */
+ EFM_ASSERT(0);
+ return;
+ }
+
+ if (enable) {
+ #if defined(_CMU_HFXOCTRL_MASK)
+ bool firstHfxoEnable = false;
+
+ /* Enabling the HFXO for the first time requires special handling. We use the
+ * PEAKDETSHUTOPTMODE field of the HFXOCTRL register to see if this is the
+ * first time the HFXO is enabled. */
+ if ((osc == cmuOsc_HFXO) && (getHfxoTuningMode() == HFXO_TUNING_MODE_AUTO)) {
+ /* REGPWRSEL must be set to DVDD before the HFXO can be enabled. */
+#if defined(_EMU_PWRCTRL_REGPWRSEL_MASK)
+ EFM_ASSERT(EMU->PWRCTRL & EMU_PWRCTRL_REGPWRSEL_DVDD);
+#endif
+
+ firstHfxoEnable = true;
+ /* First time we enable an external clock we should switch to CMD mode to make sure that
+ * we only do SCO and not PDA tuning. */
+ if ((CMU->HFXOCTRL & (_CMU_HFXOCTRL_MODE_MASK)) == CMU_HFXOCTRL_MODE_DIGEXTCLK) {
+ setHfxoTuningMode(HFXO_TUNING_MODE_CMD);
+ }
+ }
+#endif
+ CMU->OSCENCMD = enBit;
+
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ /* Always wait for ENS to go high */
+ while (!BUS_RegBitRead(&CMU->STATUS, ensBitPos)) {
+ }
+#endif
+
+ /* Wait for clock to become ready after enable */
+ if (wait) {
+ while (!BUS_RegBitRead(&CMU->STATUS, rdyBitPos)) ;
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ if ((osc == cmuOsc_HFXO) && firstHfxoEnable) {
+ if ((CMU->HFXOCTRL & _CMU_HFXOCTRL_MODE_MASK) == CMU_HFXOCTRL_MODE_DIGEXTCLK) {
+#if defined(CMU_CMD_HFXOSHUNTOPTSTART)
+ /* External clock mode should only do shunt current optimization. */
+ CMU_OscillatorTuningOptimize(cmuOsc_HFXO, cmuHFXOTuningMode_ShuntCommand, true);
+#endif
+ } else {
+ /* Wait for peak detection and shunt current optimization to complete. */
+ CMU_OscillatorTuningWait(cmuOsc_HFXO, cmuHFXOTuningMode_Auto);
+ }
+
+ /* Disable the HFXO again to apply the trims. Apply trim from HFXOTRIMSTATUS
+ when disabled. */
+ hfxoTrimStatus = CMU_OscillatorTuningGet(cmuOsc_HFXO);
+ CMU_OscillatorEnable(cmuOsc_HFXO, false, true);
+ CMU_OscillatorTuningSet(cmuOsc_HFXO, hfxoTrimStatus);
+
+ /* Restart in CMD mode. */
+ CMU->OSCENCMD = enBit;
+ while (!BUS_RegBitRead(&CMU->STATUS, rdyBitPos)) ;
+ }
+#endif
+ }
+ } else {
+ CMU->OSCENCMD = disBit;
+
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ /* Always wait for ENS to go low */
+ while (BUS_RegBitRead(&CMU->STATUS, ensBitPos)) {
+ }
+#endif
+ }
+}
+
+/***************************************************************************//**
+ * @brief
+ * Get oscillator frequency tuning setting.
+ *
+ * @param[in] osc
+ * Oscillator to get tuning value for, one of:
+ * @li #cmuOsc_LFRCO
+ * @li #cmuOsc_HFRCO @if _CMU_USHFRCOCTRL_TUNING_MASK
+ * @li #cmuOsc_USHFRCO
+ * @endif
+ * @li #cmuOsc_AUXHFRCO
+ * @li #cmuOsc_HFXO if CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE is defined
+ *
+ * @return
+ * The oscillator frequency tuning setting in use.
+ ******************************************************************************/
+uint32_t CMU_OscillatorTuningGet(CMU_Osc_TypeDef osc)
+{
+ uint32_t ret;
+
+ switch (osc) {
+ case cmuOsc_LFRCO:
+ ret = (CMU->LFRCOCTRL & _CMU_LFRCOCTRL_TUNING_MASK)
+ >> _CMU_LFRCOCTRL_TUNING_SHIFT;
+ break;
+
+ case cmuOsc_HFRCO:
+ ret = (CMU->HFRCOCTRL & _CMU_HFRCOCTRL_TUNING_MASK)
+ >> _CMU_HFRCOCTRL_TUNING_SHIFT;
+ break;
+
+#if defined (_CMU_USHFRCOCTRL_TUNING_MASK)
+ case cmuOsc_USHFRCO:
+ ret = (CMU->USHFRCOCTRL & _CMU_USHFRCOCTRL_TUNING_MASK)
+ >> _CMU_USHFRCOCTRL_TUNING_SHIFT;
+ break;
+#endif
+
+ case cmuOsc_AUXHFRCO:
+ ret = (CMU->AUXHFRCOCTRL & _CMU_AUXHFRCOCTRL_TUNING_MASK)
+ >> _CMU_AUXHFRCOCTRL_TUNING_SHIFT;
+ break;
+
+#if defined(_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK)
+ case cmuOsc_HFXO:
+ ret = CMU->HFXOTRIMSTATUS & (_CMU_HFXOTRIMSTATUS_IBTRIMXOCORE_MASK
+#if defined(_CMU_HFXOTRIMSTATUS_REGISH_MASK)
+ | _CMU_HFXOTRIMSTATUS_REGISH_MASK
+#endif
+ );
+ break;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Set the oscillator frequency tuning control.
+ *
+ * @note
+ * Oscillator tuning is done during production, and the tuning value is
+ * automatically loaded after a reset. Changing the tuning value from the
+ * calibrated value is for more advanced use. Certain oscillators also have
+ * build-in tuning optimization.
+ *
+ * @param[in] osc
+ * Oscillator to set tuning value for, one of:
+ * @li #cmuOsc_LFRCO
+ * @li #cmuOsc_HFRCO @if _CMU_USHFRCOCTRL_TUNING_MASK
+ * @li #cmuOsc_USHFRCO
+ * @endif
+ * @li #cmuOsc_AUXHFRCO
+ * @li #cmuOsc_HFXO if PEAKDETSHUNTOPTMODE is available. Note that CMD mode is set.
+ *
+ * @param[in] val
+ * The oscillator frequency tuning setting to use.
+ ******************************************************************************/
+void CMU_OscillatorTuningSet(CMU_Osc_TypeDef osc, uint32_t val)
+{
+#if defined(_CMU_HFXOSTEADYSTATECTRL_REGISH_MASK)
+ uint32_t regIshUpper;
+#endif
+
+ switch (osc) {
+ case cmuOsc_LFRCO:
+ EFM_ASSERT(val <= (_CMU_LFRCOCTRL_TUNING_MASK
+ >> _CMU_LFRCOCTRL_TUNING_SHIFT));
+ val &= (_CMU_LFRCOCTRL_TUNING_MASK >> _CMU_LFRCOCTRL_TUNING_SHIFT);
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ while (BUS_RegBitRead(&CMU->SYNCBUSY, _CMU_SYNCBUSY_LFRCOBSY_SHIFT)) ;
+#endif
+ CMU->LFRCOCTRL = (CMU->LFRCOCTRL & ~(_CMU_LFRCOCTRL_TUNING_MASK))
+ | (val << _CMU_LFRCOCTRL_TUNING_SHIFT);
+ break;
+
+ case cmuOsc_HFRCO:
+ EFM_ASSERT(val <= (_CMU_HFRCOCTRL_TUNING_MASK
+ >> _CMU_HFRCOCTRL_TUNING_SHIFT));
+ val &= (_CMU_HFRCOCTRL_TUNING_MASK >> _CMU_HFRCOCTRL_TUNING_SHIFT);
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ while (BUS_RegBitRead(&CMU->SYNCBUSY, _CMU_SYNCBUSY_HFRCOBSY_SHIFT)) {
+ }
+#endif
+ CMU->HFRCOCTRL = (CMU->HFRCOCTRL & ~(_CMU_HFRCOCTRL_TUNING_MASK))
+ | (val << _CMU_HFRCOCTRL_TUNING_SHIFT);
+ break;
+
+#if defined (_CMU_USHFRCOCTRL_TUNING_MASK)
+ case cmuOsc_USHFRCO:
+ EFM_ASSERT(val <= (_CMU_USHFRCOCTRL_TUNING_MASK
+ >> _CMU_USHFRCOCTRL_TUNING_SHIFT));
+ val &= (_CMU_USHFRCOCTRL_TUNING_MASK >> _CMU_USHFRCOCTRL_TUNING_SHIFT);
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ while (BUS_RegBitRead(&CMU->SYNCBUSY, _CMU_SYNCBUSY_USHFRCOBSY_SHIFT)) {
+ }
+#endif
+ CMU->USHFRCOCTRL = (CMU->USHFRCOCTRL & ~(_CMU_USHFRCOCTRL_TUNING_MASK))
+ | (val << _CMU_USHFRCOCTRL_TUNING_SHIFT);
+ break;
+#endif
+
+ case cmuOsc_AUXHFRCO:
+ EFM_ASSERT(val <= (_CMU_AUXHFRCOCTRL_TUNING_MASK
+ >> _CMU_AUXHFRCOCTRL_TUNING_SHIFT));
+ val &= (_CMU_AUXHFRCOCTRL_TUNING_MASK >> _CMU_AUXHFRCOCTRL_TUNING_SHIFT);
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ while (BUS_RegBitRead(&CMU->SYNCBUSY, _CMU_SYNCBUSY_AUXHFRCOBSY_SHIFT)) {
+ }
+#endif
+ CMU->AUXHFRCOCTRL = (CMU->AUXHFRCOCTRL & ~(_CMU_AUXHFRCOCTRL_TUNING_MASK))
+ | (val << _CMU_AUXHFRCOCTRL_TUNING_SHIFT);
+ break;
+
+#if defined(_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK)
+ case cmuOsc_HFXO:
+
+ /* Do set PEAKDETSHUNTOPTMODE or HFXOSTEADYSTATECTRL if HFXO is enabled */
+ EFM_ASSERT(!(CMU->STATUS & CMU_STATUS_HFXOENS));
+
+ /* Switch to command mode. Automatic SCO and PDA calibration is not done
+ at the next enable. Set user REGISH, REGISHUPPER and IBTRIMXOCORE. */
+ CMU->HFXOCTRL = (CMU->HFXOCTRL & ~_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK)
+ | CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_CMD;
+
+#if defined(_CMU_HFXOSTEADYSTATECTRL_REGISH_MASK)
+ regIshUpper = getRegIshUpperVal((val & _CMU_HFXOSTEADYSTATECTRL_REGISH_MASK)
+ >> _CMU_HFXOSTEADYSTATECTRL_REGISH_SHIFT);
+ CMU->HFXOSTEADYSTATECTRL = (CMU->HFXOSTEADYSTATECTRL
+ & ~(_CMU_HFXOSTEADYSTATECTRL_IBTRIMXOCORE_MASK
+ | _CMU_HFXOSTEADYSTATECTRL_REGISH_MASK
+ | _CMU_HFXOSTEADYSTATECTRL_REGISHUPPER_MASK))
+ | val
+ | regIshUpper;
+#else
+ CMU->HFXOSTEADYSTATECTRL = (CMU->HFXOSTEADYSTATECTRL
+ & ~_CMU_HFXOSTEADYSTATECTRL_IBTRIMXOCORE_MASK)
+ | val;
+#endif
+
+ break;
+#endif
+
+ default:
+ EFM_ASSERT(0);
+ break;
+ }
+}
+
+#if defined(_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK) || defined(_CMU_HFXOCTRL_PEAKDETMODE_MASK)
+/***************************************************************************//**
+ * @brief
+ * Wait for oscillator tuning optimization.
+ *
+ * @param[in] osc
+ * Oscillator to set tuning value for, one of:
+ * @li #cmuOsc_HFXO
+ *
+ * @param[in] mode
+ * Tuning optimization mode.
+ *
+ * @return
+ * Returns false on invalid parameters or oscillator error status.
+ ******************************************************************************/
+bool CMU_OscillatorTuningWait(CMU_Osc_TypeDef osc,
+ CMU_HFXOTuningMode_TypeDef mode)
+{
+ uint32_t waitFlags;
+ EFM_ASSERT(osc == cmuOsc_HFXO);
+
+ /* Currently implemented for HFXO with PEAKDETSHUNTOPTMODE only */
+ (void)osc;
+
+ if (getHfxoTuningMode() == HFXO_TUNING_MODE_AUTO) {
+ waitFlags = HFXO_TUNING_READY_FLAGS;
+ } else {
+ /* Set wait flags for each command and wait */
+ switch (mode) {
+#if defined(_CMU_STATUS_HFXOSHUNTOPTRDY_MASK)
+ case cmuHFXOTuningMode_ShuntCommand:
+ waitFlags = CMU_STATUS_HFXOSHUNTOPTRDY;
+ break;
+#endif
+ case cmuHFXOTuningMode_Auto:
+ waitFlags = HFXO_TUNING_READY_FLAGS;
+ break;
+
+#if defined(CMU_CMD_HFXOSHUNTOPTSTART)
+ case cmuHFXOTuningMode_PeakShuntCommand:
+ waitFlags = HFXO_TUNING_READY_FLAGS;
+ break;
+#endif
+
+ default:
+ waitFlags = _CMU_STATUS_MASK;
+ EFM_ASSERT(false);
+ }
+ }
+ while ((CMU->STATUS & waitFlags) != waitFlags) ;
+
+#if defined(CMU_IF_HFXOPEAKDETERR)
+ /* Check error flags */
+ if (waitFlags & CMU_STATUS_HFXOPEAKDETRDY) {
+ return (CMU->IF & CMU_IF_HFXOPEAKDETERR ? true : false);
+ }
+#endif
+ return true;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Start and optionally wait for oscillator tuning optimization.
+ *
+ * @param[in] osc
+ * Oscillator to set tuning value for, one of:
+ * @li #cmuOsc_HFXO
+ *
+ * @param[in] mode
+ * Tuning optimization mode.
+ *
+ * @param[in] wait
+ * Wait for tuning optimization to complete.
+ * true - wait for tuning optimization to complete.
+ * false - return without waiting.
+ *
+ * @return
+ * Returns false on invalid parameters or oscillator error status.
+ ******************************************************************************/
+bool CMU_OscillatorTuningOptimize(CMU_Osc_TypeDef osc,
+ CMU_HFXOTuningMode_TypeDef mode,
+ bool wait)
+{
+ switch (osc) {
+ case cmuOsc_HFXO:
+ if (mode) {
+#if defined(CMU_IF_HFXOPEAKDETERR)
+ /* Clear error flag before command write */
+ CMU->IFC = CMU_IFC_HFXOPEAKDETERR;
+#endif
+ CMU->CMD = mode;
+ }
+ if (wait) {
+ return CMU_OscillatorTuningWait(osc, mode);
+ }
+ break;
+
+ default:
+ EFM_ASSERT(false);
+ }
+ return true;
+}
+#endif
+
+/**************************************************************************//**
+ * @brief
+ * Determine if currently selected PCNTn clock used is external or LFBCLK.
+ *
+ * @param[in] instance
+ * PCNT instance number to get currently selected clock source for.
+ *
+ * @return
+ * @li true - selected clock is external clock.
+ * @li false - selected clock is LFBCLK.
+ *****************************************************************************/
+bool CMU_PCNTClockExternalGet(unsigned int instance)
+{
+ uint32_t setting;
+
+ switch (instance) {
+#if defined(_CMU_PCNTCTRL_PCNT0CLKEN_MASK)
+ case 0:
+ setting = CMU->PCNTCTRL & CMU_PCNTCTRL_PCNT0CLKSEL_PCNT0S0;
+ break;
+
+#if defined(_CMU_PCNTCTRL_PCNT1CLKEN_MASK)
+ case 1:
+ setting = CMU->PCNTCTRL & CMU_PCNTCTRL_PCNT1CLKSEL_PCNT1S0;
+ break;
+
+#if defined(_CMU_PCNTCTRL_PCNT2CLKEN_MASK)
+ case 2:
+ setting = CMU->PCNTCTRL & CMU_PCNTCTRL_PCNT2CLKSEL_PCNT2S0;
+ break;
+#endif
+#endif
+#endif
+
+ default:
+ setting = 0;
+ break;
+ }
+ return (setting ? true : false);
+}
+
+/**************************************************************************//**
+ * @brief
+ * Select PCNTn clock.
+ *
+ * @param[in] instance
+ * PCNT instance number to set selected clock source for.
+ *
+ * @param[in] external
+ * Set to true to select external clock, false to select LFBCLK.
+ *****************************************************************************/
+void CMU_PCNTClockExternalSet(unsigned int instance, bool external)
+{
+#if defined(PCNT_PRESENT)
+ uint32_t setting = 0;
+
+ EFM_ASSERT(instance < PCNT_COUNT);
+
+ if (external) {
+ setting = 1;
+ }
+
+ BUS_RegBitWrite(&(CMU->PCNTCTRL), (instance * 2) + 1, setting);
+
+#else
+ (void)instance; /* Unused parameter */
+ (void)external; /* Unused parameter */
+#endif
+}
+
+#if defined(_CMU_USHFRCOCONF_BAND_MASK)
+/***************************************************************************//**
+ * @brief
+ * Get USHFRCO band in use.
+ *
+ * @return
+ * USHFRCO band in use.
+ ******************************************************************************/
+CMU_USHFRCOBand_TypeDef CMU_USHFRCOBandGet(void)
+{
+ return (CMU_USHFRCOBand_TypeDef)((CMU->USHFRCOCONF
+ & _CMU_USHFRCOCONF_BAND_MASK)
+ >> _CMU_USHFRCOCONF_BAND_SHIFT);
+}
+#endif
+
+#if defined(_CMU_USHFRCOCONF_BAND_MASK)
+/***************************************************************************//**
+ * @brief
+ * Set USHFRCO band to use.
+ *
+ * @param[in] band
+ * USHFRCO band to activate.
+ ******************************************************************************/
+void CMU_USHFRCOBandSet(CMU_USHFRCOBand_TypeDef band)
+{
+ uint32_t tuning;
+ uint32_t fineTuning;
+ CMU_Select_TypeDef osc;
+
+ /* Cannot switch band if USHFRCO is already selected as HF clock. */
+ osc = CMU_ClockSelectGet(cmuClock_HF);
+ EFM_ASSERT((CMU_USHFRCOBandGet() != band) && (osc != cmuSelect_USHFRCO));
+
+ /* Read tuning value from calibration table */
+ switch (band) {
+ case cmuUSHFRCOBand_24MHz:
+ tuning = (DEVINFO->USHFRCOCAL0 & _DEVINFO_USHFRCOCAL0_BAND24_TUNING_MASK)
+ >> _DEVINFO_USHFRCOCAL0_BAND24_TUNING_SHIFT;
+ fineTuning = (DEVINFO->USHFRCOCAL0
+ & _DEVINFO_USHFRCOCAL0_BAND24_FINETUNING_MASK)
+ >> _DEVINFO_USHFRCOCAL0_BAND24_FINETUNING_SHIFT;
+ ushfrcoFreq = 24000000UL;
+ break;
+
+ case cmuUSHFRCOBand_48MHz:
+ tuning = (DEVINFO->USHFRCOCAL0 & _DEVINFO_USHFRCOCAL0_BAND48_TUNING_MASK)
+ >> _DEVINFO_USHFRCOCAL0_BAND48_TUNING_SHIFT;
+ fineTuning = (DEVINFO->USHFRCOCAL0
+ & _DEVINFO_USHFRCOCAL0_BAND48_FINETUNING_MASK)
+ >> _DEVINFO_USHFRCOCAL0_BAND48_FINETUNING_SHIFT;
+ /* Enable the clock divider before switching the band from 24 to 48MHz */
+ BUS_RegBitWrite(&CMU->USHFRCOCONF, _CMU_USHFRCOCONF_USHFRCODIV2DIS_SHIFT, 0);
+ ushfrcoFreq = 48000000UL;
+ break;
+
+ default:
+ EFM_ASSERT(0);
+ return;
+ }
+
+ /* Set band and tuning */
+ CMU->USHFRCOCONF = (CMU->USHFRCOCONF & ~_CMU_USHFRCOCONF_BAND_MASK)
+ | (band << _CMU_USHFRCOCONF_BAND_SHIFT);
+ CMU->USHFRCOCTRL = (CMU->USHFRCOCTRL & ~_CMU_USHFRCOCTRL_TUNING_MASK)
+ | (tuning << _CMU_USHFRCOCTRL_TUNING_SHIFT);
+ CMU->USHFRCOTUNE = (CMU->USHFRCOTUNE & ~_CMU_USHFRCOTUNE_FINETUNING_MASK)
+ | (fineTuning << _CMU_USHFRCOTUNE_FINETUNING_SHIFT);
+
+ /* Disable the clock divider after switching the band from 48 to 24MHz */
+ if (band == cmuUSHFRCOBand_24MHz) {
+ BUS_RegBitWrite(&CMU->USHFRCOCONF, _CMU_USHFRCOCONF_USHFRCODIV2DIS_SHIFT, 1);
+ }
+}
+#endif
+
+/** @} (end addtogroup CMU) */
+/** @} (end addtogroup emlib) */
+#endif /* __EM_CMU_H */
diff --git a/efm32/emlib/em_cryotimer.c b/efm32/emlib/em_cryotimer.c
new file mode 100644
index 0000000..66f4ac5
--- /dev/null
+++ b/efm32/emlib/em_cryotimer.c
@@ -0,0 +1,61 @@
+/***************************************************************************//**
+ * @file em_cryotimer.c
+ * @brief Ultra Low Energy Timer/Counter (CRYOTIMER) peripheral API
+ * @version 5.2.2
+ *******************************************************************************
+ * # License
+ * Copyright 2016 Silicon Laboratories, Inc. http://www.silabs.com
+ *******************************************************************************
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software.@n
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.@n
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
+ * obligation to support this Software. Silicon Labs is providing the
+ * Software "AS IS", with no express or implied warranties of any kind,
+ * including, but not limited to, any implied warranties of merchantability
+ * or fitness for any particular purpose or warranties against infringement
+ * of any proprietary rights of a third party.
+ *
+ * Silicon Labs will not be liable for any consequential, incidental, or
+ * special damages, or any other relief, or for any claim by any third party,
+ * arising from your use of this Software.
+ *
+ ******************************************************************************/
+
+#include "em_cryotimer.h"
+#include "em_bus.h"
+
+#if defined(CRYOTIMER_PRESENT) && (CRYOTIMER_COUNT == 1)
+
+/***************************************************************************//**
+ * @brief
+ * Initialize the CRYOTIMER.
+ *
+ * @details
+ * Use this function to initialize the CRYOTIMER.
+ * Select prescaler setting and select low frequency oscillator.
+ * Refer to the configuration structure @ref CRYOTIMER_Init_TypeDef for more
+ * details.
+ *
+ * @param[in] init
+ * Pointer to initialization structure.
+ ******************************************************************************/
+void CRYOTIMER_Init(const CRYOTIMER_Init_TypeDef *init)
+{
+ CRYOTIMER->PERIODSEL = (uint32_t)init->period & _CRYOTIMER_PERIODSEL_MASK;
+ CRYOTIMER->CTRL = ((uint32_t)init->enable << _CRYOTIMER_CTRL_EN_SHIFT)
+ | ((uint32_t)init->debugRun << _CRYOTIMER_CTRL_DEBUGRUN_SHIFT)
+ | ((uint32_t)init->osc << _CRYOTIMER_CTRL_OSCSEL_SHIFT)
+ | ((uint32_t)init->presc << _CRYOTIMER_CTRL_PRESC_SHIFT);
+ CRYOTIMER_EM4WakeupEnable(init->em4Wakeup);
+}
+
+#endif /* defined(CRYOTIMER_PRESENT) && (CRYOTIMER_COUNT > 0) */
diff --git a/efm32/emlib/em_emu.c b/efm32/emlib/em_emu.c
new file mode 100644
index 0000000..1ba8a46
--- /dev/null
+++ b/efm32/emlib/em_emu.c
@@ -0,0 +1,2587 @@
+/***************************************************************************//**
+ * @file em_emu.c
+ * @brief Energy Management Unit (EMU) Peripheral API
+ * @version 5.2.2
+ *******************************************************************************
+ * # License
+ * Copyright 2016 Silicon Laboratories, Inc. http://www.silabs.com
+ *******************************************************************************
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
+ * obligation to support this Software. Silicon Labs is providing the
+ * Software "AS IS", with no express or implied warranties of any kind,
+ * including, but not limited to, any implied warranties of merchantability
+ * or fitness for any particular purpose or warranties against infringement
+ * of any proprietary rights of a third party.
+ *
+ * Silicon Labs will not be liable for any consequential, incidental, or
+ * special damages, or any other relief, or for any claim by any third party,
+ * arising from your use of this Software.
+ *
+ ******************************************************************************/
+
+#include
+
+#include "em_emu.h"
+#if defined(EMU_PRESENT) && (EMU_COUNT > 0)
+
+#include "em_cmu.h"
+#include "em_system.h"
+#include "em_common.h"
+#include "em_assert.h"
+
+/***************************************************************************//**
+ * @addtogroup emlib
+ * @{
+ ******************************************************************************/
+
+/***************************************************************************//**
+ * @addtogroup EMU
+ * @brief Energy Management Unit (EMU) Peripheral API
+ * @details
+ * This module contains functions to control the EMU peripheral of Silicon
+ * Labs 32-bit MCUs and SoCs. The EMU handles the different low energy modes
+ * in Silicon Labs microcontrollers.
+ * @{
+ ******************************************************************************/
+
+/* Consistency check, since restoring assumes similar bitpositions in */
+/* CMU OSCENCMD and STATUS regs */
+#if (CMU_STATUS_AUXHFRCOENS != CMU_OSCENCMD_AUXHFRCOEN)
+#error Conflict in AUXHFRCOENS and AUXHFRCOEN bitpositions
+#endif
+#if (CMU_STATUS_HFXOENS != CMU_OSCENCMD_HFXOEN)
+#error Conflict in HFXOENS and HFXOEN bitpositions
+#endif
+#if (CMU_STATUS_LFRCOENS != CMU_OSCENCMD_LFRCOEN)
+#error Conflict in LFRCOENS and LFRCOEN bitpositions
+#endif
+#if (CMU_STATUS_LFXOENS != CMU_OSCENCMD_LFXOEN)
+#error Conflict in LFXOENS and LFXOEN bitpositions
+#endif
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+#if defined(_SILICON_LABS_32B_SERIES_0)
+/* Fix for errata EMU_E107 - non-WIC interrupt masks.
+ * Zero Gecko and future families are not affected by errata EMU_E107 */
+#if defined(_EFM32_GECKO_FAMILY)
+#define ERRATA_FIX_EMU_E107_EN
+#define NON_WIC_INT_MASK_0 (~(0x0dfc0323U))
+#define NON_WIC_INT_MASK_1 (~(0x0U))
+
+#elif defined(_EFM32_TINY_FAMILY)
+#define ERRATA_FIX_EMU_E107_EN
+#define NON_WIC_INT_MASK_0 (~(0x001be323U))
+#define NON_WIC_INT_MASK_1 (~(0x0U))
+
+#elif defined(_EFM32_GIANT_FAMILY)
+#define ERRATA_FIX_EMU_E107_EN
+#define NON_WIC_INT_MASK_0 (~(0xff020e63U))
+#define NON_WIC_INT_MASK_1 (~(0x00000046U))
+
+#elif defined(_EFM32_WONDER_FAMILY)
+#define ERRATA_FIX_EMU_E107_EN
+#define NON_WIC_INT_MASK_0 (~(0xff020e63U))
+#define NON_WIC_INT_MASK_1 (~(0x00000046U))
+
+#endif
+#endif
+
+/* Fix for errata EMU_E108 - High Current Consumption on EM4 Entry. */
+#if defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_HAPPY_FAMILY)
+#define ERRATA_FIX_EMU_E108_EN
+#endif
+
+/* Fix for errata EMU_E208 - Occasional Full Reset After Exiting EM4H */
+#if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
+#define ERRATA_FIX_EMU_E208_EN
+#endif
+
+/* Enable FETCNT tuning errata fix */
+#if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
+#define ERRATA_FIX_DCDC_FETCNT_SET_EN
+#endif
+
+/* Enable LN handshake errata fix */
+#if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
+#define ERRATA_FIX_DCDC_LNHS_BLOCK_EN
+typedef enum {
+ errataFixDcdcHsInit,
+ errataFixDcdcHsTrimSet,
+ errataFixDcdcHsBypassLn,
+ errataFixDcdcHsLnWaitDone
+} errataFixDcdcHs_TypeDef;
+static errataFixDcdcHs_TypeDef errataFixDcdcHsState = errataFixDcdcHsInit;
+#endif
+
+/* Used to figure out if a memory address is inside or outside of a RAM block.
+ * A memory address is inside a RAM block if the address is greater than the
+ * RAM block address. */
+#define ADDRESS_NOT_IN_BLOCK(addr, block) ((addr) <= (block))
+
+/* RAM Block layout for various device families. Note that some devices
+ * have special layout in RAM0 and some devices have a special RAM block
+ * at the end of their block layout. */
+#if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_84)
+#define RAM1_BLOCKS 2
+#define RAM1_BLOCK_SIZE 0x10000 // 64 kB blocks
+#define RAM2_BLOCKS 1
+#define RAM2_BLOCK_SIZE 0x800 // 2 kB block
+#elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_89)
+#define RAM0_BLOCKS 2
+#define RAM0_BLOCK_SIZE 0x4000
+#define RAM1_BLOCKS 2
+#define RAM1_BLOCK_SIZE 0x4000 // 16 kB blocks
+#define RAM2_BLOCKS 1
+#define RAM2_BLOCK_SIZE 0x800 // 2 kB block
+#elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_95)
+#define RAM0_BLOCKS 1
+#define RAM0_BLOCK_SIZE 0x4000 // 16 kB block
+#define RAM1_BLOCKS 1
+#define RAM1_BLOCK_SIZE 0x4000 // 16 kB block
+#define RAM2_BLOCKS 1
+#define RAM2_BLOCK_SIZE 0x800 // 2 kB block
+#elif defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_GIANT_FAMILY)
+#define RAM0_BLOCKS 4
+#define RAM0_BLOCK_SIZE 0x8000 // 32 kB blocks
+#elif defined(_SILICON_LABS_32B_SERIES_0) && defined(_EFM32_GECKO_FAMILY)
+#define RAM0_BLOCKS 4
+#define RAM0_BLOCK_SIZE 0x1000 // 4 kB blocks
+#elif defined(_SILICON_LABS_32B_SERIES_1) && defined(_EFM32_GIANT_FAMILY)
+#define RAM0_BLOCKS 8
+#define RAM0_BLOCK_SIZE 0x4000 // 16 kB blocks
+#define RAM1_BLOCKS 8
+#define RAM1_BLOCK_SIZE 0x4000 // 16 kB blocks
+#define RAM2_BLOCKS 4
+#define RAM2_BLOCK_SIZE 0x10000 // 64 kB blocks
+#endif
+
+#if defined(_SILICON_LABS_32B_SERIES_0)
+/* RAM_MEM_END on Gecko devices have a value larger than the SRAM_SIZE */
+#define RAM0_END (SRAM_BASE + SRAM_SIZE - 1)
+#else
+#define RAM0_END RAM_MEM_END
+#endif
+
+#if defined(CMU_STATUS_HFXOSHUNTOPTRDY)
+#define HFXO_STATUS_READY_FLAGS (CMU_STATUS_HFXOPEAKDETRDY | CMU_STATUS_HFXOSHUNTOPTRDY)
+#elif defined(CMU_STATUS_HFXOPEAKDETRDY)
+#define HFXO_STATUS_READY_FLAGS (CMU_STATUS_HFXOPEAKDETRDY)
+#endif
+
+/** @endcond */
+
+#if defined(_EMU_DCDCCTRL_MASK)
+/* DCDCTODVDD output range min/max */
+#if !defined(PWRCFG_DCDCTODVDD_VMIN)
+#define PWRCFG_DCDCTODVDD_VMIN 1800
+#endif
+#if !defined(PWRCFG_DCDCTODVDD_VMAX)
+#define PWRCFG_DCDCTODVDD_VMAX 3000
+#endif
+#endif
+
+/*******************************************************************************
+ *************************** LOCAL VARIABLES ********************************
+ ******************************************************************************/
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+
+/* Static user configuration */
+#if defined(_EMU_DCDCCTRL_MASK)
+static uint16_t dcdcMaxCurrent_mA;
+static uint16_t dcdcEm01LoadCurrent_mA;
+static EMU_DcdcLnReverseCurrentControl_TypeDef dcdcReverseCurrentControl;
+#endif
+#if defined(_EMU_CMD_EM01VSCALE0_MASK)
+static EMU_EM01Init_TypeDef vScaleEM01Config = { false };
+#endif
+/** @endcond */
+
+/*******************************************************************************
+ ************************** LOCAL FUNCTIONS ********************************
+ ******************************************************************************/
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+
+#if defined(_EMU_CMD_EM01VSCALE0_MASK)
+/* Convert from level to EM0 and 1 command bit */
+__STATIC_INLINE uint32_t vScaleEM01Cmd(EMU_VScaleEM01_TypeDef level)
+{
+ return EMU_CMD_EM01VSCALE0 << (_EMU_STATUS_VSCALE_VSCALE0 - (uint32_t)level);
+}
+#endif
+
+/***************************************************************************//**
+ * @brief
+ * Save/restore/update oscillator, core clock and voltage scaling configuration on
+ * EM2 or EM3 entry/exit.
+ *
+ * @details
+ * Hardware may automatically change oscillator and voltage scaling configuration
+ * when going into or out of an energy mode. Static data in this function keeps track of
+ * such configuration bits and is used to restore state if needed.
+ *
+ ******************************************************************************/
+typedef enum {
+ emState_Save, /* Save EMU and CMU state */
+ emState_Restore, /* Restore and unlock */
+} emState_TypeDef;
+
+static void emState(emState_TypeDef action)
+{
+ uint32_t oscEnCmd;
+ uint32_t cmuLocked;
+ static uint32_t cmuStatus;
+ static CMU_Select_TypeDef hfClock;
+#if defined(_EMU_CMD_EM01VSCALE0_MASK)
+ static uint8_t vScaleStatus;
+#endif
+
+ /* Save or update state */
+ if (action == emState_Save) {
+ /* Save configuration. */
+ cmuStatus = CMU->STATUS;
+ hfClock = CMU_ClockSelectGet(cmuClock_HF);
+#if defined(_EMU_CMD_EM01VSCALE0_MASK)
+ /* Save vscale */
+ EMU_VScaleWait();
+ vScaleStatus = (uint8_t)((EMU->STATUS & _EMU_STATUS_VSCALE_MASK)
+ >> _EMU_STATUS_VSCALE_SHIFT);
+#endif
+ } else if (action == emState_Restore) { /* Restore state */
+ /* Apply saved configuration. */
+#if defined(_EMU_CMD_EM01VSCALE0_MASK)
+ /* Restore EM0 and 1 voltage scaling level. EMU_VScaleWait() is called later,
+ just before HF clock select is set. */
+ EMU->CMD = vScaleEM01Cmd((EMU_VScaleEM01_TypeDef)vScaleStatus);
+#endif
+
+ /* CMU registers may be locked */
+ cmuLocked = CMU->LOCK & CMU_LOCK_LOCKKEY_LOCKED;
+ CMU_Unlock();
+
+ /* AUXHFRCO are automatically disabled (except if using debugger). */
+ /* HFRCO, USHFRCO and HFXO are automatically disabled. */
+ /* LFRCO/LFXO may be disabled by SW in EM3. */
+ /* Restore according to status prior to entering energy mode. */
+ oscEnCmd = 0;
+ oscEnCmd |= ((cmuStatus & CMU_STATUS_HFRCOENS) ? CMU_OSCENCMD_HFRCOEN : 0);
+ oscEnCmd |= ((cmuStatus & CMU_STATUS_AUXHFRCOENS) ? CMU_OSCENCMD_AUXHFRCOEN : 0);
+ oscEnCmd |= ((cmuStatus & CMU_STATUS_LFRCOENS) ? CMU_OSCENCMD_LFRCOEN : 0);
+ oscEnCmd |= ((cmuStatus & CMU_STATUS_HFXOENS) ? CMU_OSCENCMD_HFXOEN : 0);
+ oscEnCmd |= ((cmuStatus & CMU_STATUS_LFXOENS) ? CMU_OSCENCMD_LFXOEN : 0);
+#if defined(_CMU_STATUS_USHFRCOENS_MASK)
+ oscEnCmd |= ((cmuStatus & CMU_STATUS_USHFRCOENS) ? CMU_OSCENCMD_USHFRCOEN : 0);
+#endif
+ CMU->OSCENCMD = oscEnCmd;
+
+#if defined(_EMU_STATUS_VSCALE_MASK)
+ /* Wait for upscale to complete and then restore selected clock */
+ EMU_VScaleWait();
+#endif
+
+ if (hfClock != cmuSelect_HFRCO) {
+ CMU_ClockSelectSet(cmuClock_HF, hfClock);
+ }
+
+ /* If HFRCO was disabled before entering Energy Mode, turn it off again */
+ /* as it is automatically enabled by wake up */
+ if ( !(cmuStatus & CMU_STATUS_HFRCOENS) ) {
+ CMU->OSCENCMD = CMU_OSCENCMD_HFRCODIS;
+ }
+
+ /* Restore CMU register locking */
+ if (cmuLocked) {
+ CMU_Lock();
+ }
+ }
+}
+
+#if defined(ERRATA_FIX_EMU_E107_EN)
+/* Get enable conditions for errata EMU_E107 fix. */
+__STATIC_INLINE bool getErrataFixEmuE107En(void)
+{
+ /* SYSTEM_ChipRevisionGet could have been used here, but we would like a
+ * faster implementation in this case.
+ */
+ uint16_t majorMinorRev;
+
+ /* CHIP MAJOR bit [3:0] */
+ majorMinorRev = ((ROMTABLE->PID0 & _ROMTABLE_PID0_REVMAJOR_MASK)
+ >> _ROMTABLE_PID0_REVMAJOR_SHIFT)
+ << 8;
+ /* CHIP MINOR bit [7:4] */
+ majorMinorRev |= ((ROMTABLE->PID2 & _ROMTABLE_PID2_REVMINORMSB_MASK)
+ >> _ROMTABLE_PID2_REVMINORMSB_SHIFT)
+ << 4;
+ /* CHIP MINOR bit [3:0] */
+ majorMinorRev |= (ROMTABLE->PID3 & _ROMTABLE_PID3_REVMINORLSB_MASK)
+ >> _ROMTABLE_PID3_REVMINORLSB_SHIFT;
+
+#if defined(_EFM32_GECKO_FAMILY)
+ return (majorMinorRev <= 0x0103);
+#elif defined(_EFM32_TINY_FAMILY)
+ return (majorMinorRev <= 0x0102);
+#elif defined(_EFM32_GIANT_FAMILY)
+ return (majorMinorRev <= 0x0103) || (majorMinorRev == 0x0204);
+#elif defined(_EFM32_WONDER_FAMILY)
+ return (majorMinorRev == 0x0100);
+#else
+ /* Zero Gecko and future families are not affected by errata EMU_E107 */
+ return false;
+#endif
+}
+#endif
+
+/* LP prepare / LN restore P/NFET count */
+#define DCDC_LP_PFET_CNT 7
+#define DCDC_LP_NFET_CNT 7
+#if defined(ERRATA_FIX_DCDC_FETCNT_SET_EN)
+static void currentLimitersUpdate(void);
+static void dcdcFetCntSet(bool lpModeSet)
+{
+ uint32_t tmp;
+ static uint32_t emuDcdcMiscCtrlReg;
+
+ if (lpModeSet) {
+ emuDcdcMiscCtrlReg = EMU->DCDCMISCCTRL;
+ tmp = EMU->DCDCMISCCTRL
+ & ~(_EMU_DCDCMISCCTRL_PFETCNT_MASK | _EMU_DCDCMISCCTRL_NFETCNT_MASK);
+ tmp |= (DCDC_LP_PFET_CNT << _EMU_DCDCMISCCTRL_PFETCNT_SHIFT)
+ | (DCDC_LP_NFET_CNT << _EMU_DCDCMISCCTRL_NFETCNT_SHIFT);
+ EMU->DCDCMISCCTRL = tmp;
+ currentLimitersUpdate();
+ } else {
+ EMU->DCDCMISCCTRL = emuDcdcMiscCtrlReg;
+ currentLimitersUpdate();
+ }
+}
+#endif
+
+#if defined(ERRATA_FIX_DCDC_LNHS_BLOCK_EN)
+static void dcdcHsFixLnBlock(void)
+{
+#define EMU_DCDCSTATUS (*(volatile uint32_t *)(EMU_BASE + 0x7C))
+ if ((errataFixDcdcHsState == errataFixDcdcHsTrimSet)
+ || (errataFixDcdcHsState == errataFixDcdcHsBypassLn)) {
+ /* Wait for LNRUNNING */
+ if ((EMU->DCDCCTRL & _EMU_DCDCCTRL_DCDCMODE_MASK) == EMU_DCDCCTRL_DCDCMODE_LOWNOISE) {
+ while (!(EMU_DCDCSTATUS & (0x1 << 16))) ;
+ }
+ errataFixDcdcHsState = errataFixDcdcHsLnWaitDone;
+ }
+}
+#endif
+
+#if defined(_EMU_CTRL_EM23VSCALE_MASK)
+/* Configure EMU and CMU for EM2 and 3 voltage downscale */
+static void vScaleDownEM23Setup(void)
+{
+ uint32_t hfSrcClockFrequency;
+
+ EMU_VScaleEM23_TypeDef scaleEM23Voltage =
+ (EMU_VScaleEM23_TypeDef)((EMU->CTRL & _EMU_CTRL_EM23VSCALE_MASK)
+ >> _EMU_CTRL_EM23VSCALE_SHIFT);
+
+ EMU_VScaleEM01_TypeDef currentEM01Voltage =
+ (EMU_VScaleEM01_TypeDef)((EMU->STATUS & _EMU_STATUS_VSCALE_MASK)
+ >> _EMU_STATUS_VSCALE_SHIFT);
+
+ /* Wait until previous scaling is done. */
+ EMU_VScaleWait();
+
+ /* Inverse coding. */
+ if ((uint32_t)scaleEM23Voltage > (uint32_t)currentEM01Voltage) {
+ /* Set safe clock and wait-states. */
+ if (scaleEM23Voltage == emuVScaleEM23_LowPower) {
+ hfSrcClockFrequency = CMU_ClockDivGet(cmuClock_HF) * CMU_ClockFreqGet(cmuClock_HF);
+ /* Set default low power voltage HFRCO band as HF clock. */
+ if (hfSrcClockFrequency > CMU_VSCALEEM01_LOWPOWER_VOLTAGE_CLOCK_MAX) {
+ CMU_HFRCOBandSet(cmuHFRCOFreq_19M0Hz);
+ }
+ CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFRCO);
+ } else {
+ /* Other voltage scaling levels are not currently supported. */
+ EFM_ASSERT(false);
+ }
+ } else {
+ /* Same voltage or hardware will scale to min(EMU_CTRL_EM23VSCALE, EMU_STATUS_VSCALE) */
+ }
+}
+#endif
+/** @endcond */
+
+/*******************************************************************************
+ ************************** GLOBAL FUNCTIONS *******************************
+ ******************************************************************************/
+
+/***************************************************************************//**
+ * @brief
+ * Enter energy mode 2 (EM2).
+ *
+ * @details
+ * When entering EM2, the high frequency clocks are disabled, ie HFXO, HFRCO
+ * and AUXHFRCO (for AUXHFRCO, see exception note below). When re-entering
+ * EM0, HFRCO is re-enabled and the core will be clocked by the configured
+ * HFRCO band. This ensures a quick wakeup from EM2.
+ *
+ * However, prior to entering EM2, the core may have been using another
+ * oscillator than HFRCO. The @p restore parameter gives the user the option
+ * to restore all HF oscillators according to state prior to entering EM2,
+ * as well as the clock used to clock the core. This restore procedure is
+ * handled by SW. However, since handled by SW, it will not be restored
+ * before completing the interrupt function(s) waking up the core!
+ *
+ * @note
+ * If restoring core clock to use the HFXO oscillator, which has been
+ * disabled during EM2 mode, this function will stall until the oscillator
+ * has stabilized. Stalling time can be reduced by adding interrupt
+ * support detecting stable oscillator, and an asynchronous switch to the
+ * original oscillator. See CMU documentation. Such a feature is however
+ * outside the scope of the implementation in this function.
+ * @par
+ * If HFXO is re-enabled by this function, and NOT used to clock the core,
+ * this function will not wait for HFXO to stabilize. This must be considered
+ * by the application if trying to use features relying on that oscillator
+ * upon return.
+ * @par
+ * If a debugger is attached, the AUXHFRCO will not be disabled if enabled
+ * upon entering EM2. It will thus remain enabled when returning to EM0
+ * regardless of the @p restore parameter.
+ * @par
+ * If HFXO autostart and select is enabled by using CMU_HFXOAutostartEnable(),
+ * the starting and selecting of the core clocks will be identical to the user
+ * independently of the value of the @p restore parameter when waking up on
+ * the wakeup sources corresponding to the autostart and select setting.
+ * @par
+ * If voltage scaling is supported, the restore parameter is true and the EM0
+ * voltage scaling level is set higher than the EM2 level, then the EM0 level is
+ * also restored.
+ *
+ * @param[in] restore
+ * @li true - save and restore oscillators, clocks and voltage scaling, see
+ * function details.
+ * @li false - do not save and restore oscillators and clocks, see function
+ * details.
+ * @par
+ * The @p restore option should only be used if all clock control is done
+ * via the CMU API.
+ ******************************************************************************/
+void EMU_EnterEM2(bool restore)
+{
+#if defined(ERRATA_FIX_EMU_E107_EN)
+ bool errataFixEmuE107En;
+ uint32_t nonWicIntEn[2];
+#endif
+
+ /* Only save EMU and CMU state if restored on wake-up. */
+ if (restore) {
+ emState(emState_Save);
+ }
+
+#if defined(_EMU_CTRL_EM23VSCALE_MASK)
+ vScaleDownEM23Setup();
+#endif
+
+ /* Enter Cortex deep sleep mode */
+ SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
+
+ /* Fix for errata EMU_E107 - store non-WIC interrupt enable flags.
+ Disable the enabled non-WIC interrupts. */
+#if defined(ERRATA_FIX_EMU_E107_EN)
+ errataFixEmuE107En = getErrataFixEmuE107En();
+ if (errataFixEmuE107En) {
+ nonWicIntEn[0] = NVIC->ISER[0] & NON_WIC_INT_MASK_0;
+ NVIC->ICER[0] = nonWicIntEn[0];
+#if (NON_WIC_INT_MASK_1 != (~(0x0U)))
+ nonWicIntEn[1] = NVIC->ISER[1] & NON_WIC_INT_MASK_1;
+ NVIC->ICER[1] = nonWicIntEn[1];
+#endif
+ }
+#endif
+
+#if defined(ERRATA_FIX_DCDC_FETCNT_SET_EN)
+ dcdcFetCntSet(true);
+#endif
+#if defined(ERRATA_FIX_DCDC_LNHS_BLOCK_EN)
+ dcdcHsFixLnBlock();
+#endif
+
+ __WFI();
+
+#if defined(ERRATA_FIX_DCDC_FETCNT_SET_EN)
+ dcdcFetCntSet(false);
+#endif
+
+ /* Fix for errata EMU_E107 - restore state of non-WIC interrupt enable flags. */
+#if defined(ERRATA_FIX_EMU_E107_EN)
+ if (errataFixEmuE107En) {
+ NVIC->ISER[0] = nonWicIntEn[0];
+#if (NON_WIC_INT_MASK_1 != (~(0x0U)))
+ NVIC->ISER[1] = nonWicIntEn[1];
+#endif
+ }
+#endif
+
+ /* Restore oscillators/clocks and voltage scaling if supported. */
+ if (restore) {
+ emState(emState_Restore);
+ } else {
+ /* If not restoring, and original clock was not HFRCO, we have to */
+ /* update CMSIS core clock variable since HF clock has changed */
+ /* to HFRCO. */
+ SystemCoreClockUpdate();
+ }
+}
+
+/***************************************************************************//**
+ * @brief
+ * Enter energy mode 3 (EM3).
+ *
+ * @details
+ * When entering EM3, the high frequency clocks are disabled by HW, ie HFXO,
+ * HFRCO and AUXHFRCO (for AUXHFRCO, see exception note below). In addition,
+ * the low frequency clocks, ie LFXO and LFRCO are disabled by SW. When
+ * re-entering EM0, HFRCO is re-enabled and the core will be clocked by the
+ * configured HFRCO band. This ensures a quick wakeup from EM3.
+ *
+ * However, prior to entering EM3, the core may have been using another
+ * oscillator than HFRCO. The @p restore parameter gives the user the option
+ * to restore all HF/LF oscillators according to state prior to entering EM3,
+ * as well as the clock used to clock the core. This restore procedure is
+ * handled by SW. However, since handled by SW, it will not be restored
+ * before completing the interrupt function(s) waking up the core!
+ *
+ * @note
+ * If restoring core clock to use an oscillator other than HFRCO, this
+ * function will stall until the oscillator has stabilized. Stalling time
+ * can be reduced by adding interrupt support detecting stable oscillator,
+ * and an asynchronous switch to the original oscillator. See CMU
+ * documentation. Such a feature is however outside the scope of the
+ * implementation in this function.
+ * @par
+ * If HFXO/LFXO/LFRCO are re-enabled by this function, and NOT used to clock
+ * the core, this function will not wait for those oscillators to stabilize.
+ * This must be considered by the application if trying to use features
+ * relying on those oscillators upon return.
+ * @par
+ * If a debugger is attached, the AUXHFRCO will not be disabled if enabled
+ * upon entering EM3. It will thus remain enabled when returning to EM0
+ * regardless of the @p restore parameter.
+ * @par
+ * If voltage scaling is supported, the restore parameter is true and the EM0
+ * voltage scaling level is set higher than the EM3 level, then the EM0 level is
+ * also restored.
+ *
+ * @param[in] restore
+ * @li true - save and restore oscillators, clocks and voltage scaling, see
+ * function details.
+ * @li false - do not save and restore oscillators and clocks, see function
+ * details.
+ * @par
+ * The @p restore option should only be used if all clock control is done
+ * via the CMU API.
+ ******************************************************************************/
+void EMU_EnterEM3(bool restore)
+{
+ uint32_t cmuLocked;
+
+#if defined(ERRATA_FIX_EMU_E107_EN)
+ bool errataFixEmuE107En;
+ uint32_t nonWicIntEn[2];
+#endif
+
+ /* Only save EMU and CMU state if restored on wake-up. */
+ if (restore) {
+ emState(emState_Save);
+ }
+
+#if defined(_EMU_CTRL_EM23VSCALE_MASK)
+ vScaleDownEM23Setup();
+#endif
+
+ /* CMU registers may be locked */
+ cmuLocked = CMU->LOCK & CMU_LOCK_LOCKKEY_LOCKED;
+ CMU_Unlock();
+
+ /* Disable LF oscillators */
+ CMU->OSCENCMD = CMU_OSCENCMD_LFXODIS | CMU_OSCENCMD_LFRCODIS;
+
+ /* Restore CMU register locking */
+ if (cmuLocked) {
+ CMU_Lock();
+ }
+
+ /* Enter Cortex deep sleep mode */
+ SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
+
+ /* Fix for errata EMU_E107 - store non-WIC interrupt enable flags.
+ Disable the enabled non-WIC interrupts. */
+#if defined(ERRATA_FIX_EMU_E107_EN)
+ errataFixEmuE107En = getErrataFixEmuE107En();
+ if (errataFixEmuE107En) {
+ nonWicIntEn[0] = NVIC->ISER[0] & NON_WIC_INT_MASK_0;
+ NVIC->ICER[0] = nonWicIntEn[0];
+#if (NON_WIC_INT_MASK_1 != (~(0x0U)))
+ nonWicIntEn[1] = NVIC->ISER[1] & NON_WIC_INT_MASK_1;
+ NVIC->ICER[1] = nonWicIntEn[1];
+#endif
+ }
+#endif
+
+#if defined(ERRATA_FIX_DCDC_FETCNT_SET_EN)
+ dcdcFetCntSet(true);
+#endif
+#if defined(ERRATA_FIX_DCDC_LNHS_BLOCK_EN)
+ dcdcHsFixLnBlock();
+#endif
+
+ __WFI();
+
+#if defined(ERRATA_FIX_DCDC_FETCNT_SET_EN)
+ dcdcFetCntSet(false);
+#endif
+
+ /* Fix for errata EMU_E107 - restore state of non-WIC interrupt enable flags. */
+#if defined(ERRATA_FIX_EMU_E107_EN)
+ if (errataFixEmuE107En) {
+ NVIC->ISER[0] = nonWicIntEn[0];
+#if (NON_WIC_INT_MASK_1 != (~(0x0U)))
+ NVIC->ISER[1] = nonWicIntEn[1];
+#endif
+ }
+#endif
+
+ /* Restore oscillators/clocks and voltage scaling if supported. */
+ if (restore) {
+ emState(emState_Restore);
+ } else {
+ /* If not restoring, and original clock was not HFRCO, we have to */
+ /* update CMSIS core clock variable since HF clock has changed */
+ /* to HFRCO. */
+ SystemCoreClockUpdate();
+ }
+}
+
+/***************************************************************************//**
+ * @brief
+ * Save CMU HF clock select state, oscillator enable and voltage scaling
+ * (if available) before @ref EMU_EnterEM2() or @ref EMU_EnterEM3() are called
+ * with the restore parameter set to false. Calling this function is
+ * equivalent to calling @ref EMU_EnterEM2() or @ref EMU_EnterEM3() with the
+ * restore parameter set to true, but it allows the state to be saved without
+ * going to sleep. The state can be restored manually by calling
+ * @ref EMU_Restore().
+ ******************************************************************************/
+void EMU_Save(void)
+{
+ emState(emState_Save);
+}
+
+/***************************************************************************//**
+ * @brief
+ * Restore CMU HF clock select state, oscillator enable and voltage scaling
+ * (if available) after @ref EMU_EnterEM2() or @ref EMU_EnterEM3() are called
+ * with the restore parameter set to false. Calling this function is
+ * equivalent to calling @ref EMU_EnterEM2() or @ref EMU_EnterEM3() with the
+ * restore parameter set to true, but it allows the application to evaluate the
+ * wakeup reason before restoring state.
+ ******************************************************************************/
+void EMU_Restore(void)
+{
+ emState(emState_Restore);
+}
+
+/***************************************************************************//**
+ * @brief
+ * Enter energy mode 4 (EM4).
+ *
+ * @note
+ * Only a power on reset or external reset pin can wake the device from EM4.
+ ******************************************************************************/
+void EMU_EnterEM4(void)
+{
+ int i;
+
+#if defined(_EMU_EM4CTRL_EM4ENTRY_SHIFT)
+ uint32_t em4seq2 = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4ENTRY_MASK)
+ | (2 << _EMU_EM4CTRL_EM4ENTRY_SHIFT);
+ uint32_t em4seq3 = (EMU->EM4CTRL & ~_EMU_EM4CTRL_EM4ENTRY_MASK)
+ | (3 << _EMU_EM4CTRL_EM4ENTRY_SHIFT);
+#else
+ uint32_t em4seq2 = (EMU->CTRL & ~_EMU_CTRL_EM4CTRL_MASK)
+ | (2 << _EMU_CTRL_EM4CTRL_SHIFT);
+ uint32_t em4seq3 = (EMU->CTRL & ~_EMU_CTRL_EM4CTRL_MASK)
+ | (3 << _EMU_CTRL_EM4CTRL_SHIFT);
+#endif
+
+ /* Make sure register write lock is disabled */
+ EMU_Unlock();
+
+#if defined(_EMU_EM4CTRL_MASK)
+ if ((EMU->EM4CTRL & _EMU_EM4CTRL_EM4STATE_MASK) == EMU_EM4CTRL_EM4STATE_EM4S) {
+ uint32_t dcdcMode = EMU->DCDCCTRL & _EMU_DCDCCTRL_DCDCMODE_MASK;
+ if (dcdcMode == EMU_DCDCCTRL_DCDCMODE_LOWNOISE
+ || dcdcMode == EMU_DCDCCTRL_DCDCMODE_LOWPOWER) {
+ /* DCDC is not supported in EM4S so we switch DCDC to bypass mode before
+ * entering EM4S */
+ EMU_DCDCModeSet(emuDcdcMode_Bypass);
+ }
+ }
+#endif
+
+#if defined(_EMU_EM4CTRL_MASK) && defined(ERRATA_FIX_EMU_E208_EN)
+ if (EMU->EM4CTRL & EMU_EM4CTRL_EM4STATE_EM4H) {
+ /* Fix for errata EMU_E208 - Occasional Full Reset After Exiting EM4H.
+ * Full description of errata fix can be found in the errata document. */
+ __disable_irq();
+ *(volatile uint32_t *)(EMU_BASE + 0x190) = 0x0000ADE8UL;
+ *(volatile uint32_t *)(EMU_BASE + 0x198) |= (0x1UL << 7);
+ *(volatile uint32_t *)(EMU_BASE + 0x88) |= (0x1UL << 8);
+ }
+#endif
+
+#if defined(ERRATA_FIX_EMU_E108_EN)
+ /* Fix for errata EMU_E108 - High Current Consumption on EM4 Entry. */
+ __disable_irq();
+ *(volatile uint32_t *)0x400C80E4 = 0;
+#endif
+
+#if defined(ERRATA_FIX_DCDC_FETCNT_SET_EN)
+ dcdcFetCntSet(true);
+#endif
+#if defined(ERRATA_FIX_DCDC_LNHS_BLOCK_EN)
+ dcdcHsFixLnBlock();
+#endif
+
+ for (i = 0; i < 4; i++) {
+#if defined(_EMU_EM4CTRL_EM4ENTRY_SHIFT)
+ EMU->EM4CTRL = em4seq2;
+ EMU->EM4CTRL = em4seq3;
+ }
+ EMU->EM4CTRL = em4seq2;
+#else
+ EMU->CTRL = em4seq2;
+ EMU->CTRL = em4seq3;
+ }
+ EMU->CTRL = em4seq2;
+#endif
+}
+
+#if defined(_EMU_EM4CTRL_MASK)
+/***************************************************************************//**
+ * @brief
+ * Enter energy mode 4 hibernate (EM4H).
+ *
+ * @note
+ * Retention of clocks and GPIO in EM4 can be configured using
+ * @ref EMU_EM4Init before calling this function.
+ ******************************************************************************/
+void EMU_EnterEM4H(void)
+{
+ BUS_RegBitWrite(&EMU->EM4CTRL, _EMU_EM4CTRL_EM4STATE_SHIFT, 1);
+ EMU_EnterEM4();
+}
+
+/***************************************************************************//**
+ * @brief
+ * Enter energy mode 4 shutoff (EM4S).
+ *
+ * @note
+ * Retention of clocks and GPIO in EM4 can be configured using
+ * @ref EMU_EM4Init before calling this function.
+ ******************************************************************************/
+void EMU_EnterEM4S(void)
+{
+ BUS_RegBitWrite(&EMU->EM4CTRL, _EMU_EM4CTRL_EM4STATE_SHIFT, 0);
+ EMU_EnterEM4();
+}
+#endif
+
+/***************************************************************************//**
+ * @brief
+ * Power down memory block.
+ *
+ * @param[in] blocks
+ * Specifies a logical OR of bits indicating memory blocks to power down.
+ * Bit 0 selects block 1, bit 1 selects block 2, etc. Memory block 0 cannot
+ * be disabled. Please refer to the reference manual for available
+ * memory blocks for a device.
+ *
+ * @note
+ * Only a POR reset can power up the specified memory block(s) after powerdown.
+ *
+ * @deprecated
+ * This function is deprecated, use @ref EMU_RamPowerDown() instead which
+ * maps a user provided memory range into RAM blocks to power down.
+ ******************************************************************************/
+void EMU_MemPwrDown(uint32_t blocks)
+{
+#if defined(_EMU_MEMCTRL_MASK)
+ EMU->MEMCTRL = blocks & _EMU_MEMCTRL_MASK;
+#elif defined(_EMU_RAM0CTRL_MASK)
+ EMU->RAM0CTRL = blocks & _EMU_RAM0CTRL_MASK;
+#else
+ (void)blocks;
+#endif
+}
+
+/***************************************************************************//**
+ * @brief
+ * Power down RAM memory blocks.
+ *
+ * @details
+ * This function will power down all the RAM blocks that are within a given
+ * range. The RAM block layout is different between device families, so this
+ * function can be used in a generic way to power down a RAM memory region
+ * which is known to be unused.
+ *
+ * This function will only power down blocks which are completely enclosed
+ * by the memory range given by [start, end).
+ *
+ * Here is an example of how to power down all RAM blocks except the first
+ * one. The first RAM block is special in that it cannot be powered down
+ * by the hardware. The size of this first RAM block is device specific
+ * see the reference manual to find the RAM block sizes.
+ *
+ * @code
+ * EMU_RamPowerDown(SRAM_BASE, SRAM_BASE + SRAM_SIZE);
+ * @endcode
+ *
+ * @note
+ * Only a POR reset can power up the specified memory block(s) after powerdown.
+ *
+ * @param[in] start
+ * The start address of the RAM region to power down. This address is
+ * inclusive.
+ *
+ * @param[in] end
+ * The end address of the RAM region to power down. This address is
+ * exclusive. If this parameter is 0, then all RAM blocks contained in the
+ * region from start to the upper RAM address will be powered down.
+ ******************************************************************************/
+void EMU_RamPowerDown(uint32_t start, uint32_t end)
+{
+ uint32_t mask = 0;
+
+ if (end == 0) {
+ end = SRAM_BASE + SRAM_SIZE;
+ }
+
+ // Check to see if something in RAM0 can be powered down
+ if (end > RAM0_END) {
+#if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_84) // EFM32xG12 and EFR32xG12
+ // Block 0 is 16 kB and cannot be powered off
+ mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20004000) << 0; // Block 1, 16 kB
+ mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20008000) << 1; // Block 2, 16 kB
+ mask |= ADDRESS_NOT_IN_BLOCK(start, 0x2000C000) << 2; // Block 3, 16 kB
+ mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20010000) << 3; // Block 4, 64 kB
+#elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80) // EFM32xG1 and EFR32xG1
+ // Block 0 is 4 kB and cannot be powered off
+ mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20001000) << 0; // Block 1, 4 kB
+ mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20002000) << 1; // Block 2, 8 kB
+ mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20004000) << 2; // Block 3, 8 kB
+ mask |= ADDRESS_NOT_IN_BLOCK(start, 0x20006000) << 3; // Block 4, 7 kB
+#elif defined(RAM0_BLOCKS)
+ // These platforms have equally sized RAM blocks
+ for (int i = 1; i < RAM0_BLOCKS; i++) {
+ mask |= ADDRESS_NOT_IN_BLOCK(start, RAM_MEM_BASE + (i * RAM0_BLOCK_SIZE)) << (i - 1);
+ }
+#endif
+ }
+
+ // Power down the selected blocks
+#if defined(_EMU_MEMCTRL_MASK)
+ EMU->MEMCTRL = EMU->MEMCTRL | mask;
+#elif defined(_EMU_RAM0CTRL_MASK)
+ EMU->RAM0CTRL = EMU->RAM0CTRL | mask;
+#else
+ // These devices are unable to power down RAM blocks
+ (void) mask;
+ (void) start;
+#endif
+
+#if defined(RAM1_MEM_END)
+ mask = 0;
+ if (end > RAM1_MEM_END) {
+ for (int i = 0; i < RAM1_BLOCKS; i++) {
+ mask |= ADDRESS_NOT_IN_BLOCK(start, RAM1_MEM_BASE + (i * RAM1_BLOCK_SIZE)) << i;
+ }
+ }
+ EMU->RAM1CTRL |= mask;
+#endif
+
+#if defined(RAM2_MEM_END)
+ mask = 0;
+ if (end > RAM2_MEM_END) {
+ for (int i = 0; i < RAM2_BLOCKS; i++) {
+ mask |= ADDRESS_NOT_IN_BLOCK(start, RAM2_MEM_BASE + (i * RAM2_BLOCK_SIZE)) << i;
+ }
+ }
+ EMU->RAM2CTRL |= mask;
+#endif
+}
+
+#if defined(_EMU_EM23PERNORETAINCTRL_MASK)
+/***************************************************************************//**
+ * @brief
+ * Set EM2 3 peripheral retention control.
+ *
+ * @param[in] periMask
+ * Peripheral select mask. Use | operator to select multiple peripheral, for example
+ * @ref emuPeripheralRetention_LEUART0 | @ref emuPeripheralRetention_VDAC0.
+ * @param[in] enable
+ * Peripheral retention enable (true) or disable (false).
+ *
+ *
+ * @note
+ * Only peripheral retention disable is currently supported. Peripherals are
+ * enabled by default, and can only be disabled.
+ ******************************************************************************/
+void EMU_PeripheralRetention(EMU_PeripheralRetention_TypeDef periMask, bool enable)
+{
+ EFM_ASSERT(!enable);
+ EMU->EM23PERNORETAINCTRL = periMask & emuPeripheralRetention_ALL;
+}
+#endif
+
+/***************************************************************************//**
+ * @brief
+ * Update EMU module with CMU oscillator selection/enable status.
+ *
+ * @deprecated
+ * Oscillator status is saved in @ref EMU_EnterEM2() and @ref EMU_EnterEM3().
+ ******************************************************************************/
+void EMU_UpdateOscConfig(void)
+{
+ emState(emState_Save);
+}
+
+#if defined(_EMU_CMD_EM01VSCALE0_MASK)
+/***************************************************************************//**
+ * @brief
+ * Voltage scale in EM0 and 1 by clock frequency.
+ *
+ * @param[in] clockFrequency
+ * Use CMSIS HF clock if 0, or override to custom clock. Providing a
+ * custom clock frequency is required if using a non-standard HFXO
+ * frequency.
+ * @param[in] wait
+ * Wait for scaling to complete.
+ *
+ * @note
+ * This function is primarily needed by the @ref CMU module.
+ ******************************************************************************/
+void EMU_VScaleEM01ByClock(uint32_t clockFrequency, bool wait)
+{
+ uint32_t hfSrcClockFrequency;
+ uint32_t hfPresc = 1U + ((CMU->HFPRESC & _CMU_HFPRESC_PRESC_MASK)
+ >> _CMU_HFPRESC_PRESC_SHIFT);
+
+ /* VSCALE frequency is HFSRCCLK */
+ if (clockFrequency == 0) {
+ hfSrcClockFrequency = SystemHFClockGet() * hfPresc;
+ } else {
+ hfSrcClockFrequency = clockFrequency;
+ }
+
+ /* Apply EM0 and 1 voltage scaling command. */
+ if (vScaleEM01Config.vScaleEM01LowPowerVoltageEnable
+ && (hfSrcClockFrequency < CMU_VSCALEEM01_LOWPOWER_VOLTAGE_CLOCK_MAX)) {
+ EMU_VScaleEM01(emuVScaleEM01_LowPower, wait);
+ } else {
+ EMU_VScaleEM01(emuVScaleEM01_HighPerformance, wait);
+ }
+}
+#endif
+
+#if defined(_EMU_CMD_EM01VSCALE0_MASK)
+/***************************************************************************//**
+ * @brief
+ * Force voltage scaling in EM0 and 1 to a specific voltage level.
+ *
+ * @param[in] voltage
+ * Target VSCALE voltage level.
+ * @param[in] wait
+ * Wait for scaling to complate.
+ *
+ * @note
+ * This function is useful for upscaling before programming Flash from @ref MSC,
+ * and downscaling after programming is done. Flash programming is only supported
+ * at @ref emuVScaleEM01_HighPerformance.
+ *
+ * @note
+ * This function ignores @ref vScaleEM01LowPowerVoltageEnable set from @ref
+ * EMU_EM01Init().
+ ******************************************************************************/
+void EMU_VScaleEM01(EMU_VScaleEM01_TypeDef voltage, bool wait)
+{
+ uint32_t hfSrcClockFrequency;
+ uint32_t hfPresc = 1U + ((CMU->HFPRESC & _CMU_HFPRESC_PRESC_MASK)
+ >> _CMU_HFPRESC_PRESC_SHIFT);
+ uint32_t hfFreq = SystemHFClockGet();
+ EMU_VScaleEM01_TypeDef current = EMU_VScaleGet();
+
+ if (current == voltage) {
+ /* Voltage is already at correct level. */
+ return;
+ }
+
+ hfSrcClockFrequency = hfFreq * hfPresc;
+
+ if (voltage == emuVScaleEM01_LowPower) {
+ EFM_ASSERT(hfSrcClockFrequency <= CMU_VSCALEEM01_LOWPOWER_VOLTAGE_CLOCK_MAX);
+ /* Update wait states before scaling down voltage */
+ CMU_UpdateWaitStates(hfFreq, emuVScaleEM01_LowPower);
+ }
+
+ EMU->CMD = vScaleEM01Cmd(voltage);
+
+ if (voltage == emuVScaleEM01_HighPerformance) {
+ /* Update wait states after scaling up voltage */
+ CMU_UpdateWaitStates(hfFreq, emuVScaleEM01_HighPerformance);
+ }
+
+ if (wait) {
+ EMU_VScaleWait();
+ }
+}
+#endif
+
+#if defined(_EMU_CMD_EM01VSCALE0_MASK)
+/***************************************************************************//**
+ * @brief
+ * Update EMU module with Energy Mode 0 and 1 configuration
+ *
+ * @param[in] em01Init
+ * Energy Mode 0 and 1 configuration structure
+ ******************************************************************************/
+void EMU_EM01Init(const EMU_EM01Init_TypeDef *em01Init)
+{
+ vScaleEM01Config.vScaleEM01LowPowerVoltageEnable =
+ em01Init->vScaleEM01LowPowerVoltageEnable;
+ EMU_VScaleEM01ByClock(0, true);
+}
+#endif
+
+/***************************************************************************//**
+ * @brief
+ * Update EMU module with Energy Mode 2 and 3 configuration
+ *
+ * @param[in] em23Init
+ * Energy Mode 2 and 3 configuration structure
+ ******************************************************************************/
+void EMU_EM23Init(const EMU_EM23Init_TypeDef *em23Init)
+{
+#if defined(_EMU_CTRL_EMVREG_MASK)
+ EMU->CTRL = em23Init->em23VregFullEn ? (EMU->CTRL | EMU_CTRL_EMVREG)
+ : (EMU->CTRL & ~EMU_CTRL_EMVREG);
+#elif defined(_EMU_CTRL_EM23VREG_MASK)
+ EMU->CTRL = em23Init->em23VregFullEn ? (EMU->CTRL | EMU_CTRL_EM23VREG)
+ : (EMU->CTRL & ~EMU_CTRL_EM23VREG);
+#else
+ (void)em23Init;
+#endif
+
+#if defined(_EMU_CTRL_EM23VSCALE_MASK)
+ EMU->CTRL = (EMU->CTRL & ~_EMU_CTRL_EM23VSCALE_MASK)
+ | (em23Init->vScaleEM23Voltage << _EMU_CTRL_EM23VSCALE_SHIFT);
+#endif
+}
+
+#if defined(_EMU_EM4CONF_MASK) || defined(_EMU_EM4CTRL_MASK)
+/***************************************************************************//**
+ * @brief
+ * Update EMU module with Energy Mode 4 configuration
+ *
+ * @param[in] em4Init
+ * Energy Mode 4 configuration structure
+ ******************************************************************************/
+void EMU_EM4Init(const EMU_EM4Init_TypeDef *em4Init)
+{
+#if defined(_EMU_EM4CONF_MASK)
+ /* Init for platforms with EMU->EM4CONF register */
+ uint32_t em4conf = EMU->EM4CONF;
+
+ /* Clear fields that will be reconfigured */
+ em4conf &= ~(_EMU_EM4CONF_LOCKCONF_MASK
+ | _EMU_EM4CONF_OSC_MASK
+ | _EMU_EM4CONF_BURTCWU_MASK
+ | _EMU_EM4CONF_VREGEN_MASK);
+
+ /* Configure new settings */
+ em4conf |= (em4Init->lockConfig << _EMU_EM4CONF_LOCKCONF_SHIFT)
+ | (em4Init->osc)
+ | (em4Init->buRtcWakeup << _EMU_EM4CONF_BURTCWU_SHIFT)
+ | (em4Init->vreg << _EMU_EM4CONF_VREGEN_SHIFT);
+
+ /* Apply configuration. Note that lock can be set after this stage. */
+ EMU->EM4CONF = em4conf;
+
+#elif defined(_EMU_EM4CTRL_MASK)
+ /* Init for platforms with EMU->EM4CTRL register */
+
+ uint32_t em4ctrl = EMU->EM4CTRL;
+
+ em4ctrl &= ~(_EMU_EM4CTRL_RETAINLFXO_MASK
+ | _EMU_EM4CTRL_RETAINLFRCO_MASK
+ | _EMU_EM4CTRL_RETAINULFRCO_MASK
+ | _EMU_EM4CTRL_EM4STATE_MASK
+ | _EMU_EM4CTRL_EM4IORETMODE_MASK);
+
+ em4ctrl |= (em4Init->retainLfxo ? EMU_EM4CTRL_RETAINLFXO : 0)
+ | (em4Init->retainLfrco ? EMU_EM4CTRL_RETAINLFRCO : 0)
+ | (em4Init->retainUlfrco ? EMU_EM4CTRL_RETAINULFRCO : 0)
+ | (em4Init->em4State ? EMU_EM4CTRL_EM4STATE_EM4H : 0)
+ | (em4Init->pinRetentionMode);
+
+ EMU->EM4CTRL = em4ctrl;
+#endif
+
+#if defined(_EMU_CTRL_EM4HVSCALE_MASK)
+ EMU->CTRL = (EMU->CTRL & ~_EMU_CTRL_EM4HVSCALE_MASK)
+ | (em4Init->vScaleEM4HVoltage << _EMU_CTRL_EM4HVSCALE_SHIFT);
+#endif
+}
+#endif
+
+#if defined(BU_PRESENT)
+/***************************************************************************//**
+ * @brief
+ * Configure Backup Power Domain settings
+ *
+ * @param[in] bupdInit
+ * Backup power domain initialization structure
+ ******************************************************************************/
+void EMU_BUPDInit(const EMU_BUPDInit_TypeDef *bupdInit)
+{
+ uint32_t reg;
+
+ /* Set power connection configuration */
+ reg = EMU->PWRCONF & ~(_EMU_PWRCONF_PWRRES_MASK
+ | _EMU_PWRCONF_VOUTSTRONG_MASK
+ | _EMU_PWRCONF_VOUTMED_MASK
+ | _EMU_PWRCONF_VOUTWEAK_MASK);
+
+ reg |= bupdInit->resistor
+ | (bupdInit->voutStrong << _EMU_PWRCONF_VOUTSTRONG_SHIFT)
+ | (bupdInit->voutMed << _EMU_PWRCONF_VOUTMED_SHIFT)
+ | (bupdInit->voutWeak << _EMU_PWRCONF_VOUTWEAK_SHIFT);
+
+ EMU->PWRCONF = reg;
+
+ /* Set backup domain inactive mode configuration */
+ reg = EMU->BUINACT & ~(_EMU_BUINACT_PWRCON_MASK);
+ reg |= (bupdInit->inactivePower);
+ EMU->BUINACT = reg;
+
+ /* Set backup domain active mode configuration */
+ reg = EMU->BUACT & ~(_EMU_BUACT_PWRCON_MASK);
+ reg |= (bupdInit->activePower);
+ EMU->BUACT = reg;
+
+ /* Set power control configuration */
+ reg = EMU->BUCTRL & ~(_EMU_BUCTRL_PROBE_MASK
+ | _EMU_BUCTRL_BODCAL_MASK
+ | _EMU_BUCTRL_STATEN_MASK
+ | _EMU_BUCTRL_EN_MASK);
+
+ /* Note use of ->enable to both enable BUPD, use BU_VIN pin input and
+ release reset */
+ reg |= bupdInit->probe
+ | (bupdInit->bodCal << _EMU_BUCTRL_BODCAL_SHIFT)
+ | (bupdInit->statusPinEnable << _EMU_BUCTRL_STATEN_SHIFT)
+ | (bupdInit->enable << _EMU_BUCTRL_EN_SHIFT);
+
+ /* Enable configuration */
+ EMU->BUCTRL = reg;
+
+ /* If enable is true, enable BU_VIN input power pin, if not disable it */
+ EMU_BUPinEnable(bupdInit->enable);
+
+ /* If enable is true, release BU reset, if not keep reset asserted */
+ BUS_RegBitWrite(&(RMU->CTRL), _RMU_CTRL_BURSTEN_SHIFT, !bupdInit->enable);
+}
+
+/***************************************************************************//**
+ * @brief
+ * Configure Backup Power Domain BOD Threshold value
+ * @note
+ * These values are precalibrated
+ * @param[in] mode Active or Inactive mode
+ * @param[in] value
+ ******************************************************************************/
+void EMU_BUThresholdSet(EMU_BODMode_TypeDef mode, uint32_t value)
+{
+ EFM_ASSERT(value < 8);
+ EFM_ASSERT(value <= (_EMU_BUACT_BUEXTHRES_MASK >> _EMU_BUACT_BUEXTHRES_SHIFT));
+
+ switch (mode) {
+ case emuBODMode_Active:
+ EMU->BUACT = (EMU->BUACT & ~_EMU_BUACT_BUEXTHRES_MASK)
+ | (value << _EMU_BUACT_BUEXTHRES_SHIFT);
+ break;
+ case emuBODMode_Inactive:
+ EMU->BUINACT = (EMU->BUINACT & ~_EMU_BUINACT_BUENTHRES_MASK)
+ | (value << _EMU_BUINACT_BUENTHRES_SHIFT);
+ break;
+ }
+}
+
+/***************************************************************************//**
+ * @brief
+ * Configure Backup Power Domain BOD Threshold Range
+ * @note
+ * These values are precalibrated
+ * @param[in] mode Active or Inactive mode
+ * @param[in] value
+ ******************************************************************************/
+void EMU_BUThresRangeSet(EMU_BODMode_TypeDef mode, uint32_t value)
+{
+ EFM_ASSERT(value < 4);
+ EFM_ASSERT(value <= (_EMU_BUACT_BUEXRANGE_MASK >> _EMU_BUACT_BUEXRANGE_SHIFT));
+
+ switch (mode) {
+ case emuBODMode_Active:
+ EMU->BUACT = (EMU->BUACT & ~_EMU_BUACT_BUEXRANGE_MASK)
+ | (value << _EMU_BUACT_BUEXRANGE_SHIFT);
+ break;
+ case emuBODMode_Inactive:
+ EMU->BUINACT = (EMU->BUINACT & ~_EMU_BUINACT_BUENRANGE_MASK)
+ | (value << _EMU_BUINACT_BUENRANGE_SHIFT);
+ break;
+ }
+}
+#endif
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+#if defined(_EMU_DCDCCTRL_MASK)
+/* Translate fields with different names across platform generations to common names. */
+#if defined(_EMU_DCDCMISCCTRL_LPCMPBIAS_MASK)
+#define _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_MASK _EMU_DCDCMISCCTRL_LPCMPBIAS_MASK
+#define _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT _EMU_DCDCMISCCTRL_LPCMPBIAS_SHIFT
+#elif defined(_EMU_DCDCMISCCTRL_LPCMPBIASEM234H_MASK)
+#define _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_MASK _EMU_DCDCMISCCTRL_LPCMPBIASEM234H_MASK
+#define _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT _EMU_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT
+#endif
+#if defined(_EMU_DCDCLPCTRL_LPCMPHYSSEL_MASK)
+#define _GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK _EMU_DCDCLPCTRL_LPCMPHYSSEL_MASK
+#define _GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_SHIFT _EMU_DCDCLPCTRL_LPCMPHYSSEL_SHIFT
+#elif defined(_EMU_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK)
+#define _GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK _EMU_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK
+#define _GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_SHIFT _EMU_DCDCLPCTRL_LPCMPHYSSELEM234H_SHIFT
+#endif
+
+/* Internal DCDC trim modes. */
+typedef enum {
+ dcdcTrimMode_EM234H_LP = 0,
+#if defined(_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
+ dcdcTrimMode_EM01_LP,
+#endif
+ dcdcTrimMode_LN,
+} dcdcTrimMode_TypeDef;
+
+/***************************************************************************//**
+ * @brief
+ * Load DCDC calibration constants from DI page. Const means calibration
+ * data that does not change depending on other configuration parameters.
+ *
+ * @return
+ * False if calibration registers are locked
+ ******************************************************************************/
+static bool dcdcConstCalibrationLoad(void)
+{
+#if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
+ uint32_t val;
+ volatile uint32_t *reg;
+
+ /* DI calib data in flash */
+ volatile uint32_t* const diCal_EMU_DCDCLNFREQCTRL = (volatile uint32_t *)(0x0FE08038);
+ volatile uint32_t* const diCal_EMU_DCDCLNVCTRL = (volatile uint32_t *)(0x0FE08040);
+ volatile uint32_t* const diCal_EMU_DCDCLPCTRL = (volatile uint32_t *)(0x0FE08048);
+ volatile uint32_t* const diCal_EMU_DCDCLPVCTRL = (volatile uint32_t *)(0x0FE08050);
+ volatile uint32_t* const diCal_EMU_DCDCTRIM0 = (volatile uint32_t *)(0x0FE08058);
+ volatile uint32_t* const diCal_EMU_DCDCTRIM1 = (volatile uint32_t *)(0x0FE08060);
+
+ if (DEVINFO->DCDCLPVCTRL0 != UINT_MAX) {
+ val = *(diCal_EMU_DCDCLNFREQCTRL + 1);
+ reg = (volatile uint32_t *)*diCal_EMU_DCDCLNFREQCTRL;
+ *reg = val;
+
+ val = *(diCal_EMU_DCDCLNVCTRL + 1);
+ reg = (volatile uint32_t *)*diCal_EMU_DCDCLNVCTRL;
+ *reg = val;
+
+ val = *(diCal_EMU_DCDCLPCTRL + 1);
+ reg = (volatile uint32_t *)*diCal_EMU_DCDCLPCTRL;
+ *reg = val;
+
+ val = *(diCal_EMU_DCDCLPVCTRL + 1);
+ reg = (volatile uint32_t *)*diCal_EMU_DCDCLPVCTRL;
+ *reg = val;
+
+ val = *(diCal_EMU_DCDCTRIM0 + 1);
+ reg = (volatile uint32_t *)*diCal_EMU_DCDCTRIM0;
+ *reg = val;
+
+ val = *(diCal_EMU_DCDCTRIM1 + 1);
+ reg = (volatile uint32_t *)*diCal_EMU_DCDCTRIM1;
+ *reg = val;
+
+ return true;
+ }
+ EFM_ASSERT(false);
+ /* Return when assertions are disabled */
+ return false;
+
+#else
+ return true;
+#endif
+}
+
+/***************************************************************************//**
+ * @brief
+ * Set recommended and validated current optimization and timing settings
+ *
+ ******************************************************************************/
+static void dcdcValidatedConfigSet(void)
+{
+/* Disable LP mode hysterysis in the state machine control */
+#define EMU_DCDCMISCCTRL_LPCMPHYSDIS (0x1UL << 1)
+/* Comparator threshold on the high side */
+#define EMU_DCDCMISCCTRL_LPCMPHYSHI (0x1UL << 2)
+#define EMU_DCDCSMCTRL (*(volatile uint32_t *)(EMU_BASE + 0x44))
+
+ uint32_t lnForceCcm;
+
+#if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
+ uint32_t dcdcTiming;
+ SYSTEM_ChipRevision_TypeDef rev;
+#endif
+
+ /* Enable duty cycling of the bias */
+ EMU->DCDCLPCTRL |= EMU_DCDCLPCTRL_LPVREFDUTYEN;
+
+ /* Set low-noise RCO for LNFORCECCM configuration
+ * LNFORCECCM is default 1 for EFR32
+ * LNFORCECCM is default 0 for EFM32
+ */
+ lnForceCcm = BUS_RegBitRead(&EMU->DCDCMISCCTRL, _EMU_DCDCMISCCTRL_LNFORCECCM_SHIFT);
+ if (lnForceCcm) {
+ /* 7MHz is recommended for LNFORCECCM = 1 */
+ EMU_DCDCLnRcoBandSet(emuDcdcLnRcoBand_7MHz);
+ } else {
+ /* 3MHz is recommended for LNFORCECCM = 0 */
+ EMU_DCDCLnRcoBandSet(emuDcdcLnRcoBand_3MHz);
+ }
+
+#if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
+ EMU->DCDCTIMING &= ~_EMU_DCDCTIMING_DUTYSCALE_MASK;
+ EMU->DCDCMISCCTRL |= EMU_DCDCMISCCTRL_LPCMPHYSDIS
+ | EMU_DCDCMISCCTRL_LPCMPHYSHI;
+
+ SYSTEM_ChipRevisionGet(&rev);
+ if ((rev.major == 1)
+ && (rev.minor < 3)
+ && (errataFixDcdcHsState == errataFixDcdcHsInit)) {
+ /* LPCMPWAITDIS = 1 */
+ EMU_DCDCSMCTRL |= 1;
+
+ dcdcTiming = EMU->DCDCTIMING;
+ dcdcTiming &= ~(_EMU_DCDCTIMING_LPINITWAIT_MASK
+ | _EMU_DCDCTIMING_LNWAIT_MASK
+ | _EMU_DCDCTIMING_BYPWAIT_MASK);
+
+ dcdcTiming |= ((180 << _EMU_DCDCTIMING_LPINITWAIT_SHIFT)
+ | (12 << _EMU_DCDCTIMING_LNWAIT_SHIFT)
+ | (180 << _EMU_DCDCTIMING_BYPWAIT_SHIFT));
+ EMU->DCDCTIMING = dcdcTiming;
+
+ errataFixDcdcHsState = errataFixDcdcHsTrimSet;
+ }
+#endif
+}
+
+/***************************************************************************//**
+ * @brief
+ * Compute current limiters:
+ * LNCLIMILIMSEL: LN current limiter threshold
+ * LPCLIMILIMSEL: LP current limiter threshold
+ * DCDCZDETCTRL: zero detector limiter threshold
+ ******************************************************************************/
+static void currentLimitersUpdate(void)
+{
+ uint32_t lncLimSel;
+ uint32_t zdetLimSel;
+ uint32_t pFetCnt;
+ uint16_t maxReverseCurrent_mA;
+
+ /* 80mA as recommended peak in Application Note AN0948.
+ The peak current is the average current plus 50% of the current ripple.
+ Hence, a 14mA average current is recommended in LP mode. Since LP PFETCNT is also
+ a constant, we get lpcLimImSel = 1. The following calculation is provided
+ for documentation only. */
+ const uint32_t lpcLim = (((14 + 40) + ((14 + 40) / 2))
+ / (5 * (DCDC_LP_PFET_CNT + 1)))
+ - 1;
+ const uint32_t lpcLimSel = lpcLim << _EMU_DCDCMISCCTRL_LPCLIMILIMSEL_SHIFT;
+
+ /* Get enabled PFETs */
+ pFetCnt = (EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_PFETCNT_MASK)
+ >> _EMU_DCDCMISCCTRL_PFETCNT_SHIFT;
+
+ /* Compute LN current limiter threshold from nominal user input current and
+ LN PFETCNT as described in the register description for
+ EMU_DCDCMISCCTRL_LNCLIMILIMSEL. */
+ lncLimSel = (((dcdcMaxCurrent_mA + 40) + ((dcdcMaxCurrent_mA + 40) / 2))
+ / (5 * (pFetCnt + 1)))
+ - 1;
+
+ /* Saturate the register field value */
+ lncLimSel = SL_MIN(lncLimSel,
+ _EMU_DCDCMISCCTRL_LNCLIMILIMSEL_MASK
+ >> _EMU_DCDCMISCCTRL_LNCLIMILIMSEL_SHIFT);
+
+ lncLimSel <<= _EMU_DCDCMISCCTRL_LNCLIMILIMSEL_SHIFT;
+
+ /* Check for overflow */
+ EFM_ASSERT((lncLimSel & ~_EMU_DCDCMISCCTRL_LNCLIMILIMSEL_MASK) == 0x0);
+ EFM_ASSERT((lpcLimSel & ~_EMU_DCDCMISCCTRL_LPCLIMILIMSEL_MASK) == 0x0);
+
+ EMU->DCDCMISCCTRL = (EMU->DCDCMISCCTRL & ~(_EMU_DCDCMISCCTRL_LNCLIMILIMSEL_MASK
+ | _EMU_DCDCMISCCTRL_LPCLIMILIMSEL_MASK))
+ | (lncLimSel | lpcLimSel);
+
+ /* Compute reverse current limit threshold for the zero detector from user input
+ maximum reverse current and LN PFETCNT as described in the register description
+ for EMU_DCDCZDETCTRL_ZDETILIMSEL. */
+ if (dcdcReverseCurrentControl >= 0) {
+ /* If dcdcReverseCurrentControl < 0, then EMU_DCDCZDETCTRL_ZDETILIMSEL is "don't care" */
+ maxReverseCurrent_mA = (uint16_t)dcdcReverseCurrentControl;
+
+ zdetLimSel = ( ((maxReverseCurrent_mA + 40) + ((maxReverseCurrent_mA + 40) / 2))
+ / ((2 * (pFetCnt + 1)) + ((pFetCnt + 1) / 2)) );
+ /* Saturate the register field value */
+ zdetLimSel = SL_MIN(zdetLimSel,
+ _EMU_DCDCZDETCTRL_ZDETILIMSEL_MASK
+ >> _EMU_DCDCZDETCTRL_ZDETILIMSEL_SHIFT);
+
+ zdetLimSel <<= _EMU_DCDCZDETCTRL_ZDETILIMSEL_SHIFT;
+
+ /* Check for overflow */
+ EFM_ASSERT((zdetLimSel & ~_EMU_DCDCZDETCTRL_ZDETILIMSEL_MASK) == 0x0);
+
+ EMU->DCDCZDETCTRL = (EMU->DCDCZDETCTRL & ~_EMU_DCDCZDETCTRL_ZDETILIMSEL_MASK)
+ | zdetLimSel;
+ }
+}
+
+/***************************************************************************//**
+ * @brief
+ * Set static variables that hold the user set maximum peak current
+ * and reverse current. Update limiters.
+ *
+ * @param[in] maxCurrent_mA
+ * Set the maximum peak current that the DCDC can draw from the power source.
+ * @param[in] reverseCurrentControl
+ * Reverse current control as defined by
+ * @ref EMU_DcdcLnReverseCurrentControl_TypeDef. Positive values have unit mA.
+ ******************************************************************************/
+static void userCurrentLimitsSet(uint32_t maxCurrent_mA,
+ EMU_DcdcLnReverseCurrentControl_TypeDef reverseCurrentControl)
+{
+ dcdcMaxCurrent_mA = maxCurrent_mA;
+ dcdcReverseCurrentControl = reverseCurrentControl;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Set DCDC low noise compensator control register
+ *
+ * @param[in] comp
+ * Low-noise mode compensator trim setpoint
+ ******************************************************************************/
+static void compCtrlSet(EMU_DcdcLnCompCtrl_TypeDef comp)
+{
+ switch (comp) {
+ case emuDcdcLnCompCtrl_1u0F:
+ EMU->DCDCLNCOMPCTRL = 0x57204077UL;
+ break;
+
+ case emuDcdcLnCompCtrl_4u7F:
+ EMU->DCDCLNCOMPCTRL = 0xB7102137UL;
+ break;
+
+ default:
+ EFM_ASSERT(false);
+ break;
+ }
+}
+
+/***************************************************************************//**
+ * @brief
+ * Load EMU_DCDCLPCTRL_LPCMPHYSSEL depending on LP bias, LP feedback
+ * attenuation and DEVINFOREV.
+ *
+ * @param[in] lpAttenuation
+ * LP feedback attenuation.
+ * @param[in] lpCmpBias
+ * lpCmpBias selection.
+ * @param[in] trimMode
+ * DCDC trim mode.
+ ******************************************************************************/
+static bool lpCmpHystCalibrationLoad(bool lpAttenuation,
+ uint8_t lpCmpBias,
+ dcdcTrimMode_TypeDef trimMode)
+{
+ uint32_t lpcmpHystSel;
+
+ /* Get calib data revision */
+#if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
+ uint8_t devinfoRev = SYSTEM_GetDevinfoRev();
+
+ /* Load LPATT indexed calibration data */
+ if (devinfoRev < 4)
+#else
+ /* Format change not present of newer families. */
+ if (false)
+#endif
+ {
+ lpcmpHystSel = DEVINFO->DCDCLPCMPHYSSEL0;
+
+ if (lpAttenuation) {
+ lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT1_MASK)
+ >> _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT1_SHIFT;
+ } else {
+ lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT0_MASK)
+ >> _DEVINFO_DCDCLPCMPHYSSEL0_LPCMPHYSSELLPATT0_SHIFT;
+ }
+ } else {
+ /* devinfoRev >= 4: load LPCMPBIAS indexed calibration data */
+ lpcmpHystSel = DEVINFO->DCDCLPCMPHYSSEL1;
+ switch (lpCmpBias) {
+ case 0:
+ lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS0_MASK)
+ >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS0_SHIFT;
+ break;
+
+ case 1:
+ lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS1_MASK)
+ >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS1_SHIFT;
+ break;
+
+ case 2:
+ lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS2_MASK)
+ >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS2_SHIFT;
+ break;
+
+ case 3:
+ lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS3_MASK)
+ >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS3_SHIFT;
+ break;
+
+ default:
+ EFM_ASSERT(false);
+ /* Return when assertions are disabled */
+ return false;
+ }
+ }
+
+ /* Set trims */
+ if (trimMode == dcdcTrimMode_EM234H_LP) {
+ /* Make sure the sel value is within the field range. */
+ lpcmpHystSel <<= _GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_SHIFT;
+ if (lpcmpHystSel & ~_GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK) {
+ EFM_ASSERT(false);
+ /* Return when assertions are disabled */
+ return false;
+ }
+ EMU->DCDCLPCTRL = (EMU->DCDCLPCTRL & ~_GENERIC_DCDCLPCTRL_LPCMPHYSSELEM234H_MASK) | lpcmpHystSel;
+ }
+
+#if defined(_EMU_DCDCLPEM01CFG_LPCMPHYSSELEM01_MASK)
+ if (trimMode == dcdcTrimMode_EM01_LP) {
+ /* Make sure the sel value is within the field range. */
+ lpcmpHystSel <<= _EMU_DCDCLPEM01CFG_LPCMPHYSSELEM01_SHIFT;
+ if (lpcmpHystSel & ~_EMU_DCDCLPEM01CFG_LPCMPHYSSELEM01_MASK) {
+ EFM_ASSERT(false);
+ /* Return when assertions are disabled */
+ return false;
+ }
+ EMU->DCDCLPEM01CFG = (EMU->DCDCLPEM01CFG & ~_EMU_DCDCLPEM01CFG_LPCMPHYSSELEM01_MASK) | lpcmpHystSel;
+ }
+#endif
+
+ return true;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Load LPVREF low and high from DEVINFO.
+ *
+ * @param[out] vrefL
+ * LPVREF low from DEVINFO.
+ * @param[out] vrefH
+ * LPVREF high from DEVINFO.
+ * @param[in] lpAttenuation
+ * LP feedback attenuation.
+ * @param[in] lpcmpBias
+ * lpcmpBias to lookup in DEVINFO.
+ ******************************************************************************/
+static void lpGetDevinfoVrefLowHigh(uint32_t *vrefL,
+ uint32_t *vrefH,
+ bool lpAttenuation,
+ uint8_t lpcmpBias)
+{
+ uint32_t vrefLow = 0;
+ uint32_t vrefHigh = 0;
+
+ /* Find VREF high and low in DEVINFO indexed by LPCMPBIAS (lpcmpBias)
+ and LPATT (lpAttenuation) */
+ uint32_t switchVal = (lpcmpBias << 8) | (lpAttenuation ? 1 : 0);
+ switch (switchVal) {
+ case ((0 << 8) | 1):
+ vrefLow = DEVINFO->DCDCLPVCTRL2;
+ vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS0_MASK)
+ >> _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS0_SHIFT;
+ vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS0_MASK)
+ >> _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS0_SHIFT;
+ break;
+
+ case ((1 << 8) | 1):
+ vrefLow = DEVINFO->DCDCLPVCTRL2;
+ vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS1_MASK)
+ >> _DEVINFO_DCDCLPVCTRL2_3V0LPATT1LPCMPBIAS1_SHIFT;
+ vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS1_MASK)
+ >> _DEVINFO_DCDCLPVCTRL2_1V8LPATT1LPCMPBIAS1_SHIFT;
+ break;
+
+ case ((2 << 8) | 1):
+ vrefLow = DEVINFO->DCDCLPVCTRL3;
+ vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS2_MASK)
+ >> _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS2_SHIFT;
+ vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS2_MASK)
+ >> _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS2_SHIFT;
+ break;
+
+ case ((3 << 8) | 1):
+ vrefLow = DEVINFO->DCDCLPVCTRL3;
+ vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS3_MASK)
+ >> _DEVINFO_DCDCLPVCTRL3_3V0LPATT1LPCMPBIAS3_SHIFT;
+ vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS3_MASK)
+ >> _DEVINFO_DCDCLPVCTRL3_1V8LPATT1LPCMPBIAS3_SHIFT;
+ break;
+
+ case ((0 << 8) | 0):
+ vrefLow = DEVINFO->DCDCLPVCTRL0;
+ vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS0_MASK)
+ >> _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS0_SHIFT;
+ vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS0_MASK)
+ >> _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS0_SHIFT;
+ break;
+
+ case ((1 << 8) | 0):
+ vrefLow = DEVINFO->DCDCLPVCTRL0;
+ vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS1_MASK)
+ >> _DEVINFO_DCDCLPVCTRL0_1V8LPATT0LPCMPBIAS1_SHIFT;
+ vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS1_MASK)
+ >> _DEVINFO_DCDCLPVCTRL0_1V2LPATT0LPCMPBIAS1_SHIFT;
+ break;
+
+ case ((2 << 8) | 0):
+ vrefLow = DEVINFO->DCDCLPVCTRL1;
+ vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS2_MASK)
+ >> _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS2_SHIFT;
+ vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS2_MASK)
+ >> _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS2_SHIFT;
+ break;
+
+ case ((3 << 8) | 0):
+ vrefLow = DEVINFO->DCDCLPVCTRL1;
+ vrefHigh = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS3_MASK)
+ >> _DEVINFO_DCDCLPVCTRL1_1V8LPATT0LPCMPBIAS3_SHIFT;
+ vrefLow = (vrefLow & _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS3_MASK)
+ >> _DEVINFO_DCDCLPVCTRL1_1V2LPATT0LPCMPBIAS3_SHIFT;
+ break;
+
+ default:
+ EFM_ASSERT(false);
+ break;
+ }
+ *vrefL = vrefLow;
+ *vrefH = vrefHigh;
+}
+
+/** @endcond */
+
+/***************************************************************************//**
+ * @brief
+ * Set DCDC regulator operating mode
+ *
+ * @param[in] dcdcMode
+ * DCDC mode
+ ******************************************************************************/
+void EMU_DCDCModeSet(EMU_DcdcMode_TypeDef dcdcMode)
+{
+ uint32_t currentDcdcMode;
+
+ /* Wait for any previous write sync to complete and read DCDC mode. */
+ while (EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY) ;
+ currentDcdcMode = (EMU->DCDCCTRL & _EMU_DCDCCTRL_DCDCMODE_MASK);
+
+ /* Enable bypass current limiter when not in bypass mode to prevent
+ excessive current between VREGVDD and DVDD supplies when reentering bypass mode. */
+ if (currentDcdcMode != EMU_DCDCCTRL_DCDCMODE_BYPASS) {
+ BUS_RegBitWrite(&EMU->DCDCCLIMCTRL, _EMU_DCDCCLIMCTRL_BYPLIMEN_SHIFT, 1);
+ }
+
+ if ((EMU_DcdcMode_TypeDef)currentDcdcMode == dcdcMode) {
+ /* Mode already set. If already in bypass, make sure bypass current limiter
+ is disabled. */
+ if (dcdcMode == emuDcdcMode_Bypass) {
+ BUS_RegBitWrite(&EMU->DCDCCLIMCTRL, _EMU_DCDCCLIMCTRL_BYPLIMEN_SHIFT, 0);
+ }
+ return;
+ }
+
+#if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
+
+ /* Fix for errata DCDC_E203 */
+ if ((currentDcdcMode == EMU_DCDCCTRL_DCDCMODE_BYPASS)
+ && (dcdcMode == emuDcdcMode_LowNoise)) {
+ errataFixDcdcHsState = errataFixDcdcHsBypassLn;
+ }
+
+#else
+
+ /* Fix for errata DCDC_E204 */
+ if (((currentDcdcMode == EMU_DCDCCTRL_DCDCMODE_OFF) || (currentDcdcMode == EMU_DCDCCTRL_DCDCMODE_BYPASS))
+ && ((dcdcMode == emuDcdcMode_LowPower) || (dcdcMode == emuDcdcMode_LowNoise))) {
+ /* Always start in LOWNOISE mode and then switch to LOWPOWER mode once LOWNOISE startup is complete. */
+ EMU_IntClear(EMU_IFC_DCDCLNRUNNING);
+ while (EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY) ;
+ EMU->DCDCCTRL = (EMU->DCDCCTRL & ~_EMU_DCDCCTRL_DCDCMODE_MASK) | EMU_DCDCCTRL_DCDCMODE_LOWNOISE;
+ while (!(EMU_IntGet() & EMU_IF_DCDCLNRUNNING)) ;
+ }
+#endif
+
+ /* Set user requested mode. */
+ while (EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY) ;
+ EMU->DCDCCTRL = (EMU->DCDCCTRL & ~_EMU_DCDCCTRL_DCDCMODE_MASK) | dcdcMode;
+
+ /* Disable bypass current limiter after bypass mode is entered.
+ Enable the limiter if any other mode is entered. */
+ while (EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY) ;
+ BUS_RegBitWrite(&EMU->DCDCCLIMCTRL, _EMU_DCDCCLIMCTRL_BYPLIMEN_SHIFT, dcdcMode == emuDcdcMode_Bypass ? 0 : 1);
+}
+
+/***************************************************************************//**
+ * @brief
+ * Set DCDC LN regulator conduction mode
+ *
+ * @param[in] conductionMode
+ * DCDC LN conduction mode.
+ * @param[in] rcoDefaultSet
+ * The default DCDC RCO band for the conductionMode will be used if true.
+ * Otherwise the current RCO configuration is used.
+ ******************************************************************************/
+void EMU_DCDCConductionModeSet(EMU_DcdcConductionMode_TypeDef conductionMode, bool rcoDefaultSet)
+{
+ EMU_DcdcMode_TypeDef currentDcdcMode
+ = (EMU_DcdcMode_TypeDef)(EMU->DCDCCTRL & _EMU_DCDCCTRL_DCDCMODE_MASK);
+ EMU_DcdcLnRcoBand_TypeDef rcoBand
+ = (EMU_DcdcLnRcoBand_TypeDef)((EMU->DCDCLNFREQCTRL & _EMU_DCDCLNFREQCTRL_RCOBAND_MASK)
+ >> _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT);
+
+ /* Set bypass mode and wait for bypass mode to settle before
+ EMU_DCDCMISCCTRL_LNFORCECCM is set. Restore current DCDC mode. */
+ EMU_IntClear(EMU_IFC_DCDCINBYPASS);
+ EMU_DCDCModeSet(emuDcdcMode_Bypass);
+ while (EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY) ;
+ while (!(EMU_IntGet() & EMU_IF_DCDCINBYPASS)) ;
+ if (conductionMode == emuDcdcConductionMode_DiscontinuousLN) {
+ EMU->DCDCMISCCTRL &= ~EMU_DCDCMISCCTRL_LNFORCECCM;
+ if (rcoDefaultSet) {
+ EMU_DCDCLnRcoBandSet(emuDcdcLnRcoBand_3MHz);
+ } else {
+ /* emuDcdcConductionMode_DiscontinuousLN supports up to 4MHz LN RCO. */
+ EFM_ASSERT(rcoBand <= emuDcdcLnRcoBand_4MHz);
+ }
+ } else {
+ EMU->DCDCMISCCTRL |= EMU_DCDCMISCCTRL_LNFORCECCM;
+ if (rcoDefaultSet) {
+ EMU_DCDCLnRcoBandSet(emuDcdcLnRcoBand_7MHz);
+ }
+ }
+ EMU_DCDCModeSet(currentDcdcMode);
+ /* Update slice configuration as it depends on conduction mode and RCO band. */
+ EMU_DCDCOptimizeSlice(dcdcEm01LoadCurrent_mA);
+}
+
+/***************************************************************************//**
+ * @brief
+ * Configure DCDC regulator
+ *
+ * @note
+ * If the power circuit is configured for NODCDC as described in Section
+ * 11.3.4.3 of the Reference Manual, do not call this function. Instead call
+ * EMU_DCDCPowerOff().
+ *
+ * @param[in] dcdcInit
+ * DCDC initialization structure
+ *
+ * @return
+ * True if initialization parameters are valid
+ ******************************************************************************/
+bool EMU_DCDCInit(const EMU_DCDCInit_TypeDef *dcdcInit)
+{
+ uint32_t lpCmpBiasSelEM234H;
+
+#if defined(_EMU_PWRCFG_MASK)
+ /* Set external power configuration. This enables writing to the other
+ DCDC registers. */
+ EMU->PWRCFG = EMU_PWRCFG_PWRCFG_DCDCTODVDD;
+
+ /* EMU->PWRCFG is write-once and POR reset only. Check that
+ we could set the desired power configuration. */
+ if ((EMU->PWRCFG & _EMU_PWRCFG_PWRCFG_MASK) != EMU_PWRCFG_PWRCFG_DCDCTODVDD) {
+ /* If this assert triggers unexpectedly, please power cycle the
+ kit to reset the power configuration. */
+ EFM_ASSERT(false);
+ /* Return when assertions are disabled */
+ return false;
+ }
+#endif
+
+ /* Load DCDC calibration data from the DI page */
+ dcdcConstCalibrationLoad();
+
+ /* Check current parameters */
+ EFM_ASSERT(dcdcInit->maxCurrent_mA <= 200);
+ EFM_ASSERT(dcdcInit->em01LoadCurrent_mA <= dcdcInit->maxCurrent_mA);
+ EFM_ASSERT(dcdcInit->reverseCurrentControl <= 200);
+
+ if (dcdcInit->dcdcMode == emuDcdcMode_LowNoise) {
+ /* DCDC low-noise supports max 200mA */
+ EFM_ASSERT(dcdcInit->em01LoadCurrent_mA <= 200);
+ }
+#if (_SILICON_LABS_GECKO_INTERNAL_SDID != 80)
+ else if (dcdcInit->dcdcMode == emuDcdcMode_LowPower) {
+ /* Up to 10mA is supported for EM01-LP mode. */
+ EFM_ASSERT(dcdcInit->em01LoadCurrent_mA <= 10);
+ }
+#endif
+
+ /* EM2/3/4 current above 10mA is not supported */
+ EFM_ASSERT(dcdcInit->em234LoadCurrent_uA <= 10000);
+
+ if (dcdcInit->em234LoadCurrent_uA < 75) {
+ lpCmpBiasSelEM234H = 0;
+ } else if (dcdcInit->em234LoadCurrent_uA < 500) {
+ lpCmpBiasSelEM234H = 1 << _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT;
+ } else if (dcdcInit->em234LoadCurrent_uA < 2500) {
+ lpCmpBiasSelEM234H = 2 << _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT;
+ } else {
+ lpCmpBiasSelEM234H = 3 << _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT;
+ }
+
+ /* ==== THESE NEXT STEPS ARE STRONGLY ORDER DEPENDENT ==== */
+
+ /* Set DCDC low-power mode comparator bias selection */
+
+ /* 1. Set DCDC low-power mode comparator bias selection and forced CCM
+ => Updates DCDCMISCCTRL_LNFORCECCM */
+ EMU->DCDCMISCCTRL = (EMU->DCDCMISCCTRL & ~(_GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_MASK
+ | _EMU_DCDCMISCCTRL_LNFORCECCM_MASK))
+ | ((uint32_t)lpCmpBiasSelEM234H
+ | (dcdcInit->reverseCurrentControl >= 0
+ ? EMU_DCDCMISCCTRL_LNFORCECCM : 0));
+#if defined(_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
+ /* Only 10mA EM01-LP current is supported */
+ EMU->DCDCLPEM01CFG = (EMU->DCDCLPEM01CFG & ~_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
+ | EMU_DCDCLPEM01CFG_LPCMPBIASEM01_BIAS3;
+#endif
+
+ /* 2. Set recommended and validated current optimization settings
+ <= Depends on LNFORCECCM
+ => Updates DCDCLNFREQCTRL_RCOBAND */
+ dcdcValidatedConfigSet();
+
+ /* 3. Updated static currents and limits user data.
+ Limiters are updated in EMU_DCDCOptimizeSlice() */
+ userCurrentLimitsSet(dcdcInit->maxCurrent_mA,
+ dcdcInit->reverseCurrentControl);
+ dcdcEm01LoadCurrent_mA = dcdcInit->em01LoadCurrent_mA;
+
+ /* 4. Optimize LN slice based on given user input load current
+ <= Depends on DCDCMISCCTRL_LNFORCECCM and DCDCLNFREQCTRL_RCOBAND
+ <= Depends on dcdcInit->maxCurrent_mA and dcdcInit->reverseCurrentControl
+ => Updates DCDCMISCCTRL_P/NFETCNT
+ => Updates DCDCMISCCTRL_LNCLIMILIMSEL and DCDCMISCCTRL_LPCLIMILIMSEL
+ => Updates DCDCZDETCTRL_ZDETILIMSEL */
+ EMU_DCDCOptimizeSlice(dcdcInit->em01LoadCurrent_mA);
+
+ /* ======================================================= */
+
+ /* Set DCDC low noise mode compensator control register. */
+ compCtrlSet(dcdcInit->dcdcLnCompCtrl);
+
+ /* Set DCDC output voltage */
+ if (!EMU_DCDCOutputVoltageSet(dcdcInit->mVout, true, true)) {
+ EFM_ASSERT(false);
+ /* Return when assertions are disabled */
+ return false;
+ }
+
+#if (_SILICON_LABS_GECKO_INTERNAL_SDID == 80)
+ /* Select analog peripheral power supply. This must be done before
+ DCDC mode is set for all EFM32xG1 and EFR32xG1 devices. */
+ BUS_RegBitWrite(&EMU->PWRCTRL,
+ _EMU_PWRCTRL_ANASW_SHIFT,
+ dcdcInit->anaPeripheralPower ? 1 : 0);
+#endif
+
+#if defined(_EMU_PWRCTRL_REGPWRSEL_MASK)
+ /* Select DVDD as input to the digital regulator. The switch to DVDD will take
+ effect once the DCDC output is stable. */
+ EMU->PWRCTRL |= EMU_PWRCTRL_REGPWRSEL_DVDD;
+#endif
+
+ /* Set EM0 DCDC operating mode. Output voltage set in
+ EMU_DCDCOutputVoltageSet() above takes effect if mode
+ is changed from bypass/off mode. */
+ EMU_DCDCModeSet(dcdcInit->dcdcMode);
+
+#if (_SILICON_LABS_GECKO_INTERNAL_SDID != 80)
+ /* Select analog peripheral power supply. This must be done after
+ DCDC mode is set for all devices other than EFM32xG1 and EFR32xG1. */
+ BUS_RegBitWrite(&EMU->PWRCTRL,
+ _EMU_PWRCTRL_ANASW_SHIFT,
+ dcdcInit->anaPeripheralPower ? 1 : 0);
+#endif
+
+ return true;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Set DCDC output voltage
+ *
+ * @param[in] mV
+ * Target DCDC output voltage in mV
+ *
+ * @return
+ * True if the mV parameter is valid
+ ******************************************************************************/
+bool EMU_DCDCOutputVoltageSet(uint32_t mV,
+ bool setLpVoltage,
+ bool setLnVoltage)
+{
+#if defined(_DEVINFO_DCDCLNVCTRL0_3V0LNATT1_MASK)
+
+#define DCDC_TRIM_MODES ((uint8_t)dcdcTrimMode_LN + 1)
+ bool validOutVoltage;
+ bool attenuationSet;
+ uint32_t mVlow = 0;
+ uint32_t mVhigh = 0;
+ uint32_t mVdiff;
+ uint32_t vrefVal[DCDC_TRIM_MODES] = { 0 };
+ uint32_t vrefLow[DCDC_TRIM_MODES] = { 0 };
+ uint32_t vrefHigh[DCDC_TRIM_MODES] = { 0 };
+ uint8_t lpcmpBias[DCDC_TRIM_MODES] = { 0 };
+
+ /* Check that the set voltage is within valid range.
+ Voltages are obtained from the datasheet. */
+ validOutVoltage = ((mV >= PWRCFG_DCDCTODVDD_VMIN)
+ && (mV <= PWRCFG_DCDCTODVDD_VMAX));
+
+ if (!validOutVoltage) {
+ EFM_ASSERT(false);
+ /* Return when assertions are disabled */
+ return false;
+ }
+
+ /* Set attenuation to use and low/high range. */
+ attenuationSet = (mV > 1800);
+ if (attenuationSet) {
+ mVlow = 1800;
+ mVhigh = 3000;
+ mVdiff = mVhigh - mVlow;
+ } else {
+ mVlow = 1200;
+ mVhigh = 1800;
+ mVdiff = mVhigh - mVlow;
+ }
+
+ /* Get 2-point calib data from DEVINFO */
+
+ /* LN mode */
+ if (attenuationSet) {
+ vrefLow[dcdcTrimMode_LN] = DEVINFO->DCDCLNVCTRL0;
+ vrefHigh[dcdcTrimMode_LN] = (vrefLow[dcdcTrimMode_LN] & _DEVINFO_DCDCLNVCTRL0_3V0LNATT1_MASK)
+ >> _DEVINFO_DCDCLNVCTRL0_3V0LNATT1_SHIFT;
+ vrefLow[dcdcTrimMode_LN] = (vrefLow[dcdcTrimMode_LN] & _DEVINFO_DCDCLNVCTRL0_1V8LNATT1_MASK)
+ >> _DEVINFO_DCDCLNVCTRL0_1V8LNATT1_SHIFT;
+ } else {
+ vrefLow[dcdcTrimMode_LN] = DEVINFO->DCDCLNVCTRL0;
+ vrefHigh[dcdcTrimMode_LN] = (vrefLow[dcdcTrimMode_LN] & _DEVINFO_DCDCLNVCTRL0_1V8LNATT0_MASK)
+ >> _DEVINFO_DCDCLNVCTRL0_1V8LNATT0_SHIFT;
+ vrefLow[dcdcTrimMode_LN] = (vrefLow[dcdcTrimMode_LN] & _DEVINFO_DCDCLNVCTRL0_1V2LNATT0_MASK)
+ >> _DEVINFO_DCDCLNVCTRL0_1V2LNATT0_SHIFT;
+ }
+
+ /* LP EM234H mode */
+ lpcmpBias[dcdcTrimMode_EM234H_LP] = (EMU->DCDCMISCCTRL & _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_MASK)
+ >> _GENERIC_DCDCMISCCTRL_LPCMPBIASEM234H_SHIFT;
+ lpGetDevinfoVrefLowHigh(&vrefLow[dcdcTrimMode_EM234H_LP],
+ &vrefHigh[dcdcTrimMode_EM234H_LP],
+ attenuationSet,
+ lpcmpBias[dcdcTrimMode_EM234H_LP]);
+
+#if defined(_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
+ /* LP EM01 mode */
+ lpcmpBias[dcdcTrimMode_EM01_LP] = (EMU->DCDCLPEM01CFG & _EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
+ >> _EMU_DCDCLPEM01CFG_LPCMPBIASEM01_SHIFT;
+ lpGetDevinfoVrefLowHigh(&vrefLow[dcdcTrimMode_EM01_LP],
+ &vrefHigh[dcdcTrimMode_EM01_LP],
+ attenuationSet,
+ lpcmpBias[dcdcTrimMode_EM01_LP]);
+#endif
+
+ /* Calculate output voltage trims */
+ vrefVal[dcdcTrimMode_LN] = ((mV - mVlow) * (vrefHigh[dcdcTrimMode_LN] - vrefLow[dcdcTrimMode_LN]))
+ / mVdiff;
+ vrefVal[dcdcTrimMode_LN] += vrefLow[dcdcTrimMode_LN];
+
+ vrefVal[dcdcTrimMode_EM234H_LP] = ((mV - mVlow) * (vrefHigh[dcdcTrimMode_EM234H_LP] - vrefLow[dcdcTrimMode_EM234H_LP]))
+ / mVdiff;
+ vrefVal[dcdcTrimMode_EM234H_LP] += vrefLow[dcdcTrimMode_EM234H_LP];
+
+#if defined(_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
+ vrefVal[dcdcTrimMode_EM01_LP] = ((mV - mVlow) * (vrefHigh[dcdcTrimMode_EM01_LP] - vrefLow[dcdcTrimMode_EM01_LP]))
+ / mVdiff;
+ vrefVal[dcdcTrimMode_EM01_LP] += vrefLow[dcdcTrimMode_EM01_LP];
+#endif
+
+ /* Range checks */
+ if ((vrefVal[dcdcTrimMode_LN] > vrefHigh[dcdcTrimMode_LN])
+ || (vrefVal[dcdcTrimMode_LN] < vrefLow[dcdcTrimMode_LN])
+#if defined(_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
+ || (vrefVal[dcdcTrimMode_EM01_LP] > vrefHigh[dcdcTrimMode_EM01_LP])
+ || (vrefVal[dcdcTrimMode_EM01_LP] < vrefLow[dcdcTrimMode_EM01_LP])
+#endif
+ || (vrefVal[dcdcTrimMode_EM234H_LP] > vrefHigh[dcdcTrimMode_EM234H_LP])
+ || (vrefVal[dcdcTrimMode_EM234H_LP] < vrefLow[dcdcTrimMode_EM234H_LP])) {
+ EFM_ASSERT(false);
+ /* Return when assertions are disabled */
+ return false;
+ }
+
+ /* Update output voltage tuning for LN and LP modes. */
+ if (setLnVoltage) {
+ EMU->DCDCLNVCTRL = (EMU->DCDCLNVCTRL & ~(_EMU_DCDCLNVCTRL_LNVREF_MASK | _EMU_DCDCLNVCTRL_LNATT_MASK))
+ | (vrefVal[dcdcTrimMode_LN] << _EMU_DCDCLNVCTRL_LNVREF_SHIFT)
+ | (attenuationSet ? EMU_DCDCLNVCTRL_LNATT : 0);
+ }
+
+ if (setLpVoltage) {
+ /* Load LP EM234H comparator hysteresis calibration */
+ if (!(lpCmpHystCalibrationLoad(attenuationSet, lpcmpBias[dcdcTrimMode_EM234H_LP], dcdcTrimMode_EM234H_LP))) {
+ EFM_ASSERT(false);
+ /* Return when assertions are disabled */
+ return false;
+ }
+
+#if defined(_EMU_DCDCLPEM01CFG_LPCMPBIASEM01_MASK)
+ /* Load LP EM234H comparator hysteresis calibration */
+ if (!(lpCmpHystCalibrationLoad(attenuationSet, lpcmpBias[dcdcTrimMode_EM01_LP], dcdcTrimMode_EM01_LP))) {
+ EFM_ASSERT(false);
+ /* Return when assertions are disabled */
+ return false;
+ }
+
+ /* LP VREF is that max of trims for EM01 and EM234H. */
+ vrefVal[dcdcTrimMode_EM234H_LP] = SL_MAX(vrefVal[dcdcTrimMode_EM234H_LP], vrefVal[dcdcTrimMode_EM01_LP]);
+#endif
+
+ /* Don't exceed max available code as specified in the reference manual for EMU_DCDCLPVCTRL. */
+ vrefVal[dcdcTrimMode_EM234H_LP] = SL_MIN(vrefVal[dcdcTrimMode_EM234H_LP], 0xE7U);
+ EMU->DCDCLPVCTRL = (EMU->DCDCLPVCTRL & ~(_EMU_DCDCLPVCTRL_LPVREF_MASK | _EMU_DCDCLPVCTRL_LPATT_MASK))
+ | (vrefVal[dcdcTrimMode_EM234H_LP] << _EMU_DCDCLPVCTRL_LPVREF_SHIFT)
+ | (attenuationSet ? EMU_DCDCLPVCTRL_LPATT : 0);
+ }
+#endif
+ return true;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Optimize DCDC slice count based on the estimated average load current
+ * in EM0
+ *
+ * @param[in] em0LoadCurrent_mA
+ * Estimated average EM0 load current in mA.
+ ******************************************************************************/
+void EMU_DCDCOptimizeSlice(uint32_t em0LoadCurrent_mA)
+{
+ uint32_t sliceCount = 0;
+ uint32_t rcoBand = (EMU->DCDCLNFREQCTRL & _EMU_DCDCLNFREQCTRL_RCOBAND_MASK)
+ >> _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT;
+
+ /* Set recommended slice count */
+ if ((EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK) && (rcoBand >= emuDcdcLnRcoBand_5MHz)) {
+ if (em0LoadCurrent_mA < 20) {
+ sliceCount = 4;
+ } else if ((em0LoadCurrent_mA >= 20) && (em0LoadCurrent_mA < 40)) {
+ sliceCount = 8;
+ } else {
+ sliceCount = 16;
+ }
+ } else if ((!(EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK)) && (rcoBand <= emuDcdcLnRcoBand_4MHz)) {
+ if (em0LoadCurrent_mA < 10) {
+ sliceCount = 4;
+ } else if ((em0LoadCurrent_mA >= 10) && (em0LoadCurrent_mA < 20)) {
+ sliceCount = 8;
+ } else {
+ sliceCount = 16;
+ }
+ } else if ((EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK) && (rcoBand <= emuDcdcLnRcoBand_4MHz)) {
+ if (em0LoadCurrent_mA < 40) {
+ sliceCount = 8;
+ } else {
+ sliceCount = 16;
+ }
+ } else {
+ /* This configuration is not recommended. EMU_DCDCInit() applies a recommended
+ configuration. */
+ EFM_ASSERT(false);
+ }
+
+ /* The selected slices are PSLICESEL + 1 */
+ sliceCount--;
+
+ /* Apply slice count to both N and P slice */
+ sliceCount = (sliceCount << _EMU_DCDCMISCCTRL_PFETCNT_SHIFT
+ | sliceCount << _EMU_DCDCMISCCTRL_NFETCNT_SHIFT);
+ EMU->DCDCMISCCTRL = (EMU->DCDCMISCCTRL & ~(_EMU_DCDCMISCCTRL_PFETCNT_MASK
+ | _EMU_DCDCMISCCTRL_NFETCNT_MASK))
+ | sliceCount;
+
+ /* Update current limiters */
+ currentLimitersUpdate();
+}
+
+/***************************************************************************//**
+ * @brief
+ * Set DCDC Low-noise RCO band.
+ *
+ * @param[in] band
+ * RCO band to set.
+ ******************************************************************************/
+void EMU_DCDCLnRcoBandSet(EMU_DcdcLnRcoBand_TypeDef band)
+{
+ uint32_t forcedCcm;
+ forcedCcm = BUS_RegBitRead(&EMU->DCDCMISCCTRL, _EMU_DCDCMISCCTRL_LNFORCECCM_SHIFT);
+
+ /* DCM mode supports up to 4MHz LN RCO. */
+ EFM_ASSERT((!forcedCcm && band <= emuDcdcLnRcoBand_4MHz) || forcedCcm);
+
+ EMU->DCDCLNFREQCTRL = (EMU->DCDCLNFREQCTRL & ~_EMU_DCDCLNFREQCTRL_RCOBAND_MASK)
+ | (band << _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT);
+
+ /* Update slice configuration as this depends on the RCO band. */
+ EMU_DCDCOptimizeSlice(dcdcEm01LoadCurrent_mA);
+}
+
+/***************************************************************************//**
+ * @brief
+ * Power off the DCDC regulator.
+ *
+ * @details
+ * This function powers off the DCDC controller. This function should only be
+ * used if the external power circuit is wired for no DCDC. If the external power
+ * circuit is wired for DCDC usage, then use EMU_DCDCInit() and set the
+ * DCDC in bypass mode to disable DCDC.
+ *
+ * @return
+ * Return false if the DCDC could not be disabled.
+ ******************************************************************************/
+bool EMU_DCDCPowerOff(void)
+{
+ bool dcdcModeSet;
+
+#if defined(_EMU_PWRCFG_MASK)
+ /* Set DCDCTODVDD only to enable write access to EMU->DCDCCTRL */
+ EMU->PWRCFG = EMU_PWRCFG_PWRCFG_DCDCTODVDD;
+#endif
+
+ /* Select DVDD as input to the digital regulator */
+#if defined(EMU_PWRCTRL_IMMEDIATEPWRSWITCH)
+ EMU->PWRCTRL |= EMU_PWRCTRL_REGPWRSEL_DVDD | EMU_PWRCTRL_IMMEDIATEPWRSWITCH;
+#elif defined(EMU_PWRCTRL_REGPWRSEL_DVDD)
+ EMU->PWRCTRL |= EMU_PWRCTRL_REGPWRSEL_DVDD;
+#endif
+
+ /* Set DCDC to OFF and disable LP in EM2/3/4. Verify that the required
+ mode could be set. */
+ while (EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY) ;
+ EMU->DCDCCTRL = EMU_DCDCCTRL_DCDCMODE_OFF;
+
+ dcdcModeSet = (EMU->DCDCCTRL == EMU_DCDCCTRL_DCDCMODE_OFF);
+ EFM_ASSERT(dcdcModeSet);
+
+ return dcdcModeSet;
+}
+#endif
+
+#if defined(EMU_STATUS_VMONRDY)
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+
+/***************************************************************************//**
+ * @brief
+ * Get calibrated threshold value.
+ *
+ * @details
+ * All VMON channels have two calibration fields in the DI page that
+ * describes the threshold at 1.86V and 2.98V. This function will convert
+ * the uncalibrated input voltage threshold in millivolts into a calibrated
+ * threshold.
+ *
+ * @param[in] channel
+ * VMON channel
+ *
+ * @param[in] threshold
+ * Desired threshold in millivolts.
+ *
+ * @return
+ * Calibrated threshold value to use. First digit of return value is placed
+ * in the "fine" register fields while the next digits are placed in the
+ * "coarse" register fields.
+ ******************************************************************************/
+static uint32_t vmonCalibratedThreshold(EMU_VmonChannel_TypeDef channel,
+ int threshold)
+{
+ uint32_t tLow;
+ uint32_t tHigh;
+ uint32_t calReg;
+
+ /* Get calibration values for 1.86V and 2.98V */
+ switch (channel) {
+ case emuVmonChannel_AVDD:
+ calReg = DEVINFO->VMONCAL0;
+ tLow = (10 * ((calReg & _DEVINFO_VMONCAL0_AVDD1V86THRESCOARSE_MASK)
+ >> _DEVINFO_VMONCAL0_AVDD1V86THRESCOARSE_SHIFT))
+ + ((calReg & _DEVINFO_VMONCAL0_AVDD1V86THRESFINE_MASK)
+ >> _DEVINFO_VMONCAL0_AVDD1V86THRESFINE_SHIFT);
+ tHigh = (10 * ((calReg & _DEVINFO_VMONCAL0_AVDD2V98THRESCOARSE_MASK)
+ >> _DEVINFO_VMONCAL0_AVDD2V98THRESCOARSE_SHIFT))
+ + ((calReg & _DEVINFO_VMONCAL0_AVDD2V98THRESFINE_MASK)
+ >> _DEVINFO_VMONCAL0_AVDD2V98THRESFINE_SHIFT);
+ break;
+ case emuVmonChannel_ALTAVDD:
+ calReg = DEVINFO->VMONCAL0;
+ tLow = (10 * ((calReg & _DEVINFO_VMONCAL0_ALTAVDD1V86THRESCOARSE_MASK)
+ >> _DEVINFO_VMONCAL0_ALTAVDD1V86THRESCOARSE_SHIFT))
+ + ((calReg & _DEVINFO_VMONCAL0_ALTAVDD1V86THRESFINE_MASK)
+ >> _DEVINFO_VMONCAL0_ALTAVDD1V86THRESFINE_SHIFT);
+ tHigh = (10 * ((calReg & _DEVINFO_VMONCAL0_ALTAVDD2V98THRESCOARSE_MASK)
+ >> _DEVINFO_VMONCAL0_ALTAVDD2V98THRESCOARSE_SHIFT))
+ + ((calReg & _DEVINFO_VMONCAL0_ALTAVDD2V98THRESFINE_MASK)
+ >> _DEVINFO_VMONCAL0_ALTAVDD2V98THRESFINE_SHIFT);
+ break;
+ case emuVmonChannel_DVDD:
+ calReg = DEVINFO->VMONCAL1;
+ tLow = (10 * ((calReg & _DEVINFO_VMONCAL1_DVDD1V86THRESCOARSE_MASK)
+ >> _DEVINFO_VMONCAL1_DVDD1V86THRESCOARSE_SHIFT))
+ + ((calReg & _DEVINFO_VMONCAL1_DVDD1V86THRESFINE_MASK)
+ >> _DEVINFO_VMONCAL1_DVDD1V86THRESFINE_SHIFT);
+ tHigh = (10 * ((calReg & _DEVINFO_VMONCAL1_DVDD2V98THRESCOARSE_MASK)
+ >> _DEVINFO_VMONCAL1_DVDD2V98THRESCOARSE_SHIFT))
+ + ((calReg & _DEVINFO_VMONCAL1_DVDD2V98THRESFINE_MASK)
+ >> _DEVINFO_VMONCAL1_DVDD2V98THRESFINE_SHIFT);
+ break;
+ case emuVmonChannel_IOVDD0:
+ calReg = DEVINFO->VMONCAL1;
+ tLow = (10 * ((calReg & _DEVINFO_VMONCAL1_IO01V86THRESCOARSE_MASK)
+ >> _DEVINFO_VMONCAL1_IO01V86THRESCOARSE_SHIFT))
+ + ((calReg & _DEVINFO_VMONCAL1_IO01V86THRESFINE_MASK)
+ >> _DEVINFO_VMONCAL1_IO01V86THRESFINE_SHIFT);
+ tHigh = (10 * ((calReg & _DEVINFO_VMONCAL1_IO02V98THRESCOARSE_MASK)
+ >> _DEVINFO_VMONCAL1_IO02V98THRESCOARSE_SHIFT))
+ + ((calReg & _DEVINFO_VMONCAL1_IO02V98THRESFINE_MASK)
+ >> _DEVINFO_VMONCAL1_IO02V98THRESFINE_SHIFT);
+ break;
+ default:
+ EFM_ASSERT(false);
+ return threshold;
+ }
+
+ if (tHigh <= tLow) {
+ /* Uncalibrated device guard */
+ return threshold;
+ }
+
+ /* Calculate threshold.
+ *
+ * Note that volt is used in the reference manual, however we are interested
+ * in millivolt results. We also increase the precision of Va and Vb in the
+ * calculation instead of using floating points.
+ */
+ uint32_t va = (1120 * 100) / (tHigh - tLow);
+ uint32_t vb = (1860 * 100) - (va * tLow);
+ /* Round threshold to nearest integer value. */
+ return ((threshold * 100) - vb + (va / 2)) / va;
+}
+
+/** @endcond */
+
+/***************************************************************************//**
+ * @brief
+ * Initialize VMON channel.
+ *
+ * @details
+ * Initialize a VMON channel without hysteresis. If the channel supports
+ * separate rise and fall triggers, both thresholds will be set to the same
+ * value. The threshold will be converted to a register field value based
+ * on calibration values from the DI page.
+ *
+ * @param[in] vmonInit
+ * VMON initialization struct
+ ******************************************************************************/
+void EMU_VmonInit(const EMU_VmonInit_TypeDef *vmonInit)
+{
+ uint32_t thresholdCoarse, thresholdFine;
+ uint32_t threshold;
+
+ EFM_ASSERT((vmonInit->threshold >= 1620) && (vmonInit->threshold <= 3400));
+
+ threshold = vmonCalibratedThreshold(vmonInit->channel, vmonInit->threshold);
+ thresholdFine = threshold % 10;
+ thresholdCoarse = threshold / 10;
+
+ /* Saturate threshold to max values. */
+ if (thresholdCoarse > 0xF) {
+ thresholdCoarse = 0xF;
+ thresholdFine = 9;
+ }
+
+ switch (vmonInit->channel) {
+ case emuVmonChannel_AVDD:
+ EMU->VMONAVDDCTRL = (thresholdCoarse << _EMU_VMONAVDDCTRL_RISETHRESCOARSE_SHIFT)
+ | (thresholdFine << _EMU_VMONAVDDCTRL_RISETHRESFINE_SHIFT)
+ | (thresholdCoarse << _EMU_VMONAVDDCTRL_FALLTHRESCOARSE_SHIFT)
+ | (thresholdFine << _EMU_VMONAVDDCTRL_FALLTHRESFINE_SHIFT)
+ | (vmonInit->riseWakeup ? EMU_VMONAVDDCTRL_RISEWU : 0)
+ | (vmonInit->fallWakeup ? EMU_VMONAVDDCTRL_FALLWU : 0)
+ | (vmonInit->enable ? EMU_VMONAVDDCTRL_EN : 0);
+ break;
+ case emuVmonChannel_ALTAVDD:
+ EMU->VMONALTAVDDCTRL = (thresholdCoarse << _EMU_VMONALTAVDDCTRL_THRESCOARSE_SHIFT)
+ | (thresholdFine << _EMU_VMONALTAVDDCTRL_THRESFINE_SHIFT)
+ | (vmonInit->riseWakeup ? EMU_VMONALTAVDDCTRL_RISEWU : 0)
+ | (vmonInit->fallWakeup ? EMU_VMONALTAVDDCTRL_FALLWU : 0)
+ | (vmonInit->enable ? EMU_VMONALTAVDDCTRL_EN : 0);
+ break;
+ case emuVmonChannel_DVDD:
+ EMU->VMONDVDDCTRL = (thresholdCoarse << _EMU_VMONDVDDCTRL_THRESCOARSE_SHIFT)
+ | (thresholdFine << _EMU_VMONDVDDCTRL_THRESFINE_SHIFT)
+ | (vmonInit->riseWakeup ? EMU_VMONDVDDCTRL_RISEWU : 0)
+ | (vmonInit->fallWakeup ? EMU_VMONDVDDCTRL_FALLWU : 0)
+ | (vmonInit->enable ? EMU_VMONDVDDCTRL_EN : 0);
+ break;
+ case emuVmonChannel_IOVDD0:
+ EMU->VMONIO0CTRL = (thresholdCoarse << _EMU_VMONIO0CTRL_THRESCOARSE_SHIFT)
+ | (thresholdFine << _EMU_VMONIO0CTRL_THRESFINE_SHIFT)
+ | (vmonInit->retDisable ? EMU_VMONIO0CTRL_RETDIS : 0)
+ | (vmonInit->riseWakeup ? EMU_VMONIO0CTRL_RISEWU : 0)
+ | (vmonInit->fallWakeup ? EMU_VMONIO0CTRL_FALLWU : 0)
+ | (vmonInit->enable ? EMU_VMONIO0CTRL_EN : 0);
+ break;
+ default:
+ EFM_ASSERT(false);
+ return;
+ }
+}
+
+/***************************************************************************//**
+ * @brief
+ * Initialize VMON channel with hysteresis (separate rise and fall triggers).
+ *
+ * @details
+ * Initialize a VMON channel which supports hysteresis. The AVDD channel is
+ * the only channel to support separate rise and fall triggers. The rise and
+ * fall thresholds will be converted to a register field value based on
+ * calibration values from the DI page.
+ *
+ * @param[in] vmonInit
+ * VMON Hysteresis initialization struct
+ ******************************************************************************/
+void EMU_VmonHystInit(const EMU_VmonHystInit_TypeDef *vmonInit)
+{
+ uint32_t riseThreshold;
+ uint32_t fallThreshold;
+
+ /* VMON supports voltages between 1620 mV and 3400 mV (inclusive) */
+ EFM_ASSERT((vmonInit->riseThreshold >= 1620) && (vmonInit->riseThreshold <= 3400));
+ EFM_ASSERT((vmonInit->fallThreshold >= 1620) && (vmonInit->fallThreshold <= 3400));
+ /* Fall threshold has to be lower than rise threshold */
+ EFM_ASSERT(vmonInit->fallThreshold <= vmonInit->riseThreshold);
+
+ riseThreshold = vmonCalibratedThreshold(vmonInit->channel, vmonInit->riseThreshold);
+ fallThreshold = vmonCalibratedThreshold(vmonInit->channel, vmonInit->fallThreshold);
+
+ switch (vmonInit->channel) {
+ case emuVmonChannel_AVDD:
+ EMU->VMONAVDDCTRL = ((riseThreshold / 10) << _EMU_VMONAVDDCTRL_RISETHRESCOARSE_SHIFT)
+ | ((riseThreshold % 10) << _EMU_VMONAVDDCTRL_RISETHRESFINE_SHIFT)
+ | ((fallThreshold / 10) << _EMU_VMONAVDDCTRL_FALLTHRESCOARSE_SHIFT)
+ | ((fallThreshold % 10) << _EMU_VMONAVDDCTRL_FALLTHRESFINE_SHIFT)
+ | (vmonInit->riseWakeup ? EMU_VMONAVDDCTRL_RISEWU : 0)
+ | (vmonInit->fallWakeup ? EMU_VMONAVDDCTRL_FALLWU : 0)
+ | (vmonInit->enable ? EMU_VMONAVDDCTRL_EN : 0);
+ break;
+ default:
+ EFM_ASSERT(false);
+ return;
+ }
+}
+
+/***************************************************************************//**
+ * @brief
+ * Enable or disable a VMON channel
+ *
+ * @param[in] channel
+ * VMON channel to enable/disable
+ *
+ * @param[in] enable
+ * Whether to enable or disable
+ ******************************************************************************/
+void EMU_VmonEnable(EMU_VmonChannel_TypeDef channel, bool enable)
+{
+ uint32_t volatile * reg;
+ uint32_t bit;
+
+ switch (channel) {
+ case emuVmonChannel_AVDD:
+ reg = &(EMU->VMONAVDDCTRL);
+ bit = _EMU_VMONAVDDCTRL_EN_SHIFT;
+ break;
+ case emuVmonChannel_ALTAVDD:
+ reg = &(EMU->VMONALTAVDDCTRL);
+ bit = _EMU_VMONALTAVDDCTRL_EN_SHIFT;
+ break;
+ case emuVmonChannel_DVDD:
+ reg = &(EMU->VMONDVDDCTRL);
+ bit = _EMU_VMONDVDDCTRL_EN_SHIFT;
+ break;
+ case emuVmonChannel_IOVDD0:
+ reg = &(EMU->VMONIO0CTRL);
+ bit = _EMU_VMONIO0CTRL_EN_SHIFT;
+ break;
+ default:
+ EFM_ASSERT(false);
+ return;
+ }
+
+ BUS_RegBitWrite(reg, bit, enable);
+}
+
+/***************************************************************************//**
+ * @brief
+ * Get the status of a voltage monitor channel.
+ *
+ * @param[in] channel
+ * VMON channel to get status for
+ *
+ * @return
+ * Status of the selected VMON channel. True if channel is triggered.
+ ******************************************************************************/
+bool EMU_VmonChannelStatusGet(EMU_VmonChannel_TypeDef channel)
+{
+ uint32_t bit;
+ switch (channel) {
+ case emuVmonChannel_AVDD:
+ bit = _EMU_STATUS_VMONAVDD_SHIFT;
+ break;
+ case emuVmonChannel_ALTAVDD:
+ bit = _EMU_STATUS_VMONALTAVDD_SHIFT;
+ break;
+ case emuVmonChannel_DVDD:
+ bit = _EMU_STATUS_VMONDVDD_SHIFT;
+ break;
+ case emuVmonChannel_IOVDD0:
+ bit = _EMU_STATUS_VMONIO0_SHIFT;
+ break;
+ default:
+ EFM_ASSERT(false);
+ bit = 0;
+ }
+
+ return BUS_RegBitRead(&EMU->STATUS, bit);
+}
+#endif /* EMU_STATUS_VMONRDY */
+
+#if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_80)
+/***************************************************************************//**
+ * @brief
+ * Adjust the bias refresh rate
+ *
+ * @details
+ * This function is only meant to be used under high-temperature operation on
+ * EFR32xG1 and EFM32xG1 devices. Adjusting the bias mode will
+ * increase the typical current consumption. See application note 1027
+ * and errata documents for further details.
+ *
+ * @param [in] mode
+ * The new bias refresh rate
+ ******************************************************************************/
+void EMU_SetBiasMode(EMU_BiasMode_TypeDef mode)
+{
+#define EMU_TESTLOCK (*(volatile uint32_t *) (EMU_BASE + 0x190))
+#define EMU_BIASCONF (*(volatile uint32_t *) (EMU_BASE + 0x164))
+#define EMU_BIASTESTCTRL (*(volatile uint32_t *) (EMU_BASE + 0x19C))
+#define CMU_ULFRCOCTRL (*(volatile uint32_t *) (CMU_BASE + 0x03C))
+
+ uint32_t freq = 0x2u;
+ bool emuTestLocked = false;
+
+ if (mode == emuBiasMode_1KHz) {
+ freq = 0x0u;
+ }
+
+ if (EMU_TESTLOCK == 0x1u) {
+ emuTestLocked = true;
+ EMU_TESTLOCK = 0xADE8u;
+ }
+
+ if (mode == emuBiasMode_Continuous) {
+ EMU_BIASCONF &= ~0x74u;
+ } else {
+ EMU_BIASCONF |= 0x74u;
+ }
+
+ EMU_BIASTESTCTRL |= 0x8u;
+ CMU_ULFRCOCTRL = (CMU_ULFRCOCTRL & ~0xC00u)
+ | ((freq & 0x3u) << 10u);
+ EMU_BIASTESTCTRL &= ~0x8u;
+
+ if (emuTestLocked) {
+ EMU_TESTLOCK = 0u;
+ }
+}
+#endif
+
+/** @} (end addtogroup EMU) */
+/** @} (end addtogroup emlib) */
+#endif /* __EM_EMU_H */
diff --git a/efm32/emlib/em_gpio.c b/efm32/emlib/em_gpio.c
new file mode 100644
index 0000000..3b1d146
--- /dev/null
+++ b/efm32/emlib/em_gpio.c
@@ -0,0 +1,367 @@
+/***************************************************************************//**
+ * @file em_gpio.c
+ * @brief General Purpose IO (GPIO) peripheral API
+ * devices.
+ * @version 5.2.2
+ *******************************************************************************
+ * # License
+ * Copyright 2016 Silicon Laboratories, Inc. http://www.silabs.com
+ *******************************************************************************
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
+ * obligation to support this Software. Silicon Labs is providing the
+ * Software "AS IS", with no express or implied warranties of any kind,
+ * including, but not limited to, any implied warranties of merchantability
+ * or fitness for any particular purpose or warranties against infringement
+ * of any proprietary rights of a third party.
+ *
+ * Silicon Labs will not be liable for any consequential, incidental, or
+ * special damages, or any other relief, or for any claim by any third party,
+ * arising from your use of this Software.
+ *
+ ******************************************************************************/
+
+#include "em_gpio.h"
+
+#if defined(GPIO_COUNT) && (GPIO_COUNT > 0)
+
+/***************************************************************************//**
+ * @addtogroup emlib
+ * @{
+ ******************************************************************************/
+
+/***************************************************************************//**
+ * @addtogroup GPIO
+ * @brief General Purpose Input/Output (GPIO) API
+ * @details
+ * This module contains functions to control the GPIO peripheral of Silicon
+ * Labs 32-bit MCUs and SoCs. The GPIO peripheral is used for pin configuration
+ * and direct pin manipulation and sensing as well as routing for peripheral
+ * pin connections.
+ * @{
+ ******************************************************************************/
+
+/*******************************************************************************
+ ******************************* DEFINES ***********************************
+ ******************************************************************************/
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+
+/** Validation of pin typically usable in assert statements. */
+#define GPIO_DRIVEMODE_VALID(mode) ((mode) <= 3)
+#define GPIO_STRENGHT_VALID(strenght) (!((strenght) \
+ & ~(_GPIO_P_CTRL_DRIVESTRENGTH_MASK \
+ | _GPIO_P_CTRL_DRIVESTRENGTHALT_MASK)))
+/** @endcond */
+
+/*******************************************************************************
+ ************************** GLOBAL FUNCTIONS *******************************
+ ******************************************************************************/
+
+/***************************************************************************//**
+ * @brief
+ * Sets the pin location of the debug pins (Serial Wire interface).
+ *
+ * @note
+ * Changing the pins used for debugging uncontrolled, may result in a lockout.
+ *
+ * @param[in] location
+ * The debug pin location to use (0-3).
+ ******************************************************************************/
+void GPIO_DbgLocationSet(unsigned int location)
+{
+#if defined (_GPIO_ROUTE_SWLOCATION_MASK)
+ EFM_ASSERT(location < AFCHANLOC_MAX);
+
+ GPIO->ROUTE = (GPIO->ROUTE & ~_GPIO_ROUTE_SWLOCATION_MASK)
+ | (location << _GPIO_ROUTE_SWLOCATION_SHIFT);
+#else
+ (void)location;
+#endif
+}
+
+#if defined (_GPIO_P_CTRL_DRIVEMODE_MASK)
+/***************************************************************************//**
+ * @brief
+ * Sets the drive mode for a GPIO port.
+ *
+ * @param[in] port
+ * The GPIO port to access.
+ *
+ * @param[in] mode
+ * Drive mode to use for port.
+ ******************************************************************************/
+void GPIO_DriveModeSet(GPIO_Port_TypeDef port, GPIO_DriveMode_TypeDef mode)
+{
+ EFM_ASSERT(GPIO_PORT_VALID(port) && GPIO_DRIVEMODE_VALID(mode));
+
+ GPIO->P[port].CTRL = (GPIO->P[port].CTRL & ~(_GPIO_P_CTRL_DRIVEMODE_MASK))
+ | (mode << _GPIO_P_CTRL_DRIVEMODE_SHIFT);
+}
+#endif
+
+#if defined (_GPIO_P_CTRL_DRIVESTRENGTH_MASK)
+/***************************************************************************//**
+ * @brief
+ * Sets the drive strength for a GPIO port.
+ *
+ * @param[in] port
+ * The GPIO port to access.
+ *
+ * @param[in] strength
+ * Drive strength to use for port.
+ ******************************************************************************/
+void GPIO_DriveStrengthSet(GPIO_Port_TypeDef port,
+ GPIO_DriveStrength_TypeDef strength)
+{
+ EFM_ASSERT(GPIO_PORT_VALID(port) && GPIO_STRENGHT_VALID(strength));
+ BUS_RegMaskedWrite(&GPIO->P[port].CTRL,
+ _GPIO_P_CTRL_DRIVESTRENGTH_MASK | _GPIO_P_CTRL_DRIVESTRENGTHALT_MASK,
+ strength);
+}
+#endif
+
+/***************************************************************************//**
+ * @brief
+ * Configure GPIO external pin interrupt.
+ *
+ * @details
+ * If reconfiguring a GPIO interrupt that is already enabled, it is generally
+ * recommended to disable it first, see GPIO_Disable().
+ *
+ * The actual GPIO interrupt handler must be in place before enabling the
+ * interrupt.
+ *
+ * Notice that any pending interrupt for the selected interrupt is cleared
+ * by this function.
+ *
+ * @note
+ * On series 0 devices the pin number parameter is not used. The
+ * pin number used on these devices is hardwired to the interrupt with the
+ * same number. @n
+ * On series 1 devices, pin number can be selected freely within a group.
+ * Interrupt numbers are divided into 4 groups (intNo / 4) and valid pin
+ * number within the interrupt groups are:
+ * 0: pins 0-3
+ * 1: pins 4-7
+ * 2: pins 8-11
+ * 3: pins 12-15
+ *
+ * @param[in] port
+ * The port to associate with @p pin.
+ *
+ * @param[in] pin
+ * The pin number on the port.
+ *
+ * @param[in] intNo
+ * The interrupt number to trigger.
+ *
+ * @param[in] risingEdge
+ * Set to true if interrupts shall be enabled on rising edge, otherwise false.
+ *
+ * @param[in] fallingEdge
+ * Set to true if interrupts shall be enabled on falling edge, otherwise false.
+ *
+ * @param[in] enable
+ * Set to true if interrupt shall be enabled after configuration completed,
+ * false to leave disabled. See GPIO_IntDisable() and GPIO_IntEnable().
+ ******************************************************************************/
+void GPIO_ExtIntConfig(GPIO_Port_TypeDef port,
+ unsigned int pin,
+ unsigned int intNo,
+ bool risingEdge,
+ bool fallingEdge,
+ bool enable)
+{
+ uint32_t tmp = 0;
+#if !defined(_GPIO_EXTIPINSELL_MASK)
+ (void)pin;
+#endif
+
+ EFM_ASSERT(GPIO_PORT_PIN_VALID(port, pin));
+#if defined(_GPIO_EXTIPINSELL_MASK)
+ EFM_ASSERT(GPIO_INTNO_PIN_VALID(intNo, pin));
+#endif
+
+ /* There are two registers controlling the interrupt configuration:
+ * The EXTIPSELL register controls pins 0-7 and EXTIPSELH controls
+ * pins 8-15. */
+ if (intNo < 8) {
+ BUS_RegMaskedWrite(&GPIO->EXTIPSELL,
+ _GPIO_EXTIPSELL_EXTIPSEL0_MASK
+ << (_GPIO_EXTIPSELL_EXTIPSEL1_SHIFT * intNo),
+ port << (_GPIO_EXTIPSELL_EXTIPSEL1_SHIFT * intNo));
+ } else {
+ tmp = intNo - 8;
+ BUS_RegMaskedWrite(&GPIO->EXTIPSELH,
+ _GPIO_EXTIPSELH_EXTIPSEL8_MASK
+ << (_GPIO_EXTIPSELH_EXTIPSEL9_SHIFT * tmp),
+ port << (_GPIO_EXTIPSELH_EXTIPSEL9_SHIFT * tmp));
+ }
+
+#if defined(_GPIO_EXTIPINSELL_MASK)
+ /* There are two registers controlling the interrupt/pin number mapping:
+ * The EXTIPINSELL register controls interrupt 0-7 and EXTIPINSELH controls
+ * interrupt 8-15. */
+ if (intNo < 8) {
+ BUS_RegMaskedWrite(&GPIO->EXTIPINSELL,
+ _GPIO_EXTIPINSELL_EXTIPINSEL0_MASK
+ << (_GPIO_EXTIPINSELL_EXTIPINSEL1_SHIFT * intNo),
+ ((pin % 4) & _GPIO_EXTIPINSELL_EXTIPINSEL0_MASK)
+ << (_GPIO_EXTIPINSELL_EXTIPINSEL1_SHIFT * intNo));
+ } else {
+ BUS_RegMaskedWrite(&GPIO->EXTIPINSELH,
+ _GPIO_EXTIPINSELH_EXTIPINSEL8_MASK
+ << (_GPIO_EXTIPINSELH_EXTIPINSEL9_SHIFT * tmp),
+ ((pin % 4) & _GPIO_EXTIPINSELH_EXTIPINSEL8_MASK)
+ << (_GPIO_EXTIPSELH_EXTIPSEL9_SHIFT * tmp));
+ }
+#endif
+
+ /* Enable/disable rising edge */
+ BUS_RegBitWrite(&(GPIO->EXTIRISE), intNo, risingEdge);
+
+ /* Enable/disable falling edge */
+ BUS_RegBitWrite(&(GPIO->EXTIFALL), intNo, fallingEdge);
+
+ /* Clear any pending interrupt */
+ GPIO->IFC = 1 << intNo;
+
+ /* Finally enable/disable interrupt */
+ BUS_RegBitWrite(&(GPIO->IEN), intNo, enable);
+}
+
+/***************************************************************************//**
+ * @brief
+ * Set the mode for a GPIO pin.
+ *
+ * @param[in] port
+ * The GPIO port to access.
+ *
+ * @param[in] pin
+ * The pin number in the port.
+ *
+ * @param[in] mode
+ * The desired pin mode.
+ *
+ * @param[in] out
+ * Value to set for pin in DOUT register. The DOUT setting is important for
+ * even some input mode configurations, determining pull-up/down direction.
+ ******************************************************************************/
+void GPIO_PinModeSet(GPIO_Port_TypeDef port,
+ unsigned int pin,
+ GPIO_Mode_TypeDef mode,
+ unsigned int out)
+{
+ EFM_ASSERT(GPIO_PORT_PIN_VALID(port, pin));
+
+ /* If disabling pin, do not modify DOUT in order to reduce chance for */
+ /* glitch/spike (may not be sufficient precaution in all use cases) */
+ if (mode != gpioModeDisabled) {
+ if (out) {
+ GPIO_PinOutSet(port, pin);
+ } else {
+ GPIO_PinOutClear(port, pin);
+ }
+ }
+
+ /* There are two registers controlling the pins for each port. The MODEL
+ * register controls pins 0-7 and MODEH controls pins 8-15. */
+ if (pin < 8) {
+ GPIO->P[port].MODEL = (GPIO->P[port].MODEL & ~(0xFu << (pin * 4)))
+ | (mode << (pin * 4));
+ } else {
+ GPIO->P[port].MODEH = (GPIO->P[port].MODEH & ~(0xFu << ((pin - 8) * 4)))
+ | (mode << ((pin - 8) * 4));
+ }
+
+ if (mode == gpioModeDisabled) {
+ if (out) {
+ GPIO_PinOutSet(port, pin);
+ } else {
+ GPIO_PinOutClear(port, pin);
+ }
+ }
+}
+
+/***************************************************************************//**
+ * @brief
+ * Get the mode for a GPIO pin.
+ *
+ * @param[in] port
+ * The GPIO port to access.
+ *
+ * @param[in] pin
+ * The pin number in the port.
+ *
+ * @return
+ * The pin mode.
+ ******************************************************************************/
+GPIO_Mode_TypeDef GPIO_PinModeGet(GPIO_Port_TypeDef port,
+ unsigned int pin)
+{
+ EFM_ASSERT(GPIO_PORT_PIN_VALID(port, pin));
+
+ if (pin < 8) {
+ return (GPIO_Mode_TypeDef) ((GPIO->P[port].MODEL >> (pin * 4)) & 0xF);
+ } else {
+ return (GPIO_Mode_TypeDef) ((GPIO->P[port].MODEH >> ((pin - 8) * 4)) & 0xF);
+ }
+}
+
+#if defined(_GPIO_EM4WUEN_MASK)
+/**************************************************************************//**
+ * @brief
+ * Enable GPIO pin wake-up from EM4. When the function exits,
+ * EM4 mode can be safely entered.
+ *
+ * @note
+ * It is assumed that the GPIO pin modes are set correctly.
+ * Valid modes are @ref gpioModeInput and @ref gpioModeInputPull.
+ *
+ * @param[in] pinmask
+ * Bitmask containing the bitwise logic OR of which GPIO pin(s) to enable.
+ * Refer to Reference Manuals for pinmask to GPIO port/pin mapping.
+ * @param[in] polaritymask
+ * Bitmask containing the bitwise logic OR of GPIO pin(s) wake-up polarity.
+ * Refer to Reference Manuals for pinmask to GPIO port/pin mapping.
+ *****************************************************************************/
+void GPIO_EM4EnablePinWakeup(uint32_t pinmask, uint32_t polaritymask)
+{
+ EFM_ASSERT((pinmask & ~_GPIO_EM4WUEN_MASK) == 0);
+
+#if defined(_GPIO_EM4WUPOL_MASK)
+ EFM_ASSERT((polaritymask & ~_GPIO_EM4WUPOL_MASK) == 0);
+ GPIO->EM4WUPOL &= ~pinmask; /* Set wakeup polarity */
+ GPIO->EM4WUPOL |= pinmask & polaritymask;
+#elif defined(_GPIO_EXTILEVEL_MASK)
+ EFM_ASSERT((polaritymask & ~_GPIO_EXTILEVEL_MASK) == 0);
+ GPIO->EXTILEVEL &= ~pinmask;
+ GPIO->EXTILEVEL |= pinmask & polaritymask;
+#endif
+ GPIO->EM4WUEN |= pinmask; /* Enable wakeup */
+
+ GPIO_EM4SetPinRetention(true); /* Enable pin retention */
+
+#if defined(_GPIO_CMD_EM4WUCLR_MASK)
+ GPIO->CMD = GPIO_CMD_EM4WUCLR; /* Clear wake-up logic */
+#elif defined(_GPIO_IFC_EM4WU_MASK)
+ GPIO_IntClear(pinmask);
+#endif
+}
+#endif
+
+/** @} (end addtogroup GPIO) */
+/** @} (end addtogroup emlib) */
+
+#endif /* defined(GPIO_COUNT) && (GPIO_COUNT > 0) */
diff --git a/efm32/emlib/em_system.c b/efm32/emlib/em_system.c
new file mode 100644
index 0000000..6877ac4
--- /dev/null
+++ b/efm32/emlib/em_system.c
@@ -0,0 +1,114 @@
+/***************************************************************************//**
+ * @file em_system.c
+ * @brief System Peripheral API
+ * @version 5.2.2
+ *******************************************************************************
+ * # License
+ * Copyright 2016 Silicon Laboratories, Inc. http://www.silabs.com
+ *******************************************************************************
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
+ * obligation to support this Software. Silicon Labs is providing the
+ * Software "AS IS", with no express or implied warranties of any kind,
+ * including, but not limited to, any implied warranties of merchantability
+ * or fitness for any particular purpose or warranties against infringement
+ * of any proprietary rights of a third party.
+ *
+ * Silicon Labs will not be liable for any consequential, incidental, or
+ * special damages, or any other relief, or for any claim by any third party,
+ * arising from your use of this Software.
+ *
+ ******************************************************************************/
+
+#include "em_system.h"
+#include "em_assert.h"
+#include
+
+/***************************************************************************//**
+ * @addtogroup emlib
+ * @{
+ ******************************************************************************/
+
+/***************************************************************************//**
+ * @addtogroup SYSTEM
+ * @{
+ ******************************************************************************/
+
+/*******************************************************************************
+ ************************** GLOBAL FUNCTIONS *******************************
+ ******************************************************************************/
+
+/***************************************************************************//**
+ * @brief
+ * Get chip major/minor revision.
+ *
+ * @param[out] rev
+ * Location to place chip revision info.
+ ******************************************************************************/
+void SYSTEM_ChipRevisionGet(SYSTEM_ChipRevision_TypeDef *rev)
+{
+ uint8_t tmp;
+
+ EFM_ASSERT(rev);
+
+ /* CHIP FAMILY bit [5:2] */
+ tmp = (((ROMTABLE->PID1 & _ROMTABLE_PID1_FAMILYMSB_MASK) >> _ROMTABLE_PID1_FAMILYMSB_SHIFT) << 2);
+ /* CHIP FAMILY bit [1:0] */
+ tmp |= ((ROMTABLE->PID0 & _ROMTABLE_PID0_FAMILYLSB_MASK) >> _ROMTABLE_PID0_FAMILYLSB_SHIFT);
+ rev->family = tmp;
+
+ /* CHIP MAJOR bit [3:0] */
+ rev->major = (ROMTABLE->PID0 & _ROMTABLE_PID0_REVMAJOR_MASK) >> _ROMTABLE_PID0_REVMAJOR_SHIFT;
+
+ /* CHIP MINOR bit [7:4] */
+ tmp = (((ROMTABLE->PID2 & _ROMTABLE_PID2_REVMINORMSB_MASK) >> _ROMTABLE_PID2_REVMINORMSB_SHIFT) << 4);
+ /* CHIP MINOR bit [3:0] */
+ tmp |= ((ROMTABLE->PID3 & _ROMTABLE_PID3_REVMINORLSB_MASK) >> _ROMTABLE_PID3_REVMINORLSB_SHIFT);
+ rev->minor = tmp;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Get factory calibration value for a given peripheral register.
+ *
+ * @param[in] regAddress
+ * Peripheral calibration register address to get calibration value for. If
+ * a calibration value is found then this register is updated with the
+ * calibration value.
+ *
+ * @return
+ * True if a calibration value exists, false otherwise.
+ ******************************************************************************/
+bool SYSTEM_GetCalibrationValue(volatile uint32_t *regAddress)
+{
+ SYSTEM_CalAddrVal_TypeDef * p, * end;
+
+ p = (SYSTEM_CalAddrVal_TypeDef *)(DEVINFO_BASE & 0xFFFFF000);
+ end = (SYSTEM_CalAddrVal_TypeDef *)DEVINFO_BASE;
+
+ for (; p < end; p++) {
+ if (p->address == 0xFFFFFFFF) {
+ /* Found table terminator */
+ return false;
+ }
+ if (p->address == (uint32_t)regAddress) {
+ *regAddress = p->calValue;
+ return true;
+ }
+ }
+ /* Nothing found for regAddress */
+ return false;
+}
+
+/** @} (end addtogroup SYSTEM) */
+/** @} (end addtogroup emlib) */
diff --git a/efm32/emlib/em_timer.c b/efm32/emlib/em_timer.c
new file mode 100644
index 0000000..6999d6a
--- /dev/null
+++ b/efm32/emlib/em_timer.c
@@ -0,0 +1,253 @@
+/***************************************************************************//**
+ * @file em_timer.c
+ * @brief Timer/counter (TIMER) Peripheral API
+ * @version 5.2.2
+ *******************************************************************************
+ * # License
+ * Copyright 2016 Silicon Laboratories, Inc. http://www.silabs.com
+ *******************************************************************************
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
+ * obligation to support this Software. Silicon Labs is providing the
+ * Software "AS IS", with no express or implied warranties of any kind,
+ * including, but not limited to, any implied warranties of merchantability
+ * or fitness for any particular purpose or warranties against infringement
+ * of any proprietary rights of a third party.
+ *
+ * Silicon Labs will not be liable for any consequential, incidental, or
+ * special damages, or any other relief, or for any claim by any third party,
+ * arising from your use of this Software.
+ *
+ ******************************************************************************/
+
+#include "em_timer.h"
+#if defined(TIMER_COUNT) && (TIMER_COUNT > 0)
+
+#include "em_assert.h"
+
+/***************************************************************************//**
+ * @addtogroup emlib
+ * @{
+ ******************************************************************************/
+
+/***************************************************************************//**
+ * @addtogroup TIMER
+ * @brief Timer/Counter (TIMER) Peripheral API
+ * @details
+ * The timer module consists of three main parts:
+ * @li General timer config and enable control.
+ * @li Compare/capture control.
+ * @li Dead time insertion control (may not be available for all timers).
+ * @{
+ ******************************************************************************/
+
+/*******************************************************************************
+ ************************** GLOBAL FUNCTIONS *******************************
+ ******************************************************************************/
+
+/***************************************************************************//**
+ * @brief
+ * Initialize TIMER.
+ *
+ * @details
+ * Notice that counter top must be configured separately with for instance
+ * TIMER_TopSet(). In addition, compare/capture and dead-time insertion
+ * init must be initialized separately if used. That should probably
+ * be done prior to the use of this function if configuring the TIMER to
+ * start when initialization is completed.
+ *
+ * @param[in] timer
+ * Pointer to TIMER peripheral register block.
+ *
+ * @param[in] init
+ * Pointer to TIMER initialization structure.
+ ******************************************************************************/
+void TIMER_Init(TIMER_TypeDef *timer, const TIMER_Init_TypeDef *init)
+{
+ EFM_ASSERT(TIMER_REF_VALID(timer));
+
+ /* Stop timer if specified to be disabled (dosn't hurt if already stopped) */
+ if (!(init->enable)) {
+ timer->CMD = TIMER_CMD_STOP;
+ }
+
+ /* Reset counter */
+ timer->CNT = _TIMER_CNT_RESETVALUE;
+
+ timer->CTRL = ((uint32_t)(init->prescale) << _TIMER_CTRL_PRESC_SHIFT)
+ | ((uint32_t)(init->clkSel) << _TIMER_CTRL_CLKSEL_SHIFT)
+ | ((uint32_t)(init->fallAction) << _TIMER_CTRL_FALLA_SHIFT)
+ | ((uint32_t)(init->riseAction) << _TIMER_CTRL_RISEA_SHIFT)
+ | ((uint32_t)(init->mode) << _TIMER_CTRL_MODE_SHIFT)
+ | (init->debugRun ? TIMER_CTRL_DEBUGRUN : 0)
+ | (init->dmaClrAct ? TIMER_CTRL_DMACLRACT : 0)
+ | (init->quadModeX4 ? TIMER_CTRL_QDM_X4 : 0)
+ | (init->oneShot ? TIMER_CTRL_OSMEN : 0)
+
+#if defined(TIMER_CTRL_X2CNT) && defined(TIMER_CTRL_ATI)
+ | (init->count2x ? TIMER_CTRL_X2CNT : 0)
+ | (init->ati ? TIMER_CTRL_ATI : 0)
+#endif
+ | (init->sync ? TIMER_CTRL_SYNC : 0);
+
+ /* Start timer if specified to be enabled (dosn't hurt if already started) */
+ if (init->enable) {
+ timer->CMD = TIMER_CMD_START;
+ }
+}
+
+/***************************************************************************//**
+ * @brief
+ * Initialize TIMER compare/capture channel.
+ *
+ * @details
+ * Notice that if operating channel in compare mode, the CCV and CCVB register
+ * must be set separately as required.
+ *
+ * @param[in] timer
+ * Pointer to TIMER peripheral register block.
+ *
+ * @param[in] ch
+ * Compare/capture channel to init for.
+ *
+ * @param[in] init
+ * Pointer to TIMER initialization structure.
+ ******************************************************************************/
+void TIMER_InitCC(TIMER_TypeDef *timer,
+ unsigned int ch,
+ const TIMER_InitCC_TypeDef *init)
+{
+ EFM_ASSERT(TIMER_REF_VALID(timer));
+ EFM_ASSERT(TIMER_CH_VALID(ch));
+
+ timer->CC[ch].CTRL =
+ ((uint32_t)(init->eventCtrl) << _TIMER_CC_CTRL_ICEVCTRL_SHIFT)
+ | ((uint32_t)(init->edge) << _TIMER_CC_CTRL_ICEDGE_SHIFT)
+ | ((uint32_t)(init->prsSel) << _TIMER_CC_CTRL_PRSSEL_SHIFT)
+ | ((uint32_t)(init->cufoa) << _TIMER_CC_CTRL_CUFOA_SHIFT)
+ | ((uint32_t)(init->cofoa) << _TIMER_CC_CTRL_COFOA_SHIFT)
+ | ((uint32_t)(init->cmoa) << _TIMER_CC_CTRL_CMOA_SHIFT)
+ | ((uint32_t)(init->mode) << _TIMER_CC_CTRL_MODE_SHIFT)
+ | (init->filter ? TIMER_CC_CTRL_FILT_ENABLE : 0)
+ | (init->prsInput ? TIMER_CC_CTRL_INSEL_PRS : 0)
+ | (init->coist ? TIMER_CC_CTRL_COIST : 0)
+ | (init->outInvert ? TIMER_CC_CTRL_OUTINV : 0);
+}
+
+#if defined(_TIMER_DTCTRL_MASK)
+/***************************************************************************//**
+ * @brief
+ * Initialize the TIMER DTI unit.
+ *
+ * @param[in] timer
+ * Pointer to TIMER peripheral register block.
+ *
+ * @param[in] init
+ * Pointer to TIMER DTI initialization structure.
+ ******************************************************************************/
+void TIMER_InitDTI(TIMER_TypeDef *timer, const TIMER_InitDTI_TypeDef *init)
+{
+ EFM_ASSERT(TIMER0 == timer);
+
+ /* Make sure the DTI unit is disabled while initializing. */
+ TIMER_EnableDTI(timer, false);
+
+ /* Setup the DTCTRL register.
+ The enable bit will be set at the end of the function if specified. */
+ timer->DTCTRL =
+ (init->autoRestart ? TIMER_DTCTRL_DTDAS : 0)
+ | (init->activeLowOut ? TIMER_DTCTRL_DTIPOL : 0)
+ | (init->invertComplementaryOut ? TIMER_DTCTRL_DTCINV : 0)
+ | (init->enablePrsSource ? TIMER_DTCTRL_DTPRSEN : 0)
+ | ((uint32_t)(init->prsSel) << _TIMER_DTCTRL_DTPRSSEL_SHIFT);
+
+ /* Setup the DTTIME register. */
+ timer->DTTIME =
+ ((uint32_t)(init->prescale) << _TIMER_DTTIME_DTPRESC_SHIFT)
+ | ((uint32_t)(init->riseTime) << _TIMER_DTTIME_DTRISET_SHIFT)
+ | ((uint32_t)(init->fallTime) << _TIMER_DTTIME_DTFALLT_SHIFT);
+
+ /* Setup the DTFC register. */
+ timer->DTFC =
+ (init->enableFaultSourceCoreLockup ? TIMER_DTFC_DTLOCKUPFEN : 0)
+ | (init->enableFaultSourceDebugger ? TIMER_DTFC_DTDBGFEN : 0)
+ | (init->enableFaultSourcePrsSel0 ? TIMER_DTFC_DTPRS0FEN : 0)
+ | (init->enableFaultSourcePrsSel1 ? TIMER_DTFC_DTPRS1FEN : 0)
+ | ((uint32_t)(init->faultAction) << _TIMER_DTFC_DTFA_SHIFT)
+ | ((uint32_t)(init->faultSourcePrsSel0) << _TIMER_DTFC_DTPRS0FSEL_SHIFT)
+ | ((uint32_t)(init->faultSourcePrsSel1) << _TIMER_DTFC_DTPRS1FSEL_SHIFT);
+
+ /* Setup the DTOGEN register. */
+ timer->DTOGEN = init->outputsEnableMask;
+
+ /* Clear any previous DTI faults. */
+ TIMER_ClearDTIFault(timer, TIMER_GetDTIFault(timer));
+
+ /* Enable/disable before returning. */
+ TIMER_EnableDTI(timer, init->enable);
+}
+#endif
+
+/***************************************************************************//**
+ * @brief
+ * Reset TIMER to same state as after a HW reset.
+ *
+ * @note
+ * The ROUTE register is NOT reset by this function, in order to allow for
+ * centralized setup of this feature.
+ *
+ * @param[in] timer
+ * Pointer to TIMER peripheral register block.
+ ******************************************************************************/
+void TIMER_Reset(TIMER_TypeDef *timer)
+{
+ int i;
+
+ EFM_ASSERT(TIMER_REF_VALID(timer));
+
+ /* Make sure disabled first, before resetting other registers */
+ timer->CMD = TIMER_CMD_STOP;
+
+ timer->CTRL = _TIMER_CTRL_RESETVALUE;
+ timer->IEN = _TIMER_IEN_RESETVALUE;
+ timer->IFC = _TIMER_IFC_MASK;
+ timer->TOPB = _TIMER_TOPB_RESETVALUE;
+ /* Write TOP after TOPB to invalidate TOPB (clear TIMER_STATUS_TOPBV) */
+ timer->TOP = _TIMER_TOP_RESETVALUE;
+ timer->CNT = _TIMER_CNT_RESETVALUE;
+ /* Do not reset route register, setting should be done independently */
+ /* (Note: ROUTE register may be locked by DTLOCK register.) */
+
+ for (i = 0; TIMER_CH_VALID(i); i++) {
+ timer->CC[i].CTRL = _TIMER_CC_CTRL_RESETVALUE;
+ timer->CC[i].CCV = _TIMER_CC_CCV_RESETVALUE;
+ timer->CC[i].CCVB = _TIMER_CC_CCVB_RESETVALUE;
+ }
+
+ /* Reset dead time insertion module, no effect on timers without DTI */
+
+#if defined(TIMER_DTLOCK_LOCKKEY_UNLOCK)
+ /* Unlock DTI registers first in case locked */
+ timer->DTLOCK = TIMER_DTLOCK_LOCKKEY_UNLOCK;
+
+ timer->DTCTRL = _TIMER_DTCTRL_RESETVALUE;
+ timer->DTTIME = _TIMER_DTTIME_RESETVALUE;
+ timer->DTFC = _TIMER_DTFC_RESETVALUE;
+ timer->DTOGEN = _TIMER_DTOGEN_RESETVALUE;
+ timer->DTFAULTC = _TIMER_DTFAULTC_MASK;
+#endif
+}
+
+/** @} (end addtogroup TIMER) */
+/** @} (end addtogroup emlib) */
+#endif /* defined(TIMER_COUNT) && (TIMER_COUNT > 0) */
diff --git a/efm32/emlib/em_usart.c b/efm32/emlib/em_usart.c
new file mode 100644
index 0000000..3a5e65c
--- /dev/null
+++ b/efm32/emlib/em_usart.c
@@ -0,0 +1,1161 @@
+/***************************************************************************//**
+ * @file em_usart.c
+ * @brief Universal synchronous/asynchronous receiver/transmitter (USART/UART)
+ * Peripheral API
+ * @version 5.2.2
+ *******************************************************************************
+ * # License
+ * Copyright 2016 Silicon Laboratories, Inc. http://www.silabs.com
+ *******************************************************************************
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
+ * obligation to support this Software. Silicon Labs is providing the
+ * Software "AS IS", with no express or implied warranties of any kind,
+ * including, but not limited to, any implied warranties of merchantability
+ * or fitness for any particular purpose or warranties against infringement
+ * of any proprietary rights of a third party.
+ *
+ * Silicon Labs will not be liable for any consequential, incidental, or
+ * special damages, or any other relief, or for any claim by any third party,
+ * arising from your use of this Software.
+ *
+ ******************************************************************************/
+
+#include "em_usart.h"
+#if defined(USART_COUNT) && (USART_COUNT > 0)
+
+#include "em_cmu.h"
+#include "em_bus.h"
+#include "em_assert.h"
+
+/***************************************************************************//**
+ * @addtogroup emlib
+ * @{
+ ******************************************************************************/
+
+/***************************************************************************//**
+ * @addtogroup USART
+ * @{
+ ******************************************************************************/
+
+/*******************************************************************************
+ ******************************* DEFINES ***********************************
+ ******************************************************************************/
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+
+/** Validation of USART register block pointer reference for assert statements. */
+#if (USART_COUNT == 1) && defined(USART0)
+#define USART_REF_VALID(ref) ((ref) == USART0)
+
+#elif (USART_COUNT == 1) && defined(USART1)
+#define USART_REF_VALID(ref) ((ref) == USART1)
+
+#elif (USART_COUNT == 2) && defined(USART2)
+#define USART_REF_VALID(ref) (((ref) == USART1) || ((ref) == USART2))
+
+#elif (USART_COUNT == 2)
+#define USART_REF_VALID(ref) (((ref) == USART0) || ((ref) == USART1))
+
+#elif (USART_COUNT == 3)
+#define USART_REF_VALID(ref) (((ref) == USART0) || ((ref) == USART1) \
+ || ((ref) == USART2))
+#elif (USART_COUNT == 4)
+#define USART_REF_VALID(ref) (((ref) == USART0) || ((ref) == USART1) \
+ || ((ref) == USART2) || ((ref) == USART3))
+#elif (USART_COUNT == 5)
+#define USART_REF_VALID(ref) (((ref) == USART0) || ((ref) == USART1) \
+ || ((ref) == USART2) || ((ref) == USART3) \
+ || ((ref) == USART4))
+#elif (USART_COUNT == 6)
+#define USART_REF_VALID(ref) (((ref) == USART0) || ((ref) == USART1) \
+ || ((ref) == USART2) || ((ref) == USART3) \
+ || ((ref) == USART4) || ((ref) == USART5))
+#else
+#error "Undefined number of USARTs."
+#endif
+
+#if defined(USARTRF_COUNT) && (USARTRF_COUNT > 0)
+#if (USARTRF_COUNT == 1) && defined(USARTRF0)
+#define USARTRF_REF_VALID(ref) ((ref) == USARTRF0)
+#elif (USARTRF_COUNT == 1) && defined(USARTRF1)
+#define USARTRF_REF_VALID(ref) ((ref) == USARTRF1)
+#else
+#define USARTRF_REF_VALID(ref) (0)
+#endif
+#else
+#define USARTRF_REF_VALID(ref) (0)
+#endif
+
+#if defined(_EZR32_HAPPY_FAMILY)
+#define USART_IRDA_VALID(ref) ((ref) == USART0)
+#elif defined(_EFM32_HAPPY_FAMILY)
+#define USART_IRDA_VALID(ref) (((ref) == USART0) || ((ref) == USART1))
+#elif defined(USART0)
+#define USART_IRDA_VALID(ref) ((ref) == USART0)
+#elif (USART_COUNT == 1) && defined(USART1)
+#define USART_IRDA_VALID(ref) ((ref) == USART1)
+#elif defined(USARTRF0)
+#define USART_IRDA_VALID(ref) ((ref) == USARTRF0)
+#else
+#define USART_IRDA_VALID(ref) (0)
+#endif
+
+#if defined(_SILICON_LABS_32B_SERIES_1)
+ #if defined(USART3)
+ #define USART_I2S_VALID(ref) (((ref) == USART1) || ((ref) == USART3))
+ #else
+ #define USART_I2S_VALID(ref) ((ref) == USART1)
+ #endif
+#elif defined(_SILICON_LABS_32B_SERIES_0)
+ #if defined(_EZR32_HAPPY_FAMILY)
+ #define USART_I2S_VALID(ref) ((ref) == USART0)
+ #elif defined(_EFM32_HAPPY_FAMILY)
+ #define USART_I2S_VALID(ref) (((ref) == USART0) || ((ref) == USART1))
+ #elif defined(_EFM32_TINY_FAMILY) || defined(_EFM32_ZERO_FAMILY)
+ #define USART_I2S_VALID(ref) ((ref) == USART1)
+ #elif defined(_EFM32_GIANT_FAMILY) || defined(_EFM32_WONDER_FAMILY)
+ #define USART_I2S_VALID(ref) (((ref) == USART1) || ((ref) == USART2))
+#endif
+#endif
+
+#if (UART_COUNT == 1)
+#define UART_REF_VALID(ref) ((ref) == UART0)
+#elif (UART_COUNT == 2)
+#define UART_REF_VALID(ref) (((ref) == UART0) || ((ref) == UART1))
+#else
+#define UART_REF_VALID(ref) (0)
+#endif
+
+#if defined(_USART_CLKDIV_DIVEXT_MASK)
+#define CLKDIV_MASK (_USART_CLKDIV_DIV_MASK | _USART_CLKDIV_DIVEXT_MASK)
+#else
+#define CLKDIV_MASK _USART_CLKDIV_DIV_MASK
+#endif
+
+/** @endcond */
+
+/*******************************************************************************
+ ************************** GLOBAL FUNCTIONS *******************************
+ ******************************************************************************/
+
+/***************************************************************************//**
+ * @brief
+ * Configure USART/UART operating in asynchronous mode to use a given
+ * baudrate (or as close as possible to specified baudrate).
+ *
+ * @param[in] usart
+ * Pointer to USART/UART peripheral register block.
+ *
+ * @param[in] refFreq
+ * USART/UART reference clock frequency in Hz that will be used. If set to 0,
+ * the currently configured reference clock is assumed.
+ *
+ * @param[in] baudrate
+ * Baudrate to try to achieve for USART/UART.
+ *
+ * @param[in] ovs
+ * Oversampling to be used. Normal is 16x oversampling, but lower oversampling
+ * may be used to achieve higher rates or better baudrate accuracy in some
+ * cases. Notice that lower oversampling frequency makes channel more
+ * vulnerable to bit faults during reception due to clock inaccuracies
+ * compared to link partner.
+ ******************************************************************************/
+void USART_BaudrateAsyncSet(USART_TypeDef *usart,
+ uint32_t refFreq,
+ uint32_t baudrate,
+ USART_OVS_TypeDef ovs)
+{
+ uint32_t clkdiv;
+ uint32_t oversample;
+
+ /* Inhibit divide by 0 */
+ EFM_ASSERT(baudrate);
+
+ /*
+ * We want to use integer division to avoid forcing in float division
+ * utils, and yet keep rounding effect errors to a minimum.
+ *
+ * CLKDIV in asynchronous mode is given by:
+ *
+ * CLKDIV = 256 * (fHFPERCLK/(oversample * br) - 1)
+ * or
+ * CLKDIV = (256 * fHFPERCLK)/(oversample * br) - 256
+ *
+ * The basic problem with integer division in the above formula is that
+ * the dividend (256 * fHFPERCLK) may become higher than max 32 bit
+ * integer. Yet, we want to evaluate dividend first before dividing in
+ * order to get as small rounding effects as possible. We do not want
+ * to make too harsh restrictions on max fHFPERCLK value either.
+ *
+ * One can possibly factorize 256 and oversample/br. However,
+ * since the last 6 or 3 bits of CLKDIV are don't care, we can base our
+ * integer arithmetic on the below formula
+ *
+ * CLKDIV / 64 = (4 * fHFPERCLK)/(oversample * br) - 4 (3 bits dont care)
+ * or
+ * CLKDIV / 8 = (32 * fHFPERCLK)/(oversample * br) - 32 (6 bits dont care)
+ *
+ * and calculate 1/64 of CLKDIV first. This allows for fHFPERCLK
+ * up to 1GHz without overflowing a 32 bit value!
+ */
+
+ /* HFPERCLK used to clock all USART/UART peripheral modules */
+ if (!refFreq) {
+ refFreq = CMU_ClockFreqGet(cmuClock_HFPER);
+ }
+
+ /* Map oversampling */
+ switch (ovs) {
+ case usartOVS16:
+ EFM_ASSERT(baudrate <= (refFreq / 16));
+ oversample = 16;
+ break;
+
+ case usartOVS8:
+ EFM_ASSERT(baudrate <= (refFreq / 8));
+ oversample = 8;
+ break;
+
+ case usartOVS6:
+ EFM_ASSERT(baudrate <= (refFreq / 6));
+ oversample = 6;
+ break;
+
+ case usartOVS4:
+ EFM_ASSERT(baudrate <= (refFreq / 4));
+ oversample = 4;
+ break;
+
+ default:
+ /* Invalid input */
+ EFM_ASSERT(0);
+ return;
+ }
+
+ /* Calculate and set CLKDIV with fractional bits.
+ * The added (oversample*baudrate)/2 in the first line is to round the
+ * divisor to the nearest fractional divisor. */
+#if defined(_SILICON_LABS_32B_SERIES_0) && !defined(_EFM32_HAPPY_FAMILY)
+ /* Devices with 2 fractional bits. CLKDIV[7:6] */
+ clkdiv = 4 * refFreq + (oversample * baudrate) / 2;
+ clkdiv /= (oversample * baudrate);
+ clkdiv -= 4;
+ clkdiv *= 64;
+#else
+ /* Devices with 5 fractional bits. CLKDIV[7:3] */
+ clkdiv = 32 * refFreq + (oversample * baudrate) / 2;
+ clkdiv /= (oversample * baudrate);
+ clkdiv -= 32;
+ clkdiv *= 8;
+#endif
+
+ /* Verify that resulting clock divider is within limits */
+ EFM_ASSERT(clkdiv <= CLKDIV_MASK);
+
+ /* Make sure we don't write to reserved bits */
+ clkdiv &= CLKDIV_MASK;
+
+ usart->CTRL &= ~_USART_CTRL_OVS_MASK;
+ usart->CTRL |= ovs;
+ usart->CLKDIV = clkdiv;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Calculate baudrate for USART/UART given reference frequency, clock division
+ * and oversampling rate (if async mode).
+ *
+ * @details
+ * This function returns the baudrate that a USART/UART module will use if
+ * configured with the given frequency, clock divisor and mode. Notice that
+ * this function will not use actual HW configuration. It can be used
+ * to determinate if a given configuration is sufficiently accurate for the
+ * application.
+ *
+ * @param[in] refFreq
+ * USART/UART HF peripheral frequency used.
+ *
+ * @param[in] clkdiv
+ * Clock division factor to be used.
+ *
+ * @param[in] syncmode
+ * @li true - synchronous mode operation.
+ * @li false - asynchronous mode operation.
+ *
+ * @param[in] ovs
+ * Oversampling used if asynchronous mode. Not used if @p syncmode is true.
+ *
+ * @return
+ * Baudrate with given settings.
+ ******************************************************************************/
+uint32_t USART_BaudrateCalc(uint32_t refFreq,
+ uint32_t clkdiv,
+ bool syncmode,
+ USART_OVS_TypeDef ovs)
+{
+ uint32_t oversample;
+ uint64_t divisor;
+ uint64_t factor;
+ uint64_t remainder;
+ uint64_t quotient;
+ uint32_t br;
+
+ /* Out of bound clkdiv ? */
+ EFM_ASSERT(clkdiv <= CLKDIV_MASK);
+
+ /* Mask out unused bits */
+ clkdiv &= CLKDIV_MASK;
+
+ /* We want to use integer division to avoid forcing in float division */
+ /* utils, and yet keep rounding effect errors to a minimum. */
+
+ /* Baudrate calculation depends on if synchronous or asynchronous mode */
+ if (syncmode) {
+ /*
+ * Baudrate is given by:
+ *
+ * br = fHFPERCLK/(2 * (1 + (CLKDIV / 256)))
+ *
+ * which can be rewritten to
+ *
+ * br = (128 * fHFPERCLK)/(256 + CLKDIV)
+ */
+ oversample = 1; /* Not used in sync mode, ie 1 */
+ factor = 128;
+ } else {
+ /*
+ * Baudrate in asynchronous mode is given by:
+ *
+ * br = fHFPERCLK/(oversample * (1 + (CLKDIV / 256)))
+ *
+ * which can be rewritten to
+ *
+ * br = (256 * fHFPERCLK)/(oversample * (256 + CLKDIV))
+ *
+ * First of all we can reduce the 256 factor of the dividend with
+ * (part of) oversample part of the divisor.
+ */
+
+ switch (ovs) {
+ case usartOVS16:
+ oversample = 1;
+ factor = 256 / 16;
+ break;
+
+ case usartOVS8:
+ oversample = 1;
+ factor = 256 / 8;
+ break;
+
+ case usartOVS6:
+ oversample = 3;
+ factor = 256 / 2;
+ break;
+
+ default:
+ oversample = 1;
+ factor = 256 / 4;
+ break;
+ }
+ }
+
+ /*
+ * The basic problem with integer division in the above formula is that
+ * the dividend (factor * fHFPERCLK) may become larger than a 32 bit
+ * integer. Yet we want to evaluate dividend first before dividing in
+ * order to get as small rounding effects as possible. We do not want
+ * to make too harsh restrictions on max fHFPERCLK value either.
+ *
+ * For division a/b, we can write
+ *
+ * a = qb + r
+ *
+ * where q is the quotient and r is the remainder, both integers.
+ *
+ * The orignal baudrate formula can be rewritten as
+ *
+ * br = xa / b = x(qb + r)/b = xq + xr/b
+ *
+ * where x is 'factor', a is 'refFreq' and b is 'divisor', referring to
+ * variable names.
+ */
+
+ /*
+ * Divisor will never exceed max 32 bit value since
+ * clkdiv <= _USART_CLKDIV_DIV_MASK (currently 0x1FFFC0 or 0x7FFFF8)
+ * and 'oversample' has been reduced to <= 3.
+ */
+ divisor = oversample * (256 + clkdiv);
+
+ quotient = refFreq / divisor;
+ remainder = refFreq % divisor;
+
+ /* factor <= 128 and since divisor >= 256, the below cannot exceed max */
+ /* 32 bit value. However, factor * remainder can become larger than 32-bit */
+ /* because of the size of _USART_CLKDIV_DIV_MASK on some families. */
+ br = (uint32_t)(factor * quotient);
+
+ /*
+ * factor <= 128 and remainder < (oversample*(256 + clkdiv)), which
+ * means dividend (factor * remainder) worst case is
+ * 128 * (3 * (256 + _USART_CLKDIV_DIV_MASK)) = 0x1_8001_7400.
+ */
+ br += (uint32_t)((factor * remainder) / divisor);
+
+ return br;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Get current baudrate for USART/UART.
+ *
+ * @details
+ * This function returns the actual baudrate (not considering oscillator
+ * inaccuracies) used by a USART/UART peripheral.
+ *
+ * @param[in] usart
+ * Pointer to USART/UART peripheral register block.
+ *
+ * @return
+ * Current baudrate.
+ ******************************************************************************/
+uint32_t USART_BaudrateGet(USART_TypeDef *usart)
+{
+ uint32_t freq;
+ USART_OVS_TypeDef ovs;
+ bool syncmode;
+
+ if (usart->CTRL & USART_CTRL_SYNC) {
+ syncmode = true;
+ } else {
+ syncmode = false;
+ }
+
+ /* HFPERCLK used to clock all USART/UART peripheral modules */
+ freq = CMU_ClockFreqGet(cmuClock_HFPER);
+ ovs = (USART_OVS_TypeDef)(usart->CTRL & _USART_CTRL_OVS_MASK);
+ return USART_BaudrateCalc(freq, usart->CLKDIV, syncmode, ovs);
+}
+
+/***************************************************************************//**
+ * @brief
+ * Configure USART operating in synchronous mode to use a given baudrate
+ * (or as close as possible to specified baudrate).
+ *
+ * @details
+ * The configuration will be set to use a baudrate <= the specified baudrate
+ * in order to ensure that the baudrate does not exceed the specified value.
+ *
+ * Fractional clock division is suppressed, although the HW design allows it.
+ * It could cause half clock cycles to exceed specified limit, and thus
+ * potentially violate specifications for the slave device. In some special
+ * situations fractional clock division may be useful even in synchronous
+ * mode, but in those cases it must be directly adjusted, possibly assisted
+ * by USART_BaudrateCalc():
+ *
+ * @param[in] usart
+ * Pointer to USART peripheral register block. (Cannot be used on UART
+ * modules.)
+ *
+ * @param[in] refFreq
+ * USART reference clock frequency in Hz that will be used. If set to 0,
+ * the currently configured reference clock is assumed.
+ *
+ * @param[in] baudrate
+ * Baudrate to try to achieve for USART.
+ ******************************************************************************/
+void USART_BaudrateSyncSet(USART_TypeDef *usart, uint32_t refFreq, uint32_t baudrate)
+{
+ uint32_t clkdiv;
+
+ /* Inhibit divide by 0 */
+ EFM_ASSERT(baudrate);
+
+ /*
+ * CLKDIV in synchronous mode is given by:
+ *
+ * CLKDIV = 256 * (fHFPERCLK/(2 * br) - 1)
+ */
+
+ /* HFPERCLK used to clock all USART/UART peripheral modules */
+ if (!refFreq) {
+ refFreq = CMU_ClockFreqGet(cmuClock_HFPER);
+ }
+
+ clkdiv = (refFreq - 1) / (2 * baudrate);
+ clkdiv = clkdiv << 8;
+
+ /* Verify that resulting clock divider is within limits */
+ EFM_ASSERT(!(clkdiv & ~CLKDIV_MASK));
+
+ usart->CLKDIV = clkdiv;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Enable/disable USART/UART receiver and/or transmitter.
+ *
+ * @details
+ * Notice that this function does not do any configuration. Enabling should
+ * normally be done after initialization is done (if not enabled as part
+ * of init).
+ *
+ * @param[in] usart
+ * Pointer to USART/UART peripheral register block.
+ *
+ * @param[in] enable
+ * Select status for receiver/transmitter.
+ ******************************************************************************/
+void USART_Enable(USART_TypeDef *usart, USART_Enable_TypeDef enable)
+{
+ uint32_t tmp;
+
+ /* Make sure the module exists on the selected chip */
+ EFM_ASSERT(USART_REF_VALID(usart)
+ || USARTRF_REF_VALID(usart)
+ || UART_REF_VALID(usart) );
+
+ /* Disable as specified */
+ tmp = ~((uint32_t) (enable));
+ tmp &= _USART_CMD_RXEN_MASK | _USART_CMD_TXEN_MASK;
+ usart->CMD = tmp << 1;
+
+ /* Enable as specified */
+ usart->CMD = (uint32_t) (enable);
+}
+
+/***************************************************************************//**
+ * @brief
+ * Init USART/UART for normal asynchronous mode.
+ *
+ * @details
+ * This function will configure basic settings in order to operate in normal
+ * asynchronous mode.
+ *
+ * Special control setup not covered by this function must be done after
+ * using this function by direct modification of the CTRL register.
+ *
+ * Notice that pins used by the USART/UART module must be properly configured
+ * by the user explicitly, in order for the USART/UART to work as intended.
+ * (When configuring pins, one should remember to consider the sequence of
+ * configuration, in order to avoid unintended pulses/glitches on output
+ * pins.)
+ *
+ * @param[in] usart
+ * Pointer to USART/UART peripheral register block.
+ *
+ * @param[in] init
+ * Pointer to initialization structure used to configure basic async setup.
+ ******************************************************************************/
+void USART_InitAsync(USART_TypeDef *usart, const USART_InitAsync_TypeDef *init)
+{
+ /* Make sure the module exists on the selected chip */
+ EFM_ASSERT(USART_REF_VALID(usart)
+ || USARTRF_REF_VALID(usart)
+ || UART_REF_VALID(usart) );
+
+ /* Init USART registers to HW reset state. */
+ USART_Reset(usart);
+
+#if defined(USART_INPUT_RXPRS) && defined(USART_CTRL_MVDIS)
+ /* Disable majority vote if specified. */
+ if (init->mvdis) {
+ usart->CTRL |= USART_CTRL_MVDIS;
+ }
+
+ /* Configure PRS input mode. */
+ if (init->prsRxEnable) {
+ usart->INPUT = (uint32_t) init->prsRxCh | USART_INPUT_RXPRS;
+ }
+#endif
+
+ /* Configure databits, stopbits and parity */
+ usart->FRAME = (uint32_t)init->databits
+ | (uint32_t)init->stopbits
+ | (uint32_t)init->parity;
+
+ /* Configure baudrate */
+ USART_BaudrateAsyncSet(usart, init->refFreq, init->baudrate, init->oversampling);
+
+#if defined(_USART_TIMING_CSHOLD_MASK)
+ usart->TIMING = ((init->autoCsHold << _USART_TIMING_CSHOLD_SHIFT)
+ & _USART_TIMING_CSHOLD_MASK)
+ | ((init->autoCsSetup << _USART_TIMING_CSSETUP_SHIFT)
+ & _USART_TIMING_CSSETUP_MASK);
+ if (init->autoCsEnable) {
+ usart->CTRL |= USART_CTRL_AUTOCS;
+ }
+#endif
+ /* Finally enable (as specified) */
+ usart->CMD = (uint32_t)init->enable;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Init USART for synchronous mode.
+ *
+ * @details
+ * This function will configure basic settings in order to operate in
+ * synchronous mode.
+ *
+ * Special control setup not covered by this function must be done after
+ * using this function by direct modification of the CTRL register.
+ *
+ * Notice that pins used by the USART module must be properly configured
+ * by the user explicitly, in order for the USART to work as intended.
+ * (When configuring pins, one should remember to consider the sequence of
+ * configuration, in order to avoid unintended pulses/glitches on output
+ * pins.)
+ *
+ * @param[in] usart
+ * Pointer to USART peripheral register block. (UART does not support this
+ * mode.)
+ *
+ * @param[in] init
+ * Pointer to initialization structure used to configure basic async setup.
+ ******************************************************************************/
+void USART_InitSync(USART_TypeDef *usart, const USART_InitSync_TypeDef *init)
+{
+ /* Make sure the module exists on the selected chip */
+ EFM_ASSERT(USART_REF_VALID(usart) || USARTRF_REF_VALID(usart) );
+
+ /* Init USART registers to HW reset state. */
+ USART_Reset(usart);
+
+ /* Set bits for synchronous mode */
+ usart->CTRL |= (USART_CTRL_SYNC)
+ | (uint32_t)init->clockMode
+ | (init->msbf ? USART_CTRL_MSBF : 0);
+
+#if defined(_USART_CTRL_AUTOTX_MASK)
+ usart->CTRL |= init->autoTx ? USART_CTRL_AUTOTX : 0;
+#endif
+
+#if defined(_USART_INPUT_RXPRS_MASK)
+ /* Configure PRS input mode. */
+ if (init->prsRxEnable) {
+ usart->INPUT = (uint32_t)init->prsRxCh | USART_INPUT_RXPRS;
+ }
+#endif
+
+ /* Configure databits, leave stopbits and parity at reset default (not used) */
+ usart->FRAME = (uint32_t)init->databits
+ | USART_FRAME_STOPBITS_DEFAULT
+ | USART_FRAME_PARITY_DEFAULT;
+
+ /* Configure baudrate */
+ USART_BaudrateSyncSet(usart, init->refFreq, init->baudrate);
+
+ /* Finally enable (as specified) */
+ if (init->master) {
+ usart->CMD = USART_CMD_MASTEREN;
+ }
+
+#if defined(_USART_TIMING_CSHOLD_MASK)
+ usart->TIMING = ((init->autoCsHold << _USART_TIMING_CSHOLD_SHIFT)
+ & _USART_TIMING_CSHOLD_MASK)
+ | ((init->autoCsSetup << _USART_TIMING_CSSETUP_SHIFT)
+ & _USART_TIMING_CSSETUP_MASK);
+ if (init->autoCsEnable) {
+ usart->CTRL |= USART_CTRL_AUTOCS;
+ }
+#endif
+
+ usart->CMD = (uint32_t)init->enable;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Init USART for asynchronous IrDA mode.
+ *
+ * @details
+ * This function will configure basic settings in order to operate in
+ * asynchronous IrDA mode.
+ *
+ * Special control setup not covered by this function must be done after
+ * using this function by direct modification of the CTRL and IRCTRL
+ * registers.
+ *
+ * Notice that pins used by the USART/UART module must be properly configured
+ * by the user explicitly, in order for the USART/UART to work as intended.
+ * (When configuring pins, one should remember to consider the sequence of
+ * configuration, in order to avoid unintended pulses/glitches on output
+ * pins.)
+ *
+ * @param[in] usart
+ * Pointer to USART peripheral register block.
+ *
+ * @param[in] init
+ * Pointer to initialization structure used to configure async IrDA setup.
+ *
+ * @note
+ * Not all USART instances support IrDA. See the datasheet for your device.
+ *
+ ******************************************************************************/
+void USARTn_InitIrDA(USART_TypeDef *usart, const USART_InitIrDA_TypeDef *init)
+{
+ EFM_ASSERT(USART_IRDA_VALID(usart));
+
+ /* Init USART as async device */
+ USART_InitAsync(usart, &(init->async));
+
+ /* Set IrDA modulation to RZI (return-to-zero-inverted) */
+ usart->CTRL |= USART_CTRL_TXINV;
+
+ /* Invert Rx signal before demodulator if enabled */
+ if (init->irRxInv) {
+ usart->CTRL |= USART_CTRL_RXINV;
+ }
+
+ /* Configure IrDA */
+ usart->IRCTRL |= (uint32_t)init->irPw
+ | (uint32_t)init->irPrsSel
+ | ((uint32_t)init->irFilt << _USART_IRCTRL_IRFILT_SHIFT)
+ | ((uint32_t)init->irPrsEn << _USART_IRCTRL_IRPRSEN_SHIFT);
+
+ /* Enable IrDA */
+ usart->IRCTRL |= USART_IRCTRL_IREN;
+}
+
+#if defined(_USART_I2SCTRL_MASK)
+/***************************************************************************//**
+ * @brief
+ * Init USART for I2S mode.
+ *
+ * @details
+ * This function will configure basic settings in order to operate in I2S
+ * mode.
+ *
+ * Special control setup not covered by this function must be done after
+ * using this function by direct modification of the CTRL and I2SCTRL
+ * registers.
+ *
+ * Notice that pins used by the USART module must be properly configured
+ * by the user explicitly, in order for the USART to work as intended.
+ * (When configuring pins, one should remember to consider the sequence of
+ * configuration, in order to avoid unintended pulses/glitches on output
+ * pins.)
+ *
+ * @param[in] usart
+ * Pointer to USART peripheral register block. (UART does not support this
+ * mode.)
+ *
+ * @param[in] init
+ * Pointer to initialization structure used to configure basic I2S setup.
+ *
+ * @note
+ * This function does not apply to all USART's. Refer to chip manuals.
+ *
+ ******************************************************************************/
+void USART_InitI2s(USART_TypeDef *usart, USART_InitI2s_TypeDef *init)
+{
+ USART_Enable_TypeDef enable;
+
+ /* Make sure the module exists on the selected chip */
+ EFM_ASSERT(USART_I2S_VALID(usart));
+
+ /* Override the enable setting. */
+ enable = init->sync.enable;
+ init->sync.enable = usartDisable;
+
+ /* Init USART as a sync device. */
+ USART_InitSync(usart, &init->sync);
+
+ /* Configure and enable I2CCTRL register acording to selected mode. */
+ usart->I2SCTRL = (uint32_t)init->format
+ | (uint32_t)init->justify
+ | (init->delay ? USART_I2SCTRL_DELAY : 0)
+ | (init->dmaSplit ? USART_I2SCTRL_DMASPLIT : 0)
+ | (init->mono ? USART_I2SCTRL_MONO : 0)
+ | USART_I2SCTRL_EN;
+
+ if (enable != usartDisable) {
+ USART_Enable(usart, enable);
+ }
+}
+#endif
+
+/***************************************************************************//**
+ * @brief
+ * Initialize automatic transmissions using PRS channel as trigger
+ * @note
+ * Initialize USART with USART_Init() before setting up PRS configuration
+ *
+ * @param[in] usart Pointer to USART to configure
+ * @param[in] init Pointer to initialization structure
+ ******************************************************************************/
+void USART_InitPrsTrigger(USART_TypeDef *usart, const USART_PrsTriggerInit_TypeDef *init)
+{
+ uint32_t trigctrl;
+
+ /* Clear values that will be reconfigured */
+ trigctrl = usart->TRIGCTRL & ~(_USART_TRIGCTRL_RXTEN_MASK
+ | _USART_TRIGCTRL_TXTEN_MASK
+#if defined(USART_TRIGCTRL_AUTOTXTEN)
+ | _USART_TRIGCTRL_AUTOTXTEN_MASK
+#endif
+ | _USART_TRIGCTRL_TSEL_MASK);
+
+#if defined(USART_TRIGCTRL_AUTOTXTEN)
+ if (init->autoTxTriggerEnable) {
+ trigctrl |= USART_TRIGCTRL_AUTOTXTEN;
+ }
+#endif
+ if (init->txTriggerEnable) {
+ trigctrl |= USART_TRIGCTRL_TXTEN;
+ }
+ if (init->rxTriggerEnable) {
+ trigctrl |= USART_TRIGCTRL_RXTEN;
+ }
+ trigctrl |= init->prsTriggerChannel;
+
+ /* Enable new configuration */
+ usart->TRIGCTRL = trigctrl;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Reset USART/UART to same state as after a HW reset.
+ *
+ * @param[in] usart
+ * Pointer to USART/UART peripheral register block.
+ ******************************************************************************/
+void USART_Reset(USART_TypeDef *usart)
+{
+ /* Make sure the module exists on the selected chip */
+ EFM_ASSERT(USART_REF_VALID(usart)
+ || USARTRF_REF_VALID(usart)
+ || UART_REF_VALID(usart) );
+
+ /* Make sure disabled first, before resetting other registers */
+ usart->CMD = USART_CMD_RXDIS | USART_CMD_TXDIS | USART_CMD_MASTERDIS
+ | USART_CMD_RXBLOCKDIS | USART_CMD_TXTRIDIS | USART_CMD_CLEARTX
+ | USART_CMD_CLEARRX;
+ usart->CTRL = _USART_CTRL_RESETVALUE;
+ usart->FRAME = _USART_FRAME_RESETVALUE;
+ usart->TRIGCTRL = _USART_TRIGCTRL_RESETVALUE;
+ usart->CLKDIV = _USART_CLKDIV_RESETVALUE;
+ usart->IEN = _USART_IEN_RESETVALUE;
+ usart->IFC = _USART_IFC_MASK;
+#if defined(_USART_ROUTEPEN_MASK) || defined(_UART_ROUTEPEN_MASK)
+ usart->ROUTEPEN = _USART_ROUTEPEN_RESETVALUE;
+ usart->ROUTELOC0 = _USART_ROUTELOC0_RESETVALUE;
+ usart->ROUTELOC1 = _USART_ROUTELOC1_RESETVALUE;
+#else
+ usart->ROUTE = _USART_ROUTE_RESETVALUE;
+#endif
+
+ if (USART_IRDA_VALID(usart)) {
+ usart->IRCTRL = _USART_IRCTRL_RESETVALUE;
+ }
+
+#if defined(_USART_INPUT_RESETVALUE)
+ usart->INPUT = _USART_INPUT_RESETVALUE;
+#endif
+
+#if defined(_USART_I2SCTRL_RESETVALUE)
+ if (USART_I2S_VALID(usart)) {
+ usart->I2SCTRL = _USART_I2SCTRL_RESETVALUE;
+ }
+#endif
+}
+
+/***************************************************************************//**
+ * @brief
+ * Receive one 4-8 bit frame, (or part of 10-16 bit frame).
+ *
+ * @details
+ * This function is normally used to receive one frame when operating with
+ * frame length 4-8 bits. Please refer to @ref USART_RxExt() for reception of
+ * 9 bit frames.
+ *
+ * Notice that possible parity/stop bits in asynchronous mode are not
+ * considered part of specified frame bit length.
+ *
+ * @note
+ * This function will stall if the buffer is empty, until data is received.
+ * Alternatively the user can explicitly check whether data is available, and
+ * if data is avaliable, call @ref USART_RxDataGet() to read the RXDATA
+ * register directly.
+ *
+ * @param[in] usart
+ * Pointer to USART/UART peripheral register block.
+ *
+ * @return
+ * Data received.
+ ******************************************************************************/
+uint8_t USART_Rx(USART_TypeDef *usart)
+{
+ while (!(usart->STATUS & USART_STATUS_RXDATAV))
+ ;
+
+ return (uint8_t)usart->RXDATA;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Receive two 4-8 bit frames, or one 10-16 bit frame.
+ *
+ * @details
+ * This function is normally used to receive one frame when operating with
+ * frame length 10-16 bits. Please refer to @ref USART_RxDoubleExt() for
+ * reception of two 9 bit frames.
+ *
+ * Notice that possible parity/stop bits in asynchronous mode are not
+ * considered part of specified frame bit length.
+ *
+ * @note
+ * This function will stall if buffer is empty, until data is received.
+ * Alternatively the user can explicitly check whether data is available, and
+ * if data is avaliable, call @ref USART_RxDoubleGet() to read the RXDOUBLE
+ * register directly.
+ *
+ * @param[in] usart
+ * Pointer to USART/UART peripheral register block.
+ *
+ * @return
+ * Data received.
+ ******************************************************************************/
+uint16_t USART_RxDouble(USART_TypeDef *usart)
+{
+ while (!(usart->STATUS & USART_STATUS_RXFULL))
+ ;
+
+ return (uint16_t)usart->RXDOUBLE;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Receive two 4-9 bit frames, or one 10-16 bit frame with extended
+ * information.
+ *
+ * @details
+ * This function is normally used to receive one frame when operating with
+ * frame length 10-16 bits and additional RX status information is required.
+ *
+ * Notice that possible parity/stop bits in asynchronous mode are not
+ * considered part of specified frame bit length.
+ *
+ * @note
+ * This function will stall if buffer is empty, until data is received.
+ * Alternatively the user can explicitly check whether data is available, and
+ * if data is avaliable, call @ref USART_RxDoubleXGet() to read the RXDOUBLEX
+ * register directly.
+ *
+ * @param[in] usart
+ * Pointer to USART/UART peripheral register block.
+ *
+ * @return
+ * Data received.
+ ******************************************************************************/
+uint32_t USART_RxDoubleExt(USART_TypeDef *usart)
+{
+ while (!(usart->STATUS & USART_STATUS_RXFULL))
+ ;
+
+ return usart->RXDOUBLEX;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Receive one 4-9 bit frame, (or part of 10-16 bit frame) with extended
+ * information.
+ *
+ * @details
+ * This function is normally used to receive one frame when operating with
+ * frame length 4-9 bits and additional RX status information is required.
+ *
+ * Notice that possible parity/stop bits in asynchronous mode are not
+ * considered part of specified frame bit length.
+ *
+ * @note
+ * This function will stall if buffer is empty, until data is received.
+ * Alternatively the user can explicitly check whether data is available, and
+ * if data is avaliable, call @ref USART_RxDataXGet() to read the RXDATAX
+ * register directly.
+ *
+ * @param[in] usart
+ * Pointer to USART/UART peripheral register block.
+ *
+ * @return
+ * Data received.
+ ******************************************************************************/
+uint16_t USART_RxExt(USART_TypeDef *usart)
+{
+ while (!(usart->STATUS & USART_STATUS_RXDATAV))
+ ;
+
+ return (uint16_t)usart->RXDATAX;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Perform one 8 bit frame SPI transfer.
+ *
+ * @note
+ * This function will stall if the transmit buffer is full. When a transmit
+ * buffer becomes available, data is written and the function will wait until
+ * the data is fully transmitted. The SPI return value is then read out and
+ * returned.
+ *
+ * @param[in] usart
+ * Pointer to USART peripheral register block.
+ *
+ * @param[in] data
+ * Data to transmit.
+ *
+ * @return
+ * Data received.
+ ******************************************************************************/
+uint8_t USART_SpiTransfer(USART_TypeDef *usart, uint8_t data)
+{
+ while (!(usart->STATUS & USART_STATUS_TXBL))
+ ;
+ usart->TXDATA = (uint32_t)data;
+ while (!(usart->STATUS & USART_STATUS_TXC))
+ ;
+ return (uint8_t)usart->RXDATA;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Transmit one 4-9 bit frame.
+ *
+ * @details
+ * Depending on frame length configuration, 4-8 (least significant) bits from
+ * @p data are transmitted. If frame length is 9, 8 bits are transmitted from
+ * @p data and one bit as specified by CTRL register, BIT8DV field. Please
+ * refer to USART_TxExt() for transmitting 9 bit frame with full control of
+ * all 9 bits.
+ *
+ * Notice that possible parity/stop bits in asynchronous mode are not
+ * considered part of specified frame bit length.
+ *
+ * @note
+ * This function will stall if buffer is full, until buffer becomes available.
+ *
+ * @param[in] usart
+ * Pointer to USART/UART peripheral register block.
+ *
+ * @param[in] data
+ * Data to transmit. See details above for further info.
+ ******************************************************************************/
+void USART_Tx(USART_TypeDef *usart, uint8_t data)
+{
+ /* Check that transmit buffer is empty */
+ while (!(usart->STATUS & USART_STATUS_TXBL))
+ ;
+ usart->TXDATA = (uint32_t)data;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Transmit two 4-9 bit frames, or one 10-16 bit frame.
+ *
+ * @details
+ * Depending on frame length configuration, 4-8 (least significant) bits from
+ * each byte in @p data are transmitted. If frame length is 9, 8 bits are
+ * transmitted from each byte in @p data adding one bit as specified by CTRL
+ * register, BIT8DV field, to each byte. Please refer to USART_TxDoubleExt()
+ * for transmitting two 9 bit frames with full control of all 9 bits.
+ *
+ * If frame length is 10-16, 10-16 (least significant) bits from @p data
+ * are transmitted.
+ *
+ * Notice that possible parity/stop bits in asynchronous mode are not
+ * considered part of specified frame bit length.
+ *
+ * @note
+ * This function will stall if buffer is full, until buffer becomes available.
+ *
+ * @param[in] usart
+ * Pointer to USART/UART peripheral register block.
+ *
+ * @param[in] data
+ * Data to transmit, the least significant byte holds the frame transmitted
+ * first. See details above for further info.
+ ******************************************************************************/
+void USART_TxDouble(USART_TypeDef *usart, uint16_t data)
+{
+ /* Check that transmit buffer is empty */
+ while (!(usart->STATUS & USART_STATUS_TXBL))
+ ;
+ usart->TXDOUBLE = (uint32_t)data;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Transmit two 4-9 bit frames, or one 10-16 bit frame with extended control.
+ *
+ * @details
+ * Notice that possible parity/stop bits in asynchronous mode are not
+ * considered part of specified frame bit length.
+ *
+ * @note
+ * This function will stall if buffer is full, until buffer becomes available.
+ *
+ * @param[in] usart
+ * Pointer to USART/UART peripheral register block.
+ *
+ * @param[in] data
+ * Data to transmit with extended control. Contains two 16 bit words
+ * concatenated. Least significant word holds frame transitted first. If frame
+ * length is 4-9, two frames with 4-9 least significant bits from each 16 bit
+ * word are transmitted.
+ * @par
+ * If frame length is 10-16 bits, 8 data bits are taken from the least
+ * significant 16 bit word, and the remaining bits from the other 16 bit word.
+ * @par
+ * Additional control bits are available as documented in the reference
+ * manual (set to 0 if not used). For 10-16 bit frame length, these control
+ * bits are taken from the most significant 16 bit word.
+ ******************************************************************************/
+void USART_TxDoubleExt(USART_TypeDef *usart, uint32_t data)
+{
+ /* Check that transmit buffer is empty */
+ while (!(usart->STATUS & USART_STATUS_TXBL))
+ ;
+ usart->TXDOUBLEX = data;
+}
+
+/***************************************************************************//**
+ * @brief
+ * Transmit one 4-9 bit frame with extended control.
+ *
+ * @details
+ * Notice that possible parity/stop bits in asynchronous mode are not
+ * considered part of specified frame bit length.
+ *
+ * @note
+ * This function will stall if buffer is full, until buffer becomes available.
+ *
+ * @param[in] usart
+ * Pointer to USART/UART peripheral register block.
+ *
+ * @param[in] data
+ * Data to transmit with extended control. Least significant bits contains
+ * frame bits, and additional control bits are available as documented in
+ * the reference manual (set to 0 if not used).
+ ******************************************************************************/
+void USART_TxExt(USART_TypeDef *usart, uint16_t data)
+{
+ /* Check that transmit buffer is empty */
+ while (!(usart->STATUS & USART_STATUS_TXBL))
+ ;
+ usart->TXDATAX = (uint32_t)data;
+}
+
+/** @} (end addtogroup USART) */
+/** @} (end addtogroup emlib) */
+#endif /* defined(USART_COUNT) && (USART_COUNT > 0) */
diff --git a/efm32/inc/InitDevice.h b/efm32/inc/InitDevice.h
new file mode 100644
index 0000000..31af980
--- /dev/null
+++ b/efm32/inc/InitDevice.h
@@ -0,0 +1,48 @@
+//=========================================================
+// inc/InitDevice.h: generated by Hardware Configurator
+//
+// This file will be regenerated when saving a document.
+// leave the sections inside the "$[...]" comment tags alone
+// or they will be overwritten!
+//=========================================================
+#ifndef __INIT_DEVICE_H__
+#define __INIT_DEVICE_H__
+
+// USER CONSTANTS
+// USER PROTOTYPES
+
+// $[Mode Transition Prototypes]
+extern void enter_DefaultMode_from_RESET(void);
+// [Mode Transition Prototypes]$
+
+// $[Config(Per-Module Mode)Transition Prototypes]
+extern void EMU_enter_DefaultMode_from_RESET(void);
+extern void LFXO_enter_DefaultMode_from_RESET(void);
+extern void CMU_enter_DefaultMode_from_RESET(void);
+extern void ADC0_enter_DefaultMode_from_RESET(void);
+extern void ACMP0_enter_DefaultMode_from_RESET(void);
+extern void ACMP1_enter_DefaultMode_from_RESET(void);
+extern void IDAC0_enter_DefaultMode_from_RESET(void);
+extern void RTCC_enter_DefaultMode_from_RESET(void);
+extern void USART0_enter_DefaultMode_from_RESET(void);
+extern void USART1_enter_DefaultMode_from_RESET(void);
+extern void LEUART0_enter_DefaultMode_from_RESET(void);
+extern void WDOG0_enter_DefaultMode_from_RESET(void);
+extern void I2C0_enter_DefaultMode_from_RESET(void);
+extern void GPCRC_enter_DefaultMode_from_RESET(void);
+extern void LDMA_enter_DefaultMode_from_RESET(void);
+extern void TIMER0_enter_DefaultMode_from_RESET(void);
+extern void TIMER1_enter_DefaultMode_from_RESET(void);
+extern void LETIMER0_enter_DefaultMode_from_RESET(void);
+extern void CRYOTIMER_enter_DefaultMode_from_RESET(void);
+extern void PCNT0_enter_DefaultMode_from_RESET(void);
+extern void PRS_enter_DefaultMode_from_RESET(void);
+extern void PORTIO_enter_DefaultMode_from_RESET(void);
+// [Config(Per-Module Mode)Transition Prototypes]$
+
+// $[User-defined pin name abstraction]
+
+// [User-defined pin name abstraction]$
+
+#endif
+
diff --git a/efm32/src/InitDevice.c b/efm32/src/InitDevice.c
new file mode 100644
index 0000000..2574816
--- /dev/null
+++ b/efm32/src/InitDevice.c
@@ -0,0 +1,547 @@
+//=========================================================
+// src/InitDevice.c: generated by Hardware Configurator
+//
+// This file will be regenerated when saving a document.
+// leave the sections inside the "$[...]" comment tags alone
+// or they will be overwritten!
+//=========================================================
+
+// USER INCLUDES
+#include "InitDevice.h"
+
+// USER PROTOTYPES
+// USER FUNCTIONS
+
+// $[Library includes]
+#include "em_system.h"
+#include "em_emu.h"
+#include "em_cmu.h"
+#include "em_device.h"
+#include "em_chip.h"
+#include "em_assert.h"
+#include "em_cryotimer.h"
+#include "em_gpio.h"
+#include "em_usart.h"
+// [Library includes]$
+
+//==============================================================================
+// enter_DefaultMode_from_RESET
+//==============================================================================
+extern void enter_DefaultMode_from_RESET(void) {
+ // $[Config Calls]
+ CHIP_Init();
+
+ EMU_enter_DefaultMode_from_RESET();
+ CMU_enter_DefaultMode_from_RESET();
+ USART0_enter_DefaultMode_from_RESET();
+ CRYOTIMER_enter_DefaultMode_from_RESET();
+ PORTIO_enter_DefaultMode_from_RESET();
+ // [Config Calls]$
+
+}
+
+//================================================================================
+// EMU_enter_DefaultMode_from_RESET
+//================================================================================
+extern void EMU_enter_DefaultMode_from_RESET(void) {
+
+ // $[EMU Initialization]
+ /* Initialize DCDC regulator */
+ EMU_DCDCInit_TypeDef dcdcInit = EMU_DCDCINIT_DEFAULT;
+
+ dcdcInit.powerConfig = emuPowerConfig_DcdcToDvdd;
+ dcdcInit.dcdcMode = emuDcdcMode_LowNoise;
+ dcdcInit.mVout = 1800;
+ dcdcInit.em01LoadCurrent_mA = 15;
+ dcdcInit.em234LoadCurrent_uA = 10;
+ dcdcInit.maxCurrent_mA = 200;
+ dcdcInit.anaPeripheralPower = emuDcdcAnaPeripheralPower_DCDC;
+ dcdcInit.reverseCurrentControl = 160;
+
+ EMU_DCDCInit(&dcdcInit);
+ /* Initialize EM2/EM3 mode */
+ EMU_EM23Init_TypeDef em23Init = EMU_EM23INIT_DEFAULT;
+
+ em23Init.em23VregFullEn = 0;
+
+ EMU_EM23Init(&em23Init);
+ /* Initialize EM4H/S mode */
+ EMU_EM4Init_TypeDef em4Init = EMU_EM4INIT_DEFAULT;
+
+ em4Init.retainLfrco = 0;
+ em4Init.retainLfxo = 0;
+ em4Init.retainUlfrco = 0;
+ em4Init.em4State = emuEM4Shutoff;
+ em4Init.pinRetentionMode = emuPinRetentionDisable;
+
+ EMU_EM4Init(&em4Init);
+ // [EMU Initialization]$
+
+}
+
+//================================================================================
+// LFXO_enter_DefaultMode_from_RESET
+//================================================================================
+extern void LFXO_enter_DefaultMode_from_RESET(void) {
+
+}
+
+//================================================================================
+// CMU_enter_DefaultMode_from_RESET
+//================================================================================
+extern void CMU_enter_DefaultMode_from_RESET(void) {
+
+ // $[High Frequency Clock Setup]
+ /* Initializing HFXO */
+ CMU_HFXOInit_TypeDef hfxoInit = CMU_HFXOINIT_DEFAULT;
+
+ CMU_HFXOInit(&hfxoInit);
+
+ /* Setting system HFRCO frequency */
+ CMU_HFRCOFreqSet (cmuHFRCOFreq_38M0Hz);
+
+ /* Using HFRCO as high frequency clock, HFCLK */
+ CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFRCO);
+ // [High Frequency Clock Setup]$
+
+ // $[LE clocks enable]
+ /* Enable LFRCO oscillator, and wait for it to be stable */
+ CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);
+
+ // [LE clocks enable]$
+
+ // $[LFACLK Setup]
+ /* LFACLK is disabled */
+ // [LFACLK Setup]$
+ // $[LFBCLK Setup]
+ /* LFBCLK is disabled */
+ // [LFBCLK Setup]$
+ // $[LFECLK Setup]
+ /* LFECLK is disabled */
+ // [LFECLK Setup]$
+ // $[Peripheral Clock enables]
+ /* Enable clock for HF peripherals */
+ CMU_ClockEnable(cmuClock_HFPER, true);
+
+ /* Enable clock for CRYOTIMER */
+ CMU_ClockEnable(cmuClock_CRYOTIMER, true);
+
+ /* Enable clock for USART0 */
+ CMU_ClockEnable(cmuClock_USART0, true);
+
+ /* Enable clock for GPIO by default */
+ CMU_ClockEnable(cmuClock_GPIO, true);
+
+ // [Peripheral Clock enables]$
+
+ // $[Clock output]
+ /* Disable CLKOUT0 output */
+ CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_CLKOUTSEL0_MASK)
+ | CMU_CTRL_CLKOUTSEL0_DISABLED;
+ /* Disable CLKOUT1 output */
+ CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_CLKOUTSEL1_MASK)
+ | CMU_CTRL_CLKOUTSEL1_DISABLED;
+
+ // [Clock output]$
+
+ // $[CMU_IO]
+ /* Disable CLKOUT0 pin */
+ CMU->ROUTEPEN &= ~CMU_ROUTEPEN_CLKOUT0PEN;
+
+ /* Disable CLKOUT1 pin */
+ CMU->ROUTEPEN &= ~CMU_ROUTEPEN_CLKOUT1PEN;
+
+ // [CMU_IO]$
+
+}
+
+//================================================================================
+// ADC0_enter_DefaultMode_from_RESET
+//================================================================================
+extern void ADC0_enter_DefaultMode_from_RESET(void) {
+
+ // $[ADC0_Init]
+ // [ADC0_Init]$
+
+ // $[ADC0_InputConfiguration]
+ // [ADC0_InputConfiguration]$
+
+}
+
+//================================================================================
+// ACMP0_enter_DefaultMode_from_RESET
+//================================================================================
+extern void ACMP0_enter_DefaultMode_from_RESET(void) {
+
+ // $[ACMP0_Init]
+ // [ACMP0_Init]$
+
+ // $[ACMP0_IO]
+ // [ACMP0_IO]$
+
+}
+
+//================================================================================
+// ACMP1_enter_DefaultMode_from_RESET
+//================================================================================
+extern void ACMP1_enter_DefaultMode_from_RESET(void) {
+
+ // $[ACMP1_Init]
+ // [ACMP1_Init]$
+
+ // $[ACMP1_IO]
+ // [ACMP1_IO]$
+
+}
+
+//================================================================================
+// IDAC0_enter_DefaultMode_from_RESET
+//================================================================================
+extern void IDAC0_enter_DefaultMode_from_RESET(void) {
+
+}
+
+//================================================================================
+// RTCC_enter_DefaultMode_from_RESET
+//================================================================================
+extern void RTCC_enter_DefaultMode_from_RESET(void) {
+
+ // $[Compare/Capture Channel 0 init]
+ // [Compare/Capture Channel 0 init]$
+
+ // $[Compare/Capture Channel 1 init]
+ // [Compare/Capture Channel 1 init]$
+
+ // $[Compare/Capture Channel 2 init]
+ // [Compare/Capture Channel 2 init]$
+
+ // $[RTCC init]
+ // [RTCC init]$
+
+}
+
+//================================================================================
+// USART0_enter_DefaultMode_from_RESET
+//================================================================================
+extern void USART0_enter_DefaultMode_from_RESET(void) {
+
+ // $[USART_InitAsync]
+ USART_InitAsync_TypeDef initasync = USART_INITASYNC_DEFAULT;
+
+ initasync.enable = usartDisable;
+ initasync.baudrate = 115200;
+ initasync.databits = usartDatabits8;
+ initasync.parity = usartNoParity;
+ initasync.stopbits = usartStopbits1;
+ initasync.oversampling = usartOVS16;
+#if defined( USART_INPUT_RXPRS ) && defined( USART_CTRL_MVDIS )
+ initasync.mvdis = 0;
+ initasync.prsRxEnable = 0;
+ initasync.prsRxCh = 0;
+#endif
+
+ USART_InitAsync(USART0, &initasync);
+ // [USART_InitAsync]$
+
+ // $[USART_InitSync]
+ // [USART_InitSync]$
+
+ // $[USART_InitPrsTrigger]
+ USART_PrsTriggerInit_TypeDef initprs = USART_INITPRSTRIGGER_DEFAULT;
+
+ initprs.rxTriggerEnable = 0;
+ initprs.txTriggerEnable = 0;
+ initprs.prsTriggerChannel = usartPrsTriggerCh0;
+
+ USART_InitPrsTrigger(USART0, &initprs);
+ // [USART_InitPrsTrigger]$
+
+ // $[USART_InitIO]
+ /* Disable CLK pin */
+ USART0->ROUTELOC0 = (USART0->ROUTELOC0 & (~_USART_ROUTELOC0_CLKLOC_MASK))
+ | USART_ROUTELOC0_CLKLOC_LOC0;
+ USART0->ROUTEPEN = USART0->ROUTEPEN & (~USART_ROUTEPEN_CLKPEN);
+
+ /* Disable CS pin */
+ USART0->ROUTELOC0 = (USART0->ROUTELOC0 & (~_USART_ROUTELOC0_CSLOC_MASK))
+ | USART_ROUTELOC0_CSLOC_LOC0;
+ USART0->ROUTEPEN = USART0->ROUTEPEN & (~USART_ROUTEPEN_CSPEN);
+
+ /* Set up CTS pin */
+ USART0->ROUTELOC1 = (USART0->ROUTELOC1 & (~_USART_ROUTELOC1_CTSLOC_MASK))
+ | USART_ROUTELOC1_CTSLOC_LOC30;
+ USART0->ROUTEPEN = USART0->ROUTEPEN | USART_ROUTEPEN_CTSPEN;
+
+ /* Set up RTS pin */
+ USART0->ROUTELOC1 = (USART0->ROUTELOC1 & (~_USART_ROUTELOC1_RTSLOC_MASK))
+ | USART_ROUTELOC1_RTSLOC_LOC30;
+ USART0->ROUTEPEN = USART0->ROUTEPEN | USART_ROUTEPEN_RTSPEN;
+
+ /* Set up RX pin */
+ USART0->ROUTELOC0 = (USART0->ROUTELOC0 & (~_USART_ROUTELOC0_RXLOC_MASK))
+ | USART_ROUTELOC0_RXLOC_LOC0;
+ USART0->ROUTEPEN = USART0->ROUTEPEN | USART_ROUTEPEN_RXPEN;
+
+ /* Set up TX pin */
+ USART0->ROUTELOC0 = (USART0->ROUTELOC0 & (~_USART_ROUTELOC0_TXLOC_MASK))
+ | USART_ROUTELOC0_TXLOC_LOC0;
+ USART0->ROUTEPEN = USART0->ROUTEPEN | USART_ROUTEPEN_TXPEN;
+
+ // [USART_InitIO]$
+
+ // $[USART_Misc]
+ /* Disable CTS */
+ USART0->CTRLX = USART0->CTRLX & (~USART_CTRLX_CTSEN);
+ /* Set CTS active low */
+ USART0->CTRLX = USART0->CTRLX & (~USART_CTRLX_CTSINV);
+ /* Set RTS active low */
+ USART0->CTRLX = USART0->CTRLX & (~USART_CTRLX_RTSINV);
+ /* Set CS active low */
+ USART0->CTRL = USART0->CTRL & (~USART_CTRL_CSINV);
+ /* Set TX active high */
+ USART0->CTRL = USART0->CTRL & (~USART_CTRL_TXINV);
+ /* Set RX active high */
+ USART0->CTRL = USART0->CTRL & (~USART_CTRL_RXINV);
+ // [USART_Misc]$
+
+ // $[USART_Enable]
+
+ /* Enable USART if opted by user */
+ USART_Enable(USART0, usartEnable);
+ // [USART_Enable]$
+
+}
+
+//================================================================================
+// USART1_enter_DefaultMode_from_RESET
+//================================================================================
+extern void USART1_enter_DefaultMode_from_RESET(void) {
+
+ // $[USART_InitAsync]
+ // [USART_InitAsync]$
+
+ // $[USART_InitSync]
+ // [USART_InitSync]$
+
+ // $[USART_InitPrsTrigger]
+ // [USART_InitPrsTrigger]$
+
+ // $[USART_InitIO]
+ // [USART_InitIO]$
+
+ // $[USART_Misc]
+ // [USART_Misc]$
+
+ // $[USART_Enable]
+ // [USART_Enable]$
+
+}
+
+//================================================================================
+// LEUART0_enter_DefaultMode_from_RESET
+//================================================================================
+extern void LEUART0_enter_DefaultMode_from_RESET(void) {
+
+ // $[LEUART0 initialization]
+ // [LEUART0 initialization]$
+
+}
+
+//================================================================================
+// WDOG0_enter_DefaultMode_from_RESET
+//================================================================================
+extern void WDOG0_enter_DefaultMode_from_RESET(void) {
+
+ // $[WDOG Initialization]
+ // [WDOG Initialization]$
+
+}
+
+//================================================================================
+// I2C0_enter_DefaultMode_from_RESET
+//================================================================================
+extern void I2C0_enter_DefaultMode_from_RESET(void) {
+
+ // $[I2C0 I/O setup]
+ // [I2C0 I/O setup]$
+
+ // $[I2C0 initialization]
+ // [I2C0 initialization]$
+
+}
+
+//================================================================================
+// GPCRC_enter_DefaultMode_from_RESET
+//================================================================================
+extern void GPCRC_enter_DefaultMode_from_RESET(void) {
+
+}
+
+//================================================================================
+// LDMA_enter_DefaultMode_from_RESET
+//================================================================================
+extern void LDMA_enter_DefaultMode_from_RESET(void) {
+
+}
+
+//================================================================================
+// TIMER0_enter_DefaultMode_from_RESET
+//================================================================================
+extern void TIMER0_enter_DefaultMode_from_RESET(void) {
+
+ // $[TIMER0 I/O setup]
+ // [TIMER0 I/O setup]$
+
+ // $[TIMER0 initialization]
+ // [TIMER0 initialization]$
+
+ // $[TIMER0 CC0 init]
+ // [TIMER0 CC0 init]$
+
+ // $[TIMER0 CC1 init]
+ // [TIMER0 CC1 init]$
+
+ // $[TIMER0 CC2 init]
+ // [TIMER0 CC2 init]$
+
+ // $[TIMER0 DTI init]
+ // [TIMER0 DTI init]$
+
+}
+
+//================================================================================
+// TIMER1_enter_DefaultMode_from_RESET
+//================================================================================
+extern void TIMER1_enter_DefaultMode_from_RESET(void) {
+
+ // $[TIMER1 I/O setup]
+ // [TIMER1 I/O setup]$
+
+ // $[TIMER1 initialization]
+ // [TIMER1 initialization]$
+
+ // $[TIMER1 CC0 init]
+ // [TIMER1 CC0 init]$
+
+ // $[TIMER1 CC1 init]
+ // [TIMER1 CC1 init]$
+
+ // $[TIMER1 CC2 init]
+ // [TIMER1 CC2 init]$
+
+ // $[TIMER1 CC3 init]
+ // [TIMER1 CC3 init]$
+
+}
+
+//================================================================================
+// LETIMER0_enter_DefaultMode_from_RESET
+//================================================================================
+extern void LETIMER0_enter_DefaultMode_from_RESET(void) {
+
+ // $[LETIMER0 Compare Values]
+ // [LETIMER0 Compare Values]$
+
+ // $[LETIMER0 Repeat Values]
+ // [LETIMER0 Repeat Values]$
+
+ // $[LETIMER0 Initialization]
+ // [LETIMER0 Initialization]$
+
+ // $[LETIMER0 PRS Input Triggers]
+ // [LETIMER0 PRS Input Triggers]$
+
+ // $[LETIMER0 I/O setup]
+ // [LETIMER0 I/O setup]$
+
+}
+
+//================================================================================
+// CRYOTIMER_enter_DefaultMode_from_RESET
+//================================================================================
+extern void CRYOTIMER_enter_DefaultMode_from_RESET(void) {
+
+ // $[CRYOTIMER_Init]
+ CRYOTIMER_Init_TypeDef cryoInit = CRYOTIMER_INIT_DEFAULT;
+
+ /* General settings */
+ cryoInit.enable = 1;
+ cryoInit.debugRun = 0;
+ cryoInit.em4Wakeup = 0;
+
+ /* Clocking settings */
+ /* With a frequency of 32768Hz on LFRCO, this will result in a 0.98 ms timeout */
+ cryoInit.osc = cryotimerOscLFRCO;
+ cryoInit.presc = cryotimerPresc_32;
+ cryoInit.period = cryotimerPeriod_1;
+ CRYOTIMER_Init(&cryoInit);
+ // [CRYOTIMER_Init]$
+
+}
+
+//================================================================================
+// PCNT0_enter_DefaultMode_from_RESET
+//================================================================================
+extern void PCNT0_enter_DefaultMode_from_RESET(void) {
+
+ // $[PCNT0 I/O setup]
+ // [PCNT0 I/O setup]$
+
+ // $[PCNT0 initialization]
+ // [PCNT0 initialization]$
+
+}
+
+//================================================================================
+// PRS_enter_DefaultMode_from_RESET
+//================================================================================
+extern void PRS_enter_DefaultMode_from_RESET(void) {
+
+ // $[PRS initialization]
+ // [PRS initialization]$
+
+}
+
+//================================================================================
+// PORTIO_enter_DefaultMode_from_RESET
+//================================================================================
+extern void PORTIO_enter_DefaultMode_from_RESET(void) {
+
+ // $[Port A Configuration]
+
+ /* Pin PA0 is configured to Push-pull */
+ GPIO_PinModeSet(gpioPortA, 0, gpioModePushPull, 0);
+
+ /* Pin PA1 is configured to Input enabled with pull-up */
+ GPIO_PinModeSet(gpioPortA, 1, gpioModeInputPull, 1);
+
+ /* Pin PA3 is configured to Push-pull */
+ GPIO_PinModeSet(gpioPortA, 3, gpioModePushPull, 0);
+
+ /* Pin PA5 is configured to Push-pull */
+ GPIO_PinModeSet(gpioPortA, 5, gpioModePushPull, 1);
+ // [Port A Configuration]$
+
+ // $[Port B Configuration]
+ // [Port B Configuration]$
+
+ // $[Port C Configuration]
+ // [Port C Configuration]$
+
+ // $[Port D Configuration]
+ // [Port D Configuration]$
+
+ // $[Port E Configuration]
+ // [Port E Configuration]$
+
+ // $[Port F Configuration]
+
+ /* Pin PF4 is configured to Push-pull */
+ GPIO_PinModeSet(gpioPortF, 4, gpioModePushPull, 0);
+
+ /* Pin PF5 is configured to Push-pull */
+ GPIO_PinModeSet(gpioPortF, 5, gpioModePushPull, 0);
+ // [Port F Configuration]$
+
+}
+
diff --git a/efm32/src/app.h b/efm32/src/app.h
new file mode 100644
index 0000000..3a93e7d
--- /dev/null
+++ b/efm32/src/app.h
@@ -0,0 +1,18 @@
+/*
+ * app.h
+ *
+ * Created on: Jun 26, 2018
+ * Author: conor
+ */
+
+#ifndef SRC_APP_H_
+#define SRC_APP_H_
+
+#define PRINTING_USE_VCOM
+
+#define USING_DEV_BOARD
+
+void printing_init();
+
+
+#endif /* SRC_APP_H_ */
diff --git a/efm32/src/device.c b/efm32/src/device.c
new file mode 100644
index 0000000..b7b3d77
--- /dev/null
+++ b/efm32/src/device.c
@@ -0,0 +1,131 @@
+/*
+ * device.c
+ *
+ * Created on: Jun 27, 2018
+ * Author: conor
+ */
+#include
+#include
+#include
+
+#include "em_chip.h"
+#include "em_gpio.h"
+
+#include "cbor.h"
+#include "log.h"
+#include "ctaphid.h"
+#include "util.h"
+
+// Generate @num bytes of random numbers to @dest
+// return 1 if success, error otherwise
+int ctap_generate_rng(uint8_t * dst, size_t num)
+{
+ int i;
+ for (i = 0; i < num; i++)
+ {
+ *dst++ = rand();
+ }
+ return 1;
+}
+
+uint32_t _c1 = 0, _c2 = 0;
+uint32_t ctap_atomic_count(int sel)
+{
+ if (sel == 0)
+ {
+ _c1++;
+ return _c1;
+ }
+ else
+ {
+ _c2++;
+ return _c2;
+ }
+}
+
+// Verify the user
+// return 1 if user is verified, 0 if not
+int ctap_user_verification(uint8_t arg)
+{
+ return 1;
+}
+
+// Test for user presence
+// Return 1 for user is present, 0 user not present
+int ctap_user_presence_test()
+{
+ return 1;
+}
+
+// Must be implemented by application
+// data is HID_MESSAGE_SIZE long in bytes
+void ctaphid_write_block(uint8_t * data)
+{
+ dump_hex(data, HID_MESSAGE_SIZE);
+}
+
+void heartbeat()
+{
+ static int beat = 0;
+ GPIO_PinOutToggle(gpioPortF,4);
+ GPIO_PinOutToggle(gpioPortF,5);
+// printf("heartbeat %d\r\n", CRYOTIMER->CNT);
+}
+
+uint64_t millis()
+{
+ return CRYOTIMER->CNT;
+}
+
+
+void usbhid_init()
+{
+
+}
+
+int usbhid_recv(uint8_t * msg)
+{
+ return 0;
+}
+
+void usbhid_send(uint8_t * msg)
+{
+}
+
+void usbhid_close()
+{
+}
+
+void main_loop_delay()
+{
+}
+
+
+void device_init(void)
+{
+ /* Chip errata */
+ CHIP_Init();
+ enter_DefaultMode_from_RESET();
+
+ GPIO_PinModeSet(gpioPortF,
+ 4,
+ gpioModePushPull,
+ 0);
+
+ GPIO_PinModeSet(gpioPortF,
+ 5,
+ gpioModePushPull,
+ 1);
+
+
+
+
+ printing_init();
+
+ CborEncoder test;
+ uint8_t buf[20];
+ cbor_encoder_init(&test, buf, 20, 0);
+
+ printf("Device init\r\n");
+
+}
diff --git a/efm32/src/main.c b/efm32/src/main.c
new file mode 100644
index 0000000..bde5aed
--- /dev/null
+++ b/efm32/src/main.c
@@ -0,0 +1,13 @@
+#include
+#include
+
+#include "em_chip.h"
+#include "em_cmu.h"
+#include "em_emu.h"
+#include "em_core.h"
+#include "em_gpio.h"
+
+#include "InitDevice.h"
+
+#include "app.h"
+#include "cbor.h"
diff --git a/efm32/src/printing.c b/efm32/src/printing.c
new file mode 100644
index 0000000..c09fd30
--- /dev/null
+++ b/efm32/src/printing.c
@@ -0,0 +1,82 @@
+#include "em_chip.h"
+#include "em_cmu.h"
+#include "em_emu.h"
+#include "em_core.h"
+#include "em_usart.h"
+#include "em_gpio.h"
+#include
+#include
+
+#include "app.h"
+#ifndef PRINTING_USE_VCOM
+int RETARGET_WriteChar(char c)
+{
+ return ITM_SendChar(c);
+}
+
+int RETARGET_ReadChar(void)
+{
+ return 0;
+}
+
+void setupSWOForPrint(void)
+{
+ /* Enable GPIO clock. */
+ CMU_ClockEnable(cmuClock_GPIO, true);
+
+ /* Enable Serial wire output pin */
+ GPIO->ROUTEPEN |= GPIO_ROUTEPEN_SWVPEN;
+
+ /* Set location 0 */
+ GPIO->ROUTELOC0 = GPIO_ROUTELOC0_SWVLOC_LOC0;
+
+ /* Enable output on pin - GPIO Port F, Pin 2 */
+ GPIO->P[5].MODEL &= ~(_GPIO_P_MODEL_MODE2_MASK);
+ GPIO->P[5].MODEL |= GPIO_P_MODEL_MODE2_PUSHPULL;
+
+ /* Enable debug clock AUXHFRCO */
+ CMU_OscillatorEnable(cmuOsc_AUXHFRCO, true, true);
+ CMU->OSCENCMD = CMU_OSCENCMD_AUXHFRCOEN;
+
+ /* Wait until clock is ready */
+ while (!(CMU->STATUS & CMU_STATUS_AUXHFRCORDY));
+
+ /* Enable trace in core debug */
+ CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
+ ITM->LAR = 0xC5ACCE55;
+ ITM->TER = 0x0;
+ ITM->TCR = 0x0;
+ TPI->SPPR = 2;
+ TPI->ACPR = 0x15; // changed from 0x0F on Giant, etc. to account for 19 MHz default AUXHFRCO frequency
+ ITM->TPR = 0x0;
+ DWT->CTRL = 0x400003FE;
+ ITM->TCR = 0x0001000D;
+ TPI->FFCR = 0x00000100;
+ ITM->TER = 0x1;
+}
+
+
+void printing_init()
+{
+ setupSWOForPrint();
+}
+#else
+
+int RETARGET_WriteChar(char c)
+{
+ USART_Tx(USART0,c);
+ return 0;
+}
+
+int RETARGET_ReadChar(void)
+{
+ return 0;
+}
+
+
+void printing_init()
+{
+// GPIO_PinModeSet(gpioPortA,5,gpioModePushPull,1); // VCOM enable
+}
+
+#endif
diff --git a/efm32/src/retargetio.c b/efm32/src/retargetio.c
new file mode 100644
index 0000000..05e0143
--- /dev/null
+++ b/efm32/src/retargetio.c
@@ -0,0 +1,475 @@
+/***************************************************************************//**
+ * @file
+ * @brief Provide stdio retargeting for all supported toolchains.
+ * @version 5.5.0
+ *******************************************************************************
+ * # License
+ * Copyright 2015 Silicon Labs, Inc. http://www.silabs.com
+ *******************************************************************************
+ *
+ * This file is licensed under the Silabs License Agreement. See the file
+ * "Silabs_License_Agreement.txt" for details. Before using this software for
+ * any purpose, you must agree to the terms of that agreement.
+ *
+ ******************************************************************************/
+
+/***************************************************************************//**
+ * @addtogroup RetargetIo
+ * @{ This module provide low-level stubs for retargetting stdio for all
+ * supported toolchains.
+ * The stubs are minimal yet sufficient implementations.
+ * Refer to chapter 12 in the reference manual for newlib 1.17.0
+ * for details on implementing newlib stubs.
+ ******************************************************************************/
+
+extern int RETARGET_ReadChar(void);
+extern int RETARGET_WriteChar(char c);
+
+#if !defined(__CROSSWORKS_ARM) && defined(__GNUC__)
+
+#include
+#include
+#include
+#include
+#include "em_device.h"
+
+/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
+int fileno(FILE *);
+/** @endcond */
+
+int _close(int file);
+int _fstat(int file, struct stat *st);
+int _isatty(int file);
+int _lseek(int file, int ptr, int dir);
+int _read(int file, char *ptr, int len);
+caddr_t _sbrk(int incr);
+int _write(int file, const char *ptr, int len);
+
+extern char _end; /**< Defined by the linker */
+
+/**************************************************************************//**
+ * @brief
+ * Close a file.
+ *
+ * @param[in] file
+ * File you want to close.
+ *
+ * @return
+ * Returns 0 when the file is closed.
+ *****************************************************************************/
+int _close(int file)
+{
+ (void) file;
+ return 0;
+}
+
+/**************************************************************************//**
+ * @brief Exit the program.
+ * @param[in] status The value to return to the parent process as the
+ * exit status (not used).
+ *****************************************************************************/
+void _exit(int status)
+{
+ (void) status;
+ while (1) {
+ } /* Hang here forever... */
+}
+
+/**************************************************************************//**
+ * @brief
+ * Status of an open file.
+ *
+ * @param[in] file
+ * Check status for this file.
+ *
+ * @param[in] st
+ * Status information.
+ *
+ * @return
+ * Returns 0 when st_mode is set to character special.
+ *****************************************************************************/
+int _fstat(int file, struct stat *st)
+{
+ (void) file;
+ st->st_mode = S_IFCHR;
+ return 0;
+}
+
+/**************************************************************************//**
+ * @brief Get process ID.
+ *****************************************************************************/
+int _getpid(void)
+{
+ return 1;
+}
+
+/**************************************************************************//**
+ * @brief
+ * Query whether output stream is a terminal.
+ *
+ * @param[in] file
+ * Descriptor for the file.
+ *
+ * @return
+ * Returns 1 when query is done.
+ *****************************************************************************/
+int _isatty(int file)
+{
+ (void) file;
+ return 1;
+}
+
+/**************************************************************************//**
+ * @brief Send signal to process.
+ * @param[in] pid Process id (not used).
+ * @param[in] sig Signal to send (not used).
+ *****************************************************************************/
+int _kill(int pid, int sig)
+{
+ (void)pid;
+ (void)sig;
+ return -1;
+}
+
+/**************************************************************************//**
+ * @brief
+ * Set position in a file.
+ *
+ * @param[in] file
+ * Descriptor for the file.
+ *
+ * @param[in] ptr
+ * Poiter to the argument offset.
+ *
+ * @param[in] dir
+ * Directory whence.
+ *
+ * @return
+ * Returns 0 when position is set.
+ *****************************************************************************/
+int _lseek(int file, int ptr, int dir)
+{
+ (void) file;
+ (void) ptr;
+ (void) dir;
+ return 0;
+}
+
+/**************************************************************************//**
+ * @brief
+ * Read from a file.
+ *
+ * @param[in] file
+ * Descriptor for the file you want to read from.
+ *
+ * @param[in] ptr
+ * Pointer to the chacaters that are beeing read.
+ *
+ * @param[in] len
+ * Number of characters to be read.
+ *
+ * @return
+ * Number of characters that have been read.
+ *****************************************************************************/
+int _read(int file, char *ptr, int len)
+{
+ int c, rxCount = 0;
+
+ (void) file;
+
+ while (len--) {
+ if ((c = RETARGET_ReadChar()) != -1) {
+ *ptr++ = c;
+ rxCount++;
+ } else {
+ break;
+ }
+ }
+
+ if (rxCount <= 0) {
+ return -1; /* Error exit */
+ }
+
+ return rxCount;
+}
+
+/**************************************************************************//**
+ * @brief
+ * Increase heap.
+ *
+ * @param[in] incr
+ * Number of bytes you want increment the program's data space.
+ *
+ * @return
+ * Rsturns a pointer to the start of the new area.
+ *****************************************************************************/
+caddr_t _sbrk(int incr)
+{
+ static char *heap_end;
+ char *prev_heap_end;
+
+ if (heap_end == 0) {
+ heap_end = &_end;
+ }
+
+ prev_heap_end = heap_end;
+ heap_end += incr;
+
+ return (caddr_t) prev_heap_end;
+}
+
+/**************************************************************************//**
+ * @brief
+ * Write to a file.
+ *
+ * @param[in] file
+ * Descriptor for the file you want to write to.
+ *
+ * @param[in] ptr
+ * Pointer to the text you want to write
+ *
+ * @param[in] len
+ * Number of characters to be written.
+ *
+ * @return
+ * Number of characters that have been written.
+ *****************************************************************************/
+int _write(int file, const char *ptr, int len)
+{
+ int txCount;
+
+ (void) file;
+
+ for (txCount = 0; txCount < len; txCount++) {
+ RETARGET_WriteChar(*ptr++);
+ }
+
+ return len;
+}
+#endif /* !defined( __CROSSWORKS_ARM ) && defined( __GNUC__ ) */
+
+#if defined(__ICCARM__)
+/*******************
+ *
+ * Copyright 1998-2003 IAR Systems. All rights reserved.
+ *
+ * $Revision: 38614 $
+ *
+ * This is a template implementation of the "__write" function used by
+ * the standard library. Replace it with a system-specific
+ * implementation.
+ *
+ * The "__write" function should output "size" number of bytes from
+ * "buffer" in some application-specific way. It should return the
+ * number of characters written, or _LLIO_ERROR on failure.
+ *
+ * If "buffer" is zero then __write should perform flushing of
+ * internal buffers, if any. In this case "handle" can be -1 to
+ * indicate that all handles should be flushed.
+ *
+ * The template implementation below assumes that the application
+ * provides the function "MyLowLevelPutchar". It should return the
+ * character written, or -1 on failure.
+ *
+ ********************/
+
+#include
+#include
+#include "em_common.h"
+
+_STD_BEGIN
+
+/**************************************************************************//**
+ * @brief Transmit buffer to USART1
+ * @param buffer Array of characters to send
+ * @param nbytes Number of bytes to transmit
+ * @return Number of bytes sent
+ *****************************************************************************/
+static int TxBuf(uint8_t *buffer, int nbytes)
+{
+ int i;
+
+ for (i = 0; i < nbytes; i++) {
+ RETARGET_WriteChar(*buffer++);
+ }
+ return nbytes;
+}
+
+/*
+ * If the __write implementation uses internal buffering, uncomment
+ * the following line to ensure that we are called with "buffer" as 0
+ * (i.e. flush) when the application terminates.
+ */
+size_t __write(int handle, const unsigned char * buffer, size_t size)
+{
+ /* Remove the #if #endif pair to enable the implementation */
+
+ size_t nChars = 0;
+
+ if (buffer == 0) {
+ /*
+ * This means that we should flush internal buffers. Since we
+ * don't we just return. (Remember, "handle" == -1 means that all
+ * handles should be flushed.)
+ */
+ return 0;
+ }
+
+ /* This template only writes to "standard out" and "standard err",
+ * for all other file handles it returns failure. */
+ if (handle != _LLIO_STDOUT && handle != _LLIO_STDERR) {
+ return _LLIO_ERROR;
+ }
+
+ /* Hook into USART1 transmit function here */
+ if (TxBuf((uint8_t *) buffer, size) != size) {
+ return _LLIO_ERROR;
+ } else {
+ nChars = size;
+ }
+
+ return nChars;
+}
+
+size_t __read(int handle, unsigned char * buffer, size_t size)
+{
+ /* Remove the #if #endif pair to enable the implementation */
+ int nChars = 0;
+
+ /* This template only reads from "standard in", for all other file
+ * handles it returns failure. */
+ if (handle != _LLIO_STDIN) {
+ return _LLIO_ERROR;
+ }
+
+ for (/* Empty */; size > 0; --size) {
+ int c = RETARGET_ReadChar();
+ if (c < 0) {
+ break;
+ }
+
+ *buffer++ = c;
+ ++nChars;
+ }
+
+ return nChars;
+}
+
+_STD_END
+
+#endif /* defined( __ICCARM__ ) */
+
+#if defined(__CROSSWORKS_ARM)
+
+/* Pass each of these function straight to the USART */
+int __putchar(int ch)
+{
+ return(RETARGET_WriteChar(ch));
+}
+
+int __getchar(void)
+{
+ return(RETARGET_ReadChar());
+}
+
+#endif /* defined( __CROSSWORKS_ARM ) */
+
+#if defined(__CC_ARM)
+/******************************************************************************/
+/* RETARGET.C: 'Retarget' layer for target-dependent low level functions */
+/******************************************************************************/
+/* This file is part of the uVision/ARM development tools. */
+/* Copyright (c) 2005-2006 Keil Software. All rights reserved. */
+/* This software may only be used under the terms of a valid, current, */
+/* end user licence from KEIL for a compatible version of KEIL software */
+/* development tools. Nothing else gives you the right to use this software. */
+/******************************************************************************/
+
+#include
+
+/* #pragma import(__use_no_semihosting_swi) */
+
+struct __FILE{
+ int handle;
+};
+
+/**Standard output stream*/
+FILE __stdout;
+
+/**************************************************************************//**
+ * @brief
+ * Writes character to file
+ *
+ * @param[in] f
+ * File
+ *
+ * @param[in] ch
+ * Character
+ *
+ * @return
+ * Written character
+ *****************************************************************************/
+int fputc(int ch, FILE *f)
+{
+ return(RETARGET_WriteChar(ch));
+}
+
+/**************************************************************************//**
+ * @brief
+ * Reads character from file
+ *
+ * @param[in] f
+ * File
+ *
+ * @return
+ * Character
+ *****************************************************************************/
+int fgetc(FILE *f)
+{
+ return(RETARGET_ReadChar());
+}
+
+/**************************************************************************//**
+ * @brief
+ * Tests the error indicator for the stream pointed
+ * to by file
+ *
+ * @param[in] f
+ * File
+ *
+ * @return
+ * Returns non-zero if it is set
+ *****************************************************************************/
+int ferror(FILE *f)
+{
+ /* Your implementation of ferror */
+ return EOF;
+}
+
+/**************************************************************************//**
+ * @brief
+ * Writes a character to the console
+ *
+ * @param[in] ch
+ * Character
+ *****************************************************************************/
+void _ttywrch(int ch)
+{
+ RETARGET_WriteChar(ch);
+}
+
+/**************************************************************************//**
+ * @brief
+ * Library exit function. This function is called if stack
+ * overflow occurs.
+ *
+ * @param[in] return_code
+ * Return code
+ *****************************************************************************/
+void _sys_exit(int return_code)
+{
+ label: goto label;/* endless loop */
+}
+#endif /* defined( __CC_ARM ) */
+
+/** @} (end group RetargetIo) */
diff --git a/efm8/.cproject b/efm8/.cproject
new file mode 100644
index 0000000..efc88e1
--- /dev/null
+++ b/efm8/.cproject
@@ -0,0 +1,188 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/efm8/.project b/efm8/.project
new file mode 100644
index 0000000..f26a120
--- /dev/null
+++ b/efm8/.project
@@ -0,0 +1,27 @@
+
+
+ efm8
+
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.genmakebuilder
+ clean,full,incremental,
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
+ full,incremental,
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ com.silabs.ss.framework.ide.project.sls.core.SLSProjectNature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
+
+
diff --git a/efm8/.settings/com.silabs.ss.framework.ide.project.sls.core.prefs b/efm8/.settings/com.silabs.ss.framework.ide.project.sls.core.prefs
new file mode 100644
index 0000000..b4554b4
--- /dev/null
+++ b/efm8/.settings/com.silabs.ss.framework.ide.project.sls.core.prefs
@@ -0,0 +1,2 @@
+copiedFilesOriginState={}
+eclipse.preferences.version=1
diff --git a/efm8/.settings/org.eclipse.ltk.core.refactoring.prefs b/efm8/.settings/org.eclipse.ltk.core.refactoring.prefs
new file mode 100644
index 0000000..b196c64
--- /dev/null
+++ b/efm8/.settings/org.eclipse.ltk.core.refactoring.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false
diff --git a/efm8/efm8.hwconf b/efm8/efm8.hwconf
new file mode 100644
index 0000000..90bd159
--- /dev/null
+++ b/efm8/efm8.hwconf
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/efm8/inc/InitDevice.h b/efm8/inc/InitDevice.h
new file mode 100644
index 0000000..9c1b01a
--- /dev/null
+++ b/efm8/inc/InitDevice.h
@@ -0,0 +1,33 @@
+//=========================================================
+// inc/InitDevice.h: generated by Hardware Configurator
+//
+// This file will be regenerated when saving a document.
+// leave the sections inside the "$[...]" comment tags alone
+// or they will be overwritten!
+//=========================================================
+#ifndef __INIT_DEVICE_H__
+#define __INIT_DEVICE_H__
+
+// USER CONSTANTS
+// USER PROTOTYPES
+
+// $[Mode Transition Prototypes]
+extern void enter_DefaultMode_from_RESET(void);
+// [Mode Transition Prototypes]$
+
+// $[Config(Per-Module Mode)Transition Prototypes]
+extern void WDT_0_enter_DefaultMode_from_RESET(void);
+extern void PORTS_0_enter_DefaultMode_from_RESET(void);
+extern void PBCFG_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 TIMER16_2_enter_DefaultMode_from_RESET(void);
+extern void TIMER16_3_enter_DefaultMode_from_RESET(void);
+extern void TIMER_SETUP_0_enter_DefaultMode_from_RESET(void);
+extern void UARTE_1_enter_DefaultMode_from_RESET(void);
+extern void INTERRUPT_0_enter_DefaultMode_from_RESET(void);
+extern void USBLIB_0_enter_DefaultMode_from_RESET(void);
+// [Config(Per-Module Mode)Transition Prototypes]$
+
+#endif
+
diff --git a/efm8/inc/app.h b/efm8/inc/app.h
new file mode 100644
index 0000000..4ab7d29
--- /dev/null
+++ b/efm8/inc/app.h
@@ -0,0 +1,13 @@
+/*
+ * app.h
+ *
+ * Created on: Jun 25, 2018
+ * Author: conor
+ */
+
+#ifndef INC_APP_H_
+#define INC_APP_H_
+
+#define USE_PRINTING
+
+#endif /* INC_APP_H_ */
diff --git a/efm8/inc/config/usbconfig.h b/efm8/inc/config/usbconfig.h
new file mode 100644
index 0000000..3a82317
--- /dev/null
+++ b/efm8/inc/config/usbconfig.h
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * @file usbconfig.h
+ * @brief USB protocol stack library, application supplied configuration options.
+ *******************************************************************************/
+
+//=============================================================================
+// inc/config/usbconfig.h: generated by Hardware Configurator
+//
+// This file will be regenerated when saving a document. leave the sections
+// inside the "$[...]" comment tags alone or they will be overwritten!
+//=============================================================================
+#ifndef __SILICON_LABS_USBCONFIG_H
+#define __SILICON_LABS_USBCONFIG_H
+
+// -----------------------------------------------------------------------------
+// Specify bus- or self-powered
+// -----------------------------------------------------------------------------
+// $[Device Power]
+#define SLAB_USB_BUS_POWERED 1
+// [Device Power]$
+
+// -----------------------------------------------------------------------------
+// Specify USB speed
+// -----------------------------------------------------------------------------
+// $[USB Speed]
+#define SLAB_USB_FULL_SPEED 1
+// [USB Speed]$
+
+// -----------------------------------------------------------------------------
+// Enable or disable the clock recovery
+// -----------------------------------------------------------------------------
+// $[Clock Recovery]
+#define SLAB_USB_CLOCK_RECOVERY_ENABLED 1
+// [Clock Recovery]$
+
+// -----------------------------------------------------------------------------
+// Enable or disable remote wakeup
+// -----------------------------------------------------------------------------
+// $[Remote Wake-up]
+#define SLAB_USB_REMOTE_WAKEUP_ENABLED 0
+// [Remote Wake-up]$
+
+// -----------------------------------------------------------------------------
+// Specify number of interfaces and whether any interfaces support alternate
+// settings
+// -----------------------------------------------------------------------------
+// $[Number of Interfaces]
+#define SLAB_USB_NUM_INTERFACES 1
+#define SLAB_USB_SUPPORT_ALT_INTERFACES 0
+// [Number of Interfaces]$
+
+// -----------------------------------------------------------------------------
+// Enable or disable each endpoint
+// -----------------------------------------------------------------------------
+// $[Endpoints Used]
+#define SLAB_USB_EP1IN_USED 1
+#define SLAB_USB_EP1OUT_USED 1
+#define SLAB_USB_EP2IN_USED 0
+#define SLAB_USB_EP2OUT_USED 0
+#define SLAB_USB_EP3IN_USED 0
+#define SLAB_USB_EP3OUT_USED 0
+// [Endpoints Used]$
+
+// -----------------------------------------------------------------------------
+// Specify maximum packet size for each endpoint
+// -----------------------------------------------------------------------------
+// $[Endpoint Max Packet Size]
+#define SLAB_USB_EP1IN_MAX_PACKET_SIZE 64
+#define SLAB_USB_EP1OUT_MAX_PACKET_SIZE 64
+#define SLAB_USB_EP2IN_MAX_PACKET_SIZE 1
+#define SLAB_USB_EP2OUT_MAX_PACKET_SIZE 1
+#define SLAB_USB_EP3IN_MAX_PACKET_SIZE 1
+#define SLAB_USB_EP3OUT_MAX_PACKET_SIZE 1
+// [Endpoint Max Packet Size]$
+
+// -----------------------------------------------------------------------------
+// Specify transfer type of each endpoint
+// -----------------------------------------------------------------------------
+// $[Endpoint Transfer Type]
+#define SLAB_USB_EP1IN_TRANSFER_TYPE USB_EPTYPE_INTR
+#define SLAB_USB_EP1OUT_TRANSFER_TYPE USB_EPTYPE_INTR
+#define SLAB_USB_EP2IN_TRANSFER_TYPE USB_EPTYPE_BULK
+#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
+// [Endpoint Transfer Type]$
+
+// -----------------------------------------------------------------------------
+// Enable or disable callback functions
+// -----------------------------------------------------------------------------
+// $[Callback Functions]
+#define SLAB_USB_HANDLER_CB 0
+#define SLAB_USB_IS_SELF_POWERED_CB 1
+#define SLAB_USB_RESET_CB 1
+#define SLAB_USB_SETUP_CMD_CB 1
+#define SLAB_USB_SOF_CB 0
+#define SLAB_USB_STATE_CHANGE_CB 1
+// [Callback Functions]$
+
+// -----------------------------------------------------------------------------
+// Specify number of languages supported by string descriptors.
+// -----------------------------------------------------------------------------
+// $[Number of Languages]
+#define SLAB_USB_NUM_LANGUAGES 1
+// [Number of Languages]$
+
+// -----------------------------------------------------------------------------
+// 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.
+// -----------------------------------------------------------------------------
+// $[USB Language]
+#define SLAB_USB_LANGUAGE USB_LANGID_ENUS
+// [USB Language]$
+
+// -----------------------------------------------------------------------------
+//
+// 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.
+//
+// -----------------------------------------------------------------------------
+// $[Power Save Mode]
+#define SLAB_USB_PWRSAVE_MODE USB_PWRSAVE_MODE_OFF
+// [Power Save Mode]$
+
+// -----------------------------------------------------------------------------
+// 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.
+// -----------------------------------------------------------------------------
+// $[Polled Mode]
+#define SLAB_USB_POLLED_MODE 0
+// [Polled Mode]$
+
+#endif // __SILICON_LABS_USBCONFIG_H
+
diff --git a/efm8/inc/descriptors.h b/efm8/inc/descriptors.h
new file mode 100644
index 0000000..4bad6cb
--- /dev/null
+++ b/efm8/inc/descriptors.h
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * @file descriptors.h
+ * @brief USB descriptors header file.
+ *******************************************************************************/
+
+//=============================================================================
+// inc/descriptors.h: generated by Hardware Configurator
+//
+// This file will be regenerated when saving a document. leave the sections
+// inside the "$[...]" comment tags alone or they will be overwritten!
+//=============================================================================
+#ifndef __SILICON_LABS_DESCRIPTORS_H
+#define __SILICON_LABS_DESCRIPTORS_H
+
+//-----------------------------------------------------------------------------
+// Includes
+//-----------------------------------------------------------------------------
+#include
+#include
+#include
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// -------------------- USB Identification ------------------------------------
+//
+// **********
+// NOTE: YOU MUST PROVIDE YOUR OWN USB VID/PID (below)
+// **********
+//
+// Following are the definition of the USB VID and PID. These are, by default,
+// values that are assigned to Silicon Labs. These values are provided merely
+// as an example. You may not use the Silicon Labs VID/PID values in your
+// product. You must provide your own assigned VID and PID values.
+//-----------------------------------------------------------------------------
+// $[Vendor ID]
+#define USB_VENDOR_ID htole16(0x10c4)
+// [Vendor ID]$
+
+// $[Product ID]
+#define USB_PRODUCT_ID htole16(0x8acf)
+// [Product ID]$
+
+extern SI_SEGMENT_VARIABLE(ReportDescriptor0[34], const uint8_t, SI_SEG_CODE);
+
+extern SI_SEGMENT_VARIABLE(deviceDesc[], const USB_DeviceDescriptor_TypeDef, SI_SEG_CODE);
+extern SI_SEGMENT_VARIABLE(configDesc[], const uint8_t, SI_SEG_CODE);
+extern SI_SEGMENT_VARIABLE(initstruct, const USBD_Init_TypeDef, SI_SEG_CODE);
+
+#define HID_PACKET_SIZE 64
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __SILICON_LABS_DESCRIPTORS_H
+
diff --git a/efm8/inc/printing.h b/efm8/inc/printing.h
new file mode 100644
index 0000000..25c0320
--- /dev/null
+++ b/efm8/inc/printing.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016, Conor Patrick
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+#ifndef PRINTING_H_
+#define PRINTING_H_
+
+#include
+#include
+#include
+#include "app.h"
+
+#define watchdog() (WDTCN = 0xA5)
+
+#define reboot() (RSTSRC = 1 << 4)
+
+void u2f_delay(uint32_t ms);
+
+void usb_write(uint8_t* buf, uint8_t len);
+
+
+
+#ifdef USE_PRINTING
+
+ void dump_hex(uint8_t* hex, uint8_t len);
+
+ void cputd(uint32_t i);
+ void cputx(uint32_t i);
+
+#define cputb(x) cputx((uint8_t) (x))
+#define cputl(x) cputd((uint32_t) (x))
+#define cputlx(x) cputx((uint32_t) (x))
+
+ void cprints(const char * str);
+ void cprintb(const char * tag, uint8_t c, ...);
+ void cprintd(const char * tag, uint8_t c, ...);
+ void cprintx(const char * tag, uint8_t c, ...);
+ void cprintl(const char * tag, uint8_t c, ...);
+ void cprintlx(const char * tag, uint8_t c, ...);
+
+#else
+
+ #define cprintx(x)
+ #define cprintb(x)
+ #define cprintlx(x)
+ #define cprintl(x)
+ #define cprintd(x)
+ #define cprints(x)
+
+ #define cputx(x)
+ #define cputb(x)
+ #define cputl(x)
+ #define cputlx(x)
+
+ #define putf(x)
+ #define dump_hex(x)
+
+#endif
+
+
+
+
+#endif /* BSP_H_ */
diff --git a/efm8/lib/efm8_assert/assert.c b/efm8/lib/efm8_assert/assert.c
new file mode 100644
index 0000000..b9a65c7
--- /dev/null
+++ b/efm8/lib/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/efm8_assert/assert.h b/efm8/lib/efm8_assert/assert.h
new file mode 100644
index 0000000..5b951a5
--- /dev/null
+++ b/efm8/lib/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/efm8_usb/Readme.txt b/efm8/lib/efm8_usb/Readme.txt
new file mode 100644
index 0000000..8bcff83
--- /dev/null
+++ b/efm8/lib/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/efm8_usb/inc/efm8_usb.h b/efm8/lib/efm8_usb/inc/efm8_usb.h
new file mode 100644
index 0000000..fe70a9c
--- /dev/null
+++ b/efm8/lib/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/efm8_usb/src/efm8_usbd.c b/efm8/lib/efm8_usb/src/efm8_usbd.c
new file mode 100644
index 0000000..34f94e4
--- /dev/null
+++ b/efm8/lib/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/efm8_usb/src/efm8_usbdch9.c b/efm8/lib/efm8_usb/src/efm8_usbdch9.c
new file mode 100644
index 0000000..6bb2a47
--- /dev/null
+++ b/efm8/lib/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/efm8_usb/src/efm8_usbdep.c b/efm8/lib/efm8_usb/src/efm8_usbdep.c
new file mode 100644
index 0000000..2982658
--- /dev/null
+++ b/efm8/lib/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/efm8_usb/src/efm8_usbdint.c b/efm8/lib/efm8_usb/src/efm8_usbdint.c
new file mode 100644
index 0000000..39d744f
--- /dev/null
+++ b/efm8/lib/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/efm8ub1/peripheralDrivers/inc/usb_0.h b/efm8/lib/efm8ub1/peripheralDrivers/inc/usb_0.h
new file mode 100644
index 0000000..d094fde
--- /dev/null
+++ b/efm8/lib/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/efm8ub1/peripheralDrivers/src/usb_0.c b/efm8/lib/efm8ub1/peripheralDrivers/src/usb_0.c
new file mode 100644
index 0000000..91a03ea
--- /dev/null
+++ b/efm8/lib/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/src/InitDevice.c b/efm8/src/InitDevice.c
new file mode 100644
index 0000000..20a38e9
--- /dev/null
+++ b/efm8/src/InitDevice.c
@@ -0,0 +1,366 @@
+//=========================================================
+// src/InitDevice.c: generated by Hardware Configurator
+//
+// This file will be regenerated when saving a document.
+// leave the sections inside the "$[...]" comment tags alone
+// or they will be overwritten!
+//=========================================================
+
+// USER INCLUDES
+#include
+#include "InitDevice.h"
+
+// USER PROTOTYPES
+// USER FUNCTIONS
+
+// $[Library Includes]
+#include "efm8_usb.h"
+#include "descriptors.h"
+#include "usb_0.h"
+// [Library Includes]$
+
+//==============================================================================
+// enter_DefaultMode_from_RESET
+//==============================================================================
+extern void enter_DefaultMode_from_RESET(void) {
+ // $[Config Calls]
+ // Save the SFRPAGE
+ uint8_t SFRPAGE_save = SFRPAGE;
+ WDT_0_enter_DefaultMode_from_RESET();
+ PORTS_0_enter_DefaultMode_from_RESET();
+ PBCFG_0_enter_DefaultMode_from_RESET();
+ CIP51_0_enter_DefaultMode_from_RESET();
+ CLOCK_0_enter_DefaultMode_from_RESET();
+ TIMER16_2_enter_DefaultMode_from_RESET();
+ TIMER16_3_enter_DefaultMode_from_RESET();
+ TIMER_SETUP_0_enter_DefaultMode_from_RESET();
+ UARTE_1_enter_DefaultMode_from_RESET();
+ INTERRUPT_0_enter_DefaultMode_from_RESET();
+ USBLIB_0_enter_DefaultMode_from_RESET();
+ // Restore the SFRPAGE
+ SFRPAGE = SFRPAGE_save;
+ // [Config Calls]$
+
+}
+
+extern void INTERRUPT_0_enter_DefaultMode_from_RESET(void) {
+ // $[EIE1 - Extended Interrupt Enable 1]
+ // [EIE1 - Extended Interrupt Enable 1]$
+
+ // $[EIE2 - Extended Interrupt Enable 2]
+ // [EIE2 - Extended Interrupt Enable 2]$
+
+ // $[EIP1H - Extended Interrupt Priority 1 High]
+ // [EIP1H - Extended Interrupt Priority 1 High]$
+
+ // $[EIP1 - Extended Interrupt Priority 1 Low]
+ // [EIP1 - Extended Interrupt Priority 1 Low]$
+
+ // $[EIP2 - Extended Interrupt Priority 2]
+ // [EIP2 - Extended Interrupt Priority 2]$
+
+ // $[EIP2H - Extended Interrupt Priority 2 High]
+ // [EIP2H - Extended Interrupt Priority 2 High]$
+
+ // $[IE - Interrupt Enable]
+ /***********************************************************************
+ - Enable each interrupt according to its individual mask setting
+ - Disable external interrupt 0
+ - Disable external interrupt 1
+ - Disable all SPI0 interrupts
+ - Disable all Timer 0 interrupt
+ - Disable all Timer 1 interrupt
+ - Disable Timer 2 interrupt
+ - Disable UART0 interrupt
+ ***********************************************************************/
+ SFRPAGE = 0x00;
+ IE = IE_EA__ENABLED | IE_EX0__DISABLED | IE_EX1__DISABLED
+ | IE_ESPI0__DISABLED | IE_ET0__DISABLED | IE_ET1__DISABLED
+ | IE_ET2__DISABLED | IE_ES0__DISABLED;
+ // [IE - Interrupt Enable]$
+
+ // $[IP - Interrupt Priority]
+ // [IP - Interrupt Priority]$
+
+ // $[IPH - Interrupt Priority High]
+ // [IPH - Interrupt Priority High]$
+
+}
+
+extern void USBLIB_0_enter_DefaultMode_from_RESET(void) {
+ // $[USBD Init]
+ USBD_Init (&initstruct);
+ // [USBD Init]$
+
+}
+
+extern void CLOCK_0_enter_DefaultMode_from_RESET(void) {
+ // $[HFOSC1 Setup]
+ // Ensure SYSCLK is > 24 MHz before switching to HFOSC1
+ SFRPAGE = 0x00;
+ CLKSEL = CLKSEL_CLKSL__HFOSC0 | CLKSEL_CLKDIV__SYSCLK_DIV_1;
+ while ((CLKSEL & CLKSEL_DIVRDY__BMASK) == CLKSEL_DIVRDY__NOT_READY)
+ ;
+ // [HFOSC1 Setup]$
+
+ // $[CLKSEL - Clock Select]
+ /***********************************************************************
+ - Clock derived from the Internal High Frequency Oscillator 1
+ - SYSCLK is equal to selected clock source divided by 1
+ ***********************************************************************/
+ CLKSEL = CLKSEL_CLKSL__HFOSC1 | CLKSEL_CLKDIV__SYSCLK_DIV_1;
+ while ((CLKSEL & CLKSEL_DIVRDY__BMASK) == CLKSEL_DIVRDY__NOT_READY)
+ ;
+ // [CLKSEL - Clock Select]$
+
+}
+
+extern void WDT_0_enter_DefaultMode_from_RESET(void) {
+ // $[WDTCN - Watchdog Timer Control]
+ SFRPAGE = 0x00;
+ //Disable Watchdog with key sequence
+ WDTCN = 0xDE; //First key
+ WDTCN = 0xAD; //Second key
+ // [WDTCN - Watchdog Timer Control]$
+
+}
+
+extern void CIP51_0_enter_DefaultMode_from_RESET(void) {
+ // $[PFE0CN - Prefetch Engine Control]
+ /***********************************************************************
+ - Enable the prefetch engine
+ - SYSCLK < 50 MHz
+ ***********************************************************************/
+ SFRPAGE = 0x10;
+ PFE0CN = PFE0CN_PFEN__ENABLED | PFE0CN_FLRT__SYSCLK_BELOW_50_MHZ;
+ // [PFE0CN - Prefetch Engine Control]$
+
+}
+
+extern void PBCFG_0_enter_DefaultMode_from_RESET(void) {
+ // $[XBR2 - Port I/O Crossbar 2]
+ /***********************************************************************
+ - Weak Pullups enabled
+ - Crossbar enabled
+ - UART1 TX1 RX1 routed to Port pins
+ - UART1 RTS1 unavailable at Port pin
+ - UART1 CTS1 unavailable at Port pin
+ ***********************************************************************/
+ XBR2 = XBR2_WEAKPUD__PULL_UPS_ENABLED | XBR2_XBARE__ENABLED
+ | XBR2_URT1E__ENABLED | XBR2_URT1RTSE__DISABLED
+ | XBR2_URT1CTSE__DISABLED;
+ // [XBR2 - Port I/O Crossbar 2]$
+
+ // $[PRTDRV - Port Drive Strength]
+ // [PRTDRV - Port Drive Strength]$
+
+ // $[XBR0 - Port I/O Crossbar 0]
+ // [XBR0 - Port I/O Crossbar 0]$
+
+ // $[XBR1 - Port I/O Crossbar 1]
+ // [XBR1 - Port I/O Crossbar 1]$
+
+}
+
+extern void TIMER_SETUP_0_enter_DefaultMode_from_RESET(void) {
+ // $[CKCON0 - Clock Control 0]
+ /***********************************************************************
+ - System clock divided by 12
+ - 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 3 high byte uses the clock defined by T3XCLK in TMR3CN0
+ - Timer 3 low byte uses the system clock
+ - Timer 1 uses the clock defined by the prescale field, SCA
+ ***********************************************************************/
+ CKCON0 = CKCON0_SCA__SYSCLK_DIV_12 | CKCON0_T0M__PRESCALE
+ | CKCON0_T2MH__EXTERNAL_CLOCK | CKCON0_T2ML__SYSCLK
+ | CKCON0_T3MH__EXTERNAL_CLOCK | CKCON0_T3ML__SYSCLK
+ | CKCON0_T1M__PRESCALE;
+ // [CKCON0 - Clock Control 0]$
+
+ // $[CKCON1 - Clock Control 1]
+ // [CKCON1 - Clock Control 1]$
+
+ // $[TMOD - Timer 0/1 Mode]
+ // [TMOD - Timer 0/1 Mode]$
+
+ // $[TCON - Timer 0/1 Control]
+ // [TCON - Timer 0/1 Control]$
+
+}
+
+extern void UARTE_1_enter_DefaultMode_from_RESET(void) {
+ // $[SBCON1 - UART1 Baud Rate Generator Control]
+ /***********************************************************************
+ - Enable the baud rate generator
+ - Prescaler = 1
+ ***********************************************************************/
+ SFRPAGE = 0x20;
+ SBCON1 = SBCON1_BREN__ENABLED | SBCON1_BPS__DIV_BY_1;
+ // [SBCON1 - UART1 Baud Rate Generator Control]$
+
+ // $[SMOD1 - UART1 Mode]
+ // [SMOD1 - UART1 Mode]$
+
+ // $[UART1FCN0 - UART1 FIFO Control 0]
+ // [UART1FCN0 - UART1 FIFO Control 0]$
+
+ // $[SBRLH1 - UART1 Baud Rate Generator High Byte]
+ /***********************************************************************
+ - UART1 Baud Rate Reload High = 0xFF
+ ***********************************************************************/
+ SBRLH1 = (0xFF << SBRLH1_BRH__SHIFT);
+ // [SBRLH1 - UART1 Baud Rate Generator High Byte]$
+
+ // $[SBRLL1 - UART1 Baud Rate Generator Low Byte]
+ /***********************************************************************
+ - UART1 Baud Rate Reload Low = 0x30
+ ***********************************************************************/
+ SBRLL1 = (0x30 << SBRLL1_BRL__SHIFT);
+ // [SBRLL1 - UART1 Baud Rate Generator Low Byte]$
+
+ // $[UART1LIN - UART1 LIN Configuration]
+ // [UART1LIN - UART1 LIN Configuration]$
+
+ // $[SCON1 - UART1 Serial Port Control]
+ /***********************************************************************
+ - UART1 reception enabled
+ ***********************************************************************/
+ SCON1 |= SCON1_REN__RECEIVE_ENABLED;
+ // [SCON1 - UART1 Serial Port Control]$
+
+ // $[UART1FCN1 - UART1 FIFO Control 1]
+ // [UART1FCN1 - UART1 FIFO Control 1]$
+
+}
+
+extern void TIMER16_2_enter_DefaultMode_from_RESET(void) {
+ // $[Timer Initialization]
+ // Save Timer Configuration
+ uint8_t TMR2CN0_TR2_save;
+ TMR2CN0_TR2_save = TMR2CN0 & TMR2CN0_TR2__BMASK;
+ // Stop Timer
+ TMR2CN0 &= ~(TMR2CN0_TR2__BMASK);
+ // [Timer Initialization]$
+
+ // $[TMR2CN1 - Timer 2 Control 1]
+ // [TMR2CN1 - Timer 2 Control 1]$
+
+ // $[TMR2CN0 - Timer 2 Control]
+ // [TMR2CN0 - Timer 2 Control]$
+
+ // $[TMR2H - Timer 2 High Byte]
+ // [TMR2H - Timer 2 High Byte]$
+
+ // $[TMR2L - Timer 2 Low Byte]
+ // [TMR2L - Timer 2 Low Byte]$
+
+ // $[TMR2RLH - Timer 2 Reload High Byte]
+ /***********************************************************************
+ - Timer 2 Reload High Byte = 0x44
+ ***********************************************************************/
+ TMR2RLH = (0x44 << TMR2RLH_TMR2RLH__SHIFT);
+ // [TMR2RLH - Timer 2 Reload High Byte]$
+
+ // $[TMR2RLL - Timer 2 Reload Low Byte]
+ /***********************************************************************
+ - Timer 2 Reload Low Byte = 0x80
+ ***********************************************************************/
+ TMR2RLL = (0x80 << TMR2RLL_TMR2RLL__SHIFT);
+ // [TMR2RLL - Timer 2 Reload Low Byte]$
+
+ // $[TMR2CN0]
+ /***********************************************************************
+ - Start Timer 2 running
+ ***********************************************************************/
+ TMR2CN0 |= TMR2CN0_TR2__RUN;
+ // [TMR2CN0]$
+
+ // $[Timer Restoration]
+ // Restore Timer Configuration
+ TMR2CN0 |= TMR2CN0_TR2_save;
+ // [Timer Restoration]$
+
+}
+
+extern void TIMER16_3_enter_DefaultMode_from_RESET(void) {
+ // $[Timer Initialization]
+ // Save Timer Configuration
+ uint8_t TMR3CN0_TR3_save;
+ TMR3CN0_TR3_save = TMR3CN0 & TMR3CN0_TR3__BMASK;
+ // Stop Timer
+ TMR3CN0 &= ~(TMR3CN0_TR3__BMASK);
+ // [Timer Initialization]$
+
+ // $[TMR3CN1 - Timer 3 Control 1]
+ // [TMR3CN1 - Timer 3 Control 1]$
+
+ // $[TMR3CN0 - Timer 3 Control]
+ // [TMR3CN0 - Timer 3 Control]$
+
+ // $[TMR3H - Timer 3 High Byte]
+ // [TMR3H - Timer 3 High Byte]$
+
+ // $[TMR3L - Timer 3 Low Byte]
+ // [TMR3L - Timer 3 Low Byte]$
+
+ // $[TMR3RLH - Timer 3 Reload High Byte]
+ // [TMR3RLH - Timer 3 Reload High Byte]$
+
+ // $[TMR3RLL - Timer 3 Reload Low Byte]
+ // [TMR3RLL - Timer 3 Reload Low Byte]$
+
+ // $[TMR3CN0]
+ // [TMR3CN0]$
+
+ // $[Timer Restoration]
+ // Restore Timer Configuration
+ TMR3CN0 |= TMR3CN0_TR3_save;
+ // [Timer Restoration]$
+
+}
+
+extern void PORTS_0_enter_DefaultMode_from_RESET(void) {
+ // $[P0 - Port 0 Pin Latch]
+ // [P0 - Port 0 Pin Latch]$
+
+ // $[P0MDOUT - Port 0 Output Mode]
+ /***********************************************************************
+ - P0.0 output is push-pull
+ - P0.1 output is open-drain
+ - P0.2 output is open-drain
+ - P0.3 output is open-drain
+ - P0.4 output is open-drain
+ - P0.5 output is open-drain
+ - P0.6 output is open-drain
+ - P0.7 output is open-drain
+ ***********************************************************************/
+ P0MDOUT = P0MDOUT_B0__PUSH_PULL | P0MDOUT_B1__OPEN_DRAIN
+ | P0MDOUT_B2__OPEN_DRAIN | P0MDOUT_B3__OPEN_DRAIN
+ | P0MDOUT_B4__OPEN_DRAIN | P0MDOUT_B5__OPEN_DRAIN
+ | P0MDOUT_B6__OPEN_DRAIN | P0MDOUT_B7__OPEN_DRAIN;
+ // [P0MDOUT - Port 0 Output Mode]$
+
+ // $[P0MDIN - Port 0 Input Mode]
+ // [P0MDIN - Port 0 Input Mode]$
+
+ // $[P0SKIP - Port 0 Skip]
+ // [P0SKIP - Port 0 Skip]$
+
+ // $[P0MASK - Port 0 Mask]
+ // [P0MASK - Port 0 Mask]$
+
+ // $[P0MAT - Port 0 Match]
+ // [P0MAT - Port 0 Match]$
+
+}
+
+extern void PORTS_1_enter_DefaultMode_from_RESET(void) {
+
+}
+
+extern void PORTS_2_enter_DefaultMode_from_RESET(void) {
+
+}
+
diff --git a/efm8/src/SILABS_STARTUP.A51 b/efm8/src/SILABS_STARTUP.A51
new file mode 100644
index 0000000..bef2e8d
--- /dev/null
+++ b/efm8/src/SILABS_STARTUP.A51
@@ -0,0 +1,203 @@
+$NOMOD51
+;------------------------------------------------------------------------------
+; This file is part of the C51 Compiler package
+; Copyright (c) 1988-2005 Keil Elektronik GmbH and Keil Software, Inc.
+; Version 8.01
+;
+; *** <<< Use Configuration Wizard in Context Menu >>> ***
+;------------------------------------------------------------------------------
+; STARTUP.A51: This code is executed after processor reset.
+;
+; To translate this file use A51 with the following invocation:
+;
+; A51 STARTUP.A51
+;
+; To link the modified STARTUP.OBJ file to your application use the following
+; Lx51 invocation:
+;
+; Lx51 your object file list, STARTUP.OBJ controls
+;
+;------------------------------------------------------------------------------
+;
+; User-defined Power-On Initialization of Memory
+;
+; With the following EQU statements the initialization of memory
+; at processor reset can be defined:
+;
+; IDATALEN: IDATA memory size <0x0-0x100>
+; Note: The absolute start-address of IDATA memory is always 0
+; The IDATA space overlaps physically the DATA and BIT areas.
+IDATALEN EQU 80H
+;
+; XDATASTART: XDATA memory start address <0x0-0xFFFF>
+; The absolute start address of XDATA memory
+XDATASTART EQU 0
+;
+; XDATALEN: XDATA memory size <0x0-0xFFFF>
+; The length of XDATA memory in bytes.
+XDATALEN EQU 0
+;
+; PDATASTART: PDATA memory start address <0x0-0xFFFF>
+; The absolute start address of PDATA memory
+PDATASTART EQU 0H
+;
+; PDATALEN: PDATA memory size <0x0-0xFF>
+; The length of PDATA memory in bytes.
+PDATALEN EQU 0H
+;
+;
+;------------------------------------------------------------------------------
+;
+; Reentrant Stack Initialization
+;
+; The following EQU statements define the stack pointer for reentrant
+; functions and initialized it:
+;
+; Stack Space for reentrant functions in the SMALL model.
+; IBPSTACK: Enable SMALL model reentrant stack
+; Stack space for reentrant functions in the SMALL model.
+IBPSTACK EQU 0 ; set to 1 if small reentrant is used.
+; IBPSTACKTOP: End address of SMALL model stack <0x0-0xFF>
+; Set the top of the stack to the highest location.
+IBPSTACKTOP EQU 0xFF +1 ; default 0FFH+1
+;
+;
+; Stack Space for reentrant functions in the LARGE model.
+; XBPSTACK: Enable LARGE model reentrant stack
+; Stack space for reentrant functions in the LARGE model.
+XBPSTACK EQU 0 ; set to 1 if large reentrant is used.
+; XBPSTACKTOP: End address of LARGE model stack <0x0-0xFFFF>
+; Set the top of the stack to the highest location.
+XBPSTACKTOP EQU 0xFFFF +1 ; default 0FFFFH+1
+;
+;
+; Stack Space for reentrant functions in the COMPACT model.
+; PBPSTACK: Enable COMPACT model reentrant stack
+; Stack space for reentrant functions in the COMPACT model.
+PBPSTACK EQU 0 ; set to 1 if compact reentrant is used.
+;
+; PBPSTACKTOP: End address of COMPACT model stack <0x0-0xFFFF>
+; Set the top of the stack to the highest location.
+PBPSTACKTOP EQU 0xFF +1 ; default 0FFH+1
+;
+;
+;------------------------------------------------------------------------------
+;
+; Memory Page for Using the Compact Model with 64 KByte xdata RAM
+; Compact Model Page Definition
+;
+; Define the XDATA page used for PDATA variables.
+; PPAGE must conform with the PPAGE set in the linker invocation.
+;
+; Enable pdata memory page initalization
+PPAGEENABLE EQU 0 ; set to 1 if pdata object are used.
+;
+; PPAGE number <0x0-0xFF>
+; uppermost 256-byte address of the page used for PDATA variables.
+PPAGE EQU 0
+;
+; SFR address which supplies uppermost address byte <0x0-0xFF>
+; most 8051 variants use P2 as uppermost address byte
+PPAGE_SFR DATA 0A0H
+;
+;
+;------------------------------------------------------------------------------
+
+; Standard SFR Symbols
+ACC DATA 0E0H
+B DATA 0F0H
+SP DATA 81H
+DPL DATA 82H
+DPH DATA 83H
+
+ NAME ?C_STARTUP
+
+
+?C_C51STARTUP SEGMENT CODE
+?STACK SEGMENT IDATA
+
+ RSEG ?STACK
+ DS 1
+
+ EXTRN CODE (?C_START)
+ PUBLIC ?C_STARTUP
+
+ CSEG AT 0
+?C_STARTUP: LJMP STARTUP1
+
+ RSEG ?C_C51STARTUP
+
+STARTUP1:
+
+$IF (SILABS_STARTUP = 1)
+EXTRN CODE (SiLabs_Startup)
+ LCALL SiLabs_Startup
+$ENDIF
+
+IF IDATALEN <> 0
+ MOV R0,#IDATALEN - 1
+ CLR A
+IDATALOOP: MOV @R0,A
+ DJNZ R0,IDATALOOP
+ENDIF
+
+IF XDATALEN <> 0
+ MOV DPTR,#XDATASTART
+ MOV R7,#LOW (XDATALEN)
+ IF (LOW (XDATALEN)) <> 0
+ MOV R6,#(HIGH (XDATALEN)) +1
+ ELSE
+ MOV R6,#HIGH (XDATALEN)
+ ENDIF
+ CLR A
+XDATALOOP: MOVX @DPTR,A
+ INC DPTR
+ DJNZ R7,XDATALOOP
+ DJNZ R6,XDATALOOP
+ENDIF
+
+IF PPAGEENABLE <> 0
+ MOV PPAGE_SFR,#PPAGE
+ENDIF
+
+IF PDATALEN <> 0
+ MOV R0,#LOW (PDATASTART)
+ MOV R7,#LOW (PDATALEN)
+ CLR A
+PDATALOOP: MOVX @R0,A
+ INC R0
+ DJNZ R7,PDATALOOP
+ENDIF
+
+IF IBPSTACK <> 0
+EXTRN DATA (?C_IBP)
+
+ MOV ?C_IBP,#LOW IBPSTACKTOP
+ENDIF
+
+IF XBPSTACK <> 0
+EXTRN DATA (?C_XBP)
+
+ MOV ?C_XBP,#HIGH XBPSTACKTOP
+ MOV ?C_XBP+1,#LOW XBPSTACKTOP
+ENDIF
+
+IF PBPSTACK <> 0
+EXTRN DATA (?C_PBP)
+ MOV ?C_PBP,#LOW PBPSTACKTOP
+ENDIF
+
+ MOV SP,#?STACK-1
+
+; This code is required if you use L51_BANK.A51 with Banking Mode 4
+; Code Banking
+; Select Bank 0 for L51_BANK.A51 Mode 4
+$IF (USE_BANKING = 1)
+; Initialize bank mechanism to code bank 0 when using L51_BANK.A51 with Banking Mode 4.
+EXTRN CODE (?B_SWITCH0)
+ CALL ?B_SWITCH0 ; init bank mechanism to code bank 0
+$ENDIF
+;
+ LJMP ?C_START
+
+ END
diff --git a/efm8/src/callback.c b/efm8/src/callback.c
new file mode 100644
index 0000000..57e5168
--- /dev/null
+++ b/efm8/src/callback.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2016, Conor Patrick
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+#include
+#include
+#include
+#include "descriptors.h"
+
+#define UNUSED(expr) do { (void)(expr); } while (0)
+
+#define HID_INTERFACE_INDEX 0
+
+uint8_t tmpBuffer;
+
+
+
+void USBD_ResetCb(void) {
+// u2f_print_ev("USBD_ResetCb\r\n");
+}
+
+
+void USBD_DeviceStateChangeCb(USBD_State_TypeDef oldState,
+ USBD_State_TypeDef newState) {
+
+ UNUSED(oldState);
+ UNUSED(newState);
+
+// u2f_print_ev("USBD_DeviceStateChangeCb\r\n");
+}
+
+bool USBD_IsSelfPoweredCb(void) {
+ return false;
+}
+
+// Necessary routine for USB HID
+USB_Status_TypeDef USBD_SetupCmdCb(
+ SI_VARIABLE_SEGMENT_POINTER(setup, USB_Setup_TypeDef, MEM_MODEL_SEG)) {
+
+ USB_Status_TypeDef retVal = USB_STATUS_REQ_UNHANDLED;
+
+
+ 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.
+
+ switch (setup->bRequest) {
+ case GET_DESCRIPTOR:
+ if (setup->wIndex == 0)
+ {
+ if ((setup->wValue >> 8) == USB_HID_REPORT_DESCRIPTOR) {
+
+ USBD_Write(EP0, ReportDescriptor0,
+ EFM8_MIN(sizeof(ReportDescriptor0), setup->wLength),
+ false);
+ retVal = USB_STATUS_OK;
+
+ } else if ((setup->wValue >> 8) == USB_HID_DESCRIPTOR) {
+
+ USBD_Write(EP0, (&configDesc[18]),
+ EFM8_MIN(USB_HID_DESCSIZE, setup->wLength), false);
+ retVal = USB_STATUS_OK;
+
+ }
+ }
+ break;
+ }
+ }
+ else if ((setup->bmRequestType.Type == USB_SETUP_TYPE_CLASS)
+ && (setup->bmRequestType.Recipient == USB_SETUP_RECIPIENT_INTERFACE)
+ && (setup->wIndex == HID_INTERFACE_INDEX))
+ {
+ // Implement the necessary HID class specific commands.
+ switch (setup->bRequest)
+ {
+ case USB_HID_SET_IDLE:
+ if (((setup->wValue & 0xFF) == 0) // Report ID
+ && (setup->wLength == 0)
+ && (setup->bmRequestType.Direction != USB_SETUP_DIR_IN))
+ {
+ retVal = USB_STATUS_OK;
+ }
+ break;
+
+ case USB_HID_GET_IDLE:
+ if ((setup->wValue == 0) // Report ID
+ && (setup->wLength == 1)
+ && (setup->bmRequestType.Direction == USB_SETUP_DIR_IN))
+ {
+ tmpBuffer = 24;
+ USBD_Write(EP0, &tmpBuffer, 1, false);
+ retVal = USB_STATUS_OK;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return retVal;
+}
+
+
+
+
+uint8_t hidmsgbuf[64];
+uint16_t USBD_XferCompleteCb(uint8_t epAddr, USB_Status_TypeDef status,
+ uint16_t xferred, uint16_t remaining ) {
+
+ UNUSED(status);
+ UNUSED(xferred);
+ UNUSED(remaining);
+
+
+ if (epAddr == EP1OUT)
+ {
+// set_app_u2f_hid_msg((struct u2f_hid_msg *) hidmsgbuf );
+ }
+ return 0;
+}
+
+
diff --git a/efm8/src/descriptors.c b/efm8/src/descriptors.c
new file mode 100644
index 0000000..ee84d4e
--- /dev/null
+++ b/efm8/src/descriptors.c
@@ -0,0 +1,174 @@
+//=============================================================================
+// src/descriptors.c: generated by Hardware Configurator
+//
+// This file is only generated if it does not exist. Modifications in this file
+// will persist even if Configurator generates code. To refresh this file,
+// you must first delete it and then regenerate code.
+//=============================================================================
+//-----------------------------------------------------------------------------
+// Includes
+//-----------------------------------------------------------------------------
+#include
+#include
+#include
+#include
+#include
+#include "descriptors.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// HID Report Descriptor for Interface 0
+SI_SEGMENT_VARIABLE(ReportDescriptor0[34],
+ const uint8_t,
+ SI_SEG_CODE) =
+{
+
+ 0x06, 0xd0, 0xf1,// USAGE_PAGE (FIDO Alliance)
+ 0x09, 0x01,// USAGE (Keyboard)
+ 0xa1, 0x01,// COLLECTION (Application)
+
+ 0x09, 0x20, // USAGE (Input Report Data)
+ 0x15, 0x00, // LOGICAL_MINIMUM (0)
+ 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
+ 0x75, 0x08, // REPORT_SIZE (8)
+ 0x95, HID_PACKET_SIZE, // REPORT_COUNT (64)
+ 0x81, 0x02, // INPUT (Data,Var,Abs)
+ 0x09, 0x21, // USAGE(Output Report Data)
+ 0x15, 0x00, // LOGICAL_MINIMUM (0)
+ 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
+ 0x75, 0x08, // REPORT_SIZE (8)
+ 0x95, HID_PACKET_SIZE, // REPORT_COUNT (64)
+ 0x91, 0x02, // OUTPUT (Data,Var,Abs)
+
+
+ 0xc0,// END_COLLECTION
+
+};
+SI_SEGMENT_VARIABLE(deviceDesc[],
+ const USB_DeviceDescriptor_TypeDef,
+ SI_SEG_CODE) =
+{
+ USB_DEVICE_DESCSIZE, // bLength
+ USB_DEVICE_DESCRIPTOR,// bLength
+ htole16(0x0200),// bcdUSB
+ 0,// bDeviceClass
+ 0,// bDeviceSubClass
+ 0,// bDeviceProtocol
+ 64,// bMaxPacketSize
+ USB_VENDOR_ID,// idVendor
+ USB_PRODUCT_ID,// idProduct
+ htole16(0x0100),// bcdDevice
+ 1,// iManufacturer
+ 2,// iProduct
+ 3,// iSerialNumber
+ 1,// bNumConfigurations
+};
+
+SI_SEGMENT_VARIABLE(configDesc[],
+ const uint8_t,
+ SI_SEG_CODE) =
+{
+ USB_CONFIG_DESCSIZE, // bLength
+ USB_CONFIG_DESCRIPTOR,// bLength
+ 0x29,// wTotalLength(LSB)
+ 0x00,// wTotalLength(MSB)
+ 1,// bNumInterfaces
+ 1,// bConfigurationValue
+ 0,// iConfiguration
+
+ CONFIG_DESC_BM_RESERVED_D7,// bmAttrib: Bus powered
+
+ CONFIG_DESC_MAXPOWER_mA(100),// bMaxPower: 100 mA
+
+ //Interface 0 Descriptor
+ USB_INTERFACE_DESCSIZE,// bLength
+ USB_INTERFACE_DESCRIPTOR,// bDescriptorType
+ 0,// bInterfaceNumber
+ 0,// bAlternateSetting
+ 2,// bNumEndpoints
+ 3,// bInterfaceClass: HID (Human Interface Device)
+ 0,// bInterfaceSubClass
+ 0,// bInterfaceProtocol
+ 4,// iInterface
+
+ //HID Descriptor
+ USB_HID_DESCSIZE,// bLength
+ USB_HID_DESCRIPTOR,// bLength
+ 0x11,// bcdHID (LSB)
+ 0x01,// bcdHID (MSB)
+ 0,// bCountryCode
+ 1,// bNumDescriptors
+ USB_HID_REPORT_DESCRIPTOR,// bDescriptorType
+ sizeof( ReportDescriptor0 ),// wDescriptorLength(LSB)
+ sizeof( ReportDescriptor0 )>>8,// wDescriptorLength(MSB)
+
+ //Endpoint 1 IN Descriptor
+ USB_ENDPOINT_DESCSIZE,// bLength
+ USB_ENDPOINT_DESCRIPTOR,// bDescriptorType
+ 0x81,// bEndpointAddress
+ USB_EPTYPE_INTR,// bAttrib
+ HID_PACKET_SIZE,// wMaxPacketSize (LSB)
+ 0x00,// wMaxPacketSize (MSB)
+ 5,// bInterval
+
+ //Endpoint 1 OUT Descriptor
+ USB_ENDPOINT_DESCSIZE,// bLength
+ USB_ENDPOINT_DESCRIPTOR,// bDescriptorType
+ 0x01,// bEndpointAddress
+ USB_EPTYPE_INTR,// bAttrib
+ HID_PACKET_SIZE,// wMaxPacketSize (LSB)
+ 0x00,// wMaxPacketSize (MSB)
+ 5,// bInterval
+};
+
+#define LANG_STRING htole16( SLAB_USB_LANGUAGE )
+#define MFR_STRING 'S','i','l','i','c','o','n',' ','L','a','b','s','\0'
+#define MFR_SIZE 13
+#define PROD_STRING 'E','O','S',' ','W','a','l','l','e','t','\0'
+#define PROD_SIZE 11
+#define SER_STRING '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','\0'
+#define SER_SIZE 17
+#define CFG_STRING 'C','o','n','f','i','g',' ','#','1','\0'
+#define CFG_SIZE 10
+#define INT0_STRING 'E','O','S',' ','W','a','l','l','e','t','\0'
+#define INT0_SIZE 11
+
+LANGID_STATIC_CONST_STRING_DESC( langDesc[], LANG_STRING );
+UTF16LE_PACKED_STATIC_CONST_STRING_DESC( mfrDesc[], MFR_STRING, MFR_SIZE);
+UTF16LE_PACKED_STATIC_CONST_STRING_DESC( prodDesc[], PROD_STRING, PROD_SIZE);
+UTF16LE_PACKED_STATIC_CONST_STRING_DESC( serDesc[], SER_STRING, SER_SIZE);
+UTF16LE_PACKED_STATIC_CONST_STRING_DESC( cfgDesc[], CFG_STRING, CFG_SIZE);
+UTF16LE_PACKED_STATIC_CONST_STRING_DESC( int0Desc[], INT0_STRING, INT0_SIZE);
+
+
+
+//-----------------------------------------------------------------------------
+SI_SEGMENT_POINTER(myUsbStringTable_USEnglish[],
+ static const USB_StringDescriptor_TypeDef,
+ const SI_SEG_CODE) =
+{
+ langDesc,
+ mfrDesc,
+ prodDesc,
+ serDesc,
+ int0Desc,
+
+};
+
+//-----------------------------------------------------------------------------
+SI_SEGMENT_VARIABLE(initstruct,
+ const USBD_Init_TypeDef,
+ SI_SEG_CODE) =
+{
+ deviceDesc, // deviceDescriptor
+ configDesc,// configDescriptor
+ myUsbStringTable_USEnglish,// stringDescriptors
+ sizeof(myUsbStringTable_USEnglish) / sizeof(void *)// numberOfStrings
+};
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/efm8/src/main.c b/efm8/src/main.c
new file mode 100644
index 0000000..ba0029f
--- /dev/null
+++ b/efm8/src/main.c
@@ -0,0 +1,17 @@
+#include
+#include "InitDevice.h"
+#include "efm8_usb.h"
+#include "printing.h"
+
+
+
+
+int main(void) {
+ enter_DefaultMode_from_RESET();
+
+ cprints("hello,world\r\n");
+
+ while (1) {
+
+ }
+}
diff --git a/efm8/src/printing.c b/efm8/src/printing.c
new file mode 100644
index 0000000..ca5b87c
--- /dev/null
+++ b/efm8/src/printing.c
@@ -0,0 +1,171 @@
+/*
+ * printing.c
+ *
+ * Created on: Jun 25, 2018
+ * Author: conor
+ */
+
+#include
+#include
+#include
+#include
+#include "printing.h"
+
+void putf(char c)
+{
+ uint8_t i;
+ SBUF0 = c;
+ // Blocking delay that works for 115200 baud on this device (<1ms)
+ 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;
+ for (i=0 ; i < len ; i++)
+ {
+ if (hex[i]<0x10)
+ {
+ putf('0');
+ }
+ cputb(hex[i]);
+ }
+ cprints("\r\n");
+}
+
+
+void cprints(char* d)
+{
+ while(*d)
+ {
+ // UART0 output queue
+ putf(*d++);
+ }
+}
+
+static void int2str_reduce_n(char ** snum, uint32_t copy, uint8_t n)
+{
+ do
+ {
+ copy /= n;
+ }while(copy);
+}
+
+
+static const char * __digits = "0123456789abcdef";
+static char xdata __int2str_buf[9];
+
+static void int2str_map_n(char ** snum, uint32_t i, uint8_t n)
+{
+ do
+ {
+ *--*snum = __digits[i % n];
+ i /= n;
+ }while(i);
+}
+
+#define dint2str(i) __int2strn(i,10)
+#define xint2str(i) __int2strn(i,16)
+
+char * __int2strn(int32_t i, uint8_t n)
+{
+ char * snum = __int2str_buf;
+ if (i<0) *snum++ = '-';
+ int2str_reduce_n(&snum, i, n);
+ *snum = '\0';
+ int2str_map_n(&snum, i, n);
+ return snum;
+}
+
+void cputd(int32_t i)
+{
+ cprints(dint2str((int32_t)i));
+}
+
+void cputx(int32_t i)
+{
+ cprints(xint2str(i));
+}
+
+static void put_space()
+{
+ cprints(" ");
+}
+static void put_line()
+{
+ cprints("\r\n");
+}
+
+void cprintd(const char * tag, uint8_t c, ...)
+{
+ va_list args;
+ cprints(tag);
+ va_start(args,c);
+ while(c--)
+ {
+ cputd((int32_t)va_arg(args, int16_t));
+
+ }
+ put_line();
+ va_end(args);
+}
+
+void cprintl(const char * tag, uint8_t c, ...)
+{
+ va_list args;
+ cprints(tag);
+ va_start(args,c);
+ while(c--)
+ {
+ cputl(va_arg(args, int32_t));
+ cprints(" ");
+ }
+ put_line();
+ va_end(args);
+}
+
+void cprintx(const char * tag, uint8_t c, ...)
+{
+ va_list args;
+ cprints(tag);
+ va_start(args,c);
+ while(c--)
+ {
+ cputx((int32_t)va_arg(args, uint16_t));
+ cprints(" ");
+ }
+ put_line();
+ va_end(args);
+}
+
+void cprintb(const char * tag, uint8_t c, ...)
+{
+ va_list args;
+ cprints(tag);
+ va_start(args,c);
+ while(c--)
+ {
+ cputb(va_arg(args, uint8_t));
+ put_space();
+ }
+ put_line();
+ va_end(args);
+}
+
+void cprintlx(const char * tag, uint8_t c, ...)
+{
+ va_list args;
+ cprints(tag);
+ va_start(args,c);
+ while(c--)
+ {
+ cputlx(va_arg(args, int32_t));
+ put_space();
+ }
+ put_line();
+ va_end(args);
+}
diff --git a/cose_key.h b/fido2/cose_key.h
similarity index 100%
rename from cose_key.h
rename to fido2/cose_key.h
diff --git a/crypto.c b/fido2/crypto.c
similarity index 99%
rename from crypto.c
rename to fido2/crypto.c
index 3007cd9..d11efe3 100644
--- a/crypto.c
+++ b/fido2/crypto.c
@@ -6,6 +6,8 @@
#include
#include
+
+
#include "util.h"
#include "crypto.h"
diff --git a/crypto.h b/fido2/crypto.h
similarity index 100%
rename from crypto.h
rename to fido2/crypto.h
diff --git a/ctap.c b/fido2/ctap.c
similarity index 100%
rename from ctap.c
rename to fido2/ctap.c
diff --git a/ctap.h b/fido2/ctap.h
similarity index 91%
rename from ctap.h
rename to fido2/ctap.h
index 9fd4c73..013fa9d 100644
--- a/ctap.h
+++ b/fido2/ctap.h
@@ -2,6 +2,7 @@
#define _CTAP_H
#include "cbor.h"
+#include "device.h"
#define CTAP_MAKE_CREDENTIAL 0x01
#define CTAP_GET_ASSERTION 0x02
@@ -257,25 +258,7 @@ void ctap_reset();
int8_t ctap_device_locked();
-// Test for user presence
-// Return 1 for user is present, 0 user not present
-extern int ctap_user_presence_test();
-// Generate @num bytes of random numbers to @dest
-// return 1 if success, error otherwise
-extern int ctap_generate_rng(uint8_t * dst, size_t num);
-
-// Increment atomic counter and return it.
-// Must support two counters, @sel selects counter0 or counter1.
-uint32_t ctap_atomic_count(int sel);
-
-// Verify the user
-// return 1 if user is verified, 0 if not
-extern int ctap_user_verification(uint8_t arg);
-
-// Must be implemented by application
-// data is HID_MESSAGE_SIZE long in bytes
-extern void ctaphid_write_block(uint8_t * data);
#endif
diff --git a/ctap_errors.h b/fido2/ctap_errors.h
similarity index 100%
rename from ctap_errors.h
rename to fido2/ctap_errors.h
diff --git a/ctap_parse.c b/fido2/ctap_parse.c
similarity index 100%
rename from ctap_parse.c
rename to fido2/ctap_parse.c
diff --git a/ctap_parse.h b/fido2/ctap_parse.h
similarity index 100%
rename from ctap_parse.h
rename to fido2/ctap_parse.h
diff --git a/ctaphid.c b/fido2/ctaphid.c
similarity index 100%
rename from ctaphid.c
rename to fido2/ctaphid.c
diff --git a/ctaphid.h b/fido2/ctaphid.h
similarity index 100%
rename from ctaphid.h
rename to fido2/ctaphid.h
diff --git a/fido2/device.h b/fido2/device.h
new file mode 100644
index 0000000..425f2ef
--- /dev/null
+++ b/fido2/device.h
@@ -0,0 +1,44 @@
+#ifndef _DEVICE_H
+#define _DEVICE_H
+
+void device_init();
+
+uint64_t millis();
+
+// HID message size in bytes
+#define HID_MESSAGE_SIZE 64
+
+void usbhid_init();
+
+int usbhid_recv(uint8_t * msg);
+
+void usbhid_send(uint8_t * msg);
+
+void usbhid_close();
+
+void main_loop_delay();
+
+void heartbeat();
+
+
+// Test for user presence
+// Return 1 for user is present, 0 user not present
+extern int ctap_user_presence_test();
+
+// Generate @num bytes of random numbers to @dest
+// return 1 if success, error otherwise
+extern int ctap_generate_rng(uint8_t * dst, size_t num);
+
+// Increment atomic counter and return it.
+// Must support two counters, @sel selects counter0 or counter1.
+uint32_t ctap_atomic_count(int sel);
+
+// Verify the user
+// return 1 if user is verified, 0 if not
+extern int ctap_user_verification(uint8_t arg);
+
+// Must be implemented by application
+// data is HID_MESSAGE_SIZE long in bytes
+extern void ctaphid_write_block(uint8_t * data);
+
+#endif
diff --git a/log.c b/fido2/log.c
similarity index 100%
rename from log.c
rename to fido2/log.c
diff --git a/log.h b/fido2/log.h
similarity index 100%
rename from log.h
rename to fido2/log.h
diff --git a/main.c b/fido2/main.c
similarity index 100%
rename from main.c
rename to fido2/main.c
index ea23f4d..5c2c02f 100644
--- a/main.c
+++ b/fido2/main.c
@@ -38,8 +38,8 @@ int main(int argc, char * argv[])
TAG_ERR
);
- printf1(TAG_GEN,"init device\n");
device_init();
+ printf1(TAG_GEN,"init device\n");
printf1(TAG_GEN,"init ctaphid\n");
ctaphid_init();
diff --git a/stubs.c b/fido2/stubs.c
similarity index 100%
rename from stubs.c
rename to fido2/stubs.c
diff --git a/test_power.c b/fido2/test_power.c
similarity index 100%
rename from test_power.c
rename to fido2/test_power.c
diff --git a/u2f.c b/fido2/u2f.c
similarity index 100%
rename from u2f.c
rename to fido2/u2f.c
diff --git a/u2f.h b/fido2/u2f.h
similarity index 100%
rename from u2f.h
rename to fido2/u2f.h
diff --git a/util.c b/fido2/util.c
similarity index 100%
rename from util.c
rename to fido2/util.c
diff --git a/util.h b/fido2/util.h
similarity index 100%
rename from util.h
rename to fido2/util.h
diff --git a/old-crypto.c b/old-crypto.c
deleted file mode 100644
index 9fa66cc..0000000
--- a/old-crypto.c
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * Wrapper for crypto implementation on device
- *
- * */
-#include
-#include
-#include
-
-#include "sdk_common.h"
-#include "nrf_assert.h"
-#include "nrf_log.h"
-#include "nrf_log_ctrl.h"
-#include "nrf_log_default_backends.h"
-#include "nrf_crypto.h"
-#include "nrf_crypto_ecc.h"
-#include "nrf_crypto_error.h"
-#include "nrf_crypto_ecdsa.h"
-#include "mem_manager.h"
-
-
-#include "util.h"
-#include "crypto.h"
-#include "sha256.h"
-#include "uECC.h"
-#include "aes.h"
-#include "ctap.h"
-
-
-const uint8_t attestation_cert_der[];
-const uint16_t attestation_cert_der_size;
-const uint8_t attestation_key[];
-const uint16_t attestation_key_size;
-
-
-
-static SHA256_CTX sha256_ctx;
-
-
-static const uint8_t * _signing_key = NULL;
-
-// Secrets for testing only
-static uint8_t master_secret[32] = "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff"
- "\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x77\x66\x55\x44\x33\x22\x11\x00";
-
-static uint8_t transport_secret[32] = "\x10\x01\x22\x33\x44\x55\x66\x77\x87\x90\x0a\xbb\x3c\xd8\xee\xff"
- "\xff\xee\x8d\x1c\x3b\xfa\x99\x88\x77\x86\x55\x44\xd3\xff\x33\x00";
-
-
-
-void crypto_sha256_init()
-{
- sha256_init(&sha256_ctx);
-}
-
-void crypto_reset_master_secret()
-{
- ctap_generate_rng(master_secret, 32);
-}
-
-
-void crypto_sha256_update(uint8_t * data, size_t len)
-{
- sha256_update(&sha256_ctx, data, len);
-}
-
-void crypto_sha256_update_secret()
-{
- sha256_update(&sha256_ctx, master_secret, 32);
-}
-
-void crypto_sha256_final(uint8_t * hash)
-{
- sha256_final(&sha256_ctx, hash);
-}
-
-void crypto_sha256_hmac_init(uint8_t * key, uint32_t klen, uint8_t * hmac)
-{
- uint8_t buf[64];
- int i;
- memset(buf, 0, sizeof(buf));
-
- if (key == CRYPTO_MASTER_KEY)
- {
- key = master_secret;
- klen = sizeof(master_secret);
- }
-
- if(klen > 64)
- {
- printf("Error, key size must be <= 64\n");
- exit(1);
- }
-
- memmove(buf, key, klen);
-
- for (i = 0; i < sizeof(buf); i++)
- {
- buf[i] = buf[i] ^ 0x36;
- }
-
- crypto_sha256_init();
- crypto_sha256_update(buf, 64);
-}
-
-void crypto_sha256_hmac_final(uint8_t * key, uint32_t klen, uint8_t * hmac)
-{
- uint8_t buf[64];
- int i;
- crypto_sha256_final(hmac);
- memset(buf, 0, sizeof(buf));
- if (key == CRYPTO_MASTER_KEY)
- {
- key = master_secret;
- klen = sizeof(master_secret);
- }
-
-
- if(klen > 64)
- {
- printf("Error, key size must be <= 64\n");
- exit(1);
- }
- memmove(buf, key, klen);
-
- for (i = 0; i < sizeof(buf); i++)
- {
- buf[i] = buf[i] ^ 0x5c;
- }
-
- crypto_sha256_init();
- crypto_sha256_update(buf, 64);
- crypto_sha256_update(hmac, 32);
- crypto_sha256_final(hmac);
-}
-
-
-void crypto_ecc256_init()
-{
- int ret;
- ret = nrf_mem_init();
- if (ret != NRF_SUCCESS)
- {
- printf("nrf_mem_init fail %d\n", ret);
- exit(1);
- }
-
- ret = nrf_crypto_init();
- if (ret != NRF_SUCCESS)
- {
- printf("nrf_crypto_init fail 0x%02x\n", ret);
- printf("nrf_crypto_init fail %s\n", nrf_strerror_get(ret));
- printf("nrf_crypto_init fail %s\n", nrf_strerror_get(ret));
- printf("nrf_crypto_init fail %s\n", nrf_strerror_get(ret));
- exit(1);
- }
-
- uECC_set_rng((uECC_RNG_Function)ctap_generate_rng);
-}
-
-
-void crypto_ecc256_load_attestation_key()
-{
- _signing_key = attestation_key;
-}
-
-void crypto_ecc256_sign(uint8_t * data, int len, uint8_t * sig)
-{
- nrf_crypto_ecc_private_key_t privkey;
- nrf_crypto_ecdsa_sign_context_t context;
- ret_code_t ret = NRF_SUCCESS;
- size_t sigsz;
-
- /*dump_hex(_signing_key,32);*/
- memset(&privkey, 0, sizeof(nrf_crypto_ecc_private_key_t));
- memset(&context, 0, sizeof(nrf_crypto_ecdsa_sign_context_t));
-
- ret = nrf_crypto_ecc_private_key_from_raw(&g_nrf_crypto_ecc_secp256r1_curve_info,
- &privkey,
- _signing_key,
- (size_t)32);
- if (ret != NRF_SUCCESS)
- {
- printf("private_key_from_raw failed\n");
- exit(1);
- }
-
- sigsz = 64;
- ret = nrf_crypto_ecdsa_sign(&context,
- &privkey,
- data,
- (size_t)len,
- sig,
- &sigsz);
- if (ret != NRF_SUCCESS)
- {
- printf("crypto_ecdsa failed\n");
- exit(1);
- }
-
- if (sigsz != 64)
- {
- printf("sig wrong size %d\n", sigsz);
- exit(1);
- }
-
- ret = nrf_crypto_ecc_private_key_free(&privkey);
-
- if (ret != NRF_SUCCESS)
- {
- printf("crypto free failed\n");
- exit(1);
- }
-
-}
-
-
-/*int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve);*/
-void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8_t * y)
-{
- nrf_crypto_ecc_private_key_t nrfprivkey;
- nrf_crypto_ecc_public_key_calculate_context_t context;
- nrf_crypto_ecc_public_key_t nrfpubkey;
- uint8_t privkey[32];
- uint8_t pubkey[64];
- size_t sz;
- ret_code_t ret = NRF_SUCCESS;
- memset(&nrfprivkey, 0, sizeof(nrf_crypto_ecc_private_key_t));
- memset(&context, 0, sizeof(nrf_crypto_ecc_public_key_calculate_context_t));
-
- generate_private_key(data,len,NULL,0,privkey);
-
-
- ret = nrf_crypto_ecc_private_key_from_raw(&g_nrf_crypto_ecc_secp256r1_curve_info,
- &nrfprivkey,
- privkey,
- (size_t)32);
- if (ret != NRF_SUCCESS)
- {
- printf("private_key_from_raw failed\n");
- exit(1);
- }
-
- ret = nrf_crypto_ecc_public_key_calculate(&context, &nrfprivkey, &nrfpubkey);
-
- if (ret != NRF_SUCCESS)
- {
- printf("public key compute failed: %s\n", nrf_strerror_get(ret));
- exit(1);
- }
-
- sz = sizeof(pubkey);
- nrf_crypto_ecc_public_key_to_raw(&nrfpubkey, pubkey, &sz);
-
- memmove(x,pubkey,32);
- memmove(y,pubkey+32,32);
-
- nrf_crypto_ecc_public_key_free(&nrfpubkey);
- nrf_crypto_ecc_private_key_free(&nrfprivkey);
-
-}
-
-void crypto_ecc256_load_key(uint8_t * data, int len, uint8_t * data2, int len2)
-{
- static uint8_t privkey[32];
- generate_private_key(data,len,data2,len2,privkey);
- _signing_key = privkey;
-}
-
-void crypto_ecc256_make_key_pair(uint8_t * pubkey, uint8_t * privkey)
-{
- if (uECC_make_key(pubkey, privkey, uECC_secp256r1()) != 1)
- {
- printf("Error, uECC_make_key failed\n");
- exit(1);
- }
-}
-
-void crypto_ecc256_shared_secret(const uint8_t * pubkey, const uint8_t * privkey, uint8_t * shared_secret)
-{
- if (uECC_shared_secret(pubkey, privkey, shared_secret, uECC_secp256r1()) != 1)
- {
- printf("Error, uECC_shared_secret failed\n");
- exit(1);
- }
-
-}
-
-void generate_private_key(uint8_t * data, int len, uint8_t * data2, int len2, uint8_t * privkey)
-{
- crypto_sha256_hmac_init(CRYPTO_MASTER_KEY, 0, privkey);
- crypto_sha256_update(data, len);
- crypto_sha256_update(data2, len2);
- crypto_sha256_update(master_secret, 32);
- crypto_sha256_hmac_final(CRYPTO_MASTER_KEY, 0, privkey);
-}
-
-struct AES_ctx aes_ctx;
-void crypto_aes256_init(uint8_t * key, uint8_t * nonce)
-{
- if (key == CRYPTO_TRANSPORT_KEY)
- {
- AES_init_ctx(&aes_ctx, transport_secret);
- }
- else
- {
- AES_init_ctx(&aes_ctx, key);
- }
- if (nonce == NULL)
- {
- memset(aes_ctx.Iv, 0, 16);
- }
- else
- {
- memmove(aes_ctx.Iv, nonce, 16);
- }
-}
-
-// prevent round key recomputation
-void crypto_aes256_reset_iv(uint8_t * nonce)
-{
- if (nonce == NULL)
- {
- memset(aes_ctx.Iv, 0, 16);
- }
- else
- {
- memmove(aes_ctx.Iv, nonce, 16);
- }
-}
-
-void crypto_aes256_decrypt(uint8_t * buf, int length)
-{
- AES_CBC_decrypt_buffer(&aes_ctx, buf, length);
-}
-
-void crypto_aes256_encrypt(uint8_t * buf, int length)
-{
- AES_CBC_encrypt_buffer(&aes_ctx, buf, length);
-}
-
-
-const uint8_t attestation_cert_der[] =
-"\x30\x82\x01\xfb\x30\x82\x01\xa1\xa0\x03\x02\x01\x02\x02\x01\x00\x30\x0a\x06\x08"
-"\x2a\x86\x48\xce\x3d\x04\x03\x02\x30\x2c\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13"
-"\x02\x55\x53\x31\x0b\x30\x09\x06\x03\x55\x04\x08\x0c\x02\x4d\x44\x31\x10\x30\x0e"
-"\x06\x03\x55\x04\x0a\x0c\x07\x54\x45\x53\x54\x20\x43\x41\x30\x20\x17\x0d\x31\x38"
-"\x30\x35\x31\x30\x30\x33\x30\x36\x32\x30\x5a\x18\x0f\x32\x30\x36\x38\x30\x34\x32"
-"\x37\x30\x33\x30\x36\x32\x30\x5a\x30\x7c\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13"
-"\x02\x55\x53\x31\x0b\x30\x09\x06\x03\x55\x04\x08\x0c\x02\x4d\x44\x31\x0f\x30\x0d"
-"\x06\x03\x55\x04\x07\x0c\x06\x4c\x61\x75\x72\x65\x6c\x31\x15\x30\x13\x06\x03\x55"
-"\x04\x0a\x0c\x0c\x54\x45\x53\x54\x20\x43\x4f\x4d\x50\x41\x4e\x59\x31\x22\x30\x20"
-"\x06\x03\x55\x04\x0b\x0c\x19\x41\x75\x74\x68\x65\x6e\x74\x69\x63\x61\x74\x6f\x72"
-"\x20\x41\x74\x74\x65\x73\x74\x61\x74\x69\x6f\x6e\x31\x14\x30\x12\x06\x03\x55\x04"
-"\x03\x0c\x0b\x63\x6f\x6e\x6f\x72\x70\x70\x2e\x63\x6f\x6d\x30\x59\x30\x13\x06\x07"
-"\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07\x03\x42\x00"
-"\x04\x45\xa9\x02\xc1\x2e\x9c\x0a\x33\xfa\x3e\x84\x50\x4a\xb8\x02\xdc\x4d\xb9\xaf"
-"\x15\xb1\xb6\x3a\xea\x8d\x3f\x03\x03\x55\x65\x7d\x70\x3f\xb4\x02\xa4\x97\xf4\x83"
-"\xb8\xa6\xf9\x3c\xd0\x18\xad\x92\x0c\xb7\x8a\x5a\x3e\x14\x48\x92\xef\x08\xf8\xca"
-"\xea\xfb\x32\xab\x20\xa3\x62\x30\x60\x30\x46\x06\x03\x55\x1d\x23\x04\x3f\x30\x3d"
-"\xa1\x30\xa4\x2e\x30\x2c\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x55\x53\x31"
-"\x0b\x30\x09\x06\x03\x55\x04\x08\x0c\x02\x4d\x44\x31\x10\x30\x0e\x06\x03\x55\x04"
-"\x0a\x0c\x07\x54\x45\x53\x54\x20\x43\x41\x82\x09\x00\xf7\xc9\xec\x89\xf2\x63\x94"
-"\xd9\x30\x09\x06\x03\x55\x1d\x13\x04\x02\x30\x00\x30\x0b\x06\x03\x55\x1d\x0f\x04"
-"\x04\x03\x02\x04\xf0\x30\x0a\x06\x08\x2a\x86\x48\xce\x3d\x04\x03\x02\x03\x48\x00"
-"\x30\x45\x02\x20\x18\x38\xb0\x45\x03\x69\xaa\xa7\xb7\x38\x62\x01\xaf\x24\x97\x5e"
-"\x7e\x74\x64\x1b\xa3\x7b\xf7\xe6\xd3\xaf\x79\x28\xdb\xdc\xa5\x88\x02\x21\x00\xcd"
-"\x06\xf1\xe3\xab\x16\x21\x8e\xd8\xc0\x14\xaf\x09\x4f\x5b\x73\xef\x5e\x9e\x4b\xe7"
-"\x35\xeb\xdd\x9b\x6d\x8f\x7d\xf3\xc4\x3a\xd7";
-
-
-const uint16_t attestation_cert_der_size = sizeof(attestation_cert_der)-1;
-
-
-const uint8_t attestation_key[] = "\xcd\x67\xaa\x31\x0d\x09\x1e\xd1\x6e\x7e\x98\x92\xaa\x07\x0e\x19\x94\xfc\xd7\x14\xae\x7c\x40\x8f\xb9\x46\xb7\x2e\x5f\xe7\x5d\x30";
-const uint16_t attestation_key_size = sizeof(attestation_key)-1;
-
-
diff --git a/device.c b/pc/device.c
similarity index 100%
rename from device.c
rename to pc/device.c
diff --git a/convert_log_to_c.py b/tools/convert_log_to_c.py
similarity index 100%
rename from convert_log_to_c.py
rename to tools/convert_log_to_c.py
diff --git a/ctap_test.py b/tools/ctap_test.py
similarity index 100%
rename from ctap_test.py
rename to tools/ctap_test.py
diff --git a/tools/gencert/attest b/tools/gencert/attest
new file mode 100644
index 0000000..1496084
--- /dev/null
+++ b/tools/gencert/attest
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIIB+zCCAaGgAwIBAgIBADAKBggqhkjOPQQDAjAsMQswCQYDVQQGEwJVUzELMAkG
+A1UECAwCTUQxEDAOBgNVBAoMB1RFU1QgQ0EwIBcNMTgwNTEwMDMwNjIwWhgPMjA2
+ODA0MjcwMzA2MjBaMHwxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNRDEPMA0GA1UE
+BwwGTGF1cmVsMRUwEwYDVQQKDAxURVNUIENPTVBBTlkxIjAgBgNVBAsMGUF1dGhl
+bnRpY2F0b3IgQXR0ZXN0YXRpb24xFDASBgNVBAMMC2Nvbm9ycHAuY29tMFkwEwYH
+KoZIzj0CAQYIKoZIzj0DAQcDQgAERakCwS6cCjP6PoRQSrgC3E25rxWxtjrqjT8D
+A1VlfXA/tAKkl/SDuKb5PNAYrZIMt4paPhRIku8I+Mrq+zKrIKNiMGAwRgYDVR0j
+BD8wPaEwpC4wLDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk1EMRAwDgYDVQQKDAdU
+RVNUIENBggkA98nsifJjlNkwCQYDVR0TBAIwADALBgNVHQ8EBAMCBPAwCgYIKoZI
+zj0EAwIDSAAwRQIgGDiwRQNpqqe3OGIBrySXXn50ZBuje/fm0695KNvcpYgCIQDN
+BvHjqxYhjtjAFK8JT1tz716eS+c1692bbY9988Q61w==
+-----END CERTIFICATE-----
diff --git a/tools/ca_sign.sh b/tools/gencert/ca_sign.sh
similarity index 100%
rename from tools/ca_sign.sh
rename to tools/gencert/ca_sign.sh
diff --git a/tools/cbytes.py b/tools/gencert/cbytes.py
similarity index 100%
rename from tools/cbytes.py
rename to tools/gencert/cbytes.py
diff --git a/tools/dump_pem.py b/tools/gencert/dump_pem.py
similarity index 100%
rename from tools/dump_pem.py
rename to tools/gencert/dump_pem.py
diff --git a/tools/genca.sh b/tools/gencert/genca.sh
similarity index 100%
rename from tools/genca.sh
rename to tools/gencert/genca.sh
diff --git a/tools/v3.ext b/tools/gencert/v3.ext
similarity index 100%
rename from tools/v3.ext
rename to tools/gencert/v3.ext