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.
This commit is contained in:
2026-10-28 14:37:42 +00:00
commit 50e4ba8a07
56 changed files with 7718 additions and 0 deletions

11
.clangd Normal file
View File

@@ -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

2
.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

10
.gitignore vendored Normal file
View File

@@ -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

View File

@@ -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"
}
]
}
]
}

View File

@@ -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"
}
]
}

11
.settings/ide.store.json Normal file
View File

@@ -0,0 +1,11 @@
{
"board": "NUCLEO-H563ZI",
"device": "STM32H563ZIT6",
"core": "Cortex-M33",
"order": 0,
"toolchain": "GCC",
"source": {
"sourceType": "Empty"
},
"tz": "TZ-disabled"
}

8
.vscode/c_cpp_properties.json vendored Normal file
View File

@@ -0,0 +1,8 @@
{
"configurations": [
{
"name": "STM32",
"compileCommands": "${workspaceFolder}/build/Debug/compile_commands.json"
}
]
}

22
.vscode/launch.json vendored Normal file
View File

@@ -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}"
}
]
}
]
}

15
.vscode/settings.json vendored Normal file
View File

@@ -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++*"
]
}

65
.vscode/tasks.json vendored Normal file
View File

@@ -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"}
]
}

188
CMakeLists.txt Normal file
View File

@@ -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}
$<$<COMPILE_LANGUAGE:C>: ${include_c_DIRS}>
$<$<COMPILE_LANGUAGE:CXX>: ${include_cxx_DIRS}>
$<$<COMPILE_LANGUAGE:ASM>: ${include_asm_DIRS}>
)
# Add project symbols (macros)
target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE
${symbols_SYMB}
$<$<COMPILE_LANGUAGE:C>: ${symbols_c_SYMB}>
$<$<COMPILE_LANGUAGE:CXX>: ${symbols_cxx_SYMB}>
$<$<COMPILE_LANGUAGE:ASM>: ${symbols_asm_SYMB}>
# Configuration specific
$<$<CONFIG:Debug>:DEBUG>
$<$<CONFIG:Release>: >
)
# 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
$<$<COMPILE_LANGUAGE:C>: >
$<$<COMPILE_LANGUAGE:CXX>:
# -Wno-volatile
# -Wold-style-cast
# -Wuseless-cast
# -Wsuggest-override
>
$<$<COMPILE_LANGUAGE:ASM>:-x assembler-with-cpp -MMD -MP>
$<$<CONFIG:Debug>:-O0 -g3 -ggdb>
$<$<CONFIG:Release>:-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} $<TARGET_FILE:${CMAKE_PROJECT_NAME}>
COMMAND ${CMAKE_OBJCOPY} -O ihex $<TARGET_FILE:${CMAKE_PROJECT_NAME}> ${CMAKE_PROJECT_NAME}.hex
COMMAND ${CMAKE_OBJCOPY} -O binary $<TARGET_FILE:${CMAKE_PROJECT_NAME}> ${CMAKE_PROJECT_NAME}.bin
)

55
CMakePresets.json Normal file
View File

@@ -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"
}
]
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,39 @@
#ifndef __YEEP144_DCMOTOR_H
#define __YEEP144_DCMOTOR_H
#include <stdint.h>
// 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

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,29 @@
#ifndef __YEEP144_HCSR04_H
#define __YEEP144_HCSR04_H
#include <stdint.h>
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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 <stdbool.h>
#include <stdarg.h>
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

View File

@@ -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

View File

@@ -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

166
YEEP144lib/src/YEEP144.c Normal file
View File

@@ -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));
}

View File

@@ -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;
}

View File

@@ -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 <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#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

View File

@@ -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 <math.h>
#include <stdlib.h>
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);
}
}

View File

@@ -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 <stdint.h>
// 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);
}

View File

@@ -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 <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#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

View File

@@ -0,0 +1,18 @@
#include "YEEP144_GP2Y0E02B.h"
#include "YEEP144_I2C.h"
#include "stm32h5xx_hal_i2c.h"
#include <math.h>
#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);
}

View File

@@ -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 <stdint.h>
#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){
}

View File

@@ -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 <stdint.h>
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);
}

View File

@@ -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){
}

View File

@@ -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 <string.h>
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;
}

View File

@@ -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){
}

View File

@@ -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);
}

View File

@@ -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 <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdbool.h>
#include <strings.h>
#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.
*/

View File

@@ -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 <stdio.h>
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);
}

View File

@@ -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;
}
}
}

View File

@@ -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)

View File

@@ -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})

View File

@@ -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 */

67
include/stm32h5xx_it.h Normal file
View File

@@ -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 */

View File

@@ -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 */

7
src/main.c Normal file
View File

@@ -0,0 +1,7 @@
#include "YEEP144.h"
#include "stm32h563xx.h"
#include "stm32h5xx_hal.h"
int main(void){
}

683
src/startup_stm32h563xx.S Normal file
View File

@@ -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****/

244
src/syscall.c Normal file
View File

@@ -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 <sys/stat.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>
/* 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__

87
src/sysmem.c Normal file
View File

@@ -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 <errno.h>
#include <stdint.h>
#include <stddef.h>
/**
* 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

403
src/system_stm32h5xx.c Normal file
View File

@@ -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;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/

221
stm32h563xi_flash.ld Normal file
View File

@@ -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) }
}

67
yeepi.py Normal file
View File

@@ -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()