Kinda works
This commit is contained in:
parent
f3d345e2e3
commit
662a7a9b12
40 changed files with 2851 additions and 26 deletions
60
.cproject
60
.cproject
|
@ -51,6 +51,9 @@
|
||||||
<listOptionValue builtIn="false" value="../Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F"/>
|
<listOptionValue builtIn="false" value="../Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F"/>
|
||||||
<listOptionValue builtIn="false" value="../Drivers/CMSIS/Device/ST/STM32F4xx/Include"/>
|
<listOptionValue builtIn="false" value="../Drivers/CMSIS/Device/ST/STM32F4xx/Include"/>
|
||||||
<listOptionValue builtIn="false" value="../Drivers/CMSIS/Include"/>
|
<listOptionValue builtIn="false" value="../Drivers/CMSIS/Include"/>
|
||||||
|
<listOptionValue builtIn="false" value="../platforms/firmware"/>
|
||||||
|
<listOptionValue builtIn="false" value="../components"/>
|
||||||
|
<listOptionValue builtIn="false" value="../Application"/>
|
||||||
</option>
|
</option>
|
||||||
<inputType id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.input.c.1972746724" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.input.c"/>
|
<inputType id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.input.c.1972746724" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.input.c"/>
|
||||||
</tool>
|
</tool>
|
||||||
|
@ -72,6 +75,9 @@
|
||||||
<listOptionValue builtIn="false" value="../Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F"/>
|
<listOptionValue builtIn="false" value="../Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F"/>
|
||||||
<listOptionValue builtIn="false" value="../Drivers/CMSIS/Device/ST/STM32F4xx/Include"/>
|
<listOptionValue builtIn="false" value="../Drivers/CMSIS/Device/ST/STM32F4xx/Include"/>
|
||||||
<listOptionValue builtIn="false" value="../Drivers/CMSIS/Include"/>
|
<listOptionValue builtIn="false" value="../Drivers/CMSIS/Include"/>
|
||||||
|
<listOptionValue builtIn="false" value="../platforms/firmware"/>
|
||||||
|
<listOptionValue builtIn="false" value="../components"/>
|
||||||
|
<listOptionValue builtIn="false" value="../Application"/>
|
||||||
</option>
|
</option>
|
||||||
<inputType id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.input.cpp.288272109" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.input.cpp"/>
|
<inputType id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.input.cpp.288272109" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.input.cpp"/>
|
||||||
</tool>
|
</tool>
|
||||||
|
@ -94,9 +100,12 @@
|
||||||
</toolChain>
|
</toolChain>
|
||||||
</folderInfo>
|
</folderInfo>
|
||||||
<sourceEntries>
|
<sourceEntries>
|
||||||
|
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="Application"/>
|
||||||
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="Core"/>
|
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="Core"/>
|
||||||
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="Middlewares"/>
|
|
||||||
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="Drivers"/>
|
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="Drivers"/>
|
||||||
|
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="Middlewares"/>
|
||||||
|
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="components"/>
|
||||||
|
<entry excluding="test" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="platforms"/>
|
||||||
</sourceEntries>
|
</sourceEntries>
|
||||||
</configuration>
|
</configuration>
|
||||||
</storageModule>
|
</storageModule>
|
||||||
|
@ -118,28 +127,28 @@
|
||||||
<configuration artifactExtension="elf" artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.config.exe.release.1989290122" name="Release" parent="com.st.stm32cube.ide.mcu.gnu.managedbuild.config.exe.release">
|
<configuration artifactExtension="elf" artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.config.exe.release.1989290122" name="Release" parent="com.st.stm32cube.ide.mcu.gnu.managedbuild.config.exe.release">
|
||||||
<folderInfo id="com.st.stm32cube.ide.mcu.gnu.managedbuild.config.exe.release.1989290122." name="/" resourcePath="">
|
<folderInfo id="com.st.stm32cube.ide.mcu.gnu.managedbuild.config.exe.release.1989290122." name="/" resourcePath="">
|
||||||
<toolChain id="com.st.stm32cube.ide.mcu.gnu.managedbuild.toolchain.exe.release.88032185" name="MCU ARM GCC" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.toolchain.exe.release">
|
<toolChain id="com.st.stm32cube.ide.mcu.gnu.managedbuild.toolchain.exe.release.88032185" name="MCU ARM GCC" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.toolchain.exe.release">
|
||||||
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_mcu.1654975242" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_mcu" value="STM32F407VETx" valueType="string"/>
|
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_mcu.1654975242" name="MCU" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_mcu" useByScannerDiscovery="true" value="STM32F407VETx" valueType="string"/>
|
||||||
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_cpuid.170353378" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_cpuid" value="0" valueType="string"/>
|
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_cpuid.170353378" name="CPU" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_cpuid" useByScannerDiscovery="false" value="0" valueType="string"/>
|
||||||
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_coreid.769479580" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_coreid" value="0" valueType="string"/>
|
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_coreid.769479580" name="Core" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_coreid" useByScannerDiscovery="false" value="0" valueType="string"/>
|
||||||
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.fpu.298796293" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.fpu" value="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.fpu.value.fpv4-sp-d16" valueType="enumerated"/>
|
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.fpu.298796293" name="Floating-point unit" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.fpu" useByScannerDiscovery="true" value="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.fpu.value.fpv4-sp-d16" valueType="enumerated"/>
|
||||||
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.floatabi.1826749064" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.floatabi" value="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.floatabi.value.hard" valueType="enumerated"/>
|
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.floatabi.1826749064" name="Floating-point ABI" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.floatabi" useByScannerDiscovery="true" value="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.floatabi.value.hard" valueType="enumerated"/>
|
||||||
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_board.747128701" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_board" value="genericBoard" valueType="string"/>
|
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_board.747128701" name="Board" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.target_board" useByScannerDiscovery="false" value="genericBoard" valueType="string"/>
|
||||||
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.defaults.856929943" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.defaults" value="com.st.stm32cube.ide.common.services.build.inputs.revA.1.0.5 || Release || false || Executable || com.st.stm32cube.ide.mcu.gnu.managedbuild.option.toolchain.value.workspace || STM32F407VETx || 0 || 0 || arm-none-eabi- || ${gnu_tools_for_stm32_compiler_path} || ../Core/Inc | ../Drivers/STM32F4xx_HAL_Driver/Inc | ../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy | ../Middlewares/Third_Party/FreeRTOS/Source/include | ../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 | ../Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F | ../Drivers/CMSIS/Device/ST/STM32F4xx/Include | ../Drivers/CMSIS/Include || || || USE_FULL_LL_DRIVER | USE_HAL_DRIVER | STM32F407xx || || Drivers | Core/Startup | Middlewares | Core || || || ${workspace_loc:/${ProjName}/STM32F407VETX_FLASH.ld} || true || NonSecure || || secure_nsclib.o || || None || " valueType="string"/>
|
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.defaults.856929943" name="Defaults" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.option.defaults" useByScannerDiscovery="false" value="com.st.stm32cube.ide.common.services.build.inputs.revA.1.0.5 || Release || false || Executable || com.st.stm32cube.ide.mcu.gnu.managedbuild.option.toolchain.value.workspace || STM32F407VETx || 0 || 0 || arm-none-eabi- || ${gnu_tools_for_stm32_compiler_path} || ../Core/Inc | ../Drivers/STM32F4xx_HAL_Driver/Inc | ../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy | ../Middlewares/Third_Party/FreeRTOS/Source/include | ../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 | ../Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F | ../Drivers/CMSIS/Device/ST/STM32F4xx/Include | ../Drivers/CMSIS/Include || || || USE_FULL_LL_DRIVER | USE_HAL_DRIVER | STM32F407xx || || Drivers | Core/Startup | Middlewares | Core || || || ${workspace_loc:/${ProjName}/STM32F407VETX_FLASH.ld} || true || NonSecure || || secure_nsclib.o || || None || " valueType="string"/>
|
||||||
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.targetplatform.700970692" isAbstract="false" osList="all" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.targetplatform"/>
|
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.targetplatform.700970692" isAbstract="false" osList="all" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.targetplatform"/>
|
||||||
<builder buildPath="${workspace_loc:/f407ve_freertos}/Release" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.builder.1409602479" managedBuildOn="true" name="Gnu Make Builder.Release" parallelBuildOn="true" parallelizationNumber="optimal" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.builder"/>
|
<builder buildPath="${workspace_loc:/f407ve_freertos}/Release" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.builder.1409602479" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" parallelBuildOn="true" parallelizationNumber="optimal" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.builder"/>
|
||||||
<tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.1624786789" name="MCU GCC Assembler" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler">
|
<tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.1624786789" name="MCU GCC Assembler" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler">
|
||||||
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.option.debuglevel.1965571508" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.option.debuglevel" value="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.option.debuglevel.value.g0" valueType="enumerated"/>
|
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.option.debuglevel.1965571508" name="Debug level" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.option.debuglevel" value="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.option.debuglevel.value.g0" valueType="enumerated"/>
|
||||||
<inputType id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.input.269278791" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.input"/>
|
<inputType id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.input.269278791" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.assembler.input"/>
|
||||||
</tool>
|
</tool>
|
||||||
<tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.1575473883" name="MCU GCC Compiler" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler">
|
<tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.1575473883" name="MCU GCC Compiler" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler">
|
||||||
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.option.debuglevel.1374927620" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.option.debuglevel" value="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.option.debuglevel.value.g0" valueType="enumerated"/>
|
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.option.debuglevel.1374927620" name="Debug level" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.option.debuglevel" useByScannerDiscovery="false" value="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.option.debuglevel.value.g0" valueType="enumerated"/>
|
||||||
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.option.optimization.level.321101054" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.option.optimization.level" value="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.option.optimization.level.value.os" valueType="enumerated"/>
|
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.option.optimization.level.321101054" name="Optimization level" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.option.optimization.level" useByScannerDiscovery="false" value="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.option.optimization.level.value.os" valueType="enumerated"/>
|
||||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.option.definedsymbols.2036404840" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.option.definedsymbols" valueType="definedSymbols">
|
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.option.definedsymbols.2036404840" name="Define symbols (-D)" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.option.definedsymbols" useByScannerDiscovery="false" valueType="definedSymbols">
|
||||||
<listOptionValue builtIn="false" value="USE_FULL_LL_DRIVER"/>
|
<listOptionValue builtIn="false" value="USE_FULL_LL_DRIVER"/>
|
||||||
<listOptionValue builtIn="false" value="USE_HAL_DRIVER"/>
|
<listOptionValue builtIn="false" value="USE_HAL_DRIVER"/>
|
||||||
<listOptionValue builtIn="false" value="STM32F407xx"/>
|
<listOptionValue builtIn="false" value="STM32F407xx"/>
|
||||||
</option>
|
</option>
|
||||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.option.includepaths.1378819109" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.option.includepaths" valueType="includePath">
|
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.option.includepaths.1378819109" name="Include paths (-I)" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.option.includepaths" useByScannerDiscovery="false" valueType="includePath">
|
||||||
<listOptionValue builtIn="false" value="../Core/Inc"/>
|
<listOptionValue builtIn="false" value="../Core/Inc"/>
|
||||||
<listOptionValue builtIn="false" value="../Drivers/STM32F4xx_HAL_Driver/Inc"/>
|
<listOptionValue builtIn="false" value="../Drivers/STM32F4xx_HAL_Driver/Inc"/>
|
||||||
<listOptionValue builtIn="false" value="../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy"/>
|
<listOptionValue builtIn="false" value="../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy"/>
|
||||||
|
@ -148,18 +157,21 @@
|
||||||
<listOptionValue builtIn="false" value="../Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F"/>
|
<listOptionValue builtIn="false" value="../Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F"/>
|
||||||
<listOptionValue builtIn="false" value="../Drivers/CMSIS/Device/ST/STM32F4xx/Include"/>
|
<listOptionValue builtIn="false" value="../Drivers/CMSIS/Device/ST/STM32F4xx/Include"/>
|
||||||
<listOptionValue builtIn="false" value="../Drivers/CMSIS/Include"/>
|
<listOptionValue builtIn="false" value="../Drivers/CMSIS/Include"/>
|
||||||
|
<listOptionValue builtIn="false" value="../platforms/firmware"/>
|
||||||
|
<listOptionValue builtIn="false" value="../components"/>
|
||||||
|
<listOptionValue builtIn="false" value="../Application"/>
|
||||||
</option>
|
</option>
|
||||||
<inputType id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.input.c.1563730164" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.input.c"/>
|
<inputType id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.input.c.1563730164" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.compiler.input.c"/>
|
||||||
</tool>
|
</tool>
|
||||||
<tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.256939633" name="MCU G++ Compiler" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler">
|
<tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.256939633" name="MCU G++ Compiler" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler">
|
||||||
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.option.debuglevel.1430120357" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.option.debuglevel" value="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.option.debuglevel.value.g0" valueType="enumerated"/>
|
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.option.debuglevel.1430120357" name="Debug level" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.option.debuglevel" useByScannerDiscovery="false" value="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.option.debuglevel.value.g0" valueType="enumerated"/>
|
||||||
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.option.optimization.level.1325171401" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.option.optimization.level" value="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.option.optimization.level.value.os" valueType="enumerated"/>
|
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.option.optimization.level.1325171401" name="Optimization level" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.option.optimization.level" useByScannerDiscovery="false" value="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.option.optimization.level.value.os" valueType="enumerated"/>
|
||||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.option.definedsymbols.1279950951" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.option.definedsymbols" valueType="definedSymbols">
|
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.option.definedsymbols.1279950951" name="Define symbols (-D)" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.option.definedsymbols" useByScannerDiscovery="false" valueType="definedSymbols">
|
||||||
<listOptionValue builtIn="false" value="USE_FULL_LL_DRIVER"/>
|
<listOptionValue builtIn="false" value="USE_FULL_LL_DRIVER"/>
|
||||||
<listOptionValue builtIn="false" value="USE_HAL_DRIVER"/>
|
<listOptionValue builtIn="false" value="USE_HAL_DRIVER"/>
|
||||||
<listOptionValue builtIn="false" value="STM32F407xx"/>
|
<listOptionValue builtIn="false" value="STM32F407xx"/>
|
||||||
</option>
|
</option>
|
||||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.option.includepaths.1781286458" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.option.includepaths" valueType="includePath">
|
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.option.includepaths.1781286458" name="Include paths (-I)" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.option.includepaths" useByScannerDiscovery="false" valueType="includePath">
|
||||||
<listOptionValue builtIn="false" value="../Core/Inc"/>
|
<listOptionValue builtIn="false" value="../Core/Inc"/>
|
||||||
<listOptionValue builtIn="false" value="../Drivers/STM32F4xx_HAL_Driver/Inc"/>
|
<listOptionValue builtIn="false" value="../Drivers/STM32F4xx_HAL_Driver/Inc"/>
|
||||||
<listOptionValue builtIn="false" value="../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy"/>
|
<listOptionValue builtIn="false" value="../Drivers/STM32F4xx_HAL_Driver/Inc/Legacy"/>
|
||||||
|
@ -168,12 +180,15 @@
|
||||||
<listOptionValue builtIn="false" value="../Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F"/>
|
<listOptionValue builtIn="false" value="../Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F"/>
|
||||||
<listOptionValue builtIn="false" value="../Drivers/CMSIS/Device/ST/STM32F4xx/Include"/>
|
<listOptionValue builtIn="false" value="../Drivers/CMSIS/Device/ST/STM32F4xx/Include"/>
|
||||||
<listOptionValue builtIn="false" value="../Drivers/CMSIS/Include"/>
|
<listOptionValue builtIn="false" value="../Drivers/CMSIS/Include"/>
|
||||||
|
<listOptionValue builtIn="false" value="../platforms/firmware"/>
|
||||||
|
<listOptionValue builtIn="false" value="../components"/>
|
||||||
|
<listOptionValue builtIn="false" value="../Application"/>
|
||||||
</option>
|
</option>
|
||||||
<inputType id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.input.cpp.87434455" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.input.cpp"/>
|
<inputType id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.input.cpp.87434455" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.compiler.input.cpp"/>
|
||||||
</tool>
|
</tool>
|
||||||
<tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.linker.380289902" name="MCU GCC Linker" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.linker"/>
|
<tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.linker.380289902" name="MCU GCC Linker" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.c.linker"/>
|
||||||
<tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.linker.318348735" name="MCU G++ Linker" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.linker">
|
<tool id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.linker.318348735" name="MCU G++ Linker" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.linker">
|
||||||
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.linker.option.script.675226933" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.linker.option.script" value="${workspace_loc:/${ProjName}/STM32F407VETX_FLASH.ld}" valueType="string"/>
|
<option id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.linker.option.script.675226933" name="Linker Script (-T)" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.linker.option.script" value="${workspace_loc:/${ProjName}/STM32F407VETX_FLASH.ld}" valueType="string"/>
|
||||||
<inputType id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.linker.input.1621169407" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.linker.input">
|
<inputType id="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.linker.input.1621169407" superClass="com.st.stm32cube.ide.mcu.gnu.managedbuild.tool.cpp.linker.input">
|
||||||
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
|
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
|
||||||
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
|
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
|
||||||
|
@ -190,12 +205,16 @@
|
||||||
</toolChain>
|
</toolChain>
|
||||||
</folderInfo>
|
</folderInfo>
|
||||||
<sourceEntries>
|
<sourceEntries>
|
||||||
|
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="Application"/>
|
||||||
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="Core"/>
|
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="Core"/>
|
||||||
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="Middlewares"/>
|
|
||||||
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="Drivers"/>
|
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="Drivers"/>
|
||||||
|
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="Middlewares"/>
|
||||||
|
<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="components"/>
|
||||||
|
<entry excluding="test" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="platforms"/>
|
||||||
</sourceEntries>
|
</sourceEntries>
|
||||||
</configuration>
|
</configuration>
|
||||||
</storageModule>
|
</storageModule>
|
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||||
</cconfiguration>
|
</cconfiguration>
|
||||||
</storageModule>
|
</storageModule>
|
||||||
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
|
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
|
||||||
|
@ -219,4 +238,5 @@
|
||||||
<autodiscovery enabled="false" problemReportingEnabled="true" selectedProfileId=""/>
|
<autodiscovery enabled="false" problemReportingEnabled="true" selectedProfileId=""/>
|
||||||
</scannerConfigBuildInfo>
|
</scannerConfigBuildInfo>
|
||||||
</storageModule>
|
</storageModule>
|
||||||
|
<storageModule moduleId="refreshScope"/>
|
||||||
</cproject>
|
</cproject>
|
118
Application/application.cpp
Normal file
118
Application/application.cpp
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* mainloop.cpp
|
||||||
|
*
|
||||||
|
* Created on: Sep 11, 2019
|
||||||
|
* Author: abody
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../Application/application.h"
|
||||||
|
|
||||||
|
#include <f4ll_cpp/ili9341.h>
|
||||||
|
#include <initializer_list>
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
#include "../Application/globals.h"
|
||||||
|
#include "../Application/strutil.h"
|
||||||
|
|
||||||
|
#define BORDER 60
|
||||||
|
#define BARWIDTH 2
|
||||||
|
|
||||||
|
using namespace f4ll_cpp;
|
||||||
|
|
||||||
|
void AppInit()
|
||||||
|
{
|
||||||
|
static Application m;
|
||||||
|
|
||||||
|
m.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t SpiIo(SPI_TypeDef *spi, uint8_t data)
|
||||||
|
{
|
||||||
|
while(!LL_SPI_IsActiveFlag_TXE(spi));
|
||||||
|
LL_SPI_TransmitData8(spi, data);
|
||||||
|
while(!LL_SPI_IsActiveFlag_RXNE(spi));
|
||||||
|
return LL_SPI_ReceiveData8(spi);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t ReadTouch(SPI_TypeDef *spi, bool x)
|
||||||
|
{
|
||||||
|
static uint8_t const CMD_X_READ=0b10010000;
|
||||||
|
static uint8_t const CMD_Y_READ=0b11010000;
|
||||||
|
|
||||||
|
uint16_t tmp;
|
||||||
|
|
||||||
|
LL_GPIO_ResetOutputPin(TOUCH_CS_GPIO_Port, TOUCH_CS_Pin);
|
||||||
|
SpiIo(spi, x ? CMD_X_READ: CMD_Y_READ);
|
||||||
|
tmp = (uint16_t)SpiIo(spi, 0) << 8;
|
||||||
|
tmp |= SpiIo(spi, 0);
|
||||||
|
LL_GPIO_SetOutputPin(TOUCH_CS_GPIO_Port, TOUCH_CS_Pin);
|
||||||
|
|
||||||
|
return tmp >> 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
Application::Application()
|
||||||
|
: GlobalsInitializer(&m_console)
|
||||||
|
, Task(3)
|
||||||
|
, m_console(USART1, DMA2, LL_DMA_STREAM_2, LL_DMA_STREAM_7, this, nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::TaskFn(void *taskObj)
|
||||||
|
{
|
||||||
|
static_cast<Application*>(reinterpret_cast<fsl::Task<Application, APPLICATION_STACK_SIZE>*>(taskObj))->Loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::Loop()
|
||||||
|
{
|
||||||
|
Ili9341Fsmc &lcd(Ili9341Fsmc::Init(nullptr, nullptr, DMA2, LL_DMA_STREAM_4, false));
|
||||||
|
lcd.SetScrollMode(true);
|
||||||
|
|
||||||
|
lcd.FillRect(Ili9341Fsmc::ILI9341_BLACK, false);
|
||||||
|
|
||||||
|
LL_SPI_Enable(SPI2);
|
||||||
|
|
||||||
|
for(int i = 0; i < 100; ++i) {
|
||||||
|
m_console.SendLine("Lofasz a seggedbe!\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
if(m_lineReceived && m_transmissionCompleted) {
|
||||||
|
m_transmissionCompleted = false;
|
||||||
|
const char *line = const_cast<const char*>(m_rcvdBuffer->buffer);
|
||||||
|
m_console.SendLine(line, m_rcvdBuffer->len);
|
||||||
|
lcd.Print(line);
|
||||||
|
lcd.Print("\r\n", 2);
|
||||||
|
m_lineReceived = false;
|
||||||
|
m_rcvdBuffer->busy = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(LL_GPIO_IsInputPinSet(PENIRQ_GPIO_Port, PENIRQ_Pin))
|
||||||
|
LL_GPIO_SetOutputPin(LED1_GPIO_Port, LED1_Pin);
|
||||||
|
else {
|
||||||
|
LL_GPIO_ResetOutputPin(LED1_GPIO_Port, LED1_Pin);
|
||||||
|
|
||||||
|
uint16_t x = ReadTouch(SPI2, true);
|
||||||
|
uint16_t y = ReadTouch(SPI2, false);
|
||||||
|
unsigned len = strcpy_ex(m_appBuffer, "X: ");
|
||||||
|
len += uitodec(m_appBuffer+len, x);
|
||||||
|
len += strcpy_ex(m_appBuffer + len, ", Y: ");
|
||||||
|
len += uitodec(m_appBuffer + len, y);
|
||||||
|
len += strcpy_ex(m_appBuffer + len, "\r\n");
|
||||||
|
lcd.Print(m_appBuffer, len);
|
||||||
|
m_console.SendLine(m_appBuffer, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::LineReceived(void *userParam, SerialConsole<257>::Buffer *buffer)
|
||||||
|
{
|
||||||
|
m_lineReceived = true;
|
||||||
|
m_rcvdBuffer = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::TransmissionComplete(void *userParam, SerialConsole<257>::Buffer *buffer)
|
||||||
|
{
|
||||||
|
m_transmissionCompleted = true;
|
||||||
|
}
|
||||||
|
|
60
Application/application.h
Normal file
60
Application/application.h
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* mainloop.h
|
||||||
|
*
|
||||||
|
* Created on: Sep 11, 2019
|
||||||
|
* Author: abody
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MAINLOOP_H_
|
||||||
|
#define MAINLOOP_H_
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void AppInit();
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
#include <f4ll_cpp/serialconsole.h>
|
||||||
|
#include <fsl/task.h>
|
||||||
|
#include "../Application/globals.h"
|
||||||
|
|
||||||
|
struct GlobalsInitializer {
|
||||||
|
GlobalsInitializer(f4ll_cpp::SerialConsole<257> *console) {
|
||||||
|
g_console = console;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define APPLICATION_STACK_SIZE 16384
|
||||||
|
|
||||||
|
class Application : public GlobalsInitializer
|
||||||
|
, public f4ll_cpp::SerialConsole<257>::ISerialConsoleCallback
|
||||||
|
, public fsl::Task<Application, APPLICATION_STACK_SIZE>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Application();
|
||||||
|
void Loop();
|
||||||
|
|
||||||
|
friend class fsl::Task<Application, APPLICATION_STACK_SIZE>;
|
||||||
|
private:
|
||||||
|
static void TaskFn(void *taskObj);
|
||||||
|
|
||||||
|
virtual void LineReceived(void *userParam, f4ll_cpp::SerialConsole<257>::Buffer *buffer);
|
||||||
|
virtual void TransmissionComplete(void *userParam, f4ll_cpp::SerialConsole<257>::Buffer *buffer);
|
||||||
|
virtual char const * getName() { return "Application"; }
|
||||||
|
|
||||||
|
f4ll_cpp::SerialConsole<257> m_console;
|
||||||
|
volatile bool m_lineReceived = false;
|
||||||
|
volatile f4ll_cpp::SerialConsole<257>::Buffer *m_rcvdBuffer;
|
||||||
|
char m_appBuffer[128];
|
||||||
|
|
||||||
|
volatile bool m_transmissionCompleted = true;
|
||||||
|
};
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* MAINLOOP_H_ */
|
10
Application/globals.cpp
Normal file
10
Application/globals.cpp
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
/*
|
||||||
|
* globals.c
|
||||||
|
*
|
||||||
|
* Created on: Aug 29, 2019
|
||||||
|
* Author: abody
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../Application/globals.h"
|
||||||
|
|
||||||
|
f4ll_cpp::SerialConsole<257> *g_console = nullptr;
|
18
Application/globals.h
Normal file
18
Application/globals.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* globals.h
|
||||||
|
*
|
||||||
|
* Created on: Aug 29, 2019
|
||||||
|
* Author: abody
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GLOBALS_H_
|
||||||
|
#define GLOBALS_H_
|
||||||
|
#include <f4ll_cpp/serialconsole.h>
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
|
||||||
|
extern f4ll_cpp::SerialConsole<257> *g_console;
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif /* GLOBALS_H_ */
|
35
Application/interrupt_handlers.cpp
Normal file
35
Application/interrupt_handlers.cpp
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* interrupt.c
|
||||||
|
*
|
||||||
|
* Created on: Aug 29, 2019
|
||||||
|
* Author: abody
|
||||||
|
*/
|
||||||
|
#include "../Application/interrupt_handlers.h"
|
||||||
|
|
||||||
|
#include "main.h"
|
||||||
|
#include <f4ll_cpp/ili9341.h>
|
||||||
|
#include "../Application/globals.h"
|
||||||
|
|
||||||
|
void HandleLcdDmaIrq()
|
||||||
|
{
|
||||||
|
// DMA2 Stream4
|
||||||
|
f4ll_cpp::Ili9341Fsmc::HandleDmaIrq(&f4ll_cpp::Ili9341Fsmc::Instance());
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleConsoleRxDmaIrq()
|
||||||
|
{
|
||||||
|
if(g_console)
|
||||||
|
g_console->HandleRxDmaIrq();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleConsoleTxDmaIrq()
|
||||||
|
{
|
||||||
|
if(g_console)
|
||||||
|
g_console->HandleTxDmaIrq();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleConsoleUsartIrq()
|
||||||
|
{
|
||||||
|
if(g_console)
|
||||||
|
g_console->HandleUsartIrq();
|
||||||
|
}
|
25
Application/interrupt_handlers.h
Normal file
25
Application/interrupt_handlers.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* interrupt.h
|
||||||
|
*
|
||||||
|
* Created on: Aug 29, 2019
|
||||||
|
* Author: abody
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INTERRUPT_HANDLERS_H_
|
||||||
|
#define INTERRUPT_HANDLERS_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void HandleLcdDmaIrq();
|
||||||
|
|
||||||
|
void HandleConsoleRxDmaIrq();
|
||||||
|
void HandleConsoleTxDmaIrq();
|
||||||
|
void HandleConsoleUsartIrq();
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /* INTERRUPT_HANDLERS_H_ */
|
111
Application/strutil.c
Normal file
111
Application/strutil.c
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
#include "../Application/strutil.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
size_t strcpy_ex(char *dst, char const *src)
|
||||||
|
{
|
||||||
|
size_t ret = 0;
|
||||||
|
do {
|
||||||
|
*dst++ = *src;
|
||||||
|
++ret;
|
||||||
|
} while(*src++);
|
||||||
|
return ret - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
void strrev(char *first, char *last)
|
||||||
|
{
|
||||||
|
char tmp;
|
||||||
|
while(last > first) {
|
||||||
|
tmp = *first;
|
||||||
|
*first++ = *last;
|
||||||
|
*last-- = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
char tochr(const uint8_t in, const uint8_t upper)
|
||||||
|
{
|
||||||
|
return in + ((in < 10) ? '0' : (upper ? 'A' : 'a') - 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
size_t uitodec(char* buffer, uint32_t data)
|
||||||
|
{
|
||||||
|
char *b2 = buffer;
|
||||||
|
if(!data) {
|
||||||
|
*b2++ = '0';
|
||||||
|
*b2 = '\0';
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(data) {
|
||||||
|
*b2++ = (data % 10) + '0';
|
||||||
|
data /= 10;
|
||||||
|
}
|
||||||
|
size_t ret = b2 - buffer;
|
||||||
|
|
||||||
|
*b2-- = 0;
|
||||||
|
|
||||||
|
strrev(buffer, b2);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
size_t uitohex(char* buffer, uint32_t data, uint8_t chars)
|
||||||
|
{
|
||||||
|
char *b2 = buffer;
|
||||||
|
size_t ret = 0;
|
||||||
|
|
||||||
|
if(chars == 0xff || !chars)
|
||||||
|
{
|
||||||
|
if(!data) {
|
||||||
|
*b2++ = '0';
|
||||||
|
*b2 = '\0';
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(data) {
|
||||||
|
uint8_t curval = data & 0x0f;
|
||||||
|
*b2++ = tochr(curval, 1);
|
||||||
|
data >>= 4;
|
||||||
|
}
|
||||||
|
ret = b2 - buffer;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = chars;
|
||||||
|
for(uint8_t pos = 0; pos < (uint8_t)ret; ++pos) {
|
||||||
|
*b2++ = tochr(data & 0x0f, 1);
|
||||||
|
data >>= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
*b2-- = 0;
|
||||||
|
strrev(buffer, b2);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
size_t itodec(char* buffer, int data)
|
||||||
|
{
|
||||||
|
if(data < 0) {
|
||||||
|
*buffer++ = '-';
|
||||||
|
return uitodec(buffer, -data) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return uitodec(buffer, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
size_t itohex(char* buffer, int data)
|
||||||
|
{
|
||||||
|
if(data < 0) {
|
||||||
|
*buffer++ = '-';
|
||||||
|
return uitohex(buffer, -data, 0) + 1;
|
||||||
|
}
|
||||||
|
return uitohex(buffer, data, 0);
|
||||||
|
}
|
31
Application/strutil.h
Normal file
31
Application/strutil.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* strutil.h
|
||||||
|
*
|
||||||
|
* Created on: Feb 11, 2017
|
||||||
|
* Author: compi
|
||||||
|
*/
|
||||||
|
#ifndef _STRUTIL_H_
|
||||||
|
#define _STRUTIL_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
size_t strcpy_ex(char *dst, char const *src);
|
||||||
|
size_t uitodec(char* buffer, uint32_t data);
|
||||||
|
size_t uitohex(char* buffer, uint32_t data, uint8_t chars);
|
||||||
|
size_t itodec(char* buffer, int data);
|
||||||
|
size_t itohex(char* buffer, int data);
|
||||||
|
void strrev(char *first, char *last);
|
||||||
|
char tochr(const uint8_t in, const uint8_t upper);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _STRUTIL_H_
|
98
Application/zxpix_font.h
Normal file
98
Application/zxpix_font.h
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
const unsigned char font[96][6] = {
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x00}, //
|
||||||
|
{0x2f,0x00,0x00,0x00,0x00,0x00}, // !
|
||||||
|
{0x03,0x00,0x03,0x00,0x00,0x00}, // "
|
||||||
|
{0x12,0x3f,0x12,0x12,0x3f,0x12}, // #
|
||||||
|
{0x2e,0x2a,0x7f,0x2a,0x3a,0x00}, // $
|
||||||
|
{0x23,0x13,0x08,0x04,0x32,0x31}, // %
|
||||||
|
{0x10,0x2a,0x25,0x2a,0x10,0x20}, // &
|
||||||
|
{0x02,0x01,0x00,0x00,0x00,0x00}, // '
|
||||||
|
{0x1e,0x21,0x00,0x00,0x00,0x00}, // (
|
||||||
|
{0x21,0x1e,0x00,0x00,0x00,0x00}, // )
|
||||||
|
{0x08,0x2a,0x1c,0x2a,0x08,0x08}, // *
|
||||||
|
{0x08,0x08,0x3e,0x08,0x08,0x08}, // +
|
||||||
|
{0x80,0x60,0x00,0x00,0x00,0x00}, // ,
|
||||||
|
{0x08,0x08,0x08,0x08,0x08,0x00}, // -
|
||||||
|
{0x30,0x30,0x00,0x00,0x00,0x00}, // .
|
||||||
|
{0x20,0x10,0x08,0x04,0x02,0x00}, // /
|
||||||
|
{0x1e,0x31,0x29,0x25,0x23,0x1e}, // 0
|
||||||
|
{0x22,0x21,0x3f,0x20,0x20,0x20}, // 1
|
||||||
|
{0x32,0x29,0x29,0x29,0x29,0x26}, // 2
|
||||||
|
{0x12,0x21,0x21,0x25,0x25,0x1a}, // 3
|
||||||
|
{0x18,0x14,0x12,0x3f,0x10,0x10}, // 4
|
||||||
|
{0x17,0x25,0x25,0x25,0x25,0x19}, // 5
|
||||||
|
{0x1e,0x25,0x25,0x25,0x25,0x18}, // 6
|
||||||
|
{0x01,0x01,0x31,0x09,0x05,0x03}, // 7
|
||||||
|
{0x1a,0x25,0x25,0x25,0x25,0x1a}, // 8
|
||||||
|
{0x06,0x29,0x29,0x29,0x29,0x1e}, // 9
|
||||||
|
{0x24,0x00,0x00,0x00,0x00,0x00}, // :
|
||||||
|
{0x80,0x64,0x00,0x00,0x00,0x00}, // ;
|
||||||
|
{0x08,0x14,0x22,0x00,0x00,0x00}, // <
|
||||||
|
{0x14,0x14,0x14,0x14,0x14,0x00}, // =
|
||||||
|
{0x22,0x14,0x08,0x00,0x00,0x00}, // >
|
||||||
|
{0x02,0x01,0x01,0x29,0x05,0x02}, // ?
|
||||||
|
{0x1e,0x21,0x2d,0x2b,0x2d,0x0e}, // @
|
||||||
|
{0x3e,0x09,0x09,0x09,0x09,0x3e}, // A
|
||||||
|
{0x3f,0x25,0x25,0x25,0x25,0x1a}, // B
|
||||||
|
{0x1e,0x21,0x21,0x21,0x21,0x12}, // C
|
||||||
|
{0x3f,0x21,0x21,0x21,0x12,0x0c}, // D
|
||||||
|
{0x3f,0x25,0x25,0x25,0x25,0x21}, // E
|
||||||
|
{0x3f,0x05,0x05,0x05,0x05,0x01}, // F
|
||||||
|
{0x1e,0x21,0x21,0x21,0x29,0x1a}, // G
|
||||||
|
{0x3f,0x04,0x04,0x04,0x04,0x3f}, // H
|
||||||
|
{0x21,0x21,0x3f,0x21,0x21,0x21}, // I
|
||||||
|
{0x10,0x20,0x20,0x20,0x20,0x1f}, // J
|
||||||
|
{0x3f,0x04,0x0c,0x0a,0x11,0x20}, // K
|
||||||
|
{0x3f,0x20,0x20,0x20,0x20,0x20}, // L
|
||||||
|
{0x3f,0x02,0x04,0x04,0x02,0x3f}, // M
|
||||||
|
{0x3f,0x02,0x04,0x08,0x10,0x3f}, // N
|
||||||
|
{0x1e,0x21,0x21,0x21,0x21,0x1e}, // O
|
||||||
|
{0x3f,0x09,0x09,0x09,0x09,0x06}, // P
|
||||||
|
{0x1e,0x21,0x29,0x31,0x21,0x1e}, // Q
|
||||||
|
{0x3f,0x09,0x09,0x09,0x19,0x26}, // R
|
||||||
|
{0x12,0x25,0x25,0x25,0x25,0x18}, // S
|
||||||
|
{0x01,0x01,0x01,0x3f,0x01,0x01}, // T
|
||||||
|
{0x1f,0x20,0x20,0x20,0x20,0x1f}, // U
|
||||||
|
{0x0f,0x10,0x20,0x20,0x10,0x0f}, // V
|
||||||
|
{0x1f,0x20,0x10,0x10,0x20,0x1f}, // W
|
||||||
|
{0x21,0x12,0x0c,0x0c,0x12,0x21}, // X
|
||||||
|
{0x01,0x02,0x0c,0x38,0x04,0x02}, // Y
|
||||||
|
{0x21,0x31,0x29,0x25,0x23,0x21}, // Z
|
||||||
|
{0x3f,0x21,0x00,0x00,0x00,0x00}, // [
|
||||||
|
{0x02,0x04,0x08,0x10,0x20,0x00}, // "\"
|
||||||
|
{0x21,0x3f,0x00,0x00,0x00,0x00}, // ]
|
||||||
|
{0x04,0x02,0x3f,0x02,0x04,0x00}, // ^
|
||||||
|
{0x40,0x40,0x40,0x40,0x40,0x40}, // _
|
||||||
|
{0x01,0x02,0x00,0x00,0x00,0x00}, // `
|
||||||
|
{0x10,0x30,0x2a,0x2a,0x3c,0x00}, // a
|
||||||
|
{0x3f,0x24,0x24,0x24,0x18,0x00}, // b
|
||||||
|
{0x0c,0x14,0x22,0x22,0x00,0x00}, // c
|
||||||
|
{0x18,0x24,0x24,0x24,0x3f,0x00}, // d
|
||||||
|
{0x1c,0x2c,0x2a,0x2a,0x24,0x00}, // e
|
||||||
|
{0x3e,0x05,0x01,0x00,0x00,0x00}, // f
|
||||||
|
{0x18,0x28,0xa4,0xa4,0x7c,0x00}, // g
|
||||||
|
{0x3f,0x04,0x04,0x0c,0x30,0x00}, // h
|
||||||
|
{0x24,0x3d,0x20,0x00,0x00,0x00}, // i
|
||||||
|
{0x20,0x40,0x40,0x3d,0x00,0x00}, // j
|
||||||
|
{0x3f,0x0c,0x12,0x20,0x00,0x00}, // k
|
||||||
|
{0x1f,0x20,0x20,0x00,0x00,0x00}, // l
|
||||||
|
{0x3e,0x02,0x3c,0x02,0x3c,0x00}, // m
|
||||||
|
{0x3e,0x02,0x02,0x02,0x3c,0x00}, // n
|
||||||
|
{0x0c,0x14,0x22,0x32,0x0c,0x00}, // o
|
||||||
|
{0xfc,0x24,0x24,0x24,0x18,0x00}, // p
|
||||||
|
{0x18,0x24,0x24,0x24,0xfc,0x80}, // q
|
||||||
|
{0x3c,0x04,0x02,0x02,0x00,0x00}, // r
|
||||||
|
{0x24,0x2c,0x2a,0x2a,0x10,0x00}, // s
|
||||||
|
{0x02,0x1f,0x22,0x20,0x00,0x00}, // t
|
||||||
|
{0x1e,0x20,0x20,0x20,0x1e,0x00}, // u
|
||||||
|
{0x06,0x18,0x20,0x18,0x06,0x00}, // v
|
||||||
|
{0x1e,0x30,0x1c,0x30,0x0e,0x00}, // w
|
||||||
|
{0x22,0x14,0x08,0x14,0x22,0x00}, // x
|
||||||
|
{0x0c,0x10,0xa0,0xa0,0x7c,0x00}, // y
|
||||||
|
{0x22,0x32,0x2a,0x26,0x22,0x22}, // z
|
||||||
|
{0x0c,0x3f,0x21,0x00,0x00,0x00}, // {
|
||||||
|
{0x3f,0x00,0x00,0x00,0x00,0x00}, // |
|
||||||
|
{0x21,0x3f,0x0c,0x00,0x00,0x00}, // }
|
||||||
|
{0x02,0x01,0x02,0x01,0x00,0x00}, // ~
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x00}
|
||||||
|
};
|
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
/* Private includes ----------------------------------------------------------*/
|
/* Private includes ----------------------------------------------------------*/
|
||||||
/* USER CODE BEGIN Includes */
|
/* USER CODE BEGIN Includes */
|
||||||
|
#include "application.h"
|
||||||
|
|
||||||
/* USER CODE END Includes */
|
/* USER CODE END Includes */
|
||||||
|
|
||||||
|
@ -61,7 +62,17 @@ void MX_FREERTOS_Init(void);
|
||||||
|
|
||||||
/* Private user code ---------------------------------------------------------*/
|
/* Private user code ---------------------------------------------------------*/
|
||||||
/* USER CODE BEGIN 0 */
|
/* USER CODE BEGIN 0 */
|
||||||
|
//TaskHandle_t g_handle;
|
||||||
|
//StaticTask_t g_tcb;
|
||||||
|
//StackType_t g_stack[200];
|
||||||
|
//
|
||||||
|
//void TaskFn(void * param)
|
||||||
|
//{
|
||||||
|
// for(;;) {
|
||||||
|
// vTaskDelay(100);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//
|
||||||
/* USER CODE END 0 */
|
/* USER CODE END 0 */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,7 +109,9 @@ int main(void)
|
||||||
MX_CRC_Init();
|
MX_CRC_Init();
|
||||||
MX_SPI2_Init();
|
MX_SPI2_Init();
|
||||||
/* USER CODE BEGIN 2 */
|
/* USER CODE BEGIN 2 */
|
||||||
|
// g_handle = xTaskCreateStatic(TaskFn, "lofasz", sizeof(g_stack)/sizeof(g_stack[0]),
|
||||||
|
// NULL, 5, g_stack, &g_tcb);
|
||||||
|
AppInit();
|
||||||
/* USER CODE END 2 */
|
/* USER CODE END 2 */
|
||||||
|
|
||||||
/* Init scheduler */
|
/* Init scheduler */
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
#include "stm32f4xx_it.h"
|
#include "stm32f4xx_it.h"
|
||||||
/* Private includes ----------------------------------------------------------*/
|
/* Private includes ----------------------------------------------------------*/
|
||||||
/* USER CODE BEGIN Includes */
|
/* USER CODE BEGIN Includes */
|
||||||
|
#include "interrupt_handlers.h"
|
||||||
|
|
||||||
/* USER CODE END Includes */
|
/* USER CODE END Includes */
|
||||||
|
|
||||||
/* Private typedef -----------------------------------------------------------*/
|
/* Private typedef -----------------------------------------------------------*/
|
||||||
|
@ -166,7 +168,7 @@ void DebugMon_Handler(void)
|
||||||
void USART1_IRQHandler(void)
|
void USART1_IRQHandler(void)
|
||||||
{
|
{
|
||||||
/* USER CODE BEGIN USART1_IRQn 0 */
|
/* USER CODE BEGIN USART1_IRQn 0 */
|
||||||
|
HandleConsoleUsartIrq();
|
||||||
/* USER CODE END USART1_IRQn 0 */
|
/* USER CODE END USART1_IRQn 0 */
|
||||||
/* USER CODE BEGIN USART1_IRQn 1 */
|
/* USER CODE BEGIN USART1_IRQn 1 */
|
||||||
|
|
||||||
|
@ -193,7 +195,7 @@ void TIM6_DAC_IRQHandler(void)
|
||||||
void DMA2_Stream2_IRQHandler(void)
|
void DMA2_Stream2_IRQHandler(void)
|
||||||
{
|
{
|
||||||
/* USER CODE BEGIN DMA2_Stream2_IRQn 0 */
|
/* USER CODE BEGIN DMA2_Stream2_IRQn 0 */
|
||||||
|
HandleConsoleRxDmaIrq();
|
||||||
/* USER CODE END DMA2_Stream2_IRQn 0 */
|
/* USER CODE END DMA2_Stream2_IRQn 0 */
|
||||||
|
|
||||||
/* USER CODE BEGIN DMA2_Stream2_IRQn 1 */
|
/* USER CODE BEGIN DMA2_Stream2_IRQn 1 */
|
||||||
|
@ -207,7 +209,7 @@ void DMA2_Stream2_IRQHandler(void)
|
||||||
void DMA2_Stream4_IRQHandler(void)
|
void DMA2_Stream4_IRQHandler(void)
|
||||||
{
|
{
|
||||||
/* USER CODE BEGIN DMA2_Stream4_IRQn 0 */
|
/* USER CODE BEGIN DMA2_Stream4_IRQn 0 */
|
||||||
|
HandleLcdDmaIrq();
|
||||||
/* USER CODE END DMA2_Stream4_IRQn 0 */
|
/* USER CODE END DMA2_Stream4_IRQn 0 */
|
||||||
|
|
||||||
/* USER CODE BEGIN DMA2_Stream4_IRQn 1 */
|
/* USER CODE BEGIN DMA2_Stream4_IRQn 1 */
|
||||||
|
@ -221,7 +223,7 @@ void DMA2_Stream4_IRQHandler(void)
|
||||||
void DMA2_Stream7_IRQHandler(void)
|
void DMA2_Stream7_IRQHandler(void)
|
||||||
{
|
{
|
||||||
/* USER CODE BEGIN DMA2_Stream7_IRQn 0 */
|
/* USER CODE BEGIN DMA2_Stream7_IRQn 0 */
|
||||||
|
HandleConsoleTxDmaIrq();
|
||||||
/* USER CODE END DMA2_Stream7_IRQn 0 */
|
/* USER CODE END DMA2_Stream7_IRQn 0 */
|
||||||
|
|
||||||
/* USER CODE BEGIN DMA2_Stream7_IRQn 1 */
|
/* USER CODE BEGIN DMA2_Stream7_IRQn 1 */
|
||||||
|
|
194
components/f4ll_cpp/crcscheduler.cpp
Normal file
194
components/f4ll_cpp/crcscheduler.cpp
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
/*
|
||||||
|
* interrupt.c
|
||||||
|
*
|
||||||
|
* Created on: Aug 29, 2019
|
||||||
|
* Author: abody
|
||||||
|
*/
|
||||||
|
#include <f4ll_cpp/crcscheduler.h>
|
||||||
|
#include <string.h>
|
||||||
|
#if defined(HAVE_DIAG)
|
||||||
|
#include "diag.h"
|
||||||
|
#endif
|
||||||
|
#include "f4ll_cpp/dmahelper.h"
|
||||||
|
|
||||||
|
#ifndef DIAG_CRC_CALC_START
|
||||||
|
# define DIAG_CRC_CALC_START()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DIAG_CRC_CALC_END
|
||||||
|
# define DIAG_CRC_CALC_END()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DIAG_INTERRUPT_IN
|
||||||
|
# define DIAG_INTERRUPT_IN()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DIAG_INTERRUPT_OUT
|
||||||
|
# define DIAG_INTERRUPT_OUT()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace f4ll_cpp
|
||||||
|
{
|
||||||
|
|
||||||
|
void Crc_StartNextTask(struct crcstatus_t *status);
|
||||||
|
|
||||||
|
|
||||||
|
CrcScheduler::CrcScheduler(CRC_TypeDef *crcUnit, DMA_TypeDef *dma, uint32_t stream) :
|
||||||
|
m_dma(dma, stream),
|
||||||
|
m_activeSlot(nullptr),
|
||||||
|
m_firstSlot(nullptr)
|
||||||
|
{
|
||||||
|
m_crcUnit = crcUnit;
|
||||||
|
LL_DMA_EnableIT_TC(dma, stream);
|
||||||
|
LL_DMA_EnableIT_TE(dma, stream);
|
||||||
|
LL_DMA_SetM2MDstAddress(dma, stream, (uint32_t)&crcUnit->DR);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CrcScheduler::AttachTasks(struct crcslot_t *slot, struct crctask_t *tasks, uint8_t taskCount)
|
||||||
|
{
|
||||||
|
slot->count = taskCount;
|
||||||
|
slot->tasks = tasks;
|
||||||
|
memset(tasks, 0, sizeof(*tasks)*taskCount);
|
||||||
|
|
||||||
|
uint32_t prim = __get_PRIMASK();
|
||||||
|
__disable_irq();
|
||||||
|
slot->next = m_firstSlot;
|
||||||
|
m_firstSlot = slot;
|
||||||
|
__set_PRIMASK(prim);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t CrcScheduler::GetActiveTask(struct crcslot_t **slot_out)
|
||||||
|
{
|
||||||
|
uint8_t ret;
|
||||||
|
|
||||||
|
uint32_t prim = __get_PRIMASK();
|
||||||
|
|
||||||
|
__disable_irq();
|
||||||
|
ret = m_activeTask;
|
||||||
|
if(slot_out)
|
||||||
|
*slot_out = (struct crcslot_t *) m_activeSlot;
|
||||||
|
__set_PRIMASK(prim);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool CrcScheduler::IsTaskQueued(struct crcslot_t *slot, uint8_t task) {
|
||||||
|
return ((struct crctask_t volatile)slot->tasks[task]).address != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool CrcScheduler::IsTaskBusy(struct crcslot_t *slot, uint8_t task) {
|
||||||
|
struct crctask_t volatile *taskPtr = &slot->tasks[task];
|
||||||
|
return taskPtr->callback != NULL || taskPtr->callbackParam != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CrcScheduler::WaitResults(struct crcslot_t *slot, uint8_t task) {
|
||||||
|
while(IsTaskBusy(slot, task));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t CrcScheduler::Enqueue(struct crcslot_t *slot, uint8_t task, void *address, uint16_t len,
|
||||||
|
ICrcCallback* callback, void* callbackParam)
|
||||||
|
{
|
||||||
|
uint32_t prim = __get_PRIMASK();
|
||||||
|
bool need_start;
|
||||||
|
//struct crcstatus_t volatile *st = status;
|
||||||
|
|
||||||
|
while(IsTaskBusy(slot, task));
|
||||||
|
__disable_irq();
|
||||||
|
need_start = (m_activeSlot == nullptr);
|
||||||
|
slot->tasks[task].address = need_start ? NULL : address;
|
||||||
|
slot->tasks[task].wordCount = (len+3)/4;
|
||||||
|
slot->tasks[task].callback = callback;
|
||||||
|
slot->tasks[task].callbackParam = callbackParam;
|
||||||
|
if(need_start) {
|
||||||
|
m_activeSlot = slot;
|
||||||
|
m_activeTask = task;
|
||||||
|
}
|
||||||
|
__set_PRIMASK(prim);
|
||||||
|
|
||||||
|
if(need_start) {
|
||||||
|
DIAG_CRC_CALC_START();
|
||||||
|
m_crcUnit->CR = 1;
|
||||||
|
LL_DMA_SetM2MSrcAddress(m_dma.GetDma(), m_dma.GetStream(), (uint32_t)address);
|
||||||
|
LL_DMA_SetDataLength(m_dma.GetDma(), m_dma.GetStream(), (len+3)/4);
|
||||||
|
DIAG_CRC_CALC_START();
|
||||||
|
LL_DMA_EnableStream(m_dma.GetDma(), m_dma.GetStream());
|
||||||
|
}
|
||||||
|
return need_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t CrcScheduler::Compute(struct crcslot_t *slot, uint8_t task, void *address, uint16_t len)
|
||||||
|
{
|
||||||
|
uint32_t result;
|
||||||
|
Enqueue(slot, task, address, len, NULL, &result);
|
||||||
|
while((struct crcslot_t volatile *)slot->tasks[task].callbackParam);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// only called from ISR context
|
||||||
|
void CrcScheduler::StartNextTask()
|
||||||
|
{
|
||||||
|
char moreTasks;
|
||||||
|
uint8_t index = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
struct crcslot_t *slot = m_firstSlot;
|
||||||
|
moreTasks = 0;
|
||||||
|
while(slot) {
|
||||||
|
if(index < slot->count) {
|
||||||
|
if(slot->tasks[index].address) {
|
||||||
|
DIAG_CRC_CALC_START();
|
||||||
|
m_activeSlot = slot;
|
||||||
|
m_activeTask = index;
|
||||||
|
m_crcUnit->CR = 1;
|
||||||
|
LL_DMA_SetM2MSrcAddress(m_dma.GetDma(), m_dma.GetStream(), (uint32_t)slot->tasks[index].address);
|
||||||
|
LL_DMA_SetDataLength(m_dma.GetDma(), m_dma.GetStream(), slot->tasks[index].wordCount);
|
||||||
|
LL_DMA_EnableStream(m_dma.GetDma(), m_dma.GetStream());
|
||||||
|
slot->tasks[index].address = nullptr; // marking as started
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(index + 1 < slot->count)
|
||||||
|
moreTasks = 1;
|
||||||
|
}
|
||||||
|
slot = slot->next;
|
||||||
|
}
|
||||||
|
++index;
|
||||||
|
} while(moreTasks);
|
||||||
|
m_activeSlot = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// !!!PORTABILITY WARNING!!! using registers and bits directly. should be reviewed extremely when porting to a different MCU
|
||||||
|
void CrcScheduler::_HandleDmaIrq()
|
||||||
|
{
|
||||||
|
uint8_t success = 1;
|
||||||
|
|
||||||
|
DIAG_INTERRUPT_IN();
|
||||||
|
if((*m_dma.GetIsReg() & m_dma.GetTcMask()) ||
|
||||||
|
(*m_dma.GetIsReg() & m_dma.GetTeMask())) {
|
||||||
|
if(*m_dma.GetIsReg() & m_dma.GetTeMask())
|
||||||
|
success = 0;
|
||||||
|
*m_dma.GetIfcReg() = *m_dma.GetIsReg() & (m_dma.GetTcMask() | m_dma.GetTeMask());
|
||||||
|
LL_DMA_DisableStream(m_dma.GetDma(), m_dma.GetStream());
|
||||||
|
if(m_activeSlot) {
|
||||||
|
crctask_t *tsk = &m_activeSlot->tasks[m_activeTask];
|
||||||
|
if(tsk->callback)
|
||||||
|
tsk->callback->CrcCalculationCompleted(tsk->callbackParam, m_crcUnit->DR, success);
|
||||||
|
else if(tsk->callbackParam)
|
||||||
|
*(uint32_t*)tsk->callbackParam = success ? m_crcUnit->DR : 0xffffffff;
|
||||||
|
tsk->callback = nullptr;
|
||||||
|
tsk->callbackParam = nullptr; // marking as inactive
|
||||||
|
DIAG_CRC_CALC_END();
|
||||||
|
StartNextTask();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DIAG_INTERRUPT_OUT();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // f4ll_cpp
|
72
components/f4ll_cpp/crcscheduler.h
Normal file
72
components/f4ll_cpp/crcscheduler.h
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* interrupt.h
|
||||||
|
*
|
||||||
|
* Created on: Aug 29, 2019
|
||||||
|
* Author: abody
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CRC_HANDLER_H_
|
||||||
|
#define CRC_HANDLER_H_
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG
|
||||||
|
#include "config.h"
|
||||||
|
#endif // HAVE_CONFIG
|
||||||
|
|
||||||
|
#include <platform/crc_ll.h>
|
||||||
|
#include <f4ll_cpp/dmahelper.h>
|
||||||
|
|
||||||
|
namespace f4ll_cpp
|
||||||
|
{
|
||||||
|
|
||||||
|
class CrcScheduler {
|
||||||
|
public:
|
||||||
|
struct ICrcCallback {
|
||||||
|
virtual void CrcCalculationCompleted(void*, uint32_t, uint8_t) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct crctask_t {
|
||||||
|
void * volatile address;
|
||||||
|
uint16_t wordCount;
|
||||||
|
ICrcCallback* callback;
|
||||||
|
void *callbackParam;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct crcslot_t {
|
||||||
|
uint16_t count;
|
||||||
|
struct crcslot_t *next;
|
||||||
|
struct crctask_t *tasks;
|
||||||
|
};
|
||||||
|
|
||||||
|
CrcScheduler(CRC_TypeDef *crcUnit, DMA_TypeDef *dma, uint32_t stream);
|
||||||
|
|
||||||
|
uint8_t GetActiveTask(struct crcslot_t **slot_out);
|
||||||
|
bool IsTaskQueued(struct crcslot_t *slot, uint8_t task);
|
||||||
|
bool IsTaskBusy(struct crcslot_t *slot, uint8_t task);
|
||||||
|
|
||||||
|
void WaitResults(struct crcslot_t *slot, uint8_t task);
|
||||||
|
|
||||||
|
void AttachTasks(struct crcslot_t *slot, struct crctask_t *tasks, uint8_t taskCount);
|
||||||
|
|
||||||
|
uint8_t Enqueue(struct crcslot_t *slot, uint8_t task, void *address, uint16_t len,
|
||||||
|
ICrcCallback* callback, void* callbackParam);
|
||||||
|
uint32_t Compute(struct crcslot_t *slot, uint8_t task, void *address, uint16_t len);
|
||||||
|
static void HandleDmaIrq(void *param) { reinterpret_cast<CrcScheduler*>(param)->_HandleDmaIrq(); }
|
||||||
|
void _HandleDmaIrq();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void StartNextTask();
|
||||||
|
|
||||||
|
CRC_TypeDef *m_crcUnit;
|
||||||
|
DmaHelper m_dma;
|
||||||
|
|
||||||
|
volatile crcslot_t *m_activeSlot;
|
||||||
|
volatile uint8_t m_activeTask;
|
||||||
|
|
||||||
|
crcslot_t *m_firstSlot;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // f4ll_cpp
|
||||||
|
|
||||||
|
#endif /* CRC_HANDLER_H_ */
|
86
components/f4ll_cpp/dmahelper.cpp
Normal file
86
components/f4ll_cpp/dmahelper.cpp
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* dma_helper.c
|
||||||
|
*
|
||||||
|
* Created on: Sep 18, 2019
|
||||||
|
* Author: abody
|
||||||
|
*/
|
||||||
|
#include <f4ll_cpp/dmahelper.h>
|
||||||
|
#ifndef MOCKABLE
|
||||||
|
#define MOCKABLE(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace f4ll_cpp
|
||||||
|
{
|
||||||
|
|
||||||
|
DmaHelper::DmaHelper(DMA_TypeDef *dma, uint32_t stream)
|
||||||
|
{
|
||||||
|
m_dma = dma;
|
||||||
|
m_stream = stream;
|
||||||
|
m_isReg = _GetIsReg(dma, stream);
|
||||||
|
m_ifcReg = _GetIfcReg(dma, stream);
|
||||||
|
m_feMask = _GetFeMask(stream);
|
||||||
|
m_dmeMask = _GetDmeMask(stream);
|
||||||
|
m_teMask = _GetTeMask(stream);
|
||||||
|
m_htMask = _GetHtMask(stream);
|
||||||
|
m_tcMask = _GetTcMask(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
volatile uint32_t* DmaHelper::_GetIsReg(DMA_TypeDef *dma, uint32_t stream)
|
||||||
|
{
|
||||||
|
if(dma == DMA1)
|
||||||
|
return (stream < LL_DMA_STREAM_4) ? &DMA1->LISR : &DMA1->HISR;
|
||||||
|
else
|
||||||
|
return (stream < LL_DMA_STREAM_4) ? &DMA2->LISR : &DMA2->HISR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
volatile uint32_t* DmaHelper::_GetIfcReg(DMA_TypeDef *dma, uint32_t stream)
|
||||||
|
{
|
||||||
|
if(dma == DMA1)
|
||||||
|
return (stream < LL_DMA_STREAM_4) ? &DMA1->LIFCR : &DMA1->HIFCR;
|
||||||
|
else
|
||||||
|
return (stream < LL_DMA_STREAM_4) ? &DMA2->LIFCR : &DMA2->HIFCR;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DmaHelper::_GetFeMask(uint32_t stream)
|
||||||
|
{
|
||||||
|
static const uint32_t feMasks[8] = {
|
||||||
|
DMA_LISR_FEIF0, DMA_LISR_FEIF1, DMA_LISR_FEIF2, DMA_LISR_FEIF3, DMA_HISR_FEIF4, DMA_HISR_FEIF5, DMA_HISR_FEIF6, DMA_HISR_FEIF7
|
||||||
|
};
|
||||||
|
return feMasks[stream];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DmaHelper::_GetDmeMask(uint32_t stream)
|
||||||
|
{
|
||||||
|
static const uint32_t dmeMasks[8] = {
|
||||||
|
DMA_LISR_DMEIF0, DMA_LISR_DMEIF1, DMA_LISR_DMEIF2, DMA_LISR_DMEIF3, DMA_HISR_DMEIF4, DMA_HISR_DMEIF5, DMA_HISR_DMEIF6, DMA_HISR_DMEIF7
|
||||||
|
};
|
||||||
|
return dmeMasks[stream];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DmaHelper::_GetTeMask(uint32_t stream)
|
||||||
|
{
|
||||||
|
static const uint32_t teMasks[8] = {
|
||||||
|
DMA_LISR_TEIF0, DMA_LISR_TEIF1, DMA_LISR_TEIF2, DMA_LISR_TEIF3, DMA_HISR_TEIF4, DMA_HISR_TEIF5, DMA_HISR_TEIF6, DMA_HISR_TEIF7
|
||||||
|
};
|
||||||
|
return teMasks[stream];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DmaHelper::_GetHtMask(uint32_t stream)
|
||||||
|
{
|
||||||
|
static const uint32_t htMasks[8] = {
|
||||||
|
DMA_LISR_HTIF0, DMA_LISR_HTIF1, DMA_LISR_HTIF2, DMA_LISR_HTIF3, DMA_HISR_HTIF4, DMA_HISR_HTIF5, DMA_HISR_HTIF6, DMA_HISR_HTIF7
|
||||||
|
};
|
||||||
|
return htMasks[stream];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DmaHelper::_GetTcMask(uint32_t stream)
|
||||||
|
{
|
||||||
|
static const uint32_t tcMasks[8] = {
|
||||||
|
DMA_LISR_TCIF0, DMA_LISR_TCIF1, DMA_LISR_TCIF2, DMA_LISR_TCIF3, DMA_HISR_TCIF4, DMA_HISR_TCIF5, DMA_HISR_TCIF6, DMA_HISR_TCIF7
|
||||||
|
};
|
||||||
|
|
||||||
|
return tcMasks[stream];
|
||||||
|
}
|
||||||
|
|
||||||
|
} // f4ll_cpp
|
57
components/f4ll_cpp/dmahelper.h
Normal file
57
components/f4ll_cpp/dmahelper.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* dma_helper.h
|
||||||
|
*
|
||||||
|
* Created on: Sep 18, 2019
|
||||||
|
* Author: abody
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DMA_HELPER_H_
|
||||||
|
#define DMA_HELPER_H_
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <platform/dma_ll.h>
|
||||||
|
|
||||||
|
#ifndef DECLARE_MOCK
|
||||||
|
#define DECLARE_MOCK(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace f4ll_cpp
|
||||||
|
{
|
||||||
|
|
||||||
|
class DmaHelper {
|
||||||
|
public:
|
||||||
|
DmaHelper(DMA_TypeDef *dma, uint32_t stream);
|
||||||
|
|
||||||
|
DMA_TypeDef* GetDma() { return m_dma; }
|
||||||
|
uint32_t GetStream() { return m_stream; }
|
||||||
|
volatile uint32_t* GetIsReg() { return m_isReg; }
|
||||||
|
volatile uint32_t* GetIfcReg() { return m_ifcReg; }
|
||||||
|
uint32_t GetDmeMask() { return m_dmeMask; }
|
||||||
|
uint32_t GetTeMask() { return m_teMask; }
|
||||||
|
uint32_t GetHtMask() { return m_htMask; }
|
||||||
|
uint32_t GetTcMask() { return m_tcMask; }
|
||||||
|
uint32_t GetFeMask() { return m_feMask; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
static volatile uint32_t* _GetIsReg(DMA_TypeDef *dma, uint32_t stream);
|
||||||
|
static volatile uint32_t* _GetIfcReg(DMA_TypeDef *dma, uint32_t stream);
|
||||||
|
static uint32_t _GetDmeMask(uint32_t stream);
|
||||||
|
static uint32_t _GetTeMask(uint32_t stream);
|
||||||
|
static uint32_t _GetHtMask(uint32_t stream);
|
||||||
|
static uint32_t _GetTcMask(uint32_t stream);
|
||||||
|
static uint32_t _GetFeMask(uint32_t stream);
|
||||||
|
|
||||||
|
private:
|
||||||
|
DMA_TypeDef *m_dma;
|
||||||
|
uint32_t m_stream;
|
||||||
|
volatile uint32_t *m_isReg;
|
||||||
|
volatile uint32_t *m_ifcReg;
|
||||||
|
uint32_t m_feMask;
|
||||||
|
uint32_t m_dmeMask;
|
||||||
|
uint32_t m_teMask;
|
||||||
|
uint32_t m_htMask;
|
||||||
|
uint32_t m_tcMask;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // f4ll_cpp
|
||||||
|
|
||||||
|
#endif /* DMA_HELPER_H_ */
|
404
components/f4ll_cpp/ili9341.cpp
Normal file
404
components/f4ll_cpp/ili9341.cpp
Normal file
|
@ -0,0 +1,404 @@
|
||||||
|
#include <f4ll_cpp/ili9341.h>
|
||||||
|
#include <platform/core_ll.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include <FreeRTOS.h>
|
||||||
|
#include <task.h>
|
||||||
|
|
||||||
|
#define LCD_L 320
|
||||||
|
#define LCD_S 240
|
||||||
|
|
||||||
|
#define LCD_W LCD_L
|
||||||
|
#define LCD_H LCD_S
|
||||||
|
|
||||||
|
#define LCD_REG (*((volatile unsigned short *) 0x60000000)) /* DC = 0 */
|
||||||
|
#define LCD_RAM (*((volatile unsigned short *) 0x60080000)) /* DC = 1 */
|
||||||
|
|
||||||
|
#define RGB2U16(R,G,B) ((R & 0xf8) << 8 | (G & 0xfc) << 3 | (B & 0xf8) >> 3)
|
||||||
|
#define MSBSPLIT(x) ((uint8_t)(x >> 8)), ((uint8_t)x)
|
||||||
|
|
||||||
|
namespace f4ll_cpp {
|
||||||
|
|
||||||
|
Ili9341Fsmc::Ili9341Fsmc(volatile uint16_t *reg, volatile uint16_t *ram,
|
||||||
|
DMA_TypeDef *dma, uint32_t dmaStream,
|
||||||
|
bool horizontal)
|
||||||
|
: DmaHelper(dma, dmaStream)
|
||||||
|
, m_reg(reg ? reg : (volatile unsigned short *) 0x60000000)
|
||||||
|
, m_ram(ram ? ram : (volatile unsigned short *) 0x60080000)
|
||||||
|
, m_width(horizontal ? LCD_L : LCD_S)
|
||||||
|
, m_height(horizontal ? LCD_S : LCD_L)
|
||||||
|
, m_rectX(0)
|
||||||
|
, m_rectY(0)
|
||||||
|
, m_rectWidth(m_width)
|
||||||
|
, m_rectHeight(m_height)
|
||||||
|
{
|
||||||
|
LL_DMA_EnableIT_TC(GetDma(), GetStream());
|
||||||
|
LL_DMA_EnableIT_TE(GetDma(), GetStream());
|
||||||
|
|
||||||
|
WriteCmd(ILI9341_RESET);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(10));
|
||||||
|
WriteCmd(ILI9341_DISPLAY_OFF);
|
||||||
|
WriteCmd(ILI9341_POWERA, {0x39, 0x2C, 0x00, 0x34, 0x02});
|
||||||
|
WriteCmd(ILI9341_POWERB, {0x00, 0xC1, 0x30});
|
||||||
|
WriteCmd(ILI9341_DTCA, {0x85, 0x00, 0x78});
|
||||||
|
WriteCmd(ILI9341_DTCB, {0x00, 0x00});
|
||||||
|
WriteCmd(ILI9341_POWER_SEQ, {0x64, 0x03, 0x12, 0x81});
|
||||||
|
WriteCmd(ILI9341_PRC, 0x20);
|
||||||
|
WriteCmd(ILI9341_POWER1, 0x23);
|
||||||
|
WriteCmd(ILI9341_POWER2, 0x10);
|
||||||
|
WriteCmd(ILI9341_VCOM1, {0x3E, 0x28});
|
||||||
|
WriteCmd(ILI9341_VCOM2, 0x86);
|
||||||
|
WriteCmd(ILI9341_MAC, horizontal ? 0xe8 : 0x48);
|
||||||
|
WriteCmd(ILI9341_PIXEL_FORMAT, 0x55);
|
||||||
|
WriteCmd(ILI9341_FRC, {0x00, 0x18});
|
||||||
|
WriteCmd(ILI9341_DFC, {0x08, 0x82, 0x27});
|
||||||
|
WriteCmd(ILI9341_3GAMMA_EN, 0x00);
|
||||||
|
WriteCmd(ILI9341_COLUMN_ADDR, {0x00, 0x00, (uint16_t)((m_width-1) >> 8), (uint16_t)((m_width-1) & 0x00ff)});
|
||||||
|
WriteCmd(ILI9341_PAGE_ADDR, {0x00, 0x00, (uint16_t)((m_height-1) >> 8), (uint16_t)((m_height-1) & 0x00ff)});
|
||||||
|
WriteCmd(ILI9341_GAMMA, 0x01);
|
||||||
|
WriteCmd(ILI9341_PGAMMA, {0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00});
|
||||||
|
WriteCmd(ILI9341_NGAMMA, {0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F});
|
||||||
|
WriteCmd(ILI9341_SLEEP_OUT);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
WriteCmd(ILI9341_DISPLAY_ON);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ili9341Fsmc::WriteCmd(uint16_t cmd, std::initializer_list<const uint16_t> params)
|
||||||
|
{
|
||||||
|
*m_reg = cmd;
|
||||||
|
for(uint16_t param : params)
|
||||||
|
*m_ram = param;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ili9341Fsmc::WriteCmd_(uint16_t cmd, uint16_t cnt, ...)
|
||||||
|
{
|
||||||
|
va_list argp;
|
||||||
|
va_start(argp, cnt);
|
||||||
|
|
||||||
|
*m_reg = cmd;
|
||||||
|
for(uint16_t n = 0; n < cnt; ++n) {
|
||||||
|
*m_ram = (uint16_t) va_arg(argp, uint32_t);
|
||||||
|
}
|
||||||
|
va_end(argp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ili9341Fsmc::SetScrollMode(bool on)
|
||||||
|
{
|
||||||
|
if(on != m_scrollMode) {
|
||||||
|
if(on)
|
||||||
|
WriteCmd(ILI9341_VERTICAL_SCROLLING_DEFINITION, {0x00, 0x00, MSBSPLIT(m_height), 0x00, 0x00});
|
||||||
|
else
|
||||||
|
WriteCmd(ILI9341_NORMAL_DISPLAY_MODE_ON);
|
||||||
|
m_scrollMode = on;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ili9341Fsmc::WritePixels(void *src, uint32_t count, bool increment, bool async)
|
||||||
|
{
|
||||||
|
WriteCmd(ILI9341_GRAM);
|
||||||
|
LL_DMA_SetM2MDstAddress(GetDma(), GetStream(), (uint32_t)m_ram);
|
||||||
|
LL_DMA_SetMemoryIncMode(GetDma(), GetStream(), LL_DMA_MEMORY_NOINCREMENT);
|
||||||
|
LL_DMA_SetM2MSrcAddress(GetDma(), GetStream(), (uint32_t) src);
|
||||||
|
LL_DMA_SetPeriphIncMode(GetDma(), GetStream(), increment ? LL_DMA_PERIPH_NOINCREMENT : LL_DMA_PERIPH_NOINCREMENT);
|
||||||
|
SetupDmaSize(count);
|
||||||
|
m_dmaEngineBusy = true;
|
||||||
|
LL_DMA_EnableStream(GetDma(), GetStream());
|
||||||
|
if(!async)
|
||||||
|
WaitDmaIdle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ili9341Fsmc::ReadGRam(PixelPair *dst, uint32_t count, bool async)
|
||||||
|
{
|
||||||
|
WriteCmd(ILI9341_MEMORY_READ);
|
||||||
|
*m_ram;
|
||||||
|
LL_DMA_SetM2MSrcAddress(GetDma(), GetStream(), reinterpret_cast<uint32_t>(m_ram));
|
||||||
|
LL_DMA_SetPeriphIncMode(GetDma(), GetStream(), LL_DMA_PERIPH_NOINCREMENT);
|
||||||
|
LL_DMA_SetM2MDstAddress(GetDma(), GetStream(), reinterpret_cast<uint32_t>(dst));
|
||||||
|
LL_DMA_SetMemoryIncMode(GetDma(), GetStream(), LL_DMA_MEMORY_INCREMENT);
|
||||||
|
SetupDmaSize(count);
|
||||||
|
m_dmaEngineBusy = true;
|
||||||
|
LL_DMA_EnableStream(GetDma(), GetStream());
|
||||||
|
if(!async)
|
||||||
|
WaitDmaIdle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ili9341Fsmc::ReadPixels(uint16_t *dst, uint32_t count)
|
||||||
|
{
|
||||||
|
uint16_t *barrier = dst + count;
|
||||||
|
union {
|
||||||
|
PixelPair pp;
|
||||||
|
uint16_t u16[3];
|
||||||
|
} rawData;
|
||||||
|
|
||||||
|
WriteCmd(ILI9341_MEMORY_READ);
|
||||||
|
*m_ram;
|
||||||
|
do {
|
||||||
|
for(uint8_t n = 0; n < 3; ++n)
|
||||||
|
rawData.u16[n] = *m_ram;
|
||||||
|
*dst++ = RGB2U16(rawData.pp.r0, rawData.pp.g0, rawData.pp.b0);
|
||||||
|
if(dst != barrier)
|
||||||
|
*dst++ = RGB2U16(rawData.pp.r1, rawData.pp.g1, rawData.pp.b1);
|
||||||
|
} while(dst != barrier);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ili9341Fsmc::SetScrollOffset()
|
||||||
|
{
|
||||||
|
uint16_t offsetData[2] = { MSBSPLIT(m_scrollOffset) };
|
||||||
|
WriteCmd(ILI9341_VERTICAL_SCROLLING_START_ADDRESS);
|
||||||
|
*m_ram = offsetData[0];
|
||||||
|
*m_ram = offsetData[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ili9341Fsmc::SetRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height)
|
||||||
|
{
|
||||||
|
if(x > m_width || y > m_height || !width || !height )
|
||||||
|
return;
|
||||||
|
|
||||||
|
WaitDmaIdle();
|
||||||
|
|
||||||
|
m_rectX = x;
|
||||||
|
m_rectY = y;
|
||||||
|
m_rectWidth = x + width > m_width ? m_width - x : width;
|
||||||
|
m_rectHeight = y + height > m_height ? m_height - x : height;
|
||||||
|
|
||||||
|
uint16_t right = x + m_rectWidth - 1;
|
||||||
|
uint16_t bottom = y + m_rectHeight - 1;
|
||||||
|
|
||||||
|
WriteCmd(ILI9341_COLUMN_ADDR, { MSBSPLIT(x), MSBSPLIT(right) });
|
||||||
|
WriteCmd(ILI9341_PAGE_ADDR, { MSBSPLIT(y), MSBSPLIT(bottom) });
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ili9341Fsmc::FillRect(uint16_t color, bool async)
|
||||||
|
{
|
||||||
|
uint32_t count = m_rectWidth * m_rectHeight;
|
||||||
|
WaitDmaIdle();
|
||||||
|
m_dmaColor = color;
|
||||||
|
WritePixels(&m_dmaColor, count, false, async);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ili9341Fsmc::FillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color, bool async)
|
||||||
|
{
|
||||||
|
SetRect(x, y, width, height);
|
||||||
|
FillRect(color, async);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ili9341Fsmc::SetupDmaSize(uint32_t size)
|
||||||
|
{
|
||||||
|
if(size > 0xffff) {
|
||||||
|
LL_DMA_SetDataLength(GetDma(), GetStream(), 0xffff);
|
||||||
|
m_dmaRemainingPixels = size - 0xffff;
|
||||||
|
} else {
|
||||||
|
LL_DMA_SetDataLength(GetDma(), GetStream(), size);
|
||||||
|
m_dmaRemainingPixels = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ili9341Fsmc::HandleDmaIrq()
|
||||||
|
{
|
||||||
|
if(*GetIsReg() & GetTcMask()) { //LL_DMA_IsActiveFlag_TCx(DMAy))
|
||||||
|
*GetIfcReg() = GetTcMask(); //LL_DMA_ClearFlag_TCx(DMAy)
|
||||||
|
LL_DMA_DisableStream(GetDma(), GetStream());
|
||||||
|
if(!m_dmaRemainingPixels)
|
||||||
|
m_dmaEngineBusy = false;
|
||||||
|
else {
|
||||||
|
SetupDmaSize(m_dmaRemainingPixels);
|
||||||
|
LL_DMA_EnableStream(GetDma(), GetStream());
|
||||||
|
}
|
||||||
|
} else if(*GetIsReg() & GetTeMask()) //LL_DMA_IsActiveFlag_TEx(DMAy))
|
||||||
|
*GetIfcReg() = GetTeMask(); // //LL_DMA_ClearFlag_TEx(DMAy)
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ili9341Fsmc::SetCursor(uint16_t x, uint16_t y, uint16_t fgColor, uint16_t bgColor)
|
||||||
|
{
|
||||||
|
m_xPos = x;
|
||||||
|
m_yPos = y;
|
||||||
|
m_fgColor = fgColor;
|
||||||
|
m_bgColor = bgColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ili9341Fsmc::SetCursor(uint16_t x, uint16_t y)
|
||||||
|
{
|
||||||
|
m_xPos = x;
|
||||||
|
m_yPos = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ili9341Fsmc::PrintChar(char c, bool transparent)
|
||||||
|
{
|
||||||
|
// fonts are rotated, one byte representing one column
|
||||||
|
if(m_xPos > m_width - CHRWIDTH || m_yPos > m_height - CHRHEIGHT || c < ' ' || c >= '~')
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint8_t const *chrPtr = m_font[c - 32];
|
||||||
|
|
||||||
|
SetRect(m_xPos, AdjustY(m_yPos), CHRWIDTH, CHRHEIGHT);
|
||||||
|
WaitDmaIdle();
|
||||||
|
if(transparent)
|
||||||
|
ReadPixels(m_fontBkgBuffer[0], CHRHEIGHT * CHRWIDTH);
|
||||||
|
WriteCmd(ILI9341_GRAM);
|
||||||
|
for(uint8_t y = 0; y < CHRHEIGHT; ++y ) {
|
||||||
|
uint8_t mask = 1 << y;
|
||||||
|
for(uint8_t x = 0; x < CHRWIDTH; ++x) {
|
||||||
|
*m_ram = (chrPtr[x] & mask) ? m_fgColor : (transparent ? m_fontBkgBuffer[y][x] : m_bgColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_xPos += CHRWIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ili9341Fsmc::PrintChar(char c, uint16_t x, uint16_t y, uint16_t fgColor, uint16_t bgColor)
|
||||||
|
{
|
||||||
|
SetCursor(x, y, fgColor, bgColor);
|
||||||
|
PrintChar(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ili9341Fsmc::Print(char const *str, uint8_t len, bool transparent)
|
||||||
|
{
|
||||||
|
if(!len)
|
||||||
|
len = strlen(str);
|
||||||
|
while(len--) {
|
||||||
|
if(*str == '\r')
|
||||||
|
m_xPos = 0;
|
||||||
|
else if(*str == '\n') {
|
||||||
|
m_yPos += CHRHEIGHT;
|
||||||
|
if(m_yPos >= m_height) {
|
||||||
|
m_yPos -= CHRHEIGHT;
|
||||||
|
m_scrollOffset += CHRHEIGHT;
|
||||||
|
if(m_scrollOffset >= m_height)
|
||||||
|
m_scrollOffset -= m_height;
|
||||||
|
WaitDmaIdle();
|
||||||
|
SetScrollOffset();
|
||||||
|
if(!transparent)
|
||||||
|
FillRect(0, AdjustY(m_yPos), m_width, CHRHEIGHT, m_bgColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
PrintChar(*str, transparent);
|
||||||
|
++str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ili9341Fsmc::Test()
|
||||||
|
{
|
||||||
|
// static PixelPair linebuf[320/2];
|
||||||
|
// uint16_t x;
|
||||||
|
|
||||||
|
// WriteCmd(ILI9341_READ_DISPLAY_PIXEL_FORMAT);
|
||||||
|
// for( x= 0; x < 2; ++x)
|
||||||
|
// reinterpret_cast<uint16_t*>(linebuf)[x] = *m_ram;
|
||||||
|
|
||||||
|
|
||||||
|
// WriteCmd(ILI9341_GRAM);
|
||||||
|
// uint16_t fillers[4] = { 0xf800, 0x7e0, 0x1f, 0xffff };
|
||||||
|
// for(uint32_t y = 0; y < m_height; ++y) {
|
||||||
|
// for(x = 0; x < m_width / 2; ++x)
|
||||||
|
// *m_ram = fillers[ (x&0x18) >> 3 ];
|
||||||
|
// for( ; x < m_width; ++x)
|
||||||
|
// *m_ram = 0;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// SetRect(0, 0, 11, 2);
|
||||||
|
// ReadGRam(linebuf, 11 * 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const uint8_t Ili9341Fsmc::m_font[CHRCOUNT][CHRWIDTH] = {
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x00}, //
|
||||||
|
{0x2f,0x00,0x00,0x00,0x00,0x00}, // !
|
||||||
|
{0x03,0x00,0x03,0x00,0x00,0x00}, // "
|
||||||
|
{0x12,0x3f,0x12,0x12,0x3f,0x12}, // #
|
||||||
|
{0x2e,0x2a,0x7f,0x2a,0x3a,0x00}, // $
|
||||||
|
{0x23,0x13,0x08,0x04,0x32,0x31}, // %
|
||||||
|
{0x10,0x2a,0x25,0x2a,0x10,0x20}, // &
|
||||||
|
{0x02,0x01,0x00,0x00,0x00,0x00}, // '
|
||||||
|
{0x1e,0x21,0x00,0x00,0x00,0x00}, // (
|
||||||
|
{0x21,0x1e,0x00,0x00,0x00,0x00}, // )
|
||||||
|
{0x08,0x2a,0x1c,0x2a,0x08,0x08}, // *
|
||||||
|
{0x08,0x08,0x3e,0x08,0x08,0x08}, // +
|
||||||
|
{0x80,0x60,0x00,0x00,0x00,0x00}, // ,
|
||||||
|
{0x08,0x08,0x08,0x08,0x08,0x00}, // -
|
||||||
|
{0x30,0x30,0x00,0x00,0x00,0x00}, // .
|
||||||
|
{0x20,0x10,0x08,0x04,0x02,0x00}, // /
|
||||||
|
{0x1e,0x31,0x29,0x25,0x23,0x1e}, // 0
|
||||||
|
{0x22,0x21,0x3f,0x20,0x20,0x20}, // 1
|
||||||
|
{0x32,0x29,0x29,0x29,0x29,0x26}, // 2
|
||||||
|
{0x12,0x21,0x21,0x25,0x25,0x1a}, // 3
|
||||||
|
{0x18,0x14,0x12,0x3f,0x10,0x10}, // 4
|
||||||
|
{0x17,0x25,0x25,0x25,0x25,0x19}, // 5
|
||||||
|
{0x1e,0x25,0x25,0x25,0x25,0x18}, // 6
|
||||||
|
{0x01,0x01,0x31,0x09,0x05,0x03}, // 7
|
||||||
|
{0x1a,0x25,0x25,0x25,0x25,0x1a}, // 8
|
||||||
|
{0x06,0x29,0x29,0x29,0x29,0x1e}, // 9
|
||||||
|
{0x24,0x00,0x00,0x00,0x00,0x00}, // :
|
||||||
|
{0x80,0x64,0x00,0x00,0x00,0x00}, // ;
|
||||||
|
{0x08,0x14,0x22,0x00,0x00,0x00}, // <
|
||||||
|
{0x14,0x14,0x14,0x14,0x14,0x00}, // =
|
||||||
|
{0x22,0x14,0x08,0x00,0x00,0x00}, // >
|
||||||
|
{0x02,0x01,0x01,0x29,0x05,0x02}, // ?
|
||||||
|
{0x1e,0x21,0x2d,0x2b,0x2d,0x0e}, // @
|
||||||
|
{0x3e,0x09,0x09,0x09,0x09,0x3e}, // A
|
||||||
|
{0x3f,0x25,0x25,0x25,0x25,0x1a}, // B
|
||||||
|
{0x1e,0x21,0x21,0x21,0x21,0x12}, // C
|
||||||
|
{0x3f,0x21,0x21,0x21,0x12,0x0c}, // D
|
||||||
|
{0x3f,0x25,0x25,0x25,0x25,0x21}, // E
|
||||||
|
{0x3f,0x05,0x05,0x05,0x05,0x01}, // F
|
||||||
|
{0x1e,0x21,0x21,0x21,0x29,0x1a}, // G
|
||||||
|
{0x3f,0x04,0x04,0x04,0x04,0x3f}, // H
|
||||||
|
{0x21,0x21,0x3f,0x21,0x21,0x21}, // I
|
||||||
|
{0x10,0x20,0x20,0x20,0x20,0x1f}, // J
|
||||||
|
{0x3f,0x04,0x0c,0x0a,0x11,0x20}, // K
|
||||||
|
{0x3f,0x20,0x20,0x20,0x20,0x20}, // L
|
||||||
|
{0x3f,0x02,0x04,0x04,0x02,0x3f}, // M
|
||||||
|
{0x3f,0x02,0x04,0x08,0x10,0x3f}, // N
|
||||||
|
{0x1e,0x21,0x21,0x21,0x21,0x1e}, // O
|
||||||
|
{0x3f,0x09,0x09,0x09,0x09,0x06}, // P
|
||||||
|
{0x1e,0x21,0x29,0x31,0x21,0x1e}, // Q
|
||||||
|
{0x3f,0x09,0x09,0x09,0x19,0x26}, // R
|
||||||
|
{0x12,0x25,0x25,0x25,0x25,0x18}, // S
|
||||||
|
{0x01,0x01,0x01,0x3f,0x01,0x01}, // T
|
||||||
|
{0x1f,0x20,0x20,0x20,0x20,0x1f}, // U
|
||||||
|
{0x0f,0x10,0x20,0x20,0x10,0x0f}, // V
|
||||||
|
{0x1f,0x20,0x10,0x10,0x20,0x1f}, // W
|
||||||
|
{0x21,0x12,0x0c,0x0c,0x12,0x21}, // X
|
||||||
|
{0x01,0x02,0x0c,0x38,0x04,0x02}, // Y
|
||||||
|
{0x21,0x31,0x29,0x25,0x23,0x21}, // Z
|
||||||
|
{0x3f,0x21,0x00,0x00,0x00,0x00}, // [
|
||||||
|
{0x02,0x04,0x08,0x10,0x20,0x00}, // "\"
|
||||||
|
{0x21,0x3f,0x00,0x00,0x00,0x00}, // ]
|
||||||
|
{0x04,0x02,0x3f,0x02,0x04,0x00}, // ^
|
||||||
|
{0x40,0x40,0x40,0x40,0x40,0x40}, // _
|
||||||
|
{0x01,0x02,0x00,0x00,0x00,0x00}, // `
|
||||||
|
{0x10,0x30,0x2a,0x2a,0x3c,0x00}, // a
|
||||||
|
{0x3f,0x24,0x24,0x24,0x18,0x00}, // b
|
||||||
|
{0x0c,0x14,0x22,0x22,0x00,0x00}, // c
|
||||||
|
{0x18,0x24,0x24,0x24,0x3f,0x00}, // d
|
||||||
|
{0x1c,0x2c,0x2a,0x2a,0x24,0x00}, // e
|
||||||
|
{0x3e,0x05,0x01,0x00,0x00,0x00}, // f
|
||||||
|
{0x18,0x28,0xa4,0xa4,0x7c,0x00}, // g
|
||||||
|
{0x3f,0x04,0x04,0x0c,0x30,0x00}, // h
|
||||||
|
{0x24,0x3d,0x20,0x00,0x00,0x00}, // i
|
||||||
|
{0x20,0x40,0x40,0x3d,0x00,0x00}, // j
|
||||||
|
{0x3f,0x0c,0x12,0x20,0x00,0x00}, // k
|
||||||
|
{0x1f,0x20,0x20,0x00,0x00,0x00}, // l
|
||||||
|
{0x3e,0x02,0x3c,0x02,0x3c,0x00}, // m
|
||||||
|
{0x3e,0x02,0x02,0x02,0x3c,0x00}, // n
|
||||||
|
{0x0c,0x14,0x22,0x32,0x0c,0x00}, // o
|
||||||
|
{0xfc,0x24,0x24,0x24,0x18,0x00}, // p
|
||||||
|
{0x18,0x24,0x24,0x24,0xfc,0x80}, // q
|
||||||
|
{0x3c,0x04,0x02,0x02,0x00,0x00}, // r
|
||||||
|
{0x24,0x2c,0x2a,0x2a,0x10,0x00}, // s
|
||||||
|
{0x02,0x1f,0x22,0x20,0x00,0x00}, // t
|
||||||
|
{0x1e,0x20,0x20,0x20,0x1e,0x00}, // u
|
||||||
|
{0x06,0x18,0x20,0x18,0x06,0x00}, // v
|
||||||
|
{0x1e,0x30,0x1c,0x30,0x0e,0x00}, // w
|
||||||
|
{0x22,0x14,0x08,0x14,0x22,0x00}, // x
|
||||||
|
{0x0c,0x10,0xa0,0xa0,0x7c,0x00}, // y
|
||||||
|
{0x22,0x32,0x2a,0x26,0x22,0x22}, // z
|
||||||
|
{0x0c,0x3f,0x21,0x00,0x00,0x00}, // {
|
||||||
|
{0x3f,0x00,0x00,0x00,0x00,0x00}, // |
|
||||||
|
{0x21,0x3f,0x0c,0x00,0x00,0x00}, // }
|
||||||
|
{0x02,0x01,0x02,0x01,0x00,0x00}, // ~
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x00}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // f4ll_cpp
|
193
components/f4ll_cpp/ili9341.h
Normal file
193
components/f4ll_cpp/ili9341.h
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
#ifndef __ili9341_H
|
||||||
|
#define __ili9341_H
|
||||||
|
|
||||||
|
#include <f4ll_cpp/strangeton.h>
|
||||||
|
#include <f4ll_cpp/dmahelper.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
namespace f4ll_cpp {
|
||||||
|
|
||||||
|
class Ili9341Fsmc : public Strangeton<Ili9341Fsmc>, private DmaHelper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct PixelPair {
|
||||||
|
uint8_t g0, r0, r1, b0, b1, g1;
|
||||||
|
};
|
||||||
|
|
||||||
|
Ili9341Fsmc(volatile uint16_t *reg, volatile uint16_t *ram,
|
||||||
|
DMA_TypeDef *dma, uint32_t dmaStream,
|
||||||
|
bool horizontal = true);
|
||||||
|
|
||||||
|
void SetScrollMode(bool on);
|
||||||
|
void FillRect(uint16_t color, bool async = true);
|
||||||
|
void FillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color, bool async = true);
|
||||||
|
uint16_t Width() { return m_width; }
|
||||||
|
uint16_t Height() { return m_height; }
|
||||||
|
uint8_t ChrHeight() { return CHRHEIGHT; }
|
||||||
|
uint8_t ChrWidth() { return CHRWIDTH; }
|
||||||
|
void SetCursor(uint16_t x, uint16_t y, uint16_t fgColor, uint16_t bgColor);
|
||||||
|
void SetCursor(uint16_t x, uint16_t y);
|
||||||
|
void PrintChar(char c, uint16_t x, uint16_t y, uint16_t fgColor, uint16_t bgColor);
|
||||||
|
void PrintChar(char c, bool transparent = false);
|
||||||
|
void Print(char const *str, uint8_t len = 0, bool transparent = false);
|
||||||
|
|
||||||
|
inline void WaitDmaIdle() { while(m_dmaEngineBusy); }
|
||||||
|
|
||||||
|
void Test();
|
||||||
|
|
||||||
|
static void HandleDmaIrq(Ili9341Fsmc *obj) { obj->HandleDmaIrq(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline void WriteCmd(uint16_t cmd) { *m_reg = cmd; }
|
||||||
|
inline void WriteCmd(uint16_t cmd, uint16_t param) { *m_reg = cmd; *m_ram = param; }
|
||||||
|
void WriteCmd(uint16_t cmd, std::initializer_list<const uint16_t> params);
|
||||||
|
void WriteCmd_(uint16_t cmd, uint16_t cnt, ...);
|
||||||
|
void SetRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height);
|
||||||
|
void WritePixels(void *src, uint32_t count, bool increment, bool async = true);
|
||||||
|
void ReadGRam(PixelPair *dst, uint32_t count, bool async = true);
|
||||||
|
void ReadPixels(uint16_t *dst, uint32_t count);
|
||||||
|
void SetScrollOffset();
|
||||||
|
|
||||||
|
volatile uint16_t * const m_reg;
|
||||||
|
volatile uint16_t * const m_ram;
|
||||||
|
|
||||||
|
void HandleDmaIrq();
|
||||||
|
void SetupDmaSize(uint32_t size);
|
||||||
|
uint16_t AdjustY(uint16_t y) { return (m_scrollOffset + y) % m_height; }
|
||||||
|
|
||||||
|
volatile bool m_dmaEngineBusy = false;
|
||||||
|
uint32_t m_dmaRemainingPixels = 0;
|
||||||
|
uint16_t m_dmaColor = 0;
|
||||||
|
|
||||||
|
|
||||||
|
// initialized in the constructor
|
||||||
|
uint16_t const m_width;
|
||||||
|
uint16_t const m_height;
|
||||||
|
uint16_t m_rectX;
|
||||||
|
uint16_t m_rectY;
|
||||||
|
uint16_t m_rectWidth;
|
||||||
|
uint16_t m_rectHeight;
|
||||||
|
|
||||||
|
bool m_scrollMode = false;
|
||||||
|
uint16_t m_scrollOffset = 0;
|
||||||
|
|
||||||
|
uint16_t m_xPos = 0;
|
||||||
|
uint16_t m_yPos = 0;
|
||||||
|
uint16_t m_fgColor = ILI9341_WHITE;
|
||||||
|
uint16_t m_bgColor = ILI9341_BLACK;
|
||||||
|
|
||||||
|
enum Commands {
|
||||||
|
ILI9341_NOP = 0x00,
|
||||||
|
ILI9341_RESET = 0x01,
|
||||||
|
ILI9341_READ_DISPLAY_IDENTIFICATION_INFORMATION = 0x04,
|
||||||
|
ILI9341_READ_DISPLAY_STATUS = 0x09,
|
||||||
|
ILI9341_READ_DISPLAY_POWER_MODE = 0x0A,
|
||||||
|
ILI9341_READ_DISPLAY_MADCTL = 0x0B,
|
||||||
|
ILI9341_READ_DISPLAY_PIXEL_FORMAT = 0x0C,
|
||||||
|
ILI9341_READ_DISPLAY_IMAGE_FORMAT = 0x0D,
|
||||||
|
ILI9341_READ_DISPLAY_SIGNAL_MODE = 0x0E,
|
||||||
|
ILI9341_READ_DISPLAY_SELF_DIAGNOSTIC_RESULT = 0x0F,
|
||||||
|
ILI9341_ENTER_SLEEP_MODE = 0x10,
|
||||||
|
ILI9341_SLEEP_OUT = 0x11,
|
||||||
|
ILI9341_PARTIAL_MODE_ON = 0x12,
|
||||||
|
ILI9341_NORMAL_DISPLAY_MODE_ON = 0x13,
|
||||||
|
ILI9341_DISPLAY_INVERSION_OFF = 0x20,
|
||||||
|
ILI9341_DISPLAY_INVERSION_ON = 0x21,
|
||||||
|
ILI9341_GAMMA = 0x26,
|
||||||
|
ILI9341_DISPLAY_OFF = 0x28,
|
||||||
|
ILI9341_DISPLAY_ON = 0x29,
|
||||||
|
ILI9341_COLUMN_ADDR = 0x2A,
|
||||||
|
ILI9341_PAGE_ADDR = 0x2B,
|
||||||
|
ILI9341_GRAM = 0x2C,
|
||||||
|
ILI9341_COLOR_SET = 0x2D,
|
||||||
|
ILI9341_MEMORY_READ = 0x2E,
|
||||||
|
ILI9341_PARTIAL_AREA = 0x30,
|
||||||
|
ILI9341_VERTICAL_SCROLLING_DEFINITION = 0x33,
|
||||||
|
ILI9341_TEARING_EFFECT_LINE_OFF = 0x34,
|
||||||
|
ILI9341_TEARING_EFFECT_LINE_ON = 0x35,
|
||||||
|
ILI9341_MAC = 0x36,
|
||||||
|
ILI9341_VERTICAL_SCROLLING_START_ADDRESS = 0x37,
|
||||||
|
ILI9341_IDLE_MODE_OFF = 0x38,
|
||||||
|
ILI9341_IDLE_MODE_ON = 0x39,
|
||||||
|
ILI9341_PIXEL_FORMAT = 0x3A,
|
||||||
|
ILI9341_WMC = 0x3C,
|
||||||
|
ILI9341_RMC = 0x3E,
|
||||||
|
ILI9341_SET_TEAR_SCANLINE = 0x44,
|
||||||
|
ILI9341_WDB = 0x51,
|
||||||
|
ILI9341_READ_DISPLAY_BRIGHTNESS = 0x52,
|
||||||
|
ILI9341_WCD = 0x53,
|
||||||
|
ILI9341_READ_CTRL_DISPLAY = 0x54,
|
||||||
|
ILI9341_WCABC = 0x55,
|
||||||
|
ILI9341_RCABC = 0x56,
|
||||||
|
ILI9341_WCABCMB = 0x5E,
|
||||||
|
ILI9341_RCABCMB = 0x5F,
|
||||||
|
ILI9341_RGB_INTERFACE = 0xB0,
|
||||||
|
ILI9341_FRC = 0xB1,
|
||||||
|
ILI9341_FRAME_CTRL_NM = 0xB2,
|
||||||
|
ILI9341_FRAME_CTRL_IM = 0xB3,
|
||||||
|
ILI9341_FRAME_CTRL_PM = 0xB4,
|
||||||
|
ILI9341_BPC = 0xB5,
|
||||||
|
ILI9341_DFC = 0xB6,
|
||||||
|
ILI9341_ENTRY_MODE_SET = 0xB7,
|
||||||
|
ILI9341_BACKLIGHT_CONTROL_1 = 0xB8,
|
||||||
|
ILI9341_BACKLIGHT_CONTROL_2 = 0xB9,
|
||||||
|
ILI9341_BACKLIGHT_CONTROL_3 = 0xBA,
|
||||||
|
ILI9341_BACKLIGHT_CONTROL_4 = 0xBB,
|
||||||
|
ILI9341_BACKLIGHT_CONTROL_5 = 0xBC,
|
||||||
|
ILI9341_BACKLIGHT_CONTROL_6 = 0xBD,
|
||||||
|
ILI9341_BACKLIGHT_CONTROL_7 = 0xBE,
|
||||||
|
ILI9341_BACKLIGHT_CONTROL_8 = 0xBF,
|
||||||
|
ILI9341_POWER1 = 0xC0,
|
||||||
|
ILI9341_POWER2 = 0xC1,
|
||||||
|
ILI9341_VCOM1 = 0xC5,
|
||||||
|
ILI9341_VCOM2 = 0xC7,
|
||||||
|
ILI9341_POWERA = 0xCB,
|
||||||
|
ILI9341_POWERB = 0xCF,
|
||||||
|
ILI9341_READ_ID1 = 0xDA,
|
||||||
|
ILI9341_READ_ID2 = 0xDB,
|
||||||
|
ILI9341_READ_ID3 = 0xDC,
|
||||||
|
ILI9341_READ_ID4 = 0xD3,
|
||||||
|
ILI9341_PGAMMA = 0xE0,
|
||||||
|
ILI9341_NGAMMA = 0xE1,
|
||||||
|
ILI9341_DTCA = 0xE8,
|
||||||
|
ILI9341_DTCB = 0xEA,
|
||||||
|
ILI9341_POWER_SEQ = 0xED,
|
||||||
|
ILI9341_3GAMMA_EN = 0xF2,
|
||||||
|
ILI9341_INTERFACE = 0xF6,
|
||||||
|
ILI9341_PRC = 0xF7,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t CHRHEIGHT = 8; // SHOULD BE 8
|
||||||
|
static const uint8_t CHRWIDTH = 6;
|
||||||
|
static const uint8_t CHRCOUNT = 96;
|
||||||
|
static const uint8_t m_font[CHRCOUNT][CHRWIDTH];
|
||||||
|
|
||||||
|
uint16_t m_fontBkgBuffer[CHRHEIGHT][CHRWIDTH];
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Colors {
|
||||||
|
ILI9341_BLACK = 0x0000, /* 0, 0, 0 */
|
||||||
|
ILI9341_NAVY = 0x000F, /* 0, 0, 128 */
|
||||||
|
ILI9341_DARKGREEN = 0x03E0, /* 0, 128, 0 */
|
||||||
|
ILI9341_DARKCYAN = 0x03EF, /* 0, 128, 128 */
|
||||||
|
ILI9341_MAROON = 0x7800, /* 128, 0, 0 */
|
||||||
|
ILI9341_PURPLE = 0x780F, /* 128, 0, 128 */
|
||||||
|
ILI9341_OLIVE = 0x7BE0, /* 128, 128, 0 */
|
||||||
|
ILI9341_LIGHTGREY = 0xC618, /* 192, 192, 192 */
|
||||||
|
ILI9341_DARKGREY = 0x7BEF, /* 128, 128, 128 */
|
||||||
|
ILI9341_BLUE = 0x001F, /* 0, 0, 255 */
|
||||||
|
ILI9341_GREEN = 0x07E0, /* 0, 255, 0 */
|
||||||
|
ILI9341_CYAN = 0x07FF, /* 0, 255, 255 */
|
||||||
|
ILI9341_RED = 0xF800, /* 255, 0, 0 */
|
||||||
|
ILI9341_MAGENTA = 0xF81F, /* 255, 0, 255 */
|
||||||
|
ILI9341_YELLOW = 0xFFE0, /* 255, 255, 0 */
|
||||||
|
ILI9341_WHITE = 0xFFFF, /* 255, 255, 255 */
|
||||||
|
ILI9341_ORANGE = 0xFD20, /* 255, 165, 0 */
|
||||||
|
ILI9341_GREENYELLOW = 0xAFE5, /* 173, 255, 47 */
|
||||||
|
ILI9341_PINK = 0xF81F,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // f4ll_cpp
|
||||||
|
|
||||||
|
#endif
|
39
components/f4ll_cpp/memcpydma.cpp
Normal file
39
components/f4ll_cpp/memcpydma.cpp
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* memcpy_dma.c
|
||||||
|
*
|
||||||
|
* Created on: Oct 1, 2019
|
||||||
|
* Author: abody
|
||||||
|
*/
|
||||||
|
#include <f4ll_cpp/dmahelper.h>
|
||||||
|
#include <f4ll_cpp/memcpydma.h>
|
||||||
|
|
||||||
|
namespace f4ll_cpp {
|
||||||
|
|
||||||
|
MemcpyDma::MemcpyDma(DMA_TypeDef *dma, uint32_t stream) :
|
||||||
|
DmaHelper(dma, stream),
|
||||||
|
m_busy(false)
|
||||||
|
{
|
||||||
|
LL_DMA_EnableIT_TC(dma, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* MemcpyDma::Copy(void *dst, void const *src, size_t length)
|
||||||
|
{
|
||||||
|
while(m_busy);
|
||||||
|
LL_DMA_SetM2MSrcAddress(GetDma(), GetStream(), (uint32_t)src);
|
||||||
|
LL_DMA_SetM2MDstAddress(GetDma(), GetStream(), (uint32_t)dst);
|
||||||
|
LL_DMA_SetDataLength(GetDma(), GetStream(), (length+3)/4 );
|
||||||
|
m_busy = true;
|
||||||
|
LL_DMA_EnableStream(GetDma(), GetStream());
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemcpyDma::HandleDmaIrq(void)
|
||||||
|
{
|
||||||
|
if(*GetIsReg() & GetTcMask()) { // DMA transfer complete
|
||||||
|
*GetIfcReg() = GetTcMask();
|
||||||
|
LL_DMA_DisableStream(GetDma(), GetStream());
|
||||||
|
m_busy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // f4ll_cpp
|
33
components/f4ll_cpp/memcpydma.h
Normal file
33
components/f4ll_cpp/memcpydma.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* memcpy_dma.h
|
||||||
|
*
|
||||||
|
* Created on: Oct 1, 2019
|
||||||
|
* Author: abody
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MEMCPY_DMA_H_
|
||||||
|
#define MEMCPY_DMA_H_
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <platform/dma_ll.h>
|
||||||
|
#include <f4ll_cpp/dmahelper.h>
|
||||||
|
#include <f4ll_cpp/singleton.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace f4ll_cpp {
|
||||||
|
|
||||||
|
class MemcpyDma : public DmaHelper, public Singleton<MemcpyDma>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MemcpyDma(DMA_TypeDef *dma, uint32_t stream);
|
||||||
|
void* Copy(void *dst, void const *src, size_t length);
|
||||||
|
static inline void HandleDmaIrq(void *param) { reinterpret_cast<MemcpyDma*>(param)->HandleDmaIrq(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void HandleDmaIrq();
|
||||||
|
volatile bool m_busy;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace f4ll_cpp
|
||||||
|
|
||||||
|
#endif /* MEMCPY_DMA_H_ */
|
286
components/f4ll_cpp/packetuart.cpp
Normal file
286
components/f4ll_cpp/packetuart.cpp
Normal file
|
@ -0,0 +1,286 @@
|
||||||
|
/*
|
||||||
|
* usart_handler.c
|
||||||
|
*
|
||||||
|
* Created on: Sep 16, 2019
|
||||||
|
* Author: abody
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <f4ll_cpp/memcpydma.h>
|
||||||
|
#include "f4ll_cpp/crcscheduler.h"
|
||||||
|
#include <f4ll_cpp/packetuart.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <platform/usart_ll.h>
|
||||||
|
#if defined(HAVE_DIAG)
|
||||||
|
#include "diag.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MOCKABLE
|
||||||
|
#define MOCKABLE(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DIAG_RX_BUFFER_SWITCH
|
||||||
|
# define DIAG_RX_BUFFER_SWITCH(x)
|
||||||
|
#endif
|
||||||
|
#ifndef DIAG_INTERRUPT_IN
|
||||||
|
# define DIAG_INTERRUPT_IN()
|
||||||
|
#endif
|
||||||
|
#ifndef DIAG_INTERRUPT_OUT
|
||||||
|
# define DIAG_INTERRUPT_OUT()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define STARTMARKER 0x95
|
||||||
|
|
||||||
|
namespace f4ll_cpp
|
||||||
|
{
|
||||||
|
|
||||||
|
static inline uint32_t RoundUpTo4(uint32_t inp)
|
||||||
|
{
|
||||||
|
return (inp + 3) & 0xfffc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef USART_STATS_DISABLED
|
||||||
|
static inline void StatsIncOverrun(struct usart_stats *s) {
|
||||||
|
++s->overrun;
|
||||||
|
}
|
||||||
|
static inline void StatsIncHdrError(struct usart_stats *s, uint32_t hdr) {
|
||||||
|
++s->hdrError;
|
||||||
|
s->lastErrHdr = hdr;
|
||||||
|
}
|
||||||
|
static inline void StatsIncPayloadError(struct usart_stats *s, uint32_t pep1, uint32_t pep2) {
|
||||||
|
++s->payloadErrror;
|
||||||
|
s->pep1 = pep1;
|
||||||
|
s->pep2 = pep2;
|
||||||
|
}
|
||||||
|
static inline void StatsIncDmaError(struct usart_stats *s) {
|
||||||
|
++s->dmaError;
|
||||||
|
}
|
||||||
|
static inline void StatsIncRcvd(struct usart_stats *s) {
|
||||||
|
++s->rcvd;
|
||||||
|
}
|
||||||
|
static inline void StatsIncPremature_hdr(struct usart_stats *s) {
|
||||||
|
++s->premature_hdr;
|
||||||
|
}
|
||||||
|
static inline void StatsIncPremature_payload(struct usart_stats *s) {
|
||||||
|
++s->premature_payload;
|
||||||
|
}
|
||||||
|
static inline void StatsIncSent(struct usart_stats *s) {
|
||||||
|
++s->sent;
|
||||||
|
}
|
||||||
|
static inline void StatsAddSkiped(struct usart_stats *s, uint8_t cnt) {
|
||||||
|
s->skiped += s->rcvd > 2 ? cnt : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // USART_STATS_DISABLED
|
||||||
|
#define StatsIncOverrun(x)
|
||||||
|
#define StatsIncHdrError(x,y)
|
||||||
|
#define StatsIncPayloadError(x,y,z)
|
||||||
|
#define StatsIncDmaError(x)
|
||||||
|
#define StatsIncRcvd(x)
|
||||||
|
#define StatsIncPremature_hdr(x)
|
||||||
|
#define StatsIncPremature_payload(x)
|
||||||
|
#define StatsIncSent(x)
|
||||||
|
#define StatsAddSkiped(x,y)
|
||||||
|
#endif // USART_STATS_DISABLED
|
||||||
|
|
||||||
|
PacketUart::PacketUart(
|
||||||
|
USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx, CrcScheduler *crcScheduler,
|
||||||
|
PacketUart::pku_packetreceivedcallback_t packetReceivedCallback, void * packetReceivedCallbackParam)
|
||||||
|
: UartBase(uart, dma, stream_rx, stream_tx)
|
||||||
|
, m_crcScheduler(crcScheduler)
|
||||||
|
{
|
||||||
|
uint32_t status = uart->SR;
|
||||||
|
volatile uint32_t tmpreg = uart->DR; // clearing some of the error/status bits in the USART
|
||||||
|
(void) tmpreg;
|
||||||
|
(void) status;
|
||||||
|
|
||||||
|
txBuffer.busy = 0;
|
||||||
|
txBuffer.error = 0;
|
||||||
|
txBuffer.requestedLength = 0;
|
||||||
|
rxBuffers[0].busy = 0;
|
||||||
|
rxBuffers[1].busy = 0;
|
||||||
|
rxBuffers[0].error = 0;
|
||||||
|
rxBuffers[1].error = 0;
|
||||||
|
rxBuffers[0].requestedLength = 0;
|
||||||
|
rxBuffers[1].requestedLength = 0;
|
||||||
|
packetReceivedCallback = packetReceivedCallback;
|
||||||
|
packetReceivedCallbackParam = packetReceivedCallbackParam;
|
||||||
|
rxSerial = -1;
|
||||||
|
txSerial = 0;
|
||||||
|
activeRxBuf = 0;
|
||||||
|
m_crcScheduler->AttachTasks( &crcSlot, crcTasks, 2);
|
||||||
|
#ifndef USART_STATS_DISABLED
|
||||||
|
memset(&st->stats, 0, sizeof(st->stats));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LL_USART_EnableIT_IDLE(uart);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t* PacketUart::GetTxBuffer()
|
||||||
|
{
|
||||||
|
return txBuffer.packet.payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t PacketUart::CheckHeader(Packet *packet)
|
||||||
|
{
|
||||||
|
return packet->header.startByte == STARTMARKER && (packet->header.startByte ^ packet->header.serial ^ packet->header.payloadLength) == packet->header.hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t PacketUart::Post(uint8_t const *payload, uint8_t length, uint8_t waitForCrcQueue)
|
||||||
|
{
|
||||||
|
struct Buffer *buffer = &txBuffer;
|
||||||
|
uint8_t hash = STARTMARKER;
|
||||||
|
buffer->packet.header.startByte = STARTMARKER;
|
||||||
|
buffer->packet.header.serial = txSerial;
|
||||||
|
hash ^= txSerial++;
|
||||||
|
buffer->packet.header.payloadLength = length;
|
||||||
|
hash ^= length;
|
||||||
|
buffer->packet.header.hash = hash;
|
||||||
|
|
||||||
|
uint16_t payloadLength = RoundUpTo4(length);
|
||||||
|
if(payload)
|
||||||
|
memcpy(txBuffer.packet.payload, payload, length);
|
||||||
|
txBuffer.requestedLength = sizeof(struct Header) + payloadLength + sizeof(uint32_t); // +4 for the hash
|
||||||
|
txBuffer.busy = 1;
|
||||||
|
txBuffer.error = 0;
|
||||||
|
m_crcScheduler->Enqueue(&crcSlot, 0, &txBuffer.packet, sizeof(txBuffer.packet.header) + payloadLength,
|
||||||
|
NULL, (uint32_t*)(txBuffer.packet.payload + payloadLength));
|
||||||
|
while(waitForCrcQueue && m_crcScheduler->IsTaskQueued(&crcSlot, 0));
|
||||||
|
SetupTransmit(&txBuffer.packet, txBuffer.requestedLength);
|
||||||
|
|
||||||
|
StatsIncSent(&status->stats);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PacketUart::SetupReceive()
|
||||||
|
{
|
||||||
|
uint8_t packetIndex = activeRxBuf;
|
||||||
|
rxBuffers[packetIndex].requestedLength = sizeof(rxBuffers[packetIndex].packet);
|
||||||
|
UartBase::SetupReceive(&rxBuffers[packetIndex], sizeof(rxBuffers[packetIndex].packet));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PacketUart::ConsumePacket(uint8_t packetIndex)
|
||||||
|
{
|
||||||
|
Buffer *buffer = &rxBuffers[packetIndex];
|
||||||
|
if(buffer->busy) {
|
||||||
|
if(buffer->error)
|
||||||
|
StatsIncPayloadError(&status->stats, Buffer->errorInfo, *(uint32_t*) (Buffer->packet.payload + RoundUpTo4(Buffer->packet.header.payloadLength)));
|
||||||
|
else {
|
||||||
|
uint8_t diff = buffer->packet.header.serial - rxSerial;
|
||||||
|
if(diff > 1)
|
||||||
|
StatsAddSkiped(&status->stats, diff - 1);
|
||||||
|
rxSerial = buffer->packet.header.serial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer->busy = buffer->error = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PacketUart::HandleRxDmaIrq()
|
||||||
|
{
|
||||||
|
DIAG_INTERRUPT_IN();
|
||||||
|
StatsIncRcvd(&status->stats);
|
||||||
|
if(*m_rxDma.GetIsReg() & m_rxDma.GetTcMask()) {
|
||||||
|
*m_rxDma.GetIfcReg() = m_rxDma.GetTcMask();
|
||||||
|
if(CheckHeader(&rxBuffers[activeRxBuf].packet)) {
|
||||||
|
m_crcScheduler->Enqueue(&crcSlot, 1, &rxBuffers[activeRxBuf].packet,
|
||||||
|
RoundUpTo4(rxBuffers[activeRxBuf].packet.header.payloadLength) + sizeof(struct Header),
|
||||||
|
this, &rxBuffers[activeRxBuf]);
|
||||||
|
} else {
|
||||||
|
StatsIncHdrError(&status->stats, *(uint32_t*)&status->rxBuffers[status->activeRxBuf].packet.header);
|
||||||
|
rxBuffers[activeRxBuf].error = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(*m_rxDma.GetIsReg() & m_rxDma.GetTeMask()) {
|
||||||
|
*m_rxDma.GetIfcReg() = m_rxDma.GetTeMask();
|
||||||
|
rxBuffers[activeRxBuf].error = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
activeRxBuf ^= 1;
|
||||||
|
|
||||||
|
DIAG_RX_BUFFER_SWITCH(status->activeRxBuf);
|
||||||
|
if(rxBuffers[activeRxBuf].busy)
|
||||||
|
StatsIncOverrun(&status->stats);
|
||||||
|
SetupReceive();
|
||||||
|
DIAG_INTERRUPT_OUT();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PacketUart::CrcCalculationCompleted(void *callbackParm, uint32_t calculatedCrc, uint8_t success)
|
||||||
|
{
|
||||||
|
struct Buffer *ub = (struct Buffer*) callbackParm;
|
||||||
|
if(!success)
|
||||||
|
ub->error = 1;
|
||||||
|
else if(*(uint32_t*) (ub->packet.payload + RoundUpTo4(ub->packet.header.payloadLength)) == calculatedCrc)
|
||||||
|
ub->busy = 1;
|
||||||
|
else {
|
||||||
|
ub->error = ub->busy = 1;
|
||||||
|
ub->errorInfo = calculatedCrc;
|
||||||
|
}
|
||||||
|
if(packetReceivedCallback)
|
||||||
|
packetReceivedCallback(packetReceivedCallbackParam, ub);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PacketUart::HandleTxDmaIrq()
|
||||||
|
{
|
||||||
|
DIAG_INTERRUPT_IN();
|
||||||
|
if(*m_txDma.GetIsReg() & m_txDma.GetTcMask()) { // DMA transfer complete
|
||||||
|
*m_txDma.GetIfcReg() = m_txDma.GetTcMask();
|
||||||
|
LL_USART_EnableIT_TC(m_uart);
|
||||||
|
LL_DMA_DisableStream(m_txDma.GetDma(), m_txDma.GetStream());
|
||||||
|
}
|
||||||
|
if(*m_txDma.GetIsReg() & m_txDma.GetTeMask()) {
|
||||||
|
*m_txDma.GetIfcReg() = m_txDma.GetTeMask();
|
||||||
|
txBuffer.error = 1;
|
||||||
|
LL_USART_EnableIT_TC(m_uart);
|
||||||
|
LL_DMA_DisableStream(m_txDma.GetDma(), m_txDma.GetStream());
|
||||||
|
StatsIncDmaError(&status->stats);
|
||||||
|
}
|
||||||
|
if(*m_txDma.GetIsReg() & m_txDma.GetFeMask())
|
||||||
|
*m_txDma.GetIfcReg() = m_txDma.GetFeMask();
|
||||||
|
if(*m_txDma.GetIsReg() & m_txDma.GetHtMask())
|
||||||
|
*m_txDma.GetIfcReg() = m_txDma.GetHtMask();
|
||||||
|
if(*m_txDma.GetIsReg() & m_txDma.GetDmeMask())
|
||||||
|
*m_txDma.GetIfcReg() = m_txDma.GetDmeMask();
|
||||||
|
DIAG_INTERRUPT_OUT();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PacketUart::HandleUsartIrq()
|
||||||
|
{
|
||||||
|
DIAG_INTERRUPT_IN();
|
||||||
|
if(LL_USART_IsActiveFlag_IDLE(m_uart) && LL_USART_IsEnabledIT_IDLE(m_uart)) { // receiver idle
|
||||||
|
LL_USART_ClearFlag_IDLE(m_uart);
|
||||||
|
uint16_t rcvdLen = rxBuffers[activeRxBuf].requestedLength - LL_DMA_GetDataLength(m_rxDma.GetDma(), m_rxDma.GetStream());
|
||||||
|
if(rcvdLen >= sizeof(struct Header)) {
|
||||||
|
if(CheckHeader(&rxBuffers[activeRxBuf].packet)) {
|
||||||
|
if(rcvdLen >= sizeof(struct Header) + RoundUpTo4(rxBuffers[activeRxBuf].packet.header.payloadLength) + sizeof(uint32_t))
|
||||||
|
LL_DMA_DisableStream(m_rxDma.GetDma(), m_rxDma.GetStream());
|
||||||
|
else
|
||||||
|
StatsIncPremature_payload(&stats);
|
||||||
|
} else {
|
||||||
|
rxBuffers[activeRxBuf].error = 1;
|
||||||
|
rxBuffers[activeRxBuf].busy = 1;
|
||||||
|
LL_DMA_DisableStream(m_rxDma.GetDma(), m_rxDma.GetStream());
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
StatsIncPremature_hdr(&status->stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(LL_USART_IsActiveFlag_TC(m_uart) && LL_USART_IsEnabledIT_TC(m_uart)) { // transmission complete
|
||||||
|
LL_USART_DisableIT_TC(m_uart);
|
||||||
|
LL_USART_DisableDirectionTx(m_uart); // enforcing an idle frame
|
||||||
|
LL_USART_EnableDirectionTx(m_uart);
|
||||||
|
txBuffer.busy = 0;
|
||||||
|
}
|
||||||
|
DIAG_INTERRUPT_OUT();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // f4ll_cpp
|
107
components/f4ll_cpp/packetuart.h
Normal file
107
components/f4ll_cpp/packetuart.h
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* usart_handler.h
|
||||||
|
*
|
||||||
|
* Created on: Sep 16, 2019
|
||||||
|
* Author: abody
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef USART_HANDLER_H_
|
||||||
|
#define USART_HANDLER_H_
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <platform/usart_ll.h>
|
||||||
|
#include <f4ll_cpp/uartbase.h>
|
||||||
|
|
||||||
|
#define USART_STATS_DISABLED
|
||||||
|
|
||||||
|
namespace f4ll_cpp {
|
||||||
|
|
||||||
|
class PacketUart : public UartBase, public CrcScheduler::ICrcCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Buffer;
|
||||||
|
|
||||||
|
struct IPacketUsartCallback {
|
||||||
|
virtual void PacketReceived(void *userParam, Buffer *buffer) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Stats {
|
||||||
|
uint32_t overrun;
|
||||||
|
uint32_t hdrError;
|
||||||
|
uint32_t lastErrHdr;
|
||||||
|
uint32_t payloadErrror;
|
||||||
|
uint32_t pep1, pep2;
|
||||||
|
uint32_t dmaError;
|
||||||
|
uint32_t rcvd;
|
||||||
|
uint32_t premature_hdr;
|
||||||
|
uint32_t premature_payload;
|
||||||
|
uint32_t sent;
|
||||||
|
uint32_t skiped;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Header {
|
||||||
|
uint8_t startByte;
|
||||||
|
uint8_t serial;
|
||||||
|
uint8_t payloadLength;
|
||||||
|
uint8_t hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Packet {
|
||||||
|
struct Header header;
|
||||||
|
//!!! should start on word offset !!!
|
||||||
|
uint8_t payload[256+sizeof(uint32_t)]; // extra room for crc32
|
||||||
|
} __attribute__((aligned));
|
||||||
|
|
||||||
|
struct Buffer {
|
||||||
|
Packet packet;
|
||||||
|
//transfer area ends here
|
||||||
|
volatile uint8_t busy;
|
||||||
|
volatile uint8_t error;
|
||||||
|
uint16_t requestedLength;
|
||||||
|
uint32_t errorInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef void (*pku_packetreceivedcallback_t)(void *userParam, Buffer *Buffer);
|
||||||
|
|
||||||
|
PacketUart(
|
||||||
|
USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx, CrcScheduler *crcScheduler,
|
||||||
|
PacketUart::pku_packetreceivedcallback_t packetReceivedCallback, void * packetReceivedCallbackParam);
|
||||||
|
|
||||||
|
uint8_t* GetTxBuffer();
|
||||||
|
|
||||||
|
uint8_t Post(uint8_t const *payload, uint8_t length, uint8_t waitForCrcQueue);
|
||||||
|
void SetupReceive();
|
||||||
|
void ConsumePacket(uint8_t packetIndex);
|
||||||
|
|
||||||
|
static void HandleRxDmaIrq(void* param) { reinterpret_cast<PacketUart*>(param)->HandleRxDmaIrq(); }
|
||||||
|
static void HandleTxDmaIrq(void* param) { reinterpret_cast<PacketUart*>(param)->HandleTxDmaIrq(); }
|
||||||
|
static void HandleUsartIrq(void* param) { reinterpret_cast<PacketUart*>(param)->HandleUsartIrq(); }
|
||||||
|
|
||||||
|
uint8_t CheckHeader(struct Packet *packet);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
private:
|
||||||
|
void HandleRxDmaIrq();
|
||||||
|
void HandleTxDmaIrq();
|
||||||
|
void HandleUsartIrq();
|
||||||
|
|
||||||
|
virtual void CrcCalculationCompleted(void*, uint32_t, uint8_t);
|
||||||
|
|
||||||
|
CrcScheduler *m_crcScheduler;
|
||||||
|
CrcScheduler::crcslot_t crcSlot;
|
||||||
|
CrcScheduler::crctask_t crcTasks[2];
|
||||||
|
|
||||||
|
uint8_t rxSerial;
|
||||||
|
uint8_t txSerial;
|
||||||
|
Stats stats;
|
||||||
|
uint8_t activeRxBuf;
|
||||||
|
pku_packetreceivedcallback_t packetReceivedCallback;
|
||||||
|
void *packetReceivedCallbackParam;
|
||||||
|
Buffer txBuffer;
|
||||||
|
Buffer rxBuffers[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
} // f4ll_cpp
|
||||||
|
|
||||||
|
#endif /* UART_HANDLER_H_ */
|
173
components/f4ll_cpp/serialconsole.h
Normal file
173
components/f4ll_cpp/serialconsole.h
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
/*
|
||||||
|
* interrupt.h
|
||||||
|
*
|
||||||
|
* Created on: Aug 29, 2019
|
||||||
|
* Author: abody
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CONSOLEHANDLER_H_
|
||||||
|
#define CONSOLEHANDLER_H_
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include "usart.h"
|
||||||
|
#include <f4ll_cpp/dmahelper.h>
|
||||||
|
#include <f4ll_cpp/uartbase.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace f4ll_cpp {
|
||||||
|
|
||||||
|
template<unsigned int bufSize> class SerialConsole : protected UartBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Buffer {
|
||||||
|
volatile bool busy = false;
|
||||||
|
volatile bool error = false;
|
||||||
|
uint8_t len;
|
||||||
|
char buffer[bufSize];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ISerialConsoleCallback {
|
||||||
|
virtual void LineReceived(void *userParam, Buffer *buffer) = 0;
|
||||||
|
virtual void TransmissionComplete(void *userParam, Buffer *buffer) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
SerialConsole(USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx,
|
||||||
|
ISerialConsoleCallback *callback, void *callbackUserParam);
|
||||||
|
|
||||||
|
void Send(char const *buffer, uint8_t length = 0);
|
||||||
|
void SendLine(char const *buffer, uint8_t length = 0);
|
||||||
|
|
||||||
|
void HandleRxDmaIrq();
|
||||||
|
void HandleTxDmaIrq();
|
||||||
|
void HandleUsartIrq();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SetupTransmit(void *buffer, uint16_t length);
|
||||||
|
|
||||||
|
bool m_activeRxBuffer = false;
|
||||||
|
Buffer m_rxBuffers[2];
|
||||||
|
Buffer m_txBuffer;
|
||||||
|
|
||||||
|
ISerialConsoleCallback *m_callback;
|
||||||
|
void *m_callbackUserParam;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<unsigned int bufSize> SerialConsole<bufSize>::SerialConsole(
|
||||||
|
USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx,
|
||||||
|
ISerialConsoleCallback *callback, void *callbackUserParam
|
||||||
|
)
|
||||||
|
: UartBase(uart, dma, stream_rx, stream_tx)
|
||||||
|
, m_callback(callback), m_callbackUserParam(callbackUserParam)
|
||||||
|
{
|
||||||
|
LL_USART_EnableIT_IDLE(uart);
|
||||||
|
SetupReceive(m_rxBuffers[m_activeRxBuffer].buffer, bufSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<unsigned int bufSize> void SerialConsole<bufSize>::SetupTransmit(void *buffer, uint16_t length)
|
||||||
|
{
|
||||||
|
m_txBuffer.busy = true;
|
||||||
|
UartBase::SetupTransmit(buffer, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<unsigned int bufSize> void SerialConsole<bufSize>::HandleRxDmaIrq()
|
||||||
|
{
|
||||||
|
if(*m_rxDma.GetIsReg() & m_rxDma.GetTcMask()) {
|
||||||
|
*m_rxDma.GetIfcReg() = m_rxDma.GetTcMask();
|
||||||
|
m_rxBuffers[m_activeRxBuffer].busy = true;
|
||||||
|
if(m_callback)
|
||||||
|
m_callback->LineReceived(m_callbackUserParam, &m_rxBuffers[m_activeRxBuffer]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(*m_rxDma.GetIsReg() & m_rxDma.GetTeMask()) {
|
||||||
|
*m_rxDma.GetIfcReg() = m_rxDma.GetTeMask();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_activeRxBuffer = !m_activeRxBuffer;
|
||||||
|
|
||||||
|
SetupReceive(m_rxBuffers[m_activeRxBuffer].buffer, bufSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<unsigned int bufSize> void SerialConsole<bufSize>::HandleTxDmaIrq()
|
||||||
|
{
|
||||||
|
if(*m_txDma.GetIsReg() & m_txDma.GetTcMask()) { // DMA transfer complete
|
||||||
|
*m_txDma.GetIfcReg() = m_txDma.GetTcMask();
|
||||||
|
LL_USART_EnableIT_TC(m_uart);
|
||||||
|
LL_DMA_DisableStream(m_txDma.GetDma(), m_txDma.GetStream());
|
||||||
|
}
|
||||||
|
if(*m_txDma.GetIsReg() & m_txDma.GetTeMask()) {
|
||||||
|
*m_txDma.GetIfcReg() = m_txDma.GetTeMask();
|
||||||
|
m_txBuffer.error = true;
|
||||||
|
LL_USART_EnableIT_TC(m_uart);
|
||||||
|
LL_DMA_DisableStream(m_txDma.GetDma(), m_txDma.GetStream());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<unsigned int bufSize> void SerialConsole<bufSize>::HandleUsartIrq()
|
||||||
|
{
|
||||||
|
if(LL_USART_IsActiveFlag_IDLE(m_uart) && LL_USART_IsEnabledIT_IDLE(m_uart)) { // receiver idle
|
||||||
|
// we assume that new line marker will arrive without an idle cycle even if it is CRLF
|
||||||
|
LL_USART_ClearFlag_IDLE(m_uart);
|
||||||
|
uint16_t rcvdLen = bufSize - LL_DMA_GetDataLength(m_rxDma.GetDma(), m_rxDma.GetStream());
|
||||||
|
if(rcvdLen ) {
|
||||||
|
bool newLine = false;;
|
||||||
|
do {
|
||||||
|
auto lastChar = m_rxBuffers[m_activeRxBuffer].buffer[rcvdLen-1];
|
||||||
|
if( lastChar == '\r' || lastChar == '\n')
|
||||||
|
newLine = true;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
} while(--rcvdLen);
|
||||||
|
|
||||||
|
if(newLine) {
|
||||||
|
m_rxBuffers[m_activeRxBuffer].buffer[rcvdLen] = 0;
|
||||||
|
m_rxBuffers[m_activeRxBuffer].len = rcvdLen;
|
||||||
|
LL_DMA_DisableStream(m_rxDma.GetDma(), m_rxDma.GetStream());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(LL_USART_IsActiveFlag_TC(m_uart) && LL_USART_IsEnabledIT_TC(m_uart)) { // transmission complete
|
||||||
|
LL_USART_DisableIT_TC(m_uart);
|
||||||
|
LL_USART_DisableDirectionTx(m_uart); // enforcing an idle frame
|
||||||
|
LL_USART_EnableDirectionTx(m_uart);
|
||||||
|
m_txBuffer.busy = false;
|
||||||
|
if(m_callback)
|
||||||
|
m_callback->TransmissionComplete(m_callbackUserParam, &m_txBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<unsigned int bufSize> void SerialConsole<bufSize>::Send(char const *buffer, uint8_t length)
|
||||||
|
{
|
||||||
|
if(!length) {
|
||||||
|
auto computedLength = strlen(buffer);
|
||||||
|
if(computedLength <= (uint8_t)-1)
|
||||||
|
length = computedLength;
|
||||||
|
}
|
||||||
|
if(length) {
|
||||||
|
while( m_txBuffer.busy );
|
||||||
|
memcpy(m_txBuffer.buffer, buffer, length);
|
||||||
|
SetupTransmit(m_txBuffer.buffer, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<unsigned int bufSize> void SerialConsole<bufSize>::SendLine(char const *buffer, uint8_t length)
|
||||||
|
{
|
||||||
|
if(!length) {
|
||||||
|
auto computedLength = strlen(buffer);
|
||||||
|
if(computedLength <= (uint8_t)-1)
|
||||||
|
length = computedLength;
|
||||||
|
}
|
||||||
|
if(length) {
|
||||||
|
while( m_txBuffer.busy );
|
||||||
|
memcpy(m_txBuffer.buffer, buffer, length);
|
||||||
|
if(m_txBuffer.buffer[length-1] != '\n') {
|
||||||
|
m_txBuffer.buffer[length++] = '\r';
|
||||||
|
m_txBuffer.buffer[length++] = '\n';
|
||||||
|
}
|
||||||
|
SetupTransmit(m_txBuffer.buffer, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // f4ll_cpp
|
||||||
|
|
||||||
|
#endif /* CONSOLEHANDLER_H_ */
|
34
components/f4ll_cpp/singleton.h
Normal file
34
components/f4ll_cpp/singleton.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* singleton.h
|
||||||
|
*
|
||||||
|
* Created on: Sep 11, 2019
|
||||||
|
* Author: compi
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SINGLETON_H_
|
||||||
|
#define SINGLETON_H_
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace f4ll_cpp {
|
||||||
|
|
||||||
|
template<typename T> class Singleton {
|
||||||
|
public:
|
||||||
|
static T &Instance() {
|
||||||
|
static T instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Singleton() = default;
|
||||||
|
Singleton(const Singleton &) = delete;
|
||||||
|
Singleton &operator=(const Singleton &) = delete;
|
||||||
|
virtual ~Singleton() = default;
|
||||||
|
static T *m_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T> T* Singleton<T>::m_instance = nullptr;
|
||||||
|
|
||||||
|
} // f4ll_cpp
|
||||||
|
|
||||||
|
#endif /* SINGLETON_H_ */
|
39
components/f4ll_cpp/strangeton.h
Normal file
39
components/f4ll_cpp/strangeton.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* singleton.h
|
||||||
|
*
|
||||||
|
* Created on: Sep 11, 2019
|
||||||
|
* Author: compi
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SINGLETON_H_
|
||||||
|
#define SINGLETON_H_
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace f4ll_cpp {
|
||||||
|
|
||||||
|
template<typename T> class Strangeton {
|
||||||
|
public:
|
||||||
|
static T &Instance() {
|
||||||
|
return *m_instance;
|
||||||
|
}
|
||||||
|
template<typename ... Args> static T &Init(Args &&... args) {
|
||||||
|
static T instance{ std::forward<Args>(args)... };
|
||||||
|
if(!m_instance)
|
||||||
|
m_instance = &instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Strangeton() = default;
|
||||||
|
Strangeton(const Strangeton &) = delete;
|
||||||
|
Strangeton &operator=(const Strangeton &) = delete;
|
||||||
|
virtual ~Strangeton() = default;
|
||||||
|
static T *m_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T> T* Strangeton<T>::m_instance = nullptr;
|
||||||
|
|
||||||
|
} // f4ll_cpp
|
||||||
|
|
||||||
|
#endif /* SINGLETON_H_ */
|
49
components/f4ll_cpp/uartbase.cpp
Normal file
49
components/f4ll_cpp/uartbase.cpp
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* UartBase.cpp
|
||||||
|
*
|
||||||
|
* Created on: Feb 4, 2020
|
||||||
|
* Author: abody
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <f4ll_cpp/uartbase.h>
|
||||||
|
|
||||||
|
namespace f4ll_cpp {
|
||||||
|
|
||||||
|
UartBase::UartBase(USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx)
|
||||||
|
: m_uart(uart)
|
||||||
|
, m_rxDma(dma, stream_rx)
|
||||||
|
, m_txDma(dma, stream_tx)
|
||||||
|
{
|
||||||
|
*m_rxDma.GetIfcReg() =
|
||||||
|
m_rxDma.GetTcMask() | m_rxDma.GetHtMask() |
|
||||||
|
m_rxDma.GetTeMask() | m_rxDma.GetFeMask() | m_rxDma.GetDmeMask();
|
||||||
|
*m_txDma.GetIfcReg() =
|
||||||
|
m_txDma.GetTcMask() | m_txDma.GetHtMask() |
|
||||||
|
m_txDma.GetTeMask() | m_txDma.GetFeMask() | m_txDma.GetDmeMask();
|
||||||
|
|
||||||
|
LL_DMA_EnableIT_TC(dma, stream_rx);
|
||||||
|
LL_DMA_EnableIT_TE(dma, stream_rx);
|
||||||
|
LL_DMA_EnableIT_TC(dma, stream_tx);
|
||||||
|
LL_DMA_EnableIT_TE(dma, stream_tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UartBase::SetupReceive(void *buffer, uint16_t length)
|
||||||
|
{
|
||||||
|
LL_DMA_ConfigAddresses(m_rxDma.GetDma(), m_rxDma.GetStream(), LL_USART_DMA_GetRegAddr(m_uart),
|
||||||
|
(uint32_t)buffer, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
|
||||||
|
LL_DMA_SetDataLength(m_rxDma.GetDma(), m_rxDma.GetStream(), length); // payload already have extra room for hash
|
||||||
|
LL_USART_EnableDMAReq_RX(m_uart);
|
||||||
|
LL_USART_ClearFlag_ORE(m_uart);
|
||||||
|
LL_DMA_EnableStream(m_rxDma.GetDma(), m_rxDma.GetStream());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void UartBase::SetupTransmit(void *buffer, uint16_t length)
|
||||||
|
{
|
||||||
|
LL_DMA_ConfigAddresses(m_txDma.GetDma(), m_txDma.GetStream(), (uint32_t)buffer, LL_USART_DMA_GetRegAddr(m_uart), LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
|
||||||
|
LL_DMA_SetDataLength(m_txDma.GetDma(), m_txDma.GetStream(), length);
|
||||||
|
LL_USART_EnableDMAReq_TX(m_uart);
|
||||||
|
LL_DMA_EnableStream(m_txDma.GetDma(), m_txDma.GetStream());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // f4ll_cpp
|
31
components/f4ll_cpp/uartbase.h
Normal file
31
components/f4ll_cpp/uartbase.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* UartBase.h
|
||||||
|
*
|
||||||
|
* Created on: Feb 4, 2020
|
||||||
|
* Author: abody
|
||||||
|
*/
|
||||||
|
#ifndef F4LL_CPP_UARTBASE_H_
|
||||||
|
#define F4LL_CPP_UARTBASE_H_
|
||||||
|
|
||||||
|
#include <platform/usart_ll.h>
|
||||||
|
#include <f4ll_cpp/dmahelper.h>
|
||||||
|
|
||||||
|
namespace f4ll_cpp {
|
||||||
|
|
||||||
|
class UartBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UartBase() = delete;
|
||||||
|
protected:
|
||||||
|
UartBase(USART_TypeDef *uart, DMA_TypeDef *dma, uint32_t stream_rx, uint32_t stream_tx);
|
||||||
|
void SetupTransmit(void *buffer, uint16_t length);
|
||||||
|
void SetupReceive(void *buffer, uint16_t length);
|
||||||
|
|
||||||
|
USART_TypeDef *m_uart;
|
||||||
|
DmaHelper m_rxDma;
|
||||||
|
DmaHelper m_txDma;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // f4ll_cpp
|
||||||
|
|
||||||
|
#endif /* F4LL_CPP_UARTBASE_H_ */
|
36
components/fsl/task.h
Normal file
36
components/fsl/task.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* task.h
|
||||||
|
*
|
||||||
|
* Created on: Oct 29, 2021
|
||||||
|
* Author: compi
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FSL_TASK_H_
|
||||||
|
#define FSL_TASK_H_
|
||||||
|
|
||||||
|
#include <FreeRTOS.h>
|
||||||
|
#include <task.h> // FreeRTOS
|
||||||
|
#include <semphr.h> // FreeRTOS
|
||||||
|
|
||||||
|
namespace fsl {
|
||||||
|
|
||||||
|
template<typename T, uint32_t stackSize> class Task {
|
||||||
|
public:
|
||||||
|
Task(UBaseType_t priority) : m_priority(priority) {}
|
||||||
|
void Start(SemaphoreHandle_t doneSem = nullptr, bool waitForInit = false) {
|
||||||
|
m_handle = xTaskCreateStatic(T::TaskFn, getName(), sizeof(m_stack)/sizeof(m_stack[0]),
|
||||||
|
this, m_priority, m_stack, &m_tcb);
|
||||||
|
}
|
||||||
|
virtual ~Task() {};
|
||||||
|
virtual char const * getName() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
TaskHandle_t m_handle;
|
||||||
|
UBaseType_t m_priority;
|
||||||
|
StaticTask_t m_tcb;
|
||||||
|
StackType_t m_stack[stackSize];
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace fsl */
|
||||||
|
|
||||||
|
#endif /* FSL_TASK_H_ */
|
12
platforms/firmware/.gitrepo
Normal file
12
platforms/firmware/.gitrepo
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
; DO NOT EDIT (unless you know what you are doing)
|
||||||
|
;
|
||||||
|
; This subdirectory is a git "subrepo", and this file is maintained by the
|
||||||
|
; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
|
||||||
|
;
|
||||||
|
[subrepo]
|
||||||
|
remote = git@10.183.3.92:mississippi/mississippi-mcu-platform-f40x_mx.git
|
||||||
|
branch = master
|
||||||
|
commit = 8bb5394e3d7194db11059efde6e41c6456ae5e6c
|
||||||
|
method = merge
|
||||||
|
cmdver = 0.4.0
|
||||||
|
parent = 0a503c37d418e11e363d1aa66977b91757f7d31c
|
10
platforms/firmware/component.mk
Normal file
10
platforms/firmware/component.mk
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
SELF_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))
|
||||||
|
REL_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
|
||||||
|
ifeq ($(MKDBG), 1)
|
||||||
|
$(info >>> $(REL_DIR)/component.mk)
|
||||||
|
endif
|
||||||
|
#$(eval C_SOURCES += $(wildcard $(REL_DIR)/*.c))
|
||||||
|
$(eval COMMON_INCLUDES += -I$(REL_DIR))
|
||||||
|
ifeq ($(MKDBG), 1)
|
||||||
|
$(info <<<)
|
||||||
|
endif
|
14
platforms/firmware/platform/core_ll.h
Normal file
14
platforms/firmware/platform/core_ll.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* core_ll.h
|
||||||
|
*
|
||||||
|
* Created on: Feb 12, 2020
|
||||||
|
* Author: abody
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FIRMWARE_PLATFORM_CORE_LL_H_
|
||||||
|
#define FIRMWARE_PLATFORM_CORE_LL_H_
|
||||||
|
|
||||||
|
#include <stm32f4xx_ll_cortex.h>
|
||||||
|
#include <stm32f4xx_ll_utils.h>
|
||||||
|
|
||||||
|
#endif /* FIRMWARE_PLATFORM_CORE_LL_H_ */
|
6
platforms/firmware/platform/crc_ll.h
Normal file
6
platforms/firmware/platform/crc_ll.h
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef __PLATFORM_CRC_LL_H_INCLUDED
|
||||||
|
#define __PLATFORM_CRC_LL_H_INCLUDED
|
||||||
|
|
||||||
|
#include "crc.h"
|
||||||
|
|
||||||
|
#endif // __PLATFORM_CRC_LL_H_INCLUDED
|
6
platforms/firmware/platform/dma_ll.h
Normal file
6
platforms/firmware/platform/dma_ll.h
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef __PLATFORM_DMA_LL_H_INCLUDED
|
||||||
|
#define __PLATFORM_DMA_LL_H_INCLUDED
|
||||||
|
|
||||||
|
#include "stm32f4xx_ll_dma.h"
|
||||||
|
|
||||||
|
#endif // __PLATFORM_DMA_LL_H_INCLUDED
|
97
platforms/firmware/platform/mockme.h
Normal file
97
platforms/firmware/platform/mockme.h
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* mockme.h
|
||||||
|
*
|
||||||
|
* Created on: Nov 25, 2019
|
||||||
|
* Author: abody
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PLATFORM_MOCKME_H_
|
||||||
|
#define PLATFORM_MOCKME_H_
|
||||||
|
|
||||||
|
//#define TOSTR(x) #x
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define DECLARE_MOCK(F) \
|
||||||
|
extern decltype(F) F ## __, *test_ ## F
|
||||||
|
#else
|
||||||
|
#define DECLARE_MOCK(F) \
|
||||||
|
extern typeof(F) F ## __, *test_ ## F
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MOCKABLE(F) __attribute__((section(\
|
||||||
|
".bss\n\t"\
|
||||||
|
".globl test_" #F "\n\t"\
|
||||||
|
".align 4\n\t"\
|
||||||
|
".type test_" #F ", @object\n\t"\
|
||||||
|
".size test_" #F ", 4\n"\
|
||||||
|
"test_" #F ":\n\t"\
|
||||||
|
".zero 4\n\t"\
|
||||||
|
".text\n\t"\
|
||||||
|
".p2align 4,,15\n\t"\
|
||||||
|
".globl " #F "\n\t"\
|
||||||
|
".type " #F ", @function\n"\
|
||||||
|
#F ":\n\t"\
|
||||||
|
".cfi_startproc\n\t"\
|
||||||
|
"push %edx\n\t"\
|
||||||
|
"push %edx\n\t"\
|
||||||
|
"push %eax\n\t"\
|
||||||
|
"movl test_" #F ", %eax\n\t"\
|
||||||
|
"leal " #F "__, %edx\n\t"\
|
||||||
|
"test %eax, %eax\n\t"\
|
||||||
|
"cmove %edx, %eax\n\t"\
|
||||||
|
"mov %eax, 8(%esp)\n\t"\
|
||||||
|
"pop %eax\n\t"\
|
||||||
|
"pop %edx\n\t"\
|
||||||
|
"ret\n\t"\
|
||||||
|
".cfi_endproc\n\t"\
|
||||||
|
".size " #F ", .-" #F "\n\t"\
|
||||||
|
".section .text"))) F ## __
|
||||||
|
|
||||||
|
#define DEFINE_MOCK_RET(rettype, fn, decor, ...) \
|
||||||
|
static int fn ## _ ## decor ## _callcount; \
|
||||||
|
static rettype fn ## _ ## decor ## _retval; \
|
||||||
|
static rettype fn ## _ ## decor(__VA_ARGS__) { \
|
||||||
|
++fn ## _ ## decor ## _callcount;
|
||||||
|
|
||||||
|
#define DEFINE_MOCK(fn, decor, ...) \
|
||||||
|
static int fn ## _ ## decor ## _callcount; \
|
||||||
|
static void fn ## _ ## decor(__VA_ARGS__) { \
|
||||||
|
++fn ## _ ## decor ## _callcount;
|
||||||
|
|
||||||
|
#define RETURN_MOCK(fn, decor, ret) \
|
||||||
|
fn##_##decor##_retval = ret; \
|
||||||
|
return ret; }
|
||||||
|
|
||||||
|
#define RETURN_MOCK_PREDEF(fn, decor) \
|
||||||
|
return fn##_##decor##_retval; }
|
||||||
|
|
||||||
|
#define LEAVE_MOCK }
|
||||||
|
|
||||||
|
#define DEFINE_MOCK_VAR(type, fn, decor, varname) type fn##_##decor##_##varname
|
||||||
|
|
||||||
|
#define MOCK_STORE(fn, decor, varname, value) fn##_##decor##_##varname = value
|
||||||
|
|
||||||
|
#define MOCK_VAR(fn, decor, varname) fn##_##decor##_##varname
|
||||||
|
#define MOCK_CALLCOUNT(fn, decor) fn ## _ ## decor ## _callcount
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
namespace mockme {
|
||||||
|
template <typename T> class mockguard {
|
||||||
|
T* m_guarded;
|
||||||
|
public:
|
||||||
|
mockguard(T* guarded, T testFunc) : m_guarded(guarded) { *m_guarded = testFunc; }
|
||||||
|
~mockguard() { *m_guarded = nullptr; }
|
||||||
|
};
|
||||||
|
} // namespace mockme
|
||||||
|
|
||||||
|
#define ACTIVATE_MOCK(fn, decor) \
|
||||||
|
fn ## _ ## decor ## _callcount = 0; \
|
||||||
|
mockme::mockguard<decltype(fn)*> fn ## _ ## decor ## _mockguard(&test_ ## fn, fn ## _ ## decor)
|
||||||
|
|
||||||
|
#define ACTIVATE_MOCK_RV(fn, decor, ret) \
|
||||||
|
fn##_##decor##_callcount = 0; \
|
||||||
|
fn##_##decor##_retval = ret; \
|
||||||
|
mockme::mockguard<decltype(fn)*> fn##_##decor##_mockguard(&test_ ## fn, fn##_##decor)
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif /* PLATFORM_MOCKME_H_ */
|
6
platforms/firmware/platform/usart_ll.h
Normal file
6
platforms/firmware/platform/usart_ll.h
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef __PLATFORM_USART_LL_H_INCLUDED
|
||||||
|
#define __PLATFORM_USART_LL_H_INCLUDED
|
||||||
|
|
||||||
|
#include "usart.h"
|
||||||
|
|
||||||
|
#endif // __PLATFORM_USART_LL_H_INCLUDED
|
3
platforms/test/.gitignore
vendored
Normal file
3
platforms/test/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
gtest_i386/
|
||||||
|
googletest/**/generated/
|
||||||
|
|
12
platforms/test/.gitrepo
Normal file
12
platforms/test/.gitrepo
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
; DO NOT EDIT (unless you know what you are doing)
|
||||||
|
;
|
||||||
|
; This subdirectory is a git "subrepo", and this file is maintained by the
|
||||||
|
; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
|
||||||
|
;
|
||||||
|
[subrepo]
|
||||||
|
remote = git@10.183.3.92:mississippi/mississippi-mcu-platform-x86_gtest.git
|
||||||
|
branch = master
|
||||||
|
commit = 71472440d8296fe81d0891a972d6677288c64590
|
||||||
|
parent = 24552e91a4f68cd15d944c09c2a7a8d7d7e2183c
|
||||||
|
method = merge
|
||||||
|
cmdver = 0.4.0
|
259
platforms/test/Readme.md
Normal file
259
platforms/test/Readme.md
Normal file
|
@ -0,0 +1,259 @@
|
||||||
|
<h1>Mocking (low level bare-metal embedded) C code</h1>
|
||||||
|
|
||||||
|
<h2>Preparations</h2>
|
||||||
|
As Google test framework expect your test code to be written in c++, declaring your C functions as extern "C" is mandatory. Use
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
at the beginning of your headers and
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
at the end.
|
||||||
|
|
||||||
|
Keep in mind that STM32 is a 32 bit platform so unfortunately we cannot use amd64 for running our tests as pointer sizes would not match.
|
||||||
|
|
||||||
|
<h2>Creating stubs for external code</h2>
|
||||||
|
|
||||||
|
Unfortunately there is no way to make C functions dynamically mockable without source code modifications. We should use some macro magic to declare/define the functions need to be dynamically mockable.
|
||||||
|
|
||||||
|
<h3>Original code</h3>
|
||||||
|
|
||||||
|
foo.h:
|
||||||
|
|
||||||
|
...
|
||||||
|
uint8_t* Pu_GetTxBuffer(struct usartstatus_t *status);
|
||||||
|
...
|
||||||
|
|
||||||
|
foo.c:
|
||||||
|
|
||||||
|
...
|
||||||
|
uint8_t* Pu_GetTxBuffer(struct usartstatus_t *status)
|
||||||
|
{
|
||||||
|
return status->txBuffer.packet.payload;
|
||||||
|
}
|
||||||
|
...
|
||||||
|
|
||||||
|
<h3>Prepared for dynamic mocking</h3>
|
||||||
|
|
||||||
|
foo.h:
|
||||||
|
|
||||||
|
...
|
||||||
|
uint8_t* Pu_GetTxBuffer(struct usartstatus_t *status);
|
||||||
|
...
|
||||||
|
DECLARE_MOCK(Pu_GetTxBuffer);
|
||||||
|
...
|
||||||
|
|
||||||
|
foo.c:
|
||||||
|
|
||||||
|
...
|
||||||
|
uint8_t* MOCKABLE(Pu_GetTxBuffer)(struct usartstatus_t *status)
|
||||||
|
{
|
||||||
|
return status->txBuffer.packet.payload;
|
||||||
|
}
|
||||||
|
...
|
||||||
|
|
||||||
|
During normal build `DECLARE_MOCK(Pu_GetTxBuffer)` expands to nothing and `MOCKABLE(Pu_GetTxBuffer)` expands to `Pu_GetTxBuffer`, so using them have no effect on the compiled binary.
|
||||||
|
|
||||||
|
When compiling the code for unit tests `DECLARE_MOCK(Pu_GetTxBuffer)` will do two things:
|
||||||
|
* Declares a function with the same signature as `Pu_GetTxBuffer` named `Pu_GetTxBuffer__`
|
||||||
|
* Declares a function pointer named `test_GetTxBuffer`
|
||||||
|
|
||||||
|
`MOCKABLE` macro is the tricikiest part of the whole framework. It injects x86 assembly code into the intermediate assembly source generated from the C source to achieve the following:
|
||||||
|
|
||||||
|
Hijacks `Pu_GetTxBuffer` and injects a code which check s the value of `test_GetTextBuffer` pointer and calls the function it points to if the pointer is not NULL. Defines `Pu_GetTxBuffer__` (using the original implementation) which is called in case `test_GetTextBuffer` contains NULL.
|
||||||
|
|
||||||
|
As result we have an extra pointer for each prepared function to divert the execution when we need it and leave the original implementation in place when not.
|
||||||
|
|
||||||
|
|
||||||
|
<h2>Mocking/stubing platform code</h2>
|
||||||
|
|
||||||
|
Platform (like CMSIS, STM32 HAL or LL) has plenty of declarations and definitions necessary your code might be using. Unfortunately unit tests will need them too to compile. In most of the cases they even should be mockable. As the platform code written for ARM (sometimes even containing ARM assembly inserts) it would be extremely hard to make it compile on x86. there is no other way to make your own code compilable but copying necessary declarations and provide trivial (stub) definition in your own "fake" platform code.
|
||||||
|
|
||||||
|
It is also a good idea to make (at least parts of) your stub implementation mockable using the macros described above (see headers and sources in platforms/test/platform for example)
|
||||||
|
|
||||||
|
<h2>Writing your unit tests</h2>
|
||||||
|
|
||||||
|
There are several macros provided to make writing unit test as convinient as possible.
|
||||||
|
|
||||||
|
<h3>Defining mocks</h3>
|
||||||
|
|
||||||
|
Defining mock functions with no (void) return value:
|
||||||
|
|
||||||
|
DEFINE_MOCK(<function_name>, <decoration>, [<parameter list>]) {
|
||||||
|
<mock_function_implementation>
|
||||||
|
LEAVE_MOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
DEFINE_MOCK(LL_DMA_SetM2MDstAddress, mock, DMA_TypeDef *dma, uint32_t stream, uint32_t address) {
|
||||||
|
<implementation>
|
||||||
|
LEAVE_MOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
The above will generate the following C code:
|
||||||
|
|
||||||
|
static int LL_DMA_SetM2MDstAddress_mock_callcount;
|
||||||
|
static void LL_DMA_SetM2MDstAddress_mock(DMA_TypeDef *dma, uint32_t stream, uint32_t address) {
|
||||||
|
++LL_DMA_SetM2MDstAddress_mock_callcount;
|
||||||
|
{
|
||||||
|
<implementation>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Defining mock functions with return (non-void) value:
|
||||||
|
|
||||||
|
DEFINE_MOCK_RET(<return_type>, <function_name>, <decoration>, [<parameter list>]) {
|
||||||
|
<mock_function_implementation>
|
||||||
|
RETURN_MOCK_PREDEF(<function_name>, <decoration> | RETURN_MOCK(<function_name>, <decoration>, <return value>);
|
||||||
|
}
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
DEFINE_MOCK_RET(uint32_t, LL_USART_IsActiveFlag_IDLE, mock, USART_TypeDef *usart) {
|
||||||
|
<implementation>
|
||||||
|
RETURN_MOCK_PREDEF(LL_USART_IsActiveFlag_IDLE, mock)
|
||||||
|
}
|
||||||
|
|
||||||
|
The above will generate the following C code:
|
||||||
|
|
||||||
|
static int LL_USART_IsActiveFlag_IDLE_mock_callcount;
|
||||||
|
static uint32_t LL_USART_IsActiveFlag_IDLE_mock_retval;
|
||||||
|
static uint32_t LL_USART_IsActiveFlag_IDLE_mock(USART_TypeDef *usart) {
|
||||||
|
++LL_USART_IsActiveFlag_IDLE_mock_callcount;
|
||||||
|
{
|
||||||
|
<implementation>
|
||||||
|
}
|
||||||
|
return LL_USART_IsActiveFlag_IDLE_mock_retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
Return value of the function above can be set by
|
||||||
|
|
||||||
|
MOCK_STORE(LL_USART_IsActiveFlag_IDLE, mock, retval, <value>);
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
MOCK_VAR(LL_USART_IsActiveFlag_IDLE, mock, retval) = <value>;
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
LL_USART_IsActiveFlag_IDLE_mock_retval = <value>;
|
||||||
|
|
||||||
|
during the test setup.
|
||||||
|
|
||||||
|
<h3>Helper variables for mocking</h3>
|
||||||
|
|
||||||
|
It is quite common that you need to store some data in global variables (can be checked later in from the test code or can be used by other mocks). There are few helper macros to make this easier. You can define a mock helper variable using
|
||||||
|
|
||||||
|
DEFINE_MOCK_VAR(<type>, <function_name>, <decoration>, <variable_name>);
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
DEFINE_MOCK_VAR(uint32_t, __set_PRIMASK, mock, lastprimask);
|
||||||
|
|
||||||
|
Which will expand to:
|
||||||
|
|
||||||
|
uint32_t __set_PRIMASK_mock_lastprimask;
|
||||||
|
|
||||||
|
You can access these variables using `MOCK_VAR(<function_name>, <decoration>, <name>)` (e.g. `if(MOCK_VAR(__set_PRIMASK, mock, lastprimask) != 0)` or `MOCK_VAR(__set_PRIMASK, mock, lastprimask) = 1;` ) but for setting the value of a mock helper variable you can also use `MOCK_STORE(<function_name>, <decoration>, <varable_name>, <value>);` (e.g `MOCK_STORE(__set_PRIMASK, mock, lastprimask, 1)` which is equivalent to setting the variable using `MOCK_VAR`.
|
||||||
|
|
||||||
|
As it was descibed above, defining a mock function also defines (and administers) a call count variable for that function. For easier access of those variables we have `MOCK_CALLCOUNT(<function_name>, <decoration>)` (e.g. `if(MOCK_CALLCOUNT(__set_PRIMASK, mock) != 5) ...`)
|
||||||
|
|
||||||
|
<h2>Real-life example</h2>
|
||||||
|
|
||||||
|
Test writing using the infrastructure described above is quite straight-forward and easy. Let's assume we would like to write a unit test for the following function:
|
||||||
|
|
||||||
|
void MOCKABLE(Crc_AttachTasks)(struct crcstatus_t *status, struct crcslot_t *slot,
|
||||||
|
struct crctask_t *tasks, uint8_t taskCount)
|
||||||
|
{
|
||||||
|
slot->count = taskCount;
|
||||||
|
slot->tasks = tasks;
|
||||||
|
memset(tasks, 0, sizeof(*tasks)*taskCount);
|
||||||
|
|
||||||
|
uint32_t prim = __get_PRIMASK();
|
||||||
|
__disable_irq();
|
||||||
|
slot->next = status->firstSlot;
|
||||||
|
status->firstSlot = slot;
|
||||||
|
__set_PRIMASK(prim);
|
||||||
|
}
|
||||||
|
|
||||||
|
This function attaches a new tasks to one of the slots of CRC scheduler. As this ;lis is also processed from interrupt context it needs to disable interrupts for the period of the modification and restore the original interrupt enablement status on the end.
|
||||||
|
|
||||||
|
We can identify three platform specific function calls: `__get_PRIMASK(), __disable_irq()` and `__set_PRIMASK()` so we need stubs for them somewhere in the platform stub code:
|
||||||
|
|
||||||
|
Platform stub header:
|
||||||
|
|
||||||
|
void __disable_irq();
|
||||||
|
uint32_t __get_PRIMASK();
|
||||||
|
void __set_PRIMASK(uint32_t priMask);
|
||||||
|
|
||||||
|
Platform stub source:
|
||||||
|
|
||||||
|
void MOCKABLE(__disable_irq)() {}
|
||||||
|
uint32_t MOCKABLE(__get_PRIMASK)() { return 0; }
|
||||||
|
void MOCKABLE(__set_PRIMASK)(uint32_t primask) {}
|
||||||
|
|
||||||
|
In our test code we need to mock these function (making possible to verify that they're called as modification of the linked list of slots need to be guarded against interrupts)
|
||||||
|
|
||||||
|
uint32_t effective_primask = 0;
|
||||||
|
|
||||||
|
DEFINE_MOCK(__set_PRIMASK, mock, uint32_t primask) {
|
||||||
|
effective_primask = primask;
|
||||||
|
LEAVE_MOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_MOCK_RET(uint32_t, __get_PRIMASK, mock) {
|
||||||
|
RETURN_MOCK(__get_PRIMASK, mock, effective_primask);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_MOCK_VAR(crcslot_t *, __disable_irq, mock, firstslot_required);
|
||||||
|
DEFINE_MOCK(__disable_irq, mock) {
|
||||||
|
if(MOCK_CALLCOUNT(__disable_irq, mock) < 2) {
|
||||||
|
EXPECT_EQ(crcStatus.firstSlot, MOCK_VAR(__disable_irq, mock, firstslot_required));
|
||||||
|
}
|
||||||
|
effective_primask = 1;
|
||||||
|
LEAVE_MOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
With these mock functions we actually mock the behaviour of he ARM Cortex PRIMASK register API. We also add some check to `_disable_irq_mock()` that verifies that the firstSlot member of the crcStatus has not changed before disabling interrupts.
|
||||||
|
|
||||||
|
Now we prepared everything for writing our first unit test for Crc_AttachTasks function:
|
||||||
|
|
||||||
|
TEST(CrcScheduler, AttachTask_single) {
|
||||||
|
DMA1 = &dma1;
|
||||||
|
DMA2 = &dma2;
|
||||||
|
effective_primask = 0;
|
||||||
|
Crc_InitStatus(&crcStatus, &fakeCrc, DMA2, LL_DMA_STREAM_4);
|
||||||
|
ACTIVATE_MOCK_RV(__get_PRIMASK, mock, 0);
|
||||||
|
ACTIVATE_MOCK(__set_PRIMASK, mock);
|
||||||
|
ACTIVATE_MOCK(__disable_irq, mock);
|
||||||
|
MOCK_STORE(__disable_irq, mock, firstslot_required, nullptr);
|
||||||
|
|
||||||
|
Crc_AttachTasks(&crcStatus, &slot1, tasks1, 2);
|
||||||
|
|
||||||
|
EXPECT_EQ(MOCK_CALLCOUNT(__get_PRIMASK, mock), 1);
|
||||||
|
EXPECT_EQ(MOCK_CALLCOUNT(__set_PRIMASK, mock), 1);
|
||||||
|
EXPECT_EQ(MOCK_CALLCOUNT(__disable_irq, mock), 1);
|
||||||
|
EXPECT_EQ(crcStatus.firstSlot, &slot1);
|
||||||
|
EXPECT_EQ(slot1.next, nullptr);
|
||||||
|
EXPECT_EQ(slot1.count, 2);
|
||||||
|
EXPECT_EQ(crcStatus.activeSlot, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
There are two ways to activate a mock:
|
||||||
|
|
||||||
|
ACTIVATE_MOCK(<function>, <decoration>);
|
||||||
|
|
||||||
|
and
|
||||||
|
|
||||||
|
ACTIVATE_MOCK_RV(<function>, <decoration>, <return_value>)
|
||||||
|
|
||||||
|
Both macros reset the corresponding `callcount` variable of the mock function to zero and divert the mocked function to the mock. In addition to this `ACTIVATE_MOCK_RV` also sets the return value variable of the mock function (created by `DEFINE_MOCK_RET`) to the supplied value. This can be used to define the return valuse of the mock (if the test writer decides to write the mock function this way).
|
||||||
|
|
||||||
|
After preparing everything for the test wi actually call `Crc_AttachTasks` with the appropriate parameters then verifying the results.
|
||||||
|
|
9
platforms/test/build-googletest.sh
Executable file
9
platforms/test/build-googletest.sh
Executable file
|
@ -0,0 +1,9 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -x
|
||||||
|
SCRIPTDIR=$(dirname "$0")
|
||||||
|
OUTDIR="$1"
|
||||||
|
cd "$SCRIPTDIR"/googletest
|
||||||
|
cmake -DCMAKE_CXX_FLAGS=-m32 -DCMAKE_INSTALL_PREFIX:PATH="../$OUTDIR" .
|
||||||
|
make -j8 && make install
|
||||||
|
rm install_manifest.txt
|
||||||
|
|
17
platforms/test/component.mk
Normal file
17
platforms/test/component.mk
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
SELF_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))
|
||||||
|
REL_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
|
||||||
|
ifeq ($(MKDBG), 1)
|
||||||
|
$(info >>> $(REL_DIR)/component.mk)
|
||||||
|
endif
|
||||||
|
$(eval C_SOURCES += $(wildcard $(REL_DIR)/platform/*.c))
|
||||||
|
$(eval COMMON_INCLUDES += -I$(REL_DIR) -I$(REL_DIR)/gtest_i386/include)
|
||||||
|
$(eval LIBDIR += -L$(REL_DIR)/gtest_i386/lib)
|
||||||
|
$(eval LIBS += -lgtest -lgtest_main -lpthread)
|
||||||
|
$(eval COMPONENT_DEPS += $(REL_DIR)/gtest_i386)
|
||||||
|
|
||||||
|
$(REL_DIR)/gtest_i386:
|
||||||
|
$(REL_DIR)/build-googletest.sh gtest_i386
|
||||||
|
|
||||||
|
ifeq ($(MKDBG), 1)
|
||||||
|
$(info <<<)
|
||||||
|
endif
|
Loading…
Add table
Add a link
Reference in a new issue