diff --git a/examples/ArmTimerCallbacks/ArmTimerCallbacks.uvoptx b/examples/ArmTimerCallbacks - C++/ArmTimerCallbacks.uvoptx
similarity index 100%
rename from examples/ArmTimerCallbacks/ArmTimerCallbacks.uvoptx
rename to examples/ArmTimerCallbacks - C++/ArmTimerCallbacks.uvoptx
diff --git a/examples/ArmTimerCallbacks/ArmTimerCallbacks.uvprojx b/examples/ArmTimerCallbacks - C++/ArmTimerCallbacks.uvprojx
similarity index 98%
rename from examples/ArmTimerCallbacks/ArmTimerCallbacks.uvprojx
rename to examples/ArmTimerCallbacks - C++/ArmTimerCallbacks.uvprojx
index 1d18e62d..ed494f20 100644
--- a/examples/ArmTimerCallbacks/ArmTimerCallbacks.uvprojx
+++ b/examples/ArmTimerCallbacks - C++/ArmTimerCallbacks.uvprojx
@@ -10,8 +10,8 @@
Target 1
0x4
ARM-ADS
- 5060528::V5.06 update 5 (build 528)::ARMCC
- 0
+ 6070000::V6.7::.\ARMCLANG
+ 1
STM32F401RETx
@@ -311,7 +311,7 @@
1
- 4
+ 7
0
0
1
@@ -320,7 +320,7 @@
1
0
0
- 2
+ 3
0
0
1
@@ -336,7 +336,7 @@
- ..\..\src;..\ArmTimerCallbacks
+ ..\..\src;..\ArmTimerCallbacks - C++
diff --git a/examples/ArmTimerCallbacks/RTE/Device/STM32F401RETx/startup_stm32f401xe.s b/examples/ArmTimerCallbacks - C++/RTE/Device/STM32F401RETx/startup_stm32f401xe.s
similarity index 100%
rename from examples/ArmTimerCallbacks/RTE/Device/STM32F401RETx/startup_stm32f401xe.s
rename to examples/ArmTimerCallbacks - C++/RTE/Device/STM32F401RETx/startup_stm32f401xe.s
diff --git a/examples/ArmTimerCallbacks/RTE/Device/STM32F401RETx/system_stm32f4xx.c b/examples/ArmTimerCallbacks - C++/RTE/Device/STM32F401RETx/system_stm32f4xx.c
similarity index 100%
rename from examples/ArmTimerCallbacks/RTE/Device/STM32F401RETx/system_stm32f4xx.c
rename to examples/ArmTimerCallbacks - C++/RTE/Device/STM32F401RETx/system_stm32f4xx.c
diff --git a/examples/ArmTimerCallbacks/etl_profile.h b/examples/ArmTimerCallbacks - C++/etl_profile.h
similarity index 100%
rename from examples/ArmTimerCallbacks/etl_profile.h
rename to examples/ArmTimerCallbacks - C++/etl_profile.h
diff --git a/examples/ArmTimerCallbacks/main.cpp b/examples/ArmTimerCallbacks - C++/main.cpp
similarity index 100%
rename from examples/ArmTimerCallbacks/main.cpp
rename to examples/ArmTimerCallbacks - C++/main.cpp
diff --git a/examples/ArmTimerCallbacks - C/ArmTimerCallbacks.uvoptx b/examples/ArmTimerCallbacks - C/ArmTimerCallbacks.uvoptx
new file mode 100644
index 00000000..a96071c6
--- /dev/null
+++ b/examples/ArmTimerCallbacks - C/ArmTimerCallbacks.uvoptx
@@ -0,0 +1,322 @@
+
+
+
+ 1.0
+
+ ### uVision Project, (C) Keil Software
+
+
+ *.c
+ *.s*; *.src; *.a*
+ *.obj; *.o
+ *.lib
+ *.txt; *.h; *.inc
+ *.plm
+ *.cpp
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ Target 1
+ 0x4
+ ARM-ADS
+
+ 12000000
+
+ 1
+ 1
+ 0
+ 1
+ 0
+
+
+ 1
+ 65535
+ 0
+ 0
+ 0
+
+
+ 79
+ 66
+ 8
+ .\Listings\
+
+
+ 1
+ 1
+ 1
+ 0
+ 1
+ 1
+ 0
+ 1
+ 0
+ 0
+ 0
+ 0
+
+
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0
+ 0
+
+
+ 1
+ 0
+ 1
+
+ 18
+
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0
+ 1
+ 1
+ 1
+ 1
+ 0
+ 0
+ 1
+ 5
+
+
+
+
+
+
+
+
+
+
+ STLink\ST-LINKIII-KEIL_SWO.dll
+
+
+
+ 0
+ ARMRTXEVENTFLAGS
+ -L70 -Z18 -C0 -M0 -T1
+
+
+ 0
+ DLGTARM
+ (1010=-1,-1,-1,-1,0)(1007=-1,-1,-1,-1,0)(1008=-1,-1,-1,-1,0)(1009=-1,-1,-1,-1,0)(1012=-1,-1,-1,-1,0)
+
+
+ 0
+ ARMDBGFLAGS
+
+
+
+ 0
+ DLGUARM
+ (105=-1,-1,-1,-1,0)
+
+
+ 0
+ ST-LINKIII-KEIL_SWO
+ -U066CFF485550707267024134 -O207 -SF4000 -C0 -A0 -I0 -HNlocalhost -HP7184 -P2 -N00("ARM CoreSight SW-DP") -D00(2BA01477) -L00(0) -TO18 -TC10000000 -TP21 -TDS8007 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -FO7 -FD20000000 -FC1000 -FN1 -FF0STM32F4xx_512.FLM -FS08000000 -FL080000 -FP0($$Device:STM32F401RETx$CMSIS\Flash\STM32F4xx_512.FLM)
+
+
+ 0
+ UL2CM3
+ UL2CM3(-S0 -C0 -P0 -FD20000000 -FC1000 -FN1 -FF0STM32F4xx_512 -FS08000000 -FL080000 -FP0($$Device:STM32F401RETx$CMSIS\Flash\STM32F4xx_512.FLM))
+
+
+
+
+
+ 0
+ 1
+ returnCode
+
+
+ 1
+ 1
+ short_toggle
+
+
+ 2
+ 1
+ timer
+
+
+
+ 0
+
+
+ 0
+ 1
+ 1
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+
+
+
+ 0
+ 0
+ 0
+
+
+
+
+
+
+
+
+
+ 1
+ 0
+ 2
+ 10000000
+
+
+
+
+
+ Source Group 1
+ 1
+ 0
+ 0
+ 0
+
+ 1
+ 1
+ 1
+ 0
+ 0
+ 0
+ .\main.c
+ main.c
+ 0
+ 0
+
+
+ 1
+ 2
+ 1
+ 0
+ 0
+ 0
+ ..\..\src\c\ecl_timer.c
+ ecl_timer.c
+ 0
+ 0
+
+
+ 1
+ 3
+ 1
+ 0
+ 0
+ 0
+ ..\..\src\c\ecl_timer_list.c
+ ecl_timer_list.c
+ 0
+ 0
+
+
+ 1
+ 4
+ 5
+ 0
+ 0
+ 0
+ ..\..\src\c\ecl_timer.h
+ ecl_timer.h
+ 0
+ 0
+
+
+ 1
+ 5
+ 5
+ 0
+ 0
+ 0
+ ..\..\src\c\ecl_timer_list.h
+ ecl_timer_list.h
+ 0
+ 0
+
+
+ 1
+ 6
+ 5
+ 0
+ 0
+ 0
+ .\ecl_user.h
+ ecl_user.h
+ 0
+ 0
+
+
+
+
+ ::Board Support
+ 1
+ 0
+ 0
+ 1
+
+
+
+ ::CMSIS
+ 0
+ 0
+ 0
+ 1
+
+
+
+ ::Device
+ 1
+ 0
+ 0
+ 1
+
+
+
diff --git a/examples/ArmTimerCallbacks - C/ArmTimerCallbacks.uvprojx b/examples/ArmTimerCallbacks - C/ArmTimerCallbacks.uvprojx
new file mode 100644
index 00000000..28b06f23
--- /dev/null
+++ b/examples/ArmTimerCallbacks - C/ArmTimerCallbacks.uvprojx
@@ -0,0 +1,489 @@
+
+
+
+ 2.1
+
+ ### uVision Project, (C) Keil Software
+
+
+
+ Target 1
+ 0x4
+ ARM-ADS
+ 5060528::V5.06 update 5 (build 528)::ARMCC
+ 0
+
+
+ STM32F401RETx
+ STMicroelectronics
+ Keil.STM32F4xx_DFP.2.11.0
+ http://www.keil.com/pack
+ IRAM(0x20000000,0x18000) IROM(0x08000000,0x80000) CPUTYPE("Cortex-M4") FPU2 CLOCK(12000000) ELITTLE
+
+
+ UL2CM3(-S0 -C0 -P0 -FD20000000 -FC1000 -FN1 -FF0STM32F4xx_512 -FS08000000 -FL080000 -FP0($$Device:STM32F401RETx$CMSIS\Flash\STM32F4xx_512.FLM))
+ 0
+ $$Device:STM32F401RETx$Drivers\CMSIS\Device\ST\STM32F4xx\Include\stm32f4xx.h
+
+
+
+
+
+
+
+
+
+ $$Device:STM32F401RETx$CMSIS\SVD\STM32F401xE.svd
+ 0
+ 0
+
+
+
+
+
+
+ 0
+ 0
+ 0
+ 0
+ 1
+
+ .\Objects\
+ ArmTimerCallbacks
+ 1
+ 0
+ 0
+ 1
+ 1
+ .\Listings\
+ 1
+ 0
+ 0
+
+ 0
+ 0
+
+
+ 0
+ 0
+ 0
+ 0
+
+
+ 0
+ 0
+
+
+ 0
+ 0
+ 0
+ 0
+
+
+ 0
+ 0
+
+
+ 0
+ 0
+ 0
+ 0
+
+ 0
+
+
+
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+ 0
+ 3
+
+
+ 1
+
+
+ SARMCM3.DLL
+ -REMAP -MPU
+ DCM.DLL
+ -pCM4
+ SARMCM3.DLL
+ -MPU
+ TCM.DLL
+ -pCM4
+
+
+
+ 1
+ 0
+ 0
+ 0
+ 16
+
+
+
+
+ 1
+ 0
+ 0
+ 1
+ 1
+ 4096
+
+ 1
+ BIN\UL2CM3.DLL
+ "" ()
+
+
+
+
+ 0
+
+
+
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0
+ 1
+ 1
+ 0
+ 1
+ 1
+ 0
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0
+ 0
+ "Cortex-M4"
+
+ 0
+ 0
+ 0
+ 1
+ 1
+ 0
+ 0
+ 2
+ 0
+ 0
+ 8
+ 0
+ 0
+ 0
+ 0
+ 3
+ 3
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+
+
+ 0
+ 0x0
+ 0x0
+
+
+ 0
+ 0x0
+ 0x0
+
+
+ 0
+ 0x0
+ 0x0
+
+
+ 0
+ 0x0
+ 0x0
+
+
+ 0
+ 0x0
+ 0x0
+
+
+ 0
+ 0x0
+ 0x0
+
+
+ 0
+ 0x20000000
+ 0x18000
+
+
+ 1
+ 0x8000000
+ 0x80000
+
+
+ 0
+ 0x0
+ 0x0
+
+
+ 1
+ 0x0
+ 0x0
+
+
+ 1
+ 0x0
+ 0x0
+
+
+ 1
+ 0x0
+ 0x0
+
+
+ 1
+ 0x8000000
+ 0x80000
+
+
+ 1
+ 0x0
+ 0x0
+
+
+ 0
+ 0x0
+ 0x0
+
+
+ 0
+ 0x0
+ 0x0
+
+
+ 0
+ 0x0
+ 0x0
+
+
+ 0
+ 0x20000000
+ 0x18000
+
+
+ 0
+ 0x0
+ 0x0
+
+
+
+
+
+ 1
+ 4
+ 0
+ 0
+ 1
+ 0
+ 0
+ 1
+ 0
+ 0
+ 2
+ 0
+ 0
+ 1
+ 0
+ 3
+ 3
+ 1
+ 1
+ 0
+ 0
+ 0
+
+
+
+
+ ..\..\src;../../src/c;..\ArmTimerCallbacks - C
+
+
+
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0x08000000
+ 0x20000000
+
+
+
+
+
+
+
+
+
+
+
+
+ Source Group 1
+
+
+ main.c
+ 1
+ .\main.c
+
+
+ ecl_timer.c
+ 1
+ ..\..\src\c\ecl_timer.c
+
+
+ ecl_timer_list.c
+ 1
+ ..\..\src\c\ecl_timer_list.c
+
+
+ ecl_timer.h
+ 5
+ ..\..\src\c\ecl_timer.h
+
+
+ ecl_timer_list.h
+ 5
+ ..\..\src\c\ecl_timer_list.h
+
+
+ ecl_user.h
+ 5
+ .\ecl_user.h
+
+
+
+
+ ::Board Support
+
+
+ ::CMSIS
+
+
+ ::Device
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RTE\Device\STM32F401RETx\startup_stm32f401xe.s
+
+
+
+
+
+
+
+ RTE\Device\STM32F401RETx\system_stm32f4xx.c
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/ArmTimerCallbacks - C/RTE/Device/STM32F401RETx/startup_stm32f401xe.s b/examples/ArmTimerCallbacks - C/RTE/Device/STM32F401RETx/startup_stm32f401xe.s
new file mode 100644
index 00000000..dc82c615
--- /dev/null
+++ b/examples/ArmTimerCallbacks - C/RTE/Device/STM32F401RETx/startup_stm32f401xe.s
@@ -0,0 +1,392 @@
+;******************** (C) COPYRIGHT 2016 STMicroelectronics ********************
+;* File Name : startup_stm32f401xe.s
+;* Author : MCD Application Team
+;* Version : V2.6.0
+;* Date : 04-November-2016
+;* Description : STM32F401xe devices vector table for MDK-ARM toolchain.
+;* This module performs:
+;* - Set the initial SP
+;* - Set the initial PC == Reset_Handler
+;* - Set the vector table entries with the exceptions ISR address
+;* - Branches to __main in the C library (which eventually
+;* calls main()).
+;* After Reset the CortexM4 processor is in Thread mode,
+;* priority is Privileged, and the Stack is set to Main.
+;* <<< Use Configuration Wizard in Context Menu >>>
+;*******************************************************************************
+;
+;* Redistribution and use in source and binary forms, with or without modification,
+;* are permitted provided that the following conditions are met:
+;* 1. Redistributions of source code must retain the above copyright notice,
+;* this list of conditions and the following disclaimer.
+;* 2. Redistributions in binary form must reproduce the above copyright notice,
+;* this list of conditions and the following disclaimer in the documentation
+;* and/or other materials provided with the distribution.
+;* 3. Neither the name of STMicroelectronics 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+;* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+;* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+;* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+;* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+;* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+;* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;
+;*******************************************************************************
+
+; Amount of memory (in bytes) allocated for Stack
+; Tailor this value to your application needs
+; Stack Configuration
+; Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
+;
+
+Stack_Size EQU 0x00000400
+
+ AREA STACK, NOINIT, READWRITE, ALIGN=3
+Stack_Mem SPACE Stack_Size
+__initial_sp
+
+
+; Heap Configuration
+; Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
+;
+
+Heap_Size EQU 0x00000200
+
+ AREA HEAP, NOINIT, READWRITE, ALIGN=3
+__heap_base
+Heap_Mem SPACE Heap_Size
+__heap_limit
+
+ PRESERVE8
+ THUMB
+
+
+; Vector Table Mapped to Address 0 at Reset
+ AREA RESET, DATA, READONLY
+ EXPORT __Vectors
+ EXPORT __Vectors_End
+ EXPORT __Vectors_Size
+
+__Vectors DCD __initial_sp ; Top of Stack
+ DCD Reset_Handler ; Reset Handler
+ DCD NMI_Handler ; NMI Handler
+ DCD HardFault_Handler ; Hard Fault Handler
+ DCD MemManage_Handler ; MPU Fault Handler
+ DCD BusFault_Handler ; Bus Fault Handler
+ DCD UsageFault_Handler ; Usage Fault Handler
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD SVC_Handler ; SVCall Handler
+ DCD DebugMon_Handler ; Debug Monitor Handler
+ DCD 0 ; Reserved
+ DCD PendSV_Handler ; PendSV Handler
+ DCD SysTick_Handler ; SysTick Handler
+
+ ; External Interrupts
+ DCD WWDG_IRQHandler ; Window WatchDog
+ DCD PVD_IRQHandler ; PVD through EXTI Line detection
+ DCD TAMP_STAMP_IRQHandler ; Tamper and TimeStamps through the EXTI line
+ DCD RTC_WKUP_IRQHandler ; RTC Wakeup through the EXTI line
+ DCD FLASH_IRQHandler ; FLASH
+ DCD RCC_IRQHandler ; RCC
+ DCD EXTI0_IRQHandler ; EXTI Line0
+ DCD EXTI1_IRQHandler ; EXTI Line1
+ DCD EXTI2_IRQHandler ; EXTI Line2
+ DCD EXTI3_IRQHandler ; EXTI Line3
+ DCD EXTI4_IRQHandler ; EXTI Line4
+ DCD DMA1_Stream0_IRQHandler ; DMA1 Stream 0
+ DCD DMA1_Stream1_IRQHandler ; DMA1 Stream 1
+ DCD DMA1_Stream2_IRQHandler ; DMA1 Stream 2
+ DCD DMA1_Stream3_IRQHandler ; DMA1 Stream 3
+ DCD DMA1_Stream4_IRQHandler ; DMA1 Stream 4
+ DCD DMA1_Stream5_IRQHandler ; DMA1 Stream 5
+ DCD DMA1_Stream6_IRQHandler ; DMA1 Stream 6
+ DCD ADC_IRQHandler ; ADC1, ADC2 and ADC3s
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD EXTI9_5_IRQHandler ; External Line[9:5]s
+ DCD TIM1_BRK_TIM9_IRQHandler ; TIM1 Break and TIM9
+ DCD TIM1_UP_TIM10_IRQHandler ; TIM1 Update and TIM10
+ DCD TIM1_TRG_COM_TIM11_IRQHandler ; TIM1 Trigger and Commutation and TIM11
+ DCD TIM1_CC_IRQHandler ; TIM1 Capture Compare
+ DCD TIM2_IRQHandler ; TIM2
+ DCD TIM3_IRQHandler ; TIM3
+ DCD TIM4_IRQHandler ; TIM4
+ DCD I2C1_EV_IRQHandler ; I2C1 Event
+ DCD I2C1_ER_IRQHandler ; I2C1 Error
+ DCD I2C2_EV_IRQHandler ; I2C2 Event
+ DCD I2C2_ER_IRQHandler ; I2C2 Error
+ DCD SPI1_IRQHandler ; SPI1
+ DCD SPI2_IRQHandler ; SPI2
+ DCD USART1_IRQHandler ; USART1
+ DCD USART2_IRQHandler ; USART2
+ DCD 0 ; Reserved
+ DCD EXTI15_10_IRQHandler ; External Line[15:10]s
+ DCD RTC_Alarm_IRQHandler ; RTC Alarm (A and B) through EXTI Line
+ DCD OTG_FS_WKUP_IRQHandler ; USB OTG FS Wakeup through EXTI line
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD DMA1_Stream7_IRQHandler ; DMA1 Stream7
+ DCD 0 ; Reserved
+ DCD SDIO_IRQHandler ; SDIO
+ DCD TIM5_IRQHandler ; TIM5
+ DCD SPI3_IRQHandler ; SPI3
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD DMA2_Stream0_IRQHandler ; DMA2 Stream 0
+ DCD DMA2_Stream1_IRQHandler ; DMA2 Stream 1
+ DCD DMA2_Stream2_IRQHandler ; DMA2 Stream 2
+ DCD DMA2_Stream3_IRQHandler ; DMA2 Stream 3
+ DCD DMA2_Stream4_IRQHandler ; DMA2 Stream 4
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD OTG_FS_IRQHandler ; USB OTG FS
+ DCD DMA2_Stream5_IRQHandler ; DMA2 Stream 5
+ DCD DMA2_Stream6_IRQHandler ; DMA2 Stream 6
+ DCD DMA2_Stream7_IRQHandler ; DMA2 Stream 7
+ DCD USART6_IRQHandler ; USART6
+ DCD I2C3_EV_IRQHandler ; I2C3 event
+ DCD I2C3_ER_IRQHandler ; I2C3 error
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD FPU_IRQHandler ; FPU
+ DCD 0 ; Reserved
+ DCD 0 ; Reserved
+ DCD SPI4_IRQHandler ; SPI4
+
+__Vectors_End
+
+__Vectors_Size EQU __Vectors_End - __Vectors
+
+ AREA |.text|, CODE, READONLY
+
+; Reset handler
+Reset_Handler PROC
+ EXPORT Reset_Handler [WEAK]
+ IMPORT SystemInit
+ IMPORT __main
+
+ LDR R0, =SystemInit
+ BLX R0
+ LDR R0, =__main
+ BX R0
+ ENDP
+
+; Dummy Exception Handlers (infinite loops which can be modified)
+
+NMI_Handler PROC
+ EXPORT NMI_Handler [WEAK]
+ B .
+ ENDP
+HardFault_Handler\
+ PROC
+ EXPORT HardFault_Handler [WEAK]
+ B .
+ ENDP
+MemManage_Handler\
+ PROC
+ EXPORT MemManage_Handler [WEAK]
+ B .
+ ENDP
+BusFault_Handler\
+ PROC
+ EXPORT BusFault_Handler [WEAK]
+ B .
+ ENDP
+UsageFault_Handler\
+ PROC
+ EXPORT UsageFault_Handler [WEAK]
+ B .
+ ENDP
+SVC_Handler PROC
+ EXPORT SVC_Handler [WEAK]
+ B .
+ ENDP
+DebugMon_Handler\
+ PROC
+ EXPORT DebugMon_Handler [WEAK]
+ B .
+ ENDP
+PendSV_Handler PROC
+ EXPORT PendSV_Handler [WEAK]
+ B .
+ ENDP
+SysTick_Handler PROC
+ EXPORT SysTick_Handler [WEAK]
+ B .
+ ENDP
+
+Default_Handler PROC
+
+ EXPORT WWDG_IRQHandler [WEAK]
+ EXPORT PVD_IRQHandler [WEAK]
+ EXPORT TAMP_STAMP_IRQHandler [WEAK]
+ EXPORT RTC_WKUP_IRQHandler [WEAK]
+ EXPORT FLASH_IRQHandler [WEAK]
+ EXPORT RCC_IRQHandler [WEAK]
+ EXPORT EXTI0_IRQHandler [WEAK]
+ EXPORT EXTI1_IRQHandler [WEAK]
+ EXPORT EXTI2_IRQHandler [WEAK]
+ EXPORT EXTI3_IRQHandler [WEAK]
+ EXPORT EXTI4_IRQHandler [WEAK]
+ EXPORT DMA1_Stream0_IRQHandler [WEAK]
+ EXPORT DMA1_Stream1_IRQHandler [WEAK]
+ EXPORT DMA1_Stream2_IRQHandler [WEAK]
+ EXPORT DMA1_Stream3_IRQHandler [WEAK]
+ EXPORT DMA1_Stream4_IRQHandler [WEAK]
+ EXPORT DMA1_Stream5_IRQHandler [WEAK]
+ EXPORT DMA1_Stream6_IRQHandler [WEAK]
+ EXPORT ADC_IRQHandler [WEAK]
+ EXPORT EXTI9_5_IRQHandler [WEAK]
+ EXPORT TIM1_BRK_TIM9_IRQHandler [WEAK]
+ EXPORT TIM1_UP_TIM10_IRQHandler [WEAK]
+ EXPORT TIM1_TRG_COM_TIM11_IRQHandler [WEAK]
+ EXPORT TIM1_CC_IRQHandler [WEAK]
+ EXPORT TIM2_IRQHandler [WEAK]
+ EXPORT TIM3_IRQHandler [WEAK]
+ EXPORT TIM4_IRQHandler [WEAK]
+ EXPORT I2C1_EV_IRQHandler [WEAK]
+ EXPORT I2C1_ER_IRQHandler [WEAK]
+ EXPORT I2C2_EV_IRQHandler [WEAK]
+ EXPORT I2C2_ER_IRQHandler [WEAK]
+ EXPORT SPI1_IRQHandler [WEAK]
+ EXPORT SPI2_IRQHandler [WEAK]
+ EXPORT USART1_IRQHandler [WEAK]
+ EXPORT USART2_IRQHandler [WEAK]
+ EXPORT EXTI15_10_IRQHandler [WEAK]
+ EXPORT RTC_Alarm_IRQHandler [WEAK]
+ EXPORT OTG_FS_WKUP_IRQHandler [WEAK]
+ EXPORT DMA1_Stream7_IRQHandler [WEAK]
+ EXPORT SDIO_IRQHandler [WEAK]
+ EXPORT TIM5_IRQHandler [WEAK]
+ EXPORT SPI3_IRQHandler [WEAK]
+ EXPORT DMA2_Stream0_IRQHandler [WEAK]
+ EXPORT DMA2_Stream1_IRQHandler [WEAK]
+ EXPORT DMA2_Stream2_IRQHandler [WEAK]
+ EXPORT DMA2_Stream3_IRQHandler [WEAK]
+ EXPORT DMA2_Stream4_IRQHandler [WEAK]
+ EXPORT OTG_FS_IRQHandler [WEAK]
+ EXPORT DMA2_Stream5_IRQHandler [WEAK]
+ EXPORT DMA2_Stream6_IRQHandler [WEAK]
+ EXPORT DMA2_Stream7_IRQHandler [WEAK]
+ EXPORT USART6_IRQHandler [WEAK]
+ EXPORT I2C3_EV_IRQHandler [WEAK]
+ EXPORT I2C3_ER_IRQHandler [WEAK]
+ EXPORT FPU_IRQHandler [WEAK]
+ EXPORT SPI4_IRQHandler [WEAK]
+
+WWDG_IRQHandler
+PVD_IRQHandler
+TAMP_STAMP_IRQHandler
+RTC_WKUP_IRQHandler
+FLASH_IRQHandler
+RCC_IRQHandler
+EXTI0_IRQHandler
+EXTI1_IRQHandler
+EXTI2_IRQHandler
+EXTI3_IRQHandler
+EXTI4_IRQHandler
+DMA1_Stream0_IRQHandler
+DMA1_Stream1_IRQHandler
+DMA1_Stream2_IRQHandler
+DMA1_Stream3_IRQHandler
+DMA1_Stream4_IRQHandler
+DMA1_Stream5_IRQHandler
+DMA1_Stream6_IRQHandler
+ADC_IRQHandler
+EXTI9_5_IRQHandler
+TIM1_BRK_TIM9_IRQHandler
+TIM1_UP_TIM10_IRQHandler
+TIM1_TRG_COM_TIM11_IRQHandler
+TIM1_CC_IRQHandler
+TIM2_IRQHandler
+TIM3_IRQHandler
+TIM4_IRQHandler
+I2C1_EV_IRQHandler
+I2C1_ER_IRQHandler
+I2C2_EV_IRQHandler
+I2C2_ER_IRQHandler
+SPI1_IRQHandler
+SPI2_IRQHandler
+USART1_IRQHandler
+USART2_IRQHandler
+EXTI15_10_IRQHandler
+RTC_Alarm_IRQHandler
+OTG_FS_WKUP_IRQHandler
+DMA1_Stream7_IRQHandler
+SDIO_IRQHandler
+TIM5_IRQHandler
+SPI3_IRQHandler
+DMA2_Stream0_IRQHandler
+DMA2_Stream1_IRQHandler
+DMA2_Stream2_IRQHandler
+DMA2_Stream3_IRQHandler
+DMA2_Stream4_IRQHandler
+OTG_FS_IRQHandler
+DMA2_Stream5_IRQHandler
+DMA2_Stream6_IRQHandler
+DMA2_Stream7_IRQHandler
+USART6_IRQHandler
+I2C3_EV_IRQHandler
+I2C3_ER_IRQHandler
+FPU_IRQHandler
+SPI4_IRQHandler
+
+ B .
+
+ ENDP
+
+ ALIGN
+
+;*******************************************************************************
+; User Stack and Heap initialization
+;*******************************************************************************
+ IF :DEF:__MICROLIB
+
+ EXPORT __initial_sp
+ EXPORT __heap_base
+ EXPORT __heap_limit
+
+ ELSE
+
+ IMPORT __use_two_region_memory
+ EXPORT __user_initial_stackheap
+
+__user_initial_stackheap
+
+ LDR R0, = Heap_Mem
+ LDR R1, =(Stack_Mem + Stack_Size)
+ LDR R2, = (Heap_Mem + Heap_Size)
+ LDR R3, = Stack_Mem
+ BX LR
+
+ ALIGN
+
+ ENDIF
+
+ END
+
+;************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE*****
diff --git a/examples/ArmTimerCallbacks - C/RTE/Device/STM32F401RETx/system_stm32f4xx.c b/examples/ArmTimerCallbacks - C/RTE/Device/STM32F401RETx/system_stm32f4xx.c
new file mode 100644
index 00000000..bca0633d
--- /dev/null
+++ b/examples/ArmTimerCallbacks - C/RTE/Device/STM32F401RETx/system_stm32f4xx.c
@@ -0,0 +1,763 @@
+/**
+ ******************************************************************************
+ * @file system_stm32f4xx.c
+ * @author MCD Application Team
+ * @version V2.6.0
+ * @date 04-November-2016
+ * @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File.
+ *
+ * This file provides two functions and one global variable to be called from
+ * user application:
+ * - SystemInit(): This function is called at startup just after reset and
+ * before branch to main program. This call is made inside
+ * the "startup_stm32f4xx.s" file.
+ *
+ * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
+ * by the user application to setup the SysTick
+ * timer or configure other parameters.
+ *
+ * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
+ * be called whenever the core clock is changed
+ * during program execution.
+ *
+ *
+ ******************************************************************************
+ * @attention
+ *
+ * © COPYRIGHT 2016 STMicroelectronics
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+/** @addtogroup CMSIS
+ * @{
+ */
+
+/** @addtogroup stm32f4xx_system
+ * @{
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Includes
+ * @{
+ */
+
+
+#include "stm32f4xx.h"
+
+#if !defined (HSE_VALUE)
+ #define HSE_VALUE ((uint32_t)25000000) /*!< Default value of the External oscillator in Hz */
+#endif /* HSE_VALUE */
+
+#if !defined (HSI_VALUE)
+ #define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/
+#endif /* HSI_VALUE */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_TypesDefinitions
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Defines
+ * @{
+ */
+
+/************************* Miscellaneous Configuration ************************/
+/*!< Uncomment the following line if you need to use external SRAM or SDRAM as data memory */
+#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx)\
+ || defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
+ || defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F412Zx) || defined(STM32F412Vx)
+/* #define DATA_IN_ExtSRAM */
+#endif /* STM32F40xxx || STM32F41xxx || STM32F42xxx || STM32F43xxx || STM32F469xx || STM32F479xx ||\
+ STM32F412Zx || STM32F412Vx */
+
+#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
+ || defined(STM32F446xx) || defined(STM32F469xx) || defined(STM32F479xx)
+/* #define DATA_IN_ExtSDRAM */
+#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F446xx || STM32F469xx ||\
+ STM32F479xx */
+
+/*!< Uncomment the following line if you need to relocate your vector Table in
+ Internal SRAM. */
+/* #define VECT_TAB_SRAM */
+#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field.
+ This value must be a multiple of 0x200. */
+/******************************************************************************/
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Variables
+ * @{
+ */
+ /* This variable is updated in three ways:
+ 1) by calling CMSIS function SystemCoreClockUpdate()
+ 2) by calling HAL API function HAL_RCC_GetHCLKFreq()
+ 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
+ Note: If you use this function to configure the system clock; then there
+ is no need to call the 2 first functions listed above, since SystemCoreClock
+ variable is updated automatically.
+ */
+uint32_t SystemCoreClock = 16000000;
+const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
+const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4};
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_FunctionPrototypes
+ * @{
+ */
+
+#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
+ static void SystemInit_ExtMemCtl(void);
+#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F4xx_System_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief Setup the microcontroller system
+ * Initialize the FPU setting, vector table location and External memory
+ * configuration.
+ * @param None
+ * @retval None
+ */
+void SystemInit(void)
+{
+ /* FPU settings ------------------------------------------------------------*/
+ #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
+ SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
+ #endif
+ /* Reset the RCC clock configuration to the default reset state ------------*/
+ /* Set HSION bit */
+ RCC->CR |= (uint32_t)0x00000001;
+
+ /* Reset CFGR register */
+ RCC->CFGR = 0x00000000;
+
+ /* Reset HSEON, CSSON and PLLON bits */
+ RCC->CR &= (uint32_t)0xFEF6FFFF;
+
+ /* Reset PLLCFGR register */
+ RCC->PLLCFGR = 0x24003010;
+
+ /* Reset HSEBYP bit */
+ RCC->CR &= (uint32_t)0xFFFBFFFF;
+
+ /* Disable all interrupts */
+ RCC->CIR = 0x00000000;
+
+#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
+ SystemInit_ExtMemCtl();
+#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
+
+ /* Configure the Vector Table location add offset address ------------------*/
+#ifdef VECT_TAB_SRAM
+ SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
+#else
+ SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
+#endif
+}
+
+/**
+ * @brief Update SystemCoreClock variable according to Clock Register Values.
+ * The SystemCoreClock variable contains the core clock (HCLK), it can
+ * be used by the user application to setup the SysTick timer or configure
+ * other parameters.
+ *
+ * @note Each time the core clock (HCLK) changes, this function must be called
+ * to update SystemCoreClock variable value. Otherwise, any configuration
+ * based on this variable will be incorrect.
+ *
+ * @note - The system frequency computed by this function is not the real
+ * frequency in the chip. It is calculated based on the predefined
+ * constant and the selected clock source:
+ *
+ * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
+ *
+ * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
+ *
+ * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
+ * or HSI_VALUE(*) multiplied/divided by the PLL factors.
+ *
+ * (*) HSI_VALUE is a constant defined in stm32f4xx_hal_conf.h file (default value
+ * 16 MHz) but the real value may vary depending on the variations
+ * in voltage and temperature.
+ *
+ * (**) HSE_VALUE is a constant defined in stm32f4xx_hal_conf.h file (its value
+ * depends on the application requirements), user has to ensure that HSE_VALUE
+ * is same as the real frequency of the crystal used. Otherwise, this function
+ * may have wrong result.
+ *
+ * - The result of this function could be not correct when using fractional
+ * value for HSE crystal.
+ *
+ * @param None
+ * @retval None
+ */
+void SystemCoreClockUpdate(void)
+{
+ uint32_t tmp = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2;
+
+ /* Get SYSCLK source -------------------------------------------------------*/
+ tmp = RCC->CFGR & RCC_CFGR_SWS;
+
+ switch (tmp)
+ {
+ case 0x00: /* HSI used as system clock source */
+ SystemCoreClock = HSI_VALUE;
+ break;
+ case 0x04: /* HSE used as system clock source */
+ SystemCoreClock = HSE_VALUE;
+ break;
+ case 0x08: /* PLL used as system clock source */
+
+ /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N
+ SYSCLK = PLL_VCO / PLL_P
+ */
+ pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22;
+ pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;
+
+ if (pllsource != 0)
+ {
+ /* HSE used as PLL clock source */
+ pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
+ }
+ else
+ {
+ /* HSI used as PLL clock source */
+ pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
+ }
+
+ pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2;
+ SystemCoreClock = pllvco/pllp;
+ break;
+ default:
+ SystemCoreClock = HSI_VALUE;
+ break;
+ }
+ /* Compute HCLK frequency --------------------------------------------------*/
+ /* Get HCLK prescaler */
+ tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
+ /* HCLK frequency */
+ SystemCoreClock >>= tmp;
+}
+
+#if defined (DATA_IN_ExtSRAM) && defined (DATA_IN_ExtSDRAM)
+#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
+ || defined(STM32F469xx) || defined(STM32F479xx)
+/**
+ * @brief Setup the external memory controller.
+ * Called in startup_stm32f4xx.s before jump to main.
+ * This function configures the external memories (SRAM/SDRAM)
+ * This SRAM/SDRAM will be used as program data memory (including heap and stack).
+ * @param None
+ * @retval None
+ */
+void SystemInit_ExtMemCtl(void)
+{
+ __IO uint32_t tmp = 0x00;
+
+ register uint32_t tmpreg = 0, timeout = 0xFFFF;
+ register __IO uint32_t index;
+
+ /* Enable GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, GPIOH and GPIOI interface clock */
+ RCC->AHB1ENR |= 0x000001F8;
+
+ /* Delay after an RCC peripheral clock enabling */
+ tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOCEN);
+
+ /* Connect PDx pins to FMC Alternate function */
+ GPIOD->AFR[0] = 0x00CCC0CC;
+ GPIOD->AFR[1] = 0xCCCCCCCC;
+ /* Configure PDx pins in Alternate function mode */
+ GPIOD->MODER = 0xAAAA0A8A;
+ /* Configure PDx pins speed to 100 MHz */
+ GPIOD->OSPEEDR = 0xFFFF0FCF;
+ /* Configure PDx pins Output type to push-pull */
+ GPIOD->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PDx pins */
+ GPIOD->PUPDR = 0x00000000;
+
+ /* Connect PEx pins to FMC Alternate function */
+ GPIOE->AFR[0] = 0xC00CC0CC;
+ GPIOE->AFR[1] = 0xCCCCCCCC;
+ /* Configure PEx pins in Alternate function mode */
+ GPIOE->MODER = 0xAAAA828A;
+ /* Configure PEx pins speed to 100 MHz */
+ GPIOE->OSPEEDR = 0xFFFFC3CF;
+ /* Configure PEx pins Output type to push-pull */
+ GPIOE->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PEx pins */
+ GPIOE->PUPDR = 0x00000000;
+
+ /* Connect PFx pins to FMC Alternate function */
+ GPIOF->AFR[0] = 0xCCCCCCCC;
+ GPIOF->AFR[1] = 0xCCCCCCCC;
+ /* Configure PFx pins in Alternate function mode */
+ GPIOF->MODER = 0xAA800AAA;
+ /* Configure PFx pins speed to 50 MHz */
+ GPIOF->OSPEEDR = 0xAA800AAA;
+ /* Configure PFx pins Output type to push-pull */
+ GPIOF->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PFx pins */
+ GPIOF->PUPDR = 0x00000000;
+
+ /* Connect PGx pins to FMC Alternate function */
+ GPIOG->AFR[0] = 0xCCCCCCCC;
+ GPIOG->AFR[1] = 0xCCCCCCCC;
+ /* Configure PGx pins in Alternate function mode */
+ GPIOG->MODER = 0xAAAAAAAA;
+ /* Configure PGx pins speed to 50 MHz */
+ GPIOG->OSPEEDR = 0xAAAAAAAA;
+ /* Configure PGx pins Output type to push-pull */
+ GPIOG->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PGx pins */
+ GPIOG->PUPDR = 0x00000000;
+
+ /* Connect PHx pins to FMC Alternate function */
+ GPIOH->AFR[0] = 0x00C0CC00;
+ GPIOH->AFR[1] = 0xCCCCCCCC;
+ /* Configure PHx pins in Alternate function mode */
+ GPIOH->MODER = 0xAAAA08A0;
+ /* Configure PHx pins speed to 50 MHz */
+ GPIOH->OSPEEDR = 0xAAAA08A0;
+ /* Configure PHx pins Output type to push-pull */
+ GPIOH->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PHx pins */
+ GPIOH->PUPDR = 0x00000000;
+
+ /* Connect PIx pins to FMC Alternate function */
+ GPIOI->AFR[0] = 0xCCCCCCCC;
+ GPIOI->AFR[1] = 0x00000CC0;
+ /* Configure PIx pins in Alternate function mode */
+ GPIOI->MODER = 0x0028AAAA;
+ /* Configure PIx pins speed to 50 MHz */
+ GPIOI->OSPEEDR = 0x0028AAAA;
+ /* Configure PIx pins Output type to push-pull */
+ GPIOI->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PIx pins */
+ GPIOI->PUPDR = 0x00000000;
+
+/*-- FMC Configuration -------------------------------------------------------*/
+ /* Enable the FMC interface clock */
+ RCC->AHB3ENR |= 0x00000001;
+ /* Delay after an RCC peripheral clock enabling */
+ tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
+
+ FMC_Bank5_6->SDCR[0] = 0x000019E4;
+ FMC_Bank5_6->SDTR[0] = 0x01115351;
+
+ /* SDRAM initialization sequence */
+ /* Clock enable command */
+ FMC_Bank5_6->SDCMR = 0x00000011;
+ tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
+ while((tmpreg != 0) && (timeout-- > 0))
+ {
+ tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
+ }
+
+ /* Delay */
+ for (index = 0; index<1000; index++);
+
+ /* PALL command */
+ FMC_Bank5_6->SDCMR = 0x00000012;
+ timeout = 0xFFFF;
+ while((tmpreg != 0) && (timeout-- > 0))
+ {
+ tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
+ }
+
+ /* Auto refresh command */
+ FMC_Bank5_6->SDCMR = 0x00000073;
+ timeout = 0xFFFF;
+ while((tmpreg != 0) && (timeout-- > 0))
+ {
+ tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
+ }
+
+ /* MRD register program */
+ FMC_Bank5_6->SDCMR = 0x00046014;
+ timeout = 0xFFFF;
+ while((tmpreg != 0) && (timeout-- > 0))
+ {
+ tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
+ }
+
+ /* Set refresh count */
+ tmpreg = FMC_Bank5_6->SDRTR;
+ FMC_Bank5_6->SDRTR = (tmpreg | (0x0000027C<<1));
+
+ /* Disable write protection */
+ tmpreg = FMC_Bank5_6->SDCR[0];
+ FMC_Bank5_6->SDCR[0] = (tmpreg & 0xFFFFFDFF);
+
+#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)
+ /* Configure and enable Bank1_SRAM2 */
+ FMC_Bank1->BTCR[2] = 0x00001011;
+ FMC_Bank1->BTCR[3] = 0x00000201;
+ FMC_Bank1E->BWTR[2] = 0x0fffffff;
+#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx */
+#if defined(STM32F469xx) || defined(STM32F479xx)
+ /* Configure and enable Bank1_SRAM2 */
+ FMC_Bank1->BTCR[2] = 0x00001091;
+ FMC_Bank1->BTCR[3] = 0x00110212;
+ FMC_Bank1E->BWTR[2] = 0x0fffffff;
+#endif /* STM32F469xx || STM32F479xx */
+
+ (void)(tmp);
+}
+#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx */
+#elif defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
+/**
+ * @brief Setup the external memory controller.
+ * Called in startup_stm32f4xx.s before jump to main.
+ * This function configures the external memories (SRAM/SDRAM)
+ * This SRAM/SDRAM will be used as program data memory (including heap and stack).
+ * @param None
+ * @retval None
+ */
+void SystemInit_ExtMemCtl(void)
+{
+ __IO uint32_t tmp = 0x00;
+#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
+ || defined(STM32F446xx) || defined(STM32F469xx) || defined(STM32F479xx)
+#if defined (DATA_IN_ExtSDRAM)
+ register uint32_t tmpreg = 0, timeout = 0xFFFF;
+ register __IO uint32_t index;
+
+#if defined(STM32F446xx)
+ /* Enable GPIOA, GPIOC, GPIOD, GPIOE, GPIOF, GPIOG interface
+ clock */
+ RCC->AHB1ENR |= 0x0000007D;
+#else
+ /* Enable GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, GPIOH and GPIOI interface
+ clock */
+ RCC->AHB1ENR |= 0x000001F8;
+#endif /* STM32F446xx */
+ /* Delay after an RCC peripheral clock enabling */
+ tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIOCEN);
+
+#if defined(STM32F446xx)
+ /* Connect PAx pins to FMC Alternate function */
+ GPIOA->AFR[0] |= 0xC0000000;
+ GPIOA->AFR[1] |= 0x00000000;
+ /* Configure PDx pins in Alternate function mode */
+ GPIOA->MODER |= 0x00008000;
+ /* Configure PDx pins speed to 50 MHz */
+ GPIOA->OSPEEDR |= 0x00008000;
+ /* Configure PDx pins Output type to push-pull */
+ GPIOA->OTYPER |= 0x00000000;
+ /* No pull-up, pull-down for PDx pins */
+ GPIOA->PUPDR |= 0x00000000;
+
+ /* Connect PCx pins to FMC Alternate function */
+ GPIOC->AFR[0] |= 0x00CC0000;
+ GPIOC->AFR[1] |= 0x00000000;
+ /* Configure PDx pins in Alternate function mode */
+ GPIOC->MODER |= 0x00000A00;
+ /* Configure PDx pins speed to 50 MHz */
+ GPIOC->OSPEEDR |= 0x00000A00;
+ /* Configure PDx pins Output type to push-pull */
+ GPIOC->OTYPER |= 0x00000000;
+ /* No pull-up, pull-down for PDx pins */
+ GPIOC->PUPDR |= 0x00000000;
+#endif /* STM32F446xx */
+
+ /* Connect PDx pins to FMC Alternate function */
+ GPIOD->AFR[0] = 0x000000CC;
+ GPIOD->AFR[1] = 0xCC000CCC;
+ /* Configure PDx pins in Alternate function mode */
+ GPIOD->MODER = 0xA02A000A;
+ /* Configure PDx pins speed to 50 MHz */
+ GPIOD->OSPEEDR = 0xA02A000A;
+ /* Configure PDx pins Output type to push-pull */
+ GPIOD->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PDx pins */
+ GPIOD->PUPDR = 0x00000000;
+
+ /* Connect PEx pins to FMC Alternate function */
+ GPIOE->AFR[0] = 0xC00000CC;
+ GPIOE->AFR[1] = 0xCCCCCCCC;
+ /* Configure PEx pins in Alternate function mode */
+ GPIOE->MODER = 0xAAAA800A;
+ /* Configure PEx pins speed to 50 MHz */
+ GPIOE->OSPEEDR = 0xAAAA800A;
+ /* Configure PEx pins Output type to push-pull */
+ GPIOE->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PEx pins */
+ GPIOE->PUPDR = 0x00000000;
+
+ /* Connect PFx pins to FMC Alternate function */
+ GPIOF->AFR[0] = 0xCCCCCCCC;
+ GPIOF->AFR[1] = 0xCCCCCCCC;
+ /* Configure PFx pins in Alternate function mode */
+ GPIOF->MODER = 0xAA800AAA;
+ /* Configure PFx pins speed to 50 MHz */
+ GPIOF->OSPEEDR = 0xAA800AAA;
+ /* Configure PFx pins Output type to push-pull */
+ GPIOF->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PFx pins */
+ GPIOF->PUPDR = 0x00000000;
+
+ /* Connect PGx pins to FMC Alternate function */
+ GPIOG->AFR[0] = 0xCCCCCCCC;
+ GPIOG->AFR[1] = 0xCCCCCCCC;
+ /* Configure PGx pins in Alternate function mode */
+ GPIOG->MODER = 0xAAAAAAAA;
+ /* Configure PGx pins speed to 50 MHz */
+ GPIOG->OSPEEDR = 0xAAAAAAAA;
+ /* Configure PGx pins Output type to push-pull */
+ GPIOG->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PGx pins */
+ GPIOG->PUPDR = 0x00000000;
+
+#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
+ || defined(STM32F469xx) || defined(STM32F479xx)
+ /* Connect PHx pins to FMC Alternate function */
+ GPIOH->AFR[0] = 0x00C0CC00;
+ GPIOH->AFR[1] = 0xCCCCCCCC;
+ /* Configure PHx pins in Alternate function mode */
+ GPIOH->MODER = 0xAAAA08A0;
+ /* Configure PHx pins speed to 50 MHz */
+ GPIOH->OSPEEDR = 0xAAAA08A0;
+ /* Configure PHx pins Output type to push-pull */
+ GPIOH->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PHx pins */
+ GPIOH->PUPDR = 0x00000000;
+
+ /* Connect PIx pins to FMC Alternate function */
+ GPIOI->AFR[0] = 0xCCCCCCCC;
+ GPIOI->AFR[1] = 0x00000CC0;
+ /* Configure PIx pins in Alternate function mode */
+ GPIOI->MODER = 0x0028AAAA;
+ /* Configure PIx pins speed to 50 MHz */
+ GPIOI->OSPEEDR = 0x0028AAAA;
+ /* Configure PIx pins Output type to push-pull */
+ GPIOI->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PIx pins */
+ GPIOI->PUPDR = 0x00000000;
+#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx */
+
+/*-- FMC Configuration -------------------------------------------------------*/
+ /* Enable the FMC interface clock */
+ RCC->AHB3ENR |= 0x00000001;
+ /* Delay after an RCC peripheral clock enabling */
+ tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
+
+ /* Configure and enable SDRAM bank1 */
+#if defined(STM32F446xx)
+ FMC_Bank5_6->SDCR[0] = 0x00001954;
+#else
+ FMC_Bank5_6->SDCR[0] = 0x000019E4;
+#endif /* STM32F446xx */
+ FMC_Bank5_6->SDTR[0] = 0x01115351;
+
+ /* SDRAM initialization sequence */
+ /* Clock enable command */
+ FMC_Bank5_6->SDCMR = 0x00000011;
+ tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
+ while((tmpreg != 0) && (timeout-- > 0))
+ {
+ tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
+ }
+
+ /* Delay */
+ for (index = 0; index<1000; index++);
+
+ /* PALL command */
+ FMC_Bank5_6->SDCMR = 0x00000012;
+ timeout = 0xFFFF;
+ while((tmpreg != 0) && (timeout-- > 0))
+ {
+ tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
+ }
+
+ /* Auto refresh command */
+#if defined(STM32F446xx)
+ FMC_Bank5_6->SDCMR = 0x000000F3;
+#else
+ FMC_Bank5_6->SDCMR = 0x00000073;
+#endif /* STM32F446xx */
+ timeout = 0xFFFF;
+ while((tmpreg != 0) && (timeout-- > 0))
+ {
+ tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
+ }
+
+ /* MRD register program */
+#if defined(STM32F446xx)
+ FMC_Bank5_6->SDCMR = 0x00044014;
+#else
+ FMC_Bank5_6->SDCMR = 0x00046014;
+#endif /* STM32F446xx */
+ timeout = 0xFFFF;
+ while((tmpreg != 0) && (timeout-- > 0))
+ {
+ tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
+ }
+
+ /* Set refresh count */
+ tmpreg = FMC_Bank5_6->SDRTR;
+#if defined(STM32F446xx)
+ FMC_Bank5_6->SDRTR = (tmpreg | (0x0000050C<<1));
+#else
+ FMC_Bank5_6->SDRTR = (tmpreg | (0x0000027C<<1));
+#endif /* STM32F446xx */
+
+ /* Disable write protection */
+ tmpreg = FMC_Bank5_6->SDCR[0];
+ FMC_Bank5_6->SDCR[0] = (tmpreg & 0xFFFFFDFF);
+#endif /* DATA_IN_ExtSDRAM */
+#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F446xx || STM32F469xx || STM32F479xx */
+
+#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx)\
+ || defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
+ || defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F412Zx) || defined(STM32F412Vx)
+
+#if defined(DATA_IN_ExtSRAM)
+/*-- GPIOs Configuration -----------------------------------------------------*/
+ /* Enable GPIOD, GPIOE, GPIOF and GPIOG interface clock */
+ RCC->AHB1ENR |= 0x00000078;
+ /* Delay after an RCC peripheral clock enabling */
+ tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIODEN);
+
+ /* Connect PDx pins to FMC Alternate function */
+ GPIOD->AFR[0] = 0x00CCC0CC;
+ GPIOD->AFR[1] = 0xCCCCCCCC;
+ /* Configure PDx pins in Alternate function mode */
+ GPIOD->MODER = 0xAAAA0A8A;
+ /* Configure PDx pins speed to 100 MHz */
+ GPIOD->OSPEEDR = 0xFFFF0FCF;
+ /* Configure PDx pins Output type to push-pull */
+ GPIOD->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PDx pins */
+ GPIOD->PUPDR = 0x00000000;
+
+ /* Connect PEx pins to FMC Alternate function */
+ GPIOE->AFR[0] = 0xC00CC0CC;
+ GPIOE->AFR[1] = 0xCCCCCCCC;
+ /* Configure PEx pins in Alternate function mode */
+ GPIOE->MODER = 0xAAAA828A;
+ /* Configure PEx pins speed to 100 MHz */
+ GPIOE->OSPEEDR = 0xFFFFC3CF;
+ /* Configure PEx pins Output type to push-pull */
+ GPIOE->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PEx pins */
+ GPIOE->PUPDR = 0x00000000;
+
+ /* Connect PFx pins to FMC Alternate function */
+ GPIOF->AFR[0] = 0x00CCCCCC;
+ GPIOF->AFR[1] = 0xCCCC0000;
+ /* Configure PFx pins in Alternate function mode */
+ GPIOF->MODER = 0xAA000AAA;
+ /* Configure PFx pins speed to 100 MHz */
+ GPIOF->OSPEEDR = 0xFF000FFF;
+ /* Configure PFx pins Output type to push-pull */
+ GPIOF->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PFx pins */
+ GPIOF->PUPDR = 0x00000000;
+
+ /* Connect PGx pins to FMC Alternate function */
+ GPIOG->AFR[0] = 0x00CCCCCC;
+ GPIOG->AFR[1] = 0x000000C0;
+ /* Configure PGx pins in Alternate function mode */
+ GPIOG->MODER = 0x00085AAA;
+ /* Configure PGx pins speed to 100 MHz */
+ GPIOG->OSPEEDR = 0x000CAFFF;
+ /* Configure PGx pins Output type to push-pull */
+ GPIOG->OTYPER = 0x00000000;
+ /* No pull-up, pull-down for PGx pins */
+ GPIOG->PUPDR = 0x00000000;
+
+/*-- FMC/FSMC Configuration --------------------------------------------------*/
+ /* Enable the FMC/FSMC interface clock */
+ RCC->AHB3ENR |= 0x00000001;
+
+#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)
+ /* Delay after an RCC peripheral clock enabling */
+ tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
+ /* Configure and enable Bank1_SRAM2 */
+ FMC_Bank1->BTCR[2] = 0x00001011;
+ FMC_Bank1->BTCR[3] = 0x00000201;
+ FMC_Bank1E->BWTR[2] = 0x0fffffff;
+#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx */
+#if defined(STM32F469xx) || defined(STM32F479xx)
+ /* Delay after an RCC peripheral clock enabling */
+ tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FMCEN);
+ /* Configure and enable Bank1_SRAM2 */
+ FMC_Bank1->BTCR[2] = 0x00001091;
+ FMC_Bank1->BTCR[3] = 0x00110212;
+ FMC_Bank1E->BWTR[2] = 0x0fffffff;
+#endif /* STM32F469xx || STM32F479xx */
+#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx)|| defined(STM32F417xx)\
+ || defined(STM32F412Zx) || defined(STM32F412Vx)
+ /* Delay after an RCC peripheral clock enabling */
+ tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FSMCEN);
+ /* Configure and enable Bank1_SRAM2 */
+ FSMC_Bank1->BTCR[2] = 0x00001011;
+ FSMC_Bank1->BTCR[3] = 0x00000201;
+ FSMC_Bank1E->BWTR[2] = 0x0FFFFFFF;
+#endif /* STM32F405xx || STM32F415xx || STM32F407xx || STM32F417xx || STM32F412Zx || STM32F412Vx */
+
+#endif /* DATA_IN_ExtSRAM */
+#endif /* STM32F405xx || STM32F415xx || STM32F407xx || STM32F417xx || STM32F427xx || STM32F437xx ||\
+ STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx || STM32F412Zx || STM32F412Vx */
+ (void)(tmp);
+}
+#endif /* DATA_IN_ExtSRAM && DATA_IN_ExtSDRAM */
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/examples/ArmTimerCallbacks - C/ecl_user.h b/examples/ArmTimerCallbacks - C/ecl_user.h
new file mode 100644
index 00000000..6fbb9d8e
--- /dev/null
+++ b/examples/ArmTimerCallbacks - C/ecl_user.h
@@ -0,0 +1,38 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ECL_USER__
+#define __ECL_USER__
+
+#include
+
+#define ECL_TIMER_TIMER_SEMAPHORE uint32_t
+#define ECL_TIMER_DISABLE_PROCESSING(x) __sync_fetch_and_add(&x, 1)
+#define ECL_TIMER_ENABLE_PROCESSING(x) __sync_fetch_and_sub(&x, 1)
+#define ECL_TIMER_PROCESSING_ENABLED(x) (__sync_fetch_and_add(&x, 0) == 0)
+#endif
diff --git a/examples/ArmTimerCallbacks - C/main.c b/examples/ArmTimerCallbacks - C/main.c
new file mode 100644
index 00000000..8b80a68c
--- /dev/null
+++ b/examples/ArmTimerCallbacks - C/main.c
@@ -0,0 +1,142 @@
+
+#include
+
+#include "Board_LED.h" // ::Board Support:LED
+#include "Board_Buttons.h" // ::Board Support:Buttons
+
+#include "stm32f4xx.h" // Device header
+
+#include "ecl_timer.h"
+
+#define N_TIMERS 4
+struct ecl_timer_config timers[N_TIMERS];
+
+ecl_timer_id_t short_toggle;
+ecl_timer_id_t long_toggle;
+ecl_timer_id_t start_timers;
+ecl_timer_id_t swap_timers;
+
+/*----------------------------------------------------------------------------
+ * SystemCoreClockConfigure: configure SystemCoreClock using HSI
+ (HSE is not populated on Nucleo board)
+ *----------------------------------------------------------------------------*/
+void SystemCoreClockConfigure(void) {
+
+ RCC->CR |= ((uint32_t)RCC_CR_HSION); // Enable HSI
+ while ((RCC->CR & RCC_CR_HSIRDY) == 0); // Wait for HSI Ready
+
+ RCC->CFGR = RCC_CFGR_SW_HSI; // HSI is system clock
+ while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI); // Wait for HSI used as system clock
+
+ FLASH->ACR = FLASH_ACR_PRFTEN; // Enable Prefetch Buffer
+ FLASH->ACR |= FLASH_ACR_ICEN; // Instruction cache enable
+ FLASH->ACR |= FLASH_ACR_DCEN; // Data cache enable
+ FLASH->ACR |= FLASH_ACR_LATENCY_5WS; // Flash 5 wait state
+
+ RCC->CFGR |= RCC_CFGR_HPRE_DIV1; // HCLK = SYSCLK
+ RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; // APB1 = HCLK/4
+ RCC->CFGR |= RCC_CFGR_PPRE2_DIV2; // APB2 = HCLK/2
+
+ RCC->CR &= ~RCC_CR_PLLON; // Disable PLL
+
+ // PLL configuration: VCO = HSI/M * N, Sysclk = VCO/P
+ RCC->PLLCFGR = ( 16ul | // PLL_M = 16
+ (384ul << 6) | // PLL_N = 384
+ ( 3ul << 16) | // PLL_P = 8
+ (RCC_PLLCFGR_PLLSRC_HSI) | // PLL_SRC = HSI
+ ( 8ul << 24) ); // PLL_Q = 8
+
+ RCC->CR |= RCC_CR_PLLON; // Enable PLL
+ while((RCC->CR & RCC_CR_PLLRDY) == 0) __NOP(); // Wait till PLL is ready
+
+ RCC->CFGR &= ~RCC_CFGR_SW; // Select PLL as system clock source
+ RCC->CFGR |= RCC_CFGR_SW_PLL;
+ while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); // Wait till PLL is system clock src
+}
+
+void StartTimers()
+{
+ ecl_timer_start(short_toggle, ECL_TIMER_START_DELAYED);
+ ecl_timer_start(swap_timers, ECL_TIMER_START_DELAYED);
+}
+
+void SwapTimers()
+{
+ static int state = 0;
+
+ if (!state)
+ {
+ ecl_timer_stop(short_toggle);
+ ecl_timer_start(long_toggle, ECL_TIMER_START_DELAYED);
+ }
+ else
+ {
+ ecl_timer_start(short_toggle, ECL_TIMER_START_DELAYED);
+ ecl_timer_stop(long_toggle);
+ }
+
+ state = !state;
+
+ ecl_timer_start(swap_timers, ECL_TIMER_START_DELAYED);
+}
+
+void LedToggle()
+{
+ static int state = 0;
+
+ if (state)
+ {
+ LED_On(0);
+ }
+ else
+ {
+ LED_Off(0);
+ }
+
+ state = !state;
+}
+
+int main()
+{
+ SystemCoreClockConfigure(); // configure HSI as System Clock
+ SystemCoreClockUpdate();
+
+ LED_Initialize();
+ Buttons_Initialize();
+
+ ecl_timer_init(timers, N_TIMERS);
+
+ // The LEDs will start flashing fast after 2 seconds.
+ // After another 5 seconds they will start flashing slower.
+ short_toggle = ecl_timer_register(LedToggle, 50, ECL_TIMER_REPEATING);
+ long_toggle = ecl_timer_register(LedToggle, 100, ECL_TIMER_REPEATING);
+ start_timers = ecl_timer_register(StartTimers, 2000, ECL_TIMER_SINGLE_SHOT);
+ swap_timers = ecl_timer_register(SwapTimers, 1500, ECL_TIMER_SINGLE_SHOT);
+
+ SysTick_Config(SystemCoreClock / 1000);
+
+ ecl_timer_enable(ECL_TIMER_ENABLED);
+
+ ecl_timer_start(start_timers, ECL_TIMER_START_DELAYED);
+
+ while (1)
+ {
+ __NOP();
+ }
+}
+
+void SysTick_Handler()
+{
+ const uint32_t TICK = 1;
+ static uint32_t nticks = TICK;
+
+ if (ecl_timer_tick(nticks))
+ {
+ nticks = TICK;
+ }
+ else
+ {
+ nticks += TICK;
+ }
+}
+
diff --git a/src/c/ecl_timer.c b/src/c/ecl_timer.c
new file mode 100644
index 00000000..29b5b17b
--- /dev/null
+++ b/src/c/ecl_timer.c
@@ -0,0 +1,398 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#include
+#include
+
+#include "ecl_timer.h"
+#include "ecl_timer_list.h"
+
+//*******************************************
+/// Default initialisation.
+//*******************************************
+void ecl_timer_data_init_default(struct ecl_timer_config* ptimer_data_)
+{
+ assert(ptimer_data_ != 0);
+
+ ptimer_data_->pcallback = 0;
+ ptimer_data_->period = 0;
+ ptimer_data_->delta = ECL_TIMER_INACTIVE;
+ ptimer_data_->id = ECL_TIMER_NO_TIMER;
+ ptimer_data_->previous = ECL_TIMER_NO_TIMER;
+ ptimer_data_->next = ECL_TIMER_NO_TIMER;
+ ptimer_data_->repeating = ECL_TIMER_REPEATING;
+}
+
+//*******************************************
+/// Parameterised initialisation.
+//*******************************************
+void ecl_timer_data_init(struct ecl_timer_config* ptimer_data_,
+ ecl_timer_id_t id_,
+ void (*pcallback_)(),
+ ecl_timer_time_t period_,
+ ecl_timer_mode_t repeating_)
+{
+ assert(ptimer_data_ != 0);
+ assert(pcallback_ != 0);
+
+ ptimer_data_->pcallback = pcallback_;
+ ptimer_data_->period = period_;
+ ptimer_data_->delta = ECL_TIMER_INACTIVE;
+ ptimer_data_->id = id_;
+ ptimer_data_->previous = ECL_TIMER_NO_TIMER;
+ ptimer_data_->next = ECL_TIMER_NO_TIMER;
+ ptimer_data_->repeating = repeating_;
+}
+
+//*******************************************
+/// Returns true if the timer is active.
+//*******************************************
+ecl_timer_result_t ecl_timer_is_active(struct ecl_timer_config* ptimer_data_)
+{
+ assert(ptimer_data_ != 0);
+
+ return (ptimer_data_->delta != ECL_TIMER_INACTIVE) ? ECL_TIMER_PASS : ECL_TIMER_FAIL;
+}
+
+//*******************************************
+/// Sets the timer to the inactive state.
+//*******************************************
+void ecl_set_timer_inactive(struct ecl_timer_config* ptimer_data_)
+{
+ assert(ptimer_data_ != 0);
+
+ ptimer_data_->delta = ECL_TIMER_INACTIVE;
+}
+
+struct ecl_time_config
+{
+ struct ecl_timer_config* ptimers;
+ uint_least8_t max_timers;
+ volatile ecl_timer_enable_t enabled;
+ ECL_TIMER_TIMER_SEMAPHORE process_semaphore;
+ volatile uint_least8_t registered_timers;
+};
+
+static struct ecl_time_config ecl;
+
+void ecl_timer_init(struct ecl_timer_config* ptimers_, uint_least8_t max_timers_)
+{
+ assert(ptimers_ != 0);
+
+ ecl.ptimers = ptimers_;
+ ecl.max_timers = max_timers_;
+ ecl.enabled = 0;
+ ecl.process_semaphore = 0;
+ ecl.registered_timers = 0;
+
+ int i;
+ for (i = 0; i < max_timers_; ++i)
+ {
+ ecl_timer_data_init_default(&ecl.ptimers[i]);
+ }
+
+ ecl_timer_list_init(ecl.ptimers);
+}
+
+//*******************************************
+/// Register a ptimer->
+//*******************************************
+ecl_timer_id_t ecl_timer_register(void (*pcallback_)(),
+ ecl_timer_time_t period_,
+ ecl_timer_mode_t repeating_)
+{
+ assert(pcallback_ != 0);
+ assert(ecl.ptimers != 0);
+
+ ecl_timer_id_t id = ECL_TIMER_NO_TIMER;
+
+ ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore);
+
+ int is_space = (ecl.registered_timers < ecl.max_timers);
+
+ if (is_space)
+ {
+ // Search for the free space.
+ uint_least8_t i;
+ for (i = 0; i < ecl.max_timers; ++i)
+ {
+ struct ecl_timer_config* ptimer = &ecl.ptimers[i];
+
+ if (ptimer->id == ECL_TIMER_NO_TIMER)
+ {
+ // Create in-place.
+ ecl_timer_data_init(ptimer, i, pcallback_, period_, repeating_);
+ ++ecl.registered_timers;
+ id = i;
+ break;
+ }
+ }
+ }
+
+ ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore);
+
+ return id;
+}
+
+//*******************************************
+/// Unregister a ptimer->
+//*******************************************
+ecl_timer_result_t ecl_timer_unregister(ecl_timer_id_t id_)
+{
+ assert(ecl.ptimers != 0);
+
+ ecl_timer_result_t result = ECL_TIMER_FAIL;
+
+ if (id_ != ECL_TIMER_NO_TIMER)
+ {
+ ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore);
+
+ struct ecl_timer_config* ptimer = &ecl.ptimers[id_];
+
+ if (ptimer->id != ECL_TIMER_NO_TIMER)
+ {
+ if (ecl_timer_is_active(ptimer))
+ {
+ ecl_timer_list_remove(ptimer->id, 0);
+
+ // Reset in-place.
+ ecl_timer_data_init_default(ptimer);
+ --ecl.registered_timers;
+
+ result = ECL_TIMER_PASS;
+ }
+ }
+
+ ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore);
+ }
+
+ return result;
+}
+
+//*******************************************
+/// Enable/disable the ptimer->
+//*******************************************
+void ecl_timer_enable(ecl_timer_enable_t state_)
+{
+ assert(ecl.ptimers != 0);
+ assert((state_ == ECL_TIMER_ENABLED) || (state_ == ECL_TIMER_DISABLED));
+
+ ecl.enabled = state_;
+}
+
+//*******************************************
+/// Get the enable/disable state.
+//*******************************************
+ecl_timer_result_t ecl_timer_is_running()
+{
+ return ecl.enabled;
+}
+
+//*******************************************
+/// Clears the timer of data.
+//*******************************************
+void ecl_timer_clear()
+{
+ ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore);
+
+ ecl_timer_list_clear();
+
+ int i;
+ for (i = 0; i < ecl.max_timers; ++i)
+ {
+ ecl_timer_data_init_default(&ecl.ptimers[i]);
+ }
+
+ ecl.registered_timers = 0;
+
+ ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore);
+}
+
+//*******************************************
+// Called by the timer service to indicate the
+// amount of time that has elapsed since the last successful call to 'tick'.
+// Returns true if the tick was processed, false if not.
+//*******************************************
+ecl_timer_result_t ecl_timer_tick(uint32_t count)
+{
+ assert(ecl.ptimers != 0);
+
+ if (ecl.enabled)
+ {
+ if (ECL_TIMER_PROCESSING_ENABLED(ecl.process_semaphore))
+ {
+ // We have something to do?
+ int has_active = !ecl_timer_list_empty();
+
+ if (has_active)
+ {
+ while (has_active && (count >= ecl_timer_list_front()->delta))
+ {
+ struct ecl_timer_config* ptimer = ecl_timer_list_front();
+
+ count -= ptimer->delta;
+
+ ecl_timer_list_remove(ptimer->id, 1);
+
+ if (ptimer->repeating)
+ {
+ // Reinsert the ptimer->
+ ptimer->delta = ptimer->period;
+ ecl_timer_list_insert(ptimer->id);
+ }
+
+ if (ptimer->pcallback != 0)
+ {
+ // Call the C callback.
+ (ptimer->pcallback)();
+ }
+
+ has_active = !ecl_timer_list_empty();
+ }
+
+ if (has_active)
+ {
+ // Subtract any remainder from the next due timeout.
+ ecl_timer_list_front()->delta -= count;
+ }
+ }
+
+ return ECL_TIMER_PASS;
+ }
+ }
+
+ return ECL_TIMER_FAIL;
+}
+
+//*******************************************
+/// Starts a timer
+//*******************************************
+ecl_timer_result_t ecl_timer_start(ecl_timer_id_t id_, ecl_timer_start_t immediate_)
+{
+ assert(ecl.ptimers != 0);
+
+ ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore);
+
+ ecl_timer_result_t result = ECL_TIMER_FAIL;
+
+ // Valid timer id?
+ if (id_ != ECL_TIMER_NO_TIMER)
+ {
+ struct ecl_timer_config* ptimer = &ecl.ptimers[id_];
+
+ // Registered timer?
+ if (ptimer->id != ECL_TIMER_NO_TIMER)
+ {
+ // Has a valid period.
+ if (ptimer->period != ECL_TIMER_INACTIVE)
+ {
+ if (ecl_timer_is_active(ptimer))
+ {
+ ecl_timer_list_remove(ptimer->id, 0);
+ }
+
+ ptimer->delta = immediate_ ? 0 : ptimer->period;
+ ecl_timer_list_insert(ptimer->id);
+
+ result = ECL_TIMER_PASS;
+ }
+ }
+ }
+
+ ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore);
+
+ return result;
+}
+
+//*******************************************
+/// Stops a timer
+//*******************************************
+ecl_timer_result_t ecl_timer_stop(ecl_timer_id_t id_)
+{
+ assert(ecl.ptimers != 0);
+
+ ECL_TIMER_DISABLE_PROCESSING(ecl.process_semaphore);
+
+ ecl_timer_result_t result = ECL_TIMER_FAIL;
+
+ // Valid timer id?
+ if (id_ != ECL_TIMER_NO_TIMER)
+ {
+ struct ecl_timer_config* ptimer = &ecl.ptimers[id_];
+
+ // Registered timer?
+ if (ptimer->id != ECL_TIMER_NO_TIMER)
+ {
+ if (ecl_timer_is_active(ptimer))
+ {
+ ecl_timer_list_remove(ptimer->id, 0);
+ result = ECL_TIMER_PASS;
+ }
+ }
+ }
+
+ ECL_TIMER_ENABLE_PROCESSING(ecl.process_semaphore);
+
+ return result;
+}
+
+//*******************************************
+/// Sets a timer's period.
+//*******************************************
+ecl_timer_result_t ecl_timer_set_period(ecl_timer_id_t id_, ecl_timer_time_t period_)
+{
+ assert(ecl.ptimers != 0);
+
+ if (ecl_timer_stop(id_))
+ {
+ ecl.ptimers[id_].period = period_;
+ return ecl_timer_start(id_, 0);
+ }
+
+ return ECL_TIMER_FAIL;
+}
+
+//*******************************************
+/// Sets a timer's mode.
+//*******************************************
+ecl_timer_result_t ecl_timer_set_mode(ecl_timer_id_t id_, ecl_timer_mode_t repeating_)
+{
+ assert(ecl.ptimers != 0);
+
+ if (ecl_timer_stop(id_))
+ {
+ ecl.ptimers[id_].repeating = repeating_;
+ return ecl_timer_start(id_, 0);
+ }
+
+ return ECL_TIMER_FAIL;
+}
+
+
+
+
diff --git a/src/c/ecl_timer.h b/src/c/ecl_timer.h
new file mode 100644
index 00000000..0d5e33e9
--- /dev/null
+++ b/src/c/ecl_timer.h
@@ -0,0 +1,118 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_C_TIMER_FRAMEWORK__
+#define __ETL_C_TIMER_FRAMEWORK__
+
+#include
+
+#include "ecl_user.h"
+
+// Pass/fail results.
+enum
+{
+ ECL_TIMER_FAIL = 0,
+ ECL_TIMER_PASS = 1,
+};
+
+typedef int ecl_timer_result_t;
+
+// Enable states.
+enum
+{
+ ECL_TIMER_DISABLED = ECL_TIMER_FAIL,
+ ECL_TIMER_ENABLED = ECL_TIMER_PASS
+};
+
+typedef int ecl_timer_enable_t;
+
+// Timer modes.
+enum
+{
+ ECL_TIMER_SINGLE_SHOT = 0,
+ ECL_TIMER_REPEATING = 1
+};
+
+typedef char ecl_timer_mode_t;
+
+// Timer start action.
+enum
+{
+ ECL_TIMER_START_DELAYED = 0,
+ ECL_TIMER_START_IMMEDIATE = 1
+};
+
+typedef char ecl_timer_start_t;
+
+// Timer identifiers.
+enum
+{
+ ECL_TIMER_NO_TIMER = 255
+};
+
+typedef uint_least8_t ecl_timer_id_t;
+
+// Timer times.
+#define ECL_TIMER_INACTIVE 0xFFFFFFFF
+
+typedef uint32_t ecl_timer_time_t;
+
+//*************************************************************************
+/// The configuration of a timer.
+//*************************************************************************
+struct ecl_timer_config
+{
+ void (*pcallback)();
+ ecl_timer_time_t period;
+ ecl_timer_time_t delta;
+ ecl_timer_id_t id;
+ uint_least8_t previous;
+ uint_least8_t next;
+ char repeating;
+};
+
+//*************************************************************************
+/// The API.
+//*************************************************************************
+void ecl_timer_data_init_default(struct ecl_timer_config* ptimer_data_);
+void ecl_timer_data_init(struct ecl_timer_config* ptimer_data_, ecl_timer_id_t id_, void(*pcallback_)(), ecl_timer_time_t period_, ecl_timer_mode_t repeating_);
+ecl_timer_result_t ecl_timer_is_active(struct ecl_timer_config* ptimer_data_);
+void ecl_set_timer_inactive(struct ecl_timer_config* ptimer_data_);
+void ecl_timer_init(struct ecl_timer_config* ptimers_, uint_least8_t max_timers_);
+ecl_timer_id_t ecl_timer_register(void(*pcallback_)(), ecl_timer_time_t period_, ecl_timer_mode_t repeating_);
+ecl_timer_result_t ecl_timer_unregister(ecl_timer_id_t id_);
+void ecl_timer_enable(ecl_timer_enable_t state_);
+ecl_timer_result_t ecl_timer_is_running(void);
+void ecl_timer_clear(void);
+ecl_timer_result_t ecl_timer_tick(uint32_t count);
+ecl_timer_result_t ecl_timer_start(ecl_timer_id_t id_, ecl_timer_start_t immediate_);
+ecl_timer_result_t ecl_timer_stop(ecl_timer_id_t id_);
+ecl_timer_result_t ecl_timer_set_period(ecl_timer_id_t id_, ecl_timer_time_t period_);
+ecl_timer_result_t ecl_timer_set_mode(ecl_timer_id_t id_, ecl_timer_mode_t repeating_);
+
+#endif
diff --git a/src/c/ecl_timer_list.c b/src/c/ecl_timer_list.c
new file mode 100644
index 00000000..1e728ff0
--- /dev/null
+++ b/src/c/ecl_timer_list.c
@@ -0,0 +1,201 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#include "ecl_timer.h"
+#include "ecl_timer_list.h"
+
+//*************************************************************************
+/// A specialised intrusive linked list for timer data.
+//*************************************************************************
+
+static ecl_timer_id_t head;
+static ecl_timer_id_t tail;
+static ecl_timer_id_t current;
+
+struct ecl_timer_config* ptimers;
+
+void ecl_timer_list_init(struct ecl_timer_config* const ptimers_)
+{
+ ptimers = ptimers_;
+ head = ECL_TIMER_NO_TIMER;
+ tail = ECL_TIMER_NO_TIMER;
+ current = ECL_TIMER_NO_TIMER;
+}
+
+//*******************************
+struct ecl_timer_config* ecl_timer_list_front()
+{
+ return &ptimers[head];
+}
+
+//*******************************
+ecl_timer_id_t ecl_timer_list_begin()
+{
+ current = head;
+ return current;
+}
+
+//*******************************
+ecl_timer_id_t ecl_timer_list_previous(ecl_timer_id_t last)
+{
+ current = ptimers[last].previous;
+ return current;
+}
+
+//*******************************
+ecl_timer_id_t ecl_timer_list_next(ecl_timer_id_t last)
+{
+ current = ptimers[last].next;
+ return current;
+}
+
+//*******************************
+int ecl_timer_list_empty()
+{
+ return head == ECL_TIMER_NO_TIMER;
+}
+
+//*******************************
+// Inserts the timer at the correct delta position
+//*******************************
+void ecl_timer_list_insert(ecl_timer_id_t id_)
+{
+ struct ecl_timer_config* ptimer = &ptimers[id_];
+
+ if (head == ECL_TIMER_NO_TIMER)
+ {
+ // No entries yet.
+ head = id_;
+ tail = id_;
+ ptimer->previous = ECL_TIMER_NO_TIMER;
+ ptimer->next = ECL_TIMER_NO_TIMER;
+ }
+ else
+ {
+ // We already have entries.
+ ecl_timer_id_t test_id = ecl_timer_list_begin();
+
+ while (test_id != ECL_TIMER_NO_TIMER)
+ {
+ struct ecl_timer_config* ptest = &ptimers[test_id];
+
+ // Find the correct place to insert.
+ if (ptimer->delta <= ptest->delta)
+ {
+ if (ptest->id == head)
+ {
+ head = ptimer->id;
+ }
+
+ // Insert before ptest->
+ ptimer->previous = ptest->previous;
+ ptest->previous = ptimer->id;
+ ptimer->next = ptest->id;
+
+ // Adjust the next delta to compensate.
+ ptest->delta -= ptimer->delta;
+
+ if (ptimer->previous != ECL_TIMER_NO_TIMER)
+ {
+ ptimers[ptimer->previous].next = ptimer->id;
+ }
+ break;
+ }
+ else
+ {
+ ptimer->delta -= ptest->delta;
+ }
+
+ test_id = ecl_timer_list_next(test_id);
+ }
+
+ // Reached the end?
+ if (test_id == ECL_TIMER_NO_TIMER)
+ {
+ // Tag on to the tail.
+ ptimers[tail].next = ptimer->id;
+ ptimer->previous = tail;
+ ptimer->next = ECL_TIMER_NO_TIMER;
+ tail = ptimer->id;
+ }
+ }
+}
+
+//*******************************
+void ecl_timer_list_remove(ecl_timer_id_t id_, int has_expired)
+{
+ struct ecl_timer_config* ptimer = &ptimers[id_];
+
+ if (head == id_)
+ {
+ head = ptimer->next;
+ }
+ else
+ {
+ ptimers[ptimer->previous].next = ptimer->next;
+ }
+
+ if (tail == id_)
+ {
+ tail = ptimer->previous;
+ }
+ else
+ {
+ ptimers[ptimer->next].previous = ptimer->previous;
+ }
+
+ if (!has_expired)
+ {
+ // Adjust the next delta.
+ if (ptimer->next != ECL_TIMER_NO_TIMER)
+ {
+ ptimers[ptimer->next].delta += ptimer->delta;
+ }
+ }
+
+ ptimer->previous = ECL_TIMER_NO_TIMER;
+ ptimer->next = ECL_TIMER_NO_TIMER;
+ ptimer->delta = ECL_TIMER_INACTIVE;
+}
+
+//*******************************
+void ecl_timer_list_clear()
+{
+ ecl_timer_id_t id = ecl_timer_list_begin();
+
+ while (id != ECL_TIMER_NO_TIMER)
+ {
+ struct ecl_timer_config* ptimer = &ptimers[id];
+ id = ecl_timer_list_next(id);
+ ptimer->next = ECL_TIMER_NO_TIMER;
+ }
+
+ head = ECL_TIMER_NO_TIMER;
+ tail = ECL_TIMER_NO_TIMER;
+ current = ECL_TIMER_NO_TIMER;
+}
diff --git a/src/c/ecl_timer_list.h b/src/c/ecl_timer_list.h
new file mode 100644
index 00000000..7662b48e
--- /dev/null
+++ b/src/c/ecl_timer_list.h
@@ -0,0 +1,44 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_C_TIMER_FRAMEWORK_LIST__
+#define __ETL_C_TIMER_FRAMEWORK_LIST__
+
+#include "ecl_timer.h"
+
+void ecl_timer_list_init(struct ecl_timer_config* const ptimers_);
+struct ecl_timer_config* ecl_timer_list_front(void);
+ecl_timer_id_t ecl_timer_list_begin(void);
+ecl_timer_id_t ecl_timer_list_previous(ecl_timer_id_t last);
+ecl_timer_id_t ecl_timer_list_next(ecl_timer_id_t last);
+int ecl_timer_list_empty(void);
+void ecl_timer_list_insert(ecl_timer_id_t id_);
+void ecl_timer_list_remove(ecl_timer_id_t id_, int has_expired);
+void ecl_timer_list_clear(void);
+
+#endif
diff --git a/test/codeblocks/ETL.cbp b/test/codeblocks/ETL.cbp
index d25c0e6f..b3b13bf4 100644
--- a/test/codeblocks/ETL.cbp
+++ b/test/codeblocks/ETL.cbp
@@ -50,6 +50,7 @@
+
@@ -58,6 +59,14 @@
+
+
+
+
+
+
+
+
@@ -258,6 +267,7 @@
+
@@ -269,6 +279,7 @@
+
diff --git a/test/ecl_user.h b/test/ecl_user.h
new file mode 100644
index 00000000..637089e4
--- /dev/null
+++ b/test/ecl_user.h
@@ -0,0 +1,50 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ECL_USER__
+#define __ECL_USER__
+
+#include "platform.h"
+
+#include
+
+#if defined(ETL_COMPILER_GCC)
+ #define ECL_TIMER_TIMER_SEMAPHORE uint32_t
+ #define ECL_TIMER_DISABLE_PROCESSING(x) __sync_fetch_and_add(&x, 1)
+ #define ECL_TIMER_ENABLE_PROCESSING(x) __sync_fetch_and_sub(&x, 1)
+ #define ECL_TIMER_PROCESSING_ENABLED(x) (__sync_fetch_and_add(&x, 0) == 0)
+#else
+ #include
+
+ #define ECL_TIMER_TIMER_SEMAPHORE uint32_t
+ #define ECL_TIMER_DISABLE_PROCESSING(x) InterlockedIncrement((volatile long*)&x)
+ #define ECL_TIMER_ENABLE_PROCESSING(x) InterlockedDecrement((volatile long*)&x)
+ #define ECL_TIMER_PROCESSING_ENABLED(x) (InterlockedAdd((volatile long*)&x, 0) == 0)
+#endif
+
+#endif
diff --git a/test/test_c_timer_framework.cpp b/test/test_c_timer_framework.cpp
new file mode 100644
index 00000000..c96a712b
--- /dev/null
+++ b/test/test_c_timer_framework.cpp
@@ -0,0 +1,681 @@
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+https://www.etlcpp.com
+
+Copyright(c) 2017 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#include "UnitTest++.h"
+#include "ExtraCheckMacros.h"
+
+#include "platform.h"
+
+extern "C"
+{
+ #include "ecl_timer.h"
+}
+
+#include
+#include
+#include
+#include
+
+#if defined(ETL_COMPILER_MICROSOFT)
+#include
+#endif
+
+#define REALTIME_TEST 0
+
+namespace
+{
+ uint64_t ticks = 0;
+
+ std::vector callback_list1;
+ std::vector callback_list2;
+ std::vector callback_list3;
+
+ void callback1()
+ {
+ callback_list1.push_back(ticks);
+ }
+
+ void callback2()
+ {
+ callback_list2.push_back(ticks);
+ }
+
+ void callback3()
+ {
+ callback_list3.push_back(ticks);
+ }
+
+ void callback3b()
+ {
+ callback_list3.push_back(ticks);
+
+ ecl_timer_start(2, ECL_TIMER_START_DELAYED);
+ ecl_timer_start(1, ECL_TIMER_START_DELAYED);
+ }
+
+ const int NTIMERS = 3;
+ struct ecl_timer_config timers[NTIMERS];
+
+ SUITE(test_ecl_timer)
+ {
+ //=========================================================================
+ TEST(ecl_timer_too_many_timers)
+ {
+ ecl_timer_init(timers, NTIMERS);
+
+ ecl_timer_id_t id1 = ecl_timer_register(callback1, 37, ECL_TIMER_SINGLE_SHOT);
+ ecl_timer_id_t id2 = ecl_timer_register(callback2, 23, ECL_TIMER_SINGLE_SHOT);
+ ecl_timer_id_t id3 = ecl_timer_register(callback3, 11, ECL_TIMER_SINGLE_SHOT);
+ ecl_timer_id_t id4 = ecl_timer_register(callback3, 11, ECL_TIMER_SINGLE_SHOT);
+
+ CHECK(id1 != ECL_TIMER_NO_TIMER);
+ CHECK(id2 != ECL_TIMER_NO_TIMER);
+ CHECK(id3 != ECL_TIMER_NO_TIMER);
+ CHECK(id4 == ECL_TIMER_NO_TIMER);
+
+ ecl_timer_clear();
+ id3 = ecl_timer_register(callback3, 11, ECL_TIMER_SINGLE_SHOT);
+ CHECK(id3 != ECL_TIMER_NO_TIMER);
+ }
+
+ //=========================================================================
+ TEST(ecl_timer_one_shot)
+ {
+ ecl_timer_init(timers, NTIMERS);
+
+ ecl_timer_id_t id1 = ecl_timer_register(callback1, 37, ECL_TIMER_SINGLE_SHOT);
+ ecl_timer_id_t id2 = ecl_timer_register(callback2, 23, ECL_TIMER_SINGLE_SHOT);
+ ecl_timer_id_t id3 = ecl_timer_register(callback3, 11, ECL_TIMER_SINGLE_SHOT);
+
+ callback_list1.clear();
+ callback_list2.clear();
+ callback_list3.clear();
+
+ ecl_timer_enable(ECL_TIMER_ENABLED);
+
+ ecl_timer_start(id1, ECL_TIMER_START_DELAYED);
+ ecl_timer_start(id2, ECL_TIMER_START_DELAYED);
+ ecl_timer_start(id3, ECL_TIMER_START_DELAYED);
+
+ ecl_timer_enable(ECL_TIMER_ENABLED);
+
+ ticks = 0;
+
+ const uint32_t step = 1;
+
+ while (ticks <= 100U)
+ {
+ ticks += step;
+ ecl_timer_tick(step);
+ }
+
+ std::vector compare1 = { 37 };
+ std::vector compare2 = { 23 };
+ std::vector compare3 = { 11 };
+
+ CHECK(callback_list1.size() != 0);
+ CHECK(callback_list2.size() != 0);
+ CHECK(callback_list3.size() != 0);
+
+ CHECK_ARRAY_EQUAL(compare1.data(), callback_list1.data(), compare1.size());
+ CHECK_ARRAY_EQUAL(compare2.data(), callback_list2.data(), compare2.size());
+ CHECK_ARRAY_EQUAL(compare3.data(), callback_list3.data(), compare3.size());
+ }
+
+ //=========================================================================
+ TEST(ecl_timer_repeating)
+ {
+ ecl_timer_init(timers, NTIMERS);
+
+ ecl_timer_id_t id1 = ecl_timer_register(callback1, 37, ECL_TIMER_REPEATING);
+ ecl_timer_id_t id2 = ecl_timer_register(callback2, 23, ECL_TIMER_REPEATING);
+ ecl_timer_id_t id3 = ecl_timer_register(callback3, 11, ECL_TIMER_REPEATING);
+
+ callback_list1.clear();
+ callback_list2.clear();
+ callback_list3.clear();
+
+ ecl_timer_enable(ECL_TIMER_ENABLED);
+
+ ecl_timer_start(id1, ECL_TIMER_START_DELAYED);
+ ecl_timer_start(id2, ECL_TIMER_START_DELAYED);
+ ecl_timer_start(id3, ECL_TIMER_START_DELAYED);
+
+ ecl_timer_enable(ECL_TIMER_ENABLED);
+
+ ticks = 0;
+
+ const uint32_t step = 1;
+
+ while (ticks <= 100U)
+ {
+ ticks += step;
+ ecl_timer_tick(step);
+ }
+
+ std::vector compare1 = { 37, 74 };
+ std::vector compare2 = { 23, 46, 69, 92 };
+ std::vector compare3 = { 11, 22, 33, 44, 55, 66, 77, 88, 99 };
+
+ CHECK(callback_list1.size() != 0);
+ CHECK(callback_list2.size() != 0);
+ CHECK(callback_list3.size() != 0);
+
+ CHECK_ARRAY_EQUAL(compare1.data(), callback_list1.data(), compare1.size());
+ CHECK_ARRAY_EQUAL(compare2.data(), callback_list2.data(), compare2.size());
+ CHECK_ARRAY_EQUAL(compare3.data(), callback_list3.data(), compare3.size());
+ }
+
+ //=========================================================================
+ TEST(ecl_timer_repeating_bigger_step)
+ {
+ ecl_timer_init(timers, NTIMERS);
+
+ ecl_timer_id_t id1 = ecl_timer_register(callback1, 37, ECL_TIMER_REPEATING);
+ ecl_timer_id_t id2 = ecl_timer_register(callback2, 23, ECL_TIMER_REPEATING);
+ ecl_timer_id_t id3 = ecl_timer_register(callback3, 11, ECL_TIMER_REPEATING);
+
+ callback_list1.clear();
+ callback_list2.clear();
+ callback_list3.clear();
+
+ ecl_timer_enable(ECL_TIMER_ENABLED);
+
+ ecl_timer_start(id1, ECL_TIMER_START_DELAYED);
+ ecl_timer_start(id2, ECL_TIMER_START_DELAYED);
+ ecl_timer_start(id3, ECL_TIMER_START_DELAYED);
+
+ ecl_timer_enable(ECL_TIMER_ENABLED);
+
+ ticks = 0;
+
+ const uint32_t step = 5;
+
+ while (ticks <= 100U)
+ {
+ ticks += step;
+ ecl_timer_tick(step);
+ }
+
+ std::vector compare1 = { 40, 75 };
+ std::vector compare2 = { 25, 50, 70, 95 };
+ std::vector compare3 = { 15, 25, 35, 45, 55, 70, 80, 90, 100 };
+
+ CHECK(callback_list1.size() != 0);
+ CHECK(callback_list2.size() != 0);
+ CHECK(callback_list3.size() != 0);
+
+ CHECK_ARRAY_EQUAL(compare1.data(), callback_list1.data(), compare1.size());
+ CHECK_ARRAY_EQUAL(compare2.data(), callback_list2.data(), compare2.size());
+ CHECK_ARRAY_EQUAL(compare3.data(), callback_list3.data(), compare3.size());
+ }
+
+ //=========================================================================
+ TEST(ecl_timer_repeating_stop_start)
+ {
+ ecl_timer_init(timers, NTIMERS);
+
+ ecl_timer_id_t id1 = ecl_timer_register(callback1, 37, ECL_TIMER_REPEATING);
+ ecl_timer_id_t id2 = ecl_timer_register(callback2, 23, ECL_TIMER_REPEATING);
+ ecl_timer_id_t id3 = ecl_timer_register(callback3, 11, ECL_TIMER_REPEATING);
+
+ callback_list1.clear();
+ callback_list2.clear();
+ callback_list3.clear();
+
+ ecl_timer_enable(ECL_TIMER_ENABLED);
+
+ ecl_timer_start(id2, ECL_TIMER_START_DELAYED);
+ ecl_timer_start(id3, ECL_TIMER_START_DELAYED);
+
+ ecl_timer_enable(ECL_TIMER_ENABLED);
+
+ ticks = 0;
+
+ const uint32_t step = 1;
+
+ while (ticks <= 100U)
+ {
+ if (ticks == 40)
+ {
+ ecl_timer_start(id1, ECL_TIMER_START_DELAYED);
+ ecl_timer_stop(id2);
+ }
+
+ if (ticks == 80)
+ {
+ ecl_timer_stop(id1);
+ ecl_timer_start(id2, ECL_TIMER_START_DELAYED);
+ }
+
+ ticks += step;
+ ecl_timer_tick(step);
+ }
+
+ std::vector compare1 = { 77 };
+ std::vector compare2 = { 23 };
+ std::vector compare3 = { 11, 22, 33, 44, 55, 66, 77, 88, 99 };
+
+ CHECK(callback_list1.size() != 0);
+ CHECK(callback_list2.size() != 0);
+ CHECK(callback_list3.size() != 0);
+
+ CHECK_ARRAY_EQUAL(compare1.data(), callback_list1.data(), compare1.size());
+ CHECK_ARRAY_EQUAL(compare2.data(), callback_list2.data(), compare2.size());
+ CHECK_ARRAY_EQUAL(compare3.data(), callback_list3.data(), compare3.size());
+ }
+
+ //=========================================================================
+ TEST(ecl_timer_timer_starts_timer_small_step)
+ {
+ ecl_timer_init(timers, NTIMERS);
+
+ ecl_timer_id_t id1 = ecl_timer_register(callback3b, 100, ECL_TIMER_SINGLE_SHOT);
+ ecl_timer_id_t id2 = ecl_timer_register(callback3, 10, ECL_TIMER_SINGLE_SHOT);
+ ecl_timer_id_t id3 = ecl_timer_register(callback3, 22, ECL_TIMER_SINGLE_SHOT);
+
+ (void)id2;
+ (void)id3;
+
+ callback_list3.clear();
+
+ ecl_timer_start(id1, ECL_TIMER_START_DELAYED);
+
+ ecl_timer_enable(ECL_TIMER_ENABLED);
+
+ ticks = 0;
+
+ const uint32_t step = 1;
+
+ while (ticks <= 200U)
+ {
+ ticks += step;
+ ecl_timer_tick(step);
+ }
+
+ std::vector compare3 = { 100, 110, 122 };
+
+ CHECK(callback_list3.size() != 0);
+
+ CHECK_ARRAY_EQUAL(compare3.data(), callback_list3.data(), compare3.size());
+ }
+
+ //=========================================================================
+ TEST(ecl_timer_timer_starts_timer_big_step)
+ {
+ ecl_timer_init(timers, NTIMERS);
+
+ ecl_timer_id_t id1 = ecl_timer_register(callback3b, 100, ECL_TIMER_SINGLE_SHOT);
+ ecl_timer_id_t id2 = ecl_timer_register(callback3, 10, ECL_TIMER_SINGLE_SHOT);
+ ecl_timer_id_t id3 = ecl_timer_register(callback3, 22, ECL_TIMER_SINGLE_SHOT);
+
+ (void)id2;
+ (void)id3;
+
+ callback_list3.clear();
+
+ ecl_timer_start(id1, ECL_TIMER_START_DELAYED);
+
+ ecl_timer_enable(ECL_TIMER_ENABLED);
+
+ ticks = 0;
+
+ const uint32_t step = 3;
+
+ while (ticks <= 200U)
+ {
+ ticks += step;
+ ecl_timer_tick(step);
+ }
+
+ std::vector compare3 = { 102, 111, 123 };
+
+ CHECK(callback_list3.size() != 0);
+
+ CHECK_ARRAY_EQUAL(compare3.data(), callback_list3.data(), compare3.size());
+ }
+
+
+ //=========================================================================
+ TEST(ecl_timer_repeating_register_unregister)
+ {
+ ecl_timer_init(timers, NTIMERS);
+
+ ecl_timer_id_t id1;
+ ecl_timer_id_t id2 = ecl_timer_register(callback2, 23, ECL_TIMER_REPEATING);
+ ecl_timer_id_t id3 = ecl_timer_register(callback3, 11, ECL_TIMER_REPEATING);
+
+ callback_list1.clear();
+ callback_list2.clear();
+ callback_list3.clear();
+
+ ecl_timer_start(id3, ECL_TIMER_START_DELAYED);
+ ecl_timer_start(id2, ECL_TIMER_START_DELAYED);
+
+ ecl_timer_enable(ECL_TIMER_ENABLED);
+
+ ticks = 0;
+
+ const uint32_t step = 1;
+
+ while (ticks <= 100U)
+ {
+ if (ticks == 40)
+ {
+ ecl_timer_unregister(id2);
+
+ id1 = ecl_timer_register(callback1, 37, ECL_TIMER_REPEATING);
+ ecl_timer_start(id1, ECL_TIMER_START_DELAYED);
+ }
+
+ ticks += step;
+ ecl_timer_tick(step);
+ }
+
+ std::vector compare1 = { 77 };
+ std::vector compare2 = { 23 };
+ std::vector compare3 = { 11, 22, 33, 44, 55, 66, 77, 88, 99 };
+
+ CHECK(callback_list1.size() != 0);
+ CHECK(callback_list2.size() != 0);
+ CHECK(callback_list3.size() != 0);
+
+ CHECK_ARRAY_EQUAL(compare1.data(), callback_list1.data(), compare1.size());
+ CHECK_ARRAY_EQUAL(compare2.data(), callback_list2.data(), compare2.size());
+ CHECK_ARRAY_EQUAL(compare3.data(), callback_list3.data(), compare3.size());
+ }
+
+ //=========================================================================
+ TEST(ecl_timer_repeating_clear)
+ {
+ ecl_timer_init(timers, NTIMERS);
+
+ ecl_timer_id_t id1 = ecl_timer_register(callback1, 37, ECL_TIMER_REPEATING);
+ ecl_timer_id_t id2 = ecl_timer_register(callback2, 23, ECL_TIMER_REPEATING);
+ ecl_timer_id_t id3 = ecl_timer_register(callback3, 11, ECL_TIMER_REPEATING);
+
+ callback_list1.clear();
+ callback_list2.clear();
+ callback_list3.clear();
+
+ ecl_timer_enable(ECL_TIMER_ENABLED);
+
+ ecl_timer_start(id1, ECL_TIMER_START_DELAYED);
+ ecl_timer_start(id2, ECL_TIMER_START_DELAYED);
+ ecl_timer_start(id3, ECL_TIMER_START_DELAYED);
+
+ ecl_timer_enable(ECL_TIMER_ENABLED);
+
+ ticks = 0;
+
+ const uint32_t step = 1;
+
+ while (ticks <= 100U)
+ {
+ ticks += step;
+
+ if (ticks == 40)
+ {
+ ecl_timer_clear();
+ }
+
+ ecl_timer_tick(step);
+ }
+
+ std::vector compare1 = { 37 };
+ std::vector compare2 = { 23 };
+ std::vector compare3 = { 11, 22, 33, 44, 55, 66, 77, 88, 99 };
+
+ CHECK(callback_list1.size() != 0);
+ CHECK(callback_list2.size() != 0);
+ CHECK(callback_list3.size() != 0);
+
+ CHECK_ARRAY_EQUAL(compare1.data(), callback_list1.data(), compare1.size());
+ CHECK_ARRAY_EQUAL(compare2.data(), callback_list2.data(), compare2.size());
+ CHECK_ARRAY_EQUAL(compare3.data(), callback_list3.data(), compare3.size());
+ }
+
+ //=========================================================================
+ TEST(ecl_timer_delayed_immediate)
+ {
+ ecl_timer_init(timers, NTIMERS);
+
+ ecl_timer_id_t id1 = ecl_timer_register(callback1, 37, ECL_TIMER_REPEATING);
+ ecl_timer_id_t id2 = ecl_timer_register(callback2, 23, ECL_TIMER_REPEATING);
+ ecl_timer_id_t id3 = ecl_timer_register(callback3, 11, ECL_TIMER_REPEATING);
+
+ callback_list1.clear();
+ callback_list2.clear();
+ callback_list3.clear();
+
+ ecl_timer_enable(ECL_TIMER_ENABLED);
+
+ ticks = 5;
+ ecl_timer_tick(uint32_t(ticks));
+
+ ecl_timer_start(id1, ECL_TIMER_START_IMMEDIATE);
+ ecl_timer_start(id2, ECL_TIMER_START_IMMEDIATE);
+ ecl_timer_start(id3, ECL_TIMER_START_DELAYED);
+
+ const uint32_t step = 1;
+
+ while (ticks <= 100U)
+ {
+ ticks += step;
+ ecl_timer_tick(step);
+ }
+
+ std::vector compare1 = { 6, 42, 79 };
+ std::vector compare2 = { 6, 28, 51, 74, 97 };
+ std::vector compare3 = { 16, 27, 38, 49, 60, 71, 82, 93 };
+
+ CHECK(callback_list1.size() != 0);
+ CHECK(callback_list2.size() != 0);
+ CHECK(callback_list3.size() != 0);
+
+ CHECK_ARRAY_EQUAL(compare1.data(), callback_list1.data(), compare1.size());
+ CHECK_ARRAY_EQUAL(compare2.data(), callback_list2.data(), compare2.size());
+ CHECK_ARRAY_EQUAL(compare3.data(), callback_list3.data(), compare3.size());
+ }
+
+ //=========================================================================
+ TEST(ecl_timer_one_shot_big_step_short_delay_insert)
+ {
+ ecl_timer_init(timers, NTIMERS);
+
+ ecl_timer_id_t id1 = ecl_timer_register(callback1, 15, ECL_TIMER_SINGLE_SHOT);
+ ecl_timer_id_t id2 = ecl_timer_register(callback2, 5, ECL_TIMER_REPEATING);
+
+ callback_list1.clear();
+ callback_list2.clear();
+
+ ecl_timer_start(id1, ECL_TIMER_START_DELAYED);
+ ecl_timer_start(id2, ECL_TIMER_START_DELAYED);
+
+ ecl_timer_enable(ECL_TIMER_ENABLED);
+
+ ticks = 0;
+
+ const uint32_t step = 11;
+
+ ticks += step;
+ ecl_timer_tick(step);
+
+ ticks += step;
+ ecl_timer_tick(step);
+
+ std::vector compare1 = { 22 };
+ std::vector compare2 = { 11, 11, 22, 22 };
+
+ CHECK(callback_list1.size() != 0);
+ CHECK(callback_list2.size() != 0);
+
+ CHECK_ARRAY_EQUAL(compare1.data(), callback_list1.data(), compare1.size());
+ CHECK_ARRAY_EQUAL(compare2.data(), callback_list2.data(), compare2.size());
+ }
+
+ //=========================================================================
+ TEST(ecl_timer_one_shot_empty_list_huge_tick_before_insert)
+ {
+ ecl_timer_init(timers, NTIMERS);
+
+ ecl_timer_id_t id1 = ecl_timer_register(callback1, 5, ECL_TIMER_SINGLE_SHOT);
+
+ callback_list1.clear();
+
+ ecl_timer_start(id1, ECL_TIMER_START_DELAYED);
+
+ ecl_timer_enable(ECL_TIMER_ENABLED);
+
+ ticks = 0;
+
+ const uint32_t step = 5;
+
+ for (uint32_t i = 0; i < step; ++i)
+ {
+ ++ticks;
+ ecl_timer_tick(1);
+ }
+
+ // Huge tick count.
+ ecl_timer_tick(UINT32_MAX - step + 1);
+
+ ecl_timer_start(id1, ECL_TIMER_START_DELAYED);
+
+ for (uint32_t i = 0; i < step; ++i)
+ {
+ ++ticks;
+ ecl_timer_tick(1);
+ }
+ std::vector compare1 = { 5, 10 };
+
+ CHECK(callback_list1.size() != 0);
+
+ CHECK_ARRAY_EQUAL(compare1.data(), callback_list1.data(), compare1.size());
+ }
+
+ //=========================================================================
+#if REALTIME_TEST
+
+ #if defined(ETL_TARGET_OS_WINDOWS) // Only Windows priority is currently supported
+ #define RAISE_THREAD_PRIORITY SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)
+ #define FIX_PROCESSOR_AFFINITY SetThreadAffinityMask(GetCurrentThread(), 1);
+ #else
+ #error No thread priority modifier defined
+ #endif
+
+ void timer_event()
+ {
+ const uint32_t TICK = 1;
+ uint32_t tick = TICK;
+ ticks = 1;
+
+ RAISE_THREAD_PRIORITY;
+ FIX_PROCESSOR_AFFINITY;
+
+ while (ticks <= 1000)
+ {
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+
+ if (ecl_timer_tick(tick))
+ {
+ tick = TICK;
+ }
+ else
+ {
+ tick += TICK;
+ }
+
+ ++ticks;
+ }
+ }
+
+ TEST(ecl_timer_threads)
+ {
+ FIX_PROCESSOR_AFFINITY;
+
+ ecl_timer_init(timers, NTIMERS);
+
+ ecl_timer_id_t id1 = ecl_timer_register(callback1, 400, ECL_TIMER_SINGLE_SHOT);
+ ecl_timer_id_t id2 = ecl_timer_register(callback2, 100, ECL_TIMER_REPEATING);
+ ecl_timer_id_t id3 = ecl_timer_register(callback3, 10, ECL_TIMER_REPEATING);
+
+ callback_list1.clear();
+ callback_list2.clear();
+ callback_list3.clear();
+
+ ecl_timer_start(id1, ECL_TIMER_START_DELAYED);
+ ecl_timer_start(id2, ECL_TIMER_START_DELAYED);
+
+ ecl_timer_enable(ECL_TIMER_ENABLED);
+
+ std::thread t1(timer_event);
+
+ bool restart_1 = true;
+
+ while (ticks <= 1000U)
+ {
+ if ((ticks > 200U) && (ticks < 500U))
+ {
+ ecl_timer_stop(id3);
+ }
+
+ if ((ticks > 600U) && (ticks < 800U))
+ {
+ ecl_timer_start(id3, ECL_TIMER_START_DELAYED);
+ }
+
+ if ((ticks > 500U) && restart_1)
+ {
+ ecl_timer_start(id1, ECL_TIMER_START_DELAYED);
+ restart_1 = false;
+ }
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ }
+
+ //Join the thread with the main thread
+ t1.join();
+
+ CHECK_EQUAL(2U, callback_list1.size());
+ CHECK_EQUAL(10U, callback_list2.size());
+ CHECK(callback_list3.size() < 65U);
+
+ std::vector compare1 = { 400, 900 };
+ std::vector compare2 = { 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 };
+
+ CHECK(callback_list1.size() != 0);
+ CHECK(callback_list2.size() != 0);
+ CHECK(callback_list3.size() != 0);
+
+ //CHECK_ARRAY_EQUAL(compare1.data(), callback_list1.data(), min(compare1.size(), callback_list1.size()));
+ //CHECK_ARRAY_EQUAL(compare2.data(), callback_list2.data(), min(compare2.size(), callback_list2.size()));
+ }
+#endif
+ };
+}
diff --git a/test/vs2017/etl.vcxproj b/test/vs2017/etl.vcxproj
index 40bba69d..adb06e25 100644
--- a/test/vs2017/etl.vcxproj
+++ b/test/vs2017/etl.vcxproj
@@ -74,7 +74,7 @@
Level3
Disabled
WIN32;_DEBUG;_CONSOLE;_LIB;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
- ../../unittest-cpp/UnitTest++/;../../src;../../test
+ ../../unittest-cpp/UnitTest++/;../../src;../../src/c;../../test
@@ -93,7 +93,7 @@
Level3
Disabled
WIN32;_DEBUG;_CONSOLE;_LIB;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
- ../../unittest-cpp/UnitTest++/;../../src;../../test
+ ../../unittest-cpp/UnitTest++/;../../src;../../src/c;../../test
@@ -136,6 +136,8 @@
+
+
@@ -291,12 +293,15 @@
+
+
+
@@ -344,6 +349,7 @@
+
false
diff --git a/test/vs2017/etl.vcxproj.filters b/test/vs2017/etl.vcxproj.filters
index 294cdfd0..da20846f 100644
--- a/test/vs2017/etl.vcxproj.filters
+++ b/test/vs2017/etl.vcxproj.filters
@@ -52,6 +52,12 @@
{0a77d88b-f9f0-456a-be4b-c0a0ce6b437b}
+
+ {1fdf39d9-079e-4404-a24a-6d5cb30def6a}
+
+
+ {4ac80fd1-3eca-4775-8695-eb1ea39c93f1}
+
@@ -552,6 +558,15 @@
ETL\Utilities\Atomic
+
+ ECL
+
+
+ ECL
+
+
+ Source Files\ECL
+
@@ -917,6 +932,15 @@
Source Files
+
+ ECL
+
+
+ ECL
+
+
+ Source Files\ECL
+