From 50e4ba8a0754373ed5d06727620486172c4fe30f Mon Sep 17 00:00:00 2001 From: Movitz Aaron Date: Wed, 28 Oct 2026 14:37:42 +0000 Subject: [PATCH] Import YEEP-144 library 1.2 sources Source-only snapshot of the 1.2 release. Drivers/ (the vendored ST HAL and CMSIS) is excluded at 173 MB; fetch it from STMicroelectronics/STM32CubeH5 to build. --- .clangd | 11 + .gitattributes | 2 + .gitignore | 10 + .settings/bundles-lock.store.json | 290 ++++++++ .settings/bundles.store.json | 32 + .settings/ide.store.json | 11 + .vscode/c_cpp_properties.json | 8 + .vscode/launch.json | 22 + .vscode/settings.json | 15 + .vscode/tasks.json | 65 ++ CMakeLists.txt | 188 +++++ CMakePresets.json | 55 ++ YEEP144lib/include/YEEP144.h | 21 + YEEP144lib/include/YEEP144_ADCPot.h | 8 + YEEP144lib/include/YEEP144_BluetoothUART.h | 19 + YEEP144lib/include/YEEP144_Buzzer.h | 10 + YEEP144lib/include/YEEP144_DCMotor.h | 39 ++ YEEP144lib/include/YEEP144_DebugUART.h | 17 + YEEP144lib/include/YEEP144_GP2Y0E02B.h | 10 + YEEP144lib/include/YEEP144_HCSR04.h | 29 + YEEP144lib/include/YEEP144_I2C.h | 13 + YEEP144lib/include/YEEP144_PiSPI.h | 18 + YEEP144lib/include/YEEP144_Pinout.h | 190 +++++ YEEP144lib/include/YEEP144_PushButton.h | 14 + YEEP144lib/include/YEEP144_RGB.h | 91 +++ YEEP144lib/include/YEEP144_SSD1306.h | 35 + YEEP144lib/include/YEEP144_Servo.h | 24 + YEEP144lib/include/YEEP144_TSOP4838.h | 8 + YEEP144lib/src/YEEP144.c | 166 +++++ YEEP144lib/src/YEEP144_ADCPot.c | 126 ++++ YEEP144lib/src/YEEP144_BluetoothUART.c | 257 +++++++ YEEP144lib/src/YEEP144_Buzzer.c | 135 ++++ YEEP144lib/src/YEEP144_DCMotor.c | 386 ++++++++++ YEEP144lib/src/YEEP144_DebugUART.c | 200 ++++++ YEEP144lib/src/YEEP144_GP2Y0E02B.c | 18 + YEEP144lib/src/YEEP144_HCSR04.c | 596 ++++++++++++++++ YEEP144lib/src/YEEP144_I2C.c | 70 ++ YEEP144lib/src/YEEP144_IRQ.c | 241 +++++++ YEEP144lib/src/YEEP144_PiSPI.c | 173 +++++ YEEP144lib/src/YEEP144_PushButton.c | 111 +++ YEEP144lib/src/YEEP144_RGB.c | 148 ++++ YEEP144lib/src/YEEP144_SSD1306.c | 779 +++++++++++++++++++++ YEEP144lib/src/YEEP144_Servo.c | 313 +++++++++ YEEP144lib/src/YEEP144_TSOP4838.c | 143 ++++ cmake/gnu-tools-for-stm32.cmake | 159 +++++ cmake/vscode_generated.cmake | 64 ++ include/stm32h5xx_hal_conf.h | 522 ++++++++++++++ include/stm32h5xx_it.h | 67 ++ include/stm32h5xx_nucleo_conf.h | 77 ++ src/main.c | 7 + src/startup_stm32h563xx.S | 683 ++++++++++++++++++ src/syscall.c | 244 +++++++ src/sysmem.c | 87 +++ src/system_stm32h5xx.c | 403 +++++++++++ stm32h563xi_flash.ld | 221 ++++++ yeepi.py | 67 ++ 56 files changed, 7718 insertions(+) create mode 100644 .clangd create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .settings/bundles-lock.store.json create mode 100644 .settings/bundles.store.json create mode 100644 .settings/ide.store.json create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 CMakeLists.txt create mode 100644 CMakePresets.json create mode 100644 YEEP144lib/include/YEEP144.h create mode 100644 YEEP144lib/include/YEEP144_ADCPot.h create mode 100644 YEEP144lib/include/YEEP144_BluetoothUART.h create mode 100644 YEEP144lib/include/YEEP144_Buzzer.h create mode 100644 YEEP144lib/include/YEEP144_DCMotor.h create mode 100644 YEEP144lib/include/YEEP144_DebugUART.h create mode 100644 YEEP144lib/include/YEEP144_GP2Y0E02B.h create mode 100644 YEEP144lib/include/YEEP144_HCSR04.h create mode 100644 YEEP144lib/include/YEEP144_I2C.h create mode 100644 YEEP144lib/include/YEEP144_PiSPI.h create mode 100644 YEEP144lib/include/YEEP144_Pinout.h create mode 100644 YEEP144lib/include/YEEP144_PushButton.h create mode 100644 YEEP144lib/include/YEEP144_RGB.h create mode 100644 YEEP144lib/include/YEEP144_SSD1306.h create mode 100644 YEEP144lib/include/YEEP144_Servo.h create mode 100644 YEEP144lib/include/YEEP144_TSOP4838.h create mode 100644 YEEP144lib/src/YEEP144.c create mode 100644 YEEP144lib/src/YEEP144_ADCPot.c create mode 100644 YEEP144lib/src/YEEP144_BluetoothUART.c create mode 100644 YEEP144lib/src/YEEP144_Buzzer.c create mode 100644 YEEP144lib/src/YEEP144_DCMotor.c create mode 100644 YEEP144lib/src/YEEP144_DebugUART.c create mode 100644 YEEP144lib/src/YEEP144_GP2Y0E02B.c create mode 100644 YEEP144lib/src/YEEP144_HCSR04.c create mode 100644 YEEP144lib/src/YEEP144_I2C.c create mode 100644 YEEP144lib/src/YEEP144_IRQ.c create mode 100644 YEEP144lib/src/YEEP144_PiSPI.c create mode 100644 YEEP144lib/src/YEEP144_PushButton.c create mode 100644 YEEP144lib/src/YEEP144_RGB.c create mode 100644 YEEP144lib/src/YEEP144_SSD1306.c create mode 100644 YEEP144lib/src/YEEP144_Servo.c create mode 100644 YEEP144lib/src/YEEP144_TSOP4838.c create mode 100644 cmake/gnu-tools-for-stm32.cmake create mode 100644 cmake/vscode_generated.cmake create mode 100644 include/stm32h5xx_hal_conf.h create mode 100644 include/stm32h5xx_it.h create mode 100644 include/stm32h5xx_nucleo_conf.h create mode 100644 src/main.c create mode 100644 src/startup_stm32h563xx.S create mode 100644 src/syscall.c create mode 100644 src/sysmem.c create mode 100644 src/system_stm32h5xx.c create mode 100644 stm32h563xi_flash.ld create mode 100644 yeepi.py diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..80891f8 --- /dev/null +++ b/.clangd @@ -0,0 +1,11 @@ +CompileFlags: + Add: + - -ferror-limit=0 + - -Wno-implicit-int + CompilationDatabase: build/Debug +Diagnostics: + Suppress: + - unused-includes + - unknown_typename + - unknown_typename_suggest + - typename_requires_specqual diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2ed8b11 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +build +!.settings +*.code-workspace + +# Vendored ST HAL/CMSIS - not part of the YEEP library, 173 MB, of which 108 MB +# is ST's .chm user manuals. Get it from STMicroelectronics/STM32CubeH5. +Drivers/ + +# macOS +.DS_Store diff --git a/.settings/bundles-lock.store.json b/.settings/bundles-lock.store.json new file mode 100644 index 0000000..b417a82 --- /dev/null +++ b/.settings/bundles-lock.store.json @@ -0,0 +1,290 @@ +{ + "resolved": [ + { + "name": "cmake", + "version": "4.2.3+st.1", + "platform": "darwin", + "selected_by": [ + { + "name": "cmake", + "version": "4.2.3+st.1" + } + ] + }, + { + "name": "cmake", + "version": "4.2.3+st.1", + "platform": "x86_64-linux", + "selected_by": [ + { + "name": "cmake", + "version": "4.2.3+st.1" + } + ] + }, + { + "name": "cmake", + "version": "4.2.3+st.1", + "platform": "x86_64-windows", + "selected_by": [ + { + "name": "cmake", + "version": "4.2.3+st.1" + } + ] + }, + { + "name": "gnu-gdb-for-stm32", + "version": "14.3.1+st.2", + "platform": "aarch64-darwin", + "selected_by": [ + { + "name": "gnu-gdb-for-stm32", + "version": "14.3.1+st.2" + } + ] + }, + { + "name": "gnu-gdb-for-stm32", + "version": "14.3.1+st.2", + "platform": "x86_64-darwin", + "selected_by": [ + { + "name": "gnu-gdb-for-stm32", + "version": "14.3.1+st.2" + } + ] + }, + { + "name": "gnu-gdb-for-stm32", + "version": "14.3.1+st.2", + "platform": "x86_64-linux", + "selected_by": [ + { + "name": "gnu-gdb-for-stm32", + "version": "14.3.1+st.2" + } + ] + }, + { + "name": "gnu-gdb-for-stm32", + "version": "14.3.1+st.2", + "platform": "x86_64-windows", + "selected_by": [ + { + "name": "gnu-gdb-for-stm32", + "version": "14.3.1+st.2" + } + ] + }, + { + "name": "gnu-tools-for-stm32", + "version": "14.3.1+st.2", + "platform": "aarch64-darwin", + "selected_by": [ + { + "name": "gnu-tools-for-stm32", + "version": "14.3.1+st.2" + } + ] + }, + { + "name": "gnu-tools-for-stm32", + "version": "14.3.1+st.2", + "platform": "x86_64-darwin", + "selected_by": [ + { + "name": "gnu-tools-for-stm32", + "version": "14.3.1+st.2" + } + ] + }, + { + "name": "gnu-tools-for-stm32", + "version": "14.3.1+st.2", + "platform": "x86_64-linux", + "selected_by": [ + { + "name": "gnu-tools-for-stm32", + "version": "14.3.1+st.2" + } + ] + }, + { + "name": "gnu-tools-for-stm32", + "version": "14.3.1+st.2", + "platform": "x86_64-windows", + "selected_by": [ + { + "name": "gnu-tools-for-stm32", + "version": "14.3.1+st.2" + } + ] + }, + { + "name": "gnu-tools-for-stm32-14_3_1-description", + "version": "1.0.1+st.2", + "platform": "all", + "selected_by": [ + { + "name": "gnu-tools-for-stm32-14_3_1-description", + "version": ">=0.0.1" + } + ] + }, + { + "name": "ninja", + "version": "1.13.2+st.1", + "platform": "darwin", + "selected_by": [ + { + "name": "ninja", + "version": "1.13.2+st.1" + } + ] + }, + { + "name": "ninja", + "version": "1.13.2+st.1", + "platform": "x86_64-linux", + "selected_by": [ + { + "name": "ninja", + "version": "1.13.2+st.1" + } + ] + }, + { + "name": "ninja", + "version": "1.13.2+st.1", + "platform": "x86_64-windows", + "selected_by": [ + { + "name": "ninja", + "version": "1.13.2+st.1" + } + ] + }, + { + "name": "programmer", + "version": "2.22.0+st.1", + "platform": "aarch64-darwin", + "selected_by": [ + { + "name": "programmer", + "version": "2.22.0+st.1" + } + ] + }, + { + "name": "programmer", + "version": "2.22.0+st.1", + "platform": "darwin", + "selected_by": [ + { + "name": "programmer", + "version": "2.22.0+st.1" + } + ] + }, + { + "name": "programmer", + "version": "2.22.0+st.1", + "platform": "x86_64-linux", + "selected_by": [ + { + "name": "programmer", + "version": "2.22.0+st.1" + } + ] + }, + { + "name": "programmer", + "version": "2.22.0+st.1", + "platform": "x86_64-windows", + "selected_by": [ + { + "name": "programmer", + "version": "2.22.0+st.1" + } + ] + }, + { + "name": "st-arm-clangd", + "version": "21.1.0+st.2", + "platform": "darwin", + "selected_by": [ + { + "name": "st-arm-clangd", + "version": "21.1.0+st.2" + } + ] + }, + { + "name": "st-arm-clangd", + "version": "21.1.0+st.2", + "platform": "x86_64-linux", + "selected_by": [ + { + "name": "st-arm-clangd", + "version": "21.1.0+st.2" + } + ] + }, + { + "name": "st-arm-clangd", + "version": "21.1.0+st.2", + "platform": "x86_64-windows", + "selected_by": [ + { + "name": "st-arm-clangd", + "version": "21.1.0+st.2" + } + ] + }, + { + "name": "stlink-gdbserver", + "version": "7.13.0+st.3", + "platform": "aarch64-darwin", + "selected_by": [ + { + "name": "stlink-gdbserver", + "version": "7.13.0+st.3" + } + ] + }, + { + "name": "stlink-gdbserver", + "version": "7.13.0+st.3", + "platform": "darwin", + "selected_by": [ + { + "name": "stlink-gdbserver", + "version": "7.13.0+st.3" + } + ] + }, + { + "name": "stlink-gdbserver", + "version": "7.13.0+st.3", + "platform": "x86_64-linux", + "selected_by": [ + { + "name": "stlink-gdbserver", + "version": "7.13.0+st.3" + } + ] + }, + { + "name": "stlink-gdbserver", + "version": "7.13.0+st.3", + "platform": "x86_64-windows", + "selected_by": [ + { + "name": "stlink-gdbserver", + "version": "7.13.0+st.3" + } + ] + } + ] +} diff --git a/.settings/bundles.store.json b/.settings/bundles.store.json new file mode 100644 index 0000000..62dcae0 --- /dev/null +++ b/.settings/bundles.store.json @@ -0,0 +1,32 @@ +{ + "bundles": [ + { + "name": "st-arm-clangd", + "version": "21.1.0+st.2" + }, + { + "name": "cmake", + "version": "4.2.3+st.1" + }, + { + "name": "ninja", + "version": "1.13.2+st.1" + }, + { + "name": "gnu-tools-for-stm32", + "version": "14.3.1+st.2" + }, + { + "name": "programmer", + "version": "2.22.0+st.1" + }, + { + "name": "stlink-gdbserver", + "version": "7.13.0+st.3" + }, + { + "name": "gnu-gdb-for-stm32", + "version": "14.3.1+st.2" + } + ] +} diff --git a/.settings/ide.store.json b/.settings/ide.store.json new file mode 100644 index 0000000..35f24e3 --- /dev/null +++ b/.settings/ide.store.json @@ -0,0 +1,11 @@ +{ + "board": "NUCLEO-H563ZI", + "device": "STM32H563ZIT6", + "core": "Cortex-M33", + "order": 0, + "toolchain": "GCC", + "source": { + "sourceType": "Empty" + }, + "tz": "TZ-disabled" +} \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..233ee1f --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,8 @@ +{ + "configurations": [ + { + "name": "STM32", + "compileCommands": "${workspaceFolder}/build/Debug/compile_commands.json" + } + ] +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..e128955 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,22 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "stlinkgdbtarget", + "request": "launch", + "name": "STM32Cube: Launch ST-Link GDB Server", + "origin": "snippet", + "cwd": "${workspaceFolder}", + "preBuild": "${command:st-stm32-ide-debug-launch.build}", + "runEntry": "main", + "imagesAndSymbols": [ + { + "imageFileName": "${command:st-stm32-ide-debug-launch.get-projects-binary-from-context1}" + } + ] + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..8627b90 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,15 @@ +{ + "cmake.cmakePath": "cube-cmake", + "cmake.configureArgs": [ + "-DCMAKE_COMMAND=cube-cmake" + ], + "cmake.preferredGenerators": [ + "Ninja" + ], + "stm32cube-ide-clangd.path": "cube", + "stm32cube-ide-clangd.arguments": [ + "starm-clangd", + "--query-driver=${env:CUBE_BUNDLE_PATH}/gnu-tools-for-stm32/14.3.1+st.2/bin/arm-none-eabi-gcc*", + "--query-driver=${env:CUBE_BUNDLE_PATH}/gnu-tools-for-stm32/14.3.1+st.2/bin/arm-none-eabi-g++*" + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..7bb5daf --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,65 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "shell", + "label": "CubeProg: Flash project (SWD)", + "command": "cube", + "args": [ + "programmer", + "--connect", + "port=swd", + "--download", + "${command:cmake.launchTargetPath}", + "-hardRst", + "-rst", + "--start" + ], + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": [], + "presentation": { + "showReuseMessage": false + } + }, + { + "label": "Build + Flash", + "dependsOrder": "sequence", + "dependsOn": [ + "CMake: clean rebuild", + "CubeProg: Flash project (SWD)" + ], + "problemMatcher": [ + "$gcc" + ], + "presentation": { + "showReuseMessage": false + } + }, + { + "type": "cmake", + "label": "CMake: clean rebuild", + "command": "cleanRebuild", + "targets": [ + "all" + ], + "preset": "Debug", + "group": "build", + "problemMatcher": [], + "detail": "CMake template clean rebuild task" + }, + { + "type": "cmake", + "label": "CMake: configure", + "command": "configure", + "preset": "Debug", + "problemMatcher": [], + "detail": "CMake template configure task" + }, + { + "label": "Configure and Build", + "dependsOn": ["CMake: configure", "${command:st-stm32-ide-debug-launch.build}"], + "dependsOrder": "sequence"} + ] + } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..559bf67 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,188 @@ +# ----------------------------------------------------------------------------- +# @author Auto-generated by STM32CubeIDE for Visual Studio Code Extension +# ----------------------------------------------------------------------------- +# @attention +# +# Copyright (c) 2025 STMicroelectronics. +# All rights reserved. +# +# This software is licensed under terms that can be found in the LICENSE file +# in the root directory of this software component. +# If no LICENSE file comes with this software, it is provided AS-IS. +# +# ----------------------------------------------------------------------------- + + cmake_minimum_required(VERSION 3.20) + +# +# This file is generated only once, and is not re-generated. +# +# User is free to modify the file as much as necessary +# + +# Core project settings +project("EEP-144_Library") +enable_language(C CXX ASM) +message("Build type: " ${CMAKE_BUILD_TYPE}) + +# Setup compiler settings +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_EXTENSIONS ON) +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS ON) + +# Core MCU flags, CPU type, instruction set and FPU setup +set(cpu_PARAMS + # Other parameters + # -mthumb + # -mcpu, -mfloat, -mfloat-abi, ... +) + +# Sources +file(GLOB_RECURSE + sources_SRCS CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c + ${CMAKE_CURRENT_SOURCE_DIR}/YEEP144lib/src/*.c + #${CMAKE_CURRENT_SOURCE_DIR}/Drivers/BSP/STM32H5xx_Nucleo/stm32h5xx_nucleo.c + ${CMAKE_CURRENT_SOURCE_DIR}/Drivers/STM32H5xx_HAL_Driver/Src/*.c +) + +# Include directories for all compilers +set(include_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/YEEP144lib/include + ${CMAKE_CURRENT_SOURCE_DIR}/Drivers/STM32H5xx_HAL_Driver/Inc + ${CMAKE_CURRENT_SOURCE_DIR}/Drivers/STM32H5xx_HAL_Driver/Inc/Legacy + #${CMAKE_CURRENT_SOURCE_DIR}/Drivers/BSP/STM32H5xx_Nucleo + ${CMAKE_CURRENT_SOURCE_DIR}/Drivers/CMSIS/Device/ST/STM32H5xx/Include + ${CMAKE_CURRENT_SOURCE_DIR}/Drivers/CMSIS/Include +) + +# Include directories for each compiler +set(include_c_DIRS) +set(include_cxx_DIRS) +set(include_asm_DIRS) + +# Symbols definition for all compilers +set(symbols_SYMB + USE_HAL_DRIVER + STM32H563xx) + +# Symbols definition for each compiler +set(symbols_c_SYMB) +set(symbols_cxx_SYMB) +set(symbols_asm_SYMB) + +# Link directories and names of libraries +set(link_DIRS) +set(link_LIBS + m) + +# Linker script +set(linker_script_SRC) + +# Compiler options +set(compiler_OPTS) + +# Linker options +set(linker_OPTS) + +# Now call generated cmake +# This will add script generated +# information to the project +include("cmake/vscode_generated.cmake") + +# Link directories setup +# Must be before executable is added +link_directories(${CMAKE_PROJECT_NAME} ${link_DIRS}) + +# Create an executable object type +add_executable(${CMAKE_PROJECT_NAME}) + +# Add sources to executable +target_sources(${CMAKE_PROJECT_NAME} PUBLIC ${sources_SRCS}) + +# Add include paths +target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE + ${include_DIRS} + $<$: ${include_c_DIRS}> + $<$: ${include_cxx_DIRS}> + $<$: ${include_asm_DIRS}> +) + +# Add project symbols (macros) +target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE + ${symbols_SYMB} + $<$: ${symbols_c_SYMB}> + $<$: ${symbols_cxx_SYMB}> + $<$: ${symbols_asm_SYMB}> + + # Configuration specific + $<$:DEBUG> + $<$: > +) + +# Add linked libraries +target_link_libraries(${CMAKE_PROJECT_NAME} ${link_LIBS}) + +# Compiler options +target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE + ${cpu_PARAMS} + ${compiler_OPTS} + -fstack-usage + # -fcyclomatic-complexity + -Wall + -Wextra + -Wpedantic + -Wno-unused-parameter + $<$: > + $<$: + + # -Wno-volatile + # -Wold-style-cast + # -Wuseless-cast + # -Wsuggest-override + > + $<$:-x assembler-with-cpp -MMD -MP> + $<$:-O0 -g3 -ggdb> + $<$:-Os> +) + +# Linker options +target_link_options(${CMAKE_PROJECT_NAME} PRIVATE + -T${linker_script_SRC} + ${cpu_PARAMS} + ${linker_OPTS} + -Wl,-Map=${CMAKE_PROJECT_NAME}.map + -u _printf_float + #-u _scanf_float + --specs=nosys.specs + -Wl,--start-group + -lc + -lm + -lstdc++ + -lsupc++ + -Wl,--end-group + -Wl,-z,max-page-size=8 # Allow good software remapping across address space (with proper GCC section making) + -Wl,--print-memory-usage +) + +# Conditionally add CMSE linker options +if(CMSIS_Dsecure STREQUAL "Secure") + target_link_options(${CMAKE_PROJECT_NAME} PRIVATE + -Wl,--cmse-implib + -Wl,--out-implib=secure_nsclib.o + ) +endif() + +# Set linker script as a dependency to force re-link if it changes +set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES LINK_DEPENDS ${linker_script_SRC}) + +# Execute post-build to print size, generate hex and bin +add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_SIZE} $ + COMMAND ${CMAKE_OBJCOPY} -O ihex $ ${CMAKE_PROJECT_NAME}.hex + COMMAND ${CMAKE_OBJCOPY} -O binary $ ${CMAKE_PROJECT_NAME}.bin +) diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..688d5a2 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,55 @@ +{ + "version": 3, + "configurePresets": [ + { + "name": "default", + "hidden": true, + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/${presetName}", + "toolchainFile": "${sourceDir}/cmake/gnu-tools-for-stm32.cmake", + "cacheVariables": { + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", + "CMSIS_Dvendor": "STMicroelectronics:13", + "CMSIS_Dname": "STM32H563ZIT6", + "CMSIS_Dcore": "Cortex-M33", + "CMSIS_Dtz": "TZ", + "CMSIS_Dfpu": "SP_FPU", + "CMSIS_Ddsp": "DSP", + "CMSIS_Dmve": "NO_MVE", + "CMSIS_Dmpu": "MPU", + "CMSIS_Dendian": "Little-endian", + "CMSIS_Dsecure": "TZ-disabled", + "CMSIS_Tcompiler": "GCC" + } + }, + { + "name": "Debug", + "inherits": "default", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "Release", + "inherits": "default", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + } + ], + "buildPresets": [ + { + "name": "default", + "hidden": true, + "configurePreset": "default" + }, + { + "name": "Debug", + "configurePreset": "Debug" + }, + { + "name": "Release", + "configurePreset": "Release" + } + ] +} \ No newline at end of file diff --git a/YEEP144lib/include/YEEP144.h b/YEEP144lib/include/YEEP144.h new file mode 100644 index 0000000..57e1651 --- /dev/null +++ b/YEEP144lib/include/YEEP144.h @@ -0,0 +1,21 @@ +#ifndef __YEEP144_H +#define __YEEP144_H + +#include "stm32h5xx_hal.h" + +#define GPIO_MODE_OUTPUT GPIO_MODE_OUTPUT_PP + +#define DEBUGUART 1 +#define BLUETOOTHUART 2 + +#define UARTSEL DEBUGUART + +// Public Function Prototypes +int YEEP144_Init(void); + +void delayUS(uint32_t us); + +void YEEP144_GPIO_Init(GPIO_TypeDef* port, uint32_t pins, uint32_t mode); +void YEEP144_GPIO_InitAdv(GPIO_TypeDef* port, uint32_t pins, uint32_t mode, uint32_t pull, uint32_t speed, uint32_t alternate); + +#endif \ No newline at end of file diff --git a/YEEP144lib/include/YEEP144_ADCPot.h b/YEEP144lib/include/YEEP144_ADCPot.h new file mode 100644 index 0000000..11cb2bd --- /dev/null +++ b/YEEP144lib/include/YEEP144_ADCPot.h @@ -0,0 +1,8 @@ +#ifndef __YEEP144_ADCPOT_H +#define __YEEP144_ADCPOT_H + +void YEEP144_ADCPot_Init(void); +uint16_t YEEP144_ADCPot_GetPot1(void); +uint16_t YEEP144_ADCPot_GetPot2(void); + +#endif \ No newline at end of file diff --git a/YEEP144lib/include/YEEP144_BluetoothUART.h b/YEEP144lib/include/YEEP144_BluetoothUART.h new file mode 100644 index 0000000..7c30573 --- /dev/null +++ b/YEEP144lib/include/YEEP144_BluetoothUART.h @@ -0,0 +1,19 @@ +#ifndef __YEEP144_BLUETOOTHUART_H +#define __YEEP144_BLUETOOTHUART_H + +#include "stm32h5xx_hal.h" +#include "stm32h5xx_hal_uart.h" + +// Structure for UART info +extern UART_HandleTypeDef huart2; + +void YEEP144_BluetoothUART_Init(void); +int YEEP144_BluetoothUART_printf(const char * format, ...); + +void YEEP144_BluetoothUART_EnableCharMatchIRQ(void); +void YEEP144_BluetoothUART_DisableCharMatchIRQ(void); +void YEEP144_BluetoothUART_SetCharMatch(char match); + +void YEEP144_BluetoothUART_SetStatusDelimiter(char prefix, char postfix); + +#endif \ No newline at end of file diff --git a/YEEP144lib/include/YEEP144_Buzzer.h b/YEEP144lib/include/YEEP144_Buzzer.h new file mode 100644 index 0000000..2bec69d --- /dev/null +++ b/YEEP144lib/include/YEEP144_Buzzer.h @@ -0,0 +1,10 @@ +#ifndef __YEEP144_BUZZER_H +#define __YEEP144_BUZZER_H + +void YEEP144_Buzzer_Init(void); +void YEEP144_Buzzer_Tone(uint32_t freq, uint32_t duration); +void YEEP144_Buzzer_GoTone(uint32_t freq); +void YEEP144_Buzzer_NoTone(void); +void YEEP144_Buzzer_Daisy(void); + +#endif \ No newline at end of file diff --git a/YEEP144lib/include/YEEP144_DCMotor.h b/YEEP144lib/include/YEEP144_DCMotor.h new file mode 100644 index 0000000..4562c73 --- /dev/null +++ b/YEEP144lib/include/YEEP144_DCMotor.h @@ -0,0 +1,39 @@ +#ifndef __YEEP144_DCMOTOR_H +#define __YEEP144_DCMOTOR_H + +#include + +// Defines +#define DCMOTOR1 1 +#define DCMOTOR2 2 +#define DCMOTOR3 3 +#define DCMOTOR4 4 + +#define DCMOTOR_STOP 0 // 0b00 +#define DCMOTOR_CCW 1 // 0b01 +#define DCMOTOR_CW 2 // 0b10 +#define DCMOTOR_SHORTBRAKE 3 // 0b11 + +#define DCMOTOR_MIN_SPEED 0 +#define DCMOTOR_MAX_SPEED 4095 // This corresponds to the Period of the timer + +// Function prototypes + +// Init functions +void YEEP144_DCMotor_Init(void); +void YEEP144_Encoder1_Init(void); +void YEEP144_Encoder2_Init(void); +void YEEP144_Encoder3_Init(void); +void YEEP144_Encoder4_Init(void); + +// Motor functions +void YEEP144_DCMotor_SetSpeed(uint8_t motor, uint16_t speed); +void YEEP144_DCMotor_SetDirection(uint8_t motor, uint8_t direction); + +// Encoder functions +uint16_t YEEP144_Encoder1_Get(void); +uint16_t YEEP144_Encoder2_Get(void); +uint16_t YEEP144_Encoder3_Get(void); +uint16_t YEEP144_Encoder4_Get(void); + +#endif \ No newline at end of file diff --git a/YEEP144lib/include/YEEP144_DebugUART.h b/YEEP144lib/include/YEEP144_DebugUART.h new file mode 100644 index 0000000..6fe85ba --- /dev/null +++ b/YEEP144lib/include/YEEP144_DebugUART.h @@ -0,0 +1,17 @@ +#ifndef __YEEP144_DEBUGUART_H +#define __YEEP144_DEBUGUART_H + +#include "stm32h5xx_hal.h" +#include "stm32h5xx_hal_uart.h" + +// Structure for UART info +extern UART_HandleTypeDef huart3; + +void YEEP144_DebugUART_Init(void); +int YEEP144_DebugUART_printf(const char * format, ...); + +void YEEP144_DebugUART_EnableCharMatchIRQ(void); +void YEEP144_DebugUART_DisableCharMatchIRQ(void); +void YEEP144_DebugUART_SetCharMatch(char match); + +#endif \ No newline at end of file diff --git a/YEEP144lib/include/YEEP144_GP2Y0E02B.h b/YEEP144lib/include/YEEP144_GP2Y0E02B.h new file mode 100644 index 0000000..76a8bd6 --- /dev/null +++ b/YEEP144lib/include/YEEP144_GP2Y0E02B.h @@ -0,0 +1,10 @@ +#ifndef __YEEP144_GP2Y0E02B_H +#define __YEEP144_GP2Y0E02B_H + +#define GP2Y0E02B_I2C_ADDR 0x80 +#define GP2Y0E02B_SHIFT_REG_ADDR 0x35 +#define GP2Y0E02B_DISTANCE_REG_ADDR 0x5E + +float YEEP144_GP2Y0E02B_Read(void); + +#endif \ No newline at end of file diff --git a/YEEP144lib/include/YEEP144_HCSR04.h b/YEEP144lib/include/YEEP144_HCSR04.h new file mode 100644 index 0000000..05ac2d8 --- /dev/null +++ b/YEEP144lib/include/YEEP144_HCSR04.h @@ -0,0 +1,29 @@ +#ifndef __YEEP144_HCSR04_H +#define __YEEP144_HCSR04_H + +#include + +void YEEP144_Ultrasonic1_Init(void); +void YEEP144_Ultrasonic2_Init(void); +void YEEP144_Ultrasonic3_Init(void); +void YEEP144_Ultrasonic4_Init(void); + +uint8_t YEEP144_Ultrasonic_PingNext(void); +float YEEP144_Ultrasonic_TickTocm(uint16_t ticks); + +uint8_t YEEP144_Ultrasonic1_Ping(void); +uint8_t YEEP144_Ultrasonic2_Ping(void); +uint8_t YEEP144_Ultrasonic3_Ping(void); +uint8_t YEEP144_Ultrasonic4_Ping(void); + +uint16_t YEEP144_Ultrasonic1_PingBlocking(void); +uint16_t YEEP144_Ultrasonic2_PingBlocking(void); +uint16_t YEEP144_Ultrasonic3_PingBlocking(void); +uint16_t YEEP144_Ultrasonic4_PingBlocking(void); + +void YEEP144_Ultrasonic_EXTI10Handler(void); +void YEEP144_Ultrasonic_EXTI12Handler(void); + +extern uint16_t ultrasonicTickLen[4]; + +#endif \ No newline at end of file diff --git a/YEEP144lib/include/YEEP144_I2C.h b/YEEP144lib/include/YEEP144_I2C.h new file mode 100644 index 0000000..0c26abc --- /dev/null +++ b/YEEP144lib/include/YEEP144_I2C.h @@ -0,0 +1,13 @@ +#ifndef __YEEP144_I2C_H +#define __YEEP144_I2C_H + +#include "stm32h5xx_hal.h" + +#define I2C_MUX_ADDR 0xEE + +extern I2C_HandleTypeDef hi2c2; + +void YEEP144_I2C_Init(void); +void YEEP144_I2C_MuxSelect(uint8_t busNumber); + +#endif \ No newline at end of file diff --git a/YEEP144lib/include/YEEP144_PiSPI.h b/YEEP144lib/include/YEEP144_PiSPI.h new file mode 100644 index 0000000..ae3bdec --- /dev/null +++ b/YEEP144lib/include/YEEP144_PiSPI.h @@ -0,0 +1,18 @@ +#ifndef __YEEP144_PISPI_H +#define __YEEP144_PISPI_H + +// This value define the size of the transfer buffers. +// It needs to match what is set on the Pi side so the correct amount of data is transferred each time +#define PISPI_BUFFER_SIZE 256 + +// Extern the buffer arrays so they are accessible from other files +extern uint8_t PiSPIRxBuf[PISPI_BUFFER_SIZE]; +extern uint8_t PiSPITxBuf[PISPI_BUFFER_SIZE]; + +void YEEP144_PiSPI_Init(void); +void YEEP144_PiSPI_SetReady(void); +void YEEP144_PiSPI_ResetReady(void); +void YEEP144_PiSPI_LoadTx(void); +void YEEP144_PiSPI_TxRxHandler(void); + +#endif \ No newline at end of file diff --git a/YEEP144lib/include/YEEP144_Pinout.h b/YEEP144lib/include/YEEP144_Pinout.h new file mode 100644 index 0000000..12dbf8c --- /dev/null +++ b/YEEP144lib/include/YEEP144_Pinout.h @@ -0,0 +1,190 @@ +/** +* This file contains #defines for the ports and pins used by the EEP-144 functions +* and is shared by all modules +*/ + +#ifndef __YEEP144_PINOUT_H +#define __YEEP144_PINOUT_H + +// DC Motors + +#define MOT1A_PORT GPIOG +#define MOT1A_PIN GPIO_PIN_0 +#define MOT1B_PORT GPIOG +#define MOT1B_PIN GPIO_PIN_1 +#define MOT1PWM_PORT GPIOC +#define MOT1PWM_PIN GPIO_PIN_6 + +#define MOT2A_PORT GPIOG +#define MOT2A_PIN GPIO_PIN_2 +#define MOT2B_PORT GPIOG +#define MOT2B_PIN GPIO_PIN_3 +#define MOT2PWM_PORT GPIOC +#define MOT2PWM_PIN GPIO_PIN_7 + +#define MOT3A_PORT GPIOE +#define MOT3A_PIN GPIO_PIN_7 +#define MOT3B_PORT GPIOE +#define MOT3B_PIN GPIO_PIN_8 +#define MOT3PWM_PORT GPIOB +#define MOT3PWM_PIN GPIO_PIN_0 + +#define MOT4A_PORT GPIOB +#define MOT4A_PIN GPIO_PIN_2 +#define MOT4B_PORT GPIOB +#define MOT4B_PIN GPIO_PIN_4 +#define MOT4PWM_PORT GPIOC +#define MOT4PWM_PIN GPIO_PIN_9 + +// DC Motor Encoders + +#define ENC1A_PORT GPIOD +#define ENC1A_PIN GPIO_PIN_12 +#define ENC1B_PORT GPIOD +#define ENC1B_PIN GPIO_PIN_13 + +#define ENC2A_PORT GPIOC +#define ENC2A_PIN GPIO_PIN_11 +#define ENC2B_PORT GPIOA +#define ENC2B_PIN GPIO_PIN_15 + +#define ENC3A_PORT GPIOF +#define ENC3A_PIN GPIO_PIN_2 +#define ENC3B_PORT GPIOF +#define ENC3B_PIN GPIO_PIN_9 + +#define ENC4A_PORT GPIOB +#define ENC4A_PIN GPIO_PIN_10 +#define ENC4B_PORT GPIOD +#define ENC4B_PIN GPIO_PIN_11 + +// Servos +#define SERVO1_PORT GPIOA +#define SERVO1_PIN GPIO_PIN_0 +#define SERVO2_PORT GPIOA +#define SERVO2_PIN GPIO_PIN_3 +#define SERVO3_PORT GPIOF +#define SERVO3_PIN GPIO_PIN_8 +#define SERVO4_PORT GPIOF +#define SERVO4_PIN GPIO_PIN_7 + +// Buzzer + +#define BUZZER_PORT GPIOF +#define BUZZER_PIN GPIO_PIN_7 + +// UART + +#define UART2_TX_PORT GPIOD +#define UART2_TX_PIN GPIO_PIN_5 +#define UART2_RX_PORT GPIOD +#define UART2_RX_PIN GPIO_PIN_6 +#define UART2_RTS_PORT GPIOD +#define UART2_RTS_PIN GPIO_PIN_4 +#define UART2_CTS_PORT GPIOD +#define UART2_CTS_PIN GPIO_PIN_3 + +#define UART3_TX_PORT GPIOD +#define UART3_TX_PIN GPIO_PIN_9 +#define UART3_RX_PORT GPIOD +#define UART3_RX_PIN GPIO_PIN_8 + +#define UART4_TX_PORT GPIOD +#define UART4_TX_PIN GPIO_PIN_1 +#define UART4_RX_PORT GPIOD +#define UART4_RX_PIN GPIO_PIN_0 + +// I2C + +#define I2C_SDA_PORT GPIOF +#define I2C_SDA_PIN GPIO_PIN_0 +#define I2C_SCL_PORT GPIOF +#define I2C_SCL_PIN GPIO_PIN_1 + +// SPI +#define SPI_MISO_PORT GPIOE +#define SPI_MISO_PIN GPIO_PIN_5 +#define SPI_MOSI_PORT GPIOE +#define SPI_MOSI_PIN GPIO_PIN_6 +#define SPI_SCK_PORT GPIOE +#define SPI_SCK_PIN GPIO_PIN_12 +#define SPI_CS_PORT GPIOE +#define SPI_CS_PIN GPIO_PIN_4 + +// Ultrasonic Distance Sensors + +#define USONIC1_TRIG_PORT GPIOE +#define USONIC1_TRIG_PIN GPIO_PIN_0 +#define USONIC1_ECHO_PORT GPIOC +#define USONIC1_ECHO_PIN GPIO_PIN_10 +#define USONIC1_ECHO_EXTI EXTI10_IRQn + +#define USONIC2_TRIG_PORT GPIOE +#define USONIC2_TRIG_PIN GPIO_PIN_2 +#define USONIC2_ECHO_PORT GPIOG +#define USONIC2_ECHO_PIN GPIO_PIN_10 +#define USONIC2_ECHO_EXTI EXTI10_IRQn + +#define USONIC3_TRIG_PORT GPIOE +#define USONIC3_TRIG_PIN GPIO_PIN_3 +#define USONIC3_ECHO_PORT GPIOE +#define USONIC3_ECHO_PIN GPIO_PIN_10 +#define USONIC3_ECHO_EXTI EXTI10_IRQn + +#define USONIC4_TRIG_PORT GPIOE +#define USONIC4_TRIG_PIN GPIO_PIN_15 +#define USONIC4_ECHO_PORT GPIOF +#define USONIC4_ECHO_PIN GPIO_PIN_12 +#define USONIC4_ECHO_EXTI EXTI12_IRQn + +// Pushbuttons + +#define BUTTON_BLUE_PORT GPIOC +#define BUTTON_BLUE_PIN GPIO_PIN_13 +#define BUTTON_BLUE_EXTI EXTI13_IRQn +#define BUTTON_0_PORT GPIOC +#define BUTTON_0_PIN GPIO_PIN_13 +#define BUTTON_0_EXTI EXTI13_IRQn + +#define BUTTON_GREEN_PORT GPIOD +#define BUTTON_GREEN_PIN GPIO_PIN_7 +#define BUTTON_GREEN_EXTI EXTI7_IRQn +#define BUTTON_1_PORT GPIOD +#define BUTTON_1_PIN GPIO_PIN_7 +#define BUTTON_1_EXTI EXTI7_IRQn + +#define BUTTON_YELLOW_PORT GPIOG +#define BUTTON_YELLOW_PIN GPIO_PIN_6 +#define BUTTON_YELLOW_EXTI EXTI6_IRQn +#define BUTTON_2_PORT GPIOG +#define BUTTON_2_PIN GPIO_PIN_6 +#define BUTTON_2_EXTI EXTI6_IRQn + +#define BUTTON_RED_PORT GPIOB +#define BUTTON_RED_PIN GPIO_PIN_12 +#define BUTTON_RED_EXTI EXTI12_IRQn +#define BUTTON_3_PORT GPIOB +#define BUTTON_3_PIN GPIO_PIN_12 +#define BUTTON_3_EXTI EXTI12_IRQn + +// Potentiometers + +#define POT1_PORT GPIOF +#define POT1_PIN GPIO_PIN_13 +#define POT2_PORT GPIOF +#define POT2_PIN GPIO_PIN_14 + +// SD Card +#define SD_CK_PORT GPIOC +#define SD_CK_PIN GPIO_PIN_12 +#define SD_CMD_PORT GPIOD +#define SD_CMD_PIN GPIO_PIN_2 +#define SD_D0_PORT GPIOC +#define SD_D0_PIN GPIO_PIN_8 + +// IR Beacon Receiver +#define IR_RECEIVER_PIN GPIO_PIN_3 +#define IR_RECEIVER_PORT GPIOF +#define IR_RECEIVER_EXTI EXTI3_IRQn + +#endif \ No newline at end of file diff --git a/YEEP144lib/include/YEEP144_PushButton.h b/YEEP144lib/include/YEEP144_PushButton.h new file mode 100644 index 0000000..8bd5c3a --- /dev/null +++ b/YEEP144lib/include/YEEP144_PushButton.h @@ -0,0 +1,14 @@ +#ifndef __YEEP144_PUSHBUTTON_H +#define __YEEP144_PUSHBUTTON_H + +void YEEP144_PushButton_BlueInit(void); +void YEEP144_PushButton_GreenInit(void); +void YEEP144_PushButton_YellowInit(void); +void YEEP144_PushButton_RedInit(void); + +void YEEP144_PushButton_BlueHandler(void); +void YEEP144_PushButton_GreenHandler(void); +void YEEP144_PushButton_YellowHandler(void); +void YEEP144_PushButton_RedHandler(void); + +#endif \ No newline at end of file diff --git a/YEEP144lib/include/YEEP144_RGB.h b/YEEP144lib/include/YEEP144_RGB.h new file mode 100644 index 0000000..98914d4 --- /dev/null +++ b/YEEP144lib/include/YEEP144_RGB.h @@ -0,0 +1,91 @@ +#ifndef __YEEP144_RGB_H +#define __YEEP144_RGB_H + +#define RGB1_RED 0x5 +#define RGB1_GREEN 0x4 +#define RGB1_BLUE 0x6 + +#define RGB2_RED 0x8 +#define RGB2_GREEN 0x7 +#define RGB2_BLUE 0x9 + +#define RGB3_RED 0xB +#define RGB3_GREEN 0xA +#define RGB3_BLUE 0xC + +#define RGB4_RED 0xE +#define RGB4_GREEN 0xD +#define RGB4_BLUE 0xF + +// Pure colours +#define RGB_OFF 0x00, 0x00, 0x00 +#define RGB_RED 0xFF, 0x00, 0x00 +#define RGB_GREEN 0x00, 0x80, 0x00 +#define RGB_BLUE 0x00, 0x00, 0x00 + +// HTML standard colours +#define RGB_WHITE 0xFF, 0xFF, 0xFF +#define RGB_MAROON 0x80, 0x00, 0x00 +#define RGB_YELLOW 0xFF, 0xFF, 0xFF +#define RGB_OLIVE 0x80, 0x80, 0x00 +#define RGB_LIME 0x00, 0xFF, 0x00 +#define RGB_CYAN 0x00, 0xFF, 0xFF +#define RGB_TEAL 0x00, 0x80, 0x80 +#define RGB_NAVY 0x00, 0x00, 0x80 +#define RGB_MAGENTA 0xFF, 0x00, 0xFF +#define RGB_PURPLE 0x80, 0x00, 0x80 +#define RGB_ORANGE 0xFF, 0xA5, 0x00 + +// Selection of HTML extended colours +// Pinks +#define RGB_DEEPPINK 0xFF, 0x14, 0x93 +#define RGB_HOTPINK 0xFF, 0x69, 0xB4 +#define RGB_PINK 0xFF, 0xC0, 0xCB + +// Reds +#define RGB_DARKRED 0x8B, 0x00, 0x00 +#define RGB_CRIMSON 0xDC, 0x14, 0x3C +#define RGB_SALMON 0xFA, 0x80, 0x72 + +// Oranges +#define RGB_ORANGERED 0xFF, 0x45, 0x00 +#define RGB_DARKORANGE 0xFF, 0x8C, 0x00 +#define RGB_CORAL 0xFF, 0x7F, 0x50 + +// Yellows +#define RGB_DARKKHAKI 0xBD, 0xB7, 0x6B +#define RGB_GOLD 0xFF, 0xD7, 0x00 +#define RGB_KHAKI 0xF0, 0xE6, 0x8C + +// Browns +#define RGB_BROWN 0xA5, 0x2A, 0x2A +#define RGB_SADDLEBROWN 0x8B, 0x45, 0x13 +#define RGB_ROSYBROWN 0xBC, 0x8F, 0x8F + +// Purples +#define RGB_INDIGO 0x4B, 0x00, 0x82 +#define RGB_DARKORCHID 0x99, 0x32, 0xCC +#define RGB_VIOLET 0xEE, 0x82, 0xEE + +// Blues +#define RGB_ROYALBLUE 0x41, 0x69, 0xE1 +#define RGB_CORNFLOWERBLUE 0x64, 0x95, 0xED +#define RGB_SKYBLUE 0x87, 0xCE, 0xEB + +// Cyans +#define RGB_TURQUOISE 0x40, 0xE0, 0xD0 +#define RGB_AQUAMARINE 0x7F, 0xFF, 0xD4 + +// Greens +#define RGB_DARKGREEN 0x00, 0x64, 0x00 +#define RGB_SEAGREEN 0x2E, 0x8B, 0x57 +#define RGB_CHARTREUSE 0x7F, 0xFF, 0x00 + +void YEEP144_RGB_Init(void); + +void YEEP144_RGB_SetLED(uint8_t led, uint8_t value); +void YEEP144_RGB_SetRGB(uint8_t led, uint8_t red, uint8_t green, uint8_t blue); + +void YEEP144_RGB_WriteReg(uint16_t reg, uint8_t data); + +#endif \ No newline at end of file diff --git a/YEEP144lib/include/YEEP144_SSD1306.h b/YEEP144lib/include/YEEP144_SSD1306.h new file mode 100644 index 0000000..ff413b6 --- /dev/null +++ b/YEEP144lib/include/YEEP144_SSD1306.h @@ -0,0 +1,35 @@ +#ifndef __YEEP144_SSD1306_H +#define __YEEP144_SSD1306_H + +#define SSD1306_BLACK 0 +#define SSD1306_WHITE 1 +#define SSD1306_INVERSE 2 + +#include +#include + +void YEEP144_SSD1306_Init(void); +void YEEP144_SSD1306_Display(void); +void YEEP144_SSD1306_ClearDisplay(void); +void YEEP144_SSD1306_SetPixel(uint8_t x, uint8_t y, uint8_t colour); +bool YEEP144_SSD1306_GetPixel(uint8_t x, uint8_t y); + +void YEEP144_SSD1306_DrawLine(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t colour); + +void YEEP144_SSD1306_DrawRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t colour); +void YEEP144_SSD1306_DrawFillRect(uint8_t x, uint8_t y, int8_t w, int8_t h, uint8_t colour); + +void YEEP144_SSD1306_DrawChar(uint8_t x, uint8_t y, uint8_t c, uint8_t colour, uint8_t bg, uint8_t size); +int YEEP144_SSD1306_printf(const char * format, ...); +void YEEP144_SSD1306_SetTextSize(uint8_t size); +void YEEP144_SSD1306_SetTextCursor(uint8_t x, uint8_t y); +void YEEP144_SSD1306_SetTextWrap(uint8_t wrap); + +void YEEP144_SSD1306_DrawBitmap(uint8_t x, uint8_t y, const uint8_t bitmap[], uint8_t w, uint8_t h); + +void YEEP144_SSD1306_InvertDisplay(bool i); +void YEEP144_SSD1306_SendCommand(uint8_t command); + +extern const unsigned char UOYLogo[]; + +#endif \ No newline at end of file diff --git a/YEEP144lib/include/YEEP144_Servo.h b/YEEP144lib/include/YEEP144_Servo.h new file mode 100644 index 0000000..3d44d67 --- /dev/null +++ b/YEEP144lib/include/YEEP144_Servo.h @@ -0,0 +1,24 @@ +#ifndef __YEEP144_SERVO_H +#define __YEEP144_SERVO_H + +void YEEP144_Servo_Init1_2(void); +void YEEP144_Servo_Init3(void); +void YEEP144_Servo_Init4(void); + +void YEEP144_Servo1_SetDirect(uint16_t pulse); +void YEEP144_Servo2_SetDirect(uint16_t pulse); +void YEEP144_Servo3_SetDirect(uint16_t pulse); +void YEEP144_Servo4_SetDirect(uint16_t pulse); + +void YEEP144_Servo1_SetAngle(float angle); +void YEEP144_Servo2_SetAngle(float angle); +void YEEP144_Servo3_SetAngle(float angle); +void YEEP144_Servo4_SetAngle(float angle); + +void YEEP144_Servo_SetMinTicks(uint8_t servo, uint16_t min); +void YEEP144_Servo_SetMaxTicks(uint8_t servo, uint16_t max); + +void YEEP144_Servo_SetMinAngle(uint8_t servo, float min); +void YEEP144_Servo_SetMaxAngle(uint8_t servo, float max); + +#endif \ No newline at end of file diff --git a/YEEP144lib/include/YEEP144_TSOP4838.h b/YEEP144lib/include/YEEP144_TSOP4838.h new file mode 100644 index 0000000..38ed5d4 --- /dev/null +++ b/YEEP144lib/include/YEEP144_TSOP4838.h @@ -0,0 +1,8 @@ +#ifndef __YEEP144_TSOP4838_H +#define __YEEP144_TSOP4838_H + +void YEEP144_TSOP4838_Init(void); +uint8_t YEEP144_TSOP4838_Received(void); +uint32_t YEEP144_TSOP4838_Read(void); + +#endif \ No newline at end of file diff --git a/YEEP144lib/src/YEEP144.c b/YEEP144lib/src/YEEP144.c new file mode 100644 index 0000000..090b97c --- /dev/null +++ b/YEEP144lib/src/YEEP144.c @@ -0,0 +1,166 @@ +#include "YEEP144.h" +#include "stm32h563xx.h" +#include "stm32h5xx_hal.h" +#include "stm32h5xx_hal_gpio.h" +#include "stm32h5xx_hal_rcc.h" +#include "stm32h5xx_hal_tim.h" + +// Private Function Prototypes +void SystemClock_Config(void); +void GPIO_Init(void); + +#define SYSTICK_LOAD (SystemCoreClock/1000000U) +#define SYSTICK_DELAY_CALIB (85)// Determined experimentally + +/** +* This function initialises the minimum required for basic operation +* Each feature on top of this will be initialised by its own init function +*/ +int YEEP144_Init(void){ + HAL_Init(); + + SystemClock_Config(); + + return 0; +} + +/** + * Initialises the specified GPIO with basic configuration. This assumes it will be one of the standard modes + * with no pull-ups or pull-downs, and a low frequency output + */ +void YEEP144_GPIO_Init(GPIO_TypeDef* port, uint32_t pins, uint32_t mode){ + // Initialise GPIO pins + + // Create structure to hold GPIO init data + GPIO_InitTypeDef GPIO_InitStruct = {0}; + + GPIO_InitStruct.Pin = pins; // Pins used + GPIO_InitStruct.Mode = mode; // Set pin mode + GPIO_InitStruct.Pull = GPIO_NOPULL; // No pull-ups or pull-downs + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // Low speed is sufficient for this task + + // Initialise the port + HAL_GPIO_Init(port, &GPIO_InitStruct); +} + +/** + * Initialises the specified GPIO with access to all of the configuration options, allowing you to configure + * pull-ups / pull-downs, GPIO speed, and access alternate functions such as timer IO, SPI, I2C etc + */ +void YEEP144_GPIO_InitAdv(GPIO_TypeDef* port, uint32_t pins, uint32_t mode, uint32_t pull, uint32_t speed, uint32_t alternate){ + // Initialise GPIO pins + + // Create structure to hold GPIO init data + GPIO_InitTypeDef GPIO_InitStruct = {0}; + + GPIO_InitStruct.Pin = pins; // Pins used + GPIO_InitStruct.Mode = mode; // Set pin mode + GPIO_InitStruct.Pull = pull; // Set pullup / pulldown + GPIO_InitStruct.Speed = speed; // Set speed - low is good for up to 8MHz + GPIO_InitStruct.Alternate = alternate; // Set alternate mode + + // Initialise the port + HAL_GPIO_Init(port, &GPIO_InitStruct); +} + +/** +* Initialises and configures the system clocks for standard operation +* +* By default we are configured for the maximum clock speed of 250MHz on the core +* and on the APBx peripheral and timer clocks +* +* As we do not have a HSE clock due to the configuration of the Nucleo board +* all clocks are based from the internal oscillators, primarily the HSI clock +* where possible as it should give use the most stable clock from the options available +* +* This code is mostly copied from an MX generated project +*/ +void SystemClock_Config(void){ + RCC_OscInitTypeDef RCC_OscInitStruct = {0}; + RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; + + /** Configure the main internal regulator output voltage + */ + __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0); + + while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {} + + /** Initializes the RCC Oscillators according to the specified parameters + * in the RCC_OscInitTypeDef structure. + */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_CSI; + RCC_OscInitStruct.HSIState = RCC_HSI_ON; + RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1; + RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; + RCC_OscInitStruct.CSIState = RCC_CSI_ON; + RCC_OscInitStruct.CSICalibrationValue = RCC_CSICALIBRATION_DEFAULT; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLL1_SOURCE_HSI; + RCC_OscInitStruct.PLL.PLLM = 32; + RCC_OscInitStruct.PLL.PLLN = 250; + RCC_OscInitStruct.PLL.PLLP = 2; + RCC_OscInitStruct.PLL.PLLQ = 2; + RCC_OscInitStruct.PLL.PLLR = 2; + RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1_VCIRANGE_1; + RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE; + RCC_OscInitStruct.PLL.PLLFRACN = 0; + if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) + { + //Error_Handler(); + } + + /** Initializes the CPU, AHB and APB buses clocks + */ + RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK + |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2 + |RCC_CLOCKTYPE_PCLK3; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; + RCC_ClkInitStruct.APB3CLKDivider = RCC_HCLK_DIV1; + + if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) + { + //Error_Handler(); + } + + /** Configure the programming delay + */ + __HAL_FLASH_SET_PROGRAM_DELAY(FLASH_PROGRAMMING_DELAY_2); + + // Enable all GPIO clocks + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + __HAL_RCC_GPIOH_CLK_ENABLE(); + __HAL_RCC_GPIOI_CLK_ENABLE(); +} + +/** + * This function provides a delay in uS instead of ms + * It should only be used for small delays <1ms + */ +void delayUS(uint32_t us){ + uint32_t startCount = SysTick->VAL; + uint32_t targetCount = startCount - (us * SYSTICK_LOAD) + SYSTICK_DELAY_CALIB; + + // Handle wraparounds + // If the targetCount is greater than the LOAD value, this means the previous subtraction + // has underflowed + if(targetCount > SysTick->LOAD){ + // Calculate a new targetCount taking the wraparound into account + targetCount = SysTick->LOAD - (us * SYSTICK_LOAD) + startCount + (SYSTICK_DELAY_CALIB); + + // Wait until the SysTick reloads + while(SysTick->VAL < startCount); + startCount = SysTick->LOAD; + } + + // Wait until we count down until the targetCount + while((SysTick->VAL > targetCount) && (SysTick->VAL < startCount)); +} diff --git a/YEEP144lib/src/YEEP144_ADCPot.c b/YEEP144lib/src/YEEP144_ADCPot.c new file mode 100644 index 0000000..98a853f --- /dev/null +++ b/YEEP144lib/src/YEEP144_ADCPot.c @@ -0,0 +1,126 @@ +#include "YEEP144.h" +#include "YEEP144_Pinout.h" +#include "YEEP144_ADCPot.h" + +#include "stm32h5xx_hal_adc.h" +#include "stm32h5xx_hal_gpio.h" + +#define ADC_TIMEOUT 1000 + +ADC_HandleTypeDef hadc2; + +/** + * Initialise the potentiometers. This consumes ADC2, along with 2 GPIO + */ +void YEEP144_ADCPot_Init(void){ + + // Setup and enable the ADC peripheral clock + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; + + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_ADCDAC; + PeriphClkInitStruct.AdcDacClockSelection = RCC_ADCDACCLKSOURCE_HSI; // HSI = 64MHz input clock + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK){ + //Error_Handler(); + } + + __HAL_RCC_ADC_CLK_ENABLE(); + + // Configure and initialise the ADC peripheral + + hadc2.Instance = ADC2; + hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; // No clock division = 64MHz + hadc2.Init.Resolution = ADC_RESOLUTION_12B; // 12-bit resolution (maximum) + hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT; + hadc2.Init.ScanConvMode = ADC_SCAN_ENABLE; + hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV; + hadc2.Init.LowPowerAutoWait = DISABLE; + hadc2.Init.ContinuousConvMode = DISABLE; + hadc2.Init.NbrOfConversion = 2; // 2 channels in use + hadc2.Init.DiscontinuousConvMode = DISABLE; + hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START; // Conversion triggered by software + hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; + hadc2.Init.DMAContinuousRequests = DISABLE; // No DMA + hadc2.Init.SamplingMode = ADC_SAMPLING_MODE_NORMAL; + hadc2.Init.Overrun = ADC_OVR_DATA_PRESERVED; + hadc2.Init.OversamplingMode = ENABLE; // Enable oversampling + hadc2.Init.Oversampling.Ratio = ADC_OVERSAMPLING_RATIO_256; // 256x oversampling gets us 4 extra bits of resolution + hadc2.Init.Oversampling.RightBitShift = ADC_RIGHTBITSHIFT_8; // Shift by 8 to get us back to 12-bit output + hadc2.Init.Oversampling.TriggeredMode = ADC_TRIGGEREDMODE_SINGLE_TRIGGER; + hadc2.Init.Oversampling.OversamplingStopReset = ADC_REGOVERSAMPLING_CONTINUED_MODE; + if (HAL_ADC_Init(&hadc2) != HAL_OK){ + //Error_Handler(); + } + + // Initialise the GPIO used + YEEP144_GPIO_Init(POT1_PORT, POT1_PIN | POT2_PIN, GPIO_MODE_ANALOG); +} + +/** + * Gets the current value of potentiometer 1. + * Returns a 12-bit value in the range 0 - 4095. + * This blocks until the conversion is complete, ~1ms + */ +uint16_t YEEP144_ADCPot_GetPot1(void){ + + // Configure this channel to be converted next + ADC_ChannelConfTypeDef sConfig = {0}; + sConfig.Channel = ADC_CHANNEL_2; + sConfig.Rank = ADC_REGULAR_RANK_1; + sConfig.SamplingTime = ADC_SAMPLETIME_247CYCLES_5; + // With a 64MHz clock and 256x oversampling, 247.5 cycles sample gives us a conversion time of ~1ms + // or a maximum sample rate of ~1kHz + sConfig.SingleDiff = ADC_SINGLE_ENDED; + sConfig.OffsetNumber = ADC_OFFSET_NONE; + sConfig.Offset = 0; + if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK){ + //Error_Handler(); + } + + // Start the conversion + HAL_ADC_Start(&hadc2); + + // Wait until the conversion is finished + HAL_ADC_PollForConversion(&hadc2, ADC_TIMEOUT); + + // Grab the converted value now conversion is finished + uint16_t adcval = HAL_ADC_GetValue(&hadc2); + + // Stop the ADC + HAL_ADC_Stop(&hadc2); + + return adcval; +} + +/** + * Gets the current value of potentiometer 2. + * Returns a 12-bit value in the range 0 - 4095. + * This blocks until the conversion is complete, ~1ms + */ +uint16_t YEEP144_ADCPot_GetPot2(void){ + ADC_ChannelConfTypeDef sConfig = {0}; + sConfig.Channel = ADC_CHANNEL_6; + sConfig.Rank = ADC_REGULAR_RANK_1; + sConfig.SamplingTime = ADC_SAMPLETIME_247CYCLES_5; + // With a 64MHz clock and 256x oversampling, 247.5 cycles sample gives us a conversion time of ~1ms + // or a maximum sample rate of ~1kHz + sConfig.SingleDiff = ADC_SINGLE_ENDED; + sConfig.OffsetNumber = ADC_OFFSET_NONE; + sConfig.Offset = 0; + if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK){ + //Error_Handler(); + } + + // Start the conversion + HAL_ADC_Start(&hadc2); + + // Wait until the conversion is finished + HAL_ADC_PollForConversion(&hadc2, ADC_TIMEOUT); + + // Grab the converted value now conversion is finished + uint16_t adcval = HAL_ADC_GetValue(&hadc2); + + // Stop the ADC + HAL_ADC_Stop(&hadc2); + + return adcval; +} \ No newline at end of file diff --git a/YEEP144lib/src/YEEP144_BluetoothUART.c b/YEEP144lib/src/YEEP144_BluetoothUART.c new file mode 100644 index 0000000..4956e94 --- /dev/null +++ b/YEEP144lib/src/YEEP144_BluetoothUART.c @@ -0,0 +1,257 @@ +// YEEP144 includes +#include "YEEP144.h" +#include "YEEP144_BluetoothUART.h" +#include "YEEP144_Pinout.h" + +// HAL includes +#include "stm32h563xx.h" +#include "stm32h5xx.h" +#include "stm32h5xx_hal.h" +#include "stm32h5xx_hal_cortex.h" +#include "stm32h5xx_hal_dma.h" +#include "stm32h5xx_hal_gpio_ex.h" +#include "stm32h5xx_hal_rcc.h" +#include "stm32h5xx_hal_uart.h" +#include "stm32h5xx_hal_uart_ex.h" + +// Std includes +#include +#include +#include +#include +#include + +#define UART_POLL_TIMEOUT 1000 + +// Structure for UART info +UART_HandleTypeDef huart2; + +DMA_HandleTypeDef handle_GPDMA1_Channel0; + +/** +* Initialises USART2 for use with the Bluetooth Serial addon board +* +* This consumes the USART2 peripheral and all of the UART pins on the comms headers +* as well as Channel 0 on GPDMA1 +*/ +void YEEP144_BluetoothUART_Init(void){ + + // DMA clock and interrupt + __HAL_RCC_GPDMA1_CLK_ENABLE(); + HAL_NVIC_SetPriority(GPDMA1_Channel0_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(GPDMA1_Channel0_IRQn); + + // Initialise and start the clock + + // Structure to hold clock config + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; + + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USART2; // Configuring USART2 + PeriphClkInitStruct.Lptim3ClockSelection = RCC_USART2CLKSOURCE_PCLK1; // Select PCLK1 + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK){ + //Error_Handler(); + } + + // Enable the clock + __HAL_RCC_USART2_CLK_ENABLE(); + + // Populate the UART struct with the configuration data + // 115200 8-N-1 with flow control + huart2.Instance = USART2; + huart2.Init.BaudRate = 115200; // 115200 Baud rate + huart2.Init.WordLength = UART_WORDLENGTH_8B; // 8 bit + huart2.Init.Parity = UART_PARITY_NONE; // None parity + huart2.Init.StopBits = UART_STOPBITS_1; // 1 Stop bit + huart2.Init.Mode = UART_MODE_TX_RX; // Full duplex + huart2.Init.HwFlowCtl = UART_HWCONTROL_RTS_CTS; // Full flow control (RTS, CTS) + huart2.Init.OverSampling = UART_OVERSAMPLING_8; + huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1; + if(HAL_UART_Init(&huart2) != HAL_OK){ + + } + + // Initialise GPIO pins + YEEP144_GPIO_InitAdv(UART2_TX_PORT, UART2_RX_PIN | UART2_TX_PIN | UART2_CTS_PIN | UART2_RTS_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW, GPIO_AF7_USART2); + + // Enable USART IRQs + HAL_NVIC_SetPriority(USART2_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(USART2_IRQn); + + HAL_UARTEx_DisableFifoMode(&huart2); + + // Populate DMA init structure + handle_GPDMA1_Channel0.Instance = GPDMA1_Channel0; + handle_GPDMA1_Channel0.Init.Request = GPDMA1_REQUEST_USART2_RX; + handle_GPDMA1_Channel0.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST; + handle_GPDMA1_Channel0.Init.Direction = DMA_PERIPH_TO_MEMORY; + handle_GPDMA1_Channel0.Init.SrcInc = DMA_SINC_FIXED; + handle_GPDMA1_Channel0.Init.DestInc = DMA_DINC_INCREMENTED; + handle_GPDMA1_Channel0.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE; + handle_GPDMA1_Channel0.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE; + handle_GPDMA1_Channel0.Init.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT; + handle_GPDMA1_Channel0.Init.SrcBurstLength = 1; + handle_GPDMA1_Channel0.Init.DestBurstLength = 1; + handle_GPDMA1_Channel0.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0; + handle_GPDMA1_Channel0.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER; + handle_GPDMA1_Channel0.Init.Mode = DMA_NORMAL; + if (HAL_DMA_Init(&handle_GPDMA1_Channel0) != HAL_OK) + { + //Error_Handler(); + } + + __HAL_LINKDMA(&huart2, hdmarx, handle_GPDMA1_Channel0); + + if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel0, DMA_CHANNEL_NPRIV) != HAL_OK) + { + //Error_Handler(); + } + + // Set default character match to carriage return + YEEP144_BluetoothUART_SetCharMatch('\n'); + + // Disable buffering on stdin. This prevents problems when using scanf with the UART redirection + setvbuf(stdin, NULL, _IONBF, 0); +} + +/** + * Prints to the Bluetooth UART, regardless of what the default UART is set to. + * Arguments and returns are the same as the default printf + * + * Internally this doesn't work using a stream like default printf, but uses a buffer, so the command may + * fail if the buffer cannot be allocated, or the output may be truncated if expanding the format specifiers causes + * the string to expand by more than 256 bytes + */ +int YEEP144_BluetoothUART_printf(const char * format, ...){ + // Calculate how long the input string is, plus extra space for substitition in the format specifiers + size_t bufSize = strlen(format) + 256; + + // Try to allocate that buffer + char* buffer = malloc(bufSize); + + // If the buffer cannot be allocated, return -1 + if (buffer == NULL) return -1; + + // Get the pointer to the variadic args + va_list args; + va_start (args, format); + + // Create our final string in the buffer using vsnprintf, passing through our argument pointer + vsnprintf(buffer, bufSize, format, args); + + // Calulate the final size of the string + bufSize = strlen(buffer); + + // Transmit over UART + HAL_UART_Transmit(&huart2, (uint8_t*)buffer, bufSize, UART_POLL_TIMEOUT); + + // Free the memory used + free(buffer); + + // Return number of characters printed + return bufSize; +} + +/** + * Enables the character match IRQ. When the configured character received an interrupt is fired. + * The current transfer will be terminated and the YEEP144_BluetoothUART_MatchCallback will be called + */ +void YEEP144_BluetoothUART_EnableCharMatchIRQ(void){ + __HAL_UART_ENABLE_IT(&huart2, UART_IT_CM); +} + +/** + * Disables the character match IRQ + */ +void YEEP144_BluetoothUART_DisableCharMatchIRQ(void){ + __HAL_UART_DISABLE_IT(&huart2, UART_IT_CM); +} + +/** + * Set the character match IRQ character. When the configured character received an interrupt is fired. + * The current transfer will be terminated and the YEEP144_BluetoothUART_MatchCallback will be called + */ +void YEEP144_BluetoothUART_SetCharMatch(char match){ + __HAL_UART_DISABLE(&huart2); + MODIFY_REG(huart2.Instance->CR2, USART_CR2_ADD_Msk, match<< USART_CR2_ADD_Pos); + __HAL_UART_ENABLE(&huart2); +} + +/** + * Sets the pre and post delimiters for the BT status messages + * Setting both to null disables the status messages entirely + */ +void YEEP144_BluetoothUART_SetStatusDelimiter(char prefix, char postfix){ + + // Save this register so we can restore character match IRQ if needed + uint32_t config = READ_REG(huart2.Instance->CR1); + + // Disable the character match irq so it doesn't fire during this function + YEEP144_BluetoothUART_DisableCharMatchIRQ(); + + uint8_t rxBuf[10]; + uint16_t rxSize; + + // Enter command mode + HAL_UART_Transmit(&huart2, "$$$", 3, UART_POLL_TIMEOUT); + + // Wait to receive data back from BT module + HAL_UARTEx_ReceiveToIdle(&huart2, rxBuf, 10, &rxSize, UART_POLL_TIMEOUT); + + // Set delimiters + char txBuf[8] = {0}; + if(prefix == '\0' && postfix == '\0'){ + sprintf(txBuf, "SO,,%c",'\r'); + } + else if(prefix == '\0'){ + sprintf(txBuf, "SO,,%c%c", postfix, '\r'); + } + else if(postfix == '\0'){ + sprintf(txBuf, "SO,%c,%c", prefix, '\r'); + } + else{ + sprintf(txBuf, "SO,%c,%c%c", prefix, postfix, '\r'); + } + HAL_UART_Transmit(&huart2, txBuf, sizeof(rxBuf), UART_POLL_TIMEOUT); + + // Wait to receive data back from BT module + HAL_UARTEx_ReceiveToIdle(&huart2, rxBuf, 10, &rxSize, UART_POLL_TIMEOUT); + + // Reboot device to make changes + HAL_UART_Transmit(&huart2, "R,1", 3, UART_POLL_TIMEOUT); + + // Wait to receive data back from BT module + HAL_UARTEx_ReceiveToIdle(&huart2, rxBuf, 10, &rxSize, UART_POLL_TIMEOUT); + + // Re-enable the character match IRQ if it previously was + if(config & USART_CR1_CMIE){ + YEEP144_BluetoothUART_EnableCharMatchIRQ(); + } +} + +#if UARTSEL == BLUETOOTHUART +/** +* This function overrides a function from the stdio library, effectively redirecting +* output to the UART port. This means that printf can print directly to the UART. +*/ +int __io_putchar(int ch){ + HAL_UART_Transmit(&huart2, (uint8_t *) &ch, 1, UART_POLL_TIMEOUT); + return ch; +} + +/** +* This function overrides a function from the stdio library, effectively redirecting +* input from the UART port. This means that scanf can read directly from the UART. +*/ +int __io_getchar(void){ + uint8_t ch = 0; + + /* Clear the Overrun flag just before receiving the first character */ + __HAL_UART_CLEAR_OREFLAG(&huart2); + + /* Wait for reception of a character on the USART RX line and echo this + * character on console */ + HAL_UART_Receive(&huart2, (uint8_t *)&ch, 1, HAL_MAX_DELAY); + HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, HAL_MAX_DELAY); + return ch; +} +#endif \ No newline at end of file diff --git a/YEEP144lib/src/YEEP144_Buzzer.c b/YEEP144lib/src/YEEP144_Buzzer.c new file mode 100644 index 0000000..48fd356 --- /dev/null +++ b/YEEP144lib/src/YEEP144_Buzzer.c @@ -0,0 +1,135 @@ +#include "YEEP144.h" +#include "YEEP144_Pinout.h" +#include "YEEP144_Buzzer.h" +#include "stm32h5xx_hal.h" +#include "stm32h5xx_hal_gpio.h" +#include "stm32h5xx_hal_gpio_ex.h" +#include "stm32h5xx_hal_tim.h" + +#include +#include + +TIM_HandleTypeDef htim17buzzer; + +/** + * Initialises the buzzer. This consumes timer 17 and 1 GPIO. This resource is shared with servo 4 - only 1 should be initialised + * Ensure DIP switch SW5 is correctly set to enable the buzzer output. Set both to off when using servo 4 to avoid hearing + * the servo PWM signal through the buzzer + */ +void YEEP144_Buzzer_Init(void){ + // Initialise TIM17 + + // Create structures to store our timer configuration information + TIM_OC_InitTypeDef sConfigOC = {0}; + TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; + + // Enable the clock input to TIM3 + __HAL_RCC_TIM17_CLK_ENABLE(); + + // Setup our configuration data + // Prescaler is set so that 1 timer tick = 1us for 250MHz input clock, as the frequency calculation assumes this + htim17buzzer.Instance = TIM17; + htim17buzzer.Init.Prescaler = 249; + htim17buzzer.Init.CounterMode = TIM_COUNTERMODE_UP; + htim17buzzer.Init.Period = 65535; + htim17buzzer.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim17buzzer.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; + + // Initialise the timer + if (HAL_TIM_PWM_Init(&htim17buzzer) != HAL_OK){ + //Error_Handler(); + } + + // Configure the Output Compare (OC) settings + // This determines how the PWM signal is generated based on the count of our timer + sConfigOC.OCMode = TIM_OCMODE_PWM1; // Edge-Aligned mode + sConfigOC.Pulse = 0; // Default CCR value for our duty cycle + sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; // Non-inverted polarity + sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; + sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; + sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; + sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; + + // Configure the PWM channels + if (HAL_TIM_PWM_ConfigChannel(&htim17buzzer, &sConfigOC, TIM_CHANNEL_1) != HAL_OK){ + //Error_Handler(); + } + + // Disable the break dead time feature as its not needed + sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; + sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; + sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF; + sBreakDeadTimeConfig.DeadTime = 0; + sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE; + sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; + sBreakDeadTimeConfig.BreakFilter = 0; + sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; + if (HAL_TIMEx_ConfigBreakDeadTime(&htim17buzzer, &sBreakDeadTimeConfig) != HAL_OK){ + //Error_Handler(); + } + + // Setup the GPIO output from the timer + YEEP144_GPIO_InitAdv(BUZZER_PORT, BUZZER_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW, GPIO_AF1_TIM17); + + // Start PWM generation + HAL_TIM_PWM_Start(&htim17buzzer, TIM_CHANNEL_1); + + // Default to no tone + YEEP144_Buzzer_NoTone(); +} + +/** + * Sound the buzzer at the chosen frequency (Hz) for the alloted duration (ms) + * This is blocking as it uses HAL_Delay to wait the alloted time + */ +void YEEP144_Buzzer_Tone(uint32_t freq, uint32_t duration){ + YEEP144_Buzzer_GoTone(freq); // Start playing the tone + HAL_Delay(duration); // Wait for tone duration + YEEP144_Buzzer_NoTone(); // Cease playing the tone +} + +/** + * Sound the buzzer at the chosen frequency (Hz) continuously until stopped by NoTone + * This is non-blocking, so you can go do other things while the tone is playing + */ +void YEEP144_Buzzer_GoTone(uint32_t freq){ + if(freq != 0){ + TIM17->ARR = (1000000UL / freq) - 1; // Set PWM frequency + TIM17->CCR1 = (TIM17->ARR >> 1); // Set the duty cycle to 50% by setting Capture Compare Register to half the frequency + } +} + +/** + * Stops the buzzer from sounding by setting the duty cycle to 0% + */ +void YEEP144_Buzzer_NoTone(void){ + TIM17->CCR1 = 0; // Set duty cycle to 0% +} + + +/** + * Buzzer rendition of Daisy Bell taken from: + * https://github.com/ayoungblood/daisy-bell/blob/master/arduino/daisy_basic/daisy_basic.ino + */ +#define A440 440 // frequency constant +#define QUARTER 180 // quarter note length in ms + +const uint8_t DAISY_P[] = { + 74, 71, 67, 62, 64, 66, 67, 64, 67, 62, + 69, 74, 71, 67, 64, 66, 67, 69, 71, 69, + 71, 72, 71, 69, 74, 71, 69, 67, 69, 71, 67, 64, 67, 64, 62, + 62, 67, 71, 69, 67, 71, 69, 71, 72, 74, 71, 67, 69, 62, 67 +}; +const uint8_t DAISY_T[] = { + 3, 3, 3, 3, 1, 1, 1, 2, 1, 6, + 3, 3, 3, 3, 1, 1, 1, 2, 1, 6, + 1, 1, 1, 1, 2, 1, 1, 4, 1, 2, 1, 2, 1, 1, 5, + 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 5 +}; + +void YEEP144_Buzzer_Daisy(void){ + for(int i=0; i<50; ++i){ + float freq = pow(2,(DAISY_P[i]-69)/12.0f)*A440; + YEEP144_Buzzer_Tone((uint32_t)freq, DAISY_T[i]*QUARTER); + } +} \ No newline at end of file diff --git a/YEEP144lib/src/YEEP144_DCMotor.c b/YEEP144lib/src/YEEP144_DCMotor.c new file mode 100644 index 0000000..3e2496e --- /dev/null +++ b/YEEP144lib/src/YEEP144_DCMotor.c @@ -0,0 +1,386 @@ +// YEEP Includes +#include "YEEP144.h" +#include "YEEP144_DCMotor.h" +#include "YEEP144_Pinout.h" + +// HAL Includes +#include "stm32h5xx_hal.h" +#include "stm32h5xx_hal_gpio_ex.h" +#include "stm32h5xx_hal_rcc.h" +#include "stm32h5xx_hal_tim.h" +#include "stm32h5xx_hal_lptim.h" +#include "stm32h5xx_hal_gpio.h" + +// System Includes +#include + +// Structs for timer handles +// TIM3 used for all 4 DC motors +TIM_HandleTypeDef htim3; + +// TIM3, LPTIM2, LPTIM3, LPTIM5 used for encoders +TIM_HandleTypeDef htim4; +LPTIM_HandleTypeDef hlptim2; +LPTIM_HandleTypeDef hlptim3; +LPTIM_HandleTypeDef hlptim5; + +/** +* Sets the specified motors speed by altering the duty cycle of the PWM signal +* This is done by setting the Capture and Compare Register for the relevant channel +* to a value between 0 and the Period of the timer where CCR = 0 is 0% duty cycle and +* CCR = Period is 100% duty cycle +*/ +void YEEP144_DCMotor_SetSpeed(uint8_t motor, uint16_t speed){ + // Cap speed if out of bounds + if(speed > DCMOTOR_MAX_SPEED){ + speed = DCMOTOR_MAX_SPEED; + } + + // Update the Capture Compare Register (CCR) for the relevant motor channel + switch(motor){ + case DCMOTOR1: + TIM3->CCR1 = speed; + break; + case DCMOTOR2: + TIM3->CCR2 = speed; + break; + case DCMOTOR3: + TIM3->CCR3 = speed; + break; + case DCMOTOR4: + TIM3->CCR4 = speed; + break; + } +} + +/** +* Sets the two direction bits for the specified motor. There are 4 valid options +* for stopping, counter-clockwise movement, clockwise movement, and a short +* brake. There are #defines available for these states in YEEP144_DCMotor.h +*/ +void YEEP144_DCMotor_SetDirection(uint8_t motor, uint8_t direction){ + // Check that the inputs are valid + if(direction > 3 || motor > 4){ + return; + } + + // Set the direction GPIO pins + // Some bit manipulation is used to mask the relevant bit and shift it into the LSB position + if(motor == DCMOTOR1){ + HAL_GPIO_WritePin(MOT1A_PORT, MOT1A_PIN, (direction>>1) & 1); + HAL_GPIO_WritePin(MOT1B_PORT, MOT1B_PIN, direction & 1); + } + else if (motor == DCMOTOR2) { + HAL_GPIO_WritePin(MOT2A_PORT, MOT2A_PIN, (direction>>1) & 1); + HAL_GPIO_WritePin(MOT2B_PORT, MOT2B_PIN, direction & 1); + } + else if (motor == DCMOTOR3) { + HAL_GPIO_WritePin(MOT3A_PORT, MOT3A_PIN, (direction>>1) & 1); + HAL_GPIO_WritePin(MOT3B_PORT, MOT3B_PIN, direction & 1); + } + else if (motor == DCMOTOR4) { + HAL_GPIO_WritePin(MOT4A_PORT, MOT4A_PIN, (direction>>1) & 1); + HAL_GPIO_WritePin(MOT4B_PORT, MOT4B_PIN, direction & 1); + } +} + +/** +* Gets the current value of encoder 1 +*/ +uint16_t YEEP144_Encoder1_Get(void){ + return TIM4->CNT; +} + +/** +* Gets the current value of encoder 2 +*/ +uint16_t YEEP144_Encoder2_Get(void){ + return LPTIM3->CNT; +} + +/** +* Gets the current value of encoder 3 +*/ +uint16_t YEEP144_Encoder3_Get(void){ + return LPTIM5->CNT; +} + +/** +* Gets the current value of encoder 4 +*/ +uint16_t YEEP144_Encoder4_Get(void){ + return LPTIM2->CNT; +} + +/** +* This function initialises all 4 DC motor driver channels +* They all share TIM3 for their PWM generation +* After initialisation the PWM will be set to 0%, and direction set to STOP +* +* This consumes TIM3 and the 4 GPIO it outputs on, as well as the 8 GPIO used for motor direction control +*/ +void YEEP144_DCMotor_Init(void){ + // Initialise TIM3 + + // Create structures to store our timer configuration information + TIM_MasterConfigTypeDef sMasterConfig = {0}; + TIM_OC_InitTypeDef sConfigOC = {0}; + + // Enable the clock input to TIM3 + __HAL_RCC_TIM3_CLK_ENABLE(); + + // Setup our configuration data + // For an input clock of 250MHz and a Period of 4095 these setting will produce + // a PWM signal of ~61kHz which is within the range accepted by the motor driver + + // 4095 was chosen as the period as it maps 1-to-1 with the reading from a 12-bit ADC + htim3.Instance = TIM3; + htim3.Init.Prescaler = 0; + htim3.Init.CounterMode = TIM_COUNTERMODE_UP; + htim3.Init.Period = DCMOTOR_MAX_SPEED; + htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + + // Initialise the timer + if (HAL_TIM_PWM_Init(&htim3) != HAL_OK){ + //Error_Handler(); + } + + // Configure master output + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK){ + //Error_Handler(); + } + + // Configure the Output Compare (OC) settings + // This determines how the PWM signal is generated based on the count of our timer + sConfigOC.OCMode = TIM_OCMODE_PWM1; // Edge-Aligned mode + sConfigOC.Pulse = 0; // Default CCR value for our duty cycle + sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; // Non-inverted polarity + sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // Fast mode is not required for this application + + // Configure the PWM channels + if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK){ + //Error_Handler(); + } + if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK){ + //Error_Handler(); + } + if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_3) != HAL_OK){ + //Error_Handler(); + } + if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_4) != HAL_OK){ + //Error_Handler(); + } + + // Initialise GPIO pins used for PWM output + // 3 of our PWM pins are on port C and 1 on port B + // We must configure each port separately + + YEEP144_GPIO_InitAdv(MOT1PWM_PORT, MOT1PWM_PIN | MOT2PWM_PIN | MOT4PWM_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW, GPIO_AF2_TIM3); + YEEP144_GPIO_InitAdv(MOT3PWM_PORT, MOT3PWM_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW, GPIO_AF2_TIM3); + + // Initialise GPIO for 2-bit direction control + // The pins used are split across 3 ports + // Each port must be configured separately + + YEEP144_GPIO_Init(MOT1A_PORT, MOT1A_PIN | MOT1B_PIN | MOT2A_PIN | MOT2B_PIN, GPIO_MODE_OUTPUT); + YEEP144_GPIO_Init(MOT3A_PORT, MOT3A_PIN | MOT3B_PIN, GPIO_MODE_OUTPUT); + YEEP144_GPIO_Init(MOT4A_PORT, MOT4A_PIN | MOT4B_PIN, GPIO_MODE_OUTPUT); + + // Set default outputs to stop + YEEP144_DCMotor_SetDirection(DCMOTOR1, DCMOTOR_STOP); + YEEP144_DCMotor_SetDirection(DCMOTOR2, DCMOTOR_STOP); + YEEP144_DCMotor_SetDirection(DCMOTOR3, DCMOTOR_STOP); + YEEP144_DCMotor_SetDirection(DCMOTOR4, DCMOTOR_STOP); + + // Start all the PWM channels + HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1); + HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2); + HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3); + HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4); + +} + +/** +* This initialises Encoder 1 +* This consumes TIM4 and the two GPIO it takes input from +*/ +void YEEP144_Encoder1_Init(void){ + // Initialise TIM4 + + // Enable TIM4 clock + __HAL_RCC_TIM4_CLK_ENABLE(); + + // Create structs to hold config data + TIM_Encoder_InitTypeDef sConfig = {0}; + TIM_MasterConfigTypeDef sMasterConfig = {0}; + + htim4.Instance = TIM4; + htim4.Init.Prescaler = 0; + htim4.Init.CounterMode = TIM_COUNTERMODE_UP; + htim4.Init.Period = 65535; + htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + + // Configure encoder mode and input channels + sConfig.EncoderMode = TIM_ENCODERMODE_TI1; + sConfig.IC1Polarity = TIM_ICPOLARITY_RISING; + sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI; + sConfig.IC1Prescaler = TIM_ICPSC_DIV1; + sConfig.IC1Filter = 0; + sConfig.IC2Polarity = TIM_ICPOLARITY_RISING; + sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI; + sConfig.IC2Prescaler = TIM_ICPSC_DIV1; + sConfig.IC2Filter = 0; + + // Initialise the timer + if (HAL_TIM_Encoder_Init(&htim4, &sConfig) != HAL_OK){ + //Error_Handler(); + } + + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK){ + //Error_Handler(); + } + + // Initialise the GPIO used for the encoder input + YEEP144_GPIO_InitAdv(ENC1A_PORT, ENC1A_PIN | ENC1B_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW, GPIO_AF2_TIM4); + + // Start the encoder counting + HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_ALL); + +} + +/** +* This initialises Encoder 2 +* This consumes LPTIM3 and the two GPIO it takes input from +*/ +void YEEP144_Encoder2_Init(void){ + + // Setup clock for LPTIM3 + + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; + + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LPTIM3; + PeriphClkInitStruct.Lptim3ClockSelection = RCC_LPTIM3CLKSOURCE_PCLK3; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK){ + //Error_Handler(); + } + + // Enable clock for LPTIM3 + __HAL_RCC_LPTIM3_CLK_ENABLE(); + + // Configure LPTIM3 for encoder input mode + hlptim3.Instance = LPTIM3; + hlptim3.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC; + hlptim3.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV1; + hlptim3.Init.UltraLowPowerClock.Polarity = LPTIM_CLOCKPOLARITY_RISING; + hlptim3.Init.UltraLowPowerClock.SampleTime = LPTIM_CLOCKSAMPLETIME_DIRECTTRANSITION; + hlptim3.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE; + hlptim3.Init.Period = 65535; + hlptim3.Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE; + hlptim3.Init.CounterSource = LPTIM_COUNTERSOURCE_EXTERNAL; + hlptim3.Init.Input1Source = LPTIM_INPUT1SOURCE_GPIO; + hlptim3.Init.Input2Source = LPTIM_INPUT2SOURCE_GPIO; + hlptim3.Init.RepetitionCounter = 0; + if (HAL_LPTIM_Init(&hlptim3) != HAL_OK){ + //Error_Handler(); + } + + // Initialise the GPIO used for the encoder input + YEEP144_GPIO_InitAdv(ENC2A_PORT, ENC2A_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW, GPIO_AF2_LPTIM3); + YEEP144_GPIO_InitAdv(ENC2B_PORT, ENC2B_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW, GPIO_AF2_LPTIM3); + + // Start the encoder counting + HAL_LPTIM_Encoder_Start(&hlptim3); +} + +/** +* This initialises Encoder 3 +* This consumes LPTIM5 and the two GPIO it takes input from +*/ +void YEEP144_Encoder3_Init(void){ + + // Setup clock for LPTIM5 + + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; + + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LPTIM5; + PeriphClkInitStruct.Lptim3ClockSelection = RCC_LPTIM3CLKSOURCE_PCLK3; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK){ + //Error_Handler(); + } + + // Enable clock for LPTIM3 + __HAL_RCC_LPTIM5_CLK_ENABLE(); + + // Configure LPTIM5 for encoder input mode + hlptim5.Instance = LPTIM5; + hlptim5.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC; + hlptim5.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV1; + hlptim5.Init.UltraLowPowerClock.Polarity = LPTIM_CLOCKPOLARITY_RISING; + hlptim5.Init.UltraLowPowerClock.SampleTime = LPTIM_CLOCKSAMPLETIME_DIRECTTRANSITION; + hlptim5.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE; + hlptim5.Init.Period = 65535; + hlptim5.Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE; + hlptim5.Init.CounterSource = LPTIM_COUNTERSOURCE_EXTERNAL; + hlptim5.Init.Input1Source = LPTIM_INPUT1SOURCE_GPIO; + hlptim5.Init.Input2Source = LPTIM_INPUT2SOURCE_GPIO; + hlptim5.Init.RepetitionCounter = 0; + if (HAL_LPTIM_Init(&hlptim5) != HAL_OK){ + //Error_Handler(); + } + + // Initialise the GPIO used for the encoder input + YEEP144_GPIO_InitAdv(ENC3A_PORT, ENC3A_PIN | ENC3B_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW, GPIO_AF13_LPTIM5); + + // Start the encoder counting + HAL_LPTIM_Encoder_Start(&hlptim5); +} + +/** +* This initialises Encoder 4 +* This consumes LPTIM2 and the two GPIO it takes input from +*/ +void YEEP144_Encoder4_Init(void){ + + // Setup clock for LPTIM2 + + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; + + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LPTIM2; + PeriphClkInitStruct.Lptim3ClockSelection = RCC_LPTIM3CLKSOURCE_PCLK3; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK){ + //Error_Handler(); + } + + // Enable clock for LPTIM2 + __HAL_RCC_LPTIM2_CLK_ENABLE(); + + // Configure LPTIM2 for encoder input mode + hlptim2.Instance = LPTIM2; + hlptim2.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC; + hlptim2.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV1; + hlptim2.Init.UltraLowPowerClock.Polarity = LPTIM_CLOCKPOLARITY_RISING; + hlptim2.Init.UltraLowPowerClock.SampleTime = LPTIM_CLOCKSAMPLETIME_DIRECTTRANSITION; + hlptim2.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE; + hlptim2.Init.Period = 65535; + hlptim2.Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE; + hlptim2.Init.CounterSource = LPTIM_COUNTERSOURCE_EXTERNAL; + hlptim2.Init.Input1Source = LPTIM_INPUT1SOURCE_GPIO; + hlptim2.Init.Input2Source = LPTIM_INPUT2SOURCE_GPIO; + hlptim2.Init.RepetitionCounter = 0; + if (HAL_LPTIM_Init(&hlptim2) != HAL_OK){ + //Error_Handler(); + } + + // Initialise the GPIO used for the encoder input + YEEP144_GPIO_InitAdv(ENC4A_PORT, ENC4A_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW, GPIO_AF3_LPTIM2); + YEEP144_GPIO_InitAdv(ENC4B_PORT, ENC4B_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW, GPIO_AF3_LPTIM2); + + // Start the encoder counting + HAL_LPTIM_Encoder_Start(&hlptim2); +} \ No newline at end of file diff --git a/YEEP144lib/src/YEEP144_DebugUART.c b/YEEP144lib/src/YEEP144_DebugUART.c new file mode 100644 index 0000000..44fa56b --- /dev/null +++ b/YEEP144lib/src/YEEP144_DebugUART.c @@ -0,0 +1,200 @@ +// YEEP144 includes +#include "YEEP144.h" +#include "YEEP144_DebugUART.h" +#include "YEEP144_Pinout.h" + +// HAL includes +#include "stm32h563xx.h" +#include "stm32h5xx_hal.h" +#include "stm32h5xx_hal_uart.h" + +// Std includes +#include +#include +#include +#include + +#define UART_POLL_TIMEOUT 1000 + +// Structure for UART info +UART_HandleTypeDef huart3; + +DMA_HandleTypeDef handle_GPDMA1_Channel1; + +/** +* Initialises USART3 for use as a debug console output via the STLink +* Virtual COM Port (VCP) +* +* This consumes the USART3 peripheral and no YEEP GPIO as it is routed internally +* on the Nucleo board and is not broken out +*/ +void YEEP144_DebugUART_Init(void){ + + // Initialise and start the clock + + // DMA clock and interrupt + __HAL_RCC_GPDMA1_CLK_ENABLE(); + HAL_NVIC_SetPriority(GPDMA1_Channel1_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(GPDMA1_Channel1_IRQn); + + // Structure to hold clock config + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; + + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USART3; // Configuring USART3 + PeriphClkInitStruct.Lptim3ClockSelection = RCC_USART3CLKSOURCE_PCLK1; // Select PCLK1 + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK){ + //Error_Handler(); + } + + // Enable the clock + __HAL_RCC_USART3_CLK_ENABLE(); + + // Populate the UART struct with the configuration data + // 115200 8-N-1 + huart3.Instance = USART3; + huart3.Init.BaudRate = 115200; // 115200 Baud rate + huart3.Init.WordLength = UART_WORDLENGTH_8B; // 8 bit + huart3.Init.Parity = UART_PARITY_NONE; // None parity + huart3.Init.StopBits = UART_STOPBITS_1; // 1 Stop bit + huart3.Init.Mode = UART_MODE_TX_RX; // Full duplex + huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE; // No hardware flow control (RTS, CTS) + huart3.Init.OverSampling = UART_OVERSAMPLING_8; + huart3.Init.ClockPrescaler = UART_PRESCALER_DIV1; + if(HAL_UART_Init(&huart3) != HAL_OK){ + + } + + // Initialise GPIO pins + YEEP144_GPIO_InitAdv(UART3_TX_PORT, UART3_RX_PIN | UART3_TX_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW, GPIO_AF7_USART3); + + + // Enable USART IRQs + HAL_NVIC_SetPriority(USART3_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(USART3_IRQn); + + HAL_UARTEx_DisableFifoMode(&huart3); + + // Populate DMA init structure + handle_GPDMA1_Channel1.Instance = GPDMA1_Channel1; + handle_GPDMA1_Channel1.Init.Request = GPDMA1_REQUEST_USART3_RX; + handle_GPDMA1_Channel1.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST; + handle_GPDMA1_Channel1.Init.Direction = DMA_PERIPH_TO_MEMORY; + handle_GPDMA1_Channel1.Init.SrcInc = DMA_SINC_FIXED; + handle_GPDMA1_Channel1.Init.DestInc = DMA_DINC_INCREMENTED; + handle_GPDMA1_Channel1.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE; + handle_GPDMA1_Channel1.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE; + handle_GPDMA1_Channel1.Init.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT; + handle_GPDMA1_Channel1.Init.SrcBurstLength = 1; + handle_GPDMA1_Channel1.Init.DestBurstLength = 1; + handle_GPDMA1_Channel1.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0; + handle_GPDMA1_Channel1.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER; + handle_GPDMA1_Channel1.Init.Mode = DMA_NORMAL; + if (HAL_DMA_Init(&handle_GPDMA1_Channel1) != HAL_OK) + { + //Error_Handler(); + } + + __HAL_LINKDMA(&huart3, hdmarx, handle_GPDMA1_Channel1); + + if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel1, DMA_CHANNEL_NPRIV) != HAL_OK) + { + //Error_Handler(); + } + + // Set default character match to carriage return + YEEP144_DebugUART_SetCharMatch('\r'); + + // Disable buffering on stdin. This prevents problems when using scanf with the UART redirection + setvbuf(stdin, NULL, _IONBF, 0); +} + +/** + * Prints to the Debug UART, regardless of what the default UART is set to. + * Arguments and returns are the same as the default printf + * + * Internally this doesn't work using a stream like default printf, but uses a buffer, so the command may + * fail if the buffer cannot be allocated, or the output may be truncated if expanding the format specifiers causes + * the string to expand by more than 256 bytes + */ +int YEEP144_DebugUART_printf(const char * format, ...){ + // Calculate how long the input string is, plus extra space for substitition in the format specifiers + size_t bufSize = strlen(format) + 256; + + // Try to allocate that buffer + char* buffer = malloc(bufSize); + + // If the buffer cannot be allocated, return -1 + if (buffer == NULL) return -1; + + // Get the pointer to the variadic args + va_list args; + va_start (args, format); + + // Create our final string in the buffer using vsnprintf, passing through our argument pointer + vsnprintf(buffer, bufSize, format, args); + + // Calulate the final size of the string + bufSize = strlen(buffer); + + // Transmit over UART + HAL_UART_Transmit(&huart3, (uint8_t*)buffer, bufSize, UART_POLL_TIMEOUT); + + // Free the memory used + free(buffer); + + // Return number of characters printed + return bufSize; +} + +/** + * Enables the character match IRQ. When the configured character received an interrupt is fired. + * The current transfer will be terminated and the YEEP144_DebugUART_MatchCallback will be called + */ +void YEEP144_DebugUART_EnableCharMatchIRQ(void){ + __HAL_UART_ENABLE_IT(&huart3, UART_IT_CM); +} + +/** + * Disables the character match IRQ + */ +void YEEP144_DebugUART_DisableCharMatchIRQ(void){ + __HAL_UART_DISABLE_IT(&huart3, UART_IT_CM); +} + +/** + * Set the character match IRQ character. When the configured character received an interrupt is fired. + * The current transfer will be terminated and the YEEP144_DebugUART_MatchCallback will be called + */ +void YEEP144_DebugUART_SetCharMatch(char match){ + __HAL_UART_DISABLE(&huart3); + MODIFY_REG(huart3.Instance->CR2, USART_CR2_ADD_Msk, match<< USART_CR2_ADD_Pos); + __HAL_UART_ENABLE(&huart3); +} + +#if UARTSEL == DEBUG +/** +* This function overrides a function from the stdio library, effectively redirecting +* output to the UART port. This means that printf can print directly to the UART. +*/ +int __io_putchar(int ch){ + HAL_UART_Transmit(&huart3, (uint8_t *) &ch, 1, UART_POLL_TIMEOUT); + return ch; +} + +/** +* This function overrides a function from the stdio library, effectively redirecting +* input from the UART port. This means that scanf can read directly from the UART. +*/ +int __io_getchar(void){ + uint8_t ch = 0; + + /* Clear the Overrun flag just before receiving the first character */ + __HAL_UART_CLEAR_OREFLAG(&huart3); + + /* Wait for reception of a character on the USART RX line and echo this + * character on console */ + HAL_UART_Receive(&huart3, (uint8_t *)&ch, 1, HAL_MAX_DELAY); + HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, HAL_MAX_DELAY); + return ch; +} +#endif \ No newline at end of file diff --git a/YEEP144lib/src/YEEP144_GP2Y0E02B.c b/YEEP144lib/src/YEEP144_GP2Y0E02B.c new file mode 100644 index 0000000..f987172 --- /dev/null +++ b/YEEP144lib/src/YEEP144_GP2Y0E02B.c @@ -0,0 +1,18 @@ +#include "YEEP144_GP2Y0E02B.h" +#include "YEEP144_I2C.h" +#include "stm32h5xx_hal_i2c.h" + +#include + +#define I2C_TIMEOUT 1000 + +float YEEP144_GP2Y0E02B_Read(void){ + uint8_t IRShift; + uint8_t IRValues[2] ={0}; + + HAL_I2C_Mem_Read(&hi2c2, GP2Y0E02B_I2C_ADDR, GP2Y0E02B_SHIFT_REG_ADDR, I2C_MEMADD_SIZE_8BIT, &IRShift, 1, I2C_TIMEOUT); + HAL_I2C_Mem_Read(&hi2c2, GP2Y0E02B_I2C_ADDR, GP2Y0E02B_DISTANCE_REG_ADDR, I2C_MEMADD_SIZE_8BIT, IRValues, 2, I2C_TIMEOUT); + + return ((IRValues[0]*16.0) + IRValues[1])/ 16.0 / pow(2.0, IRShift); + +} \ No newline at end of file diff --git a/YEEP144lib/src/YEEP144_HCSR04.c b/YEEP144lib/src/YEEP144_HCSR04.c new file mode 100644 index 0000000..235a358 --- /dev/null +++ b/YEEP144lib/src/YEEP144_HCSR04.c @@ -0,0 +1,596 @@ +#include "YEEP144_HCSR04.h" +#include "YEEP144.h" +#include "YEEP144_Pinout.h" +#include "stm32h5xx_hal.h" +#include "stm32h5xx_hal_cortex.h" +#include "stm32h5xx_hal_exti.h" +#include "stm32h5xx_hal_gpio.h" +#include "stm32h5xx_hal_tim.h" + +#include + +#define USONIC_PING_LEN 10 +#define BLOCKING_TIMEOUT_TICKS 1000 + +#define USONIC1_MASK (1 << 0) +#define USONIC2_MASK (1 << 1) +#define USONIC3_MASK (1 << 2) +#define USONIC4_MASK (1 << 3) + +uint8_t ultrasonicInit = 0; +uint8_t ultrasonicTIMInit = 0; + +uint8_t ultrasonicNextPing = USONIC1_MASK; +uint8_t ultrasonicPing = 0; +uint8_t ultrasonicEcho = 0; + +uint16_t ultrasonicTickStart[4]; +uint16_t ultrasonicTickLen[4]; + +TIM_HandleTypeDef htim6; + +EXTI_HandleTypeDef hexti12; +EXTI_ConfigTypeDef hexti12_conf; + +void YEEP144_Ultrasonic_TIMInit(void); + +void YEEP144_Ultrasonic1_Callback(uint16_t ticks); +void YEEP144_Ultrasonic2_Callback(uint16_t ticks); +void YEEP144_Ultrasonic3_Callback(uint16_t ticks); +void YEEP144_Ultrasonic4_Callback(uint16_t ticks); + + +/** + * Initialises ultrasonic sensor 1. This consumes the two GPIO assigned to that sensor, + * TIM6 (shared by all 4 ultrasonics), and EXTI line 10 (share by the first 3 ultrasonics) + */ +void YEEP144_Ultrasonic1_Init(void){ + YEEP144_GPIO_Init(USONIC1_TRIG_PORT, USONIC1_TRIG_PIN, GPIO_MODE_OUTPUT); + HAL_NVIC_SetPriority(USONIC1_ECHO_EXTI, 1, 0); + HAL_NVIC_EnableIRQ(USONIC1_ECHO_EXTI); + ultrasonicInit |= USONIC1_MASK; + + // Only initialise the timer if it hasn't already + if(ultrasonicTIMInit == 0){ + YEEP144_Ultrasonic_TIMInit(); + } +} + +/** + * Initialises ultrasonic sensor 2. This consumes the two GPIO assigned to that sensor, + * TIM6 (shared by all 4 ultrasonics), and EXTI line 10 (share by the first 3 ultrasonics) + */ +void YEEP144_Ultrasonic2_Init(void){ + YEEP144_GPIO_Init(USONIC2_TRIG_PORT, USONIC2_TRIG_PIN, GPIO_MODE_OUTPUT); + HAL_NVIC_SetPriority(USONIC2_ECHO_EXTI, 1, 0); + HAL_NVIC_EnableIRQ(USONIC2_ECHO_EXTI); + ultrasonicInit |= USONIC2_MASK; + + // Only initialise the timer if it hasn't already + if(ultrasonicTIMInit == 0){ + YEEP144_Ultrasonic_TIMInit(); + } +} + +/** + * Initialises ultrasonic sensor 3. This consumes the two GPIO assigned to that sensor, + * TIM6 (shared by all 4 ultrasonics), and EXTI line 10 (share by the first 3 ultrasonics) + */ +void YEEP144_Ultrasonic3_Init(void){ + YEEP144_GPIO_Init(USONIC3_TRIG_PORT, USONIC3_TRIG_PIN, GPIO_MODE_OUTPUT); + HAL_NVIC_SetPriority(USONIC3_ECHO_EXTI, 1, 0); + HAL_NVIC_EnableIRQ(USONIC4_ECHO_EXTI); + ultrasonicInit |= USONIC3_MASK; + + // Only initialise the timer if it hasn't already + if(ultrasonicTIMInit == 0){ + YEEP144_Ultrasonic_TIMInit(); + } +} + +/** + * Initialises ultrasonic sensor 4. This consumes the two GPIO assigned to that sensor, + * TIM6 (shared by all 4 ultrasonics), and EXTI line 12 (shared with button 3 / red) + */ +void YEEP144_Ultrasonic4_Init(void){ + YEEP144_GPIO_Init(USONIC4_TRIG_PORT, USONIC4_TRIG_PIN, GPIO_MODE_OUTPUT); + HAL_NVIC_SetPriority(USONIC4_ECHO_EXTI, 1, 0); + HAL_NVIC_EnableIRQ(USONIC4_ECHO_EXTI); + ultrasonicInit |= USONIC4_MASK; + + // Only initialise the timer if it hasn't already + if(ultrasonicTIMInit == 0){ + YEEP144_Ultrasonic_TIMInit(); + } +} + +/** + * Starts a reading on the next sensor in the sequence using the non-blocking method, skipping over any uninitialised sensors + * Only 1 sensor can be read at a time as they (mostly) share the same EXTI line, so this function + * checks to make sure that noting else is currently pinging. + * + * If no sensor is currently initialised returns 255 + * If a sensor is already pinging, return 0 + * If a new reading is successfully started, return the status byte indicating which sensor is currently pinging + * + * The relevant callback function will be called when pinging finishes and a new distance value is available + */ +uint8_t YEEP144_Ultrasonic_PingNext(void){ + + // If nothing is currently pinging + if(!ultrasonicPing){ + // What is the next in the sequence + switch(ultrasonicNextPing){ + case USONIC1_MASK: + // Only start if it is enabled + if(ultrasonicInit&USONIC1_MASK){ + // Reinitialise the pin to setup the interrupt + YEEP144_GPIO_Init(USONIC1_ECHO_PORT, USONIC1_ECHO_PIN, GPIO_MODE_IT_RISING_FALLING); + + // Toggle the pin on for 10uS + HAL_GPIO_WritePin(USONIC1_TRIG_PORT, USONIC1_TRIG_PIN, GPIO_PIN_SET); + delayUS(USONIC_PING_LEN); + HAL_GPIO_WritePin(USONIC1_TRIG_PORT, USONIC1_TRIG_PIN, GPIO_PIN_RESET); + + // Set the ping bit so we know this sensor is pinging + ultrasonicPing |= USONIC1_MASK; + + // Move to next sensor + ultrasonicNextPing = USONIC2_MASK; + break; // Break is within the if statement, so if a sensor is not initialised it will fall through to the next + } + else{ + // Move to next sensor + ultrasonicNextPing = USONIC2_MASK; + } + // fallthrough + case USONIC2_MASK: + if(ultrasonicInit&USONIC2_MASK){ + // Reinitialise the pin to setup the interrupt + YEEP144_GPIO_Init(USONIC2_ECHO_PORT, USONIC2_ECHO_PIN, GPIO_MODE_IT_RISING_FALLING); + + // Toggle the pin on for 10uS + HAL_GPIO_WritePin(USONIC2_TRIG_PORT, USONIC2_TRIG_PIN, GPIO_PIN_SET); + delayUS(USONIC_PING_LEN); + HAL_GPIO_WritePin(USONIC2_TRIG_PORT, USONIC2_TRIG_PIN, GPIO_PIN_RESET); + + // Set the ping bit so we know this sensor is pinging + ultrasonicPing |= USONIC2_MASK; + + // Move to next sensor + ultrasonicNextPing = USONIC3_MASK; + break; // Break is within the if statement, so if a sensor is not initialised it will fall through to the next + } + else{ + // Move to next sensor + ultrasonicNextPing = USONIC3_MASK; + } + // fallthrough + case USONIC3_MASK: + if(ultrasonicInit&USONIC3_MASK){ + // Reinitialise the pin to setup the interrupt + YEEP144_GPIO_Init(USONIC3_ECHO_PORT, USONIC3_ECHO_PIN, GPIO_MODE_IT_RISING_FALLING); + + // Toggle the pin on for 10uS + HAL_GPIO_WritePin(USONIC3_TRIG_PORT, USONIC3_TRIG_PIN, GPIO_PIN_SET); + delayUS(USONIC_PING_LEN); + HAL_GPIO_WritePin(USONIC3_TRIG_PORT, USONIC3_TRIG_PIN, GPIO_PIN_RESET); + + // Set the ping bit so we know this sensor is pinging + ultrasonicPing |= USONIC3_MASK; + + // Move to next sensor + ultrasonicNextPing = USONIC4_MASK; + break; // Break is within the if statement, so if a sensor is not initialised it will fall through to the next + } + else{ + // Move to next sensor + ultrasonicNextPing = USONIC4_MASK; + } + // fallthrough + case USONIC4_MASK: + if(ultrasonicInit&USONIC4_MASK){ + // As the interrupt line for ultrasonic 4 is shared with pushbutton 3, + // we want to save the EXTI configuration to restore when pinging is finished + HAL_EXTI_GetHandle(&hexti12, EXTI_LINE_12); + HAL_EXTI_GetConfigLine(&hexti12, &hexti12_conf); + + // Reinitialise the pin to setup the interrupt + YEEP144_GPIO_Init(USONIC4_ECHO_PORT, USONIC4_ECHO_PIN, GPIO_MODE_IT_RISING_FALLING); + + // Toggle the pin on for 10uS + HAL_GPIO_WritePin(USONIC4_TRIG_PORT, USONIC4_TRIG_PIN, GPIO_PIN_SET); + delayUS(USONIC_PING_LEN); + HAL_GPIO_WritePin(USONIC4_TRIG_PORT, USONIC4_TRIG_PIN, GPIO_PIN_RESET); + + // Set the ping bit so we know this sensor is pinging + ultrasonicPing |= USONIC4_MASK; + + // Move to next sensor + ultrasonicNextPing = USONIC1_MASK; + break; // Break is within the if statement, so if a sensor is not initialised it will fall through to the next + } + else{ + // Move to next sensor + ultrasonicNextPing = USONIC1_MASK; + } + + } + // If a ping was successfully started return the status byte, else return 255 + if(!ultrasonicPing){ + return ultrasonicPing; + } + else{ + // This should only happen if this function is called with no sensor initialised + return 255; + } + } + else{ + // Returns 0 if a sensor is already pinging + return 0; + } +} + +/** + * Starts a reading on ultrasonic 1 using the non-blocking method + * + * If no sensor is currently initialised returns 255 + * If a sensor is already pinging, return 0 + * If a new reading is successfully started, return the status byte indicating which sensor is currently pinging + * + * YEEP144_Ultrasonic1_Callback will be called when a new value is available + */ +uint8_t YEEP144_Ultrasonic1_Ping(void){ + ultrasonicNextPing = USONIC1_MASK; + return YEEP144_Ultrasonic_PingNext(); +} + +/** + * Starts a reading on ultrasonic 2 using the non-blocking method + * + * If no sensor is currently initialised returns 255 + * If a sensor is already pinging, return 0 + * If a new reading is successfully started, return the status byte indicating which sensor is currently pinging + * + * YEEP144_Ultrasonic2_Callback will be called when a new value is available + */ +uint8_t YEEP144_Ultrasonic2_Ping(void){ + ultrasonicNextPing = USONIC2_MASK; + return YEEP144_Ultrasonic_PingNext(); +} + +/** + * Starts a reading on ultrasonic 3 using the non-blocking method + * + * If no sensor is currently initialised returns 255 + * If a sensor is already pinging, return 0 + * If a new reading is successfully started, return the status byte indicating which sensor is currently pinging + * + * YEEP144_Ultrasonic3_Callback will be called when a new value is available + */ +uint8_t YEEP144_Ultrasonic3_Ping(void){ + ultrasonicNextPing = USONIC3_MASK; + return YEEP144_Ultrasonic_PingNext(); +} + +/** + * Starts a reading on ultrasonic 4 using the non-blocking method + * + * If no sensor is currently initialised returns 255 + * If a sensor is already pinging, return 0 + * If a new reading is successfully started, return the status byte indicating which sensor is currently pinging + * + * YEEP144_Ultrasonic4_Callback will be called when a new value is available + */ +uint8_t YEEP144_Ultrasonic4_Ping(void){ + ultrasonicNextPing = USONIC4_MASK; + return YEEP144_Ultrasonic_PingNext(); +} + +/** + * Starts a reading on ultrasonic 1 with blocking waits until the new value is available + * + * Returns 0 if the sensor is not initialised, or the function times out, otherwise returns the tick value + * + * YEEP144_Ultrasonic1_Callback will still be called when the new value is available + * + */ +uint16_t YEEP144_Ultrasonic1_PingBlocking(void){ + + uint32_t blockingTimeoutStart = HAL_GetTick(); + + uint8_t pingReturn; + // Attempt pings until successful + // If 255 is returned, sensor is uninitialised, so fail and return 0 + // If we exceed timeout then return 0; + do{ + pingReturn = YEEP144_Ultrasonic1_Ping(); + if(pingReturn == 255) return 0; + if((HAL_GetTick()- blockingTimeoutStart) >= BLOCKING_TIMEOUT_TICKS) return 0; + } while(pingReturn != USONIC1_MASK); + + // Wait until pinging starts + // If we exceed timeout then return 0 + while(ultrasonicPing != USONIC1_MASK){ + if((HAL_GetTick()- blockingTimeoutStart) >= BLOCKING_TIMEOUT_TICKS) return 0; + } + + // Wait until pinging ends + // If we exceed timeout then return 0 + while(ultrasonicPing == USONIC1_MASK){ + if((HAL_GetTick()- blockingTimeoutStart) >= BLOCKING_TIMEOUT_TICKS) return 0; + } + + // Return the read value + return ultrasonicTickLen[0]; +} + +/** + * Starts a reading on ultrasonic 2 with blocking waits until the new value is available + * + * Returns 0 if the sensor is not initialised, or the function times out, otherwise returns the tick value + * + * YEEP144_Ultrasonic1_Callback will still be called when the new value is available + * + */ +uint16_t YEEP144_Ultrasonic2_PingBlocking(void){ + + uint32_t blockingTimeoutStart = HAL_GetTick(); + + uint8_t pingReturn; + // Attempt pings until successful + // If 255 is returned, sensor is uninitialised, so fail and return 0 + // If we exceed timeout then return 0; + do{ + pingReturn = YEEP144_Ultrasonic2_Ping(); + if(pingReturn == 255) return 0; + if((HAL_GetTick()- blockingTimeoutStart) >= BLOCKING_TIMEOUT_TICKS) return 0; + } while(pingReturn != USONIC2_MASK); + + // Wait until pinging starts + // If we exceed timeout then return 0 + while(ultrasonicPing != USONIC2_MASK){ + if((HAL_GetTick()- blockingTimeoutStart) >= BLOCKING_TIMEOUT_TICKS) return 0; + } + + // Wait until pinging ends + // If we exceed timeout then return 0 + while(ultrasonicPing == USONIC2_MASK){ + if((HAL_GetTick()- blockingTimeoutStart) >= BLOCKING_TIMEOUT_TICKS) return 0; + } + + // Return the read value + return ultrasonicTickLen[1]; +} + +/** + * Starts a reading on ultrasonic 3 with blocking waits until the new value is available + * + * Returns 0 if the sensor is not initialised, or the function times out, otherwise returns the tick value + * + * YEEP144_Ultrasonic1_Callback will still be called when the new value is available + * + */ +uint16_t YEEP144_Ultrasonic3_PingBlocking(void){ + + uint32_t blockingTimeoutStart = HAL_GetTick(); + + uint8_t pingReturn; + // Attempt pings until successful + // If 255 is returned, sensor is uninitialised, so fail and return 0 + // If we exceed timeout then return 0; + do{ + pingReturn = YEEP144_Ultrasonic3_Ping(); + if(pingReturn == 255) return 0; + if((HAL_GetTick()- blockingTimeoutStart) >= BLOCKING_TIMEOUT_TICKS) return 0; + } while(pingReturn != USONIC3_MASK); + + // Wait until pinging starts + // If we exceed timeout then return 0 + while(ultrasonicPing != USONIC3_MASK){ + if((HAL_GetTick()- blockingTimeoutStart) >= BLOCKING_TIMEOUT_TICKS) return 0; + } + + // Wait until pinging ends + // If we exceed timeout then return 0 + while(ultrasonicPing == USONIC3_MASK){ + if((HAL_GetTick()- blockingTimeoutStart) >= BLOCKING_TIMEOUT_TICKS) return 0; + } + + // Return the read value + return ultrasonicTickLen[2]; +} + +/** + * Starts a reading on ultrasonic 4 with blocking waits until the new value is available + * + * Returns 0 if the sensor is not initialised, or the function times out, otherwise returns the tick value + * + * YEEP144_Ultrasonic1_Callback will still be called when the new value is available + * + */ +uint16_t YEEP144_Ultrasonic4_PingBlocking(void){ + + uint32_t blockingTimeoutStart = HAL_GetTick(); + + uint8_t pingReturn; + // Attempt pings until successful + // If 255 is returned, sensor is uninitialised, so fail and return 0 + // If we exceed timeout then return 0; + do{ + pingReturn = YEEP144_Ultrasonic4_Ping(); + if(pingReturn == 255) return 0; + if((HAL_GetTick()- blockingTimeoutStart) >= BLOCKING_TIMEOUT_TICKS) return 0; + } while(pingReturn != USONIC4_MASK); + + // Wait until pinging starts + // If we exceed timeout then return 0 + while(ultrasonicPing != USONIC4_MASK){ + if((HAL_GetTick()- blockingTimeoutStart) >= BLOCKING_TIMEOUT_TICKS) return 0; + } + + // Wait until pinging ends + // If we exceed timeout then return 0 + while(ultrasonicPing == USONIC4_MASK){ + if((HAL_GetTick()- blockingTimeoutStart) >= BLOCKING_TIMEOUT_TICKS) return 0; + } + + // Return the read value + return ultrasonicTickLen[3]; +} + +/** +* This function handles the interrupt for sensors 1, 2, and 3 connected to EXTI 10 +* This should be called from the main EXTI10 IRQ handler found in YEEP144_IRQ.c +*/ +void YEEP144_Ultrasonic_EXTI10Handler(void){ + // Store the value from the timer at the start of the ISR to avoid execution time affecting the result + uint16_t TIMVal = __HAL_TIM_GET_COUNTER(&htim6); + + // Rising edge interrupt means pulse is starting + if(__HAL_GPIO_EXTI_GET_RISING_IT(USONIC1_ECHO_PIN)){ + // Check to see which sensor is currently pinging based on the GPIO and the ping status byte + if((HAL_GPIO_ReadPin(USONIC1_ECHO_PORT, USONIC1_ECHO_PIN) == GPIO_PIN_SET) && (ultrasonicPing & USONIC1_MASK)){ + // Store the starting timer value and set the relevant status bit + ultrasonicTickStart[0] = TIMVal; + ultrasonicEcho |= USONIC1_MASK; + } + if((HAL_GPIO_ReadPin(USONIC2_ECHO_PORT, USONIC2_ECHO_PIN) == GPIO_PIN_SET) && (ultrasonicPing & USONIC2_MASK)){ + ultrasonicTickStart[1] = TIMVal; + ultrasonicEcho |= USONIC2_MASK; + } + if((HAL_GPIO_ReadPin(USONIC3_ECHO_PORT, USONIC3_ECHO_PIN) == GPIO_PIN_SET) && (ultrasonicPing & USONIC3_MASK)){ + ultrasonicTickStart[2] = TIMVal; + ultrasonicEcho |= USONIC3_MASK; + } + __HAL_GPIO_EXTI_CLEAR_RISING_IT(USONIC1_ECHO_PIN); // Clear the interrupt + return; + } + // Falling edge interrupt means pulse is ending + else if(__HAL_GPIO_EXTI_GET_FALLING_IT(USONIC1_ECHO_PIN)){ + // Check which sensor is pinging based on the GPIO and status byte + if((HAL_GPIO_ReadPin(USONIC1_ECHO_PORT, USONIC1_ECHO_PIN) == GPIO_PIN_RESET) && (ultrasonicEcho & USONIC1_MASK)){ + // Reset the status bits + ultrasonicPing &= ~USONIC1_MASK; + ultrasonicEcho &= ~USONIC1_MASK; + ultrasonicTickLen[0] = TIMVal - ultrasonicTickStart[0]; // Calculate the time elapsed + YEEP144_Ultrasonic1_Callback(ultrasonicTickLen[0]); // Call the relevant callback function to signal the reading is done + } + if((HAL_GPIO_ReadPin(USONIC2_ECHO_PORT, USONIC2_ECHO_PIN) == GPIO_PIN_RESET) && (ultrasonicEcho & USONIC2_MASK)){ + ultrasonicPing &= ~USONIC2_MASK; + ultrasonicEcho &= ~USONIC2_MASK; + ultrasonicTickLen[1] = TIMVal - ultrasonicTickStart[1]; + YEEP144_Ultrasonic2_Callback(ultrasonicTickLen[1]); + } + if((HAL_GPIO_ReadPin(USONIC3_ECHO_PORT, USONIC3_ECHO_PIN) == GPIO_PIN_RESET) && (ultrasonicEcho & USONIC3_MASK)){ + ultrasonicPing &= ~USONIC3_MASK; + ultrasonicEcho &= ~USONIC3_MASK; + ultrasonicTickLen[2] = TIMVal - ultrasonicTickStart[2]; + YEEP144_Ultrasonic3_Callback(ultrasonicTickLen[2]); + } + __HAL_GPIO_EXTI_CLEAR_FALLING_IT(USONIC1_ECHO_PIN); // Clear the interrupt + return; + } +} + +/** +* This function handles the interrupt for sensor 4 connected to EXTI 12 +* This should be called from the main EXTI12 IRQ handler found in YEEP144_IRQ.c +*/ +void YEEP144_Ultrasonic_EXTI12Handler(void){ + // Store the value from the timer at the start of the ISR to avoid execution time affecting the result + uint16_t TIMVal = __HAL_TIM_GET_COUNTER(&htim6); + + // Rising edge interrupt means pulse is starting + if(__HAL_GPIO_EXTI_GET_RISING_IT(USONIC4_ECHO_PIN)){ + // Check to see which sensor is currently pinging based on the GPIO and the ping status byte + if((HAL_GPIO_ReadPin(USONIC4_ECHO_PORT, USONIC4_ECHO_PIN) == GPIO_PIN_SET) && (ultrasonicPing & USONIC4_MASK)){ + // Store the starting timer value and set the relevant status bit + ultrasonicTickStart[3] = TIMVal; + ultrasonicEcho |= USONIC4_MASK; + } + __HAL_GPIO_EXTI_CLEAR_RISING_IT(USONIC4_ECHO_PIN); // Clear the interrupt + return; + } + // Falling edge interrupt means pulse is ending + else if(__HAL_GPIO_EXTI_GET_FALLING_IT(USONIC4_ECHO_PIN)){ + // Check which sensor is pinging based on the GPIO and status byte + if((HAL_GPIO_ReadPin(USONIC4_ECHO_PORT, USONIC4_ECHO_PIN) == GPIO_PIN_RESET) && (ultrasonicEcho & USONIC4_MASK)){ + // Reset the status bits + ultrasonicPing &= ~USONIC4_MASK; + ultrasonicEcho &= ~USONIC4_MASK; + ultrasonicTickLen[3] = TIMVal - ultrasonicTickStart[3]; // Calculate the time elapsed + YEEP144_Ultrasonic4_Callback(ultrasonicTickLen[3]); // Call the relevant callback function to signal the reading is done + } + __HAL_GPIO_EXTI_CLEAR_FALLING_IT(USONIC4_ECHO_PIN); // Clear the interrupt + // Restore the previous exti configuration + HAL_EXTI_GetHandle(&hexti12, EXTI_LINE_12); + HAL_EXTI_SetConfigLine(&hexti12, &hexti12_conf); + return; + } +} + +/** + * Helper function to convert timer ticks to a centimeter value + */ +float YEEP144_Ultrasonic_TickTocm(uint16_t ticks){ + // Total number of ticks is return trip time, we halve it to get distance to object + // Speed of sound taken as 343m/s = 34300 cm/s = 0.0343 cm/us + return ticks/2.0 * 0.0343; +} + +/** +* Internal function used to initialise the timer used for measuring the received pulses +*/ +void YEEP144_Ultrasonic_TIMInit(void){ + + // Enable the clock to the timer + __HAL_RCC_TIM6_CLK_ENABLE(); + + // Create empty config structure + TIM_MasterConfigTypeDef sMasterConfig = {0}; + + // Populate config structure. The should configure it for 1uS per tick, assuming 250MHz peripheral clock + htim6.Instance = TIM6; + htim6.Init.Prescaler = 249; + htim6.Init.CounterMode = TIM_COUNTERMODE_UP; + htim6.Init.Period = 65535; + htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + if (HAL_TIM_Base_Init(&htim6) != HAL_OK){ + //Error_Handler(); + } + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK){ + //Error_Handler(); + } + + // Start the counting. This counter is left free running as relevant functions + // calculate time elapsed by recording the value at the start and end of an event + HAL_TIM_Base_Start(&htim6); + + // Set the init flag so the timer doesn't get initialised multiple times + ultrasonicTIMInit = 1; +} + + +/** + * These callback functions are weakly defined so they can be overwritten by the user's + * own callback function. They have to exist at least in weak form so that the code compiles + * even if the user chooses not to define their own + */ +__weak void YEEP144_Ultrasonic1_Callback(uint16_t ticks){ + +} + +__weak void YEEP144_Ultrasonic2_Callback(uint16_t ticks){ + +} + +__weak void YEEP144_Ultrasonic3_Callback(uint16_t ticks){ + +} + +__weak void YEEP144_Ultrasonic4_Callback(uint16_t ticks){ + +} \ No newline at end of file diff --git a/YEEP144lib/src/YEEP144_I2C.c b/YEEP144lib/src/YEEP144_I2C.c new file mode 100644 index 0000000..a4f8cd0 --- /dev/null +++ b/YEEP144lib/src/YEEP144_I2C.c @@ -0,0 +1,70 @@ +#include "YEEP144.h" +#include "YEEP144_I2C.h" +#include "YEEP144_Pinout.h" + +#include "stm32h5xx_hal.h" +#include "stm32h5xx_hal_gpio_ex.h" +#include "stm32h5xx_hal_i2c.h" +#include + +I2C_HandleTypeDef hi2c2; + +void YEEP144_I2C_MuxSelect(uint8_t busNumber){ + uint8_t I2CBusSel; + + // If busNumber is greater than 3, deselect all busses + if(busNumber > 3){ + I2CBusSel = 0; + } + else{ // Else convert to 1-hot to activate bus + I2CBusSel = 1 << busNumber; + } + + // Send byte to mux chip to select bus + HAL_I2C_Master_Transmit(&hi2c2, I2C_MUX_ADDR, &I2CBusSel, 1, 1000); +} + +void YEEP144_I2C_Init(void){ + // Initialise and start the clock + + // Structure to hold clock config + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; + + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C2; // Configuring I2C2 + PeriphClkInitStruct.Lptim3ClockSelection = RCC_I2C2CLKSOURCE_PCLK1; // Select PCLK1 + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK){ + //Error_Handler(); + } + + // Enable the clock + __HAL_RCC_I2C2_CLK_ENABLE(); + + // Configure the peripheral + hi2c2.Instance = I2C2; + hi2c2.Init.Timing = 0x60808CD3; // Magic number taken from MX for 100KHz - see Reference Manual RM0481, section 48.4.5 + + // We are not operating as a target, so the rest are just defaults + hi2c2.Init.OwnAddress1 = 0; + hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; + hi2c2.Init.OwnAddress2 = 0; + hi2c2.Init.OwnAddress2Masks = I2C_OA2_NOMASK; + hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; + hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; + if (HAL_I2C_Init(&hi2c2) != HAL_OK){ + //Error_Handler(); + } + + //Configure Analogue filter (Enabled, which is default) + if (HAL_I2CEx_ConfigAnalogFilter(&hi2c2, I2C_ANALOGFILTER_ENABLE) != HAL_OK){ + //Error_Handler(); + } + + //Configure Digital filter (Disabled, which is default) + if (HAL_I2CEx_ConfigDigitalFilter(&hi2c2, 0) != HAL_OK){ + //Error_Handler(); + } + + // Initialise GPIO pins + YEEP144_GPIO_InitAdv(I2C_SDA_PORT, I2C_SDA_PIN | I2C_SCL_PIN, GPIO_MODE_AF_OD, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW, GPIO_AF4_I2C2); +} \ No newline at end of file diff --git a/YEEP144lib/src/YEEP144_IRQ.c b/YEEP144lib/src/YEEP144_IRQ.c new file mode 100644 index 0000000..2502f37 --- /dev/null +++ b/YEEP144lib/src/YEEP144_IRQ.c @@ -0,0 +1,241 @@ +/** + * This file contains all of the IRQ handlers that are required for various parts + * of the HAL and YEEP libraries to function. Unhandled IRQs will cause the system + * to jump to the default handler, trapping it in an infinite loop + */ + +#include "YEEP144_HCSR04.h" +#include "YEEP144_PushButton.h" +#include "YEEP144_PiSPI.h" +#include "stm32h563xx.h" +#include "stm32h5xx_hal.h" +#include "stm32h5xx_hal_dma.h" +#include "stm32h5xx_hal_spi.h" +#include "stm32h5xx_hal_uart.h" + +extern DMA_HandleTypeDef handle_GPDMA1_Channel0; +extern DMA_HandleTypeDef handle_GPDMA1_Channel1; +extern UART_HandleTypeDef huart2; +extern UART_HandleTypeDef huart3; +extern SPI_HandleTypeDef hspi4; + +void YEEP144_BluetoothUART_MatchCallback(void); +void YEEP144_DebugUART_MatchCallback(void); + +/** + * Handler for the SysTick interrupt + * The HAL configures the SysTick to generate an interrupt every 1ms + * HAL_IncTick needs to be called in here for the HAL to function properly + */ +void SysTick_Handler(void){ + HAL_IncTick(); +} + +/** + * Handler for EXTI line 6. In the YEEP libraries this is used by the yellow pushbutton + */ +void EXTI6_IRQHandler(void){ + YEEP144_PushButton_YellowHandler(); +} + +/** + * Handler for EXTI line 7. In the YEEP libraries this is used by the green pushbutton + */ +void EXTI7_IRQHandler(void){ + YEEP144_PushButton_GreenHandler(); +} + +/** + * Handler for EXTI line 10. In the YEEP libraries this is used by ultrasonic sensors 1, 2, and 3 + */ +void EXTI10_IRQHandler(void){ + YEEP144_Ultrasonic_EXTI10Handler(); +} + +/** + * Handler for EXTI line 12. In the YEEP libraries this is used by ultrasonic sensor 4, and pushbutton 3 / red + */ +void EXTI12_IRQHandler(void){ + YEEP144_PushButton_RedHandler(); + YEEP144_Ultrasonic_EXTI12Handler(); +} + +/** + * Handler for EXTI line 14. In the YEEP libraries this is used by the blue pushbutton + */ +void EXTI13_IRQHandler(void){ + YEEP144_PushButton_BlueHandler(); +} + +/** + * Handler for GPDMA1 channel 0. In the YEEP libraries this is used by the BT UART reception + * We just call the relevant HAL handler to let it deal with it + */ +void GPDMA1_CH0_IRQHandler(void){ + HAL_DMA_IRQHandler(&handle_GPDMA1_Channel0); + +} + +/** + * Handler for GPDMA1 channel 0. In the YEEP libraries this is used by the BT UART reception + * We just call the relevant HAL handler to let it deal with it + */ +void GPDMA1_CH1_IRQHandler(void){ + HAL_DMA_IRQHandler(&handle_GPDMA1_Channel1); + +} + +/** + * Handler for SPI4 IRQ. We just call the relevant HAL handler to let it deal with it + */ +void SPI4_IRQHandler(void){ + HAL_SPI_IRQHandler(&hspi4); +} + +void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi){ + if(hspi->Instance == SPI4){ + YEEP144_PiSPI_TxRxHandler(); + } +} + +/** + * Handler for USART2. In the YEEP libraries this is used by the BT UART. + * We do our own checks for the character match interrupt as this is not handled + * by the HAL. For any other interrupt we just let the HAL handle it + */ +void USART2_IRQHandler(void){ + uint32_t isrflags = READ_REG(huart2.Instance->ISR); + uint32_t cr1its = READ_REG(huart2.Instance->CR1); + + // If the character match is enabled and character match flag raised + if (((isrflags & USART_ISR_CMF) != 0U) && ((cr1its & USART_CR1_CMIE) != 0U)){ + __HAL_UART_CLEAR_FLAG(&huart2, UART_CLEAR_CMF); // Clear the character match flag + HAL_DMA_Abort(huart2.hdmarx); // End the current DMA + // Reset the state of the UART HAL + huart2.RxState = HAL_UART_STATE_READY; + huart2.ReceptionType = HAL_UART_RECEPTION_STANDARD; + + // Clear the idle line bit so the reception can be rearmed + ATOMIC_CLEAR_BIT(huart2.Instance->CR1, USART_CR1_IDLEIE); + + // Call the match callback + YEEP144_BluetoothUART_MatchCallback(); + return; + } + + // If this is not the character match IRQ, let the HAL handle it + HAL_UART_IRQHandler(&huart2); +} + +/** + * Handler for USART3. In the YEEP libraries this is used by the BT UART. + * We do our own checks for the character match interrupt as this is not handled + * by the HAL. For any other interrupt we just let the HAL handle it + */ +void USART3_IRQHandler(void){ + uint32_t isrflags = READ_REG(huart3.Instance->ISR); + uint32_t cr1its = READ_REG(huart3.Instance->CR1); + + // If the character match is enabled and character match flag raised + if (((isrflags & USART_ISR_CMF) != 0U) && ((cr1its & USART_CR1_CMIE) != 0U)){ + __HAL_UART_CLEAR_FLAG(&huart3, UART_CLEAR_CMF); // Clear the character match flag + HAL_DMA_Abort(huart3.hdmarx); // End the current DMA + // Reset the state of the UART HAL + huart3.RxState = HAL_UART_STATE_READY; + huart3.ReceptionType = HAL_UART_RECEPTION_STANDARD; + + // Clear the idle line bit so the reception can be rearmed + ATOMIC_CLEAR_BIT(huart3.Instance->CR1, USART_CR1_IDLEIE); + + // Call the match callback + YEEP144_DebugUART_MatchCallback(); + return; + } + + // If this is not the character match IRQ, let the HAL handle it + HAL_UART_IRQHandler(&huart3); +} + +/** + * These weakly defined callback functions are here so that the code always compiles + * You shouldn't edit these functions, but instead implement your own with the exact same name + * in one of your own files, like main.c + */ +__weak void YEEP144_BluetoothUART_MatchCallback(void){ + return; +} + +__weak void YEEP144_DebugUART_MatchCallback(void){ + return; +} + +/** +* These functions copied from STM's interrupt code to provide stubs for handling +* the internal Cortex Processor interrupts and exceptions +*/ + +/** +* This function handles Non maskable interrupt. +*/ +void NMI_Handler(void){ + while (1){ + + } +} + +/** +* This function handles Hard fault interrupt. +*/ +void HardFault_Handler(void){ + while (1){ + + } +} + +/** +* This function handles Memory management fault. +*/ +void MemManage_Handler(void){ + while (1){ + + } +} + +/** +* This function handles Prefetch fault, memory access fault. +*/ +void BusFault_Handler(void){ + while (1){ + + } +} + +/** +* This function handles Undefined instruction or illegal state. +*/ +void UsageFault_Handler(void){ + while (1){ + + } +} + +/** +* This function handles System service call via SWI instruction. +*/ +void SVC_Handler(void){ + +} + +/** +* This function handles Debug monitor. +*/ +void DebugMon_Handler(void){ + +} + +/** +* This function handles Pendable request for system service. +*/ +void PendSV_Handler(void){ + +} \ No newline at end of file diff --git a/YEEP144lib/src/YEEP144_PiSPI.c b/YEEP144lib/src/YEEP144_PiSPI.c new file mode 100644 index 0000000..ee33cb8 --- /dev/null +++ b/YEEP144lib/src/YEEP144_PiSPI.c @@ -0,0 +1,173 @@ +#include "YEEP144_Pinout.h" +#include "stm32h563xx.h" +#include "stm32h5xx.h" +#include "stm32h5xx_hal.h" +#include "stm32h5xx_hal_cortex.h" +#include "stm32h5xx_hal_def.h" +#include "stm32h5xx_hal_gpio.h" +#include "stm32h5xx_hal_gpio_ex.h" +#include "stm32h5xx_hal_rcc.h" +#include "stm32h5xx_hal_spi.h" + +#include "YEEP144.h" +#include "YEEP144_PiSPI.h" +#include "stm32h5xx_hal_spi_ex.h" +#include + +void YEEP144_PiSPI_RxCallback(void); + +SPI_HandleTypeDef hspi4; + +uint8_t PiSPIRxBuf[PISPI_BUFFER_SIZE]; + +uint8_t PiSPITxBuf[PISPI_BUFFER_SIZE]; +uint8_t PiSPITxBufInternal[PISPI_BUFFER_SIZE]; + +/** + * Initialises SPI communications for use with an attached Raspberry Pi. In this configuration the Pi will act as the master + * therefore the STM32 will be configured as a slave. This means that the master can send / ask for data at any time, and the SPI + * peripheral must be ready to avoid under/overruns. + */ +void YEEP144_PiSPI_Init(void){ + + // Setup and enable clock + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPI4; + PeriphClkInitStruct.Spi4ClockSelection = RCC_SPI4CLKSOURCE_HSI; // HSI = 64MHz clock + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK){ + //Error_Handler(); + } + + __HAL_RCC_SPI4_CLK_ENABLE(); + + // Setup GPIO + YEEP144_GPIO_InitAdv(SPI_MOSI_PORT, SPI_MOSI_PIN | SPI_MISO_PIN | SPI_SCK_PIN , GPIO_MODE_AF_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW, GPIO_AF5_SPI4); + YEEP144_GPIO_Init(SPI_CS_PORT, SPI_CS_PIN, GPIO_MODE_OUTPUT); + YEEP144_PiSPI_ResetReady(); + + // Enable interrupt + HAL_NVIC_SetPriority(SPI4_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(SPI4_IRQn); + + hspi4.Instance = SPI4; + hspi4.Init.Mode = SPI_MODE_SLAVE; // Slave mode + hspi4.Init.Direction = SPI_DIRECTION_2LINES; // Full duplex transmission + hspi4.Init.DataSize = SPI_DATASIZE_8BIT; // Standard 8-bit word size + hspi4.Init.CLKPolarity = SPI_POLARITY_LOW; // Clock polarity and phase set for SPI mode 0 + hspi4.Init.CLKPhase = SPI_PHASE_1EDGE; + hspi4.Init.NSS = SPI_NSS_SOFT; // Chip Select managed by software - we assume we are always selected so the CS line can be repurposed for the ready signal + hspi4.Init.FirstBit = SPI_FIRSTBIT_MSB; // MSB first + hspi4.Init.TIMode = SPI_TIMODE_DISABLE; // Not using TI mode + hspi4.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; // Not using CRC + hspi4.Init.CRCPolynomial = 0x7; + hspi4.Init.NSSPMode = SPI_NSS_PULSE_DISABLE; // Chip select is held not pulsed + hspi4.Init.NSSPolarity = SPI_NSS_POLARITY_LOW; // Chip select is active low + hspi4.Init.FifoThreshold = SPI_FIFO_THRESHOLD_04DATA; // FIFO threshold is 4-bytes which is the maximum + hspi4.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE; // Master configuration is defaults as we aren't master + hspi4.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE; + hspi4.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE; + hspi4.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE; + hspi4.Init.IOSwap = SPI_IO_SWAP_DISABLE; // Don't need to swap IO pins + hspi4.Init.ReadyMasterManagement = SPI_RDY_MASTER_MANAGEMENT_INTERNALLY; // We aren't using the hardware ready signal + hspi4.Init.ReadyPolarity = SPI_RDY_POLARITY_HIGH; + if (HAL_SPI_Init(&hspi4) != HAL_OK){ + //Error_Handler(); + } + + // Set up our interrupt to wait for start of transfer from the master + HAL_SPI_TransmitReceive_IT(&hspi4, PiSPITxBufInternal, PiSPIRxBuf, PISPI_BUFFER_SIZE); + + // Set the ready flag as we are now ready to communicate + YEEP144_PiSPI_SetReady(); + +} + +/** + * Resets the ready signal to ask the master to stop sending / requesting data + */ +void YEEP144_PiSPI_ResetReady(void){ + HAL_GPIO_WritePin(SPI_CS_PORT, SPI_CS_PIN, GPIO_PIN_RESET); +} + +/** + * Sets the ready signal to tell the master we are ready to receive data + */ +void YEEP144_PiSPI_SetReady(void){ + HAL_GPIO_WritePin(SPI_CS_PORT, SPI_CS_PIN, GPIO_PIN_SET); +} + +/** + * Loads the latest data into the SPI peripheral. Call this function every time you change PiSPITxBuf. + */ +void YEEP144_PiSPI_LoadTx(void){ + /** + * As we cannot know when the master will initiate a transfer, we must always be ready to receive and send data + * to avoid overrun when receiving, or underrun when sending. This means that the SPI peripheral must be active + * with a transfer pending before the master begins a transfer by begining the clock and sending data, and + * this pending transfer must be kept active as much of the time as possible. This means that we always start a + * transfer with HAL_SPI_TransmitReceive_IT at the end of SPI initialisation, and immediately after the previous + * transfer has finished in the relevant ISR. + * + * When a transfer is started with HAL_SPI_TransmitReceive_IT, the first x bytes from the transmit buffer is + * pre-loaded into the SPI peripheral's internal TX FIFO, with x depending on the FIFO Threshold configuration, + * to avoid any issues with data underrun. This means that if data in the transmit buffer is changed after a + * transfer is started, the first x bytes will remain from the state of the buffer when the transfer was started, + * leading to messages with a mix of old and new data. + * + * In order to avoid this, the transmit data is double buffered, so that the user code cannot change the data while + * a transfer is in progress, and this function aborts the transfer, which flushes the FIFO, and copies the front + * buffer into the back buffer, before restarting the transfer, which prevents the buffer changeover from also + * occurring mid transaction. + * + * This means there is a small window each time this function is called, and shortly after the end of a transfer + * where the SPI will not be active as the data is changed over. The ready signal should be reset during this period + * which will lead to a small delay on the master side + */ + + // Wait for current transfer to end + while(((SPI4->SR & SPI_SR_CTSIZE_Msk) >> SPI_SR_CTSIZE_Pos) != PISPI_BUFFER_SIZE){} + + // Clear the ready signal to tell the master we are no longer ready + YEEP144_PiSPI_ResetReady(); + + // Stop the current transfer which flushes the old data from the FIFO + HAL_SPI_Abort_IT(&hspi4); + + // Copy the user facing buffer into the internal buffer + memcpy(PiSPITxBufInternal, PiSPITxBuf, PISPI_BUFFER_SIZE); + + // Restart the transfer now the buffer has been updated + HAL_SPI_TransmitReceive_IT(&hspi4, PiSPITxBufInternal, PiSPIRxBuf, PISPI_BUFFER_SIZE); + + // Set the ready signal to tell the master we are now ready to continue communication + YEEP144_PiSPI_SetReady(); +} + +/** + * This function should be called by HAL_SPI_TxRxCpltCallback in YEEP144_IRQ to handle the end of a transfer + * It loads the latest data into the transmit buffer, reinitialises the SPI peripheral ready for the next transfer, + * and calls the user callback + */ +void YEEP144_PiSPI_TxRxHandler(void){ + + // Clear the ready signal as we are not ready to receive until the message has been handled + YEEP144_PiSPI_ResetReady(); + + // Copy the user facing buffer into the internal buffer + memcpy(PiSPITxBufInternal, PiSPITxBuf, PISPI_BUFFER_SIZE); + + // Restart the transfer now the buffer has been updated + HAL_SPI_TransmitReceive_IT(&hspi4, PiSPITxBufInternal, PiSPIRxBuf, PISPI_BUFFER_SIZE); + + // Call the user callback function - the user will need to restore the ready signal when done + // for more messages to be received + YEEP144_PiSPI_RxCallback(); +} + +/** + * This is a weakly defined function for the RX Callback function. + * It should be overriden by an identically named function in user code + */ +__weak void YEEP144_PiSPI_RxCallback(void){ + return; +} diff --git a/YEEP144lib/src/YEEP144_PushButton.c b/YEEP144lib/src/YEEP144_PushButton.c new file mode 100644 index 0000000..9f190a2 --- /dev/null +++ b/YEEP144lib/src/YEEP144_PushButton.c @@ -0,0 +1,111 @@ +#include "YEEP144_PushButton.h" +#include "YEEP144.h" +#include "YEEP144_Pinout.h" +#include "stm32h5xx_hal_cortex.h" +#include "stm32h5xx_hal_def.h" +#include "stm32h5xx_hal_gpio.h" + +void YEEP144_PushButton_BlueCallback(void); +void YEEP144_PushButton_GreenCallback(void); +void YEEP144_PushButton_YellowCallback(void); +void YEEP144_PushButton_RedCallback(void); + +/** + * Initialise the blue button. This consumes the button's GPIO and EXTI13 + */ +void YEEP144_PushButton_BlueInit(void){ + YEEP144_GPIO_Init(BUTTON_BLUE_PORT, BUTTON_BLUE_PIN, GPIO_MODE_IT_FALLING); + HAL_NVIC_SetPriority(BUTTON_BLUE_EXTI, 1, 0); + HAL_NVIC_EnableIRQ(BUTTON_BLUE_EXTI); +} + +/** + * Initialise the green button. This consumes the button's GPIO and EXTI7 + */ +void YEEP144_PushButton_GreenInit(void){ + YEEP144_GPIO_Init(BUTTON_GREEN_PORT, BUTTON_GREEN_PIN, GPIO_MODE_IT_FALLING); + HAL_NVIC_SetPriority(BUTTON_GREEN_EXTI, 1, 0); + HAL_NVIC_EnableIRQ(BUTTON_GREEN_EXTI); +} + +/** + * Initialise the yellow button. This consumes the button's GPIO and EXTI6 + */ +void YEEP144_PushButton_YellowInit(void){ + YEEP144_GPIO_Init(BUTTON_YELLOW_PORT, BUTTON_YELLOW_PIN, GPIO_MODE_IT_FALLING); + HAL_NVIC_SetPriority(BUTTON_YELLOW_EXTI, 1, 0); + HAL_NVIC_EnableIRQ(BUTTON_YELLOW_EXTI); +} + +/** + * Initialise the blue button. This consumes the button's GPIO and EXTI12 (shared with ultrasonic 4) + */ +void YEEP144_PushButton_RedInit(void){ + YEEP144_GPIO_Init(BUTTON_RED_PORT, BUTTON_RED_PIN, GPIO_MODE_IT_FALLING); + HAL_NVIC_SetPriority(BUTTON_RED_EXTI, 1, 0); + HAL_NVIC_EnableIRQ(BUTTON_RED_EXTI); +} + +/** + * Handles the interrupt for the blue button. This should be called from the main EXTI13 handler, and in turn calls YEEP144_PushButton_BlueCallback + */ +void YEEP144_PushButton_BlueHandler(void){ + // Check this interrupt has been called due to the pushbutton + if(__HAL_GPIO_EXTI_GET_IT(BUTTON_BLUE_PIN) && (HAL_GPIO_ReadPin(BUTTON_BLUE_PORT, BUTTON_BLUE_PIN) == GPIO_PIN_RESET)){ + __HAL_GPIO_EXTI_CLEAR_IT(BUTTON_BLUE_PIN); // Clear the interrupt + YEEP144_PushButton_BlueCallback(); // Call the callback function + } +} + +/** + * Handles the interrupt for the green button. This should be called from the main EXTI7 handler, and in turn calls YEEP144_PushButton_GreenCallback + */ +void YEEP144_PushButton_GreenHandler(void){ + // Check this interrupt has been called due to the pushbutton + if(__HAL_GPIO_EXTI_GET_IT(BUTTON_GREEN_PIN) && (HAL_GPIO_ReadPin(BUTTON_GREEN_PORT, BUTTON_GREEN_PIN) == GPIO_PIN_RESET)){ + __HAL_GPIO_EXTI_CLEAR_IT(BUTTON_GREEN_PIN); // Clear the interrupt + YEEP144_PushButton_GreenCallback(); // Call the callback function + } +} + +/** + * Handles the interrupt for the yellow button. This should be called from the main EXTI6 handler, and in turn calls YEEP144_PushButton_YellowCallback + */ +void YEEP144_PushButton_YellowHandler(void){ + // Check this interrupt has been called due to the pushbutton + if(__HAL_GPIO_EXTI_GET_IT(BUTTON_YELLOW_PIN) && (HAL_GPIO_ReadPin(BUTTON_YELLOW_PORT, BUTTON_YELLOW_PIN) == GPIO_PIN_RESET)){ + __HAL_GPIO_EXTI_CLEAR_IT(BUTTON_YELLOW_PIN); // Clear the interrupt + YEEP144_PushButton_YellowCallback(); // Call the callback function + } +} + +/** + * Handles the interrupt for the red button. This should be called from the main EXTI12 handler, and in turn calls YEEP144_PushButton_RedCallback + */ +void YEEP144_PushButton_RedHandler(void){ + // Check this interrupt has been called due to the pushbutton + if(__HAL_GPIO_EXTI_GET_IT(BUTTON_RED_PIN) && (HAL_GPIO_ReadPin(BUTTON_RED_PORT, BUTTON_RED_PIN) == GPIO_PIN_RESET)){ + __HAL_GPIO_EXTI_CLEAR_IT(BUTTON_RED_PIN); // Clear the interrupt + YEEP144_PushButton_RedCallback(); // Call the callback function + } +} + +/** + * These versions of the callback functions are weakly defined so they can be overwritten by the user's function elsewhere. + * They need to exist so that the code will still compile even if the user hasn't defined their own. + */ +__weak void YEEP144_PushButton_BlueCallback(void){ + +} + +__weak void YEEP144_PushButton_GreenCallback(void){ + +} + +__weak void YEEP144_PushButton_YellowCallback(void){ + +} + +__weak void YEEP144_PushButton_RedCallback(void){ + +} \ No newline at end of file diff --git a/YEEP144lib/src/YEEP144_RGB.c b/YEEP144lib/src/YEEP144_RGB.c new file mode 100644 index 0000000..13fc9b0 --- /dev/null +++ b/YEEP144lib/src/YEEP144_RGB.c @@ -0,0 +1,148 @@ +#include "YEEP144.h" +#include "YEEP144_RGB.h" +#include "YEEP144_I2C.h" +#include "stm32h5xx_hal_i2c.h" + +#define RGB_ADDR 0x50 +#define RGB_CHIP_EN_REG 0x000 +#define RGB_DEV_CONFIG_0_REG 0x001 +#define RGB_DEV_CONFIG_1_REG 0x002 +#define RGB_DEV_CONFIG_2_REG 0x003 +#define RGB_DEV_CONFIG_3_REG 0x004 +#define RGB_DEV_CONFIG_4_REG 0x005 +#define RGB_DEV_CONFIG_5_REG 0x006 +#define RGB_DEV_CONFIG_6_REG 0x007 +#define RGB_DEV_CONFIG_7_REG 0x008 +#define RGB_DEV_CONFIG_8_REG 0x009 +#define RGB_DEV_CONFIG_9_REG 0x00A +#define RGB_DEV_CONFIG_10_REG 0x00B +#define RGB_DEV_CONFIG_11_REG 0x00C +#define RGB_DEV_CONFIG_12_REG 0x00D +#define RGB_CMD_UPDATE_REG 0x010 +#define RGB_CMD_START_REG 0x011 +#define RGB_CMD_STOP_REG 0x012 +#define RGB_CMD_PAUSE_REG 0x013 +#define RGB_CMD_CONTINUE_REG 0x014 +#define RGB_LED_EN_1_REG 0x020 +#define RGB_LED_EN_2_REG 0x021 +#define RGB_FAULT_CLEAR_REG 0x022 +#define RGB_RESET_REG 0x023 +#define RGB_MANUAL_DC_BASE_REG 0x030 + +#define RGB_MANUAL_DC_4_REG 0x034 +#define RGB_MANUAL_DC_5_REG 0x035 +#define RGB_MANUAL_DC_6_REG 0x036 +#define RGB_MANUAL_DC_7_REG 0x037 +#define RGB_MANUAL_DC_8_REG 0x038 +#define RGB_MANUAL_DC_9_REG 0x039 +#define RGB_MANUAL_DC_10_REG 0x03A +#define RGB_MANUAL_DC_11_REG 0x03B +#define RGB_MANUAL_DC_12_REG 0x03C +#define RGB_MANUAL_DC_13_REG 0x03D +#define RGB_MANUAL_DC_14_REG 0x03E +#define RGB_MANUAL_DC_15_REG 0x03F +#define RGB_MANUAL_PWM_BASE_REG 0x040 + +#define RGB_MANUAL_PWM_4_REG 0x044 +#define RGB_MANUAL_PWM_5_REG 0x045 +#define RGB_MANUAL_PWM_6_REG 0x046 +#define RGB_MANUAL_PWM_7_REG 0x047 +#define RGB_MANUAL_PWM_8_REG 0x048 +#define RGB_MANUAL_PWM_9_REG 0x049 +#define RGB_MANUAL_PWM_10_REG 0x04A +#define RGB_MANUAL_PWM_11_REG 0x04B +#define RGB_MANUAL_PWM_12_REG 0x04C +#define RGB_MANUAL_PWM_13_REG 0x04D +#define RGB_MANUAL_PWM_14_REG 0x04E +#define RGB_MANUAL_PWM_15_REG 0x04F + +#define I2C_Timeout 1000 + +/** + * Initialise the RGB led driver. This requires that the I2C has already been initialised + */ +void YEEP144_RGB_Init(void){ + + // Reset the LP5812 - 0x66 is magic number according to datasheet + YEEP144_RGB_WriteReg(RGB_RESET_REG, 0x66); + + // Enable the chip + YEEP144_RGB_WriteReg(RGB_CHIP_EN_REG, 1); + + // Set the scan mode - 24kHz PWM, scan drive mode with 4 scans, no direct drive outputs + YEEP144_RGB_WriteReg(RGB_DEV_CONFIG_1_REG, 0x40); + + // Set protection options - shutdown on open LED detected, shutdown on short LED detected, short threshold 0.65 * VCC + YEEP144_RGB_WriteReg(RGB_DEV_CONFIG_12_REG, 0x0F); + + // Apply updated configuration - 0x55 is magic number as per datasheet + YEEP144_RGB_WriteReg(RGB_CMD_UPDATE_REG, 0x55); + + // Set red current limits to 50% of max 25.2mA + YEEP144_RGB_WriteReg(RGB_MANUAL_DC_BASE_REG + RGB1_RED , 0xFF / 2); + YEEP144_RGB_WriteReg(RGB_MANUAL_DC_BASE_REG + RGB2_RED , 0xFF / 2); + YEEP144_RGB_WriteReg(RGB_MANUAL_DC_BASE_REG + RGB3_RED , 0xFF / 2); + YEEP144_RGB_WriteReg(RGB_MANUAL_DC_BASE_REG + RGB4_RED , 0xFF / 2); + + // Set green and blue current limits to 20% of max + + YEEP144_RGB_WriteReg(RGB_MANUAL_DC_BASE_REG + RGB1_GREEN , 0xFF / 5); + YEEP144_RGB_WriteReg(RGB_MANUAL_DC_BASE_REG + RGB1_BLUE , 0xFF / 5); + YEEP144_RGB_WriteReg(RGB_MANUAL_DC_BASE_REG + RGB2_GREEN , 0xFF / 5); + YEEP144_RGB_WriteReg(RGB_MANUAL_DC_BASE_REG + RGB2_BLUE , 0xFF / 5); + YEEP144_RGB_WriteReg(RGB_MANUAL_DC_BASE_REG + RGB3_GREEN , 0xFF / 5); + YEEP144_RGB_WriteReg(RGB_MANUAL_DC_BASE_REG + RGB3_BLUE , 0xFF / 5); + YEEP144_RGB_WriteReg(RGB_MANUAL_DC_BASE_REG + RGB4_GREEN , 0xFF / 5); + YEEP144_RGB_WriteReg(RGB_MANUAL_DC_BASE_REG + RGB4_BLUE , 0xFF / 5); + + // Enable all the LEDS + YEEP144_RGB_WriteReg(RGB_LED_EN_1_REG, 0xF0); + YEEP144_RGB_WriteReg(RGB_LED_EN_2_REG, 0xFF); + + // Set default colours + YEEP144_RGB_SetRGB(1, RGB_GREEN); + YEEP144_RGB_SetRGB(2, RGB_GOLD); + YEEP144_RGB_SetRGB(3, RGB_RED); + YEEP144_RGB_SetRGB(4, RGB_INDIGO); + +} + +/** + * Individually sets the brightness of an LED. Use the defines in the header file + * to specify which LED e.g. RGB1_GREEN + */ +void YEEP144_RGB_SetLED(uint8_t led, uint8_t value){ + YEEP144_RGB_WriteReg(RGB_MANUAL_PWM_BASE_REG + led, value); +} + +/** + * Sets the brightness for all 3 elements of an RGB led at one. + * Instead of specifiying the RGB values, you can also substitute in one of the defines e.g. RGB_GOLD + */ +void YEEP144_RGB_SetRGB(uint8_t led, uint8_t red, uint8_t green, uint8_t blue){ + uint8_t offset = ((led - 1) * 3); + YEEP144_RGB_WriteReg(RGB_MANUAL_PWM_BASE_REG + RGB1_RED + offset, red); + YEEP144_RGB_WriteReg(RGB_MANUAL_PWM_BASE_REG + RGB1_GREEN + offset, green); + YEEP144_RGB_WriteReg(RGB_MANUAL_PWM_BASE_REG + RGB1_BLUE + offset, blue); +} + +/** + * Helper function that writes a byte to the RGB controller at the specified register address + */ +void YEEP144_RGB_WriteReg(uint16_t reg, uint8_t data){ + // As there are so many registers in this chip, it uses a couple of the I2C address bits as part of the register address + // This means we need to do some bit level manipulation to build our transmission address and data + + uint8_t I2CAddress = RGB_ADDR + (reg >> 8); // set the bottom two bits of the address to the top two bits of the register + + // Cast the register to a uint8_t so we just get the lowest 8 bits + uint8_t reg8Bit = (uint8_t) reg; + + // Pack out register address and data into an array for transmission + uint8_t RGBCommand[2]; + RGBCommand[0] = reg8Bit; + RGBCommand[1] = data; + + // Send out the data. The constructed I2CAddress still needs to be shifted by 1 due to 7/8-bit addressing differences + HAL_I2C_Master_Transmit(&hi2c2, I2CAddress << 1, RGBCommand, 2, I2C_Timeout); +} \ No newline at end of file diff --git a/YEEP144lib/src/YEEP144_SSD1306.c b/YEEP144lib/src/YEEP144_SSD1306.c new file mode 100644 index 0000000..65dd87e --- /dev/null +++ b/YEEP144lib/src/YEEP144_SSD1306.c @@ -0,0 +1,779 @@ +// This code is largely inspired by the Adafruit SSD1306 and Adafruit GFX Arduino libraries +// re-written to simplify it down to plain C rather than object based C++, optimise for STM32 +// rather than Arduino, and to focus on specifically the monochrome SSD1306 displays rather than +// a general purpose graphics library + +#include "stm32h5xx_hal.h" +#include "stm32h5xx_hal_i2c.h" +#include "YEEP144_I2C.h" +#include "YEEP144_SSD1306.h" + +#include +#include +#include +#include +#include +#include +#include + +#define WIDTH 128 +#define HEIGHT 32 +#define SSD1306_ADDR 0x3C << 1 +#define I2C_TIMEOUT 1000 + +#define FONTWIDTH 5 +#define FONTHEIGHT 7 +#define MAXCHAR ((WIDTH / (FONTWIDTH + 1)) * (HEIGHT / (FONTHEIGHT + 1))) + +#define SSD1306_MEMORYMODE 0x20 +#define SSD1306_COLUMNADDR 0x21 +#define SSD1306_PAGEADDR 0x22 +#define SSD1306_SETCONTRAST 0x81 +#define SSD1306_CHARGEPUMP 0x8D +#define SSD1306_SEGREMAP 0xA0 +#define SSD1306_DISPLAYALLON_RESUME 0xA4 +#define SSD1306_DISPLAYALLON 0xA5 +#define SSD1306_NORMALDISPLAY 0xA6 +#define SSD1306_INVERTDISPLAY 0xA7 +#define SSD1306_SETMULTIPLEX 0xA8 +#define SSD1306_DISPLAYOFF 0xAE +#define SSD1306_DISPLAYON 0xAF +#define SSD1306_COMSCANINC 0xC0 +#define SSD1306_COMSCANDEC 0xC8 +#define SSD1306_SETDISPLAYOFFSET 0xD3 +#define SSD1306_SETDISPLAYCLOCKDIV 0xD5 +#define SSD1306_SETPRECHARGE 0xD9 +#define SSD1306_SETCOMPINS 0xDA +#define SSD1306_SETVCOMDETECT 0xDB + +#define SSD1306_SETLOWCOLUMN 0x00 +#define SSD1306_SETHIGHCOLUMN 0x10 +#define SSD1306_SETSTARTLINE 0x40 + +#define SSD1306_EXTERNALVCC 0x01 +#define SSD1306_SWITCHCAPVCC 0x02 + +#define SSD1306_RIGHT_HORIZONTAL_SCROLL 0x26 +#define SSD1306_LEFT_HORIZONTAL_SCROLL 0x27 +#define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29 +#define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A +#define SSD1306_DEACTIVATE_SCROLL 0x2E +#define SSD1306_ACTIVATE_SCROLL 0x2F +#define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3 + +uint8_t *displayTXBuffer; +uint8_t *displayBuffer; + +uint8_t cursorX = 0; +uint8_t cursorY = 0; +uint8_t textSize = 1; +uint8_t textColour = SSD1306_WHITE; +uint8_t textBGColour = SSD1306_BLACK; +uint8_t textWrap = 1; + +void YEEP144_SSD1306_DrawFastHLine(uint8_t x, uint8_t y, int8_t w, uint8_t colour); +void YEEP144_SSD1306_DrawFastVLine(uint8_t x, uint8_t y, int8_t h, uint8_t colour); +void YEEP144_SSD1306_DrawLineInternal(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t colour); + +const unsigned char UOYLogo [] = { + 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xe0, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xc8, 0x18, 0x0d, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x3c, 0x04, 0x00, 0x40, 0x69, 0x24, 0xd7, 0xb8, 0xcd, 0xe9, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xbc, 0x00, 0x10, 0x00, 0x49, 0xa4, 0x02, 0x25, 0x08, 0x86, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xdc, 0x01, 0x16, 0x40, 0x49, 0x64, 0x42, 0x28, 0xc8, 0x84, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x8f, 0xe8, 0x00, 0x49, 0x24, 0x62, 0xad, 0x48, 0x84, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3e, 0x77, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7e, 0x07, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xf6, 0x0d, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xe0, 0x1c, 0xf8, 0x00, 0x00, 0x0c, 0x38, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0xc0, 0x86, 0xff, 0x80, 0x00, 0x14, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xef, 0x9f, 0xfb, 0x00, 0x00, 0x20, 0x18, 0x10, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0xa0, 0xfe, 0x00, 0x1e, 0x20, 0x10, 0x60, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x58, 0xb6, 0x00, 0x27, 0xf8, 0x30, 0xe0, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xb8, 0x3c, 0x33, 0x00, 0x4c, 0x40, 0x31, 0xc0, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x98, 0x7e, 0x33, 0x00, 0x84, 0xc0, 0x63, 0x86, 0x30, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0xc2, 0x10, 0x00, 0x88, 0x80, 0x6b, 0x12, 0xb7, 0xc3, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x69, 0xdb, 0x1a, 0x00, 0x90, 0x80, 0xd6, 0x22, 0x38, 0x86, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x79, 0xff, 0x90, 0x00, 0xe1, 0x00, 0xec, 0x42, 0x31, 0x98, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7b, 0xff, 0xd0, 0x00, 0x02, 0x01, 0x98, 0xc4, 0x61, 0xe0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x6c, 0x3c, 0x2c, 0x00, 0x04, 0x01, 0x30, 0x8c, 0x43, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0xa4, 0xa0, 0x00, 0x00, 0x00, 0x70, 0x98, 0x82, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0xc3, 0xe0, 0x00, 0x00, 0x00, 0x60, 0xe0, 0x84, 0x0f, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x99, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x11, 0xc0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x18, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x80, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x40, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const unsigned char font[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, 0x3E, 0x6B, + 0x4F, 0x6B, 0x3E, 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 0x18, 0x3C, 0x7E, 0x3C, + 0x18, 0x1C, 0x57, 0x7D, 0x57, 0x1C, 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, 0x00, + 0x18, 0x3C, 0x18, 0x00, 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, 0x00, 0x18, 0x24, + 0x18, 0x00, 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, 0x30, 0x48, 0x3A, 0x06, 0x0E, + 0x26, 0x29, 0x79, 0x29, 0x26, 0x40, 0x7F, 0x05, 0x05, 0x07, 0x40, 0x7F, + 0x05, 0x25, 0x3F, 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, 0x7F, 0x3E, 0x1C, 0x1C, + 0x08, 0x08, 0x1C, 0x1C, 0x3E, 0x7F, 0x14, 0x22, 0x7F, 0x22, 0x14, 0x5F, + 0x5F, 0x00, 0x5F, 0x5F, 0x06, 0x09, 0x7F, 0x01, 0x7F, 0x00, 0x66, 0x89, + 0x95, 0x6A, 0x60, 0x60, 0x60, 0x60, 0x60, 0x94, 0xA2, 0xFF, 0xA2, 0x94, + 0x08, 0x04, 0x7E, 0x04, 0x08, 0x10, 0x20, 0x7E, 0x20, 0x10, 0x08, 0x08, + 0x2A, 0x1C, 0x08, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x1E, 0x10, 0x10, 0x10, + 0x10, 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, 0x30, 0x38, 0x3E, 0x38, 0x30, 0x06, + 0x0E, 0x3E, 0x0E, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00, 0x14, 0x7F, 0x14, 0x7F, 0x14, + 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x23, 0x13, 0x08, 0x64, 0x62, 0x36, 0x49, + 0x56, 0x20, 0x50, 0x00, 0x08, 0x07, 0x03, 0x00, 0x00, 0x1C, 0x22, 0x41, + 0x00, 0x00, 0x41, 0x22, 0x1C, 0x00, 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x08, + 0x08, 0x3E, 0x08, 0x08, 0x00, 0x80, 0x70, 0x30, 0x00, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x00, 0x00, 0x60, 0x60, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, + 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x42, 0x7F, 0x40, 0x00, 0x72, 0x49, + 0x49, 0x49, 0x46, 0x21, 0x41, 0x49, 0x4D, 0x33, 0x18, 0x14, 0x12, 0x7F, + 0x10, 0x27, 0x45, 0x45, 0x45, 0x39, 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x41, + 0x21, 0x11, 0x09, 0x07, 0x36, 0x49, 0x49, 0x49, 0x36, 0x46, 0x49, 0x49, + 0x29, 0x1E, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x40, 0x34, 0x00, 0x00, + 0x00, 0x08, 0x14, 0x22, 0x41, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x41, + 0x22, 0x14, 0x08, 0x02, 0x01, 0x59, 0x09, 0x06, 0x3E, 0x41, 0x5D, 0x59, + 0x4E, 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x7F, 0x49, 0x49, 0x49, 0x36, 0x3E, + 0x41, 0x41, 0x41, 0x22, 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x7F, 0x49, 0x49, + 0x49, 0x41, 0x7F, 0x09, 0x09, 0x09, 0x01, 0x3E, 0x41, 0x41, 0x51, 0x73, + 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, 0x41, 0x7F, 0x41, 0x00, 0x20, 0x40, + 0x41, 0x3F, 0x01, 0x7F, 0x08, 0x14, 0x22, 0x41, 0x7F, 0x40, 0x40, 0x40, + 0x40, 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x3E, + 0x41, 0x41, 0x41, 0x3E, 0x7F, 0x09, 0x09, 0x09, 0x06, 0x3E, 0x41, 0x51, + 0x21, 0x5E, 0x7F, 0x09, 0x19, 0x29, 0x46, 0x26, 0x49, 0x49, 0x49, 0x32, + 0x03, 0x01, 0x7F, 0x01, 0x03, 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x1F, 0x20, + 0x40, 0x20, 0x1F, 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x63, 0x14, 0x08, 0x14, + 0x63, 0x03, 0x04, 0x78, 0x04, 0x03, 0x61, 0x59, 0x49, 0x4D, 0x43, 0x00, + 0x7F, 0x41, 0x41, 0x41, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x41, 0x41, + 0x41, 0x7F, 0x04, 0x02, 0x01, 0x02, 0x04, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x03, 0x07, 0x08, 0x00, 0x20, 0x54, 0x54, 0x78, 0x40, 0x7F, 0x28, + 0x44, 0x44, 0x38, 0x38, 0x44, 0x44, 0x44, 0x28, 0x38, 0x44, 0x44, 0x28, + 0x7F, 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, 0x08, 0x7E, 0x09, 0x02, 0x18, + 0xA4, 0xA4, 0x9C, 0x78, 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, 0x44, 0x7D, + 0x40, 0x00, 0x20, 0x40, 0x40, 0x3D, 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, + 0x00, 0x41, 0x7F, 0x40, 0x00, 0x7C, 0x04, 0x78, 0x04, 0x78, 0x7C, 0x08, + 0x04, 0x04, 0x78, 0x38, 0x44, 0x44, 0x44, 0x38, 0xFC, 0x18, 0x24, 0x24, + 0x18, 0x18, 0x24, 0x24, 0x18, 0xFC, 0x7C, 0x08, 0x04, 0x04, 0x08, 0x48, + 0x54, 0x54, 0x54, 0x24, 0x04, 0x04, 0x3F, 0x44, 0x24, 0x3C, 0x40, 0x40, + 0x20, 0x7C, 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x3C, 0x40, 0x30, 0x40, 0x3C, + 0x44, 0x28, 0x10, 0x28, 0x44, 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x44, 0x64, + 0x54, 0x4C, 0x44, 0x00, 0x08, 0x36, 0x41, 0x00, 0x00, 0x00, 0x77, 0x00, + 0x00, 0x00, 0x41, 0x36, 0x08, 0x00, 0x02, 0x01, 0x02, 0x04, 0x02, 0x3C, + 0x26, 0x23, 0x26, 0x3C, 0x1E, 0xA1, 0xA1, 0x61, 0x12, 0x3A, 0x40, 0x40, + 0x20, 0x7A, 0x38, 0x54, 0x54, 0x55, 0x59, 0x21, 0x55, 0x55, 0x79, 0x41, + 0x22, 0x54, 0x54, 0x78, 0x42, // a-umlaut + 0x21, 0x55, 0x54, 0x78, 0x40, 0x20, 0x54, 0x55, 0x79, 0x40, 0x0C, 0x1E, + 0x52, 0x72, 0x12, 0x39, 0x55, 0x55, 0x55, 0x59, 0x39, 0x54, 0x54, 0x54, + 0x59, 0x39, 0x55, 0x54, 0x54, 0x58, 0x00, 0x00, 0x45, 0x7C, 0x41, 0x00, + 0x02, 0x45, 0x7D, 0x42, 0x00, 0x01, 0x45, 0x7C, 0x40, 0x7D, 0x12, 0x11, + 0x12, 0x7D, // A-umlaut + 0xF0, 0x28, 0x25, 0x28, 0xF0, 0x7C, 0x54, 0x55, 0x45, 0x00, 0x20, 0x54, + 0x54, 0x7C, 0x54, 0x7C, 0x0A, 0x09, 0x7F, 0x49, 0x32, 0x49, 0x49, 0x49, + 0x32, 0x3A, 0x44, 0x44, 0x44, 0x3A, // o-umlaut + 0x32, 0x4A, 0x48, 0x48, 0x30, 0x3A, 0x41, 0x41, 0x21, 0x7A, 0x3A, 0x42, + 0x40, 0x20, 0x78, 0x00, 0x9D, 0xA0, 0xA0, 0x7D, 0x3D, 0x42, 0x42, 0x42, + 0x3D, // O-umlaut + 0x3D, 0x40, 0x40, 0x40, 0x3D, 0x3C, 0x24, 0xFF, 0x24, 0x24, 0x48, 0x7E, + 0x49, 0x43, 0x66, 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, 0xFF, 0x09, 0x29, 0xF6, + 0x20, 0xC0, 0x88, 0x7E, 0x09, 0x03, 0x20, 0x54, 0x54, 0x79, 0x41, 0x00, + 0x00, 0x44, 0x7D, 0x41, 0x30, 0x48, 0x48, 0x4A, 0x32, 0x38, 0x40, 0x40, + 0x22, 0x7A, 0x00, 0x7A, 0x0A, 0x0A, 0x72, 0x7D, 0x0D, 0x19, 0x31, 0x7D, + 0x26, 0x29, 0x29, 0x2F, 0x28, 0x26, 0x29, 0x29, 0x29, 0x26, 0x30, 0x48, + 0x4D, 0x40, 0x20, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x38, 0x2F, 0x10, 0xC8, 0xAC, 0xBA, 0x2F, 0x10, 0x28, 0x34, 0xFA, 0x00, + 0x00, 0x7B, 0x00, 0x00, 0x08, 0x14, 0x2A, 0x14, 0x22, 0x22, 0x14, 0x2A, + 0x14, 0x08, 0x55, 0x00, 0x55, 0x00, 0x55, // #176 (25% block) missing in old + // code + 0xAA, 0x55, 0xAA, 0x55, 0xAA, // 50% block + 0xFF, 0x55, 0xFF, 0x55, 0xFF, // 75% block + 0x00, 0x00, 0x00, 0xFF, 0x00, 0x10, 0x10, 0x10, 0xFF, 0x00, 0x14, 0x14, + 0x14, 0xFF, 0x00, 0x10, 0x10, 0xFF, 0x00, 0xFF, 0x10, 0x10, 0xF0, 0x10, + 0xF0, 0x14, 0x14, 0x14, 0xFC, 0x00, 0x14, 0x14, 0xF7, 0x00, 0xFF, 0x00, + 0x00, 0xFF, 0x00, 0xFF, 0x14, 0x14, 0xF4, 0x04, 0xFC, 0x14, 0x14, 0x17, + 0x10, 0x1F, 0x10, 0x10, 0x1F, 0x10, 0x1F, 0x14, 0x14, 0x14, 0x1F, 0x00, + 0x10, 0x10, 0x10, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x10, 0x10, 0x10, + 0x10, 0x1F, 0x10, 0x10, 0x10, 0x10, 0xF0, 0x10, 0x00, 0x00, 0x00, 0xFF, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xFF, 0x10, 0x00, + 0x00, 0x00, 0xFF, 0x14, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x1F, + 0x10, 0x17, 0x00, 0x00, 0xFC, 0x04, 0xF4, 0x14, 0x14, 0x17, 0x10, 0x17, + 0x14, 0x14, 0xF4, 0x04, 0xF4, 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0xF7, 0x00, 0xF7, 0x14, 0x14, 0x14, 0x17, + 0x14, 0x10, 0x10, 0x1F, 0x10, 0x1F, 0x14, 0x14, 0x14, 0xF4, 0x14, 0x10, + 0x10, 0xF0, 0x10, 0xF0, 0x00, 0x00, 0x1F, 0x10, 0x1F, 0x00, 0x00, 0x00, + 0x1F, 0x14, 0x00, 0x00, 0x00, 0xFC, 0x14, 0x00, 0x00, 0xF0, 0x10, 0xF0, + 0x10, 0x10, 0xFF, 0x10, 0xFF, 0x14, 0x14, 0x14, 0xFF, 0x14, 0x10, 0x10, + 0x10, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x38, 0x44, 0x44, + 0x38, 0x44, 0xFC, 0x4A, 0x4A, 0x4A, 0x34, // sharp-s or beta + 0x7E, 0x02, 0x02, 0x06, 0x06, 0x02, 0x7E, 0x02, 0x7E, 0x02, 0x63, 0x55, + 0x49, 0x41, 0x63, 0x38, 0x44, 0x44, 0x3C, 0x04, 0x40, 0x7E, 0x20, 0x1E, + 0x20, 0x06, 0x02, 0x7E, 0x02, 0x02, 0x99, 0xA5, 0xE7, 0xA5, 0x99, 0x1C, + 0x2A, 0x49, 0x2A, 0x1C, 0x4C, 0x72, 0x01, 0x72, 0x4C, 0x30, 0x4A, 0x4D, + 0x4D, 0x30, 0x30, 0x48, 0x78, 0x48, 0x30, 0xBC, 0x62, 0x5A, 0x46, 0x3D, + 0x3E, 0x49, 0x49, 0x49, 0x00, 0x7E, 0x01, 0x01, 0x01, 0x7E, 0x2A, 0x2A, + 0x2A, 0x2A, 0x2A, 0x44, 0x44, 0x5F, 0x44, 0x44, 0x40, 0x51, 0x4A, 0x44, + 0x40, 0x40, 0x44, 0x4A, 0x51, 0x40, 0x00, 0x00, 0xFF, 0x01, 0x03, 0xE0, + 0x80, 0xFF, 0x00, 0x00, 0x08, 0x08, 0x6B, 0x6B, 0x08, 0x36, 0x12, 0x36, + 0x24, 0x36, 0x06, 0x0F, 0x09, 0x0F, 0x06, 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x00, 0x30, 0x40, 0xFF, 0x01, 0x01, 0x00, 0x1F, + 0x01, 0x01, 0x1E, 0x00, 0x19, 0x1D, 0x17, 0x12, 0x00, 0x3C, 0x3C, 0x3C, + 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00 // #255 NBSP +}; + +/** + * Initialise the SSD1306 OLED display. This requires that the I2C has already been initialised. + */ +void YEEP144_SSD1306_Init(void){ + + // Allocate space in memory for the framebuffer to be stored + // As the display is monochrome we only need 1 bit per pixel, so the data is packed + // to save on memory space - i.e. 8 pixels per byte + // The arithmetic used ensures that the buffer size is always padded to a whole byte number + // + // This is also how the framebuffer is stored within the OLED chip, so it can be directly + // copied across without additional manipulation + // + // We make the TX buffer 1 byte larger than needed for the display data so the value 0x40 can be prepended + // When it comes time to send the framebuffer to the display, that initial byte is required so the data is treated + // as display data, not commands + displayTXBuffer = (uint8_t *)malloc((WIDTH * ((HEIGHT + 7) / 8)) + 1); + displayTXBuffer[0] = 0x40; + + // For programming ease we store a separate pointer offset by 1 to directly access the display data portion of the buffer + displayBuffer = displayTXBuffer + 1; + + // Ensure the display buffer is empty + YEEP144_SSD1306_ClearDisplay(); + + // This list of commands sets up the display and turns it on + uint8_t initCommandList[] = { + 0x00, // Tell the display these are commands not graphics data + SSD1306_DISPLAYOFF, + SSD1306_SETDISPLAYCLOCKDIV, + 0x80, // Recommended clock div + SSD1306_SETMULTIPLEX, + HEIGHT - 1, + SSD1306_SETDISPLAYOFFSET, + 0x0, // No display offset + SSD1306_SETSTARTLINE | 0x0, // Start at line 0 + SSD1306_CHARGEPUMP, + 0x14, // Enable internal charge pump + SSD1306_MEMORYMODE, + 0x00, + SSD1306_SEGREMAP | 0x1, + SSD1306_COMSCANDEC, + SSD1306_SETCOMPINS, + 0x02, // This is hardcoded for the value for a 128x32 screen + SSD1306_SETCONTRAST, + 0x8F, // This is hardcoded for the value for a 128x32 screen + SSD1306_SETPRECHARGE, + 0xF1, // Value for when charge pump is enabled + SSD1306_SETVCOMDETECT, + 0x40, + SSD1306_DISPLAYALLON_RESUME, + SSD1306_NORMALDISPLAY, + SSD1306_DEACTIVATE_SCROLL, + SSD1306_DISPLAYON + + }; + + // Send the commands + HAL_I2C_Master_Transmit(&hi2c2, SSD1306_ADDR, initCommandList, sizeof(initCommandList), I2C_TIMEOUT); + +} + +/** + * Update the display by transfering the contents of the display buffer to the display. + * No changes to the displayed graphics will be made until this command is called + */ +void YEEP144_SSD1306_Display(void){ + // Before sending graphics data we need to define where the data goes + // As we are always copying over the whole frame buffer, we want our transfer to fill + // the whole graphics memory on the driver chip + uint8_t commandList[] = { + 0x00, // Following data are commands + SSD1306_PAGEADDR, + 0, // Starting page + 0xFF, // Ending page + SSD1306_COLUMNADDR, + 0, // Starting column + (WIDTH-1), // Ending column + //0x40 // Following data will be graphics not commands + }; + + // Send these commands + HAL_I2C_Master_Transmit(&hi2c2, SSD1306_ADDR, commandList, sizeof(commandList), I2C_TIMEOUT); + + // Send the graphics data. We use the TXbuffer here so it includes the additional byte at the start that tells the chip this is graphics data + HAL_I2C_Master_Transmit(&hi2c2, SSD1306_ADDR, displayTXBuffer, (WIDTH * ((HEIGHT + 7) / 8)) + 1, I2C_TIMEOUT); + +} + +/** + * Clears the display by clearing the display buffer + */ +void YEEP144_SSD1306_ClearDisplay(void){ + + // Clear the display by filling the buffer with all zeros + memset(displayBuffer, 0, WIDTH * ((HEIGHT + 7) / 8)); +} + +/** + * Sets a single pixel in the display buffer to the specified colour + */ +void YEEP144_SSD1306_SetPixel(uint8_t x, uint8_t y, uint8_t colour){ + + // As the data is packed with 8 pixels per byte, we need to do some bit-level + // manipulation to set an individual pixel + switch(colour){ + // Set the bit for white (on) + case SSD1306_WHITE: + displayBuffer[x + (y / 8) * WIDTH] |= (1 << (y & 7)); + break; + // Clear the bit for black (off) + case SSD1306_BLACK: + displayBuffer[x + (y / 8) * WIDTH] &= ~(1 << (y & 7)); + break; + // Invert the bit to invert the colour + case SSD1306_INVERSE: + displayBuffer[x + (y / 8) * WIDTH] ^= (1 << (y & 7)); + break; + } +} + +/** + * Returns the current value of the specified pixel from the display buffer. + * Note that this is what is currently stored in the local buffer, not + * necessarily what is currently being displayed if Display has not been called + */ +bool YEEP144_SSD1306_GetPixel(uint8_t x, uint8_t y){ + // As the 1-bit pixels are packed into bytes, we need to do some bit manipulation to retrieve the individual bit + return (displayBuffer[x + (y / 8) * WIDTH] & (1 << (y & 7))); +} + +/** + * Draws a line between the specified coordinates, using the specified colour + */ +void YEEP144_SSD1306_DrawLine(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t colour){ + // This function checks if the draw can be fufilled by one of the optimised horizontal or vertical + // line drawing functions, if not passes to the generalised one + if(x0 == x1){ // If both x coordinates are the same then this is vertical + if (y0 > y1){ // Normalise direction by swapping the coords if needed + uint8_t t = y0; + y0 = y1; + y1 = t; + } + YEEP144_SSD1306_DrawFastVLine(x0, y0, y1 - y0, colour); + } + else if(y0 == y1){ // If both y coordinates are the same then this is horizontal + if(x0 > x1){ // Normalise direction by swapping the coords if needed + uint8_t t = x0; + x0 = x1; + x1 = t; + } + YEEP144_SSD1306_DrawFastHLine(x0, y0, x1 - x0, colour); + } + else{ + // If this cannot be handled by either of the fast algorithms, fallback to the general one + YEEP144_SSD1306_DrawLineInternal(x0, y0, x1, y1, colour); + } +} + +/** + * Draws a line between the two specified points using Bresenham's algorithm + * This is only used when the line is not vertical or horizontal + * This will only be an approximation of requested line due to the limited resolution of the display + * and the lack of options for antialiasing + */ +void YEEP144_SSD1306_DrawLineInternal(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t colour){ + // Bresenham's algorithm only works when going in the positive direction, which would be down and right + // for a display with (0,0) in the top left corner. So that this can be used for all cases, + // we need to detect the direction of the requested line and transform the coordinates + uint8_t steep = abs(y1 - y0) > abs(x1 - x0); + + if(steep){ + uint8_t t = x0; + x0 = y0; + y0 = t; + + t = x1; + x1 = y1; + y1 = t; + } + + if(x0 > x1){ + uint8_t t = x0; + x0 = x1; + x1 = t; + t = y0; + y0 = y1; + y1 = t; + } + + int8_t dx = x1 - x0; + int8_t dy = abs(y1 - y0); + + int8_t err = dx / 2; + int8_t ystep; + + if(y0 < y1){ + ystep = 1; + } + else{ + ystep = -1; + } + + for(; x0 <= x1; x0++){ + if(steep){ + YEEP144_SSD1306_SetPixel(y0, x0, colour); + } + else{ + YEEP144_SSD1306_SetPixel(x0, y0, colour); + } + err -= dy; + if(err < 0){ + y0 += ystep; + err += dx; + } + } +} + +/** + * Draw a purely horizontal line. This is faster than the general algorithm, + * but only works for horizontal lines + */ +void YEEP144_SSD1306_DrawFastHLine(uint8_t x, uint8_t y, int8_t w, uint8_t colour){ + if (y < HEIGHT) { // Y coord in bounds? + if ((x + w) > WIDTH) { // Clip right + w = (WIDTH - x); + } + if (w > 0) { // Proceed only if width is positive + uint8_t *pBuf = &displayBuffer[(y / 8) * WIDTH + x]; + uint8_t mask = 1 << (y & 7); + switch (colour) { + case SSD1306_WHITE: + while (w--) { + *pBuf++ |= mask; + }; + break; + case SSD1306_BLACK: + mask = ~mask; + while (w--) { + *pBuf++ &= mask; + }; + break; + case SSD1306_INVERSE: + while (w--) { + *pBuf++ ^= mask; + }; + break; + } + } + } +} + +/** + * Draw a purely vertical line. This is faster than the general algorithm, + * but only works for vertical lines + */ +void YEEP144_SSD1306_DrawFastVLine(uint8_t x, uint8_t y, int8_t h, uint8_t colour){ + if (x < WIDTH) { // X coord in bounds? + if ((y + h) > HEIGHT) { // Clip bottom + h = (HEIGHT - y); + } + if (h > 0) { // Proceed only if height is now positive + + uint8_t *pBuf = &displayBuffer[(y / 8) * WIDTH + x]; + + // do the first partial byte, if necessary - this requires some masking + uint8_t mod = (y & 7); + if (mod) { + // mask off the high n bits we want to set + mod = 8 - mod; + // note - lookup table results in a nearly 10% performance + // improvement in fill* functions + // uint8_t mask = ~(0xFF >> mod); + static const uint8_t premask[8] = {0x00, 0x80, 0xC0, 0xE0, + 0xF0, 0xF8, 0xFC, 0xFE}; + uint8_t mask = premask[mod]; + // adjust the mask if we're not going to reach the end of this byte + if (h < mod) + mask &= (0XFF >> (mod - h)); + + switch (colour) { + case SSD1306_WHITE: + *pBuf |= mask; + break; + case SSD1306_BLACK: + *pBuf &= ~mask; + break; + case SSD1306_INVERSE: + *pBuf ^= mask; + break; + } + pBuf += WIDTH; + } + + if (h >= mod) { // More to go? + h -= mod; + // Write solid bytes while we can - effectively 8 rows at a time + if (h >= 8) { + if (colour == SSD1306_INVERSE) { + // separate copy of the code so we don't impact performance of + // black/white write version with an extra comparison per loop + do { + *pBuf ^= 0xFF; // Invert byte + pBuf += WIDTH; // Advance pointer 8 rows + h -= 8; // Subtract 8 rows from height + } while (h >= 8); + } else { + // store a local value to work with + uint8_t val = (colour != SSD1306_BLACK) ? 255 : 0; + do { + *pBuf = val; // Set byte + pBuf += WIDTH; // Advance pointer 8 rows + h -= 8; // Subtract 8 rows from height + } while (h >= 8); + } + } + + if (h) { // Do the final partial byte, if necessary + mod = h & 7; + // this time we want to mask the low bits of the byte, + // vs the high bits we did above + // uint8_t mask = (1 << mod) - 1; + // note - lookup table results in a nearly 10% performance + // improvement in fill* functions + static const uint8_t postmask[8] = {0x00, 0x01, 0x03, 0x07, + 0x0F, 0x1F, 0x3F, 0x7F}; + uint8_t mask = postmask[mod]; + switch (colour) { + case SSD1306_WHITE: + *pBuf |= mask; + break; + case SSD1306_BLACK: + *pBuf &= ~mask; + break; + case SSD1306_INVERSE: + *pBuf ^= mask; + break; + } + } + } + } // endif positive height + } // endif x in bounds +} + +/** + * Draws an outline of a rectangle with no fill. Coordinates represent the top left corner + */ +void YEEP144_SSD1306_DrawRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t colour){ + YEEP144_SSD1306_DrawFastHLine(x, y, w, colour); + YEEP144_SSD1306_DrawFastHLine(x, y + h - 1, w, colour); + YEEP144_SSD1306_DrawFastVLine(x, y, h, colour); + YEEP144_SSD1306_DrawFastVLine(x + w - 1, y, h, colour); +} + +/** + * Draw a filled rectangle of given width and height, with the top left corner specified + * by the given coordinates + */ +void YEEP144_SSD1306_DrawFillRect(uint8_t x, uint8_t y, int8_t w, int8_t h, uint8_t colour){ + for (int16_t i = x; i < x + w; i++) { + YEEP144_SSD1306_DrawFastVLine(i, y, h, colour); + } +} + +/** + * Prints text to the screen using printf-style formatting. Cursor starting position, font size and + * text wrapping can be controlled using the provided functions + */ +int YEEP144_SSD1306_printf(const char * format, ...){ + // Set the buffer size to the maximum that can fit on the screen with the smallest font + size_t bufSize = MAXCHAR; + + // Try to allocate that buffer + char* buffer = malloc(bufSize); + + // If the buffer cannot be allocated, return -1 + if (buffer == NULL) return -1; + + // Get the pointer to the variadic args + va_list args; + va_start (args, format); + + // Create our final string in the buffer using vsnprintf, passing through our argument pointer + vsnprintf(buffer, bufSize, format, args); + + // Calulate the final size of the string + bufSize = strlen(buffer); + + // Write our characters one by one to the screen + for(size_t i = 0; i < bufSize; i++){ + char c = buffer[i]; + + if(c == '\n'){// Newline - move cursor down by 1 line, and back to start of line + cursorX = 0; + cursorY += textSize * (FONTHEIGHT + 1); + } + else if(c != '\r'){ // All other text - ignoring carriage returns + if(textWrap && ((cursorX + textSize * (FONTWIDTH + 1)) > WIDTH)){ + // If wrapping is enabled and this character will overflow the display, move to start of next line + cursorX = 0; + cursorY += textSize * (FONTHEIGHT + 1); + } + if((cursorY + FONTHEIGHT) > HEIGHT){ // If we have reached the bottom of the screen, start back at the top + cursorY = 0; + cursorX = 0; + } + // Draw the character at the cursor coordinates + YEEP144_SSD1306_DrawChar(cursorX, cursorY, c, textColour, textBGColour, textSize); + + // Move the cursor forward by one character + cursorX += (FONTWIDTH + 1) * textSize; + } + } + + // Free the memory used + free(buffer); + + // Return number of characters printed + return bufSize; +} + +/** + * Draws a single character to the screen, with the specified coordinates being the top left of the character + * Uses the specified text colour, background colour and size multiplier + */ +void YEEP144_SSD1306_DrawChar(uint8_t x, uint8_t y, uint8_t c, uint8_t colour, uint8_t bg, uint8_t size){ + + if ((x >= WIDTH) || // Clip right + (y >= HEIGHT) || // Clip bottom + ((x + 6 * size - 1) < 0) || // Clip left + ((y + 8 * size - 1) < 0)) // Clip top + return; + + for (int8_t i = 0; i < 5; i++) { // Char bitmap = 5 columns + uint8_t line = font[c * 5 + i]; + for (int8_t j = 0; j < 8; j++, line >>= 1) { + if (line & 1) { + if (size == 1) + YEEP144_SSD1306_SetPixel(x + i, y + j, colour); + else + YEEP144_SSD1306_DrawFillRect(x + i * size, y + j * size, size, size, colour); + } else if (bg != colour) { + if (size == 1) + YEEP144_SSD1306_SetPixel(x + i, y + j, bg); + else + YEEP144_SSD1306_DrawFillRect(x + i * size, y + j * size, size, size, bg); + } + } + } + if (bg != colour) { // If opaque, draw vertical line for last column + if (size == 1) + YEEP144_SSD1306_DrawFastVLine(x + 5, y, 8, bg); + else + YEEP144_SSD1306_DrawFillRect(x + 5 * size, y, size, 8 * size, bg); + } +} + +/** + * Sets the text scaling. + * 1 = Normal, 4 lines will fit on display + * 2 = 2 lines will fit + * 4 = 1 line will fit + */ +void YEEP144_SSD1306_SetTextSize(uint8_t size){ + textSize = size; +} + +/** + * Set the position of the cursor + * The coordinates defire the top left corner of the character + */ +void YEEP144_SSD1306_SetTextCursor(uint8_t x, uint8_t y){ + cursorX = x; + cursorY = y; +} + +/** + * Enable or disable text line wrapping + * 0 is disabled, 1 is enabled + */ +void YEEP144_SSD1306_SetTextWrap(uint8_t wrap){ + textWrap = wrap; +} + +/** + * Draws a 1-bit bitmap to the screen at the specified position + */ +void YEEP144_SSD1306_DrawBitmap(uint8_t x, uint8_t y, const uint8_t bitmap[], uint8_t w, uint8_t h){ + uint8_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte + uint8_t b = 0; + + for (uint8_t j = 0; j < h; j++, y++) { + for (uint8_t i = 0; i < w; i++) { + if (i & 7){ + b <<= 1; + } + else{ + b = bitmap[j * byteWidth + i / 8]; + } + YEEP144_SSD1306_SetPixel(x + i, y, (b & 0x80) ? SSD1306_WHITE : SSD1306_BLACK); + } + } +} + +/** + * Inverts the colours of the display. Note that this happens using a hardware command to the display + * and doesn't touch the buffer + */ +void YEEP144_SSD1306_InvertDisplay(bool i){ + YEEP144_SSD1306_SendCommand(i ? SSD1306_INVERTDISPLAY : SSD1306_NORMALDISPLAY); +} + +/** + * Helper function that sends a single command to the display + */ +void YEEP144_SSD1306_SendCommand(uint8_t command){ + + // For data to be recognised as a command, the I2C transaction must start with 0x00 + uint8_t data[] = {0x00, command}; + + // Transmit the data + HAL_I2C_Master_Transmit(&hi2c2, SSD1306_ADDR, data, 2, I2C_TIMEOUT); +} + +/* +Much of this code was taken from or inspired by the Adafruit_SSD1306 and Adafruit_GFX libraries, +adapted for use on STM32 rather than the Arduino platform. For that code the following disclaimer applies: + +Copyright (c) 2013 Adafruit Industries. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + */ \ No newline at end of file diff --git a/YEEP144lib/src/YEEP144_Servo.c b/YEEP144lib/src/YEEP144_Servo.c new file mode 100644 index 0000000..359ca35 --- /dev/null +++ b/YEEP144lib/src/YEEP144_Servo.c @@ -0,0 +1,313 @@ +#include "YEEP144.h" +#include "YEEP144_Servo.h" + +#include "YEEP144_Pinout.h" +#include "stm32h563xx.h" +#include "stm32h5xx_hal.h" +#include "stm32h5xx_hal_gpio.h" +#include "stm32h5xx_hal_gpio_ex.h" +#include "stm32h5xx_hal_rcc.h" +#include "stm32h5xx_hal_tim.h" + +#include + +TIM_HandleTypeDef htim5; +TIM_HandleTypeDef htim13; +TIM_HandleTypeDef htim17servo; + +uint16_t servoMinTicks[4] = {2048, 2048, 2048, 2048}; +uint16_t servoMaxTicks[4] = {4095, 4095, 4095, 4095}; +float servoMinDegrees[4] = {0, 0, 0, 0}; +float servoMaxDegrees[4] = {180, 180, 180, 180}; + +uint16_t YEEP144_Servo_MapAngleToTicks(float angle, float minAngle, float maxAngle, uint16_t minTicks, uint16_t maxTicks); + +/** + * Initialises servos 1 and 2. This consumes timer 5 and two GPIO + */ +void YEEP144_Servo_Init1_2(void){ + + // Enable clock to TIM5 + __HAL_RCC_TIM5_CLK_ENABLE(); + + // Configure and initialise TIM5 + // Servo PWM is a 1ms - 2ms pulse every 20ms + // This is done using a 50Hz PWM with a duty cycle between 5 and 10% + // Our ARR is set to 40950, the range of the ADC is 0-4095, /2 = 2048, which represents 5% of the total range + // Offsetting by 2048 means we cover the 5 to 10% range + TIM_MasterConfigTypeDef sMasterConfig = {0}; + TIM_OC_InitTypeDef sConfigOC = {0}; + + htim5.Instance = TIM5; + htim5.Init.Prescaler = 121; + htim5.Init.CounterMode = TIM_COUNTERMODE_UP; + htim5.Init.Period = 40950; + htim5.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim5.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + if (HAL_TIM_PWM_Init(&htim5) != HAL_OK){ + //Error_Handler(); + } + + // Disable synchronisation as it is not needed + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if (HAL_TIMEx_MasterConfigSynchronization(&htim5, &sMasterConfig) != HAL_OK){ + //Error_Handler(); + } + + // Configure the two used PWM channels + sConfigOC.OCMode = TIM_OCMODE_PWM1; + sConfigOC.Pulse = 0; + sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; + sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; + if (HAL_TIM_PWM_ConfigChannel(&htim5, &sConfigOC, TIM_CHANNEL_1) != HAL_OK){ + //Error_Handler(); + } + if (HAL_TIM_PWM_ConfigChannel(&htim5, &sConfigOC, TIM_CHANNEL_4) != HAL_OK){ + //Error_Handler(); + } + + // Configure GPIOs + YEEP144_GPIO_InitAdv(SERVO1_PORT, SERVO1_PIN | SERVO2_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW, GPIO_AF2_TIM5); + + HAL_TIM_PWM_Start(&htim5, TIM_CHANNEL_1); + HAL_TIM_PWM_Start(&htim5, TIM_CHANNEL_4); + +} + +/** + * Initialises servo 3. This consumes timer 13 and one GPIO + */ +void YEEP144_Servo_Init3(void){ + // Enable clock to TIM13 + __HAL_RCC_TIM13_CLK_ENABLE(); + + // Configure and initialise TIM13 + // Servo PWM is a 1ms - 2ms pulse every 20ms + // This is done using a 50Hz PWM with a duty cycle between 5 and 10% + // Our ARR is set to 40950, the range of the ADC is 0-4095, /2 = 2048, which represents 5% of the total range + // Offsetting by 2048 means we cover the 5 to 10% range + TIM_MasterConfigTypeDef sMasterConfig = {0}; + TIM_OC_InitTypeDef sConfigOC = {0}; + + htim13.Instance = TIM13; + htim13.Init.Prescaler = 121; + htim13.Init.CounterMode = TIM_COUNTERMODE_UP; + htim13.Init.Period = 40950; + htim13.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim13.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + if (HAL_TIM_PWM_Init(&htim13) != HAL_OK){ + //Error_Handler(); + } + + // Disable synchronisation as it is not needed + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if (HAL_TIMEx_MasterConfigSynchronization(&htim13, &sMasterConfig) != HAL_OK){ + //Error_Handler(); + } + + // Configure the two used PWM channels + sConfigOC.OCMode = TIM_OCMODE_PWM1; + sConfigOC.Pulse = 0; + sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; + sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; + if (HAL_TIM_PWM_ConfigChannel(&htim13, &sConfigOC, TIM_CHANNEL_1) != HAL_OK){ + //Error_Handler(); + } + + // Configure GPIOs + YEEP144_GPIO_InitAdv(SERVO3_PORT, SERVO3_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW, GPIO_AF9_TIM13); + + HAL_TIM_PWM_Start(&htim13, TIM_CHANNEL_1); +} + +/** + * Initialises servo 4. This consumes timer 17 and one GPIO. These resources are share with the buzzer. + * Ensure only one is initialised. When using servo 4, disable the buzzer using DIP switch SW5 so the + * PWM signal is not made audible + */ +void YEEP144_Servo_Init4(void){ + // Enable clock to TIM17 + __HAL_RCC_TIM17_CLK_ENABLE(); + + // Configure and initialise TIM17 + // Servo PWM is a 1ms - 2ms pulse every 20ms + // This is done using a 50Hz PWM with a duty cycle between 5 and 10% + // Our ARR is set to 40950, the range of the ADC is 0-4095, /2 = 2048, which represents 5% of the total range + // Offsetting by 2048 means we cover the 5 to 10% range + TIM_MasterConfigTypeDef sMasterConfig = {0}; + TIM_OC_InitTypeDef sConfigOC = {0}; + + htim17servo.Instance = TIM17; + htim17servo.Init.Prescaler = 121; + htim17servo.Init.CounterMode = TIM_COUNTERMODE_UP; + htim17servo.Init.Period = 40950; + htim17servo.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim17servo.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + if (HAL_TIM_PWM_Init(&htim17servo) != HAL_OK){ + //Error_Handler(); + } + + // Disable synchronisation as it is not needed + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if (HAL_TIMEx_MasterConfigSynchronization(&htim17servo, &sMasterConfig) != HAL_OK){ + //Error_Handler(); + } + + // Configure the two used PWM channels + sConfigOC.OCMode = TIM_OCMODE_PWM1; + sConfigOC.Pulse = 0; + sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; + sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; + if (HAL_TIM_PWM_ConfigChannel(&htim17servo, &sConfigOC, TIM_CHANNEL_1) != HAL_OK){ + //Error_Handler(); + } + + // Configure GPIOs + YEEP144_GPIO_InitAdv(SERVO4_PORT, SERVO4_PIN, GPIO_MODE_AF_PP, GPIO_NOPULL, GPIO_SPEED_FREQ_LOW, GPIO_AF1_TIM17); + + HAL_TIM_PWM_Start(&htim17servo, TIM_CHANNEL_1); +} + +/** + * Sets the zero point for a given servo + * + * Default configuration is 2048, yielding a 5% to 10% duty cycle, or 1ms - 2ms pulse, which is the typical standard + * Adjusting the zero offset can help account for differences in servos + * that means 5% duty cycle does not exactly reach 0 degrees + * + * The offset applies to both SetDirect and SetAngle + */ +void YEEP144_Servo_SetMinTicks(uint8_t servo, uint16_t min){ + if(servo == 0 || servo >= 4) return; + servoMinTicks[servo-1] = min; +} + +/** + * Sets the max point for a given servo + * + * Default configuration is 4096, yielding a 5% to 10% duty cycle, or 1ms - 2ms pulse, which is the typical standard + * Adjusting the max offset can help account for differences in servos + * that means 10% duty cycle does not exactly reach 180 degrees + * + * This only applies when using SetAngle. SetDirect has no limit on what you can set + */ +void YEEP144_Servo_SetMaxTicks(uint8_t servo, uint16_t max){ + if(servo == 0 || servo >= 4) return; + servoMaxTicks[servo-1] = max; +} + +/** + * Sets the minimum angle range for a given servo + * + * Default is 0, for 0-180deg servos + * + * This only applies to SetAngle + */ +void YEEP144_Servo_SetMinAngle(uint8_t servo, float min){ + if(servo == 0 || servo >= 4) return; + servoMinDegrees[servo-1] = min; +} + +/** + * Sets the maximum angle range for a given servo + * + * Default is 180, for 0-180deg servos + * + * This only applies to SetAngle + */ +void YEEP144_Servo_SetMaxAngle(uint8_t servo, float max){ + if(servo == 0 || servo >= 4) return; + servoMaxDegrees[servo-1] = max; +} + +/** + * Directly set the pulse value of the timer to control the position of the servo + * Typically this should be in the range 0-2047 + * The function will accept larger pulse values, which will result in a duty cycle >10%, or a pulse of >2ms + * This may be useful for servos who's maximum angle is not achieved at 10% + * Along with setting the zero offset, this should account for troublesome servos, albeit with less elegant maths + */ +void YEEP144_Servo1_SetDirect(uint16_t pulse){ + TIM5->CCR1 = pulse + servoMinTicks[0]; +} + +/** + * Directly set the pulse value of the timer to control the position of the servo + * Typically this should be in the range 0-2047 + * The function will accept larger pulse values, which will result in a duty cycle >10%, or a pulse of >2ms + * This may be useful for servos who's maximum angle is not achieved at 10% + * Along with setting the zero offset, this should account for troublesome servos, albeit with less elegant maths + */ +void YEEP144_Servo2_SetDirect(uint16_t pulse){ + TIM5->CCR4 = pulse + servoMinTicks[1]; +} + +/** + * Directly set the pulse value of the timer to control the position of the servo + * Typically this should be in the range 0-2047 + * The function will accept larger pulse values, which will result in a duty cycle >10%, or a pulse of >2ms + * This may be useful for servos who's maximum angle is not achieved at 10% + * Along with setting the zero offset, this should account for troublesome servos, albeit with less elegant maths + */ +void YEEP144_Servo3_SetDirect(uint16_t pulse){ + TIM13->CCR1 = pulse + servoMinTicks[2]; +} + +/** + * Directly set the pulse value of the timer to control the position of the servo + * Typically this should be in the range 0-2047 + * The function will accept larger pulse values, which will result in a duty cycle >10%, or a pulse of >2ms + * This may be useful for servos who's maximum angle is not achieved at 10% + * Along with setting the zero offset, this should account for troublesome servos, albeit with less elegant maths + */ +void YEEP144_Servo4_SetDirect(uint16_t pulse){ + TIM17->CCR1 = pulse + servoMinTicks[3]; +} + +/** + * Set the servo to a specified angle. This will be based on the minimum and maximum angles set for the servo + * By default this will work in the range 0 to 180 + */ +void YEEP144_Servo1_SetAngle(float angle){ + if(angle < servoMinDegrees[0] || angle > servoMaxDegrees[0]) return; // If the angle is out of range, do nothing + TIM5->CCR1 = YEEP144_Servo_MapAngleToTicks(angle, servoMinDegrees[0], servoMaxDegrees[0], servoMinTicks[0], servoMaxTicks[0]); +} + +/** + * Set the servo to a specified angle. This will be based on the minimum and maximum angles set for the servo + * By default this will work in the range 0 to 180 + */ +void YEEP144_Servo2_SetAngle(float angle){ + if(angle < servoMinDegrees[1] || angle > servoMaxDegrees[1]) return; // If the angle is out of range, do nothing + TIM5->CCR1 = YEEP144_Servo_MapAngleToTicks(angle, servoMinDegrees[1], servoMaxDegrees[1], servoMinTicks[1], servoMaxTicks[1]); +} + +/** + * Set the servo to a specified angle. This will be based on the minimum and maximum angles set for the servo + * By default this will work in the range 0 to 180 + */ +void YEEP144_Servo3_SetAngle(float angle){ + if(angle < servoMinDegrees[0] || angle > servoMaxDegrees[0]) return; // If the angle is out of range, do nothing + TIM5->CCR1 = YEEP144_Servo_MapAngleToTicks(angle, servoMinDegrees[0], servoMaxDegrees[0], servoMinTicks[0], servoMaxTicks[0]); +} + +/** + * Set the servo to a specified angle. This will be based on the minimum and maximum angles set for the servo + * By default this will work in the range 0 to 180 + */ +void YEEP144_Servo4_SetAngle(float angle){ + if(angle < servoMinDegrees[0] || angle > servoMaxDegrees[0]) return; // If the angle is out of range, do nothing + TIM5->CCR1 = YEEP144_Servo_MapAngleToTicks(angle, servoMinDegrees[0], servoMaxDegrees[0], servoMinTicks[0], servoMaxTicks[0]); +} + +/** + * Helper function used to map a float angle to a timer tick value, based on the min and max ranges specified + * e.g. map the angle 90 from the range 0 to 180, into the range 2048 - 4095 + */ +uint16_t YEEP144_Servo_MapAngleToTicks(float angle, float minAngle, float maxAngle, uint16_t minTicks, uint16_t maxTicks){ + // Map the angle value into the tick range using the min and max parameters + return (uint16_t)(( ((angle - minAngle) * (maxTicks - minTicks)) / (maxAngle - minAngle) ) + minTicks); +} \ No newline at end of file diff --git a/YEEP144lib/src/YEEP144_TSOP4838.c b/YEEP144lib/src/YEEP144_TSOP4838.c new file mode 100644 index 0000000..0057b7f --- /dev/null +++ b/YEEP144lib/src/YEEP144_TSOP4838.c @@ -0,0 +1,143 @@ +#include "YEEP144.h" +#include "YEEP144_Pinout.h" +#include "YEEP144_DebugUART.h" + +#define ASCII_ESC 27 + +// NEC Protocol Timing Constants (in microseconds) +#define NEC_START_LOW 9000 // 9ms leading pulse +#define NEC_START_HIGH 4500 // 4.5ms space +#define NEC_BIT_LOW 560 // 560us burst +#define NEC_BIT_ONE_HIGH 1690 // 1.69ms space for logical 1 +#define NEC_BIT_ZERO_HIGH 560 // 560us space for logical 0 +#define NEC_TOLERANCE 400 // +/- margin of error + +// State Machine States +typedef enum{ + IR_STATE_IDLE, + IR_STATE_LEADER, + IR_STATE_DATA +} IR_State_t; + +// Variables +volatile IR_State_t ir_state = IR_STATE_IDLE; +volatile uint32_t ir_last_time = 0; +volatile uint32_t ir_raw_bits = 0; +volatile uint8_t ir_bit_count = 0; +volatile uint8_t ir_code_ready = 0; +volatile uint32_t ir_code = 0; + +// Enable hardware DWT (Data Watchpoint and Trace) cycle counter +void DWT_Init(void) { + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + DWT->CYCCNT = 0; + DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; +} + +// Arduino-style microsecond measurement +uint32_t micros(void) { + return DWT->CYCCNT / (SystemCoreClock / 1000000); +} + +// This exact function name matches the STM32H563 hardware vector table entry +void EXTI3_IRQHandler(void) +{ + // Tells the HAL layer to clear the flag and fire your callback routine + HAL_GPIO_EXTI_IRQHandler(IR_RECEIVER_PIN); +} + +void YEEP144_TSOP4838_Init(){ + GPIO_InitTypeDef GPIO_InitStruct = {0}; + + // Enable DWT for microsecond timing + DWT_Init(); + + // Configure Pin F3 for Interrupt on Both Edges + GPIO_InitStruct.Pin = IR_RECEIVER_PIN; + GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; // Triggers on rising or falling change + GPIO_InitStruct.Pull = GPIO_NOPULL; // Uses the TSOP4838 internal pull-up + HAL_GPIO_Init(IR_RECEIVER_PORT, &GPIO_InitStruct); + + // Enable and set EXTI Line 3 Vector for STM32H563 + HAL_NVIC_SetPriority(IR_RECEIVER_EXTI, 2, 0); + HAL_NVIC_EnableIRQ(IR_RECEIVER_EXTI); +} + +uint8_t YEEP144_TSOP4838_Received(void){ + return ir_code_ready; +} + +uint32_t YEEP144_TSOP4838_Read(void){ + return ir_code; + ir_code_ready = 0; +} + +// These functions override the weak HAL geometric EXTI callbacks +void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin){ + if (GPIO_Pin == IR_RECEIVER_PIN) + { + uint32_t current_time = micros(); + uint32_t duration = current_time - ir_last_time; + ir_last_time = current_time; + switch(ir_state) { + case IR_STATE_LEADER: // Rising edge (End of 9ms pulse) + if (duration < (NEC_START_LOW - NEC_TOLERANCE) || duration > (NEC_START_LOW + NEC_TOLERANCE)){ + ir_state = IR_STATE_IDLE; // False start + } + break; + case IR_STATE_IDLE: + break; + case IR_STATE_DATA: + break; + } + } +} + +// For newer STM32 HAL libraries, rising and falling callbacks are separated for memory efficiency +void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin){ + if (GPIO_Pin == IR_RECEIVER_PIN) + { + uint32_t current_time = micros(); + uint32_t duration = current_time - ir_last_time; + ir_last_time = current_time; + switch(ir_state){ + case IR_STATE_IDLE: // Falling edge (Start of 9ms pulse) + ir_state = IR_STATE_LEADER; + break; + case IR_STATE_LEADER: // Falling edge (End of 4.5ms space) + if (duration >= (NEC_START_HIGH - NEC_TOLERANCE) && duration <= (NEC_START_HIGH + NEC_TOLERANCE)){ + ir_state = IR_STATE_DATA; + ir_bit_count = 0; + ir_raw_bits = 0; + } else { + ir_state = IR_STATE_IDLE; // Invalid preamble + } + break; + case IR_STATE_DATA: // Falling edge (End of a data bit's high space) + // The high duration determines if the bit is a 0 or a 1 + if (duration >= (NEC_BIT_ZERO_HIGH - NEC_TOLERANCE) && duration <= (NEC_BIT_ZERO_HIGH + NEC_TOLERANCE)) { + ir_raw_bits >>= 1; // It's a 0 + ir_bit_count++; + } + else if (duration >= (NEC_BIT_ONE_HIGH - NEC_TOLERANCE) && duration <= (NEC_BIT_ONE_HIGH + NEC_TOLERANCE)) { + ir_raw_bits >>= 1; + ir_raw_bits |= 0x80000000; // It's a 1 + ir_bit_count++; + } + else { + ir_state = IR_STATE_IDLE; // Timing error, reset state + } + + uint32_t ir_bits = 0; + if (ir_bit_count == 32) { + ir_bits = ir_raw_bits; + ir_code = (ir_bits >> 16) & 0xFF; + uint32_t command_inverse = (ir_bits >> 24) & 0xFF; + if (ir_code == (uint8_t)(~command_inverse)) + ir_code_ready = 1; + ir_state = IR_STATE_IDLE; + } + break; + } + } +} diff --git a/cmake/gnu-tools-for-stm32.cmake b/cmake/gnu-tools-for-stm32.cmake new file mode 100644 index 0000000..68ff597 --- /dev/null +++ b/cmake/gnu-tools-for-stm32.cmake @@ -0,0 +1,159 @@ +# ----------------------------------------------------------------------------- +# @author STM32Cube bundle system +# ----------------------------------------------------------------------------- +# @attention +# +# Copyright (c) 2025 STMicroelectronics. +# All rights reserved. +# +# This software is licensed under terms that can be found in the LICENSE file +# in the root directory of this software component. +# If no LICENSE file comes with this software, it is provided AS-IS. +# +# ----------------------------------------------------------------------------- + +# This file describes GNU Tools for STM32 Toolchain. +# +# - Applies to toolchain: GNU Tools for STM32 Toolchain 13.3.1 and greater + +set(CMAKE_SYSTEM_NAME Generic) +set(CMAKE_SYSTEM_PROCESSOR arm) + +# Some target device related default GCC settings +if(CMSIS_Dcore STREQUAL "Cortex-M0") + set(CPU_FLAGS -mcpu=cortex-m0) +elseif(CMSIS_Dcore STREQUAL "Cortex-M0+") + set(CPU_FLAGS -mcpu=cortex-m0plus) +elseif(CMSIS_Dcore STREQUAL "Cortex-M1") + set(CPU_FLAGS -mcpu=cortex-m1) +elseif(CMSIS_Dcore STREQUAL "Cortex-M3") + set(CPU_FLAGS -mcpu=cortex-m3) +elseif(CMSIS_Dcore STREQUAL "Cortex-M4") + if(CMSIS_Dfpu STREQUAL "SP_FPU") + set(CPU_FLAGS -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard) + else() + set(CPU_FLAGS -mcpu=cortex-m4) + endif() +elseif(CMSIS_Dcore STREQUAL "Cortex-M7") + if(CMSIS_Dfpu STREQUAL "DP_FPU") + set(CPU_FLAGS -mcpu=cortex-m7 -mfpu=fpv5-d16 -mfloat-abi=hard) + elseif(CMSIS_Dfpu STREQUAL "SP_FPU") + set(CPU_FLAGS -mcpu=cortex-m7 -mfpu=fpv5-sp-d16 -mfloat-abi=hard) + else() + set(CPU_FLAGS -mcpu=cortex-m7) + endif() +elseif(CMSIS_Dcore STREQUAL "Cortex-M23") + set(CPU_FLAGS -mcpu=cortex-m23) +elseif(CMSIS_Dcore STREQUAL "Cortex-M33") + if(CMSIS_Dfpu STREQUAL "SP_FPU") + if(CMSIS_Ddsp STREQUAL "DSP") + set(CPU_FLAGS -mcpu=cortex-m33 -mfpu=fpv5-sp-d16 -mfloat-abi=hard) + else() + set(CPU_FLAGS -mcpu=cortex-m33+nodsp -mfpu=fpv5-sp-d16 -mfloat-abi=hard) + endif() + else() + if(CMSIS_Ddsp STREQUAL "DSP") + set(CPU_FLAGS -mcpu=cortex-m33) + else() + set(CPU_FLAGS -mcpu=cortex-m33+nodsp) + endif() + endif() +elseif(CMSIS_Dcore STREQUAL "Cortex-M35P") + if(CMSIS_Dfpu STREQUAL "SP_FPU") + if(CMSIS_Ddsp STREQUAL "DSP") + set(CPU_FLAGS -mcpu=cortex-m35p -mfpu=fpv5-sp-d16 -mfloat-abi=hard) + else() + set(CPU_FLAGS -mcpu=cortex-m35p+nodsp -mfpu=fpv5-sp-d16 -mfloat-abi=hard) + endif() + else() + if(CMSIS_Ddsp STREQUAL "DSP") + set(CPU_FLAGS -mcpu=cortex-m35p) + else() + set(CPU_FLAGS -mcpu=cortex-m35p+nodsp) + endif() + endif() +elseif(CMSIS_Dcore STREQUAL "Cortex-M55") + if(CMSIS_Dfpu STREQUAL "NO_FPU") + if(CMSIS_Dmve STREQUAL "NO_MVE") + set(CPU_FLAGS -mcpu=cortex-m55+nofp+nomve) + else() + set(CPU_FLAGS -mcpu=cortex-m55+nofp) + endif() + else() + if(CMSIS_Dmve STREQUAL "NO_MVE") + set(CPU_FLAGS -mcpu=cortex-m55+nomve -mfloat-abi=hard) + elseif(CMSIS_Dmve STREQUAL "MVE") + set(CPU_FLAGS -mcpu=cortex-m55+nomve.fp -mfloat-abi=hard) + else() + set(CPU_FLAGS -mcpu=cortex-m55 -mfloat-abi=hard) + endif() + endif() +elseif(CMSIS_Dcore STREQUAL "Cortex-M85") + if(CMSIS_Dfpu STREQUAL "NO_FPU") + if(CMSIS_Dmve STREQUAL "NO_MVE") + set(CPU_FLAGS -mcpu=cortex-m85+nofp+nomve) + else() + set(CPU_FLAGS -mcpu=cortex-m85+nofp) + endif() + else() + if(CMSIS_Dmve STREQUAL "NO_MVE") + set(CPU_FLAGS -mcpu=cortex-m85+nomve -mfloat-abi=hard) + elseif(CMSIS_Dmve STREQUAL "MVE") + set(CPU_FLAGS -mcpu=cortex-m85+nomve.fp -mfloat-abi=hard) + else() + set(CPU_FLAGS -mcpu=cortex-m85 -mfloat-abi=hard) + endif() + endif() +elseif(CMSIS_Dcore STREQUAL "Cortex-A5") + if(CMSIS_Dfpu STREQUAL "DP_FPU") + set(CPU_FLAGS -mcpu=cortex-a5+nosimd -mfpu=auto -mfloat-abi=hard) + else() + set(CPU_FLAGS -mcpu=cortex-a5+nosimd+nofp) + endif() +elseif(CMSIS_Dcore STREQUAL "Cortex-A7") + if(CMSIS_Dfpu STREQUAL "DP_FPU") + set(CPU_FLAGS -mcpu=cortex-a7+nosimd -mfpu=auto -mfloat-abi=hard) + else() + set(CPU_FLAGS -mcpu=Cortex-a7+nosimd+nofp) + endif() +elseif(CMSIS_Dcore STREQUAL "Cortex-A9") + if(CMSIS_Dfpu STREQUAL "DP_FPU") + set(CPU_FLAGS -mcpu=cortex-a9+nosimd -mfpu=auto -mfloat-abi=hard) + else() + set(CPU_FLAGS -mcpu=cortex-a9+nosimd+nofp) + endif() +endif() + +if(CMSIS_Dendian STREQUAL "Little-endian") + set(CPU_FLAGS ${CPU_FLAGS} -mlittle-endian) +elseif(CMSIS_Dendian STREQUAL "Big-endian") + set(CPU_FLAGS ${CPU_FLAGS} -mbig-endian) +endif() + +set(CPU_FLAGS ${CPU_FLAGS} -mthumb) + +# Some C Pre-Processor related default GCC settings +if(CMSIS_Dsecure STREQUAL "Secure" OR CMSIS_Dsecure STREQUAL "Secure-only") + set(SECURE_FLAGS "-mcmse") +endif() + +# Some default GCC settings +# arm-none-eabi- must be part of path environment +set(TOOLCHAIN_PREFIX arm-none-eabi-) +set(FLAGS "-fdata-sections -ffunction-sections -Wl,--gc-sections -Wno-comment") +set(CPP_FLAGS "${FLAGS} -fno-rtti -fno-exceptions -fno-threadsafe-statics") + +set(CMAKE_C_FLAGS ${FLAGS}) +set(CMAKE_CXX_FLAGS ${CPP_FLAGS}) + +set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}gcc) +set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) +set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}g++) +set(CMAKE_OBJCOPY ${TOOLCHAIN_PREFIX}objcopy) +set(CMAKE_SIZE ${TOOLCHAIN_PREFIX}size) + +set(CMAKE_EXECUTABLE_SUFFIX_ASM ".elf") +set(CMAKE_EXECUTABLE_SUFFIX_C ".elf") +set(CMAKE_EXECUTABLE_SUFFIX_CXX ".elf") + +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) \ No newline at end of file diff --git a/cmake/vscode_generated.cmake b/cmake/vscode_generated.cmake new file mode 100644 index 0000000..f57c379 --- /dev/null +++ b/cmake/vscode_generated.cmake @@ -0,0 +1,64 @@ +# ----------------------------------------------------------------------------- +# @author Auto-generated by STM32CubeIDE for Visual Studio Code Extension +# ----------------------------------------------------------------------------- +# @attention +# +# Copyright (c) 2025 STMicroelectronics. +# All rights reserved. +# +# This software is licensed under terms that can be found in the LICENSE file +# in the root directory of this software component. +# If no LICENSE file comes with this software, it is provided AS-IS. +# +# ----------------------------------------------------------------------------- + +# This is converter generated file, and shall not be touched by user +# +# Use CMakeLists.txt to apply user changes +cmake_minimum_required(VERSION 3.20) + +# Core MCU flags, CPU, instruction set and FPU setup +set(cpu_PARAMS ${CPU_FLAGS} ${cpu_PARAMS}) + +# Linker script +set(linker_script_SRC ${linker_script_SRC} + ${CMAKE_CURRENT_SOURCE_DIR}/stm32h563xi_flash.ld +) + +# Sources +set(sources_SRCS ${sources_SRCS} + ${CMAKE_CURRENT_SOURCE_DIR}/src/syscall.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/sysmem.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/startup_stm32h563xx.S +) + +# Include directories +set(include_c_DIRS ${include_c_DIRS} +) +set(include_cxx_DIRS ${include_cxx_DIRS} +) +set(include_asm_DIRS ${include_asm_DIRS} +) + +# Symbols definition +set(symbols_c_SYMB ${symbols_c_SYMB} + RTE_DEVICE_STARTUP_STM32H5XX +) +set(symbols_cxx_SYMB ${symbols_cxx_SYMB} +) +set(symbols_asm_SYMB ${symbols_asm_SYMB} +) + +# Link directories +set(link_DIRS ${link_DIRS} +) + +# Link libraries +set(link_LIBS ${link_LIBS} +) + +# Compiler options +set(compiler_OPTS ${compiler_OPTS} ${SECURE_FLAGS}) + +# Linker options +set(linker_OPTS ${linker_OPTS}) diff --git a/include/stm32h5xx_hal_conf.h b/include/stm32h5xx_hal_conf.h new file mode 100644 index 0000000..b581c49 --- /dev/null +++ b/include/stm32h5xx_hal_conf.h @@ -0,0 +1,522 @@ +/* USER CODE BEGIN Header */ +/** + ********************************************************************************************************************** + + * @file stm32h5xx_hal_conf.h + * @author MCD Application Team + * @brief HAL configuration file. + ********************************************************************************************************************** + + * @attention + * + * Copyright (c) 2023 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ********************************************************************************************************************** + + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -----------------------------------------------------------------------------*/ + +#ifndef STM32H5xx_HAL_CONF_H +#define STM32H5xx_HAL_CONF_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Exported types ----------------------------------------------------------------------------------------------------*/ +/* Exported constants ------------------------------------------------------------------------------------------------*/ + +/* ########################################### Module Selection ##################################################### */ + +/** + * @brief This is the list of modules to be used in the HAL driver + */ + +#define HAL_MODULE_ENABLED +/*#define HAL_CCB_MODULE_ENABLED */ +#define HAL_ADC_MODULE_ENABLED +/*#define HAL_CEC_MODULE_ENABLED */ +/*#define HAL_COMP_MODULE_ENABLED */ +/*#define HAL_CORDIC_MODULE_ENABLED */ +/*#define HAL_CRC_MODULE_ENABLED */ +/*#define HAL_CRYP_MODULE_ENABLED */ +/*#define HAL_DAC_MODULE_ENABLED */ +/*#define HAL_DCACHE_MODULE_ENABLED */ +/*#define HAL_DCMI_MODULE_ENABLED */ +/*#define HAL_DTS_MODULE_ENABLED */ +/*#define HAL_ETH_MODULE_ENABLED */ +/*#define HAL_FDCAN_MODULE_ENABLED */ +/*#define HAL_FMAC_MODULE_ENABLED */ +/*#define HAL_GTZC_MODULE_ENABLED */ +/*#define HAL_HASH_MODULE_ENABLED */ +/*#define HAL_HCD_MODULE_ENABLED */ +/*#define HAL_IRDA_MODULE_ENABLED */ +/*#define HAL_IWDG_MODULE_ENABLED */ +#define HAL_I2C_MODULE_ENABLED +/*#define HAL_I3C_MODULE_ENABLED */ +/*#define HAL_I2S_MODULE_ENABLED */ +#define HAL_LPTIM_MODULE_ENABLED +/*#define HAL_NAND_MODULE_ENABLED */ +/*#define HAL_NOR_MODULE_ENABLED */ +/*#define HAL_OPAMP_MODULE_ENABLED */ +/*#define HAL_XSPI_MODULE_ENABLED */ +/*#define HAL_OTFDEC_MODULE_ENABLED */ +/*#define HAL_PKA_MODULE_ENABLED */ +/*#define HAL_RNG_MODULE_ENABLED */ +/*#define HAL_RTC_MODULE_ENABLED */ +/*#define HAL_SAI_MODULE_ENABLED */ +/*#define HAL_SD_MODULE_ENABLED */ +#define HAL_SDIO_MODULE_ENABLED +/*#define HAL_SDRAM_MODULE_ENABLED */ +/*#define HAL_MMC_MODULE_ENABLED */ +/*#define HAL_SMARTCARD_MODULE_ENABLED */ +/*#define HAL_SMBUS_MODULE_ENABLED */ +#define HAL_SPI_MODULE_ENABLED +/*#define HAL_SRAM_MODULE_ENABLED */ +#define HAL_TIM_MODULE_ENABLED +/*#define HAL_RAMCFG_MODULE_ENABLED */ +#define HAL_UART_MODULE_ENABLED +#define HAL_USART_MODULE_ENABLED +/*#define HAL_WWDG_MODULE_ENABLED */ +/*#define HAL_PSSI_MODULE_ENABLED */ +#define HAL_ICACHE_MODULE_ENABLED +/*#define HAL_PCD_MODULE_ENABLED */ +#define HAL_GPIO_MODULE_ENABLED +#define HAL_EXTI_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED + +/* ####################################### Oscillator Values adaptation ##############################################*/ + +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your application. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSE is used as system clock source, directly or through the PLL). + */ +#if !defined (HSE_VALUE) + #define HSE_VALUE 8000000U /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (HSE_STARTUP_TIMEOUT) + #define HSE_STARTUP_TIMEOUT 100U /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal Core Speed oscillator (CSI) default value. + * This value is the default CSI range value after Reset. + */ +#if !defined (CSI_VALUE) + #define CSI_VALUE 4000000UL /*!< Value of the Internal oscillator in Hz*/ +#endif /* CSI_VALUE */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system frequency + * (when HSI is used as system clock source, directly or through the PLL). + */ +#if !defined (HSI_VALUE) + #define HSI_VALUE 64000000UL /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal High Speed oscillator (HSI48) value for USB FS, SDMMC and RNG. + * This internal oscillator is mainly dedicated to provide a high precision clock to + * the USB peripheral by means of a special Clock Recovery System (CRS) circuitry. + * When the CRS is not used, the HSI48 RC oscillator runs on it default frequency + * which is subject to manufacturing process variations. + */ +#if !defined (HSI48_VALUE) + #define HSI48_VALUE 48000000UL /*!< Value of the Internal High Speed oscillator for USB FS/SDMMC/RNG in Hz. + The real value my vary depending on manufacturing process variations.*/ +#endif /* HSI48_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined (LSI_VALUE) + #define LSI_VALUE 32000UL /*!< LSI Typical Value in Hz*/ +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz + The real value may vary depending on the variations + in voltage and temperature.*/ + +#if !defined (LSI_STARTUP_TIME) + #define LSI_STARTUP_TIME 130UL /*!< Time out for LSI start up, in us */ +#endif /* LSI_STARTUP_TIME */ + +/** + * @brief External Low Speed oscillator (LSE) value. + * This value is used by the UART, RTC HAL module to compute the system frequency + */ +#if !defined (LSE_VALUE) + #define LSE_VALUE 32768UL /*!< Value of the External oscillator in Hz*/ +#endif /* LSE_VALUE */ + +#if !defined (LSE_STARTUP_TIMEOUT) + #define LSE_STARTUP_TIMEOUT 5000UL /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ +/** + * @brief External clock source for SPI/SAI peripheral + * This value is used by the SPI/SAI HAL module to compute the SPI/SAI clock source + * frequency, this source is inserted directly through I2S_CKIN pad. + + */ +#if !defined (EXTERNAL_CLOCK_VALUE) + #define EXTERNAL_CLOCK_VALUE 12288000UL /*!< Value of the External clock in Hz*/ +#endif /* EXTERNAL_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ############################################ System Configuration ################################################ */ + +/** + * @brief This is the HAL system configuration section + */ + +#define VDD_VALUE 3300UL /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY (15UL) /*!< tick interrupt priority (lowest by default) */ +#define USE_RTOS 0U +#define PREFETCH_ENABLE 0U /*!< Enable prefetch */ + +/* ############################################ Assert Selection #################################################### */ + +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ + +/* #define USE_FULL_ASSERT 1U */ + +/* ############################################ Register callback feature configuration ############################# */ + +/** + * @brief Set below the peripheral configuration to "1U" to add the support + * of HAL callback registration/unregistration feature for the HAL + * driver(s). This allows user application to provide specific callback + * functions thanks to HAL_PPP_RegisterCallback() rather than overwriting + * the default weak callback functions (see each stm32h5xx_hal_ppp.h file + * for possible callback identifiers defined in HAL_PPP_CallbackIDTypeDef + * for each PPP peripheral). + */ +#define USE_HAL_ADC_REGISTER_CALLBACKS 0U /* ADC register callback disabled */ +#define USE_HAL_CCB_REGISTER_CALLBACKS 0U /* CCB register callback disabled */ +#define USE_HAL_CEC_REGISTER_CALLBACKS 0U /* CEC register callback disabled */ +#define USE_HAL_COMP_REGISTER_CALLBACKS 0U /* COMP register callback disabled */ +#define USE_HAL_CORDIC_REGISTER_CALLBACKS 0U /* CORDIC register callback disabled */ +#define USE_HAL_CRYP_REGISTER_CALLBACKS 0U /* CRYP register callback disabled */ +#define USE_HAL_DAC_REGISTER_CALLBACKS 0U /* DAC register callback disabled */ +#define USE_HAL_DCMI_REGISTER_CALLBACKS 0U /* DCMI register callback disabled */ +#define USE_HAL_DTS_REGISTER_CALLBACKS 0U /* DTS register callback disabled */ +#define USE_HAL_ETH_REGISTER_CALLBACKS 0U /* ETH register callback disabled */ +#define USE_HAL_FDCAN_REGISTER_CALLBACKS 0U /* FDCAN register callback disabled */ +#define USE_HAL_FMAC_REGISTER_CALLBACKS 0U /* FMAC register callback disabled */ +#define USE_HAL_NOR_REGISTER_CALLBACKS 0U /* NOR register callback disabled */ +#define USE_HAL_HASH_REGISTER_CALLBACKS 0U /* HASH register callback disabled */ +#define USE_HAL_HCD_REGISTER_CALLBACKS 0U /* HCD register callback disabled */ +#define USE_HAL_I2C_REGISTER_CALLBACKS 0U /* I2C register callback disabled */ +#define USE_HAL_I2S_REGISTER_CALLBACKS 0U /* I2S register callback disabled */ +#define USE_HAL_I3C_REGISTER_CALLBACKS 0U /* I3C register callback disabled */ +#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U /* IRDA register callback disabled */ +#define USE_HAL_IWDG_REGISTER_CALLBACKS 0U /* IWDG register callback disabled */ +#define USE_HAL_LPTIM_REGISTER_CALLBACKS 0U /* LPTIM register callback disabled */ +#define USE_HAL_MMC_REGISTER_CALLBACKS 0U /* MMC register callback disabled */ +#define USE_HAL_NAND_REGISTER_CALLBACKS 0U /* NAND register callback disabled */ +#define USE_HAL_OPAMP_REGISTER_CALLBACKS 0U /* OPAMP register callback disabled */ +#define USE_HAL_OTFDEC_REGISTER_CALLBACKS 0U /* OTFDEC register callback disabled */ +#define USE_HAL_PCD_REGISTER_CALLBACKS 0U /* PCD register callback disabled */ +#define USE_HAL_PKA_REGISTER_CALLBACKS 0U /* PKA register callback disabled */ +#define USE_HAL_RAMCFG_REGISTER_CALLBACKS 0U /* RAMCFG register callback disabled */ +#define USE_HAL_RNG_REGISTER_CALLBACKS 0U /* RNG register callback disabled */ +#define USE_HAL_RTC_REGISTER_CALLBACKS 0U /* RTC register callback disabled */ +#define USE_HAL_SAI_REGISTER_CALLBACKS 0U /* SAI register callback disabled */ +#define USE_HAL_SD_REGISTER_CALLBACKS 0U /* SD register callback disabled */ +#define USE_HAL_SDIO_REGISTER_CALLBACKS 0U /* SDIO register callback disabled */ +#define USE_HAL_SDRAM_REGISTER_CALLBACKS 0U /* SDRAM register callback disabled */ +#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U /* SMARTCARD register callback disabled */ +#define USE_HAL_SMBUS_REGISTER_CALLBACKS 0U /* SMBUS register callback disabled */ +#define USE_HAL_SPI_REGISTER_CALLBACKS 0U /* SPI register callback disabled */ +#define USE_HAL_SRAM_REGISTER_CALLBACKS 0U /* SRAM register callback disabled */ +#define USE_HAL_TIM_REGISTER_CALLBACKS 0U /* TIM register callback disabled */ +#define USE_HAL_UART_REGISTER_CALLBACKS 0U /* UART register callback disabled */ +#define USE_HAL_USART_REGISTER_CALLBACKS 0U /* USART register callback disabled */ +#define USE_HAL_WWDG_REGISTER_CALLBACKS 0U /* WWDG register callback disabled */ +#define USE_HAL_XSPI_REGISTER_CALLBACKS 0U /* XSPI register callback disabled */ + +/* ############################################ SPI peripheral configuration ######################################## */ + +/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver + * Activated: CRC code is present inside driver + * Deactivated: CRC code cleaned from driver + */ +#define USE_SPI_CRC 0U + +/* ################## SDMMC peripheral configuration ######################### */ + +#define USE_SD_TRANSCEIVER 0U + +/* ################## SDIO peripheral configuration ######################### */ + +#define USE_SDIO_TRANSCEIVER 0U +#define SDIO_MAX_IO_NUMBER 7U + +/* Includes ----------------------------------------------------------------------------------------------------------*/ + +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED + #include "stm32h5xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED + #include "stm32h5xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_ICACHE_MODULE_ENABLED + #include "stm32h5xx_hal_icache.h" +#endif /* HAL_ICACHE_MODULE_ENABLED */ + +#ifdef HAL_DCACHE_MODULE_ENABLED + #include "stm32h5xx_hal_dcache.h" +#endif /* HAL_DCACHE_MODULE_ENABLED */ + +#ifdef HAL_GTZC_MODULE_ENABLED + #include "stm32h5xx_hal_gtzc.h" +#endif /* HAL_GTZC_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED + #include "stm32h5xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_DTS_MODULE_ENABLED + #include "stm32h5xx_hal_dts.h" +#endif /* HAL_DTS_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED + #include "stm32h5xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_PKA_MODULE_ENABLED + #include "stm32h5xx_hal_pka.h" +#endif /* HAL_PKA_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED + #include "stm32h5xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED + #include "stm32h5xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED + #include "stm32h5xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED + #include "stm32h5xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED + #include "stm32h5xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED + #include "stm32h5xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED + #include "stm32h5xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED + #include "stm32h5xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_SDIO_MODULE_ENABLED +#include "stm32h5xx_hal_sdio.h" +#endif /* HAL_SDIO_MODULE_ENABLED */ + +#ifdef HAL_MMC_MODULE_ENABLED + #include "stm32h5xx_hal_mmc.h" +#endif /* HAL_MMC_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED + #include "stm32h5xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED + #include "stm32h5xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED + #include "stm32h5xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED + #include "stm32h5xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_I3C_MODULE_ENABLED + #include "stm32h5xx_hal_i3c.h" +#endif /* HAL_I3C_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED + #include "stm32h5xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED +#include "stm32h5xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED + #include "stm32h5xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_XSPI_MODULE_ENABLED + #include "stm32h5xx_hal_xspi.h" +#endif /* HAL_XSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED + #include "stm32h5xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED + #include "stm32h5xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED + #include "stm32h5xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED + #include "stm32h5xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED + #include "stm32h5xx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED + #include "stm32h5xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED + #include "stm32h5xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED + #include "stm32h5xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED + #include "stm32h5xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED + #include "stm32h5xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED + #include "stm32h5xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED + #include "stm32h5xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED + #include "stm32h5xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_CCB_MODULE_ENABLED +#include "stm32h5xx_hal_ccb.h" +#endif /* HAL_CCB_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED + #include "stm32h5xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +#ifdef HAL_COMP_MODULE_ENABLED + #include "stm32h5xx_hal_comp.h" +#endif /* HAL_COMP_MODULE_ENABLED */ + +#ifdef HAL_CORDIC_MODULE_ENABLED + #include "stm32h5xx_hal_cordic.h" +#endif /* HAL_CORDIC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED + #include "stm32h5xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_EXTI_MODULE_ENABLED + #include "stm32h5xx_hal_exti.h" +#endif /* HAL_EXTI_MODULE_ENABLED */ + +#ifdef HAL_ETH_MODULE_ENABLED + #include "stm32h5xx_hal_eth.h" +#endif /* HAL_ETH_MODULE_ENABLED */ + +#ifdef HAL_FDCAN_MODULE_ENABLED + #include "stm32h5xx_hal_fdcan.h" +#endif /* HAL_FDCAN_MODULE_ENABLED */ + +#ifdef HAL_CEC_MODULE_ENABLED + #include "stm32h5xx_hal_cec.h" +#endif /* HAL_CEC_MODULE_ENABLED */ + +#ifdef HAL_FMAC_MODULE_ENABLED + #include "stm32h5xx_hal_fmac.h" +#endif /* HAL_FMAC_MODULE_ENABLED */ + +#ifdef HAL_OPAMP_MODULE_ENABLED + #include "stm32h5xx_hal_opamp.h" +#endif /* HAL_OPAMP_MODULE_ENABLED */ + +#ifdef HAL_OTFDEC_MODULE_ENABLED + #include "stm32h5xx_hal_otfdec.h" +#endif /* HAL_OTFDEC_MODULE_ENABLED */ + +#ifdef HAL_PSSI_MODULE_ENABLED + #include "stm32h5xx_hal_pssi.h" +#endif /* HAL_PSSI_MODULE_ENABLED */ + +#ifdef HAL_RAMCFG_MODULE_ENABLED + #include "stm32h5xx_hal_ramcfg.h" +#endif /* HAL_RAMCFG_MODULE_ENABLED */ + +/* Exported macro ----------------------------------------------------------------------------------------------------*/ + +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ + #define assert_param(expr) ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ----------------------------------------------------------------------------------------------- */ + + void assert_failed(uint8_t *file, uint32_t line); +#else + #define assert_param(expr) ((void)0U) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* STM32H5xx_HAL_CONF_H */ + diff --git a/include/stm32h5xx_it.h b/include/stm32h5xx_it.h new file mode 100644 index 0000000..8bfd82d --- /dev/null +++ b/include/stm32h5xx_it.h @@ -0,0 +1,67 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file stm32h5xx_it.h + * @brief This file contains the headers of the interrupt handlers. + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32H5xx_IT_H +#define __STM32H5xx_IT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Exported types ------------------------------------------------------------*/ +/* USER CODE BEGIN ET */ + +/* USER CODE END ET */ + +/* Exported constants --------------------------------------------------------*/ +/* USER CODE BEGIN EC */ + +/* USER CODE END EC */ + +/* Exported macro ------------------------------------------------------------*/ +/* USER CODE BEGIN EM */ + +/* USER CODE END EM */ + +/* Exported functions prototypes ---------------------------------------------*/ +void NMI_Handler(void); +void HardFault_Handler(void); +void MemManage_Handler(void); +void BusFault_Handler(void); +void UsageFault_Handler(void); +void SVC_Handler(void); +void DebugMon_Handler(void); +void PendSV_Handler(void); +void SysTick_Handler(void); +void EXTI13_IRQHandler(void); +/* USER CODE BEGIN EFP */ + +/* USER CODE END EFP */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32H5xx_IT_H */ diff --git a/include/stm32h5xx_nucleo_conf.h b/include/stm32h5xx_nucleo_conf.h new file mode 100644 index 0000000..df293c9 --- /dev/null +++ b/include/stm32h5xx_nucleo_conf.h @@ -0,0 +1,77 @@ + +/** + ****************************************************************************** + * @file stm32h5xx_nucleo_conf.h + * @author MCD Application Team + * @brief STM32H5xx_Nucleo board configuration file. + ****************************************************************************** + * @attention + * + * Copyright (c) 2023 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef STM32H5XX_NUCLEO_CONF_H +#define STM32H5XX_NUCLEO_CONF_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32h5xx_hal.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32H5XX_NUCLEO + * @{ + */ + +/** @defgroup STM32H5XX_NUCLEO_CONFIG Config + * @{ + */ + +/** @defgroup STM32H5XX_NUCLEO_CONFIG_Exported_Constants Exported Constants + * @{ + */ +/* Nucleo pin and part number defines */ +#define USE_NUCLEO_144 +/* #define USE_NUCLEO_64 */ + +/* COM define */ +#define USE_COM_LOG 1U +#define USE_BSP_COM_FEATURE 1U + +/* IRQ priorities */ +#define BSP_BUTTON_USER_IT_PRIORITY 15U + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* STM32H5XX_NUCLEO_CONF_H */ diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..164d01a --- /dev/null +++ b/src/main.c @@ -0,0 +1,7 @@ +#include "YEEP144.h" +#include "stm32h563xx.h" +#include "stm32h5xx_hal.h" + +int main(void){ + +} \ No newline at end of file diff --git a/src/startup_stm32h563xx.S b/src/startup_stm32h563xx.S new file mode 100644 index 0000000..4f20694 --- /dev/null +++ b/src/startup_stm32h563xx.S @@ -0,0 +1,683 @@ +/** + ****************************************************************************** + * @brief STM32H563xx device vector table for GCC toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Branches to main in the C library (which eventually + * calls main()). + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +.syntax unified +.cpu cortex-m33 +.fpu softvfp +.thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss + +/** + * @brief This is the code that gets called when the processor first + * starts execution following a reset event. Only the absolutely + * necessary set is performed, after which the application + * supplied main() routine is called. + * @param None + * @retval : None +*/ + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr sp, =_estack /* set stack pointer */ + ldr r0, =_sstack + msr MSPLIM, r0 /* set stack pointer limit */ +/* Call the clock system initialization function.*/ + bl SystemInit + +/* Copy the data segment initializers from flash to SRAM */ + ldr r0, =_sdata + ldr r1, =_edata + ldr r2, =_sidata + movs r3, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r4, [r2, r3] + str r4, [r0, r3] + adds r3, r3, #4 + +LoopCopyDataInit: + adds r4, r0, r3 + cmp r4, r1 + bcc CopyDataInit + +/* Zero fill the bss segment. */ + ldr r2, =_sbss + ldr r4, =_ebss + movs r3, #0 + b LoopFillZerobss + +FillZerobss: + str r3, [r2] + adds r2, r2, #4 + +LoopFillZerobss: + cmp r2, r4 + bcc FillZerobss + +/* Call static constructors */ + bl __libc_init_array +/* Call the application's entry point.*/ + bl main + +LoopForever: + b LoopForever + + .size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * + * @param None + * @retval : None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler + +/****************************************************************************** +* +* The STM32H563xx vector table. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + +g_pfnVectors: + .word _estack + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word MemManage_Handler + .word BusFault_Handler + .word UsageFault_Handler + .word SecureFault_Handler + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word DebugMon_Handler + .word 0 + .word PendSV_Handler + .word SysTick_Handler + .word WWDG_IRQHandler /* Window Watchdog interrupt */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word TAMP_IRQHandler /* TAMP global interrupt */ + .word RAMCFG_IRQHandler /* RAM configuration global interrupt */ + .word FLASH_IRQHandler /* FLASH non-secure global interrupt */ + .word FLASH_S_IRQHandler /* FLASH secure global interrupt */ + .word GTZC_IRQHandler /* GTZC global interrupt */ + .word RCC_IRQHandler /* RCC non-secure global interrupt */ + .word RCC_S_IRQHandler /* RCC secure global interrupt */ + .word EXTI0_IRQHandler /* EXTI Line0 interrupt */ + .word EXTI1_IRQHandler /* EXTI Line1 interrupt */ + .word EXTI2_IRQHandler /* EXTI Line2 interrupt */ + .word EXTI3_IRQHandler /* EXTI Line3 interrupt */ + .word EXTI4_IRQHandler /* EXTI Line4 interrupt */ + .word EXTI5_IRQHandler /* EXTI Line5 interrupt */ + .word EXTI6_IRQHandler /* EXTI Line6 interrupt */ + .word EXTI7_IRQHandler /* EXTI Line7 interrupt */ + .word EXTI8_IRQHandler /* EXTI Line8 interrupt */ + .word EXTI9_IRQHandler /* EXTI Line9 interrupt */ + .word EXTI10_IRQHandler /* EXTI Line10 interrupt */ + .word EXTI11_IRQHandler /* EXTI Line11 interrupt */ + .word EXTI12_IRQHandler /* EXTI Line12 interrupt */ + .word EXTI13_IRQHandler /* EXTI Line13 interrupt */ + .word EXTI14_IRQHandler /* EXTI Line14 interrupt */ + .word EXTI15_IRQHandler /* EXTI Line15 interrupt */ + .word GPDMA1_CH0_IRQHandler /* GPDMA1 channel 0 global interrupt */ + .word GPDMA1_CH1_IRQHandler /* GPDMA1 channel 1 global interrupt */ + .word GPDMA1_CH2_IRQHandler /* GPDMA1 channel 2 global interrupt */ + .word GPDMA1_CH3_IRQHandler /* GPDMA1 channel 3 global interrupt */ + .word GPDMA1_CH4_IRQHandler /* GPDMA1 channel 4 global interrupt */ + .word GPDMA1_CH5_IRQHandler /* GPDMA1 channel 5 global interrupt */ + .word GPDMA1_CH6_IRQHandler /* GPDMA1 channel 6 global interrupt */ + .word GPDMA1_CH7_IRQHandler /* GPDMA1 channel 7 global interrupt */ + .word IWDG_IRQHandler /* IWDG interrupt */ + .word 0 /* Reserved */ + .word ADC1_IRQHandler /* ADC1 global interrupt */ + .word DAC1_IRQHandler /* DAC1 global interrupt */ + .word FDCAN1_IT0_IRQHandler /* FDCAN1 interrupt 0 */ + .word FDCAN1_IT1_IRQHandler /* FDCAN1 interrupt 1 */ + .word TIM1_BRK_TERR_IERR_IRQHandler /* TIM1 break/TIM1 transition error/TIM1 index error */ + .word TIM1_UP_IRQHandler /* TIM1 Update */ + .word TIM1_TRG_COM_DIR_IDX_IRQHandler /* TIM1 trigger and commutation/TIM1 direction change interrupt/TIM1 index */ + .word TIM1_CC_IRQHandler /* TIM1 capture compare interrupt */ + .word TIM2_IRQHandler /* TIM2 global interrupt */ + .word TIM3_IRQHandler /* TIM3 global interrupt */ + .word TIM4_IRQHandler /* TIM4 global interrupt */ + .word TIM5_IRQHandler /* TIM5 global interrupt */ + .word TIM6_IRQHandler /* TIM6 global interrupt */ + .word TIM7_IRQHandler /* TIM7 global interrupt */ + .word I2C1_EV_IRQHandler /* I2C1 event interrupt */ + .word I2C1_ER_IRQHandler /* I2C1 error interrupt */ + .word I2C2_EV_IRQHandler /* I2C2 event interrupt */ + .word I2C2_ER_IRQHandler /* I2C2 error interrupt */ + .word SPI1_IRQHandler /* SPI1 global interrupt */ + .word SPI2_IRQHandler /* SPI2 global interrupt */ + .word SPI3_IRQHandler /* SPI3 global interrupt */ + .word USART1_IRQHandler /* USART1 global interrupt */ + .word USART2_IRQHandler /* USART2 global interrupt */ + .word USART3_IRQHandler /* USART3 global interrupt */ + .word UART4_IRQHandler /* UART4 global interrupt */ + .word UART5_IRQHandler /* UART5 global interrupt */ + .word LPUART1_IRQHandler /* LPUART1 global interrupt */ + .word LPTIM1_IRQHandler /* LPTIM1 global interrupt */ + .word IM8_BRK_TERR_IERR_IRQHandler /* TIM8 break interrupt/TIM8 transition error/TIM8 index error */ + .word TIM8_UP_IRQHandler /* TIM8 update interrupt */ + .word TIM8_TRG_COM_DIR_IDX_IRQHandler /* TIM8 trigger and commutation interrupt/TIM8 direction change interrupt/TIM8 index */ + .word TIM8_CC_IRQHandler /* TIM8 capture compare interrupt */ + .word ADC2_IRQHandler /* ADC2 global interrupt */ + .word LPTIM2_IRQHandler /* LPTIM2 global interrupt */ + .word TIM15_IRQHandler /* TIM5 global interrupt */ + .word TIM16_IRQHandler /* TIM6 global interrupt */ + .word TIM17_IRQHandler /* TIM17 global interrupt */ + .word USB_FS_IRQHandler /* USB OTG FS global interrupt */ + .word CRS_IRQHandler /* Clock Recovery System global interrupt */ + .word UCPD1_IRQHandler /* UCPD1 global interrupt */ + .word FMC_IRQHandler /* FMC global interrupt */ + .word OCTOSPI1_IRQHandler /* OCTOSPI1 global interrupt */ + .word SDMMC1_IRQHandler /* SDMMC1 global interrupt */ + .word I2C3_EV_IRQHandler /* I2C3 event interrupt */ + .word I2C3_ER_IRQHandler /* I2C3 error interrupt */ + .word SPI4_IRQHandler /* SPI4 global interrupt */ + .word SPI5_IRQHandler /* SPI5 global interrupt */ + .word SPI6_IRQHandler /* SPI6 global interrupt */ + .word USART6_IRQHandler /* USART6 global interrupt */ + .word USART10_IRQHandler /* USART10 global interrupt */ + .word USART11_IRQHandler /* USART11 global interrupt */ + .word SAI1_IRQHandler /* SAI1 global interrupt */ + .word SAI2_IRQHandler /* SAI2 global interrupt */ + .word GPDMA2_CH0_IRQHandler /* GPDMA2 channel 0 global interrupt */ + .word GPDMA2_CH1_IRQHandler /* GPDMA2 channel 1 global interrupt */ + .word GPDMA2_CH2_IRQHandler /* GPDMA2 channel 2 global interrupt */ + .word GPDMA2_CH3_IRQHandler /* GPDMA2 channel 3 global interrupt */ + .word GPDMA2_CH4_IRQHandler /* GPDMA2 channel 4 global interrupt */ + .word GPDMA2_CH5_IRQHandler /* GPDMA2 channel 5 global interrupt */ + .word GPDMA2_CH6_IRQHandler /* GPDMA2 channel 6 global interrupt */ + .word GPDMA2_CH7_IRQHandler /* GPDMA2 channel 7 global interrupt */ + .word UART7_IRQHandler /* UART7 global interrupt */ + .word UART8_IRQHandler /* UART8 global interrupt */ + .word UART9_IRQHandler /* UART9 global interrupt */ + .word UART12_IRQHandler /* UART12 global interrupt */ + .word SDMMC2_IRQHandler /* SDMMC2 global interrupt */ + .word 0 /* Reserved */ + .word ICACHE_IRQHandler /* Instruction cache global interrupt */ + .word DCACHE_IRQHandler /* Data cache global interrupt */ + .word ETH_IRQHandler /* ETH interrupt */ + .word ETH_WKUP_IRQHandler /* ETHERNET wakeup interrupt through EXTI line */ + .word DCMI_PSSI_IRQHandler /* DCMI/PSSI global interrupt */ + .word FDCAN2_IT0_IRQHandler /* FDCAN2 interrupt 0 */ + .word FDCAN2_IT1_IRQHandler /* FDCAN2 interrupt 1 */ + .word Cordic_IRQHandler /* Cordic interrupt */ + .word FMAC_IRQHandler /* FMAC interrupt */ + .word DTS_WKUP_IRQHandler /* DTS interrupt or DTS AIT through EXTI line */ + .word RNG_IRQHandler /* RNG global interrupt */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word HASH_IRQHandler /* HASH interrupt */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word TIM12_IRQHandler /* TIM12 global interrupt */ + .word TIM13_IRQHandler /* TIM13 global interrupt */ + .word TIM14_IRQHandler /* TIM14 global interrupt */ + .word I3C1_EV_IRQHandler /* I3C1 event interrupt */ + .word I3C1_ER_IRQHandler /* I3C1 error interrupt */ + .word I2C4_EV_IRQHandler /* I2C4 event interrupt */ + .word I2C4_ER_IRQHandler /* I2C4 error interrupt */ + .word LPTIM3_IRQHandler /* LPTIM3 global interrupt */ + .word LPTIM4_IRQHandler /* LPTIM4 global interrupt */ + .word LPTIM5_IRQHandler /* LPTIM5 global interrupt */ + .word LPTIM6_IRQHandler /* LPTIM6 global interrupt */ + .size g_pfnVectors, .-g_pfnVectors + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + + .weak SecureFault_Handler + .thumb_set SecureFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak TAMP_IRQHandler + .thumb_set TAMP_IRQHandler,Default_Handler + + .weak RAMCFG_IRQHandler + .thumb_set RAMCFG_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak FLASH_S_IRQHandler + .thumb_set FLASH_S_IRQHandler,Default_Handler + + .weak GTZC_IRQHandler + .thumb_set GTZC_IRQHandler,Default_Handler + + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + + .weak RCC_S_IRQHandler + .thumb_set RCC_S_IRQHandler,Default_Handler + + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + + .weak EXTI5_IRQHandler + .thumb_set EXTI5_IRQHandler,Default_Handler + + .weak EXTI6_IRQHandler + .thumb_set EXTI6_IRQHandler,Default_Handler + + .weak EXTI7_IRQHandler + .thumb_set EXTI7_IRQHandler,Default_Handler + + .weak EXTI8_IRQHandler + .thumb_set EXTI8_IRQHandler,Default_Handler + + .weak EXTI9_IRQHandler + .thumb_set EXTI9_IRQHandler,Default_Handler + + .weak EXTI10_IRQHandler + .thumb_set EXTI10_IRQHandler,Default_Handler + + .weak EXTI11_IRQHandler + .thumb_set EXTI11_IRQHandler,Default_Handler + + .weak EXTI12_IRQHandler + .thumb_set EXTI12_IRQHandler,Default_Handler + + .weak EXTI13_IRQHandler + .thumb_set EXTI13_IRQHandler,Default_Handler + + .weak EXTI14_IRQHandler + .thumb_set EXTI14_IRQHandler,Default_Handler + + .weak EXTI15_IRQHandler + .thumb_set EXTI15_IRQHandler,Default_Handler + + .weak GPDMA1_CH0_IRQHandler + .thumb_set GPDMA1_CH0_IRQHandler,Default_Handler + + .weak GPDMA1_CH1_IRQHandler + .thumb_set GPDMA1_CH1_IRQHandler,Default_Handler + + .weak GPDMA1_CH2_IRQHandler + .thumb_set GPDMA1_CH2_IRQHandler,Default_Handler + + .weak GPDMA1_CH3_IRQHandler + .thumb_set GPDMA1_CH3_IRQHandler,Default_Handler + + .weak GPDMA1_CH4_IRQHandler + .thumb_set GPDMA1_CH4_IRQHandler,Default_Handler + + .weak GPDMA1_CH5_IRQHandler + .thumb_set GPDMA1_CH5_IRQHandler,Default_Handler + + .weak GPDMA1_CH6_IRQHandler + .thumb_set GPDMA1_CH6_IRQHandler,Default_Handler + + .weak GPDMA1_CH7_IRQHandler + .thumb_set GPDMA1_CH7_IRQHandler,Default_Handler + + .weak IWDG_IRQHandler + .thumb_set IWDG_IRQHandler,Default_Handler + + .weak ADC1_IRQHandler + .thumb_set ADC1_IRQHandler,Default_Handler + + .weak DAC1_IRQHandler + .thumb_set DAC1_IRQHandler,Default_Handler + + .weak FDCAN1_IT0_IRQHandler + .thumb_set FDCAN1_IT0_IRQHandler,Default_Handler + + .weak FDCAN1_IT1_IRQHandler + .thumb_set FDCAN1_IT1_IRQHandler,Default_Handler + + .weak TIM1_BRK_TERR_IERR_IRQHandler + .thumb_set TIM1_BRK_TERR_IERR_IRQHandler,Default_Handler + + .weak TIM1_UP_IRQHandler + .thumb_set TIM1_UP_IRQHandler,Default_Handler + + .weak TIM1_TRG_COM_DIR_IDX_IRQHandler + .thumb_set TIM1_TRG_COM_DIR_IDX_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak TIM3_IRQHandler + .thumb_set TIM3_IRQHandler,Default_Handler + + .weak TIM4_IRQHandler + .thumb_set TIM4_IRQHandler,Default_Handler + + .weak TIM5_IRQHandler + .thumb_set TIM5_IRQHandler,Default_Handler + + .weak TIM6_IRQHandler + .thumb_set TIM6_IRQHandler,Default_Handler + + .weak TIM7_IRQHandler + .thumb_set TIM7_IRQHandler,Default_Handler + + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + + .weak I2C2_EV_IRQHandler + .thumb_set I2C2_EV_IRQHandler,Default_Handler + + .weak I2C2_ER_IRQHandler + .thumb_set I2C2_ER_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak SPI3_IRQHandler + .thumb_set SPI3_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + + .weak USART3_IRQHandler + .thumb_set USART3_IRQHandler,Default_Handler + + .weak UART4_IRQHandler + .thumb_set UART4_IRQHandler,Default_Handler + + .weak UART5_IRQHandler + .thumb_set UART5_IRQHandler,Default_Handler + + .weak LPUART1_IRQHandler + .thumb_set LPUART1_IRQHandler,Default_Handler + + .weak LPTIM1_IRQHandler + .thumb_set LPTIM1_IRQHandler,Default_Handler + + .weak IM8_BRK_TERR_IERR_IRQHandler + .thumb_set IM8_BRK_TERR_IERR_IRQHandler,Default_Handler + + .weak TIM8_UP_IRQHandler + .thumb_set TIM8_UP_IRQHandler,Default_Handler + + .weak TIM8_TRG_COM_DIR_IDX_IRQHandler + .thumb_set TIM8_TRG_COM_DIR_IDX_IRQHandler,Default_Handler + + .weak TIM8_CC_IRQHandler + .thumb_set TIM8_CC_IRQHandler,Default_Handler + + .weak ADC2_IRQHandler + .thumb_set ADC2_IRQHandler,Default_Handler + + .weak LPTIM2_IRQHandler + .thumb_set LPTIM2_IRQHandler,Default_Handler + + .weak TIM15_IRQHandler + .thumb_set TIM15_IRQHandler,Default_Handler + + .weak TIM16_IRQHandler + .thumb_set TIM16_IRQHandler,Default_Handler + + .weak TIM17_IRQHandler + .thumb_set TIM17_IRQHandler,Default_Handler + + .weak USB_FS_IRQHandler + .thumb_set USB_FS_IRQHandler,Default_Handler + + .weak CRS_IRQHandler + .thumb_set CRS_IRQHandler,Default_Handler + + .weak UCPD1_IRQHandler + .thumb_set UCPD1_IRQHandler,Default_Handler + + .weak FMC_IRQHandler + .thumb_set FMC_IRQHandler,Default_Handler + + .weak OCTOSPI1_IRQHandler + .thumb_set OCTOSPI1_IRQHandler,Default_Handler + + .weak SDMMC1_IRQHandler + .thumb_set SDMMC1_IRQHandler,Default_Handler + + .weak I2C3_EV_IRQHandler + .thumb_set I2C3_EV_IRQHandler,Default_Handler + + .weak I2C3_ER_IRQHandler + .thumb_set I2C3_ER_IRQHandler,Default_Handler + + .weak SPI4_IRQHandler + .thumb_set SPI4_IRQHandler,Default_Handler + + .weak SPI5_IRQHandler + .thumb_set SPI5_IRQHandler,Default_Handler + + .weak SPI6_IRQHandler + .thumb_set SPI6_IRQHandler,Default_Handler + + .weak USART6_IRQHandler + .thumb_set USART6_IRQHandler,Default_Handler + + .weak USART10_IRQHandler + .thumb_set USART10_IRQHandler,Default_Handler + + .weak USART11_IRQHandler + .thumb_set USART11_IRQHandler,Default_Handler + + .weak SAI1_IRQHandler + .thumb_set SAI1_IRQHandler,Default_Handler + + .weak SAI2_IRQHandler + .thumb_set SAI2_IRQHandler,Default_Handler + + .weak GPDMA2_CH0_IRQHandler + .thumb_set GPDMA2_CH0_IRQHandler,Default_Handler + + .weak GPDMA2_CH1_IRQHandler + .thumb_set GPDMA2_CH1_IRQHandler,Default_Handler + + .weak GPDMA2_CH2_IRQHandler + .thumb_set GPDMA2_CH2_IRQHandler,Default_Handler + + .weak GPDMA2_CH3_IRQHandler + .thumb_set GPDMA2_CH3_IRQHandler,Default_Handler + + .weak GPDMA2_CH4_IRQHandler + .thumb_set GPDMA2_CH4_IRQHandler,Default_Handler + + .weak GPDMA2_CH5_IRQHandler + .thumb_set GPDMA2_CH5_IRQHandler,Default_Handler + + .weak GPDMA2_CH6_IRQHandler + .thumb_set GPDMA2_CH6_IRQHandler,Default_Handler + + .weak GPDMA2_CH7_IRQHandler + .thumb_set GPDMA2_CH7_IRQHandler,Default_Handler + + .weak UART7_IRQHandler + .thumb_set UART7_IRQHandler,Default_Handler + + .weak UART8_IRQHandler + .thumb_set UART8_IRQHandler,Default_Handler + + .weak UART9_IRQHandler + .thumb_set UART9_IRQHandler,Default_Handler + + .weak UART12_IRQHandler + .thumb_set UART12_IRQHandler,Default_Handler + + .weak SDMMC2_IRQHandler + .thumb_set SDMMC2_IRQHandler,Default_Handler + + .weak ICACHE_IRQHandler + .thumb_set ICACHE_IRQHandler,Default_Handler + + .weak DCACHE_IRQHandler + .thumb_set DCACHE_IRQHandler,Default_Handler + + .weak ETH_IRQHandler + .thumb_set ETH_IRQHandler,Default_Handler + + .weak ETH_WKUP_IRQHandler + .thumb_set ETH_WKUP_IRQHandler,Default_Handler + + .weak DCMI_PSSI_IRQHandler + .thumb_set DCMI_PSSI_IRQHandler,Default_Handler + + .weak FDCAN2_IT0_IRQHandler + .thumb_set FDCAN2_IT0_IRQHandler,Default_Handler + + .weak FDCAN2_IT1_IRQHandler + .thumb_set FDCAN2_IT1_IRQHandler,Default_Handler + + .weak Cordic_IRQHandler + .thumb_set Cordic_IRQHandler,Default_Handler + + .weak FMAC_IRQHandler + .thumb_set FMAC_IRQHandler,Default_Handler + + .weak DTS_WKUP_IRQHandler + .thumb_set DTS_WKUP_IRQHandler,Default_Handler + + .weak RNG_IRQHandler + .thumb_set RNG_IRQHandler,Default_Handler + + .weak HASH_IRQHandler + .thumb_set HASH_IRQHandler,Default_Handler + + .weak TIM12_IRQHandler + .thumb_set TIM12_IRQHandler,Default_Handler + + .weak TIM13_IRQHandler + .thumb_set TIM13_IRQHandler,Default_Handler + + .weak TIM14_IRQHandler + .thumb_set TIM14_IRQHandler,Default_Handler + + .weak I3C1_EV_IRQHandler + .thumb_set I3C1_EV_IRQHandler,Default_Handler + + .weak I3C1_ER_IRQHandler + .thumb_set I3C1_ER_IRQHandler,Default_Handler + + .weak I2C4_EV_IRQHandler + .thumb_set I2C4_EV_IRQHandler,Default_Handler + + .weak I2C4_ER_IRQHandler + .thumb_set I2C4_ER_IRQHandler,Default_Handler + + .weak LPTIM3_IRQHandler + .thumb_set LPTIM3_IRQHandler,Default_Handler + + .weak LPTIM4_IRQHandler + .thumb_set LPTIM4_IRQHandler,Default_Handler + + .weak LPTIM5_IRQHandler + .thumb_set LPTIM5_IRQHandler,Default_Handler + + .weak LPTIM6_IRQHandler + .thumb_set LPTIM6_IRQHandler,Default_Handler + + .weak SystemInit + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/src/syscall.c b/src/syscall.c new file mode 100644 index 0000000..7076c50 --- /dev/null +++ b/src/syscall.c @@ -0,0 +1,244 @@ +/** + ****************************************************************************** + * @file syscalls.c + * @author Auto-generated by STM32CubeIDE for Visual Studio Code Extension + * @brief Minimal System calls file + * + * For more information about which c-functions + * need which of these lowlevel functions + * please consult the Newlib or Picolibc libc-manual + ****************************************************************************** + * @attention + * + * Copyright (c) 2025 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Includes */ +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Variables */ +extern int __io_putchar(int ch) __attribute__((weak)); +extern int __io_getchar(void) __attribute__((weak)); + + +char *__env[1] = { 0 }; +char **environ = __env; + + +/* Functions */ +void initialise_monitor_handles(void) +{ +} + +int _getpid(void) +{ + return 1; +} + +int _kill(int pid, int sig) +{ + (void)pid; + (void)sig; + errno = EINVAL; + return -1; +} + +void _exit (int status) +{ + _kill(status, -1); + while (1) {} /* Make sure we hang here */ +} + +__attribute__((weak)) int _read(int file, char *ptr, int len) +{ + (void)file; + int DataIdx; + + for (DataIdx = 0; DataIdx < len; DataIdx++) + { + *ptr++ = __io_getchar(); + } + + return len; +} + +__attribute__((weak)) int _write(int file, char *ptr, int len) +{ + (void)file; + int DataIdx; + + for (DataIdx = 0; DataIdx < len; DataIdx++) + { + __io_putchar(*ptr++); + } + return len; +} + +int _close(int file) +{ + (void)file; + return -1; +} + + +int _fstat(int file, struct stat *st) +{ + (void)file; + st->st_mode = S_IFCHR; + return 0; +} + +int _isatty(int file) +{ + (void)file; + return 1; +} + +int _lseek(int file, int ptr, int dir) +{ + (void)file; + (void)ptr; + (void)dir; + return 0; +} + +int _open(char *path, int flags, ...) +{ + (void)path; + (void)flags; + /* Pretend like we always fail */ + return -1; +} + +int _wait(int *status) +{ + (void)status; + errno = ECHILD; + return -1; +} + +int _unlink(char *name) +{ + (void)name; + errno = ENOENT; + return -1; +} + +clock_t _times(struct tms *buf) +{ + (void)buf; + return -1; +} + +int _stat(const char *file, struct stat *st) +{ + (void)file; + st->st_mode = S_IFCHR; + return 0; +} + +int _link(char *old, char *new) +{ + (void)old; + (void)new; + errno = EMLINK; + return -1; +} + +int _fork(void) +{ + errno = EAGAIN; + return -1; +} + +int _execve(char *name, char **argv, char **env) +{ + (void)name; + (void)argv; + (void)env; + errno = ENOMEM; + return -1; +} + +// --- Picolibc Specific Section --- +#if defined(__PICOLIBC__) + +/** + * @brief Picolibc helper function to output a character to a FILE stream. + * This redirects the output to the low-level __io_putchar function. + * @param c Character to write. + * @param file FILE stream pointer (ignored). + * @retval int The character written. + */ +static int starm_putc(char c, FILE *file) +{ + (void) file; + __io_putchar(c); + return c; +} + +/** + * @brief Picolibc helper function to input a character from a FILE stream. + * This redirects the input from the low-level __io_getchar function. + * @param file FILE stream pointer (ignored). + * @retval int The character read, cast to an unsigned char then int. + */ +static int starm_getc(FILE *file) +{ + unsigned char c; + (void) file; + c = __io_getchar(); + return c; +} + +// Define and initialize the standard I/O streams for Picolibc. +// FDEV_SETUP_STREAM connects the starm_putc and starm_getc helper functions to a FILE structure. +// _FDEV_SETUP_RW indicates the stream is for reading and writing. +static FILE __stdio = FDEV_SETUP_STREAM(starm_putc, + starm_getc, + NULL, + _FDEV_SETUP_RW); + +// Assign the standard stream pointers (stdin, stdout, stderr) to the initialized stream. +// Picolibc uses these pointers for standard I/O operations (printf, scanf, etc.). +FILE *const stdin = &__stdio; +__strong_reference(stdin, stdout); +__strong_reference(stdin, stderr); + +// Create strong aliases mapping standard C library function names (without underscore) +// to the implemented system call stubs (with underscore). Picolibc uses these +// standard names internally, so this linking is required. +__strong_reference(_read, read); +__strong_reference(_write, write); +__strong_reference(_times, times); +__strong_reference(_execve, execve); +__strong_reference(_fork, fork); +__strong_reference(_link, link); +__strong_reference(_unlink, unlink); +__strong_reference(_stat, stat); +__strong_reference(_wait, wait); +__strong_reference(_open, open); +__strong_reference(_close, close); +__strong_reference(_lseek, lseek); +__strong_reference(_isatty, isatty); +__strong_reference(_fstat, fstat); +__strong_reference(_exit, exit); +__strong_reference(_kill, kill); +__strong_reference(_getpid, getpid); + +#endif //__PICOLIBC__ diff --git a/src/sysmem.c b/src/sysmem.c new file mode 100644 index 0000000..f46c8de --- /dev/null +++ b/src/sysmem.c @@ -0,0 +1,87 @@ +/** + ****************************************************************************** + * @file sysmem.c + * @author Auto-generated by STM32CubeIDE for Visual Studio Code Extension + * @brief GCC System Memory calls file + * + * For more information about which C functions + * need which of these lowlevel functions + * please consult the Newlib or Picolibc libc manual + ****************************************************************************** + * @attention + * + * Copyright (c) 2025 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Includes */ +#include +#include +#include + +/** + * Pointer to the current high watermark of the heap usage + */ +static uint8_t *__sbrk_heap_end = NULL; + +/** + * @brief _sbrk() allocates memory to the newlib heap and is used by malloc + * and others from the C library + * + * @verbatim + * ############################################################################ + * # .data # .bss # newlib heap # MSP stack # + * # # # # Reserved by _Min_Stack_Size # + * ############################################################################ + * ^-- RAM start ^-- _end _estack, RAM end --^ + * @endverbatim + * + * This implementation starts allocating at the '_end' linker symbol + * The '_Min_Stack_Size' linker symbol reserves a memory for the MSP stack + * The implementation considers '_estack' linker symbol to be RAM end + * NOTE: If the MSP stack, at any point during execution, grows larger than the + * reserved size, please increase the '_Min_Stack_Size'. + * + * @param incr Memory size + * @return Pointer to allocated memory + */ +void *_sbrk(ptrdiff_t incr) +{ + extern uint8_t _end; /* Symbol defined in the linker script */ + extern uint8_t _estack; /* Symbol defined in the linker script */ + extern uint32_t _Min_Stack_Size; /* Symbol defined in the linker script */ + const uint32_t stack_limit = (uint32_t)&_estack - (uint32_t)&_Min_Stack_Size; + const uint8_t *max_heap = (uint8_t *)stack_limit; + uint8_t *prev_heap_end; + + /* Initialize heap end at first call */ + if (NULL == __sbrk_heap_end) + { + __sbrk_heap_end = &_end; + } + + /* Protect heap from growing into the reserved MSP stack */ + if (__sbrk_heap_end + incr > max_heap) + { + errno = ENOMEM; + return (void *)-1; + } + + prev_heap_end = __sbrk_heap_end; + __sbrk_heap_end += incr; + + return (void *)prev_heap_end; +} + +#if defined(__PICOLIBC__) + // Picolibc expects syscalls without the leading underscore. + // This creates a strong alias so that + // calls to `sbrk()` are resolved to our `_sbrk()` implementation. + __strong_reference(_sbrk, sbrk); +#endif diff --git a/src/system_stm32h5xx.c b/src/system_stm32h5xx.c new file mode 100644 index 0000000..d4ea960 --- /dev/null +++ b/src/system_stm32h5xx.c @@ -0,0 +1,403 @@ +/** + ****************************************************************************** + * @file system_stm32h5xx.c + * @author MCD Application Team + * @brief CMSIS Cortex-M33 Device Peripheral Access Layer System Source File + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2023 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + * This file provides two functions and one global variable to be called from + * user application: + * - SystemInit(): This function is called at startup just after reset and + * before branch to main program. This call is made inside + * the "startup_stm32h5xx.s" file. + * + * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used + * by the user application to setup the SysTick + * timer or configure other parameters. + * + * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must + * be called whenever the core clock is changed + * during program execution. + * + * After each device reset the HSI (64 MHz) is used as system clock source. + * Then SystemInit() function is called, in "startup_stm32h5xx.s" file, to + * configure the system clock before to branch to main program. + * + * This file configures the system clock as follows: + *============================================================================= + *----------------------------------------------------------------------------- + * System Clock source | HSI + *----------------------------------------------------------------------------- + * SYSCLK(Hz) | 64000000 + *----------------------------------------------------------------------------- + * HCLK(Hz) | 64000000 + *----------------------------------------------------------------------------- + * AHB Prescaler | 1 + *----------------------------------------------------------------------------- + * APB1 Prescaler | 1 + *----------------------------------------------------------------------------- + * APB2 Prescaler | 1 + *----------------------------------------------------------------------------- + * APB3 Prescaler | 1 + *----------------------------------------------------------------------------- + * HSI Division factor | 1 + *----------------------------------------------------------------------------- + * PLL1_SRC | No clock + *----------------------------------------------------------------------------- + * PLL1_M | Prescaler disabled + *----------------------------------------------------------------------------- + * PLL1_N | 129 + *----------------------------------------------------------------------------- + * PLL1_P | 2 + *----------------------------------------------------------------------------- + * PLL1_Q | 2 + *----------------------------------------------------------------------------- + * PLL1_R | 2 + *----------------------------------------------------------------------------- + * PLL1_FRACN | 0 + *----------------------------------------------------------------------------- + * PLL2_SRC | No clock + *----------------------------------------------------------------------------- + * PLL2_M | Prescaler disabled + *----------------------------------------------------------------------------- + * PLL2_N | 129 + *----------------------------------------------------------------------------- + * PLL2_P | 2 + *----------------------------------------------------------------------------- + * PLL2_Q | 2 + *----------------------------------------------------------------------------- + * PLL2_R | 2 + *----------------------------------------------------------------------------- + * PLL2_FRACN | 0 + *----------------------------------------------------------------------------- + * PLL3_SRC | No clock + *----------------------------------------------------------------------------- + * PLL3_M | Prescaler disabled + *----------------------------------------------------------------------------- + * PLL3_N | 129 + *----------------------------------------------------------------------------- + * PLL3_P | 2 + *----------------------------------------------------------------------------- + * PLL3_Q | 2 + *----------------------------------------------------------------------------- + * PLL3_R | 2 + *----------------------------------------------------------------------------- + * PLL3_FRACN | 0 + *----------------------------------------------------------------------------- + *============================================================================= + */ + +/** @addtogroup CMSIS + * @{ + */ + +/** @addtogroup STM32H5xx_system + * @{ + */ + +/** @addtogroup STM32H5xx_System_Private_Includes + * @{ + */ + +#include "stm32h5xx.h" + +/** + * @} + */ + +/** @addtogroup STM32H5xx_System_Private_TypesDefinitions + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32H5xx_System_Private_Defines + * @{ + */ + +#if !defined (HSE_VALUE) + #define HSE_VALUE (25000000UL) /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined (CSI_VALUE) + #define CSI_VALUE (4000000UL) /*!< Value of the Internal oscillator in Hz*/ +#endif /* CSI_VALUE */ + +#if !defined (HSI_VALUE) + #define HSI_VALUE (64000000UL) /*!< Value of the Internal oscillator in Hz */ +#endif /* HSI_VALUE */ + +/************************* Miscellaneous Configuration ************************/ +/*!< Uncomment the following line if you need to relocate your vector Table in + Internal SRAM. */ +/* #define VECT_TAB_SRAM */ +#if !defined(VECT_TAB_OFFSET) +#define VECT_TAB_OFFSET 0x00U /*!< Vector Table base offset field. + This value must be a multiple of 0x200. */ +#endif /* VECT_TAB_OFFSET */ +/******************************************************************************/ + +/** + * @} + */ + +/** @addtogroup STM32H5xx_System_Private_Macros + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32H5xx_System_Private_Variables + * @{ + */ + /* The SystemCoreClock variable is updated in three ways: + 1) by calling CMSIS function SystemCoreClockUpdate() + 2) by calling HAL API function HAL_RCC_GetHCLKFreq() + 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency + Note: If you use this function to configure the system clock; then there + is no need to call the 2 first functions listed above, since SystemCoreClock + variable is updated automatically. + */ + uint32_t SystemCoreClock = 64000000U; + + const uint8_t AHBPrescTable[16] = {0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 1U, 2U, 3U, 4U, 6U, 7U, 8U, 9U}; + const uint8_t APBPrescTable[8] = {0U, 0U, 0U, 0U, 1U, 2U, 3U, 4U}; +/** + * @} + */ + +/** @addtogroup STM32H5xx_System_Private_FunctionPrototypes + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32H5xx_System_Private_Functions + * @{ + */ + +/** + * @brief Setup the microcontroller system. + * @param None + * @retval None + */ + +void SystemInit(void) +{ + uint32_t reg_opsr; + + /* FPU settings ------------------------------------------------------------*/ + #if (__FPU_PRESENT == 1) && (__FPU_USED == 1) + SCB->CPACR |= ((3UL << 20U)|(3UL << 22U)); /* set CP10 and CP11 Full Access */ + #endif + + /* Reset the RCC clock configuration to the default reset state ------------*/ + /* Set HSION bit while preserving the current HSIDIV value*/ + RCC->CR = (RCC->CR & RCC_CR_HSIDIV_Msk) | RCC_CR_HSION; + + /* Reset CFGR register */ + RCC->CFGR1 = 0U; + RCC->CFGR2 = 0U; + + /* Reset HSEON, HSECSSON, HSEBYP, HSEEXT, HSIDIV, HSIKERON, CSION, CSIKERON, HSI48 and PLLxON bits */ +#if defined(RCC_CR_PLL3ON) + RCC->CR &= ~(RCC_CR_HSEON | RCC_CR_HSECSSON | RCC_CR_HSEBYP | RCC_CR_HSEEXT | RCC_CR_HSIKERON | \ + RCC_CR_CSION | RCC_CR_CSIKERON |RCC_CR_HSI48ON | RCC_CR_PLL1ON | RCC_CR_PLL2ON | RCC_CR_PLL3ON); +#else + RCC->CR &= ~(RCC_CR_HSEON | RCC_CR_HSECSSON | RCC_CR_HSEBYP | RCC_CR_HSEEXT | RCC_CR_HSIKERON | \ + RCC_CR_CSION | RCC_CR_CSIKERON |RCC_CR_HSI48ON | RCC_CR_PLL1ON | RCC_CR_PLL2ON); +#endif + + /* Reset PLLxCFGR register */ + RCC->PLL1CFGR = 0U; + RCC->PLL2CFGR = 0U; +#if defined(RCC_CR_PLL3ON) + RCC->PLL3CFGR = 0U; +#endif /* RCC_CR_PLL3ON */ + + /* Reset PLL1DIVR register */ + RCC->PLL1DIVR = 0x01010280U; + /* Reset PLL1FRACR register */ + RCC->PLL1FRACR = 0x00000000U; + /* Reset PLL2DIVR register */ + RCC->PLL2DIVR = 0x01010280U; + /* Reset PLL2FRACR register */ + RCC->PLL2FRACR = 0x00000000U; +#if defined(RCC_CR_PLL3ON) + /* Reset PLL3DIVR register */ + RCC->PLL3DIVR = 0x01010280U; + /* Reset PLL3FRACR register */ + RCC->PLL3FRACR = 0x00000000U; +#endif /* RCC_CR_PLL3ON */ + + /* Reset HSEBYP bit */ + RCC->CR &= ~(RCC_CR_HSEBYP); + + /* Disable all interrupts */ + RCC->CIER = 0U; + + /* Configure the Vector Table location add offset address ------------------*/ + #ifdef VECT_TAB_SRAM + SCB->VTOR = SRAM1_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */ + #else + SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */ + #endif /* VECT_TAB_SRAM */ + + /* Check OPSR register to verify if there is an ongoing swap or option bytes update interrupted by a reset */ + reg_opsr = FLASH->OPSR & FLASH_OPSR_CODE_OP; + if ((reg_opsr == FLASH_OPSR_CODE_OP) || (reg_opsr == (FLASH_OPSR_CODE_OP_2 | FLASH_OPSR_CODE_OP_1))) + { + /* Check FLASH Option Control Register access */ + if ((FLASH->OPTCR & FLASH_OPTCR_OPTLOCK) != 0U) + { + /* Authorizes the Option Byte registers programming */ + FLASH->OPTKEYR = 0x08192A3BU; + FLASH->OPTKEYR = 0x4C5D6E7FU; + } + /* Launch the option bytes change operation */ + FLASH->OPTCR |= FLASH_OPTCR_OPTSTART; + + /* Lock the FLASH Option Control Register access */ + FLASH->OPTCR |= FLASH_OPTCR_OPTLOCK; + } +} + +/** + * @brief Update SystemCoreClock variable according to Clock Register Values. + * The SystemCoreClock variable contains the core clock (HCLK), it can + * be used by the user application to setup the SysTick timer or configure + * other parameters. + * + * @note Each time the core clock (HCLK) changes, this function must be called + * to update SystemCoreClock variable value. Otherwise, any configuration + * based on this variable will be incorrect. + * + * @note - The system frequency computed by this function is not the real + * frequency in the chip. It is calculated based on the predefined + * constant and the selected clock source: + * + * - If SYSCLK source is CSI, SystemCoreClock will contain the CSI_VALUE(*) + * + * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(**) + * + * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(***) + * + * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(***) + * or HSI_VALUE(**) or CSI_VALUE(*) multiplied/divided by the PLL factors. + * + * (*) CSI_VALUE is a constant defined in stm32h5xx_hal.h file (default value + * 4 MHz) but the real value may vary depending on the variations + * in voltage and temperature. + * + * (**) HSI_VALUE is a constant defined in stm32h5xx_hal.h file (default value + * 64 MHz) but the real value may vary depending on the variations + * in voltage and temperature. + * + * (***) HSE_VALUE is a constant defined in stm32h5xx_hal.h file (default value + * 25 MHz), user has to ensure that HSE_VALUE is same as the real + * frequency of the crystal used. Otherwise, this function may + * have wrong result. + * + * - The result of this function could be not correct when using fractional + * value for HSE crystal. + * + * @param None + * @retval None + */ +void SystemCoreClockUpdate(void) +{ + uint32_t pllp, pllsource, pllm, pllfracen, hsivalue, tmp; + float_t fracn1, pllvco; + + /* Get SYSCLK source -------------------------------------------------------*/ + switch (RCC->CFGR1 & RCC_CFGR1_SWS) + { + case 0x00UL: /* HSI used as system clock source */ + SystemCoreClock = (uint32_t) (HSI_VALUE >> ((RCC->CR & RCC_CR_HSIDIV)>> 3)); + break; + + case 0x08UL: /* CSI used as system clock source */ + SystemCoreClock = CSI_VALUE; + break; + + case 0x10UL: /* HSE used as system clock source */ + SystemCoreClock = HSE_VALUE; + break; + + case 0x18UL: /* PLL1 used as system clock source */ + /* PLL_VCO = (HSE_VALUE or HSI_VALUE or CSI_VALUE/ PLLM) * PLLN + SYSCLK = PLL_VCO / PLLR + */ + pllsource = (RCC->PLL1CFGR & RCC_PLL1CFGR_PLL1SRC); + pllm = ((RCC->PLL1CFGR & RCC_PLL1CFGR_PLL1M)>> RCC_PLL1CFGR_PLL1M_Pos); + pllfracen = ((RCC->PLL1CFGR & RCC_PLL1CFGR_PLL1FRACEN)>>RCC_PLL1CFGR_PLL1FRACEN_Pos); + fracn1 = (float_t)(uint32_t)(pllfracen* ((RCC->PLL1FRACR & RCC_PLL1FRACR_PLL1FRACN)>> RCC_PLL1FRACR_PLL1FRACN_Pos)); + + switch (pllsource) + { + case 0x01UL: /* HSI used as PLL clock source */ + hsivalue = (HSI_VALUE >> ((RCC->CR & RCC_CR_HSIDIV)>> 3)) ; + pllvco = ((float_t)hsivalue / (float_t)pllm) * ((float_t)(uint32_t)(RCC->PLL1DIVR & RCC_PLL1DIVR_PLL1N) + \ + (fracn1/(float_t)0x2000) +(float_t)1 ); + break; + + case 0x02UL: /* CSI used as PLL clock source */ + pllvco = ((float_t)CSI_VALUE / (float_t)pllm) * ((float_t)(uint32_t)(RCC->PLL1DIVR & RCC_PLL1DIVR_PLL1N) + \ + (fracn1/(float_t)0x2000) +(float_t)1 ); + break; + + case 0x03UL: /* HSE used as PLL clock source */ + pllvco = ((float_t)HSE_VALUE / (float_t)pllm) * ((float_t)(uint32_t)(RCC->PLL1DIVR & RCC_PLL1DIVR_PLL1N) + \ + (fracn1/(float_t)0x2000) +(float_t)1 ); + break; + + default: /* No clock sent to PLL*/ + pllvco = (float_t) 0U; + break; + } + + pllp = (((RCC->PLL1DIVR & RCC_PLL1DIVR_PLL1P) >>RCC_PLL1DIVR_PLL1P_Pos) + 1U ) ; + SystemCoreClock = (uint32_t)(float_t)(pllvco/(float_t)pllp); + + break; + + default: + SystemCoreClock = HSI_VALUE; + break; + } + /* Compute HCLK clock frequency --------------------------------------------*/ + /* Get HCLK prescaler */ + tmp = AHBPrescTable[((RCC->CFGR2 & RCC_CFGR2_HPRE) >> RCC_CFGR2_HPRE_Pos)]; + /* HCLK clock frequency */ + SystemCoreClock >>= tmp; +} + + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + diff --git a/stm32h563xi_flash.ld b/stm32h563xi_flash.ld new file mode 100644 index 0000000..530ea55 --- /dev/null +++ b/stm32h563xi_flash.ld @@ -0,0 +1,221 @@ +/* +****************************************************************************** +** +** @brief : Linker script for STM32H563xI devices from STM32H5 series +** 2048KBytes FLASH +** 640KBytes RAM +** +** Set heap size, stack size and stack location according +** to application requirements. +** +** Set memory bank area and size if external memory is used +** +** Target : STMicroelectronics STM32 +** +** Distribution: The file is distributed as is, without any warranty +** of any kind. +** +****************************************************************************** +** @attention +** +** Copyright (c) 2026 STMicroelectronics. +** All rights reserved. +** +** This software is licensed under terms that can be found in the LICENSE file +** in the root directory of this software component. +** If no LICENSE file comes with this software, it is provided AS-IS. +** +****************************************************************************** +*/ + +/* Memories definition */ +MEMORY +{ + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 640K + FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 2048K +} + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */ +_sstack = _estack - _Min_Stack_Size; + +_Min_Heap_Size = 0x200; /* required amount of heap */ +_Min_Stack_Size = 0x400; /* required amount of stack */ + +/* Sections */ +SECTIONS +{ + + /* The startup code into "FLASH" Rom type memory */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH + + /* The program code and other data into "FLASH" Rom type memory */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + KEEP (*(.init)) + KEEP (*(.fini)) + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + /* Constant data into "FLASH" Rom type memory */ + .rodata : + { + . = ALIGN(4); + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + } >FLASH + + .ARM.extab (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */ + { + . = ALIGN(4); + *(.ARM.extab* .gnu.linkonce.armextab.*) + . = ALIGN(4); + } >FLASH + + .ARM (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */ + { + . = ALIGN(4); + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + . = ALIGN(4); + } >FLASH + + .preinit_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */ + { + . = ALIGN(4); + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + . = ALIGN(4); + } >FLASH + + .init_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */ + { + . = ALIGN(4); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + . = ALIGN(4); + } >FLASH + + .fini_array (READONLY) : /* The "READONLY" keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */ + { + . = ALIGN(4); + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + . = ALIGN(4); + } >FLASH + + /* Used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data section */ + .data : ALIGN(4) + { + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + *(.RamFunc) /* .RamFunc sections */ + *(.RamFunc*) /* .RamFunc* sections */ + . = ALIGN(4); + } >RAM AT> FLASH + + .tdata : ALIGN(4) + { + *(.tdata .tdata.* .gnu.linkonce.td.*) + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + PROVIDE(__data_end = .); + PROVIDE(__tdata_end = .); + } >RAM AT> FLASH + PROVIDE( __tdata_start = ADDR(.tdata) ); + PROVIDE( __tdata_size = __tdata_end - __tdata_start ); + + PROVIDE( __data_start = ADDR(.data) ); + PROVIDE( __data_size = __data_end - __data_start ); + + PROVIDE( __tdata_source = LOADADDR(.tdata) ); + PROVIDE( __tdata_source_end = LOADADDR(.tdata) + SIZEOF(.tdata) ); + PROVIDE( __tdata_source_size = __tdata_source_end - __tdata_source ); + + PROVIDE( __data_source = LOADADDR(.data) ); + PROVIDE( __data_source_end = __tdata_source_end ); + PROVIDE( __data_source_size = __data_source_end - __data_source ); + + /* Uninitialized data section */ + .tbss (NOLOAD) : ALIGN(4) + { + /* This is used by the startup in order to initialize the .bss and .tbss sections */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + PROVIDE( __bss_start = . ); + *(.tbss .tbss.*) + . = ALIGN(4); + PROVIDE( __tbss_end = . ); + } >RAM + PROVIDE( __tbss_start = ADDR(.tbss) ); + PROVIDE( __tbss_size = __tbss_end - __tbss_start ); + PROVIDE( __tbss_offset = ADDR(.tbss) - ADDR(.tdata) ); + + PROVIDE( __tls_base = __tdata_start ); + PROVIDE( __tls_end = __tbss_end ); + PROVIDE( __tls_size = __tls_end - __tls_base ); + PROVIDE( __tls_align = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)) ); + PROVIDE( __tls_size_align = (__tls_size + __tls_align - 1) & ~(__tls_align - 1) ); + PROVIDE( __arm32_tls_tcb_offset = MAX(8, __tls_align) ); + PROVIDE( __arm64_tls_tcb_offset = MAX(16, __tls_align) ); + + .bss (NOLOAD) : ALIGN(4) + { + *(.bss) + *(.bss*) + *(COMMON) + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + PROVIDE( __bss_end = . ); + } >RAM + PROVIDE( __bss_size = __bss_end - __bss_start ); + PROVIDE( __non_tls_bss_start = ADDR(.bss) ); + + /* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */ + ._user_heap_stack (NOLOAD) : + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(8); + } >RAM + + /* Remove information from the compiler libraries */ + /DISCARD/ : + { + libc.a:* ( * ) + libm.a:* ( * ) + libgcc.a:* ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/yeepi.py b/yeepi.py new file mode 100644 index 0000000..96ce499 --- /dev/null +++ b/yeepi.py @@ -0,0 +1,67 @@ +import spidev +import RPi.GPIO as GPIO + +global spi + +PISPI_BUFFER_SIZE = 256 # Buffer size must match between Pi and STM32 + +# Pin number for our CS pin repurposed as a ready pin +ReadyPin = 8 + +# Initialise the SPI communications +# You must pass in the pigpio handle +# Speed is optional, defaults to 1MHz +def YEEPiInit(speed=1000000): + + # Global these so they can be used later + global spi + + spi = spidev.SpiDev() # Create SPI object + spi.open(0,0) # Open SPI bus 0 device 0 + spi.max_speed_hz = speed # Set speed to inputted speed + spi.mode = 0 # Set SPI mode to 0 + spi.no_cs = True # Disable chip select + + GPIO.setmode(GPIO.BCM) + GPIO.setup(ReadyPin, GPIO.IN, pull_up_down=GPIO.PUD_OFF) + + +# Execute a transfer to YEEP, exchanging buffers +# Takes a bytearray of values and returns a bytearray +# with the received data +# +# Input data smaller than the buffer size will be padded to correct size +# with null bytes. Input data larger will be truncated +# Warnings will be printed in the cases of an array being truncated +# or if received data is blank + +def YEEPiTransfer(TXBuf): + # Check that the input data is a byte array, error if not + if not isinstance(TXBuf, bytearray): + raise TypeError("Data must be byte array") + + # Check if the array is larger, and delete extra entries + if len(TXBuf) > PISPI_BUFFER_SIZE: + print("Warning: Array larger than buffer size, truncating") + del TXBuf[PISPI_BUFFER_SIZE:] # Delete entries beyond buffer size + + # Pad the array to the full size if required + TXBuf = TXBuf.ljust(PISPI_BUFFER_SIZE, b'\0') #Pad to buffer size with null bytes + + # Wait until ready pin is asserted + while not GPIO.input(ReadyPin): + pass # Pass immediatly restarts the loop with no delay - we don't want to wait any longer than we have to + + # Execute the transfer + RXBuf = spi.xfer(TXBuf) + + # If the received buffer is all 0, warn the user + if sum(RXBuf) == 0: + print("Warning: Empty message received") + + # Convert returned list to bytearray + return bytearray(RXBuf) + +# This should be called when the program exits +def YEEPiExit(): + GPIO.cleanup() \ No newline at end of file