From: rtel Date: Wed, 2 Mar 2016 16:03:25 +0000 (+0000) Subject: Add Pearl Gecko demo. X-Git-Tag: V9.0.0rc2~11 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=b0badde682213684f242a1b19cd7759a8d20a53f;p=freertos Add Pearl Gecko demo. Fix build error when configSUPPORT_STATIC_ALLOCATION and configNUM_THREAD_LOCAL_STORAGE_POINTERS were greater than zero at the same time. Allow the pdMS_TO_TICKS macro to be overridden by a definition in FreeRTOSConfig.h. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2422 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- diff --git a/FreeRTOS/Demo/CORTEX_EFM32_Gecko_Starter_Kit_Simplicity_Studio/Source/Low_Power_Demo/low_power_tick_management_BURTC.c b/FreeRTOS/Demo/CORTEX_EFM32_Gecko_Starter_Kit_Simplicity_Studio/Source/Low_Power_Demo/low_power_tick_management_BURTC.c index c097bebc8..218dd7a4c 100644 --- a/FreeRTOS/Demo/CORTEX_EFM32_Gecko_Starter_Kit_Simplicity_Studio/Source/Low_Power_Demo/low_power_tick_management_BURTC.c +++ b/FreeRTOS/Demo/CORTEX_EFM32_Gecko_Starter_Kit_Simplicity_Studio/Source/Low_Power_Demo/low_power_tick_management_BURTC.c @@ -81,7 +81,6 @@ #include "em_burtc.h" #include "em_rmu.h" #include "em_int.h" -#include "em_rtc.h" #include "sleep.h" /* SEE THE COMMENTS ABOVE THE DEFINITION OF configCREATE_LOW_POWER_DEMO IN @@ -323,18 +322,18 @@ void BURTC_IRQHandler( void ) { ulTickFlag = pdTRUE; - if( RTC_CompareGet( 0 ) != ulReloadValueForOneTick ) + if( BURTC_CompareGet( 0 ) != ulReloadValueForOneTick ) { - /* Set RTC interrupt to one RTOS tick period. */ + /* Set BURTC interrupt to one RTOS tick period. */ BURTC_Enable( false ); BURTC_CompareSet( 0, ulReloadValueForOneTick ); BURTC_Enable( true ); } - BURTC_IntClear( _RTC_IFC_MASK ); + BURTC_IntClear( _BURTC_IFC_MASK ); - /* Critical section which protect incrementing the tick*/ - ( void ) portSET_INTERRUPT_MASK_FROM_ISR(); + /* Critical section which protect incrementing the tick. */ + portDISABLE_INTERRUPTS(); { if( xTaskIncrementTick() != pdFALSE ) { @@ -342,7 +341,7 @@ void BURTC_IRQHandler( void ) portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; } } - portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 ); + portENABLE_INTERRUPTS(); } #endif /* ( configCREATE_LOW_POWER_DEMO == 1 ) */ diff --git a/FreeRTOS/Demo/CORTEX_EFM32_Gecko_Starter_Kit_Simplicity_Studio/Source/Low_Power_Demo/low_power_tick_management_RTC.c b/FreeRTOS/Demo/CORTEX_EFM32_Gecko_Starter_Kit_Simplicity_Studio/Source/Low_Power_Demo/low_power_tick_management_RTC.c index 4644e061d..47fb7a9d1 100644 --- a/FreeRTOS/Demo/CORTEX_EFM32_Gecko_Starter_Kit_Simplicity_Studio/Source/Low_Power_Demo/low_power_tick_management_RTC.c +++ b/FreeRTOS/Demo/CORTEX_EFM32_Gecko_Starter_Kit_Simplicity_Studio/Source/Low_Power_Demo/low_power_tick_management_RTC.c @@ -356,8 +356,8 @@ void RTC_IRQHandler( void ) RTC_IntClear( _RTC_IFC_MASK ); - /* Critical section which protect incrementing the tick*/ - ( void ) portSET_INTERRUPT_MASK_FROM_ISR(); + /* Critical section which protect incrementing the tick. */ + portDISABLE_INTERRUPTS(); { if( xTaskIncrementTick() != pdFALSE ) { @@ -365,7 +365,7 @@ void RTC_IRQHandler( void ) portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; } } - portCLEAR_INTERRUPT_MASK_FROM_ISR( 0 ); + portENABLE_INTERRUPTS(); } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/.cproject b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/.cproject new file mode 100644 index 000000000..072724a5d --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/.cproject @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/.project b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/.project new file mode 100644 index 000000000..c257d44c8 --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/.project @@ -0,0 +1,241 @@ + + + RTOSDemo + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + com.silabs.ide.project.core.SLSProjectNature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + + FreeRTOS_Source + 2 + FREERTOS_ROOT/FreeRTOS/Source + + + Full_Demo/Standard_Demo_Tasks + 2 + FREERTOS_ROOT/FreeRTOS/Demo/Common/Minimal + + + Full_Demo/Standard_Demo_Tasks/include + 2 + FREERTOS_ROOT/FreeRTOS/Demo/Common/include + + + + + 1455990187566 + FreeRTOS_Source + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-event_groups.c + + + + 1455990187573 + FreeRTOS_Source + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-queue.c + + + + 1455990187577 + FreeRTOS_Source + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-tasks.c + + + + 1455990187582 + FreeRTOS_Source + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-timers.c + + + + 1455990187588 + FreeRTOS_Source + 9 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-include + + + + 1455990187592 + FreeRTOS_Source + 9 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-portable + + + + 1455990187597 + FreeRTOS_Source + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-list.c + + + + 0 + FreeRTOS_Source/portable + 9 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-MemMang + + + + 0 + FreeRTOS_Source/portable + 9 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-GCC + + + + 0 + Full_Demo/Standard_Demo_Tasks + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-flop.c + + + + 0 + Full_Demo/Standard_Demo_Tasks + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-dynamic.c + + + + 0 + Full_Demo/Standard_Demo_Tasks + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-blocktim.c + + + + 0 + Full_Demo/Standard_Demo_Tasks + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-GenQTest.c + + + + 0 + Full_Demo/Standard_Demo_Tasks + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-TimerDemo.c + + + + 0 + Full_Demo/Standard_Demo_Tasks + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-EventGroupsDemo.c + + + + 0 + Full_Demo/Standard_Demo_Tasks + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-TaskNotify.c + + + + 0 + Full_Demo/Standard_Demo_Tasks + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-recmutex.c + + + + 0 + Full_Demo/Standard_Demo_Tasks + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-semtest.c + + + + 0 + Full_Demo/Standard_Demo_Tasks + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-StaticAllocation.c + + + + 1455989277852 + FreeRTOS_Source/portable/GCC + 9 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-ARM_CM3 + + + + 1455989313240 + FreeRTOS_Source/portable/MemMang + 5 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-heap_4.c + + + + + + FREERTOS_ROOT + $%7BPARENT-3-PROJECT_LOC%7D + + + diff --git a/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/FreeRTOSConfig.h b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/FreeRTOSConfig.h new file mode 100644 index 000000000..def429af8 --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/FreeRTOSConfig.h @@ -0,0 +1,237 @@ +/* + FreeRTOS V9.0.0rc1 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "em_chip.h" +#include "em_cmu.h" + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ + + +/* Set configCREATE_LOW_POWER_DEMO as follows: + * + * 0: Build the full test and demo application. + * 1: Build the simple blinky tickless low power demo, generating the tick + * interrupt from the RTCC. EM2 will be entered. The LXFO clock is used. + * See the comments at the top of main.c, main_full.c and main_low_power.c for + * more information. + */ +#define configCREATE_LOW_POWER_DEMO 1 + +/* Some configuration is dependent on the demo being built. */ +#if( configCREATE_LOW_POWER_DEMO == 0 ) + + /* Tickless mode is not used. */ + + /* Some of the standard demo test tasks assume a tick rate of 1KHz, even + though that is faster than would normally be warranted by a real + application. */ + #define configTICK_RATE_HZ ( 1000 ) + + /* The full demo always has tasks to run so the tick will never be turned + off. The blinky demo will use the default tickless idle implementation to + turn the tick off. */ + #define configUSE_TICKLESS_IDLE 0 + + /* Hook function related definitions. */ + #define configUSE_TICK_HOOK ( 1 ) + #define configCHECK_FOR_STACK_OVERFLOW ( 1 ) + #define configUSE_MALLOC_FAILED_HOOK ( 1 ) + #define configUSE_IDLE_HOOK ( 1 ) + + #define configENERGY_MODE ( sleepEM3 ) + +#else + + /* Tickless idle mode, generating RTOS tick interrupts from the RTC, fed + by the LXFO clock. */ + + /* The slow clock used to generate the tick interrupt in the low power demo + runs at 32768/8=4096Hz. Ensure the tick rate is a multiple of the clock. */ + #define configTICK_RATE_HZ ( 128 ) + + /* The low power demo uses the tickless idle feature. */ + #define configUSE_TICKLESS_IDLE 1 + + /* Hook function related definitions. */ + #define configUSE_TICK_HOOK ( 0 ) + #define configCHECK_FOR_STACK_OVERFLOW ( 0 ) + #define configUSE_MALLOC_FAILED_HOOK ( 0 ) + #define configUSE_IDLE_HOOK ( 0 ) + +#endif + +/* Main functions*/ +#define configUSE_PREEMPTION ( 1 ) +#define configUSE_PORT_OPTIMISED_TASK_SELECTION ( 1 ) +#define configSUPPORT_STATIC_ALLOCATION ( 1 ) +#define configCPU_CLOCK_HZ ( CMU_ClockFreqGet( cmuClock_CORE ) ) +#define configMAX_PRIORITIES ( 6 ) +#define configMINIMAL_STACK_SIZE (( unsigned short ) 130) +#define configTOTAL_HEAP_SIZE (( size_t )(25000)) +#define configMAX_TASK_NAME_LEN ( 10 ) +#define configUSE_TRACE_FACILITY ( 0 ) +#define configUSE_16_BIT_TICKS ( 0 ) +#define configIDLE_SHOULD_YIELD ( 0 ) +#define configUSE_MUTEXES ( 1 ) +#define configUSE_RECURSIVE_MUTEXES ( 1 ) +#define configUSE_COUNTING_SEMAPHORES ( 1 ) +#define configUSE_ALTERNATIVE_API ( 0 )/* Deprecated! */ +#define configQUEUE_REGISTRY_SIZE ( 10 ) +#define configUSE_QUEUE_SETS ( 0 ) + +/* Run time stats gathering related definitions. */ +#define configGENERATE_RUN_TIME_STATS ( 0 ) + +/* Co-routine related definitions. */ +#define configUSE_CO_ROUTINES ( 0 ) +#define configMAX_CO_ROUTINE_PRIORITIES ( 1 ) + +/* Software timer related definitions. */ +#define configUSE_TIMERS ( 1 ) +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) /* Highest priority */ +#define configTIMER_QUEUE_LENGTH ( 10 ) +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE ) + +/* Cortex-M specific definitions. */ +#ifdef __NVIC_PRIO_BITS + /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */ + #define configPRIO_BITS __NVIC_PRIO_BITS +#else + #define configPRIO_BITS 3 /* 7 priority levels */ +#endif + +/* The lowest interrupt priority that can be used in a call to a "set priority" +function. */ +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x07 + +/* The highest interrupt priority that can be used by any interrupt service +routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL +INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER +PRIORITY THAN THIS! (higher priorities are lower numeric values. */ +#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 0x05 + +/* Interrupt priorities used by the kernel port layer itself. These are generic +to all Cortex-M ports, and do not rely on any particular library functions. */ +#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) +/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! +See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ +#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) + + +/* Optional functions - most linkers will remove unused functions anyway. */ +#define INCLUDE_vTaskPrioritySet ( 1 ) +#define INCLUDE_uxTaskPriorityGet ( 1 ) +#define INCLUDE_vTaskDelete ( 1 ) +#define INCLUDE_vTaskSuspend ( 1 ) +#define INCLUDE_xResumeFromISR ( 1 ) +#define INCLUDE_vTaskDelayUntil ( 1 ) +#define INCLUDE_vTaskDelay ( 1 ) +#define INCLUDE_xTaskGetSchedulerState ( 1 ) +#define INCLUDE_xTaskGetCurrentTaskHandle ( 1 ) +#define INCLUDE_uxTaskGetStackHighWaterMark ( 0 ) +#define INCLUDE_xTaskGetIdleTaskHandle ( 0 ) +#define INCLUDE_xTimerGetTimerDaemonTaskHandle ( 0 ) +#define INCLUDE_pcTaskGetTaskName ( 0 ) +#define INCLUDE_eTaskGetState ( 1 ) +#define INCLUDE_xTimerPendFunctionCall ( 1 ) + +/* Stop if an assertion fails. */ +#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); } + +/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS +standard names. */ +#define vPortSVCHandler SVC_Handler +#define xPortPendSVHandler PendSV_Handler +#define xPortSysTickHandler SysTick_Handler + +/* For the linker. */ +#define fabs __builtin_fabs + +#ifdef __cplusplus +} +#endif +#endif /* FREERTOS_CONFIG_H */ + diff --git a/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/Full_Demo/RegTest.c b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/Full_Demo/RegTest.c new file mode 100644 index 000000000..08e231926 --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/Full_Demo/RegTest.c @@ -0,0 +1,228 @@ +/* + FreeRTOS V9.0.0rc1 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * "Reg test" tasks - These fill the registers with known values, then check + * that each register maintains its expected value for the lifetime of the + * task. Each task uses a different set of values. The reg test tasks execute + * with a very low priority, so get preempted very frequently. A register + * containing an unexpected value is indicative of an error in the context + * switching mechanism. + */ + +void vRegTest1Implementation( void ) __attribute__ ((naked)); +void vRegTest2Implementation( void ) __attribute__ ((naked)); + +void vRegTest1Implementation( void ) +{ + __asm volatile + ( + ".extern ulRegTest1LoopCounter \n" + "/* Fill the core registers with known values. */ \n" + "mov r0, #100 \n" + "mov r1, #101 \n" + "mov r2, #102 \n" + "mov r3, #103 \n" + "mov r4, #104 \n" + "mov r5, #105 \n" + "mov r6, #106 \n" + "mov r7, #107 \n" + "mov r8, #108 \n" + "mov r9, #109 \n" + "mov r10, #110 \n" + "mov r11, #111 \n" + "mov r12, #112 \n" + + "reg1_loop: \n" + + "/* Check each register has maintained its expected value. */ \n" + "cmp r0, #100 \n" + "bne reg1_error_loop \n" + "cmp r1, #101 \n" + "bne reg1_error_loop \n" + "cmp r2, #102 \n" + "bne reg1_error_loop \n" + "cmp r3, #103 \n" + "bne reg1_error_loop \n" + "cmp r4, #104 \n" + "bne reg1_error_loop \n" + "cmp r5, #105 \n" + "bne reg1_error_loop \n" + "cmp r6, #106 \n" + "bne reg1_error_loop \n" + "cmp r7, #107 \n" + "bne reg1_error_loop \n" + "cmp r8, #108 \n" + "bne reg1_error_loop \n" + "cmp r9, #109 \n" + "bne reg1_error_loop \n" + "cmp r10, #110 \n" + "bne reg1_error_loop \n" + "cmp r11, #111 \n" + "bne reg1_error_loop \n" + "cmp r12, #112 \n" + "bne reg1_error_loop \n" + + "/* Everything passed, increment the loop counter. */ \n" + "push { r0-r1 } \n" + "ldr r0, =ulRegTest1LoopCounter \n" + "ldr r1, [r0] \n" + "adds r1, r1, #1 \n" + "str r1, [r0] \n" + "pop { r0-r1 } \n" + + "/* Start again. */ \n" + "b reg1_loop \n" + + "reg1_error_loop: \n" + "/* If this line is hit then there was an error in a core register value. \n" + "The loop ensures the loop counter stops incrementing. */ \n" + "b reg1_error_loop \n" + "nop " + ); /* __asm volatile. */ +} +/*-----------------------------------------------------------*/ + +void vRegTest2Implementation( void ) +{ + __asm volatile + ( + ".extern ulRegTest2LoopCounter \n" + "/* Set all the core registers to known values. */ \n" + "mov r0, #-1 \n" + "mov r1, #1 \n" + "mov r2, #2 \n" + "mov r3, #3 \n" + "mov r4, #4 \n" + "mov r5, #5 \n" + "mov r6, #6 \n" + "mov r7, #7 \n" + "mov r8, #8 \n" + "mov r9, #9 \n" + "mov r10, #10 \n" + "mov r11, #11 \n" + "mov r12, #12 \n" + + "reg2_loop: \n" + + "cmp r0, #-1 \n" + "bne reg2_error_loop \n" + "cmp r1, #1 \n" + "bne reg2_error_loop \n" + "cmp r2, #2 \n" + "bne reg2_error_loop \n" + "cmp r3, #3 \n" + "bne reg2_error_loop \n" + "cmp r4, #4 \n" + "bne reg2_error_loop \n" + "cmp r5, #5 \n" + "bne reg2_error_loop \n" + "cmp r6, #6 \n" + "bne reg2_error_loop \n" + "cmp r7, #7 \n" + "bne reg2_error_loop \n" + "cmp r8, #8 \n" + "bne reg2_error_loop \n" + "cmp r9, #9 \n" + "bne reg2_error_loop \n" + "cmp r10, #10 \n" + "bne reg2_error_loop \n" + "cmp r11, #11 \n" + "bne reg2_error_loop \n" + "cmp r12, #12 \n" + "bne reg2_error_loop \n" + + "/* Increment the loop counter to indicate this test is still functioning \n" + "correctly. */ \n" + "push { r0-r1 } \n" + "ldr r0, =ulRegTest2LoopCounter \n" + "ldr r1, [r0] \n" + "adds r1, r1, #1 \n" + "str r1, [r0] \n" + + "/* Yield to increase test coverage. */ \n" + "movs r0, #0x01 \n" + "ldr r1, =0xe000ed04 /*NVIC_INT_CTRL */ \n" + "lsl r0, r0, #28 /* Shift to PendSV bit */ \n" + "str r0, [r1] \n" + "dsb \n" + + "pop { r0-r1 } \n" + + "/* Start again. */ \n" + "b reg2_loop \n" + + "reg2_error_loop: \n" + "/* If this line is hit then there was an error in a core register value. \n" + "This loop ensures the loop counter variable stops incrementing. */ \n" + "b reg2_error_loop \n" + ); /* __asm volatile */ +} +/*-----------------------------------------------------------*/ + diff --git a/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/Full_Demo/main_full.c b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/Full_Demo/main_full.c new file mode 100644 index 000000000..67ccd0a16 --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/Full_Demo/main_full.c @@ -0,0 +1,414 @@ +/* + FreeRTOS V9.0.0rc1 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/****************************************************************************** + * NOTE 1: This project provides two demo applications. A simple blinky style + * project that demonstrates the tickless low power features of FreeRTOS, and a + * more comprehensive test and demo application. The configCREATE_LOW_POWER_DEMO + * setting in FreeRTOSConifg.h is used to select between the two, and to select + * the clock used when tickless mode is used. See the notes on using + * conifgCREATE_LOW_POWER_DEMO in main.c. This file implements the + * comprehensive test and demo version. + * + * NOTE 2: This file only contains the source code that is specific to the + * full demo. Generic functions, such FreeRTOS hook functions, and functions + * required to configure the hardware, are defined in main.c. + * + ****************************************************************************** + * + * main_full() creates all the demo application tasks and software timers, then + * starts the scheduler. The web documentation provides more details of the + * standard demo application tasks, which provide no particular functionality, + * but do provide a good example of how to use the FreeRTOS API. + * + * In addition to the standard demo tasks, the following tasks and tests are + * defined and/or created within this file: + * + * "Reg test" tasks - These fill both the core and floating point registers with + * known values, then check that each register maintains its expected value for + * the lifetime of the task. Each task uses a different set of values. The reg + * test tasks execute with a very low priority, so get preempted very + * frequently. A register containing an unexpected value is indicative of an + * error in the context switching mechanism. + * + * "Check" task - The check task period is initially set to three seconds. The + * task checks that all the standard demo tasks, and the register check tasks, + * are not only still executing, but are executing without reporting any errors. + * If the check task discovers that a task has either stalled, or reported an + * error, then it changes its own execution period from the initial three + * seconds, to just 200ms. The check task also toggles an LED each time it is + * called. This provides a visual indication of the system status: If the LED + * toggles every three seconds, then no issues have been discovered. If the LED + * toggles every 200ms, then an issue has been discovered with at least one + * task. + */ + +/* Standard includes. */ +#include + +/* Kernel includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "timers.h" +#include "semphr.h" + +/* SiLabs includes. */ +#include "bsp.h" + +/* Standard demo application includes. */ +#include "flop.h" +#include "semtest.h" +#include "dynamic.h" +#include "blocktim.h" +#include "GenQTest.h" +#include "recmutex.h" +#include "TimerDemo.h" +#include "EventGroupsDemo.h" +#include "TaskNotify.h" +#include "StaticAllocation.h" + +/* Priorities for the demo application tasks. */ +#define mainSEM_TEST_PRIORITY ( tskIDLE_PRIORITY + 1UL ) +#define mainCREATOR_TASK_PRIORITY ( tskIDLE_PRIORITY + 3UL ) +#define mainFLOP_TASK_PRIORITY ( tskIDLE_PRIORITY ) +#define mainCHECK_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) + +/* A block time of zero simply means "don't block". */ +#define mainDONT_BLOCK ( 0UL ) + +/* The period after which the check timer will expire, in ms, provided no errors +have been reported by any of the standard demo tasks. ms are converted to the +equivalent in ticks using the portTICK_PERIOD_MS constant. */ +#define mainNO_ERROR_CHECK_TASK_PERIOD ( 3000UL / portTICK_PERIOD_MS ) + +/* The period at which the check timer will expire, in ms, if an error has been +reported in one of the standard demo tasks. ms are converted to the equivalent +in ticks using the portTICK_PERIOD_MS constant. */ +#define mainERROR_CHECK_TASK_PERIOD pdMS_TO_TICKS( 200UL ) + +/* Parameters that are passed into the register check tasks solely for the +purpose of ensuring parameters are passed into tasks correctly. */ +#define mainREG_TEST_TASK_1_PARAMETER ( ( void * ) 0x12345678 ) +#define mainREG_TEST_TASK_2_PARAMETER ( ( void * ) 0x87654321 ) + +/* The base period used by the timer test tasks. */ +#define mainTIMER_TEST_PERIOD ( 50 ) + +/* The LED toggled by the check task. */ +#define mainTASK_LED ( 0 ) + +/*-----------------------------------------------------------*/ + +/* + * Called by main() to run the full demo (as opposed to the blinky demo) when + * mainCREATE_LOW_POWER_DEMO is set to 0. + */ +void main_full( void ); + +/* + * The check task, as described at the top of this file. + */ +static void prvCheckTask( void *pvParameters ); + +/* + * Some of the tests and demo tasks executed by the full demo include + * interaction from an interrupt - for which the tick interrupt is used via the + * tick hook function. + */ +void vFullDemoTickHook( void ); + +/* + * Register check tasks, and the tasks used to write over and check the contents + * of the FPU registers, as described at the top of this file. The nature of + * these files necessitates that they are written in an assembly file, but the + * entry points are kept in the C file for the convenience of checking the task + * parameter. + */ +static void prvRegTestTaskEntry1( void *pvParameters ); +extern void vRegTest1Implementation( void ); +static void prvRegTestTaskEntry2( void *pvParameters ); +extern void vRegTest2Implementation( void ); + +/*-----------------------------------------------------------*/ + +/* The following two variables are used to communicate the status of the +register check tasks to the check task. If the variables keep incrementing, +then the register check tasks have not discovered any errors. If a variable +stops incrementing, then an error has been found. */ +volatile unsigned long ulRegTest1LoopCounter = 0UL, ulRegTest2LoopCounter = 0UL; + +/* The variable incremented in lieu of having a proper LED outout. */ +extern volatile uint32_t ulLED; + +/*-----------------------------------------------------------*/ + +void main_full( void ) +{ + /* Start all the other standard demo/test tasks. They have no particular + functionality, but do demonstrate how to use the FreeRTOS API and test the + kernel port. */ + vStartDynamicPriorityTasks(); + vCreateBlockTimeTasks(); + vStartGenericQueueTasks( tskIDLE_PRIORITY ); + vStartRecursiveMutexTasks(); + vStartSemaphoreTasks( mainSEM_TEST_PRIORITY ); + vStartMathTasks( mainFLOP_TASK_PRIORITY ); + vStartTimerDemoTask( mainTIMER_TEST_PERIOD ); + vStartEventGroupTasks(); + vStartTaskNotifyTask(); + vStartStaticallyAllocatedTasks(); + + /* Create the register check tasks, as described at the top of this file */ + xTaskCreate( prvRegTestTaskEntry1, "Reg1", configMINIMAL_STACK_SIZE, mainREG_TEST_TASK_1_PARAMETER, tskIDLE_PRIORITY, NULL ); + xTaskCreate( prvRegTestTaskEntry2, "Reg2", configMINIMAL_STACK_SIZE, mainREG_TEST_TASK_2_PARAMETER, tskIDLE_PRIORITY, NULL ); + + /* Create the task that performs the 'check' functionality, as described at + the top of this file. */ + xTaskCreate( prvCheckTask, "Check", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, NULL ); + + /* Start the scheduler. */ + vTaskStartScheduler(); + + /* If all is well, the scheduler will now be running, and the following + line will never be reached. If the following line does execute, then + there was insufficient FreeRTOS heap memory available for the Idle and/or + timer tasks to be created. See the memory management section on the + FreeRTOS web site for more details on the FreeRTOS heap + http://www.freertos.org/a00111.html. */ + for( ;; ); +} +/*-----------------------------------------------------------*/ + +static void prvCheckTask( void *pvParameters ) +{ +TickType_t xDelayPeriod = mainNO_ERROR_CHECK_TASK_PERIOD; +TickType_t xLastExecutionTime; +static unsigned long ulLastRegTest1Value = 0, ulLastRegTest2Value = 0; +unsigned long ulErrorFound = pdFALSE; + + /* Just to stop compiler warnings. */ + ( void ) pvParameters; + + /* Initialise xLastExecutionTime so the first call to vTaskDelayUntil() + works correctly. */ + xLastExecutionTime = xTaskGetTickCount(); + + /* Cycle for ever, delaying then checking all the other tasks are still + operating without error. The onboard LED is toggled on each iteration. + If an error is detected then the delay period is decreased from + mainNO_ERROR_CHECK_TASK_PERIOD to mainERROR_CHECK_TASK_PERIOD. This has the + effect of increasing the rate at which the onboard LED toggles, and in so + doing gives visual feedback of the system status. */ + for( ;; ) + { + /* Delay until it is time to execute again. */ + vTaskDelayUntil( &xLastExecutionTime, xDelayPeriod ); + + /* Check all the demo tasks (other than the flash tasks) to ensure + that they are all still running, and that none have detected an error. */ + if( xAreMathsTaskStillRunning() != pdTRUE ) + { + ulErrorFound = 1UL << 1UL; + } + + if( xAreDynamicPriorityTasksStillRunning() != pdTRUE ) + { + ulErrorFound = 1UL << 2UL; + } + + if( xAreStaticAllocationTasksStillRunning() != pdPASS ) + { + ulErrorFound = 1UL << 3UL; + } + + if ( xAreBlockTimeTestTasksStillRunning() != pdTRUE ) + { + ulErrorFound = 1UL << 4UL; + } + + if ( xAreGenericQueueTasksStillRunning() != pdTRUE ) + { + ulErrorFound = 1UL << 5UL; + } + + if ( xAreRecursiveMutexTasksStillRunning() != pdTRUE ) + { + ulErrorFound = 1UL << 6UL; + } + + if( xAreSemaphoreTasksStillRunning() != pdTRUE ) + { + ulErrorFound = 1UL << 8UL; + } + + if( xAreTimerDemoTasksStillRunning( ( TickType_t ) xDelayPeriod ) != pdPASS ) + { + ulErrorFound = 1UL << 9UL; + } + + if( xAreEventGroupTasksStillRunning() != pdPASS ) + { + ulErrorFound = 1UL << 12UL; + } + + if( xAreTaskNotificationTasksStillRunning() != pdPASS ) + { + ulErrorFound = 1UL << 14UL; + } + + /* Check that the register test 1 task is still running. */ + if( ulLastRegTest1Value == ulRegTest1LoopCounter ) + { + ulErrorFound = 1UL << 15UL; + } + ulLastRegTest1Value = ulRegTest1LoopCounter; + + /* Check that the register test 2 task is still running. */ + if( ulLastRegTest2Value == ulRegTest2LoopCounter ) + { + ulErrorFound = 1UL << 16UL; + } + ulLastRegTest2Value = ulRegTest2LoopCounter; + + /* Toggle the check LED to give an indication of the system status. If + the LED toggles every mainNO_ERROR_CHECK_TASK_PERIOD milliseconds then + everything is ok. A faster toggle indicates an error. */ + BSP_LedToggle( mainTASK_LED ); + + if( ulErrorFound != pdFALSE ) + { + /* An error has been detected in one of the tasks - flash the LED + at a higher frequency to give visible feedback that something has + gone wrong. */ + xDelayPeriod = mainERROR_CHECK_TASK_PERIOD; + } + + configASSERT( ulErrorFound == pdFALSE ); + } +} +/*-----------------------------------------------------------*/ + +static void prvRegTestTaskEntry1( void *pvParameters ) +{ + /* Although the regtest task is written in assembler, its entry point is + written in C for convenience of checking the task parameter is being passed + in correctly. */ + if( pvParameters == mainREG_TEST_TASK_1_PARAMETER ) + { + /* Start the part of the test that is written in assembler. */ + vRegTest1Implementation(); + } + + /* The following line will only execute if the task parameter is found to + be incorrect. The check timer will detect that the regtest loop counter is + not being incremented and flag an error. */ + vTaskDelete( NULL ); +} +/*-----------------------------------------------------------*/ + +static void prvRegTestTaskEntry2( void *pvParameters ) +{ + /* Although the regtest task is written in assembler, its entry point is + written in C for convenience of checking the task parameter is being passed + in correctly. */ + if( pvParameters == mainREG_TEST_TASK_2_PARAMETER ) + { + /* Start the part of the test that is written in assembler. */ + vRegTest2Implementation(); + } + + /* The following line will only execute if the task parameter is found to + be incorrect. The check timer will detect that the regtest loop counter is + not being incremented and flag an error. */ + vTaskDelete( NULL ); +} +/*-----------------------------------------------------------*/ + +void vFullDemoTickHook( void ) +{ + /* Some of the tests and demo tasks executed by the full demo include + interaction from an interrupt - for which the tick interrupt is used via + the tick hook function. */ + + /* The full demo includes a software timer demo/test that requires + prodding periodically from the tick interrupt. */ + vTimerPeriodicISRTests(); + + /* Call the periodic event group from ISR demo. */ + vPeriodicEventGroupsProcessing(); + + /* Call the code that 'gives' a task notification from an ISR. */ + xNotifyTaskFromISR(); +} + + + + + + diff --git a/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/Low_Power_Demo/low_power_tick_management_RTCC.c b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/Low_Power_Demo/low_power_tick_management_RTCC.c new file mode 100644 index 000000000..6e75baed9 --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/Low_Power_Demo/low_power_tick_management_RTCC.c @@ -0,0 +1,382 @@ +/* + FreeRTOS V9.0.0rc1 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* Standard inlcludes. */ +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* SiLabs library includes. */ +#include "em_cmu.h" +#include "em_rtcc.h" +#include "em_rmu.h" +#include "em_int.h" +#include "sleep.h" + +/* SEE THE COMMENTS ABOVE THE DEFINITION OF configCREATE_LOW_POWER_DEMO IN +FreeRTOSConfig.h +This file contains functions that will override the default implementations +in the RTOS port layer. Therefore only build this file if the low power demo +is being built. */ +#if( configCREATE_LOW_POWER_DEMO == 1 ) + +/* The RTCC channel used to generate the tick interrupt. */ +#define lpRTCC_CHANNEL ( 1 ) + +/* 32768 clock divided by 1. Don't use a prescale if errata RTCC_E201 +applies. */ +#define mainTIMER_FREQUENCY_HZ ( 32768UL ) + +/* + * The low power demo does not use the SysTick, so override the + * vPortSetupTickInterrupt() function with an implementation that configures + * a low power clock source. NOTE: This function name must not be changed as + * it is called from the RTOS portable layer. + */ +void vPortSetupTimerInterrupt( void ); + +/* + * Override the default definition of vPortSuppressTicksAndSleep() that is + * weakly defined in the FreeRTOS Cortex-M port layer with a version that + * manages the RTC clock, as the tick is generated from the low power RTC + * and not the SysTick as would normally be the case on a Cortex-M. + */ +void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ); + +/*-----------------------------------------------------------*/ + +/* Calculate how many clock increments make up a single tick period. */ +static const uint32_t ulReloadValueForOneTick = ( mainTIMER_FREQUENCY_HZ / configTICK_RATE_HZ ); + +/* Will hold the maximum number of ticks that can be suppressed. */ +static uint32_t xMaximumPossibleSuppressedTicks = 0; + +/* Flag set from the tick interrupt to allow the sleep processing to know if +sleep mode was exited because of a timer interrupt or a different interrupt. */ +static volatile uint32_t ulTickFlag = pdFALSE; + +/* As the clock is only 32KHz, it is likely a value of 1 will be enough. */ +static const uint32_t ulStoppedTimerCompensation = 0UL; + +/* RTCC configuration structures. */ +static const RTCC_Init_TypeDef xRTCInitStruct = +{ + false, /* Don't start counting when init complete. */ + false, /* Disable counter during debug halt. */ + false, /* Don't care. */ + true, /* Enable counter wrap on ch. 1 CCV value. */ + rtccCntPresc_1, /* NOTE: Do not use a pre-scale if errata RTCC_E201 applies. */ + rtccCntTickPresc, /* Count using the clock input directly. */ +#if defined(_RTCC_CTRL_BUMODETSEN_MASK) + false, /* Disable storing RTCC counter value in RTCC_CCV2 upon backup mode entry. */ +#endif + false, /* Oscillator fail detection disabled. */ + rtccCntModeNormal, /* Use RTCC in normal mode (increment by 1 on each tick) and not in calendar mode. */ + false /* Don't care. */ +}; + +static const RTCC_CCChConf_TypeDef xRTCCChannel1InitStruct = +{ + rtccCapComChModeCompare, /* Use Compare mode. */ + rtccCompMatchOutActionPulse,/* Don't care. */ + rtccPRSCh0, /* PRS not used. */ + rtccInEdgeNone, /* Capture Input not used. */ + rtccCompBaseCnt, /* Compare with Base CNT register. */ + 0, /* Compare mask. */ + rtccDayCompareModeMonth /* Don't care. */ +}; + +/*-----------------------------------------------------------*/ + +void vPortSetupTimerInterrupt( void ) +{ + /* Configure the RTCC to generate the RTOS tick interrupt. */ + + /* The maximum number of ticks that can be suppressed depends on the clock + frequency. */ + xMaximumPossibleSuppressedTicks = ULONG_MAX / ulReloadValueForOneTick; + + /* Ensure LE modules are accessible. */ + CMU_ClockEnable( cmuClock_CORELE, true ); + + /* Use LFXO. */ + CMU_ClockSelectSet( cmuClock_LFE, cmuSelect_LFXO ); + + /* Enable clock to the RTC module. */ + CMU_ClockEnable( cmuClock_RTCC, true ); + + /* Use channel 1 to generate the RTOS tick interrupt. */ + RTCC_ChannelCCVSet( lpRTCC_CHANNEL, ulReloadValueForOneTick ); + + RTCC_Init( &xRTCInitStruct ); + RTCC_ChannelInit( lpRTCC_CHANNEL, &xRTCCChannel1InitStruct ); + RTCC_EM4WakeupEnable( true ); + + /* Disable RTCC interrupt. */ + RTCC_IntDisable( _RTCC_IF_MASK ); + RTCC_IntClear( _RTCC_IF_MASK ); + RTCC->CNT = _RTCC_CNT_RESETVALUE; + + /* The tick interrupt must be set to the lowest priority possible. */ + NVIC_SetPriority( RTCC_IRQn, configLIBRARY_LOWEST_INTERRUPT_PRIORITY ); + NVIC_ClearPendingIRQ( RTCC_IRQn ); + NVIC_EnableIRQ( RTCC_IRQn ); + RTCC_IntEnable( RTCC_IEN_CC1 ); + RTCC_Enable( true ); +} +/*-----------------------------------------------------------*/ + +void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) +{ +uint32_t ulReloadValue, ulCompleteTickPeriods, ulCountBeforeSleep, ulCountAfterSleep; +eSleepModeStatus eSleepAction; +TickType_t xModifiableIdleTime; + + /* THIS FUNCTION IS CALLED WITH THE SCHEDULER SUSPENDED. */ + + /* Make sure the RTC reload value does not overflow the counter. */ + if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks ) + { + xExpectedIdleTime = xMaximumPossibleSuppressedTicks; + } + + /* Calculate the reload value required to wait xExpectedIdleTime tick + periods. */ + ulReloadValue = ulReloadValueForOneTick * xExpectedIdleTime; + if( ulReloadValue > ulStoppedTimerCompensation ) + { + /* Compensate for the fact that the RTC is going to be stopped + momentarily. */ + ulReloadValue -= ulStoppedTimerCompensation; + } + + /* Stop the RTC momentarily. The time the RTC is stopped for is accounted + for as best it can be, but using the tickless mode will inevitably result + in some tiny drift of the time maintained by the kernel with respect to + calendar time. The count is latched before stopping the timer as stopping + the timer appears to clear the count. */ + ulCountBeforeSleep = RTCC_CounterGet(); + RTCC_Enable( false ); + + /* If this function is re-entered before one complete tick period then the + reload value might be set to take into account a partial time slice, but + just reading the count assumes it is counting up to a full ticks worth - so + add in the difference if any. */ + ulCountBeforeSleep += ( ulReloadValueForOneTick - RTCC_ChannelCCVGet( lpRTCC_CHANNEL ) ); + + /* Enter a critical section but don't use the taskENTER_CRITICAL() method as + that will mask interrupts that should exit sleep mode. */ + INT_Disable(); + __asm volatile( "dsb" ); + __asm volatile( "isb" ); + + /* The tick flag is set to false before sleeping. If it is true when sleep + mode is exited then sleep mode was probably exited because the tick was + suppressed for the entire xExpectedIdleTime period. */ + ulTickFlag = pdFALSE; + + /* If a context switch is pending then abandon the low power entry as the + context switch might have been pended by an external interrupt that requires + processing. */ + eSleepAction = eTaskConfirmSleepModeStatus(); + if( eSleepAction == eAbortSleep ) + { + /* Restart tick and count up to whatever was left of the current time + slice. */ + RTCC_ChannelCCVSet( lpRTCC_CHANNEL, ( ulReloadValueForOneTick - ulCountBeforeSleep ) + ulStoppedTimerCompensation ); + RTCC_Enable( true ); + + /* Re-enable interrupts - see comments above the cpsid instruction() + above. */ + INT_Enable(); + } + else + { + /* Adjust the reload value to take into account that the current time + slice is already partially complete. */ + ulReloadValue -= ulCountBeforeSleep; + RTCC_ChannelCCVSet( lpRTCC_CHANNEL, ulReloadValue ); + + /* Restart the RTC. */ + RTCC_Enable( true ); + + /* Allow the application to define some pre-sleep processing. */ + xModifiableIdleTime = xExpectedIdleTime; + configPRE_SLEEP_PROCESSING( xModifiableIdleTime ); + + /* xExpectedIdleTime being set to 0 by configPRE_SLEEP_PROCESSING() + means the application defined code has already executed the WAIT + instruction. */ + if( xModifiableIdleTime > 0 ) + { + __asm volatile( "dsb" ); + SLEEP_Sleep(); + __asm volatile( "isb" ); + } + + /* Allow the application to define some post sleep processing. */ + configPOST_SLEEP_PROCESSING( xModifiableIdleTime ); + + /* Stop RTC. Again, the time the SysTick is stopped for is accounted + for as best it can be, but using the tickless mode will inevitably + result in some tiny drift of the time maintained by the kernel with + respect to calendar time. The count value is latched before stopping + the timer as stopping the timer appears to clear the count. */ + ulCountAfterSleep = RTCC_CounterGet(); + RTCC_Enable( false ); + + /* Re-enable interrupts - see comments above the cpsid instruction() + above. */ + INT_Enable(); + __asm volatile( "dsb" ); + __asm volatile( "isb" ); + + if( ulTickFlag != pdFALSE ) + { + /* The tick interrupt has already executed, although because this + function is called with the scheduler suspended the actual tick + processing will not occur until after this function has exited. + Reset the reload value with whatever remains of this tick period. */ + ulReloadValue = ulReloadValueForOneTick - ulCountAfterSleep; + RTCC_ChannelCCVSet( lpRTCC_CHANNEL, ulReloadValue ); + + /* The tick interrupt handler will already have pended the tick + processing in the kernel. As the pending tick will be processed as + soon as this function exits, the tick value maintained by the tick + is stepped forward by one less than the time spent sleeping. The + actual stepping of the tick appears later in this function. */ + ulCompleteTickPeriods = xExpectedIdleTime - 1UL; + } + else + { + /* Something other than the tick interrupt ended the sleep. How + many complete tick periods passed while the processor was + sleeping? Add back in the adjustment that was made to the reload + value to account for the fact that a time slice was part way through + when this function was called. */ + ulCountAfterSleep += ulCountBeforeSleep; + ulCompleteTickPeriods = ulCountAfterSleep / ulReloadValueForOneTick; + + /* The reload value is set to whatever fraction of a single tick + period remains. */ + ulCountAfterSleep -= ( ulCompleteTickPeriods * ulReloadValueForOneTick ); + ulReloadValue = ulReloadValueForOneTick - ulCountAfterSleep; + + if( ulReloadValue == 0 ) + { + /* There is no fraction remaining. */ + ulReloadValue = ulReloadValueForOneTick; + ulCompleteTickPeriods++; + } + + RTCC_ChannelCCVSet( lpRTCC_CHANNEL, ulReloadValue ); + } + + /* Restart the RTC so it runs up to the alarm value. The alarm value + will get set to the value required to generate exactly one tick period + the next time the RTC interrupt executes. */ + RTCC_Enable( true ); + + /* Wind the tick forward by the number of tick periods that the CPU + remained in a low power state. */ + vTaskStepTick( ulCompleteTickPeriods ); + } +} +/*-----------------------------------------------------------*/ + +void RTCC_IRQHandler( void ) +{ + ulTickFlag = pdTRUE; + + if( RTCC_ChannelCCVGet( lpRTCC_CHANNEL ) != ulReloadValueForOneTick ) + { + /* Set RTC interrupt to one RTOS tick period. */ + RTCC_Enable( false ); + RTCC_ChannelCCVSet( lpRTCC_CHANNEL, ulReloadValueForOneTick ); + RTCC_Enable( true ); + } + + RTCC_IntClear( _RTCC_IF_MASK ); + + /* Critical section which protect incrementing the tick*/ + portDISABLE_INTERRUPTS(); + { + if( xTaskIncrementTick() != pdFALSE ) + { + /* Pend a context switch. */ + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; + } + } + portENABLE_INTERRUPTS(); +} +/*-----------------------------------------------------------*/ + +#endif /* ( configCREATE_LOW_POWER_DEMO == 1 ) */ diff --git a/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/Low_Power_Demo/main_low_power.c b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/Low_Power_Demo/main_low_power.c new file mode 100644 index 000000000..3fffc65ae --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/Low_Power_Demo/main_low_power.c @@ -0,0 +1,236 @@ +/* + FreeRTOS V9.0.0rc1 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/****************************************************************************** + * NOTE 1: This project provides two demo applications. A simple blinky demo + * that demonstrates tickless low power operation, and a more comprehensive + * test and demo application. The configCREATE_LOW_POWER_DEMO setting in + * FreeRTOSConfig.h is used to select between the two, and to select the clock + * used when tickless low power operation is demonstrated. See the notes on + * using configCREATE_LOW_POWER_DEMO in main.c. This file implements the low + * power version. + * + * NOTE 2: This file only contains the source code that is specific to the + * low power demo. Generic functions, such FreeRTOS hook functions, and + * functions required to configure the hardware are defined in main.c. + ****************************************************************************** + * + * main_low_power() creates one queue, and two tasks. It then starts the + * scheduler. + * + * The Queue Send Task: + * The queue send task is implemented by the prvQueueSendTask() function in + * this file. It sends the value 100 to the queue every second. + * + * The Queue Receive Task: + * The queue receive task is implemented by the prvQueueReceiveTask() function + * in this file. prvQueueReceiveTask() blocks on the queue, blipping (quickly + * turn on then off again) the LED each time it received the value 100 from the + * queue send task. The queue send task writes to the queue every second, so + * the LED will blip once a second. + * + * The RTOS tick is turned off when the queue send task and queue receive task + * are both in the Blocked state. + * + */ + + +/* Kernel includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +/* SiLabs includes. */ +#include "bsp.h" + +/* Priorities at which the tasks are created. */ +#define mainQUEUE_RECEIVE_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 ) +#define mainQUEUE_SEND_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 ) + +/* The rate at which data is sent to the queue. The 200ms value is converted +to ticks using the portTICK_PERIOD_MS constant. */ +#define mainQUEUE_SEND_FREQUENCY_MS pdMS_TO_TICKS( 1000 ) + +/* The number of items the queue can hold. This is 1 as the receive task +will remove items as they are added, meaning the send task should always find +the queue empty. */ +#define mainQUEUE_LENGTH ( 1 ) + +/* The LED toggled by the Rx task. */ +#define mainTASK_LED ( 0 ) + +/*-----------------------------------------------------------*/ + +/* + * Called by main when mainCREATE_LOW_POWER_DEMO is set to 1 in + * main.c. + */ +void main_low_power( void ); + +/* + * The tasks as described in the comments at the top of this file. + */ +static void prvQueueReceiveTask( void *pvParameters ); +static void prvQueueSendTask( void *pvParameters ); + +/*-----------------------------------------------------------*/ + +/* The queue used by both tasks. */ +static QueueHandle_t xQueue = NULL; + +/*-----------------------------------------------------------*/ + +void main_low_power( void ) +{ + /* Create the queue. */ + xQueue = xQueueCreate( mainQUEUE_LENGTH, sizeof( uint32_t ) ); + + if( xQueue != NULL ) + { + /* Start the two tasks as described in the comments at the top of this + file. */ + xTaskCreate( prvQueueReceiveTask, /* The function that implements the task. */ + "Rx", /* The text name assigned to the task - for debug only as it is not used by the kernel. */ + configMINIMAL_STACK_SIZE, /* The size of the stack to allocate to the task. */ + NULL, /* The parameter passed to the task - not used in this case. */ + mainQUEUE_RECEIVE_TASK_PRIORITY, /* The priority assigned to the task. */ + NULL ); /* The task handle is not required, so NULL is passed. */ + + xTaskCreate( prvQueueSendTask, "TX", configMINIMAL_STACK_SIZE, NULL, mainQUEUE_SEND_TASK_PRIORITY, NULL ); + + /* Start the tasks and timer running. */ + vTaskStartScheduler(); + } + + /* If all is well, the scheduler will now be running, and the following + line will never be reached. If the following line does execute, then + there was insufficient FreeRTOS heap memory available for the Idle and/or + timer tasks to be created. See the memory management section on the + FreeRTOS web site for more details on the FreeRTOS heap + http://www.freertos.org/a00111.html. */ + for( ;; ); +} +/*-----------------------------------------------------------*/ + +static void prvQueueSendTask( void *pvParameters ) +{ +TickType_t xNextWakeTime; +const uint32_t ulValueToSend = 100UL; + + /* Remove compiler warning about unused parameter. */ + ( void ) pvParameters; + + /* Initialise xNextWakeTime - this only needs to be done once. */ + xNextWakeTime = xTaskGetTickCount(); + + for( ;; ) + { + /* Place this task in the blocked state until it is time to run again. */ + vTaskDelayUntil( &xNextWakeTime, mainQUEUE_SEND_FREQUENCY_MS ); + + /* Send to the queue - causing the queue receive task to unblock and + toggle the LED. 0 is used as the block time so the sending operation + will not block - it shouldn't need to block as the queue should always + be empty at this point in the code. */ + xQueueSend( xQueue, &ulValueToSend, 0U ); + } +} +/*-----------------------------------------------------------*/ + +static void prvQueueReceiveTask( void *pvParameters ) +{ +uint32_t ulReceivedValue; +const uint32_t ulExpectedValue = 100UL; +const TickType_t xShortDelay = pdMS_TO_TICKS( 10 ); + + /* Remove compiler warning about unused parameter. */ + ( void ) pvParameters; + + for( ;; ) + { + /* Wait until something arrives in the queue - this task will block + indefinitely provided INCLUDE_vTaskSuspend is set to 1 in + FreeRTOSConfig.h. */ + xQueueReceive( xQueue, &ulReceivedValue, portMAX_DELAY ); + + /* To get here something must have been received from the queue, but + is it the expected value? If it is, toggle the LED. */ + if( ulReceivedValue == ulExpectedValue ) + { + /* Turn the LED on for a brief time only so it doens't distort the + energy reading. */ + BSP_LedSet( mainTASK_LED ); + vTaskDelay( xShortDelay ); + BSP_LedClear( mainTASK_LED ); + ulReceivedValue = 0U; + } + } +} +/*-----------------------------------------------------------*/ + diff --git a/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/BSP/bsp_stk_leds.c b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/BSP/bsp_stk_leds.c new file mode 100644 index 000000000..d972e3bf0 --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/BSP/bsp_stk_leds.c @@ -0,0 +1,117 @@ +/***************************************************************************//** + * @file + * @brief Board support package API for GPIO leds on STK's. + * @version 4.2.1 + ******************************************************************************* + * @section License + * (C) Copyright 2014 Silicon Labs, 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. + * + ******************************************************************************/ + + + +#include "em_device.h" +#include "em_cmu.h" +#include "em_gpio.h" +#include "bsp.h" + +#if defined( BSP_GPIO_LEDS ) +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ + +typedef struct +{ + GPIO_Port_TypeDef port; + unsigned int pin; +} tLedArray; + +static const tLedArray ledArray[ BSP_NO_OF_LEDS ] = BSP_GPIO_LEDARRAY_INIT; + +int BSP_LedsInit(void) +{ + int i; + + CMU_ClockEnable(cmuClock_HFPER, true); + CMU_ClockEnable(cmuClock_GPIO, true); + for ( i=0; i= 0) && (ledNo < BSP_NO_OF_LEDS)) + { + GPIO_PinOutClear(ledArray[ledNo].port, ledArray[ledNo].pin); + return BSP_STATUS_OK; + } + return BSP_STATUS_ILLEGAL_PARAM; +} + +int BSP_LedGet(int ledNo) +{ + int retVal = BSP_STATUS_ILLEGAL_PARAM; + + if ((ledNo >= 0) && (ledNo < BSP_NO_OF_LEDS)) + { + retVal = (int)GPIO_PinOutGet(ledArray[ledNo].port, ledArray[ledNo].pin); + } + return retVal; +} + +int BSP_LedSet(int ledNo) +{ + if ((ledNo >= 0) && (ledNo < BSP_NO_OF_LEDS)) + { + GPIO_PinOutSet(ledArray[ledNo].port, ledArray[ledNo].pin); + return BSP_STATUS_OK; + } + return BSP_STATUS_ILLEGAL_PARAM; +} + +int BSP_LedToggle(int ledNo) +{ + if ((ledNo >= 0) && (ledNo < BSP_NO_OF_LEDS)) + { + GPIO_PinOutToggle(ledArray[ledNo].port, ledArray[ledNo].pin); + return BSP_STATUS_OK; + } + return BSP_STATUS_ILLEGAL_PARAM; +} + +/** @endcond */ +#endif /* BSP_GPIO_LEDS */ diff --git a/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/CMSIS/efm32pg1b/startup_gcc_efm32pg1b.s b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/CMSIS/efm32pg1b/startup_gcc_efm32pg1b.s new file mode 100644 index 000000000..d9e8a9d3a --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/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 4.2.1 + * 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 __copy_table_start__ and __copy_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/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/CMSIS/efm32pg1b/system_efm32pg1b.c b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/CMSIS/efm32pg1b/system_efm32pg1b.c new file mode 100644 index 000000000..c2b611326 --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/CMSIS/efm32pg1b/system_efm32pg1b.c @@ -0,0 +1,383 @@ +/***************************************************************************//** + * @file system_efm32pg1b.c + * @brief CMSIS Cortex-M3/M4 System Layer for EFM32 devices. + * @version 4.2.1 + ****************************************************************************** + * @section License + * Copyright 2015 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) +#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 +#define EFM32_HFRCO_MAX_FREQ (38000000UL) +#endif + +#ifndef EFM32_HFXO_FREQ +#define EFM32_HFXO_FREQ (40000000UL) +#endif + +#ifndef EFM32_HFRCO_STARTUP_FREQ +#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 +#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; + + +/** + * @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; +} + + +/**************************************************************************//** + * @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) + /* 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/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emdrv/sleep/inc/sleep.h b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emdrv/sleep/inc/sleep.h new file mode 100644 index 000000000..c0b182fd2 --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emdrv/sleep/inc/sleep.h @@ -0,0 +1,265 @@ +/***************************************************************************//** + * @file sleep.h + * @brief Energy Modes management driver + * @version 4.2.1 + * @details + * This is a energy modes management module consisting of sleep.c and sleep.h + * source files. The main purpose of the module is to ease energy + * optimization with a simple API. The module allows the system to always sleep + * in the lowest possible energy mode. Users could set up callbacks that are + * being called before and after each and every sleep. A counting semaphore is + * available for each low energy mode (EM1/EM2/EM3) to protect certain system + * states from being corrupted. This semaphore has limit set to maximum 255 locks. + * + * The module provides the following public API to the users: + * SLEEP_Init() + * SLEEP_Sleep() + * SLEEP_SleepBlockBegin() + * SLEEP_SleepBlockEnd() + * SLEEP_ForceSleepInEM4() + * + ******************************************************************************* + * @section License + * (C) Copyright 2014 Silicon Labs, 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. + * + ******************************************************************************/ + +#ifndef __SLEEP_H +#define __SLEEP_H + +#include +#include + +/* Device specific header file(s). */ +#include "em_device.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + * @addtogroup EM_Drivers + * @{ + ******************************************************************************/ + +/***************************************************************************//** + * @addtogroup SLEEP + * @brief Energy Modes management driver. + * @details + * This is a energy modes management module consisting of sleep.c and sleep.h + * source files. The main purpose of the module is to ease energy + * optimization with a simple API. The module allows the system to always sleep + * in the lowest possible energy mode. Users could set up callbacks that are + * being called before and after each and every sleep. A counting semaphore is + * available for each low energy mode (EM1/EM2/EM3) to protect certain system + * states from being corrupted. This semaphore has limit set to maximum 255 locks. + * @{ + ******************************************************************************/ + +/******************************************************************************* + ******************************* MACROS ************************************ + ******************************************************************************/ + + +/******************************************************************************* + **************************** CONFIGURATION ******************************** + ******************************************************************************/ + +/** Enable/disable the HW block for protecting accidental setting of low energy + * modes (recommended to be set to true). */ +#ifndef SLEEP_HW_LOW_ENERGY_BLOCK_ENABLED +#define SLEEP_HW_LOW_ENERGY_BLOCK_ENABLED true +#endif + +/** Enable/disable calling wakeup callback after EM4 reset. */ +#ifndef SLEEP_EM4_WAKEUP_CALLBACK_ENABLED +#define SLEEP_EM4_WAKEUP_CALLBACK_ENABLED true +#endif + +/** Configure default lowest energy mode that the system can be set to. + * Possible values: + * @li sleepEM1 - EM1, the CPU core is turned off. + * @li sleepEM2 - EM2, like EM1 + all HF clocks are turned off, LF clocks are on. + * @li sleepEM3 - EM3, like EM2 + LF clocks are off, RAM retention, GPIO and ACMP + * interrupt is on. */ +#ifndef SLEEP_LOWEST_ENERGY_MODE_DEFAULT +#define SLEEP_LOWEST_ENERGY_MODE_DEFAULT sleepEM3 +#endif + +/******************************************************************************* + ****************************** TYPEDEFS *********************************** + ******************************************************************************/ + +/** Status value used for showing the Energy Mode the device is currently in. */ +typedef enum +{ + /** Status value for EM0. */ + sleepEM0 = 0, + + /** Status value for EM1. */ + sleepEM1 = 1, + + /** Status value for EM2. */ + sleepEM2 = 2, + + /** Status value for EM3. */ + sleepEM3 = 3, + + /** Status value for EM4. */ + sleepEM4 = 4 +} SLEEP_EnergyMode_t; + +/** Callback function pointer type. */ +typedef void (*SLEEP_CbFuncPtr_t)(SLEEP_EnergyMode_t); + + +/******************************************************************************* + ****************************** PROTOTYPES ********************************* + ******************************************************************************/ + +/***************************************************************************//** + * @brief + * Initialize the Sleep module. + * + * @details + * Use this function to initialize the Sleep module, should be called + * only once! Pointers to sleep and wake-up callback functions shall be + * provided when calling this function. + * If SLEEP_EM4_WAKEUP_CALLBACK_ENABLED is set to true, this function checks + * for the cause of the reset that implicitly called it and calls the wakeup + * callback if the reset was a wakeup from EM4 (does not work on Gecko MCU). + * + * @param[in] pSleepCb + * Pointer to the callback function that is being called before the device is + * going to sleep. + * + * @param[in] pWakeUpCb + * Pointer to the callback function that is being called after wake up. + ******************************************************************************/ +void SLEEP_Init(SLEEP_CbFuncPtr_t pSleepCb, SLEEP_CbFuncPtr_t pWakeUpCb); + +/***************************************************************************//** + * @brief + * Gets the lowest energy mode that the system is allowed to be set to. + * + * @details + * This function uses the low energy mode block counters to determine the + * lowest possible that the system is allowed to be set to. + * + * @return + * Lowest energy mode that the system can be set to. Possible values: + * @li sleepEM0 + * @li sleepEM1 + * @li sleepEM2 + * @li sleepEM3 + ******************************************************************************/ +SLEEP_EnergyMode_t SLEEP_LowestEnergyModeGet(void); + +/***************************************************************************//** + * @brief + * Sets the system to sleep into the lowest possible energy mode. + * + * @details + * This function takes care of the system states protected by the sleep block + * provided by SLEEP_SleepBlockBegin() / SLEEP_SleepBlockEnd(). It allows + * the system to go into the lowest possible energy mode that the device can + * be set into at the time of the call of this function. + * This function will not go lower than EM3 because leaving EM4 requires + * resetting MCU. To enter into EM4 call SLEEP_ForceSleepInEM4(). + * + * @return + * Energy Mode that was entered. Possible values: + * @li sleepEM0 + * @li sleepEM1 + * @li sleepEM2 + * @li sleepEM3 + ******************************************************************************/ +SLEEP_EnergyMode_t SLEEP_Sleep(void); + + +/***************************************************************************//** + * @brief + * Force the device to go to EM4 without doing any checks. + * + * @details + * This function unblocks the low energy sleep block then goes to EM4. + * + * @note + * Regular RAM is not retained in EM4 and the wake up causes a reset. + * If the configuration option SLEEP_EM4_WAKEUP_CALLBACK_ENABLED is set to + * true, the SLEEP_Init() function checks for the reset cause and calls the + * EM4 wakeup callback. + ******************************************************************************/ +void SLEEP_ForceSleepInEM4(void); + + +/***************************************************************************//** + * @brief + * Begin sleep block in the requested energy mode. + * + * @details + * Blocking a critical system state from a certain energy mode makes sure that + * the system is not set to that energy mode while the block is not being + * released. + * Every SLEEP_SleepBlockBegin() increases the corresponding counter and + * every SLEEP_SleepBlockEnd() decreases it. + * + * Example:\code + * SLEEP_SleepBlockBegin(sleepEM2); // do not allow EM2 or higher + * // do some stuff that requires EM1 at least, like ADC sampling + * SLEEP_SleepBlockEnd(sleepEM2); // remove restriction for EM2\endcode + * + * @note + * Be aware that there is limit of maximum blocks nesting to 255. + * + * @param[in] eMode + * Energy mode to begin to block. Possible values: + * @li sleepEM1 - Begin to block the system from being set to EM1 (and EM2..4). + * @li sleepEM2 - Begin to block the system from being set to EM2 (and EM3/EM4). + * @li sleepEM3 - Begin to block the system from being set to EM3 (and EM4). + ******************************************************************************/ +void SLEEP_SleepBlockBegin(SLEEP_EnergyMode_t eMode); + + +/***************************************************************************//** + * @brief + * End sleep block in the requested energy mode. + * + * @details + * Release restriction for entering certain energy mode. Every call of this + * function reduce blocking counter by 1. Once the counter for specific energy + * mode is 0 and all counters for lower energy modes are 0 as well, using + * particular energy mode is allowed. + * Every SLEEP_SleepBlockBegin() increases the corresponding counter and + * every SLEEP_SleepBlockEnd() decreases it. + * + * Example:\code + * // at start all energy modes are allowed + * SLEEP_SleepBlockBegin(sleepEM2); // EM2, EM3, EM4 are blocked + * SLEEP_SleepBlockBegin(sleepEM1); // EM1, EM2, EM3, EM4 are blocked + * SLEEP_SleepBlockBegin(sleepEM1); // EM1, EM2, EM3, EM4 are blocked + * SLEEP_SleepBlockEnd(sleepEM2); // still EM1, EM2, EM3, EM4 are blocked + * SLEEP_SleepBlockEnd(sleepEM1); // still EM1, EM2, EM3, EM4 are blocked + * SLEEP_SleepBlockEnd(sleepEM1); // all energy modes are allowed now\endcode + * + * @param[in] eMode + * Energy mode to end to block. Possible values: + * @li sleepEM1 - End to block the system from being set to EM1 (and EM2..4). + * @li sleepEM2 - End to block the system from being set to EM2 (and EM3/EM4). + * @li sleepEM3 - End to block the system from being set to EM3 (and EM4). + ******************************************************************************/ +void SLEEP_SleepBlockEnd(SLEEP_EnergyMode_t eMode); + + +/** @} (end addtogroup SLEEP) */ +/** @} (end addtogroup EM_Drivers) */ + +#ifdef __cplusplus +} +#endif +#endif /* __SLEEP_H */ diff --git a/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emdrv/sleep/src/sleep.c b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emdrv/sleep/src/sleep.c new file mode 100644 index 000000000..556ec6ba2 --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emdrv/sleep/src/sleep.c @@ -0,0 +1,427 @@ +/***************************************************************************//** + * @file sleep.c + * @brief Energy Modes management driver. + * @version 4.2.1 + * @details + * This is a energy modes management module consisting of sleep.c and sleep.h + * source files. The main purpose of the module is to ease energy + * optimization with a simple API. The module allows the system to always sleep + * in the lowest possible energy mode. Users could set up callbacks that are + * being called before and after each and every sleep. A counting semaphore is + * available for each low energy mode (EM1/EM2/EM3) to protect certain system + * states from being corrupted. This semaphore has limit set to maximum 255 locks. + * + * The module provides the following public API to the users: + * SLEEP_Init() + * SLEEP_Sleep() + * SLEEP_SleepBlockBegin() + * SLEEP_SleepBlockEnd() + * SLEEP_ForceSleepInEM4() + * + ******************************************************************************* + * @section License + * (C) Copyright 2014 Silicon Labs, 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. + * + ******************************************************************************/ + + +/* Chip specific header file(s). */ +#include "em_device.h" +#include "em_assert.h" +#include "em_int.h" +#include "em_rmu.h" +#include "em_emu.h" + +/* Module header file(s). */ +#include "sleep.h" + +/* stdlib is needed for NULL definition */ +#include + +/***************************************************************************//** + * @addtogroup EM_Drivers + * @{ + ******************************************************************************/ + +/***************************************************************************//** + * @addtogroup SLEEP + * @brief Energy Modes management driver. + * @details + * This is a energy modes management module consisting of sleep.c and sleep.h + * source files. The main purpose of the module is to ease energy + * optimization with a simple API. The module allows the system to always sleep + * in the lowest possible energy mode. Users could set up callbacks that are + * being called before and after each and every sleep. A counting semaphore is + * available for each low energy mode (EM1/EM2/EM3) to protect certain system + * states from being corrupted. This semaphore has limit set to maximum 255 locks. + * @{ + ******************************************************************************/ + +/******************************************************************************* + ******************************* MACROS ************************************ + ******************************************************************************/ + +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ + +/* Number of low energy modes (EM1, EM2, EM3). Note: EM4 sleep/wakeup is handled + * differently therefore it is not part of the list! */ +#define SLEEP_NUMOF_LOW_ENERGY_MODES 3U + + + +/******************************************************************************* + ****************************** TYPEDEFS *********************************** + ******************************************************************************/ + + +/******************************************************************************* + ****************************** CONSTANTS ********************************** + ******************************************************************************/ + + +/******************************************************************************* + ******************************* STATICS *********************************** + ******************************************************************************/ + +/* Callback functions to call before and after sleep. */ +static SLEEP_CbFuncPtr_t sleepCallback = NULL; +static SLEEP_CbFuncPtr_t wakeUpCallback = NULL; + +/* Sleep block counter array representing the nested sleep blocks for the low + * energy modes (EM1/EM2/EM3). Array index 0 corresponds to EM1, 1 to EM2 and 2 + * to EM3 accordingly. + * + * Note: + * - EM4 sleep/wakeup is handled differently therefore it is not part of the + * list! + * - Max. number of sleep block nesting is 255. */ +static uint8_t sleepBlockCnt[SLEEP_NUMOF_LOW_ENERGY_MODES]; + +/******************************************************************************* + ****************************** PROTOTYPES ********************************* + ******************************************************************************/ + +static void SLEEP_EnterEMx(SLEEP_EnergyMode_t eMode); +//static SLEEP_EnergyMode_t SLEEP_LowestEnergyModeGet(void); + +/** @endcond */ + +/******************************************************************************* + *************************** GLOBAL FUNCTIONS ****************************** + ******************************************************************************/ + +/***************************************************************************//** + * @brief + * Initialize the Sleep module. + * + * @details + * Use this function to initialize the Sleep module, should be called + * only once! Pointers to sleep and wake-up callback functions shall be + * provided when calling this function. + * If SLEEP_EM4_WAKEUP_CALLBACK_ENABLED is set to true, this function checks + * for the cause of the reset that implicitly called it and calls the wakeup + * callback if the reset was a wakeup from EM4 (does not work on Gecko MCU). + * + * @param[in] pSleepCb + * Pointer to the callback function that is being called before the device is + * going to sleep. + * + * @param[in] pWakeUpCb + * Pointer to the callback function that is being called after wake up. + ******************************************************************************/ +void SLEEP_Init(SLEEP_CbFuncPtr_t pSleepCb, SLEEP_CbFuncPtr_t pWakeUpCb) +{ + /* Initialize callback functions. */ + sleepCallback = pSleepCb; + wakeUpCallback = pWakeUpCb; + + /* Reset sleep block counters. Note: not using for() saves code! */ + sleepBlockCnt[0U] = 0U; + sleepBlockCnt[1U] = 0U; + sleepBlockCnt[2U] = 0U; + +#if (SLEEP_EM4_WAKEUP_CALLBACK_ENABLED == true) && defined(RMU_RSTCAUSE_EM4WURST) + /* Check if the Init() happened after an EM4 reset. */ + if (RMU_ResetCauseGet() & RMU_RSTCAUSE_EM4WURST) + { + /* Clear the cause of the reset. */ + RMU_ResetCauseClear(); + /* Call wakeup callback with EM4 parameter. */ + if (NULL != wakeUpCallback) + { + wakeUpCallback(sleepEM4); + } + } +#endif +} + + +/***************************************************************************//** + * @brief + * Sets the system to sleep into the lowest possible energy mode. + * + * @details + * This function takes care of the system states protected by the sleep block + * provided by SLEEP_SleepBlockBegin() / SLEEP_SleepBlockEnd(). It allows + * the system to go into the lowest possible energy mode that the device can + * be set into at the time of the call of this function. + * This function will not go lower than EM3 because leaving EM4 requires + * resetting MCU. To enter into EM4 call SLEEP_ForceSleepInEM4(). + * + * @return + * Energy Mode that was entered. Possible values: + * @li sleepEM0 + * @li sleepEM1 + * @li sleepEM2 + * @li sleepEM3 + ******************************************************************************/ +SLEEP_EnergyMode_t SLEEP_Sleep(void) +{ + SLEEP_EnergyMode_t allowedEM; + + INT_Disable(); + + allowedEM = SLEEP_LowestEnergyModeGet(); + + if ((allowedEM >= sleepEM1) && (allowedEM <= sleepEM3)) + { + SLEEP_EnterEMx(allowedEM); + } + else + { + allowedEM = sleepEM0; + } + + INT_Enable(); + + return(allowedEM); +} + + +/***************************************************************************//** + * @brief + * Force the device to go to EM4 without doing any checks. + * + * @details + * This function unblocks the low energy sleep block then goes to EM4. + * + * @note + * Regular RAM is not retained in EM4 and the wake up causes a reset. + * If the configuration option SLEEP_EM4_WAKEUP_CALLBACK_ENABLED is set to + * true, the SLEEP_Init() function checks for the reset cause and calls the + * EM4 wakeup callback. + ******************************************************************************/ +void SLEEP_ForceSleepInEM4(void) +{ +#if (SLEEP_HW_LOW_ENERGY_BLOCK_ENABLED == true) + /* Unblock the EM2/EM3/EM4 block in the EMU. */ + EMU_EM2UnBlock(); +#endif + + /* Request entering to EM4. */ + SLEEP_EnterEMx(sleepEM4); +} + +/***************************************************************************//** + * @brief + * Begin sleep block in the requested energy mode. + * + * @details + * Blocking a critical system state from a certain energy mode makes sure that + * the system is not set to that energy mode while the block is not being + * released. + * Every SLEEP_SleepBlockBegin() increases the corresponding counter and + * every SLEEP_SleepBlockEnd() decreases it. + * + * Example:\code + * SLEEP_SleepBlockBegin(sleepEM2); // do not allow EM2 or higher + * // do some stuff that requires EM1 at least, like ADC sampling + * SLEEP_SleepBlockEnd(sleepEM2); // remove restriction for EM2\endcode + * + * @note + * Be aware that there is limit of maximum blocks nesting to 255. + * + * @param[in] eMode + * Energy mode to begin to block. Possible values: + * @li sleepEM1 - Begin to block the system from being set to EM1 (and EM2..4). + * @li sleepEM2 - Begin to block the system from being set to EM2 (and EM3/EM4). + * @li sleepEM3 - Begin to block the system from being set to EM3 (and EM4). + ******************************************************************************/ +void SLEEP_SleepBlockBegin(SLEEP_EnergyMode_t eMode) +{ + EFM_ASSERT((eMode >= sleepEM1) && (eMode < sleepEM4)); + EFM_ASSERT((sleepBlockCnt[(uint8_t) eMode - 1U]) < 255U); + + /* Increase the sleep block counter of the selected energy mode. */ + sleepBlockCnt[(uint8_t) eMode - 1U]++; + +#if (SLEEP_HW_LOW_ENERGY_BLOCK_ENABLED == true) + /* Block EM2/EM3 sleep if the EM2 block begins. */ + if (eMode == sleepEM2) + { + EMU_EM2Block(); + } +#endif +} + +/***************************************************************************//** + * @brief + * End sleep block in the requested energy mode. + * + * @details + * Release restriction for entering certain energy mode. Every call of this + * function reduce blocking counter by 1. Once the counter for specific energy + * mode is 0 and all counters for lower energy modes are 0 as well, using + * particular energy mode is allowed. + * Every SLEEP_SleepBlockBegin() increases the corresponding counter and + * every SLEEP_SleepBlockEnd() decreases it. + * + * Example:\code + * // at start all energy modes are allowed + * SLEEP_SleepBlockBegin(sleepEM2); // EM2, EM3, EM4 are blocked + * SLEEP_SleepBlockBegin(sleepEM1); // EM1, EM2, EM3, EM4 are blocked + * SLEEP_SleepBlockBegin(sleepEM1); // EM1, EM2, EM3, EM4 are blocked + * SLEEP_SleepBlockEnd(sleepEM2); // still EM1, EM2, EM3, EM4 are blocked + * SLEEP_SleepBlockEnd(sleepEM1); // still EM1, EM2, EM3, EM4 are blocked + * SLEEP_SleepBlockEnd(sleepEM1); // all energy modes are allowed now\endcode + * + * @param[in] eMode + * Energy mode to end to block. Possible values: + * @li sleepEM1 - End to block the system from being set to EM1 (and EM2..4). + * @li sleepEM2 - End to block the system from being set to EM2 (and EM3/EM4). + * @li sleepEM3 - End to block the system from being set to EM3 (and EM4). + ******************************************************************************/ +void SLEEP_SleepBlockEnd(SLEEP_EnergyMode_t eMode) +{ + EFM_ASSERT((eMode >= sleepEM1) && (eMode < sleepEM4)); + + /* Decrease the sleep block counter of the selected energy mode. */ + if (sleepBlockCnt[(uint8_t) eMode - 1U] > 0U) + { + sleepBlockCnt[(uint8_t) eMode - 1U]--; + } + +#if (SLEEP_HW_LOW_ENERGY_BLOCK_ENABLED == true) + /* Check if the EM2/EM3 block should be unblocked in the EMU. */ + if (0U == sleepBlockCnt[(uint8_t) sleepEM2 - 1U]) + { + EMU_EM2UnBlock(); + } +#endif +} + +/***************************************************************************//** + * @brief + * Gets the lowest energy mode that the system is allowed to be set to. + * + * @details + * This function uses the low energy mode block counters to determine the + * lowest possible that the system is allowed to be set to. + * + * @return + * Lowest energy mode that the system can be set to. Possible values: + * @li sleepEM0 + * @li sleepEM1 + * @li sleepEM2 + * @li sleepEM3 + ******************************************************************************/ +SLEEP_EnergyMode_t SLEEP_LowestEnergyModeGet(void) +{ + SLEEP_EnergyMode_t tmpLowestEM = sleepEM0; + + /* Check which is the lowest energy mode that the system can be set to. */ + if (0U == sleepBlockCnt[(uint8_t) sleepEM1 - 1U]) + { + tmpLowestEM = sleepEM1; + if (0U == sleepBlockCnt[(uint8_t) sleepEM2 - 1U]) + { + tmpLowestEM = sleepEM2; + if (0U == sleepBlockCnt[(uint8_t) sleepEM3 - 1U]) + { + tmpLowestEM = sleepEM3; + } + } + } + + /* Compare with the default lowest energy mode setting. */ + if (SLEEP_LOWEST_ENERGY_MODE_DEFAULT < tmpLowestEM) + { + tmpLowestEM = SLEEP_LOWEST_ENERGY_MODE_DEFAULT; + } + + return tmpLowestEM; +} + +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ + +/***************************************************************************//** + * @brief + * Call the callbacks and enter the requested energy mode. + * + * @details + * This function is not part of the API, therefore it shall not be called by + * the user directly as it doesn not have any checks if the system is ready + * for sleep! + * + * @note + * The EM4 wakeup callback is not being called from this function because + * waking up from EM4 causes a reset. + * If SLEEP_EM4_WAKEUP_CALLBACK_ENABLED is set to true, SLEEP_Init() function + * checks for the cause of the reset and calls the wakeup callback if the + * reset was a wakeup from EM4. + ******************************************************************************/ +static void SLEEP_EnterEMx(SLEEP_EnergyMode_t eMode) +{ + EFM_ASSERT((eMode > sleepEM0) && (eMode <= sleepEM4)); + + /* Call sleepCallback() before going to sleep. */ + if (NULL != sleepCallback) + { + /* Call the callback before going to sleep. */ + sleepCallback(eMode); + } + + /* Enter the requested energy mode. */ + switch (eMode) + { + case sleepEM1: + { + EMU_EnterEM1(); + } break; + + case sleepEM2: + { + EMU_EnterEM2(true); + } break; + + case sleepEM3: + { + EMU_EnterEM3(true); + } break; + + case sleepEM4: + { + EMU_EnterEM4(); + } break; + + default: + { + /* Don't do anything, stay in EM0. */ + } break; + } + + /* Call the callback after waking up from sleep. */ + if (NULL != wakeUpCallback) + { + wakeUpCallback(eMode); + } +} +/** @endcond */ + +/** @} (end addtogroup SLEEP */ +/** @} (end addtogroup EM_Drivers) */ diff --git a/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emlib/em_assert.c b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emlib/em_assert.c new file mode 100644 index 000000000..9e9d99fad --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emlib/em_assert.c @@ -0,0 +1,69 @@ +/***************************************************************************//** + * @file em_assert.c + * @brief Assert API + * @version 4.2.1 + ******************************************************************************* + * @section License + * (C) Copyright 2015 Silicon Labs, 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" + +#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. + * + * Currently this implementation only 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. + * + * Please notice that this function is not used unless DEBUG_EFM is defined + * during preprocessing of EFM_ASSERT() usage. + * + * @par file + * Name of source file where assertion failed. + * + * @par 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 (1) + ; +} + +#endif /* DEBUG_EFM */ diff --git a/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emlib/em_cmu.c b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emlib/em_cmu.c new file mode 100644 index 000000000..93473ba48 --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emlib/em_cmu.c @@ -0,0 +1,3786 @@ +/***************************************************************************//** + * @file em_cmu.c + * @brief Clock management unit (CMU) Peripheral API + * @version 4.2.1 + ******************************************************************************* + * @section License + * (C) Copyright 2015 Silicon Labs, 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_system.h" + +/***************************************************************************//** + * @addtogroup EM_Library + * @{ + ******************************************************************************/ + +/***************************************************************************//** + * @addtogroup CMU + * @brief Clock management unit (CMU) Peripheral API + * @{ + ******************************************************************************/ + +/******************************************************************************* + ****************************** DEFINES ************************************ + ******************************************************************************/ + +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ + +#if defined( _SILICON_LABS_32B_PLATFORM_2 ) +/** 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 +#elif defined( _SILICON_LABS_32B_PLATFORM_1 ) +/** 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 "Unkown MCU platform." +#endif + +#if defined( CMU_CTRL_HFLE ) +/** Maximum frequency for HFLE needs to be enabled on Giant, Leopard and + Wonder. */ +#if defined( _EFM32_WONDER_FAMILY ) \ + || defined( _EZR32_LEOPARD_FAMILY ) \ + || defined( _EZR32_WONDER_FAMILY ) +#define CMU_MAX_FREQ_HFLE() 24000000 +#elif defined ( _EFM32_GIANT_FAMILY ) +#define CMU_MAX_FREQ_HFLE() (maxFreqHfle()) +#else +#error Invalid part/device. +#endif +#endif + +/******************************************************************************* + ************************** LOCAL VARIABLES ******************************** + ******************************************************************************/ + +#if defined( _CMU_AUXHFRCOCTRL_FREQRANGE_MASK ) +static CMU_AUXHFRCOFreq_TypeDef auxHfrcoFreq = cmuAUXHFRCOFreq_19M0Hz; +#endif + +/** @endcond */ + +/******************************************************************************* + ************************** LOCAL FUNCTIONS ******************************** + ******************************************************************************/ + +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ + +/***************************************************************************//** + * @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 Geckos from TG and newer */ + switch(CMU->AUXHFRCOCTRL & _CMU_AUXHFRCOCTRL_BAND_MASK) + { + case CMU_AUXHFRCOCTRL_BAND_1MHZ: + ret = 1000000; + break; + + case CMU_AUXHFRCOCTRL_BAND_7MHZ: + 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; +} + + +/***************************************************************************//** + * @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(); +#if defined( _CMU_CTRL_HFCLKDIV_MASK ) + /* Family with an additional divider. */ + ret = ret / (1 + ((CMU->CTRL & _CMU_CTRL_HFCLKDIV_MASK) + >> _CMU_CTRL_HFCLKDIV_SHIFT)); +#endif + break; + + case cmuSelect_AUXHFRCO: + ret = auxClkGet(); + break; + + default: + EFM_ASSERT(0); + ret = 0; + break; + } + return ret; +} + + +/***************************************************************************//** + * @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 + ******************************************************************************/ +static void flashWaitStateControl(uint32_t coreFreq) +{ + uint32_t mode; + bool mscLocked; +#if defined( MSC_READCTRL_MODE_WS0SCBTP ) + bool scbtpEn; /* Suppressed Conditional Branch Target Prefetch setting. */ +#endif + + /* 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 ) + 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; + } +#endif + + + /* Set mode based on the core clock frequency and SCBTP enable */ +#if defined( MSC_READCTRL_MODE_WS0SCBTP ) + 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); + } + +#else /* If MODE and SCBTP is in separate register fields */ + + if (false) + { + } +#if defined( MSC_READCTRL_MODE_WS2 ) + else if (coreFreq > CMU_MAX_FREQ_1WS) + { + mode = MSC_READCTRL_MODE_WS2; + } +#endif + else if ((coreFreq <= CMU_MAX_FREQ_1WS) && (coreFreq > CMU_MAX_FREQ_0WS)) + { + mode = MSC_READCTRL_MODE_WS1; + } + else + { + mode = MSC_READCTRL_MODE_WS0; + } +#endif + + /* BUS_RegMaskedWrite cannot be used here as it would temporarely 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()); +} + + +/***************************************************************************//** + * @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: + sel = (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFC_MASK) >> _CMU_LFCLKSEL_LFC_SHIFT; + 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_CTRL_HFLE ) + /* Family which can use an extra div 4 divider */ + /* (and must if >32MHz) or HFLE is set. */ + if(((CMU->HFCORECLKDIV & _CMU_HFCORECLKDIV_HFCORECLKLEDIV_MASK) + == CMU_HFCORECLKDIV_HFCORECLKLEDIV_DIV4) + || (CMU->CTRL & CMU_CTRL_HFLE)) + { + ret = SystemCoreClockGet() / 4U; + } + else + { + ret = SystemCoreClockGet() / 2U; + } +#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_HFCLKLE ) + case _CMU_LFACLKSEL_LFA_HFCLKLE: + ret = ((CMU->HFPRESC & _CMU_HFPRESC_HFCLKLEPRESC_MASK) + == CMU_HFPRESC_HFCLKLEPRESC_DIV4) + ? SystemCoreClockGet() / 4U + : SystemCoreClockGet() / 2U; + break; +#elif defined( _CMU_LFBCLKSEL_LFB_HFCLKLE ) + case _CMU_LFBCLKSEL_LFB_HFCLKLE: + ret = ((CMU->HFPRESC & _CMU_HFPRESC_HFCLKLEPRESC_MASK) + == CMU_HFPRESC_HFCLKLEPRESC_DIV4) + ? SystemCoreClockGet() / 4U + : SystemCoreClockGet() / 2U; + break; +#endif + + case _CMU_LFACLKSEL_LFA_DISABLED: + ret = 0; + break; + } +#endif + + return ret; +} + + +#if defined( CMU_CTRL_HFLE ) \ + && !defined( _EFM32_WONDER_FAMILY ) \ + && !defined( _EZR32_LEOPARD_FAMILY ) \ + && !defined( _EZR32_WONDER_FAMILY ) +/***************************************************************************//** + * @brief + * Return max allowed frequency for low energy peripherals. + ******************************************************************************/ +static uint32_t maxFreqHfle(void) +{ + uint16_t majorMinorRev; + + switch (SYSTEM_GetFamily()) + { + case systemPartFamilyEfm32Leopard: + /* 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 + + +/***************************************************************************//** + * @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(USB_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; + 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 a pointer to 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; + + default: /* cmuAUXHFRCOFreq_UserDefined */ + return 0; + } +} +#endif /* _CMU_AUXHFRCOCTRL_FREQRANGE_MASK */ + + +#if defined( _CMU_AUXHFRCOCTRL_FREQRANGE_MASK ) +/***************************************************************************//** + * @brief + * Get AUXHFRCO frequency enumeration in use + * + * @return + * AUXHFRCO frequency enumeration in use + ******************************************************************************/ +CMU_AUXHFRCOFreq_TypeDef CMU_AUXHFRCOFreqGet(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] frequency + * AUXHFRCO frequency to set + ******************************************************************************/ +void CMU_AUXHFRCOFreqSet(CMU_AUXHFRCOFreq_TypeDef freq) +{ + uint32_t freqCal; + + /* Get DEVINFO index, set global auxHfrcoFreq */ + freqCal = CMU_AUXHFRCODevinfoGet(freq); + EFM_ASSERT((freqCal != 0) && (freqCal != UINT_MAX)); + auxHfrcoFreq = freq; + + /* 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(freq) + { + 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; + + 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; + + 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; + + 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_PLATFORM_2 ) + return 1 + (uint32_t)CMU_ClockPrescGet(clock); + +#elif defined( _SILICON_LABS_32B_PLATFORM_1 ) + 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_PLATFORM_2 ) + CMU_ClockPrescSet(clock, (CMU_ClkPresc_TypeDef)(div - 1)); + +#elif defined( _SILICON_LABS_32B_PLATFORM_1 ) + 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 */ + flashWaitStateControl(freq); + 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_512); + + /* Configure worst case wait states for flash access before setting divisor */ + flashWaitStateMax(); + +#if defined( CMU_CTRL_HFLE ) + /* Clear HFLE and set DIV2 factor for peripheral clock + when running at frequencies lower than or equal to CMU_MAX_FREQ_HFLE. */ + if ((CMU_ClockFreqGet(cmuClock_HF) / div) <= CMU_MAX_FREQ_HFLE()) + { + /* Clear CMU HFLE */ + BUS_RegBitWrite(&CMU->CTRL, _CMU_CTRL_HFLE_SHIFT, 0); + + /* Set DIV2 factor for peripheral clock */ + BUS_RegBitWrite(&CMU->HFCORECLKDIV, + _CMU_HFCORECLKDIV_HFCORECLKLEDIV_SHIFT, 0); + } + else + { + /* Set CMU HFLE */ + BUS_RegBitWrite(&CMU->CTRL, _CMU_CTRL_HFLE_SHIFT, 1); + + /* Set DIV4 factor for peripheral clock */ + BUS_RegBitWrite(&CMU->HFCORECLKDIV, + _CMU_HFCORECLKDIV_HFCORECLKLEDIV_SHIFT, 1); + } +#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 flash access wait state setting for current core clk */ + flashWaitStateControl(freq); + 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( _SILICON_LABS_32B_PLATFORM_2 ) + case CMU_CTRL_EN_REG: + reg = &CMU->CTRL; + break; +#endif + +#if defined( _SILICON_LABS_32B_PLATFORM_1 ) + case CMU_HFCORECLKEN0_EN_REG: + reg = &CMU->HFCORECLKEN0; +#if defined( CMU_CTRL_HFLE ) + /* Set HFLE and DIV4 factor for peripheral clock when + running at frequencies higher than or equal to CMU_MAX_FREQ_HFLE. */ + if ( CMU_ClockFreqGet(cmuClock_CORE) > CMU_MAX_FREQ_HFLE()) + { + /* Enable CMU HFLE */ + BUS_RegBitWrite(&CMU->CTRL, _CMU_CTRL_HFLE_SHIFT, 1); + + /* Set DIV4 factor for peripheral clock */ + BUS_RegBitWrite(&CMU->HFCORECLKDIV, + _CMU_HFCORECLKDIV_HFCORECLKLEDIV_SHIFT, 1); + } +#endif + break; +#endif + +#if defined( _CMU_HFBUSCLKEN0_MASK ) + case CMU_HFBUSCLKEN0_EN_REG: + reg = &CMU->HFBUSCLKEN0; + break; +#endif + +#if defined( _CMU_HFRADIOCLKEN0_MASK ) + case CMU_HFRADIOCLKEN0_EN_REG: + reg = &CMU->HFRADIOCLKEN0; + 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; + + 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 + + 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(); +#if defined( _CMU_CTRL_HFCLKDIV_MASK ) + /* Family with an additional divider. */ + ret = ret / (1U + ((CMU->CTRL & _CMU_CTRL_HFCLKDIV_MASK) + >> _CMU_CTRL_HFCLKDIV_SHIFT)); +#endif +#if defined( _CMU_HFPRESC_MASK ) + ret = ret / (1U + ((CMU->HFPRESC & _CMU_HFPRESC_PRESC_MASK) + >> _CMU_HFPRESC_PRESC_SHIFT)); +#endif + break; + + case (CMU_HFPER_CLK_BRANCH << CMU_CLK_BRANCH_POS): + ret = SystemHFClockGet(); +#if defined( _SILICON_LABS_32B_PLATFORM_1 ) +#if defined( _CMU_CTRL_HFCLKDIV_MASK ) + /* Family with an additional divider. */ + ret = ret / (1U + ((CMU->CTRL & _CMU_CTRL_HFCLKDIV_MASK) + >> _CMU_CTRL_HFCLKDIV_SHIFT)); +#endif + ret >>= (CMU->HFPERCLKDIV & _CMU_HFPERCLKDIV_HFPERCLKDIV_MASK) + >> _CMU_HFPERCLKDIV_HFPERCLKDIV_SHIFT; +#elif defined( _SILICON_LABS_32B_PLATFORM_2 ) + ret /= 1U + ((CMU->HFPERPRESC & _CMU_HFPERPRESC_PRESC_MASK) + >> _CMU_HFPERPRESC_PRESC_SHIFT); +#endif + break; + +#if defined( _SILICON_LABS_32B_PLATFORM_2 ) +#if defined( _CMU_HFRADIOPRESC_PRESC_MASK ) + case (CMU_HFRADIO_CLK_BRANCH << CMU_CLK_BRANCH_POS): + ret = SystemHFClockGet(); + ret /= 1U + ((CMU->HFRADIOPRESC & _CMU_HFRADIOPRESC_PRESC_MASK) + >> _CMU_HFRADIOPRESC_PRESC_SHIFT); + break; +#endif + +#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_PLATFORM_1 ) +#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_PLATFORM_1 ) + ret >>= (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LETIMER0_MASK) + >> _CMU_LFAPRESC0_LETIMER0_SHIFT; +#elif defined( _SILICON_LABS_32B_PLATFORM_2 ) + 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); + ret >>= ((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LCD_MASK) + >> _CMU_LFAPRESC0_LCD_SHIFT) + + CMU_DivToLog2(cmuClkDiv_16); + break; + + 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 + +#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_PLATFORM_1 ) + ret >>= (CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART0_MASK) + >> _CMU_LFBPRESC0_LEUART0_SHIFT; +#elif defined( _SILICON_LABS_32B_PLATFORM_2 ) + 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_PLATFORM_1 ) + ret >>= (CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART1_MASK) + >> _CMU_LFBPRESC0_LEUART1_SHIFT; +#elif defined( _SILICON_LABS_32B_PLATFORM_2 ) + ret /= CMU_Log2ToDiv((CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART1_MASK) + >> _CMU_LFBPRESC0_LEUART1_SHIFT); +#endif + break; +#endif + +#if defined( _SILICON_LABS_32B_PLATFORM_2 ) + 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(USB_PRESENT) + case (CMU_USBC_CLK_BRANCH << CMU_CLK_BRANCH_POS): + ret = usbCClkGet(); + break; +#endif + + default: + EFM_ASSERT(0); + ret = 0; + break; + } + + return ret; +} + + +#if defined( _SILICON_LABS_32B_PLATFORM_2 ) +/***************************************************************************//** + * @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; + +#if defined( _CMU_HFRADIOPRESC_PRESC_MASK ) + case CMU_HFRADIOPRESC_REG: + ret = ((CMU->HFRADIOPRESC & _CMU_HFRADIOPRESC_PRESC_MASK) + >> _CMU_HFRADIOPRESC_PRESC_SHIFT); + break; +#endif + + 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 + + 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 + + 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; + + default: + EFM_ASSERT(0); + ret = 0U; + break; + } + + return ret; +} +#endif + + +#if defined( _SILICON_LABS_32B_PLATFORM_2 ) +/***************************************************************************//** + * @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); + + CMU->HFPRESC = (CMU->HFPRESC & ~_CMU_HFPRESC_PRESC_MASK) + | (presc << _CMU_HFPRESC_PRESC_SHIFT); + 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: + EFM_ASSERT(presc < 2U); + + /* Specifies the clock divider for HFCLKLE. When running at frequencies + * higher than 32 MHz, this must be set to DIV4. */ + 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; + +#if defined( _CMU_HFRADIOPRESC_PRESC_MASK ) + case CMU_HFRADIOPRESC_REG: + EFM_ASSERT(presc < 512U); + + CMU->HFRADIOPRESC = (CMU->HFRADIOPRESC & ~_CMU_HFRADIOPRESC_PRESC_MASK) + | (presc << _CMU_HFRADIOPRESC_PRESC_SHIFT); + break; +#endif + + case CMU_HFCOREPRESC_REG: + EFM_ASSERT(presc < 512U); + + /* Configure worst case wait states for flash access before setting + * the prescaler. */ + flashWaitStateControl(CMU_MAX_FREQ_0WS + 1); + + CMU->HFCOREPRESC = (CMU->HFCOREPRESC & ~_CMU_HFCOREPRESC_PRESC_MASK) + | (presc << _CMU_HFCOREPRESC_PRESC_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 */ + flashWaitStateControl(freq); + 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 + + 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 + + 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; + + 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_PLATFORM_2 + * @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_HFCLKSEL_HF_MASK ) + switch (CMU->HFCLKSEL & _CMU_HFCLKSEL_HF_MASK) + { + case CMU_HFCLKSEL_HF_LFXO: + ret = cmuSelect_LFXO; + break; + + case CMU_HFCLKSEL_HF_LFRCO: + ret = cmuSelect_LFRCO; + break; + + case CMU_HFCLKSEL_HF_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; + + 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_CORELEDIV2; + 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; + } +#endif /* _CMU_LFCLKSEL_MASK */ + +#if 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 + + default: + ret = cmuSelect_Disabled; + break; + } +#endif + break; + + 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_CORELEDIV2; + 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; + } +#endif /* _CMU_LFCLKSEL_MASK */ + +#if 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; + + default: + ret = cmuSelect_Disabled; + break; + } +#endif + break; + +#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 + + 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; + } +#else + ret = cmuSelect_AUXHFRCO; +#endif /* CMU_DBGCLKSEL_DBG */ + +#if 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( USB_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 + + 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_LFCLKSEL_LFAE_ULFRCO + * @li #cmuClock_LFC + * @endif @if _SILICON_LABS_32B_PLATFORM_2 + * @li #cmuClock_LFE + * @endif + * @li #cmuClock_DBG @if DOXYDOC_USB_PRESENT + * @li #cmuClock_USBC + * @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 + * @li #cmuSelect_LFXO + * @li #cmuSelect_CORELEDIV2 + * @li #cmuSelect_AUXHFRCO + * @li #cmuSelect_HFCLK @ifnot DOXYDOC_EFM32_GECKO_FAMILY + * @li #cmuSelect_ULFRCO + * @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_PLATFORM_2 ) + volatile uint32_t *selReg = NULL; +#endif +#if defined( CMU_LFCLKSEL_LFAE_ULFRCO ) + uint32_t lfExtended = 0; +#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_PLATFORM_2 ) + select = CMU_HFCLKSEL_HF_LFXO; +#elif defined( _SILICON_LABS_32B_PLATFORM_1 ) + select = CMU_CMD_HFCLKSEL_LFXO; +#endif + osc = cmuOsc_LFXO; + break; + + case cmuSelect_LFRCO: +#if defined( _SILICON_LABS_32B_PLATFORM_2 ) + select = CMU_HFCLKSEL_HF_LFRCO; +#elif defined( _SILICON_LABS_32B_PLATFORM_1 ) + select = CMU_CMD_HFCLKSEL_LFRCO; +#endif + osc = cmuOsc_LFRCO; + break; + + case cmuSelect_HFXO: + osc = cmuOsc_HFXO; +#if defined( _SILICON_LABS_32B_PLATFORM_2 ) + select = CMU_HFCLKSEL_HF_HFXO; + /* Adjust HFXO buffer current for high frequencies, */ + /* enable WSHFLE for frequencies above 32MHz. */ + if (SystemHFXOClockGet() > 32000000) + { + CMU->CTRL |= CMU_CTRL_WSHFLE; + } +#elif defined( _SILICON_LABS_32B_PLATFORM_1 ) + select = CMU_CMD_HFCLKSEL_HFXO; +#if defined( CMU_CTRL_HFLE ) + /* Adjust HFXO buffer current for high frequencies, */ + /* enable HFLE for frequencies above CMU_MAX_FREQ_HFLE. */ + if(SystemHFXOClockGet() > CMU_MAX_FREQ_HFLE()) + { + CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_HFXOBUFCUR_MASK) + | CMU_CTRL_HFXOBUFCUR_BOOSTABOVE32MHZ + /* Must have HFLE enabled to access some LE peripherals >=32MHz */ + | CMU_CTRL_HFLE; + + /* Set HFLE and DIV4 factor for peripheral clock if HFCORE */ + /* clock for LE is enabled. */ + if (CMU->HFCORECLKEN0 & CMU_HFCORECLKEN0_LE) + { + BUS_RegBitWrite(&CMU->HFCORECLKDIV, + _CMU_HFCORECLKDIV_HFCORECLKLEDIV_SHIFT, 1); + } + } + else + { + /* This can happen if the user configures the EFM32_HFXO_FREQ to */ + /* use another oscillator frequency */ + CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_HFXOBUFCUR_MASK) + | CMU_CTRL_HFXOBUFCUR_BOOSTUPTO32MHZ; + } +#endif +#endif + break; + + case cmuSelect_HFRCO: +#if defined( _SILICON_LABS_32B_PLATFORM_2 ) + select = CMU_HFCLKSEL_HF_HFRCO; +#elif defined( _SILICON_LABS_32B_PLATFORM_1 ) + select = CMU_CMD_HFCLKSEL_HFRCO; +#endif + osc = cmuOsc_HFRCO; + 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(); + + /* Switch to selected oscillator */ +#if defined( _SILICON_LABS_32B_PLATFORM_2 ) + CMU->HFCLKSEL = select; +#elif defined( _SILICON_LABS_32B_PLATFORM_1 ) + CMU->CMD = select; +#endif + + /* Keep EMU module informed */ + EMU_UpdateOscConfig(); + + /* 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 */ + flashWaitStateControl(freq); + break; + +#if defined( _SILICON_LABS_32B_PLATFORM_2 ) + 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 + 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 + 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 HFCORE to LE clocking is enabled */ + BUS_RegBitWrite(&CMU->HFBUSCLKEN0, _CMU_HFBUSCLKEN0_LE_SHIFT, 1); + tmp = _CMU_LFBCLKSEL_LFB_HFCLKLE; + + /* If core frequency is > 32MHz enable WSHFLE */ + freq = SystemCoreClockGet(); + if (freq > 32000000U) + { + /* Enable CMU HFLE */ + BUS_RegBitWrite(&CMU->CTRL, _CMU_CTRL_WSHFLE_SHIFT, 1); + + /* Enable DIV4 factor for peripheral clock */ + BUS_RegBitWrite(&CMU->HFPRESC, _CMU_HFPRESC_HFCLKLEPRESC_SHIFT, 1); + } + break; + + case cmuSelect_ULFRCO: + /* ULFRCO is always on, there is no need to enable it. */ + tmp = _CMU_LFACLKSEL_LFA_ULFRCO; + break; + + default: + EFM_ASSERT(0); + return; + } + *selReg = tmp; + break; + +#elif defined( _SILICON_LABS_32B_PLATFORM_1 ) + 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_CORELEDIV2: + /* Ensure HFCORE to LE clocking is enabled */ + BUS_RegBitWrite(&(CMU->HFCORECLKEN0), _CMU_HFCORECLKEN0_LE_SHIFT, 1); + tmp = _CMU_LFCLKSEL_LFA_HFCORECLKLEDIV2; +#if defined( CMU_CTRL_HFLE ) + /* If core frequency is higher than CMU_MAX_FREQ_HFLE on + Giant/Leopard/Wonder, enable HFLE and DIV4. */ + freq = SystemCoreClockGet(); + if(freq > CMU_MAX_FREQ_HFLE()) + { + /* Enable CMU HFLE */ + BUS_RegBitWrite(&CMU->CTRL, _CMU_CTRL_HFLE_SHIFT, 1); + + /* Enable DIV4 factor for peripheral clock */ + BUS_RegBitWrite(&CMU->HFCORECLKDIV, + _CMU_HFCORECLKDIV_HFCORECLKLEDIV_SHIFT, 1); + } +#endif + 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 ) || defined( CMU_CTRL_DBGCLK ) + case CMU_DBGCLKSEL_REG: + switch(ref) + { +#if defined( CMU_DBGCLKSEL_DBG ) + 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(USB_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 + + default: + EFM_ASSERT(0); + break; + } +} + + +/**************************************************************************//** + * @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) + { + /* Update CMSIS core clock variable and get current core clock */ + /* (The function will update the global variable) */ + /* NOTE! We need at least 21 cycles before setting zero wait state to flash */ + /* (i.e. WS0) when going from the 28MHz to 1MHz in the HFRCO band */ + freq = SystemCoreClockGet(); + + /* Optimize flash access wait state setting for current core clk */ + flashWaitStateControl(freq); + } +} +#endif /* _CMU_HFRCOCTRL_BAND_MASK */ + + +#if defined( _CMU_HFRCOCTRL_FREQRANGE_MASK ) +/**************************************************************************//** + * @brief + * Get a pointer to 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; + + default: /* cmuHFRCOFreq_UserDefined */ + return 0; + } +} + + +/***************************************************************************//** + * @brief + * Get HFRCO frequency enumeration in use + * + * @return + * HFRCO frequency enumeration in use + ******************************************************************************/ +CMU_HFRCOFreq_TypeDef CMU_HFRCOFreqGet(void) +{ + return (CMU_HFRCOFreq_TypeDef)SystemHfrcoFreq; +} + + +/***************************************************************************//** + * @brief + * Set HFRCO calibration for the selected target frequency + * + * @param[in] freq + * HFRCO frequency band to set + ******************************************************************************/ +void CMU_HFRCOFreqSet(CMU_HFRCOFreq_TypeDef freq) +{ + uint32_t freqCal; + + /* Get DEVINFO index, set CMSIS frequency SystemHfrcoFreq */ + freqCal = CMU_HFRCODevinfoGet(freq); + EFM_ASSERT((freqCal != 0) && (freqCal != UINT_MAX)); + SystemHfrcoFreq = (uint32_t)freq; + + /* 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(freq) + { + 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; + } + CMU->HFRCOCTRL = freqCal; + + /* Optimize flash access wait-state configuration for this frequency, */ + /* if HFRCO is reference for core clock. */ + if (CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCO) + { + flashWaitStateControl((uint32_t)freq); + } +} +#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_HFXOCTRL_AUTOSTARTRDYSELRAC_MASK ) +/***************************************************************************//** + * @brief + * Enable or disable HFXO autostart + * + * @param[in] enRACStartSel + * If true, HFXO is automatically started and selected upon RAC wakeup. + * If false, HFXO is not started or selected automatically upon RAC wakeup. + * + * @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(bool enRACStartSel, + bool enEM0EM1Start, + bool enEM0EM1StartSel) +{ + uint32_t hfxoCtrl; + hfxoCtrl = CMU->HFXOCTRL & ~(_CMU_HFXOCTRL_AUTOSTARTRDYSELRAC_MASK + | _CMU_HFXOCTRL_AUTOSTARTEM0EM1_MASK + | _CMU_HFXOCTRL_AUTOSTARTSELEM0EM1_MASK); + + hfxoCtrl |= (enRACStartSel ? CMU_HFXOCTRL_AUTOSTARTRDYSELRAC : 0) + | (enEM0EM1Start ? CMU_HFXOCTRL_AUTOSTARTEM0EM1 : 0) + | (enEM0EM1StartSel ? CMU_HFXOCTRL_AUTOSTARTSELEM0EM1 : 0); + + CMU->HFXOCTRL = hfxoCtrl; +} +#endif /* _CMU_HFXOCTRL_AUTOSTARTRDYSELRAC_MASK */ + + +#if defined( _CMU_HFXOCTRL_MASK ) +/**************************************************************************//** + * @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(CMU_HFXOInit_TypeDef *hfxoInit) +{ + uint32_t ishReg; + uint32_t ishMax; + + /* 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, false); + + /* Apply control settings */ + BUS_RegMaskedWrite(&CMU->HFXOCTRL, + _CMU_HFXOCTRL_LOWPOWER_MASK +#if defined( _CMU_HFXOCTRL_AUTOSTARTRDYSELRAC_MASK ) + | _CMU_HFXOCTRL_AUTOSTARTRDYSELRAC_MASK +#endif + | _CMU_HFXOCTRL_AUTOSTARTEM0EM1_MASK + | _CMU_HFXOCTRL_AUTOSTARTSELEM0EM1_MASK, + (hfxoInit->lowPowerMode + ? CMU_HFXOCTRL_LOWPOWER : 0) +#if defined( _CMU_HFXOCTRL_AUTOSTARTRDYSELRAC_MASK ) + | (hfxoInit->autoStartSelOnRacWakeup + ? CMU_HFXOCTRL_AUTOSTARTRDYSELRAC : 0) +#endif + | (hfxoInit->autoStartEm01 + ? CMU_HFXOCTRL_AUTOSTARTEM0EM1 : 0) + | (hfxoInit->autoSelEm01 + ? CMU_HFXOCTRL_AUTOSTARTSELEM0EM1 : 0)); + + /* Set XTAL tuning parameters */ + + /* Set peak detection threshold in CMU_HFXOCTRL1_PEAKDETTHR[2:0] (hidden). */ + BUS_RegMaskedWrite((volatile uint32_t *)0x400E4028, 0x7, hfxoInit->thresholdPeakDetect); + + /* Set tuning for startup and steady state */ + BUS_RegMaskedWrite(&CMU->HFXOSTARTUPCTRL, + _CMU_HFXOSTARTUPCTRL_CTUNE_MASK + | _CMU_HFXOSTARTUPCTRL_REGISHWARM_MASK + | _CMU_HFXOSTARTUPCTRL_IBTRIMXOCORE_MASK + | _CMU_HFXOSTARTUPCTRL_IBTRIMXOCOREWARM_MASK, + (hfxoInit->ctuneStartup + << _CMU_HFXOSTARTUPCTRL_CTUNE_SHIFT) + | (hfxoInit->regIshStartup + << _CMU_HFXOSTARTUPCTRL_REGISHWARM_SHIFT) + | (hfxoInit->xoCoreBiasTrimStartup + << _CMU_HFXOSTARTUPCTRL_IBTRIMXOCORE_SHIFT) + | 0x4 /* Recommended tuning */ + << _CMU_HFXOSTARTUPCTRL_IBTRIMXOCOREWARM_SHIFT); + + /* Adjust CMU_HFXOSTEADYSTATECTRL_REGISHUPPER according to regIshSteadyState. + Saturate at max value. Please see the reference manual page 433 and Section + 12.5.10 CMU_HFXOSTEADYSTATECTRL for more details. */ + ishReg = hfxoInit->regIshSteadyState + 3; + ishMax = _CMU_HFXOSTEADYSTATECTRL_REGISHUPPER_MASK + >> _CMU_HFXOSTEADYSTATECTRL_REGISHUPPER_SHIFT; + ishReg = ishReg > ishMax ? ishMax : ishReg; + ishReg <<= _CMU_HFXOSTEADYSTATECTRL_REGISHUPPER_SHIFT; + + BUS_RegMaskedWrite(&CMU->HFXOSTEADYSTATECTRL, + _CMU_HFXOSTEADYSTATECTRL_CTUNE_MASK + | _CMU_HFXOSTEADYSTATECTRL_REGISH_MASK + | _CMU_HFXOSTEADYSTATECTRL_IBTRIMXOCORE_MASK + | _CMU_HFXOSTEADYSTATECTRL_REGISHUPPER_MASK, + (hfxoInit->ctuneSteadyState + << _CMU_HFXOSTEADYSTATECTRL_CTUNE_SHIFT) + | (hfxoInit->regIshSteadyState + << _CMU_HFXOSTEADYSTATECTRL_REGISH_SHIFT) + | (hfxoInit->xoCoreBiasTrimSteadyState + << _CMU_HFXOSTEADYSTATECTRL_IBTRIMXOCORE_SHIFT) + | ishReg); + + /* Set timeouts */ + BUS_RegMaskedWrite(&CMU->HFXOTIMEOUTCTRL, + _CMU_HFXOTIMEOUTCTRL_SHUNTOPTTIMEOUT_MASK + | _CMU_HFXOTIMEOUTCTRL_PEAKDETTIMEOUT_MASK + | _CMU_HFXOTIMEOUTCTRL_WARMSTEADYTIMEOUT_MASK + | _CMU_HFXOTIMEOUTCTRL_STEADYTIMEOUT_MASK + | _CMU_HFXOTIMEOUTCTRL_STARTUPTIMEOUT_MASK, + (hfxoInit->timeoutShuntOptimization + << _CMU_HFXOTIMEOUTCTRL_SHUNTOPTTIMEOUT_SHIFT) + | (hfxoInit->timeoutPeakDetect + << _CMU_HFXOTIMEOUTCTRL_PEAKDETTIMEOUT_SHIFT) + | (hfxoInit->timeoutWarmSteady + << _CMU_HFXOTIMEOUTCTRL_WARMSTEADYTIMEOUT_SHIFT) + | (hfxoInit->timeoutSteady + << _CMU_HFXOTIMEOUTCTRL_STEADYTIMEOUT_SHIFT) + | (hfxoInit->timeoutStartup + << _CMU_HFXOTIMEOUTCTRL_STARTUPTIMEOUT_SHIFT)); +} +#endif + + +/***************************************************************************//** + * @brief + * Get the LCD framerate divisor (FDIV) setting. + * + * @return + * The LCD framerate divisor. + ******************************************************************************/ +uint32_t CMU_LCDClkFDIVGet(void) +{ +#if defined( LCD_PRESENT ) + 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 ) + 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) */ +} + + +#if defined( _CMU_LFXOCTRL_MASK ) +/**************************************************************************//** + * @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(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); + + BUS_RegMaskedWrite(&CMU->LFXOCTRL, + _CMU_LFXOCTRL_TUNING_MASK + | _CMU_LFXOCTRL_GAIN_MASK + | _CMU_LFXOCTRL_TIMEOUT_MASK, + (lfxoInit->ctune << _CMU_LFXOCTRL_TUNING_SHIFT) + | (lfxoInit->gain << _CMU_LFXOCTRL_GAIN_SHIFT) + | (lfxoInit->timeout << _CMU_LFXOCTRL_TIMEOUT_SHIFT)); +} +#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_PLATFORM_2 ) + uint32_t ensBitPos; +#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_PLATFORM_2 ) + 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_PLATFORM_2 ) + 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_PLATFORM_2 ) + 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_PLATFORM_2 ) + 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_PLATFORM_2 ) + 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_PLATFORM_2 ) + ensBitPos = _CMU_STATUS_USHFRCOENS_SHIFT; +#endif + break; +#endif + +#if defined( CMU_LFCLKSEL_LFAE_ULFRCO ) + case cmuOsc_ULFRCO: + /* ULFRCO is always enabled, and cannot be turned off */ + return; +#endif + + default: + /* Undefined clock source */ + EFM_ASSERT(0); + return; + } + + if (enable) + { + CMU->OSCENCMD = enBit; + +#if defined( _SILICON_LABS_32B_PLATFORM_2 ) + /* 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( _CMU_STATUS_HFXOSHUNTOPTRDY_MASK ) + /* Wait for shunt current optimization to complete */ + if ((osc == cmuOsc_HFXO) + && (BUS_RegMaskedRead(&CMU->HFXOCTRL, + _CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK) + == CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_AUTOCMD)) + { + while (!BUS_RegBitRead(&CMU->STATUS, _CMU_STATUS_HFXOSHUNTOPTRDY_SHIFT)) + { + } + /* Assert on failed peak detection. Incorrect HFXO initialization parameters + caused startup to fail. Please review parameters. */ + EFM_ASSERT(BUS_RegBitRead(&CMU->STATUS, _CMU_STATUS_HFXOPEAKDETRDY_SHIFT)); + } +#endif + } + } + else + { + CMU->OSCENCMD = disBit; + +#if defined( _SILICON_LABS_32B_PLATFORM_2 ) + /* Always wait for ENS to go low */ + while (BUS_RegBitRead(&CMU->STATUS, ensBitPos)) + { + } +#endif + } + + /* Keep EMU module informed */ + EMU_UpdateOscConfig(); +} + + +/***************************************************************************//** + * @brief + * Get oscillator frequency tuning setting. + * + * @param[in] osc + * Oscillator to get tuning value for, one of: + * @li #cmuOsc_LFRCO + * @li #cmuOsc_HFRCO + * @li #cmuOsc_AUXHFRCO + * + * @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; + + case cmuOsc_AUXHFRCO: + ret = (CMU->AUXHFRCOCTRL & _CMU_AUXHFRCOCTRL_TUNING_MASK) + >> _CMU_AUXHFRCOCTRL_TUNING_SHIFT; + break; + + 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. + * + * @param[in] osc + * Oscillator to set tuning value for, one of: + * @li #cmuOsc_LFRCO + * @li #cmuOsc_HFRCO + * @li #cmuOsc_AUXHFRCO + * + * @param[in] val + * The oscillator frequency tuning setting to use. + ******************************************************************************/ +void CMU_OscillatorTuningSet(CMU_Osc_TypeDef osc, uint32_t val) +{ + 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_PLATFORM_2 ) + 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_PLATFORM_2 ) + while(BUS_RegBitRead(&CMU->SYNCBUSY, _CMU_SYNCBUSY_HFRCOBSY_SHIFT)) + { + } +#endif + CMU->HFRCOCTRL = (CMU->HFRCOCTRL & ~(_CMU_HFRCOCTRL_TUNING_MASK)) + | (val << _CMU_HFRCOCTRL_TUNING_SHIFT); + break; + + 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_PLATFORM_2 ) + while(BUS_RegBitRead(&CMU->SYNCBUSY, _CMU_SYNCBUSY_AUXHFRCOBSY_SHIFT)) + { + } +#endif + CMU->AUXHFRCOCTRL = (CMU->AUXHFRCOCTRL & ~(_CMU_AUXHFRCOCTRL_TUNING_MASK)) + | (val << _CMU_AUXHFRCOCTRL_TUNING_SHIFT); + break; + + default: + EFM_ASSERT(0); + break; + } +} + + +/**************************************************************************//** + * @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; + 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); + 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 EM_Library) */ +#endif /* __EM_CMU_H */ diff --git a/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emlib/em_emu.c b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emlib/em_emu.c new file mode 100644 index 000000000..254890066 --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emlib/em_emu.c @@ -0,0 +1,1805 @@ +/***************************************************************************//** + * @file em_emu.c + * @brief Energy Management Unit (EMU) Peripheral API + * @version 4.2.1 + ******************************************************************************* + * @section License + * (C) Copyright 2015 Silicon Labs, 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_assert.h" + +/***************************************************************************//** + * @addtogroup EM_Library + * @{ + ******************************************************************************/ + +/***************************************************************************//** + * @addtogroup EMU + * @brief Energy Management Unit (EMU) Peripheral API + * @{ + ******************************************************************************/ + +/* 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 */ +/* Fix for errata EMU_E107 - non-WIC interrupt masks. */ +#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)) + +#else +/* Zero Gecko and future families are not affected by errata EMU_E107 */ +#endif + +/* Fix for errata EMU_E108 - High Current Consumption on EM4 Entry. */ +#if defined( _EFM32_HAPPY_FAMILY ) +#define ERRATA_FIX_EMU_E108_EN +#endif +/** @endcond */ + + +#if defined( _EMU_DCDCCTRL_MASK ) +/* DCDCTODVDD output range min/max */ +#define PWRCFG_DCDCTODVDD_VMIN 1200 +#define PWRCFG_DCDCTODVDD_VMAX 3000 +typedef enum +{ + errataFixDcdcHsInit, + errataFixDcdcHsTrimSet, + errataFixDcdcHsLnWaitDone +} errataFixDcdcHs_TypeDef; +errataFixDcdcHs_TypeDef errataFixDcdcHsState = errataFixDcdcHsInit; +#endif + +/******************************************************************************* + ************************** LOCAL VARIABLES ******************************** + ******************************************************************************/ + +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ +/** + * CMU configured oscillator selection and oscillator enable status. When a + * user configures oscillators, this varaiable shall shadow the configuration. + * It is used by the EMU module in order to be able to restore the oscillator + * config after having been in certain energy modes (since HW may automatically + * alter config when going into an energy mode). It is the responsibility of + * the CMU module to keep it up-to-date (or a user if not using the CMU API + * for oscillator control). + */ +static uint32_t cmuStatus; +#if defined( _CMU_HFCLKSTATUS_RESETVALUE ) +static uint16_t cmuHfclkStatus; +#endif +#if defined( _EMU_DCDCCTRL_MASK ) +static uint16_t dcdcMaxCurrent_mA; +static uint16_t dcdcOutput_mVout; +#endif + +/** @endcond */ + + +/******************************************************************************* + ************************** LOCAL FUNCTIONS ******************************** + ******************************************************************************/ + +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ + +/***************************************************************************//** + * @brief + * Restore oscillators and core clock after having been in EM2 or EM3. + ******************************************************************************/ +static void emuRestore(void) +{ + uint32_t oscEnCmd; + uint32_t cmuLocked; + + /* Although we could use the CMU API for most of the below handling, we */ + /* would like this function to be as efficient as possible. */ + + /* 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( _CMU_HFCLKSTATUS_RESETVALUE ) + /* Restore oscillator used for clocking core */ + switch (cmuHfclkStatus & _CMU_HFCLKSTATUS_SELECTED_MASK) + { + case CMU_HFCLKSTATUS_SELECTED_LFRCO: + /* HFRCO could only be selected if the autostart HFXO feature is not + * enabled, otherwise the HFXO would be started and selected automatically. + * Note: this error hook helps catching erroneous oscillator configurations, + * when the AUTOSTARTSELEM0EM1 is set in CMU_HFXOCTRL. */ + if (!(CMU->HFXOCTRL & CMU_HFXOCTRL_AUTOSTARTSELEM0EM1)) + { + /* Wait for LFRCO to stabilize */ + while (!(CMU->STATUS & CMU_STATUS_LFRCORDY)) + ; + CMU->HFCLKSEL = CMU_HFCLKSEL_HF_LFRCO; + } + else + { + EFM_ASSERT(0); + } + break; + + case CMU_HFCLKSTATUS_SELECTED_LFXO: + /* Wait for LFXO to stabilize */ + while (!(CMU->STATUS & CMU_STATUS_LFXORDY)) + ; + CMU->HFCLKSEL = CMU_HFCLKSEL_HF_LFXO; + break; + + case CMU_HFCLKSTATUS_SELECTED_HFXO: + /* Wait for HFXO to stabilize */ + while (!(CMU->STATUS & CMU_STATUS_HFXORDY)) + ; + CMU->HFCLKSEL = CMU_HFCLKSEL_HF_HFXO; + break; + + default: /* CMU_HFCLKSTATUS_SELECTED_HFRCO */ + /* If core clock was HFRCO core clock, it is automatically restored to */ + /* state prior to entering energy mode. No need for further action. */ + break; + } +#else + switch (cmuStatus & (CMU_STATUS_HFRCOSEL + | CMU_STATUS_HFXOSEL + | CMU_STATUS_LFRCOSEL +#if defined( CMU_STATUS_USHFRCODIV2SEL ) + | CMU_STATUS_USHFRCODIV2SEL +#endif + | CMU_STATUS_LFXOSEL)) + { + case CMU_STATUS_LFRCOSEL: + /* Wait for LFRCO to stabilize */ + while (!(CMU->STATUS & CMU_STATUS_LFRCORDY)) + ; + CMU->CMD = CMU_CMD_HFCLKSEL_LFRCO; + break; + + case CMU_STATUS_LFXOSEL: + /* Wait for LFXO to stabilize */ + while (!(CMU->STATUS & CMU_STATUS_LFXORDY)) + ; + CMU->CMD = CMU_CMD_HFCLKSEL_LFXO; + break; + + case CMU_STATUS_HFXOSEL: + /* Wait for HFXO to stabilize */ + while (!(CMU->STATUS & CMU_STATUS_HFXORDY)) + ; + CMU->CMD = CMU_CMD_HFCLKSEL_HFXO; + break; + +#if defined( CMU_STATUS_USHFRCODIV2SEL ) + case CMU_STATUS_USHFRCODIV2SEL: + /* Wait for USHFRCO to stabilize */ + while (!(CMU->STATUS & CMU_STATUS_USHFRCORDY)) + ; + CMU->CMD = _CMU_CMD_HFCLKSEL_USHFRCODIV2; + break; +#endif + + default: /* CMU_STATUS_HFRCOSEL */ + /* If core clock was HFRCO core clock, it is automatically restored to */ + /* state prior to entering energy mode. No need for further action. */ + break; + } + + /* 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; + } +#endif + /* 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 + + +#if defined( _EMU_DCDCCTRL_MASK ) +/* LP prepare / LN restore P/NFET count */ +static void maxCurrentUpdate(void); +#define DCDC_LP_PFET_CNT 7 +#define DCDC_LP_NFET_CNT 15 +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; + maxCurrentUpdate(); + } + else + { + EMU->DCDCMISCCTRL = emuDcdcMiscCtrlReg; + maxCurrentUpdate(); + } +} + +void dcdcHsFixLnBlock(void) +{ +#define EMU_DCDCSTATUS (* (volatile uint32_t *)(EMU_BASE + 0x7C)) + if (errataFixDcdcHsState == errataFixDcdcHsTrimSet) + { + /* Wait for LNRUNNING */ + if ((EMU->DCDCCTRL & ~_EMU_DCDCCTRL_DCDCMODE_MASK) == EMU_DCDCCTRL_DCDCMODE_LOWNOISE) + { + while (!(EMU_DCDCSTATUS & (0x1 << 16))); + } + errataFixDcdcHsState = errataFixDcdcHsLnWaitDone; + } +} +#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. + * + * @param[in] restore + * @li true - restore oscillators and clocks, see function details. + * @li false - do not 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 + + /* Auto-update CMU status just in case before entering energy mode. */ + /* This variable is normally kept up-to-date by the CMU API. */ + cmuStatus = CMU->STATUS; +#if defined( _CMU_HFCLKSTATUS_RESETVALUE ) + cmuHfclkStatus = (uint16_t)(CMU->HFCLKSTATUS); +#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( _EMU_DCDCCTRL_MASK ) + dcdcFetCntSet(true); + dcdcHsFixLnBlock(); +#endif + + __WFI(); + +#if defined( _EMU_DCDCCTRL_MASK ) + 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 if specified */ + if (restore) + { + emuRestore(); + } + /* If not restoring, and original clock was not HFRCO, we have to */ + /* update CMSIS core clock variable since core clock has changed */ + /* to using HFRCO. */ +#if defined( _CMU_HFCLKSTATUS_RESETVALUE ) + else if ((cmuHfclkStatus & _CMU_HFCLKSTATUS_SELECTED_MASK) + != CMU_HFCLKSTATUS_SELECTED_HFRCO) +#else + else if (!(cmuStatus & CMU_STATUS_HFRCOSEL)) +#endif + { + 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. + * + * @param[in] restore + * @li true - restore oscillators and clocks, see function details. + * @li false - do not 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 + + /* Auto-update CMU status just in case before entering energy mode. */ + /* This variable is normally kept up-to-date by the CMU API. */ + cmuStatus = CMU->STATUS; +#if defined( _CMU_HFCLKSTATUS_RESETVALUE ) + cmuHfclkStatus = (uint16_t)(CMU->HFCLKSTATUS); +#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( _EMU_DCDCCTRL_MASK ) + dcdcFetCntSet(true); + dcdcHsFixLnBlock(); +#endif + + __WFI(); + +#if defined( _EMU_DCDCCTRL_MASK ) + 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 if specified */ + if (restore) + { + emuRestore(); + } + /* If not restoring, and original clock was not HFRCO, we have to */ + /* update CMSIS core clock variable since core clock has changed */ + /* to using HFRCO. */ +#if defined( _CMU_HFCLKSTATUS_RESETVALUE ) + else if ((cmuHfclkStatus & _CMU_HFCLKSTATUS_SELECTED_MASK) + != CMU_HFCLKSTATUS_SELECTED_HFRCO) +#else + else if (!(cmuStatus & CMU_STATUS_HFRCOSEL)) +#endif + { + SystemCoreClockUpdate(); + } +} + + +/***************************************************************************//** + * @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( 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( _EMU_DCDCCTRL_MASK ) + dcdcFetCntSet(true); + 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 +} + + +/***************************************************************************//** + * @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 reset can make the specified memory block(s) available for use + * after having been powered down. Function will be void for devices not + * supporting this feature. + ******************************************************************************/ +void EMU_MemPwrDown(uint32_t blocks) +{ +#if defined( _EMU_MEMCTRL_POWERDOWN_MASK ) + EFM_ASSERT(blocks <= (_EMU_MEMCTRL_POWERDOWN_MASK + >> _EMU_MEMCTRL_POWERDOWN_SHIFT)); + EMU->MEMCTRL = blocks; + +#elif defined( _EMU_MEMCTRL_RAMPOWERDOWN_MASK ) \ + && defined( _EMU_MEMCTRL_RAMHPOWERDOWN_MASK ) \ + && defined( _EMU_MEMCTRL_SEQRAMPOWERDOWN_MASK ) + EFM_ASSERT((blocks & (_EMU_MEMCTRL_RAMPOWERDOWN_MASK + | _EMU_MEMCTRL_RAMHPOWERDOWN_MASK + | _EMU_MEMCTRL_SEQRAMPOWERDOWN_MASK)) + == blocks); + EMU->MEMCTRL = blocks; + +#elif defined( _EMU_MEMCTRL_RAMPOWERDOWN_MASK ) + EFM_ASSERT((blocks & _EMU_MEMCTRL_RAMPOWERDOWN_MASK) == blocks); + EMU->MEMCTRL = blocks; + +#elif defined( _EMU_RAM0CTRL_RAMPOWERDOWN_MASK ) + EFM_ASSERT((blocks & _EMU_RAM0CTRL_RAMPOWERDOWN_MASK) == blocks); + EMU->RAM0CTRL = blocks; + +#else + (void)blocks; +#endif +} + + +/***************************************************************************//** + * @brief + * Update EMU module with CMU oscillator selection/enable status. + * + * @details + * When entering EM2 and EM3, the HW may change the core clock oscillator + * used, as well as disabling some oscillators. The user may optionally select + * to restore the oscillators after waking up from EM2 and EM3 through the + * SW API. + * + * However, in order to support this in a safe way, the EMU module must + * be kept up-to-date on the actual selected configuration. The CMU + * module must keep the EMU module up-to-date. + * + * This function is mainly intended for internal use by the CMU module, + * but if the applications changes oscillator configurations without + * using the CMU API, this function can be used to keep the EMU module + * up-to-date. + ******************************************************************************/ +void EMU_UpdateOscConfig(void) +{ + /* Fetch current configuration */ + cmuStatus = CMU->STATUS; +#if defined( _CMU_HFCLKSTATUS_RESETVALUE ) + cmuHfclkStatus = (uint16_t)(CMU->HFCLKSTATUS); +#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(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_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(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 +} +#endif + + +#if defined( BU_PRESENT ) +/***************************************************************************//** + * @brief + * Configure Backup Power Domain settings + * + * @param[in] bupdInit + * Backup power domain initialization structure + ******************************************************************************/ +void EMU_BUPDInit(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 + + +#if defined( _EMU_DCDCCTRL_MASK ) + +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ + +/***************************************************************************//** + * @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 ConstCalibrationLoad(void) +{ + 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; +} + + +/***************************************************************************//** + * @brief + * Set recommended and validated current optimization settings + * + ******************************************************************************/ +void ValidatedConfigSet(void) +{ +#define EMU_DCDCSMCTRL (* (volatile uint32_t *)(EMU_BASE + 0x44)) + + uint32_t dcdcTiming; + SYSTEM_PartFamily_TypeDef family; + SYSTEM_ChipRevision_TypeDef rev; + + /* Enable duty cycling of the bias */ + EMU->DCDCLPCTRL |= EMU_DCDCLPCTRL_LPVREFDUTYEN; + + /* Set low-noise RCO for EFM32 and EFR32 */ +#if defined( _EFR_DEVICE ) + /* 7MHz is recommended for all EFR32 parts with DCDC */ + EMU->DCDCLNFREQCTRL = (EMU->DCDCLNFREQCTRL & ~_EMU_DCDCLNFREQCTRL_RCOBAND_MASK) + | (EMU_DcdcLnRcoBand_7MHz << _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT); +#else + /* 3MHz is recommended for all EFM32 parts with DCDC */ + EMU->DCDCLNFREQCTRL = (EMU->DCDCLNFREQCTRL & ~_EMU_DCDCLNFREQCTRL_RCOBAND_MASK) + | (EMU_DcdcLnRcoBand_3MHz << _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT); +#endif + + EMU->DCDCTIMING &= ~_EMU_DCDCTIMING_DUTYSCALE_MASK; + + family = SYSTEM_GetFamily(); + SYSTEM_ChipRevisionGet(&rev); + if ((((family >= systemPartFamilyMighty1P) + && (family <= systemPartFamilyFlex1V)) + || (family == systemPartFamilyEfm32Pearl1B) + || (family == systemPartFamilyEfm32Jade1B)) + && ((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; + } +} + + +/***************************************************************************//** + * @brief + * Calculate and update EMU->DCDCMISCCTRL for maximum DCDC current based + * on the slice configuration and user set maximum. + ******************************************************************************/ +static void maxCurrentUpdate(void) +{ + uint32_t lncLimImSel; + uint32_t lpcLimImSel; + uint32_t pFetCnt; + + pFetCnt = (EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_PFETCNT_MASK) + >> _EMU_DCDCMISCCTRL_PFETCNT_SHIFT; + + /* Equation from Reference Manual section 11.5.20, in the register + field description for LNCLIMILIMSEL and LPCLIMILIMSEL. */ + lncLimImSel = (dcdcMaxCurrent_mA / (5 * (pFetCnt + 1))) - 1; + /* 80mA as recommended in Application Note AN0948 */ + lpcLimImSel = (80 / (5 * (pFetCnt + 1))) - 1; + + lncLimImSel <<= _EMU_DCDCMISCCTRL_LNCLIMILIMSEL_SHIFT; + lpcLimImSel <<= _EMU_DCDCMISCCTRL_LPCLIMILIMSEL_SHIFT; + EMU->DCDCMISCCTRL = (EMU->DCDCMISCCTRL & ~(_EMU_DCDCMISCCTRL_LNCLIMILIMSEL_MASK + | _EMU_DCDCMISCCTRL_LPCLIMILIMSEL_MASK)) + | (lncLimImSel | lpcLimImSel); +} + + +/***************************************************************************//** + * @brief + * Set static variable that holds the user set maximum current. Update + * DCDC configuration. + * + * @param[in] mAmaxCurrent + * Maximum allowed current drawn by the DCDC from VREGVDD in mA. + ******************************************************************************/ +static void maxCurrentSet(uint32_t mAmaxCurrent) +{ + dcdcMaxCurrent_mA = mAmaxCurrent; + maxCurrentUpdate(); +} + + +/***************************************************************************//** + * @brief + * Load EMU_DCDCLPCTRL_LPCMPHYSSEL depending on LP bias, LP feedback + * attenuation and DEVINFOREV. + * + * @param[in] attSet + * LP feedback attenuation. + * @param[in] lpCmpBias + * lpCmpBias selection + ******************************************************************************/ +static bool LpCmpHystCalibrationLoad(bool lpAttenuation, uint32_t lpCmpBias) +{ + uint8_t devinfoRev; + uint32_t lpcmpHystSel; + + /* Get calib data revision */ + devinfoRev = SYSTEM_GetDevinfoRev(); + + /* Load LPATT indexed calibration data */ + if (devinfoRev < 4) + { + 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; + } + } + /* devinfoRev >= 4 + Load LPCMPBIAS indexed calibration data */ + else + { + lpcmpHystSel = DEVINFO->DCDCLPCMPHYSSEL1; + switch (lpCmpBias) + { + case _EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS0: + lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS0_MASK) + >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS0_SHIFT; + break; + + case _EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS1: + lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS1_MASK) + >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS1_SHIFT; + break; + + case _EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS2: + lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS2_MASK) + >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS2_SHIFT; + break; + + case _EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS3: + lpcmpHystSel = (lpcmpHystSel & _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS3_MASK) + >> _DEVINFO_DCDCLPCMPHYSSEL1_LPCMPHYSSELLPCMPBIAS3_SHIFT; + break; + + default: + EFM_ASSERT(false); + /* Return when assertions are disabled */ + return false; + } + } + + /* Make sure the sel value is within the field range. */ + lpcmpHystSel <<= _EMU_DCDCLPCTRL_LPCMPHYSSEL_SHIFT; + if (lpcmpHystSel & ~_EMU_DCDCLPCTRL_LPCMPHYSSEL_MASK) + { + EFM_ASSERT(false); + /* Return when assertions are disabled */ + return false; + } + EMU->DCDCLPCTRL = (EMU->DCDCLPCTRL & ~_EMU_DCDCLPCTRL_LPCMPHYSSEL_MASK) | lpcmpHystSel; + + return true; +} + + +/** @endcond */ + +/***************************************************************************//** + * @brief + * Set DCDC regulator operating mode + * + * @param[in] dcdcMode + * DCDC mode + ******************************************************************************/ +void EMU_DCDCModeSet(EMU_DcdcMode_TypeDef dcdcMode) +{ + while(EMU->DCDCSYNC & EMU_DCDCSYNC_DCDCCTRLBUSY); + BUS_RegBitWrite(&EMU->DCDCCLIMCTRL, _EMU_DCDCCLIMCTRL_BYPLIMEN_SHIFT, dcdcMode == emuDcdcMode_Bypass ? 0 : 1); + EMU->DCDCCTRL = (EMU->DCDCCTRL & ~_EMU_DCDCCTRL_DCDCMODE_MASK) | dcdcMode; +} + + +/***************************************************************************//** + * @brief + * Configure DCDC regulator + * + * @note + * Use the function EMU_DCDCPowerDown() to if the power circuit is configured + * for NODCDC as decribed in Section 11.3.4.3 in the Reference Manual. + * + * @param[in] dcdcInit + * DCDC initialization structure + * + * @return + * True if initialization parameters are valid + ******************************************************************************/ +bool EMU_DCDCInit(EMU_DCDCInit_TypeDef *dcdcInit) +{ + uint32_t lpCmpBiasSel; + + /* Set external power configuration. This enables writing to the other + DCDC registers. */ + EMU->PWRCFG = dcdcInit->powerConfig; + + /* 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) != dcdcInit->powerConfig) + { + /* 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; + } + + /* Load DCDC calibration data from the DI page */ + ConstCalibrationLoad(); + + /* Check current parameters */ + EFM_ASSERT(dcdcInit->maxCurrent_mA <= 200); + EFM_ASSERT(dcdcInit->em01LoadCurrent_mA <= dcdcInit->maxCurrent_mA); + + /* DCDC low-noise supports max 200mA */ + if (dcdcInit->dcdcMode == emuDcdcMode_LowNoise) + { + EFM_ASSERT(dcdcInit->em01LoadCurrent_mA <= 200); + } + + /* EM2, 3 and 4 current above 100uA is not supported */ + EFM_ASSERT(dcdcInit->em234LoadCurrent_uA <= 100); + + /* Decode LP comparator bias for EM0/1 and EM2/3 */ + lpCmpBiasSel = EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS1; + if (dcdcInit->em234LoadCurrent_uA <= 10) + { + lpCmpBiasSel = EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS0; + } + + /* Set DCDC low-power mode comparator bias selection */ + EMU->DCDCMISCCTRL = (EMU->DCDCMISCCTRL & ~(_EMU_DCDCMISCCTRL_LPCMPBIAS_MASK + | _EMU_DCDCMISCCTRL_LNFORCECCM_MASK)) + | ((uint32_t)lpCmpBiasSel + | (uint32_t)dcdcInit->lnTransientMode); + + /* Set recommended and validated current optimization settings */ + ValidatedConfigSet(); + + /* Set the maximum current that the DCDC can draw from the power source */ + maxCurrentSet(dcdcInit->maxCurrent_mA); + + /* Optimize LN slice based on given load current estimate */ + EMU_DCDCOptimizeSlice(dcdcInit->em01LoadCurrent_mA); + + /* Set DCDC output voltage */ + dcdcOutput_mVout = dcdcInit->mVout; + if (!EMU_DCDCOutputVoltageSet(dcdcOutput_mVout, true, true)) + { + EFM_ASSERT(false); + /* Return when assertions are disabled */ + return false; + } + + /* Set EM0 DCDC operating mode. Output voltage set in EMU_DCDCOutputVoltageSet() + above takes effect if mode is changed from bypass here. */ + EMU_DCDCModeSet(dcdcInit->dcdcMode); + + /* Select analog peripheral power supply */ + BUS_RegBitWrite(&EMU->PWRCTRL, _EMU_PWRCTRL_ANASW_SHIFT, dcdcInit->anaPeripheralPower ? 1 : 0); + + 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 ) + + bool validOutVoltage; + uint8_t lnMode; + bool attSet; + uint32_t attMask; + uint32_t vrefLow = 0; + uint32_t vrefHigh = 0; + uint32_t vrefVal = 0; + uint32_t mVlow = 0; + uint32_t mVhigh = 0; + uint32_t vrefShift; + uint32_t lpcmpBias; + volatile uint32_t* ctrlReg; + + /* Check that the set voltage is within valid range. + Voltages are obtained from the datasheet. */ + validOutVoltage = false; + if ((EMU->PWRCFG & _EMU_PWRCFG_PWRCFG_MASK) == EMU_PWRCFG_PWRCFG_DCDCTODVDD) + { + validOutVoltage = ((mV >= PWRCFG_DCDCTODVDD_VMIN) + && (mV <= PWRCFG_DCDCTODVDD_VMAX)); + } + + if (!validOutVoltage) + { + EFM_ASSERT(false); + /* Return when assertions are disabled */ + return false; + } + + /* Populate both LP and LN registers, set control reg pointer and VREF shift. */ + for (lnMode = 0; lnMode <= 1; lnMode++) + { + if (((lnMode == 0) && !setLpVoltage) + || ((lnMode == 1) && !setLnVoltage)) + { + continue; + } + + ctrlReg = (lnMode ? &EMU->DCDCLNVCTRL : &EMU->DCDCLPVCTRL); + vrefShift = (lnMode ? _EMU_DCDCLNVCTRL_LNVREF_SHIFT + : _EMU_DCDCLPVCTRL_LPVREF_SHIFT); + + /* Set attenuation to use */ + attSet = (mV > 1800); + if (attSet) + { + mVlow = 1800; + mVhigh = 3000; + attMask = (lnMode ? EMU_DCDCLNVCTRL_LNATT : EMU_DCDCLPVCTRL_LPATT); + } + else + { + mVlow = 1200; + mVhigh = 1800; + attMask = 0; + } + + /* Get 2-point calib data from DEVINFO, calculate trimming and set voltege */ + if (lnMode) + { + /* Set low-noise DCDC output voltage tuning */ + if (attSet) + { + vrefLow = DEVINFO->DCDCLNVCTRL0; + vrefHigh = (vrefLow & _DEVINFO_DCDCLNVCTRL0_3V0LNATT1_MASK) + >> _DEVINFO_DCDCLNVCTRL0_3V0LNATT1_SHIFT; + vrefLow = (vrefLow & _DEVINFO_DCDCLNVCTRL0_1V8LNATT1_MASK) + >> _DEVINFO_DCDCLNVCTRL0_1V8LNATT1_SHIFT; + } + else + { + vrefLow = DEVINFO->DCDCLNVCTRL0; + vrefHigh = (vrefLow & _DEVINFO_DCDCLNVCTRL0_1V8LNATT0_MASK) + >> _DEVINFO_DCDCLNVCTRL0_1V8LNATT0_SHIFT; + vrefLow = (vrefLow & _DEVINFO_DCDCLNVCTRL0_1V2LNATT0_MASK) + >> _DEVINFO_DCDCLNVCTRL0_1V2LNATT0_SHIFT; + } + } + else + { + /* Set low-power DCDC output voltage tuning */ + + /* Get LPCMPBIAS and make sure masks are not overlayed */ + lpcmpBias = EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LPCMPBIAS_MASK; + EFM_ASSERT(!(_EMU_DCDCMISCCTRL_LPCMPBIAS_MASK & attMask)); + switch (attMask | lpcmpBias) + { + case EMU_DCDCLPVCTRL_LPATT | EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS0: + 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 EMU_DCDCLPVCTRL_LPATT | EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS1: + 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 EMU_DCDCLPVCTRL_LPATT | EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS2: + 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 EMU_DCDCLPVCTRL_LPATT | EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS3: + 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 EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS0: + 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 EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS1: + 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 EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS2: + 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 EMU_DCDCMISCCTRL_LPCMPBIAS_BIAS3: + 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; + } + + /* Load LP comparator hysteresis calibration */ + if(!(LpCmpHystCalibrationLoad(attSet, lpcmpBias >> _EMU_DCDCMISCCTRL_LPCMPBIAS_SHIFT))) + { + EFM_ASSERT(false); + /* Return when assertions are disabled */ + return false; + } + } /* Low-nise / low-power mode */ + + + /* Check for valid 2-point trim values */ + if ((vrefLow == 0xFF) && (vrefHigh == 0xFF)) + { + EFM_ASSERT(false); + /* Return when assertions are disabled */ + return false; + } + + /* Calculate and set voltage trim */ + vrefVal = ((mV - mVlow) * (vrefHigh - vrefLow)) / (mVhigh - mVlow); + vrefVal += vrefLow; + + /* Range check */ + if ((vrefVal > vrefHigh) || (vrefVal < vrefLow)) + { + EFM_ASSERT(false); + /* Return when assertions are disabled */ + return false; + } + + /* Update DCDCLNVCTRL/DCDCLPVCTRL */ + *ctrlReg = (vrefVal << vrefShift) | attMask; + } +#endif + return true; +} + + +/***************************************************************************//** + * @brief + * Optimize DCDC slice count based on the estimated average load current + * in EM0 + * + * @param[in] mAEm0LoadCurrent + * Estimated average EM0 load current in mA. + ******************************************************************************/ +void EMU_DCDCOptimizeSlice(uint32_t mAEm0LoadCurrent) +{ + 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 >= EMU_DcdcLnRcoBand_5MHz)) + { + if (mAEm0LoadCurrent < 20) + { + sliceCount = 4; + } + else if ((mAEm0LoadCurrent >= 20) && (mAEm0LoadCurrent < 40)) + { + sliceCount = 8; + } + else + { + sliceCount = 16; + } + } + else if ((!(EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK)) && (rcoBand <= EMU_DcdcLnRcoBand_4MHz)) + { + if (mAEm0LoadCurrent < 10) + { + sliceCount = 4; + } + else if ((mAEm0LoadCurrent >= 10) && (mAEm0LoadCurrent < 20)) + { + sliceCount = 8; + } + else + { + sliceCount = 16; + } + } + else if ((EMU->DCDCMISCCTRL & _EMU_DCDCMISCCTRL_LNFORCECCM_MASK) && (rcoBand <= EMU_DcdcLnRcoBand_4MHz)) + { + if (mAEm0LoadCurrent < 40) + { + sliceCount = 8; + } + else + { + sliceCount = 16; + } + } + else + { + /* This configuration is not recommended. EMU_DCDCInit() applies a recommended + configuration. */ + EFM_ASSERT(false); + } + + /* The selected silices 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 limit configuration as it depends on the slice configuration. */ + maxCurrentUpdate(); +} + +/***************************************************************************//** + * @brief + * Set DCDC Low-noise RCO band. + * + * @param[in] band + * RCO band to set. + ******************************************************************************/ +void EMU_DCDCLnRcoBandSet(EMU_DcdcLnRcoBand_TypeDef band) +{ + EMU->DCDCLNFREQCTRL = (EMU->DCDCLNFREQCTRL & ~_EMU_DCDCLNFREQCTRL_RCOBAND_MASK) + | (band << _EMU_DCDCLNFREQCTRL_RCOBAND_SHIFT); +} + +/***************************************************************************//** + * @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) +{ + /* Set power configuration to hard bypass */ + EMU->PWRCFG = 0xF; + if ((EMU->PWRCFG & _EMU_PWRCFG_PWRCFG_MASK) != 0xF) + { + EFM_ASSERT(false); + /* Return when assertions are disabled */ + return false; + } + + /* Set DCDC to OFF and disable LP in EM2/3/4 */ + EMU->DCDCCTRL = EMU_DCDCCTRL_DCDCMODE_OFF; + return true; +} +#endif + + +#if defined( EMU_STATUS_VMONRDY ) +/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */ +__STATIC_INLINE uint32_t vmonMilliVoltToCoarseThreshold(int mV) +{ + return (mV - 1200) / 200; +} + +__STATIC_INLINE uint32_t vmonMilliVoltToFineThreshold(int mV, uint32_t coarseThreshold) +{ + return (mV - 1200 - (coarseThreshold * 200)) / 20; +} +/** @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. + * + * @param[in] vmonInit + * VMON initialization struct + ******************************************************************************/ +void EMU_VmonInit(EMU_VmonInit_TypeDef *vmonInit) +{ + uint32_t thresholdCoarse, thresholdFine; + EFM_ASSERT((vmonInit->threshold >= 1200) && (vmonInit->threshold <= 3980)); + + thresholdCoarse = vmonMilliVoltToCoarseThreshold(vmonInit->threshold); + thresholdFine = vmonMilliVoltToFineThreshold(vmonInit->threshold, thresholdCoarse); + + 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. + * + * @param[in] vmonInit + * VMON Hysteresis initialization struct + ******************************************************************************/ +void EMU_VmonHystInit(EMU_VmonHystInit_TypeDef *vmonInit) +{ + uint32_t riseThresholdCoarse, riseThresholdFine, fallThresholdCoarse, fallThresholdFine; + /* VMON supports voltages between 1200 mV and 3980 mV (inclusive) in 20 mV increments */ + EFM_ASSERT((vmonInit->riseThreshold >= 1200) && (vmonInit->riseThreshold < 4000)); + EFM_ASSERT((vmonInit->fallThreshold >= 1200) && (vmonInit->fallThreshold < 4000)); + /* Fall threshold has to be lower than rise threshold */ + EFM_ASSERT(vmonInit->fallThreshold <= vmonInit->riseThreshold); + + riseThresholdCoarse = vmonMilliVoltToCoarseThreshold(vmonInit->riseThreshold); + riseThresholdFine = vmonMilliVoltToFineThreshold(vmonInit->riseThreshold, riseThresholdCoarse); + fallThresholdCoarse = vmonMilliVoltToCoarseThreshold(vmonInit->fallThreshold); + fallThresholdFine = vmonMilliVoltToFineThreshold(vmonInit->fallThreshold, fallThresholdCoarse); + + switch(vmonInit->channel) + { + case emuVmonChannel_AVDD: + EMU->VMONAVDDCTRL = (riseThresholdCoarse << _EMU_VMONAVDDCTRL_RISETHRESCOARSE_SHIFT) + | (riseThresholdFine << _EMU_VMONAVDDCTRL_RISETHRESFINE_SHIFT) + | (fallThresholdCoarse << _EMU_VMONAVDDCTRL_FALLTHRESCOARSE_SHIFT) + | (fallThresholdFine << _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 */ + +/** @} (end addtogroup EMU) */ +/** @} (end addtogroup EM_Library) */ +#endif /* __EM_EMU_H */ diff --git a/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emlib/em_gpio.c b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emlib/em_gpio.c new file mode 100644 index 000000000..46db33557 --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emlib/em_gpio.c @@ -0,0 +1,320 @@ +/***************************************************************************//** + * @file em_gpio.c + * @brief General Purpose IO (GPIO) peripheral API + * devices. + * @version 4.2.1 + ******************************************************************************* + * @section License + * (C) Copyright 2015 Silicon Labs, 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 EM_Library + * @{ + ******************************************************************************/ + +/***************************************************************************//** + * @addtogroup GPIO + * @brief General Purpose Input/Output (GPIO) API + * @{ + ******************************************************************************/ + +/******************************************************************************* + ******************************* 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 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 pin is cleared by this + * function. + * + * @note + * A certain pin number can only be associated with one port. Ie, if GPIO + * interrupt 1 is assigned to port A/pin 1, then it is not possibly to use + * pin 1 from any other ports for interrupts. Please refer to the reference + * manual. + * + * @param[in] port + * The port to associate with @p pin. + * + * @param[in] pin + * The GPIO interrupt number (= port pin). + * + * @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_IntConfig(GPIO_Port_TypeDef port, + unsigned int pin, + bool risingEdge, + bool fallingEdge, + bool enable) +{ + uint32_t tmp; + + EFM_ASSERT(GPIO_PORT_PIN_VALID(port, pin)); + + /* There are two registers controlling the interrupt configuration: + * The EXTIPSELL register controls pins 0-7 and EXTIPSELH controls + * pins 8-15. */ + if (pin < 8) + { + BUS_RegMaskedWrite(&GPIO->EXTIPSELL, + 0xF << (4 * pin), + port << (4 * pin)); + } + else + { + tmp = pin - 8; + BUS_RegMaskedWrite(&GPIO->EXTIPSELH, + 0xF << (4 * tmp), + port << (4 * tmp)); + } + + /* Enable/disable rising edge */ + BUS_RegBitWrite(&(GPIO->EXTIRISE), pin, risingEdge); + + /* Enable/disable falling edge */ + BUS_RegBitWrite(&(GPIO->EXTIFALL), pin, fallingEdge); + + /* Clear any pending interrupt */ + GPIO->IFC = 1 << pin; + + /* Finally enable/disable interrupt */ + BUS_RegBitWrite(&(GPIO->IEN), pin, 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) + { + BUS_RegMaskedWrite(&GPIO->P[port].MODEL, + 0xF << (pin * 4), + mode << (pin * 4)); + } + else + { + BUS_RegMaskedWrite(&GPIO->P[port].MODEH, + 0xF << ((pin - 8) * 4), + mode << ((pin - 8) * 4)); + } + + if (mode == gpioModeDisabled) + { + if (out) + { + GPIO_PinOutSet(port, pin); + } + else + { + GPIO_PinOutClear(port, pin); + } + } +} + +#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 EM_Library) */ + +#endif /* defined(GPIO_COUNT) && (GPIO_COUNT > 0) */ diff --git a/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emlib/em_int.c b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emlib/em_int.c new file mode 100644 index 000000000..cab8c3416 --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emlib/em_int.c @@ -0,0 +1,73 @@ +/**************************************************************************//** + * @file em_int.c + * @brief Interrupt enable/disable unit API + * @version 4.2.1 + ****************************************************************************** + * @section License + * (C) Copyright 2015 Silicon Labs, 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_int.h" + +/***************************************************************************//** + * @addtogroup EM_Library + * @{ + ******************************************************************************/ + +/***************************************************************************//** + * @addtogroup INT + * @brief Safe nesting of interrupt disable/enable API + * @{ + * @details + * This module contains functions to safely disable and enable interrupts + * at CPU level. INT_Disable() disables interrupts globally and increments a lock + * level counter (counting semaphore). INT_Enable() decrements the lock level + * counter and enable interrupts if the counter reaches zero. + * + * These functions would normally be used to secure critical regions, and + * to make sure that a critical section that calls into another critical + * section does not unintentionally terminate the callee critical section. + * + * These functions should also be used inside interrupt handlers: + * @verbatim + * void SysTick_Handler(void) + * { + * INT_Disable(); + * . + * . + * . + * INT_Enable(); + * } + * @endverbatim + ******************************************************************************/ + +/** Interrupt lock level counter. Set to zero initially as we normally enter + * main with interrupts enabled */ +uint32_t INT_LockCnt = 0; + +/** @} (end addtogroup INT) */ +/** @} (end addtogroup EM_Library) */ diff --git a/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emlib/em_rtcc.c b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emlib/em_rtcc.c new file mode 100644 index 000000000..c2b0fb57f --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emlib/em_rtcc.c @@ -0,0 +1,180 @@ +/***************************************************************************//** + * @file + * @brief Real Time Counter with Calendar (RTCC) Peripheral API + * @version 4.2.1 + ******************************************************************************* + * @section License + * (C) Copyright 2015 Silicon Labs, 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_rtcc.h" +#if defined( RTCC_COUNT ) && ( RTCC_COUNT == 1 ) +#include "em_bus.h" + +/***************************************************************************//** + * @addtogroup EM_Library + * @{ + ******************************************************************************/ + +/***************************************************************************//** + * @addtogroup RTCC + * @brief Real Time Counter (RTCC) Peripheral API + * @{ + ******************************************************************************/ + +/******************************************************************************* + ******************************* DEFINES *********************************** + ******************************************************************************/ + +/******************************************************************************* + ************************** LOCAL FUNCTIONS ******************************** + ******************************************************************************/ + +/******************************************************************************* + ************************** GLOBAL FUNCTIONS ******************************* + ******************************************************************************/ + +/***************************************************************************//** + * @brief + * Configure the selected capture/compare channel of the RTCC. + * + * @details + * Use this function to configure a RTCC channel. + * Select capture/compare mode, match output action, overflow output action + * and PRS input configuration. + * Refer to the configuration structure @ref RTCC_CCChConf_TypeDef for more + * details. + * + * @param[in] ch + * Channel selector. + * + * @param[in] confPtr + * Pointer to configuration structure. + ******************************************************************************/ +void RTCC_ChannelInit( int ch, RTCC_CCChConf_TypeDef const *confPtr ) +{ + EFM_ASSERT( RTCC_CH_VALID( ch ) ); + EFM_ASSERT( (uint32_t)confPtr->compMask + < ( _RTCC_CC_CTRL_COMPMASK_MASK >> _RTCC_CC_CTRL_COMPMASK_SHIFT ) + + 1 ); + + /** Configure the selected capture/compare channel. */ + RTCC->CC[ch].CTRL = ( (uint32_t)confPtr->chMode << _RTCC_CC_CTRL_MODE_SHIFT ) + | ( (uint32_t)confPtr->compMatchOutAction << _RTCC_CC_CTRL_CMOA_SHIFT ) + | ( (uint32_t)confPtr->prsSel << _RTCC_CC_CTRL_PRSSEL_SHIFT ) + | ( (uint32_t)confPtr->inputEdgeSel << _RTCC_CC_CTRL_ICEDGE_SHIFT ) + | ( (uint32_t)confPtr->compBase << _RTCC_CC_CTRL_COMPBASE_SHIFT ) + | ( (uint32_t)confPtr->compMask << _RTCC_CC_CTRL_COMPMASK_SHIFT ) + | ( (uint32_t)confPtr->dayCompMode << _RTCC_CC_CTRL_DAYCC_SHIFT ); +} + +/***************************************************************************//** + * @brief + * Enable/disable RTCC. + * + * @param[in] enable + * True to enable RTCC, false to disable. + ******************************************************************************/ +void RTCC_Enable( bool enable ) +{ + /* Bitbanding the enable bit in the CTRL register (atomic). */ + BUS_RegBitWrite((&RTCC->CTRL), _RTCC_CTRL_ENABLE_SHIFT, enable); +} + +/***************************************************************************//** + * @brief + * Initialize RTCC. + * + * @details + * Note that the compare values must be set separately with RTCC_CompareSet(). + * That should probably be done prior to the use of this function if + * configuring the RTCC to start when initialization is completed. + * + * @param[in] init + * Pointer to RTCC initialization structure. + ******************************************************************************/ +void RTCC_Init( const RTCC_Init_TypeDef *init ) +{ + RTCC->CTRL = ( (uint32_t)init->enable << _RTCC_CTRL_ENABLE_SHIFT ) + | ( (uint32_t)init->debugRun << _RTCC_CTRL_DEBUGRUN_SHIFT ) + | ( (uint32_t)init->precntWrapOnCCV0 << _RTCC_CTRL_PRECCV0TOP_SHIFT ) + | ( (uint32_t)init->cntWrapOnCCV1 << _RTCC_CTRL_CCV1TOP_SHIFT ) + | ( (uint32_t)init->presc << _RTCC_CTRL_CNTPRESC_SHIFT ) + | ( (uint32_t)init->prescMode << _RTCC_CTRL_CNTTICK_SHIFT ) +#if defined(_RTCC_CTRL_BUMODETSEN_MASK) + | ( (uint32_t)init->enaBackupModeSet << _RTCC_CTRL_BUMODETSEN_SHIFT ) +#endif + | ( (uint32_t)init->enaOSCFailDetect << _RTCC_CTRL_OSCFDETEN_SHIFT ) + | ( (uint32_t)init->cntMode << _RTCC_CTRL_CNTMODE_SHIFT ) + | ( (uint32_t)init->disLeapYearCorr << _RTCC_CTRL_LYEARCORRDIS_SHIFT ); +} + +/***************************************************************************//** + * @brief + * Restore RTCC to its reset state. + ******************************************************************************/ +void RTCC_Reset( void ) +{ + int i; + + /* Restore all RTCC registers to their default values. */ + RTCC_Unlock(); + RTCC->CTRL = _RTCC_CTRL_RESETVALUE; + RTCC->PRECNT = _RTCC_PRECNT_RESETVALUE; + RTCC->CNT = _RTCC_CNT_RESETVALUE; + RTCC->TIME = _RTCC_TIME_RESETVALUE; + RTCC->DATE = _RTCC_DATE_RESETVALUE; + RTCC->IEN = _RTCC_IEN_RESETVALUE; + RTCC->IFC = _RTCC_IFC_MASK; + RTCC_StatusClear(); + RTCC->EM4WUEN = _RTCC_EM4WUEN_RESETVALUE; + + for (i = 0; i < 3; i++) + { + RTCC->CC[i].CTRL = _RTCC_CC_CTRL_RESETVALUE; + RTCC->CC[i].CCV = _RTCC_CC_CCV_RESETVALUE; + RTCC->CC[i].TIME = _RTCC_CC_TIME_RESETVALUE; + RTCC->CC[i].DATE = _RTCC_CC_DATE_RESETVALUE; + } +} + +/***************************************************************************//** + * @brief + * Clear STATUS register. + ******************************************************************************/ +void RTCC_StatusClear( void ) +{ + while ( RTCC->SYNCBUSY & RTCC_SYNCBUSY_CMD ) + { + // Wait for syncronization. + } + RTCC->CMD = RTCC_CMD_CLRSTATUS; +} + +/** @} (end addtogroup RTCC) */ +/** @} (end addtogroup EM_Library) */ + +#endif /* defined( RTCC_COUNT ) && ( RTCC_COUNT == 1 ) */ diff --git a/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emlib/em_system.c b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emlib/em_system.c new file mode 100644 index 000000000..98e8a0ab6 --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/SilLabs_Source/emlib/em_system.c @@ -0,0 +1,121 @@ +/***************************************************************************//** + * @file em_system.c + * @brief System Peripheral API + * @version 4.2.1 + ******************************************************************************* + * @section License + * (C) Copyright 2015 Silicon Labs, 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" + +/***************************************************************************//** + * @addtogroup EM_Library + * @{ + ******************************************************************************/ + +/***************************************************************************//** + * @addtogroup SYSTEM + * @brief System Peripheral API + * @{ + ******************************************************************************/ + +/******************************************************************************* + ************************** 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; +} + + +#if defined(CALIBRATE) +/***************************************************************************//** + * @brief + * Get factory calibration value for a given peripheral register. + * + * @param[in] regAddress + * Address of register to get a calibration value for. + * + * @return + * Calibration value for the requested register. + ******************************************************************************/ +uint32_t SYSTEM_GetCalibrationValue(volatile uint32_t *regAddress) +{ + int regCount; + CALIBRATE_TypeDef *p; + + regCount = 1; + p = CALIBRATE; + + for (;; ) + { + if ((regCount > CALIBRATE_MAX_REGISTERS) || + (p->VALUE == 0xFFFFFFFF)) + { + EFM_ASSERT(false); + return 0; /* End of device calibration table reached. */ + } + + if (p->ADDRESS == (uint32_t)regAddress) + { + return p->VALUE; /* Calibration value found ! */ + } + + p++; + regCount++; + } +} +#endif /* defined (CALIBRATE) */ + +/** @} (end addtogroup SYSTEM) */ +/** @} (end addtogroup EM_Library) */ diff --git a/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/main.c b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/main.c new file mode 100644 index 000000000..de94bcb9f --- /dev/null +++ b/FreeRTOS/Demo/CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio/main.c @@ -0,0 +1,255 @@ +/* + FreeRTOS V9.0.0rc1 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/****************************************************************************** + * This project provides two demo applications. A simple blinky style project + * that demonstrates low power tickless functionality, and a more comprehensive + * test and demo application. The configCREATE_LOW_POWER_DEMO setting, which is + * defined in FreeRTOSConfig.h, is used to select between the two, and to select + * the clock used when demonstrating tickless functionality. + * + * The simply blinky low power demo is implemented and described in + * main_low_power.c. The more comprehensive test and demo application is + * implemented and described in main_full.c. + * + * This file implements the code that is not demo specific, including the + * hardware setup and standard FreeRTOS hook functions. + * + * ENSURE TO READ THE DOCUMENTATION PAGE FOR THIS PORT AND DEMO APPLICATION ON + * THE http://www.FreeRTOS.org WEB SITE FOR FULL INFORMATION ON USING THIS DEMO + * APPLICATION, AND ITS ASSOCIATE FreeRTOS ARCHITECTURE PORT! + * + */ + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* SiLabs includes. */ +#include "em_emu.h" +#include "bsp.h" +#include "bsp_trace.h" +#include "sleep.h" + +/*-----------------------------------------------------------*/ + +/* + * Configure the hardware as necessary to run this demo. + */ +static void prvSetupHardware( void ); + +/* + * main_low_power() is used when configCREATE_LOW_POWER_DEMO is set to 1. + * main_full() is used when configCREATE_LOW_POWER_DEMO is set to 0. + */ +#if( configCREATE_LOW_POWER_DEMO != 0 ) + extern void main_low_power( void ); +#else + extern void main_full( void ); +#endif /* #if configCREATE_LOW_POWER_DEMO == 1 */ + +/* Prototypes for the standard FreeRTOS callback/hook functions implemented +within this file. */ +void vApplicationMallocFailedHook( void ); +void vApplicationIdleHook( void ); +void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ); +void vApplicationTickHook( void ); + +/*-----------------------------------------------------------*/ + +int main( void ) +{ + /* Configure the hardware ready to run the demo. */ + prvSetupHardware(); + + /* The mainCREATE_LOW_POWER_DEMO setting is described at the top + of this file. */ + #if( configCREATE_LOW_POWER_DEMO != 0 ) + { + main_low_power(); + } + #else + { + main_full(); + } + #endif + + /* Should not get here. */ + return 0; +} +/*-----------------------------------------------------------*/ + +static void prvSetupHardware( void ) +{ +EMU_DCDCInit_TypeDef xDCDInit = EMU_DCDCINIT_STK_DEFAULT; +CMU_HFXOInit_TypeDef xHFXOInit = CMU_HFXOINIT_STK_DEFAULT; + + /* Chip errata */ + CHIP_Init(); + + /* Init DCDC regulator and HFXO with kit specific parameters */ + EMU_DCDCInit( &xDCDInit ); + CMU_HFXOInit( &xHFXOInit ); + + /* Switch HFCLK to HFXO and disable HFRCO */ + CMU_ClockSelectSet( cmuClock_HF, cmuSelect_HFXO ); + CMU_OscillatorEnable( cmuOsc_HFRCO, false, false ); + + /* Initialize LED driver. */ + BSP_LedsInit(); + BSP_LedSet( 0 ); + BSP_LedClear( 1 ); +} +/*-----------------------------------------------------------*/ + +void vApplicationMallocFailedHook( void ) +{ + /* Called if a call to pvPortMalloc() fails because there is insufficient + free memory available in the FreeRTOS heap. pvPortMalloc() is called + internally by FreeRTOS API functions that create tasks, queues, software + timers, and semaphores. The size of the FreeRTOS heap is set by the + configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h. */ + + /* Force an assert. */ + configASSERT( ( volatile void * ) NULL ); +} +/*-----------------------------------------------------------*/ + +void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName ) +{ + ( void ) pcTaskName; + ( void ) pxTask; + + /* Run time stack overflow checking is performed if + configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook + function is called if a stack overflow is detected. */ + + /* Force an assert. */ + configASSERT( ( volatile void * ) NULL ); +} +/*-----------------------------------------------------------*/ + +void vApplicationIdleHook( void ) +{ +volatile size_t xFreeHeapSpace; + + /* This is just a trivial example of an idle hook. It is called on each + cycle of the idle task. It must *NOT* attempt to block. In this case the + idle task just queries the amount of FreeRTOS heap that remains. See the + memory management section on the http://www.FreeRTOS.org web site for memory + management options. If there is a lot of heap memory free then the + configTOTAL_HEAP_SIZE value in FreeRTOSConfig.h can be reduced to free up + RAM. */ + xFreeHeapSpace = xPortGetFreeHeapSize(); + + /* Remove compiler warning about xFreeHeapSpace being set but never used. */ + ( void ) xFreeHeapSpace; +} +/*-----------------------------------------------------------*/ + +void vApplicationTickHook( void ) +{ + /* The full demo includes tests that run from the tick hook. */ + #if( configCREATE_LOW_POWER_DEMO == 0 ) + { + extern void vFullDemoTickHook( void ); + + /* Some of the tests and demo tasks executed by the full demo include + interaction from an interrupt - for which the tick interrupt is used + via the tick hook function. */ + vFullDemoTickHook(); + } + #endif +} +/*-----------------------------------------------------------*/ + +void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint16_t *pusIdleTaskStackSize ) +{ + /* configUSE_STATIC_ALLOCATION is set to 1, so the application has the + opportunity to supply the buffers that will be used by the Idle task as its + stack and to hold its TCB. If these are set to NULL then the buffers will + be allocated dynamically, just as if xTaskCreate() had been called. */ + *ppxIdleTaskTCBBuffer = NULL; + *ppxIdleTaskStackBuffer = NULL; + *pusIdleTaskStackSize = configMINIMAL_STACK_SIZE; /* In words. NOT in bytes! */ +} +/*-----------------------------------------------------------*/ + +void vApplicationGetTimerTaskMemory( StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint16_t *pusTimerTaskStackSize ) +{ + /* configUSE_STATIC_ALLOCATION is set to 1, so the application has the + opportunity to supply the buffers that will be used by the Timer/RTOS daemon + task as its stack and to hold its TCB. If these are set to NULL then the + buffers will be allocated dynamically, just as if xTaskCreate() had been + called. */ + *ppxTimerTaskTCBBuffer = NULL; + *ppxTimerTaskStackBuffer = NULL; + *pusTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; /* In words. NOT in bytes! */ +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Source/include/FreeRTOS.h b/FreeRTOS/Source/include/FreeRTOS.h index dfb7e024a..3ea860df1 100644 --- a/FreeRTOS/Source/include/FreeRTOS.h +++ b/FreeRTOS/Source/include/FreeRTOS.h @@ -923,7 +923,7 @@ typedef struct xSTATIC_TCB void *pxDummy14; #endif #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 ) - void pvDummy15[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; + void *pvDummy15[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ]; #endif #if ( configGENERATE_RUN_TIME_STATS == 1 ) uint32_t ulDummy16; diff --git a/FreeRTOS/Source/include/projdefs.h b/FreeRTOS/Source/include/projdefs.h index bfb0fd88c..2cdfea54d 100644 --- a/FreeRTOS/Source/include/projdefs.h +++ b/FreeRTOS/Source/include/projdefs.h @@ -76,8 +76,12 @@ */ typedef void (*TaskFunction_t)( void * ); -/* Converts a time in milliseconds to a time in ticks. */ -#define pdMS_TO_TICKS( xTimeInMs ) ( ( TickType_t ) ( ( ( TickType_t ) ( xTimeInMs ) * ( TickType_t ) configTICK_RATE_HZ ) / ( TickType_t ) 1000 ) ) +/* Converts a time in milliseconds to a time in ticks. This macro can be +overridden by a macro of the same name defined in FreeRTOSConfig.h in case the +definition here is not suitable for your application. */ +#ifndef pdMS_TO_TICKS + #define pdMS_TO_TICKS( xTimeInMs ) ( ( TickType_t ) ( ( ( TickType_t ) ( xTimeInMs ) * ( TickType_t ) configTICK_RATE_HZ ) / ( TickType_t ) 1000 ) ) +#endif #define pdFALSE ( ( BaseType_t ) 0 ) #define pdTRUE ( ( BaseType_t ) 1 ) diff --git a/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c b/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c index 3f6d9fd4f..9fe686e7d 100644 --- a/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c +++ b/FreeRTOS/Source/portable/RVDS/ARM_CM4F/port.c @@ -509,7 +509,6 @@ __asm void xPortPendSVHandler( void ) #endif bx r14 - nop } /*-----------------------------------------------------------*/ diff --git a/Upgrading-to-FreeRTOS-9.url b/Upgrading-to-FreeRTOS-9.url new file mode 100644 index 000000000..716c8e1b6 --- /dev/null +++ b/Upgrading-to-FreeRTOS-9.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,2 +[InternetShortcut] +URL=http://www.freertos.org/FreeRTOS-V9.html +IDList=