diff --git a/.gitmodules b/.gitmodules index 5a13a8de..6b7098dc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -11,3 +11,21 @@ path = Library/ArduinoJson url = https://github.com/bblanchon/ArduinoJson.git branch = 7.x +[submodule "Library/FreeRTOS-Kernel"] + path = Library/FreeRTOS-Kernel + url = https://github.com/FreeRTOS/FreeRTOS-Kernel.git +[submodule "Library/cmsis_device_f1"] + path = Library/cmsis_device_f1 + url = https://github.com/STMicroelectronics/cmsis_device_f1.git +[submodule "Library/stm32f1xx_hal_driver"] + path = Library/stm32f1xx_hal_driver + url = https://github.com/STMicroelectronics/stm32f1xx_hal_driver.git +[submodule "Library/CMSIS_5"] + path = Library/CMSIS_5 + url = https://github.com/ARM-software/CMSIS_5.git +[submodule "Platform/STM32F1/cmsis_device_f1"] + path = Platform/STM32F1/cmsis_device_f1 + url = https://github.com/STMicroelectronics/cmsis_device_f1.git +[submodule "Platform/STM32F1/stm32f1xx_hal_driver"] + path = Platform/STM32F1/stm32f1xx_hal_driver + url = https://github.com/STMicroelectronics/stm32f1xx_hal_driver.git diff --git a/Applications/Application.h b/Applications/Application.h index ed80d384..943767b6 100644 --- a/Applications/Application.h +++ b/Applications/Application.h @@ -47,31 +47,46 @@ class Application { #define APPLICATION_HELPER_CLASS(CLASS) APPLICATION_HELPER_CLASS_IMPL(CLASS) // Stores all the applications - Optimal for ID lookup -inline std::unordered_map applications; +// Using function-local static to ensure proper initialization order +inline std::unordered_map& GetApplications() { + static std::unordered_map applications; + return applications; +} // Store all the application id in order of registration - Preserves order and is optimal for iteration -inline std::map application_ids; +inline std::map& GetApplicationIDs() { + static std::map application_ids; + return application_ids; +} template -static inline void register_application(Application_Info info, uint32_t order, bool is_system) { +static inline void register_application(uint32_t order, bool is_system) { APPLICATION_CLASS::info.is_system = is_system; // Set system flag - APPLICATION_CLASS::info.factory = []() -> Application* { \ - return new APPLICATION_CLASS(); \ - }; \ - APPLICATION_CLASS::info.destructor = [](Application* app) { \ - delete (APPLICATION_CLASS*)app; \ - }; \ - MLOGI("Application", "Registering application: %s%s", APPLICATION_CLASS::info.name.c_str(), is_system ? " (system)" : ""); \ - uint32_t app_id = StringHash(APPLICATION_CLASS::info.author + '-' + APPLICATION_CLASS::info.name); \ - if (applications.find(app_id) != applications.end()) { \ - return; \ - } \ - applications.insert({app_id, &APPLICATION_CLASS::info}); \ - application_ids[order] = app_id; \ + APPLICATION_CLASS::info.factory = []() -> Application* { + void* mem = pvPortMalloc(sizeof(APPLICATION_CLASS)); + if (mem == nullptr) { + return nullptr; + } + return new(mem) APPLICATION_CLASS(); // Placement new + }; + APPLICATION_CLASS::info.destructor = [](Application* app) { + if (app != nullptr) { + app->~Application(); // Call destructor + vPortFree(app); // Free memory + } + }; + MLOGI("Application", "Registering application: %s%s", APPLICATION_CLASS::info.name.c_str(), is_system ? " (system)" : ""); + uint32_t app_id = StringHash(APPLICATION_CLASS::info.author + '-' + APPLICATION_CLASS::info.name); + auto& applications = GetApplications(); + if (applications.find(app_id) != applications.end()) { + return; + } + applications.insert({app_id, &APPLICATION_CLASS::info}); + GetApplicationIDs()[order] = app_id; } #define REGISTER_APPLICATION(APPLICATION_CLASS, IS_SYSTEM) \ __attribute__((__constructor__)) inline void APPLICATION_HELPER_CLASS(APPLICATION_CLASS)(void) { \ - register_application(APPLICATION_CLASS::info, __COUNTER__, IS_SYSTEM); \ + register_application(__COUNTER__, IS_SYSTEM); \ } diff --git a/Applications/Reversi/Reversi.cpp b/Applications/Reversi/Reversi.cpp index b361226f..4ac7f131 100644 --- a/Applications/Reversi/Reversi.cpp +++ b/Applications/Reversi/Reversi.cpp @@ -18,7 +18,7 @@ void Reversi::Loop() uint8_t Reversi::Flip(Point pos, uint8_t currentPlayer, bool update) { - uint8_t opponentPlayer = currentPlayer == 1 ? 2 : 1; + uint8_t opponentPlayer = (1 == currentPlayer) ? 2 : 1; uint8_t flipped = 0; // Check all 8 directions @@ -548,7 +548,7 @@ bool Reversi::ResetGame(bool confirmed) firstPlayer.Load(); // For some reason, the firstPlayer is not auto loaded correctly - uint8_t secondPlayer = (firstPlayer == 1) ? 2 : 1; + uint8_t secondPlayer = (1 == firstPlayer) ? 2 : 1; board[3][3].player = firstPlayer; board[3][3].wasPlayer = firstPlayer; @@ -637,14 +637,14 @@ void Reversi::Settings() { UIButton player1FirstHand; player1FirstHand.SetName("Player 1 First Hand"); - player1FirstHand.SetColorFunc([&]() -> Color { return Color::White.DimIfNot(firstPlayer == 1); }); - player1FirstHand.OnPress([&]() -> void { if(firstPlayer == 1) {return;} if (gameState == Ended || !started || ConfirmMenu()) { firstPlayer = 1; ResetGame(true);} }); + player1FirstHand.SetColorFunc([&]() -> Color { return Color::White.DimIfNot(1 == firstPlayer); }); + player1FirstHand.OnPress([&]() -> void { if(1 == firstPlayer) {return;} if (gameState == Ended || !started || ConfirmMenu()) { firstPlayer = 1; ResetGame(true);} }); settingsUI.AddUIComponent(player1FirstHand, Point(7, 6)); UIButton player2FirstHand; player2FirstHand.SetName("Player 2 First Hand"); - player2FirstHand.SetColorFunc([&]() -> Color { return Color::White.DimIfNot(firstPlayer == 2); }); - player2FirstHand.OnPress([&]() -> void { if(firstPlayer == 2) {return;} if (gameState == Ended || !started || ConfirmMenu()) { firstPlayer = 2; ResetGame(true);} }); + player2FirstHand.SetColorFunc([&]() -> Color { return Color::White.DimIfNot(2 == firstPlayer); }); + player2FirstHand.OnPress([&]() -> void { if(2 == firstPlayer) {return;} if (gameState == Ended || !started || ConfirmMenu()) { firstPlayer = 2; ResetGame(true);} }); settingsUI.AddUIComponent(player2FirstHand, Point(0, 1)); UIToggle hintToggle; diff --git a/Applications/Shell/Shell.cpp b/Applications/Shell/Shell.cpp index f648b3b4..27a4dfad 100644 --- a/Applications/Shell/Shell.cpp +++ b/Applications/Shell/Shell.cpp @@ -61,12 +61,15 @@ void Shell::InitializeFolderSystem() { } // First, add all native apps to all_applications + auto& applications = GetApplications(); for (const auto& [app_id, app_info] : applications) { all_applications.emplace(app_id, ApplicationEntry(app_info)); } // Then discover and add Python applications +#if DEVICE_STORAGE DiscoverPythonApps(); +#endif // Try to load existing folder vectors from NVS bool folders_loaded = false; @@ -94,6 +97,7 @@ void Shell::InitializeFolderSystem() { bool missing_apps_found = false; // First, check native apps in registration order + auto& application_ids = GetApplicationIDs(); for (const auto& [order_id, app_id] : application_ids) { // If app is not in any folder, add it if (apps_in_folders.find(app_id) == apps_in_folders.end()) { @@ -359,6 +363,7 @@ uint8_t Shell::GetAppFolder(uint32_t app_id, const ApplicationEntry& app_entry) return 0; } +#if DEVICE_STORAGE void Shell::DiscoverPythonApps() { MLOGI("Shell", "Starting Python application discovery"); @@ -385,6 +390,7 @@ void Shell::DiscoverPythonApps() { MLOGI("Shell", "Python application discovery completed: %d apps added", python_app_infos.size()); } +#endif void Shell::ApplicationLauncher() { uint8_t tap_counter = 0; diff --git a/Applications/Shell/Shell.h b/Applications/Shell/Shell.h index 29ca0556..41fe316f 100644 --- a/Applications/Shell/Shell.h +++ b/Applications/Shell/Shell.h @@ -84,8 +84,10 @@ class Shell : public Application { void MoveAppToFolder(uint32_t app_id, uint8_t folder_id); // Python application discovery +#if DEVICE_STORAGE void DiscoverPythonApps(); - +#endif + // Helper functions for NVS void SaveFolderVector(uint8_t folder_id); void LoadFolderVector(uint8_t folder_id); diff --git a/CMakeLists.txt b/CMakeLists.txt index 6da50b17..79c8b84f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,15 @@ cmake_minimum_required(VERSION 3.16) +if(NOT DEFINED DEVICE) + message(FATAL_ERROR "You must specify -DDEVICE=") +endif() + +if(NOT DEFINED FAMILY) + set(FAMILY_PATH ${CMAKE_SOURCE_DIR}/Devices/${DEVICE}) +else() + set(FAMILY_PATH ${CMAKE_SOURCE_DIR}/Devices/${FAMILY}) +endif() + project(MatrixOS-${DEVICE}) # # Global C flags @@ -83,7 +93,26 @@ else() message( FATAL_ERROR "MODE is not defined" ) endif() +# Load device feature flags before processing subdirectories +if(NOT EXISTS ${FAMILY_PATH}/Config.cmake) + message(FATAL_ERROR "Config.cmake not found in ${FAMILY_PATH}. Please create this file to define DEVICE_STORAGE and DEVICE_BATTERY.") +endif() +include(${FAMILY_PATH}/Config.cmake) + +# Pass device feature flags as compile definitions to all targets +add_compile_definitions( + DEVICE_STORAGE=${DEVICE_STORAGE} + DEVICE_BATTERY=${DEVICE_BATTERY} +) + +# Set debug flags globally for all targets before adding subdirectories +if(MODE STREQUAL "DEVELOPMENT" OR MODE STREQUAL "UNDEFINED") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g3 -Og") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -Og") + message(STATUS "Building with debug symbols: -g3 -Og") +endif() + +add_subdirectory(${FAMILY_PATH}) add_subdirectory(Devices) add_subdirectory(OS) -add_subdirectory(${FAMILY_PATH}) add_subdirectory(Applications) diff --git a/Devices/MatrixBlock5/ApplicationList.txt b/Devices/MatrixBlock5/ApplicationList.txt new file mode 100644 index 00000000..f77f125d --- /dev/null +++ b/Devices/MatrixBlock5/ApplicationList.txt @@ -0,0 +1,45 @@ +# Applications List - MatrixBlock5 +# Format: +# FolderName - Regular application (sandboxed) +# [System]FolderName - System application (privileged) +# git:URL@branch/hash - Clone git repository at specific branch/commit +# [System]git:URL@branch - System application from git repository +# Applications register their class via RegisterApplicationClass() in their CMakeLists.txt +# Git applications are cloned to {FAMILY_PATH}/Applications/ directory +# Use # for comments and empty lines are allowed +# +# Git URL Examples: +# git:https://github.com/user/myapp@main +# git:https://github.com/user/myapp@v1.2.3 +# git:https://github.com/user/myapp@abc123d +# [System]git:https://github.com/user/sysapp@feature-branch + +# Device UI +Setting +BrightnessControl + +# System Apps +[System]Shell +#MSC + +# User Facing Apps +Performance +#Note +#REDACTED +#Companion +#CustomControlMap +#Lighting +#Dice +#Reversi +#Strum +#[System]Python + +# Boot animation +{FAMILY_PATH}/Applications/MystrixBoot + +# Device-specific applications (if any) +# {FAMILY_PATH}/Applications/FactoryMenu +# {FAMILY_PATH}/Applications/ForceCalibration + +# Example application template +#git:https://github.com/203-Systems/Matrix-OS-APP-Template.git@master \ No newline at end of file diff --git a/Devices/MatrixBlock5/Applications/MystrixBoot/CMakeLists.txt b/Devices/MatrixBlock5/Applications/MystrixBoot/CMakeLists.txt new file mode 100644 index 00000000..67ed049a --- /dev/null +++ b/Devices/MatrixBlock5/Applications/MystrixBoot/CMakeLists.txt @@ -0,0 +1,18 @@ +# MystrixBoot Application +file(GLOB_RECURSE MYSTRIXBOOT_SOURCES "*.cpp" "*.c") +file(GLOB_RECURSE MYSTRIXBOOT_HEADERS "*.h") + +add_library(MystrixBootAPP ${MYSTRIXBOOT_SOURCES} ${MYSTRIXBOOT_HEADERS}) + +target_include_directories(MystrixBootAPP PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_link_libraries(MystrixBootAPP PUBLIC + MatrixOSInterface + MatrixOSAPPInterface + BootAnimationTemplate +) + +# Register the application class +RegisterApplicationClass(MystrixBoot) \ No newline at end of file diff --git a/Devices/MatrixBlock5/Applications/MystrixBoot/MystrixBoot.cpp b/Devices/MatrixBlock5/Applications/MystrixBoot/MystrixBoot.cpp new file mode 100644 index 00000000..04f32805 --- /dev/null +++ b/Devices/MatrixBlock5/Applications/MystrixBoot/MystrixBoot.cpp @@ -0,0 +1,241 @@ +#include "MystrixBoot.h" + +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) > (b) ? (a) : (b)) + +void MystrixBoot::Setup(const vector& args) { + for (uint8_t i = 0; i < 100; i++) // Add small delay for USB to be connected (So no idle animation would be shown) + { + MatrixOS::SYS::DelayMs(5); + if (MatrixOS::USB::Connected()) + break; + } +} + +bool MystrixBoot::Idle(bool ready) { + uint8_t step = counter % 12; + if (timer.Tick(80)) + { + MatrixOS::LED::Fill(0); + const Color local_color = Color::White.Scale(MATRIX_BOOT_IDLE * 255); + if (step <= 3) + { + Point line_origin = origin + Point(-1, -1) + Point(0, step); + for (uint8_t i = 0; i < step + 1; i++) + { MatrixOS::LED::SetColor(line_origin + Point(1, -1) * i, local_color); } + } + else if (step <= 6) + { + Point line_origin = origin + Point(0, 2) + Point(step - 4, 0); + for (uint8_t i = 0; i < 3 - (step - 4); i++) + { MatrixOS::LED::SetColor(line_origin + Point(1, -1) * i, local_color); } + } + MatrixOS::LED::Update(); + counter++; + } + return step > 6 && ready; +} + +void MystrixBoot::Boot() { + switch (boot_phase) + { + + case 0: + MatrixOS::LED::Fill(0); + counter = 0; + boot_phase++; + [[fallthrough]]; + case 1: + BootPhase1(); + break; + case 2: + BootPhase2(); + break; + } +} + +void MystrixBoot::BootPhase1() { + if (boot_phase_1_tick_time == 0) + boot_phase_1_tick_time = MatrixOS::SYS::Millis(); + + const uint16_t section_time = 80; + if (timer.Tick(1000 / Device::LED::fps)) + { + uint32_t delta_time = MatrixOS::SYS::Millis() - boot_phase_1_tick_time; + uint8_t local_brightness = min(255 * ((float)delta_time / section_time), 255); + Color local_color = Color(local_brightness, local_brightness, local_brightness); + + if (counter <= 3) + { + Point line_origin = origin + Point(-1, -1) + Point(0, counter); + for (uint8_t i = 0; i < counter + 1; i++) + { MatrixOS::LED::SetColor(line_origin + Point(1, -1) * i, local_color); } + } + else if (counter <= 6) + { + Point line_origin = origin + Point(0, 2) + Point(counter - 4, 0); + for (uint8_t i = 0; i < 3 - (counter - 4); i++) + { MatrixOS::LED::SetColor(line_origin + Point(1, -1) * i, local_color); } + } + MatrixOS::LED::Update(); + if (delta_time >= section_time) + { + if (counter == 6) + { + boot_phase++; + counter = 0; + // MatrixOS::SYS::DelayMs(20); + return; + } + boot_phase_1_tick_time = MatrixOS::SYS::Millis(); + counter++; + } + } +} + +Color MystrixBoot::BootPhase2Color(int16_t time, float hue) { + float saturation; + float brightness; + + // Saturation Function + if (time < 0) + { saturation = 0; } + else if (time < 400) + { saturation = (float)(time - 0) / 400.0; } + else + { saturation = 1.0; } + + // Brightness Function + if (time < -100) + { brightness = 0; } + else if (time < 0) + { brightness = ((float)(time + 100) / 100 * MATRIX_BOOT_BRIGHTNESS); } + else if (time < 300) + { brightness = MATRIX_BOOT_BRIGHTNESS; } + else if (time < 500) + { brightness = ((1.0 - (float)(time - 300) / 200.0) * MATRIX_BOOT_BRIGHTNESS); } + else + { brightness = 0; } + + return Color::HsvToRgb(hue, saturation, brightness); + + // // HSV to RGB + // Color color; + // uint8_t region, remainder, p, q, t; + + // if (saturation == 0) + // { + // color.R = brightness; + // color.G = brightness; + // color.B = brightness; + // return color; + // } + + // region = hue / 43; + // remainder = (hue - (region * 43)) * 6; + + // p = (brightness * (255 - saturation)) >> 8; + // q = (brightness * (255 - ((saturation * remainder) >> 8))) >> 8; + // t = (brightness * (255 - ((saturation * (255 - remainder)) >> 8))) >> 8; + + // switch (region) + // { + // case 0: + // color.R = brightness; + // color.G = t; + // color.B = p; + // break; + // case 1: + // color.R = q; + // color.G = brightness; + // color.B = p; + // break; + // case 2: + // color.R = p; + // color.G = brightness; + // color.B = t; + // break; + // case 3: + // color.R = p; + // color.G = q; + // color.B = brightness; + // break; + // case 4: + // color.R = t; + // color.G = p; + // color.B = brightness; + // break; + // default: + // color.R = brightness; + // color.G = p; + // color.B = q; + // break; + // } + + // return color; +} + +void MystrixBoot::BootPhase2QuadSetColor(uint8_t x_offset, uint8_t y_offset, Color color1, Color color2) { + Point point_q1 = origin + Point(1, 1) + Point(x_offset, y_offset); + MatrixOS::LED::SetColor(point_q1, color2); + + Point point_q2 = origin + Point(0, 1) + Point(-x_offset, y_offset); + MatrixOS::LED::SetColor(point_q2, color1); + + Point point_q3 = origin + Point(0, 0) + Point(-x_offset, -y_offset); + MatrixOS::LED::SetColor(point_q3, color2); + + Point point_q4 = origin + Point(1, 0) + Point(x_offset, -y_offset); + MatrixOS::LED::SetColor(point_q4, color1); +} + +void MystrixBoot::BootPhase2() { + float hue[2]; + + memcpy(hue, hueList[0], sizeof(hue)); + + const uint16_t start_offset = 150; + if (timer.Tick(1000 / Device::LED::fps)) + { + + if (boot_phase_2_start_time == 0) + boot_phase_2_start_time = MatrixOS::SYS::Millis(); + + uint32_t delta_time = MatrixOS::SYS::Millis() - boot_phase_2_start_time; + uint8_t quad_size = max(X_SIZE, Y_SIZE) / 2 + 1; + if (delta_time > (quad_size - 2) * start_offset + 700 + 100) + { Exit(); } + + for (uint8_t r = 0; r < quad_size; r++) // radius + { + uint16_t local_deltatime = delta_time - (r - 1) * start_offset; + Color color1 = BootPhase2Color(local_deltatime, hue[0]); + Color color2 = BootPhase2Color(local_deltatime, hue[1]); + BootPhase2QuadSetColor(r, r, color1, color2); + if (r > 0) + { + uint16_t local_deltatime_half = local_deltatime + start_offset / 2; + Color half_color1 = BootPhase2Color(local_deltatime_half, hue[0]); + Color half_color2 = BootPhase2Color(local_deltatime_half, hue[1]); + BootPhase2QuadSetColor(r - 1, r, half_color1, half_color2); + BootPhase2QuadSetColor(r, r - 1, half_color1, half_color2); + } + #ifdef FAMILY_MYSTRIX + if(r > 3) + { + uint16_t local_deltatime_half = local_deltatime + start_offset * 3 / 2; + Color half_color1 = BootPhase2Color(local_deltatime_half, hue[0]); + Color half_color2 = BootPhase2Color(local_deltatime_half, hue[1]); + BootPhase2QuadSetColor(r - 2, r, half_color1, half_color2); + BootPhase2QuadSetColor(r, r - 2, half_color1, half_color2); + } + #endif + } + MatrixOS::LED::Update(); + } +} + +void MystrixBoot::End() { + MatrixOS::LED::Fill(0); + MatrixOS::LED::Update(); +} \ No newline at end of file diff --git a/Devices/MatrixBlock5/Applications/MystrixBoot/MystrixBoot.h b/Devices/MatrixBlock5/Applications/MystrixBoot/MystrixBoot.h new file mode 100644 index 00000000..416e4b3f --- /dev/null +++ b/Devices/MatrixBlock5/Applications/MystrixBoot/MystrixBoot.h @@ -0,0 +1,42 @@ +#pragma once + +#include "BootAnimation/BootAnimation.h" // TODO Need to be fixed + +#define MATRIX_BOOT_BRIGHTNESS 1.0 // On Top of system brightness +#define MATRIX_BOOT_IDLE 0.25 // On Top of system brightness + +class MystrixBoot : public BootAnimation { + public: + inline static Application_Info info = { + .name = "Mystrix Boot", + .author = "203 Systems", + .color = Color(0xFFFFFFFF), + .version = 1, + .visibility = false, + }; + + // CreateSavedVar(bool, notFirstBoot, false); + Timer timer; + + Point origin = Point((X_SIZE - 1) / 2, (Y_SIZE - 1) / 2); + uint8_t counter; + + uint8_t boot_phase; + uint32_t boot_phase_1_tick_time = 0; + uint32_t boot_phase_2_start_time = 0; + float hueList[1][2] = { + {0.5f, 0.167f} // Standard - Yellow Cyan + }; + + void Setup(const vector& args) override; + bool Idle(bool ready) override; + void Boot() override; + void BootPhase1(); + void BootPhase2(); + Color BootPhase2Color(int16_t time, float hue); + void BootPhase2QuadSetColor(uint8_t x_offset, uint8_t y_offset, Color color1, Color color2); + + void End(); +}; + + diff --git a/Devices/MatrixBlock5/CMakeLists.txt b/Devices/MatrixBlock5/CMakeLists.txt new file mode 100644 index 00000000..6bf57165 --- /dev/null +++ b/Devices/MatrixBlock5/CMakeLists.txt @@ -0,0 +1,192 @@ +# MatrixBlock5 uses STM32F103 +set(DEVICE_TARGET "STM32F103") + +enable_language(ASM) + +# Include the STM32 toolchain file +include(${CMAKE_CURRENT_SOURCE_DIR}/toolchain-stm32f103.cmake) + +# Common compiler flags for STM32F103 +set(COMMON_FLAGS "-mcpu=cortex-m3 -mthumb -mfloat-abi=soft -mabi=aapcs -nostartfiles") +set(CMAKE_C_FLAGS "${COMMON_FLAGS} -std=gnu11 -Wno-unused-command-line-argument") +set(CMAKE_CXX_FLAGS "${COMMON_FLAGS} -fno-rtti -fno-exceptions -Wno-unused-command-line-argument") +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_ASM_FLAGS "${COMMON_FLAGS} -x assembler-with-cpp") + +# Force Thumb mode for all compilation and assembly +# Add -w to suppress all compiler warnings as well +# Use -mthumb-interwork to improve Thumb compatibility +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mthumb-interwork -Wa,-mthumb -Wa,-mimplicit-it=always -Wa,-mcpu=cortex-m3 -Wa,-W -w") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mthumb-interwork -Wa,-mthumb -Wa,-mimplicit-it=always -Wa,-mcpu=cortex-m3 -Wa,-W -w") +set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -mthumb-interwork -Wa,-mthumb -Wa,-mimplicit-it=always -Wa,-mcpu=cortex-m3 -Wa,-W -w") + +# Disable assembler warnings being treated as errors globally - be more aggressive +# CMake should not fail on compiler warnings +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error -Wno-error=all") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error -Wno-error=all") +set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -Wno-error -Wno-error=all") + +# Tell CMake to not fail on warnings +set(CMAKE_COMPILE_WARNING_AS_ERROR OFF) + +# TinyUSB compile options for STM32F1 +# These flags reduce optimization to avoid complex ARM assembly warnings +set(DEVICE_TINYUSB_COMPILE_OPTIONS + "-O0" + "-Wno-implicit-fallthrough" + "-Wno-format" + "-fno-lto" + "-fno-fat-lto-objects" +) + +# Debug flags +if(MODE STREQUAL "DEVELOPMENT" OR MODE STREQUAL "UNDEFINED") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g3 -Og") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -Og") + set(CMAKE_EXE_LINKER_FLAGS "${COMMON_FLAGS} -g3 -specs=nosys.specs -specs=nano.specs -Wl,--gc-sections -Wl,-Map=${PROJECT_NAME}.map -T${CMAKE_CURRENT_SOURCE_DIR}/Variants/MatrixFounderEdition/STM32F103RETx_FLASH.ld") +else() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Os") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Os") + set(CMAKE_EXE_LINKER_FLAGS "${COMMON_FLAGS} -specs=nosys.specs -specs=nano.specs -Wl,--gc-sections -Wl,-Map=${PROJECT_NAME}.map -T${CMAKE_CURRENT_SOURCE_DIR}/Variants/MatrixFounderEdition/STM32F103RETx_FLASH.ld") +endif() + +# Collect all device source files +file(GLOB_RECURSE DEVICE_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/Family.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/Drivers/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/Variants/MatrixFounderEdition/*.cpp" + "${CMAKE_SOURCE_DIR}/Platform/STM32F1/WS2812/*.cpp" +) + +# STM32 HAL source files +set(STM32_HAL_SOURCES + ${CMAKE_SOURCE_DIR}/Platform/STM32F1/stm32f1xx_hal_driver/Src/stm32f1xx_hal.c + ${CMAKE_SOURCE_DIR}/Platform/STM32F1/stm32f1xx_hal_driver/Src/stm32f1xx_hal_cortex.c + ${CMAKE_SOURCE_DIR}/Platform/STM32F1/stm32f1xx_hal_driver/Src/stm32f1xx_hal_rcc.c + ${CMAKE_SOURCE_DIR}/Platform/STM32F1/stm32f1xx_hal_driver/Src/stm32f1xx_hal_rcc_ex.c + ${CMAKE_SOURCE_DIR}/Platform/STM32F1/stm32f1xx_hal_driver/Src/stm32f1xx_hal_gpio.c + ${CMAKE_SOURCE_DIR}/Platform/STM32F1/stm32f1xx_hal_driver/Src/stm32f1xx_hal_dma.c + ${CMAKE_SOURCE_DIR}/Platform/STM32F1/stm32f1xx_hal_driver/Src/stm32f1xx_hal_tim.c + ${CMAKE_SOURCE_DIR}/Platform/STM32F1/stm32f1xx_hal_driver/Src/stm32f1xx_hal_tim_ex.c + ${CMAKE_SOURCE_DIR}/Platform/STM32F1/stm32f1xx_hal_driver/Src/stm32f1xx_hal_pwr.c + ${CMAKE_SOURCE_DIR}/Platform/STM32F1/stm32f1xx_hal_driver/Src/stm32f1xx_hal_rtc.c + ${CMAKE_SOURCE_DIR}/Platform/STM32F1/stm32f1xx_hal_driver/Src/stm32f1xx_hal_rtc_ex.c + ${CMAKE_SOURCE_DIR}/Platform/STM32F1/stm32f1xx_hal_driver/Src/stm32f1xx_hal_flash.c + ${CMAKE_SOURCE_DIR}/Platform/STM32F1/stm32f1xx_hal_driver/Src/stm32f1xx_hal_flash_ex.c + ${CMAKE_SOURCE_DIR}/Platform/STM32F1/cmsis_device_f1/Source/Templates/system_stm32f1xx.c +) + +file(GLOB_RECURSE DEVICE_HEADERS + "${CMAKE_CURRENT_SOURCE_DIR}/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/Drivers/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/Variants/MatrixFounderEdition/*.h" +) + +add_library(MatrixOSDevice + ${DEVICE_SOURCES} + ${STM32_HAL_SOURCES} + ${DEVICE_HEADERS} + ${CMAKE_SOURCE_DIR}/Library/tinyusb/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + ${CMAKE_SOURCE_DIR}/Platform/STM32F1/cmsis_device_f1/Source/Templates/gcc/startup_stm32f103xe.s +) + +target_include_directories(MatrixOSDevice PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/Variants/MatrixFounderEdition + ${CMAKE_SOURCE_DIR}/Platform/STM32F1 + ${CMAKE_SOURCE_DIR}/Library/FatFs/source + ${CMAKE_SOURCE_DIR}/Library/FreeRTOS-Kernel/include + ${CMAKE_SOURCE_DIR}/Library/FreeRTOS-Kernel/portable/GCC/ARM_CM3 + ${CMAKE_SOURCE_DIR}/Platform/STM32F1/cmsis_device_f1/Include + ${CMAKE_SOURCE_DIR}/Platform/STM32F1/stm32f1xx_hal_driver/Inc + ${CMAKE_SOURCE_DIR}/Library/CMSIS_5/CMSIS/Core/Include + ${CMAKE_SOURCE_DIR}/Library/tinyusb/src + ${CMAKE_SOURCE_DIR}/OS/USB/TinyUSB +) + +# Add FreeRTOSConfig.h directory to compiler include paths +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +# Add FreeRTOS library +add_library(FreeRTOS STATIC + ${CMAKE_SOURCE_DIR}/Library/FreeRTOS-Kernel/FreeRTOS/Source/list.c + ${CMAKE_SOURCE_DIR}/Library/FreeRTOS-Kernel/FreeRTOS/Source/queue.c + ${CMAKE_SOURCE_DIR}/Library/FreeRTOS-Kernel/FreeRTOS/Source/tasks.c + ${CMAKE_SOURCE_DIR}/Library/FreeRTOS-Kernel/FreeRTOS/Source/timers.c + ${CMAKE_SOURCE_DIR}/Library/FreeRTOS-Kernel/FreeRTOS/Source/event_groups.c + ${CMAKE_SOURCE_DIR}/Library/FreeRTOS-Kernel/FreeRTOS/Source/stream_buffer.c + ${CMAKE_SOURCE_DIR}/Library/FreeRTOS-Kernel/FreeRTOS/Source/portable/MemMang/heap_4.c + ${CMAKE_SOURCE_DIR}/Library/FreeRTOS-Kernel/FreeRTOS/Source/portable/GCC/ARM_CM3/port.c +) + +# Add FreeRTOS library with proper include paths +target_include_directories(FreeRTOS PUBLIC + ${CMAKE_SOURCE_DIR}/Library/FreeRTOS-Kernel/FreeRTOS/Source/include + ${CMAKE_SOURCE_DIR}/Library/FreeRTOS-Kernel/FreeRTOS/Source/portable/GCC/ARM_CM3 + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/Variants/MatrixFounderEdition + ${CMAKE_SOURCE_DIR}/Platform/STM32F1 + ${CMAKE_SOURCE_DIR}/Platform/STM32F1/cmsis_device_f1/Include + ${CMAKE_SOURCE_DIR}/Platform/STM32F1/stm32f1xx_hal_driver/Inc + ${CMAKE_SOURCE_DIR}/Library/CMSIS_5/CMSIS/Core/Include +) + +# Apply Thumb mode compiler flags to FreeRTOS target +target_compile_options(FreeRTOS PUBLIC + "-Wa,-mthumb" + "-Wa,-mimplicit-it=thumb" + "-Wa,-mcpu=cortex-m3" +) + +# Add Thumb-2 definition for FreeRTOS +target_compile_definitions(FreeRTOS PUBLIC + __thumb2__=1 +) + +# STM32F103 specific definitions +# Note: VDD_VALUE, PREFETCH_ENABLE, HSE/LSE/HSI/LSI values are defined in stm32f1xx_hal_conf.h +target_compile_definitions(MatrixOSDevice PUBLIC + STM32F103xE + USE_HAL_DRIVER + CFG_TUSB_MCU=OPT_MCU_STM32F1 + __thumb2__=1 + VECT_TAB_OFFSET=0x2000 +) + +# Set C++ standard for MatrixOSDevice target +target_compile_features(MatrixOSDevice PUBLIC cxx_std_17) + +# Link with MatrixOS framework and FreeRTOS +target_link_libraries(MatrixOSDevice PUBLIC + DeviceInterface + MatrixOSFramework + FreeRTOS +) + +# Create executable +set(elf_file ${CMAKE_PROJECT_NAME}.elf) + +add_executable(${elf_file} ${CMAKE_SOURCE_DIR}/OS/main.cpp) +target_compile_features(${elf_file} PUBLIC cxx_std_17) + +target_link_libraries(${elf_file} + PRIVATE MatrixOS + PRIVATE MatrixOSDevice +) + +# Generate binary and hex files +add_custom_command(TARGET ${elf_file} POST_BUILD + COMMAND ${CMAKE_OBJCOPY} -O binary ${elf_file} ${PROJECT_NAME}.bin + COMMAND ${CMAKE_OBJCOPY} -O ihex ${elf_file} ${PROJECT_NAME}.hex + COMMAND ${CMAKE_SIZE} ${elf_file} + COMMENT "Generating binary and hex files" +) + +# Copy ELF file to standard location for debug tools +add_custom_command(TARGET ${elf_file} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_BINARY_DIR}/${elf_file} + ${CMAKE_BINARY_DIR}/${elf_file} + COMMENT "Copying ELF file to build root for debug tools" +) \ No newline at end of file diff --git a/Devices/MatrixBlock5/Config.cmake b/Devices/MatrixBlock5/Config.cmake new file mode 100644 index 00000000..62ba9ddd --- /dev/null +++ b/Devices/MatrixBlock5/Config.cmake @@ -0,0 +1,5 @@ +# Device feature configuration for MatrixBlock5 family +# These values must match the #define values in MatrixOSConfig.h + +set(DEVICE_STORAGE 0) +set(DEVICE_BATTERY 0) diff --git a/Devices/MatrixBlock5/Drivers/Keypad.cpp b/Devices/MatrixBlock5/Drivers/Keypad.cpp new file mode 100644 index 00000000..e6daf3af --- /dev/null +++ b/Devices/MatrixBlock5/Drivers/Keypad.cpp @@ -0,0 +1,189 @@ +// Define Device Keypad Function +#include "Device.h" +#include "timers.h" +#include "MatrixOSConfig.h" + +namespace Device::KeyPad +{ + StaticTimer_t keypad_timer_def; + TimerHandle_t keypad_timer; + + void Init() { + InitFN(); + InitKeyPad(); + InitTouchBar(); + } + + void InitFN() { + // FN key is already configured in Family.cpp's KeyPad_Init() + // This function is kept for API compatibility + } + + void InitKeyPad() { + // Keypad is already configured in Family.cpp's KeyPad_Init() + // This function is kept for API compatibility + } + + void InitTouchBar() { + // TODO: Initialize touch bar for STM32F103 + } + + // Timer callback wrapper with correct signature + static void KeypadTimerCallback(TimerHandle_t xTimer) { + (void)xTimer; + Scan(); + } + + void StartKeyPad() { + // Create FreeRTOS timer for keypad scanning + keypad_timer = xTimerCreateStatic(NULL, configTICK_RATE_HZ / keypad_scanrate, true, NULL, KeypadTimerCallback, &keypad_timer_def); + xTimerStart(keypad_timer, 0); + } + + void StartTouchBar() { + // TODO: Start touch bar scanning for STM32F103 + } + + void Start() { + StartKeyPad(); + StartTouchBar(); + } + + void Scan() { + ScanFN(); + ScanKeyPad(); + } + + bool ScanKeyPad() { + // MatrixBlock5 uses binary keypad scanning (no FSR support) + for (uint8_t x = 0; x < X_SIZE; x++) + { + // Activate column + HAL_GPIO_WritePin(keypad_write_ports[x], keypad_write_pins[x], GPIO_PIN_SET); + + for (uint8_t y = 0; y < Y_SIZE; y++) + { + // Read row + if (keypadState[x][y].Update(keypad_config, read)) + { + uint16_t keyID = (1 << 12) + (x << 6) + y; + if (NotifyOS(keyID, &keypadState[x][y])) + { + // Deactivate column and return if OS notification interrupted + HAL_GPIO_WritePin(keypad_write_ports[x], keypad_write_pins[x], GPIO_PIN_RESET); + return true; + } + } + } + + // Deactivate column + HAL_GPIO_WritePin(keypad_write_ports[x], keypad_write_pins[x], GPIO_PIN_RESET); + + // Small delay for settling + volatile int i; + for (i = 0; i < 5; ++i) {} + } + return false; + } + + bool ScanFN() { + Fract16 read = HAL_GPIO_ReadPin(fn_port, fn_pin) * UINT16_MAX; + if (fn_active_low) + { read = UINT16_MAX - (uint16_t)read; } + if (fnState.Update(keypad_config, read)) + { + if (NotifyOS(0, &fnState)) + { return true; } + } + return false; + } + + void Clear() { + fnState.Clear(); + + for (uint8_t x = 0; x < X_SIZE; x++) + { + for (uint8_t y = 0; y < Y_SIZE; y++) + { keypadState[x][y].Clear(); } + } + + for (uint8_t i = 0; i < touchbar_size; i++) + { touchbarState[i].Clear(); } + } + + KeyInfo* GetKey(uint16_t keyID) { + uint8_t keyClass = keyID >> 12; + switch (keyClass) + { + case 0: // System + { + uint16_t index = keyID & (0b0000111111111111); + switch (index) + { + case 0: + return &fnState; + } + break; + } + case 1: // Main Grid + { + int16_t x = (keyID & (0b0000111111000000)) >> 6; + int16_t y = keyID & (0b0000000000111111); + if (x < X_SIZE && y < Y_SIZE) + return &keypadState[x][y]; + break; + } + case 2: // Touch Bar + { + uint16_t index = keyID & (0b0000111111111111); + if (index < touchbar_size) + return &touchbarState[index]; + break; + } + } + return nullptr; + } + + bool NotifyOS(uint16_t keyID, KeyInfo* keyInfo) { + KeyEvent keyEvent; + keyEvent.id = keyID; + keyEvent.info = *keyInfo; + return MatrixOS::KeyPad::NewEvent(&keyEvent); + } + + uint16_t XY2ID(Point xy) { + if (xy.x >= 0 && xy.x < 8 && xy.y >= 0 && xy.y < 8) // Main grid + { return (1 << 12) + (xy.x << 6) + xy.y; } + else if ((xy.x == -1 || xy.x == 8) && (xy.y >= 0 && xy.y < 8)) // Touch Bar + { return (2 << 12) + xy.y + (xy.x == 8) * 8; } + return UINT16_MAX; + } + + Point ID2XY(uint16_t keyID) { + uint8_t keyClass = keyID >> 12; + switch (keyClass) + { + case 1: // Main Grid + { + int16_t x = (keyID & 0b0000111111000000) >> 6; + int16_t y = keyID & (0b0000000000111111); + if (x < X_SIZE && y < Y_SIZE) + return Point(x, y); + break; + } + case 2: // TouchBar + { + uint16_t index = keyID & (0b0000111111111111); + if (index < touchbar_size) + { + if (index / 8) // Right + { return Point(X_SIZE, index % 8); } + else // Left + { return Point(-1, index % 8); } + } + break; + } + } + return Point(INT16_MIN, INT16_MIN); + } +} \ No newline at end of file diff --git a/Devices/MatrixBlock5/Drivers/LED.cpp b/Devices/MatrixBlock5/Drivers/LED.cpp new file mode 100644 index 00000000..ed64de41 --- /dev/null +++ b/Devices/MatrixBlock5/Drivers/LED.cpp @@ -0,0 +1,73 @@ +#include "Device.h" +#include "MatrixOSConfig.h" +#include "WS2812/WS2812.h" + +// TIM8 handle for WS2812 LED driver +extern TIM_HandleTypeDef htim8; + +// Forward declarations +extern void MX_DMA_Init(void); +extern void MX_TIM8_Init(void); + +namespace Device +{ + namespace LED + { + void Init() { + MX_DMA_Init(); + MX_TIM8_Init(); + WS2812::Init(&htim8, TIM_CHANNEL_2, Device::LED::count); + } + + void Start() { + // LED startup tasks - none needed for MatrixBlock5 + } + + void Update(Color* frameBuffer, vector& brightness) // Render LED + { + WS2812::Show(frameBuffer, brightness); + } + + uint16_t XY2Index(Point xy) { + if (xy.x >= 0 && xy.x < 8 && xy.y >= 0 && xy.y < 8) // Main grid + { return xy.x + xy.y * 8; } + return UINT16_MAX; + } + + Point Index2XY(uint16_t index) + { + if (index < 64) + { + return Point(index % 8, index / 8); + } + return Point::Invalid(); + } + + // Matrix use the following ID Struct + // CCCC IIIIIIIIIIII + // C as class (4 bits), I as index (12 bits). I could be split by the class definition, for example, class 1 + // (grid), it's split to XXXXXXX YYYYYYY. Class List: Class 0 - Raw Index - IIIIIIIIIIII Class 1 - Grid - XXXXXX + // YYYYYY Class 2 - TouchBar - IIIIIIIIIIII Class 3 - Underglow - IIIIIIIIIIII + + uint16_t ID2Index(uint16_t ledID) { + uint8_t ledClass = ledID >> 12; + switch (ledClass) + { + case 0: + if (ledID < LED::count) + return ledID; + break; + case 1: // Main Grid + { + uint16_t index = ledID & (0b0000111111111111); + if (index < 64) + return index; + break; + } + case 3: // Underglow + break; // TODO: Underglow + } + return UINT16_MAX; + } + } +} \ No newline at end of file diff --git a/Devices/MatrixBlock5/Drivers/NVS.cpp b/Devices/MatrixBlock5/Drivers/NVS.cpp new file mode 100644 index 00000000..32587934 --- /dev/null +++ b/Devices/MatrixBlock5/Drivers/NVS.cpp @@ -0,0 +1,32 @@ +#include "Device.h" + +namespace Device::NVS +{ + void Init() { + // Stub: NVS not implemented for STM32F103 + } + + void Clear() { + // Stub: NVS not implemented for STM32F103 + } + + size_t Size(uint32_t hash) { + // Stub: NVS not implemented for STM32F103 + return 0; + } + + vector Read(uint32_t hash) { + // Stub: NVS not implemented for STM32F103 + return vector(); + } + + bool Write(uint32_t hash, void* pointer, uint16_t length) { + // Stub: NVS not implemented for STM32F103 + return false; + } + + bool Delete(uint32_t hash) { + // Stub: NVS not implemented for STM32F103 + return false; + } +} diff --git a/Devices/MatrixBlock5/Drivers/USB.cpp b/Devices/MatrixBlock5/Drivers/USB.cpp new file mode 100644 index 00000000..f812d8e5 --- /dev/null +++ b/Devices/MatrixBlock5/Drivers/USB.cpp @@ -0,0 +1,43 @@ +#include "Family.h" +#include "tusb.h" + +namespace Device::USB +{ + void Init() + { + NVIC_SetPriority(USB_HP_CAN1_TX_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY); + NVIC_SetPriority(USB_LP_CAN1_RX0_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY); + NVIC_SetPriority(USBWakeUp_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY); + + // Enable GPIO clocks + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + + // Configure USB DM and DP pins (PA11, PA12) + GPIO_InitTypeDef GPIO_InitStruct; + GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + // USB Clock enable + __HAL_RCC_USB_CLK_ENABLE(); + } +} + +extern "C" { +void USB_HP_IRQHandler(void) { + dcd_int_handler(0); +} + +void USB_LP_IRQHandler(void) { + dcd_int_handler(0); +} + +void USBWakeUp_IRQHandler(void) { + dcd_int_handler(0); +} +} \ No newline at end of file diff --git a/Devices/MatrixBlock5/Family.cpp b/Devices/MatrixBlock5/Family.cpp new file mode 100644 index 00000000..b22c385c --- /dev/null +++ b/Devices/MatrixBlock5/Family.cpp @@ -0,0 +1,288 @@ +#include "Device.h" +#include "MatrixOS.h" +#include "UI/UI.h" +#include "MatrixOSConfig.h" +#include "Variants/MatrixFounderEdition/Config.h" + +#include "timers.h" + +// Forward declare TinyUSB interrupt handler +extern "C" void dcd_int_handler(uint8_t rhport); + + + +namespace Device +{ + void DeviceInit() { + HAL_Init(); + SystemClock_Config(); + + // Load device variant info - MUST be called before subsystem Init() + LoadDeviceInfo(); + + USB::Init(); + LED::Init(); + KeyPad::Init(); + // NVS::Init(); //Not working TODO FIX + } + + void DeviceStart() { + KeyPad::Start(); + LED::Start(); + + // Keypad scanning is now handled by FreeRTOS timer, no need to call Scan() directly + //Use keyInfo->Force() instead KeyInfo->Active() because it might still be debouncing + if (KeyPad::GetKey(KeyPad::XY2ID(Point(0, 0)))->Force() && KeyPad::GetKey(KeyPad::XY2ID(Point(1, 1)))->Force()) + { MatrixOS::SYS::ExecuteAPP("203 Systems", "Matrix Factory Menu"); } + else if (KeyPad::GetKey(KeyPad::XY2ID(Point(6, 6)))->Force() && + KeyPad::GetKey(KeyPad::XY2ID(Point(7, 7)))->Force()) + { + KeyPad::Clear(); + MatrixOS::UserVar::brightness.Set(LED::brightness_level[0]); + } + else if (KeyPad::GetKey(KeyPad::XY2ID(Point(0, 5)))->Force() && + KeyPad::GetKey(KeyPad::XY2ID(Point(1, 6)))->Force() && + KeyPad::GetKey(KeyPad::XY2ID(Point(0, 7)))->Force()) + { + MatrixOS::LED::SetColor(Point(2, 2), Color(0xFF00FF)); + MatrixOS::LED::SetColor(Point(5, 2), Color(0xFF00FF)); + MatrixOS::LED::SetColor(Point(2, 5), Color(0xFF00FF)); + MatrixOS::LED::SetColor(Point(5, 5), Color(0xFF00FF)); + MatrixOS::LED::Update(); + MatrixOS::SYS::DelayMs(1500); + NVS::Clear(); + MatrixOS::SYS::Reboot(); + } + } + + void LoadDeviceInfo() { +#ifndef FACTORY_CONFIG + // For MatrixBlock5, we'll use default device info since there's no EFUSE + DeviceInfo defaultDeviceInfo{{'M', 'B', '5', 'F'}, {'F', 'O', 'U', 'N'}, 24, 1}; + memcpy(&deviceInfo, &defaultDeviceInfo, sizeof(DeviceInfo)); +#endif + LoadVariantInfo(); + } + + void LoadVariantInfo() { + // For MatrixBlock5, we'll load the Founder Edition variant + // This will set up the GPIO configurations for the specific hardware + LoadFounderEdition(); + } + + void DeviceSettings() + { + UI deviceSettings("Device Settings", Color(0x00FFAA)); + + UIToggle touchbarToggle; + touchbarToggle.SetName("Touchbar"); + touchbarToggle.SetColor(Color(0x7957FB)); + touchbarToggle.SetValuePointer(&touchbar_enable); + touchbarToggle.OnPress([&]() -> void { touchbar_enable.Save(); }); + deviceSettings.AddUIComponent(touchbarToggle, Point(0, 0)); + + deviceSettings.Start(); + } + + void Bootloader() { + // Write bootloader magic to RTC backup register + RTC_HandleTypeDef RtcHandle; + RtcHandle.Instance = RTC; + HAL_PWR_EnableBkUpAccess(); + HAL_RTCEx_BKUPWrite(&RtcHandle, 10, 0x424C); + HAL_PWR_DisableBkUpAccess(); + + Reboot(); + } + + void Reboot() { + NVIC_SystemReset(); + } + + void Delay(uint32_t interval) { + vTaskDelay(pdMS_TO_TICKS(interval)); + } + + uint32_t Millis() { + return ((((uint64_t)xTaskGetTickCount()) * 1000) / configTICK_RATE_HZ); + } + + void Log(string &format, va_list &valst) { + // For STM32, we can use printf or custom logging + // vprintf(format.c_str(), valst); + } + + string GetSerial() { + // For MatrixBlock5, we could use MCU unique ID if available + return "MXB5-" + std::to_string(HAL_GetUIDw0() ^ HAL_GetUIDw1() ^ HAL_GetUIDw2()); + } + + void ErrorHandler() {} + + uint64_t Micros() { + return HAL_GetTick() * 1000; // Approximate micros for STM32 + } + + /** + * @brief System Clock Configuration + * The system Clock is configured as follow : + * System Clock source = PLL (HSE) + * SYSCLK(Hz) = 72000000 + * HCLK(Hz) = 72000000 + * AHB Prescaler = 1 + * APB1 Prescaler = 2 + * APB2 Prescaler = 1 + * HSE Frequency(Hz) = 8000000 + * HSE PREDIV1 = 1 + * PLLMUL = 9 + * Flash Latency(WS) = 2 + * @param None + * @retval None + */ + void SystemClock_Config(void) { + RCC_ClkInitTypeDef clkinitstruct = {0}; + RCC_OscInitTypeDef oscinitstruct = {0}; + RCC_PeriphCLKInitTypeDef rccperiphclkinit = {0}; + + /* Enable HSE Oscillator and activate PLL with HSE as source */ + oscinitstruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; + oscinitstruct.HSEState = RCC_HSE_ON; + oscinitstruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; + oscinitstruct.PLL.PLLMUL = RCC_PLL_MUL9; + oscinitstruct.PLL.PLLState = RCC_PLL_ON; + oscinitstruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + HAL_RCC_OscConfig(&oscinitstruct); + + /* USB clock selection */ + rccperiphclkinit.PeriphClockSelection = RCC_PERIPHCLK_USB; + rccperiphclkinit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5; + HAL_RCCEx_PeriphCLKConfig(&rccperiphclkinit); + + /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers */ + clkinitstruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); + clkinitstruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + clkinitstruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + clkinitstruct.APB1CLKDivider = RCC_HCLK_DIV2; + clkinitstruct.APB2CLKDivider = RCC_HCLK_DIV1; + HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2); + } +} + +namespace MatrixOS::SYS +{ + void ErrorHandler(string error); +} + +extern "C" { +void _init(void) { + ; +} + +void NMI_Handler(void) { + while (true) + {} +} + +void HardFault_Handler(void) { + //MatrixOS::SYS::ErrorHandler("Hard Fault"); + while (true) + {} +} + +void MemManage_Handler(void) { + while (true) + {} +} + +void BusFault_Handler(void) { + while (true) + {} +} + +void UsageFault_Handler(void) { + while (true) + {} +} + +// void SVC_Handler (void) +// { +// while(true){ + +// } +// } + +void DebugMon_Handler(void) { + while (true) + {} +} + +// void PendSV_Handler (void) +// { +// while(true){ + +// } +// } + +void vApplicationMallocFailedHook(void) { + taskDISABLE_INTERRUPTS(); +} + +void vApplicationStackOverflowHook(xTaskHandle pxTask, char* pcTaskName) { + (void)pxTask; + (void)pcTaskName; + + taskDISABLE_INTERRUPTS(); +} + +/* configSUPPORT_STATIC_ALLOCATION is set to 1, so the application must provide an + * implementation of vApplicationGetIdleTaskMemory() to provide the memory that is + * used by the Idle task. */ +void vApplicationGetIdleTaskMemory(StaticTask_t** ppxIdleTaskTCBBuffer, StackType_t** ppxIdleTaskStackBuffer, + uint32_t* pulIdleTaskStackSize) { + /* If the buffers to be provided to the Idle task are declared inside this + * function then they must be declared static - otherwise they will be allocated on + * the stack and so not exists after this function exits. */ + static StaticTask_t xIdleTaskTCB; + static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE]; + + /* Pass out a pointer to the StaticTask_t structure in which the Idle task's + state will be stored. */ + *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + + /* Pass out the array that will be used as the Idle task's stack. */ + *ppxIdleTaskStackBuffer = uxIdleTaskStack; + + /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; +} + +/* configSUPPORT_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the + * application must provide an implementation of vApplicationGetTimerTaskMemory() + * to provide the memory that is used by the Timer service task. */ +void vApplicationGetTimerTaskMemory(StaticTask_t** ppxTimerTaskTCBBuffer, StackType_t** ppxTimerTaskStackBuffer, + uint32_t* pulTimerTaskStackSize) { + /* If the buffers to be provided to the Timer task are declared inside this + * function then they must be declared static - otherwise they will be allocated on + * the stack and so not exists after this function exits. */ + static StaticTask_t xTimerTaskTCB; + static StackType_t uxTimerTaskStack[configTIMER_TASK_STACK_DEPTH]; + + /* Pass out a pointer to the StaticTask_t structure in which the Timer + task's state will be stored. */ + *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; + + /* Pass out the array that will be used as the Timer task's stack. */ + *ppxTimerTaskStackBuffer = uxTimerTaskStack; + + /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configTIMER_TASK_STACK_DEPTH is specified in words, not bytes. */ + *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; +} +} + +extern "C" { +void* __dso_handle = 0; +} diff --git a/Devices/MatrixBlock5/Family.h b/Devices/MatrixBlock5/Family.h new file mode 100644 index 00000000..9ff0b33f --- /dev/null +++ b/Devices/MatrixBlock5/Family.h @@ -0,0 +1,110 @@ +// Declare Family specific function +#pragma once + +#include "Device.h" +#include "Framework.h" + +#include "stm32f1xx_hal.h" +#include "WS2812/WS2812.h" + +#undef USB // CMSIS defined the USB, undef so we can use USB as MatrixOS namespace + +// Family-specific defines +#define GRID_TYPE_8x8 +#define FAMILY_MATRIXBLOCK5 +#define MULTIPRESS 10 // Key Press will be process at once + +#define DEVICE_SAVED_VAR_SCOPE "Device" + +struct DeviceInfo { + char Model[4]; + char Revision[4]; + uint8_t ProductionYear; + uint8_t ProductionMonth; +}; + +namespace Device +{ + inline DeviceInfo deviceInfo; + + // Device Variable + inline CreateSavedVar(DEVICE_SAVED_VAR_SCOPE, touchbar_enable, bool, true); + + void LoadDeviceInfo(); + void LoadVariantInfo(); + + void SystemClock_Config(); + + namespace USB + { + void Init(); + } + + namespace LED + { + inline GPIO_TypeDef* led_port = nullptr; + inline uint16_t led_pin = 0; + + void Init(); + void Start(); + } + + namespace KeyPad + { + void Init(); + void InitFN(); + void InitKeyPad(); + void InitTouchBar(); + + void Start(); + void StartKeyPad(); + void StartTouchBar(); + + // If return true, meaning the scan in interrupted + void Scan(); + bool ScanKeyPad(); + bool ScanFN(); + bool ScanTouchBar(); + + inline GPIO_TypeDef* fn_port = nullptr; + inline uint16_t fn_pin = 0; + inline bool fn_active_low = true; + inline bool velocity_sensitivity = false; + + inline KeyConfig keypad_config = { + .apply_curve = false, + .low_threshold = 0, + .high_threshold = 65535, + .activation_offset = 0, + .debounce = 3, + }; + + inline GPIO_TypeDef* keypad_write_ports[X_SIZE]; + inline uint16_t keypad_write_pins[X_SIZE]; + inline GPIO_TypeDef* keypad_read_ports[Y_SIZE]; + inline uint16_t keypad_read_pins[Y_SIZE]; + + inline uint16_t keypad_scanrate = 240; + + inline GPIO_TypeDef* touchData_Port; + inline uint16_t touchData_Pin; + inline GPIO_TypeDef* touchClock_Port; + inline uint16_t touchClock_Pin; + + inline const uint8_t touchbar_size = 16; + inline const uint16_t touchbar_scanrate = 120; + inline uint8_t touchbar_map[touchbar_size]; // Touch number as index and touch location as value (Left touch down + // and then right touch down) + + inline KeyInfo fnState; + inline KeyInfo keypadState[X_SIZE][Y_SIZE]; + inline KeyInfo touchbarState[touchbar_size]; + + bool NotifyOS(uint16_t keyID, KeyInfo* keyInfo); // Passthrough MatrixOS::KeyPad::NewEvent() result + } + + namespace NVS + { + void Init(); + } +} \ No newline at end of file diff --git a/Devices/MatrixBlock5/FreeRTOSConfig.h b/Devices/MatrixBlock5/FreeRTOSConfig.h new file mode 100644 index 00000000..21b9f19f --- /dev/null +++ b/Devices/MatrixBlock5/FreeRTOSConfig.h @@ -0,0 +1,156 @@ +/* + * FreeRTOS Kernel V10.0.0 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. If you wish to use our Amazon + * FreeRTOS name, please do so in a fair use way that does not cause confusion. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +// STM32 device definition - must be defined before including HAL headers +#ifndef STM32F103xE +#define STM32F103xE +#endif + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html. + *----------------------------------------------------------*/ + +// skip if included from IAR assembler +#ifndef __IASMARM__ + #include "stm32f1xx.h" +#endif + +/* Cortex M3 port configuration. */ +#define configENABLE_MPU 0 +#define configENABLE_FPU 0 +#define configENABLE_TRUSTZONE 0 +#define configMINIMAL_SECURE_STACK_SIZE (1024) + +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configCPU_CLOCK_HZ SystemCoreClock +#define configTICK_RATE_HZ ( 1000 ) +#define configMAX_PRIORITIES ( 5 ) +#define configMINIMAL_STACK_SIZE ( 128 ) +#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*24*1024 ) +#define configMAX_TASK_NAME_LEN 16 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configQUEUE_REGISTRY_SIZE 4 +#define configUSE_QUEUE_SETS 0 +#define configUSE_TIME_SLICING 0 +#define configUSE_NEWLIB_REENTRANT 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0 + +#define configSUPPORT_STATIC_ALLOCATION 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 + +/* Hook function related definitions. */ +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 0 // cause nested extern warning +#define configCHECK_FOR_STACK_OVERFLOW 2 +#define configCHECK_HANDLER_INSTALLATION 0 + +/* Run time and task stats gathering related definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 +#define configRECORD_STACK_HIGH_ADDRESS 1 +#define configUSE_TRACE_FACILITY 1 // legacy trace +#define configUSE_STATS_FORMATTING_FUNCTIONS 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES 2 + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-2) +#define configTIMER_QUEUE_LENGTH 32 +#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE + +/* Optional functions - most linkers will remove unused functions anyway. */ +#define INCLUDE_vTaskPrioritySet 0 +#define INCLUDE_uxTaskPriorityGet 0 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskSuspend 1 // required for queue, semaphore, mutex to be blocked indefinitely with portMAX_DELAY +#define INCLUDE_xResumeFromISR 0 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 0 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0 +#define INCLUDE_pcTaskGetTaskName 0 +#define INCLUDE_eTaskGetState 0 +#define INCLUDE_xEventGroupSetBitFromISR 0 +#define INCLUDE_xTimerPendFunctionCall 0 + +/* FreeRTOS hooks to NVIC vectors */ +#define xPortPendSVHandler PendSV_Handler +#define xPortSysTickHandler SysTick_Handler +#define vPortSVCHandler SVC_Handler + +//--------------------------------------------------------------------+ +// Interrupt nesting behavior configuration. +//--------------------------------------------------------------------+ + +// For Cortex-M specific: __NVIC_PRIO_BITS is defined in mcu header +#define configPRIO_BITS 4 + +/* The lowest interrupt priority that can be used in a call to a "set priority" function. */ +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1< partitions = { + {"Grid", 1.0, 0, 64}, + }; + } +} \ No newline at end of file diff --git a/Devices/MatrixBlock5/STM32F103RETX_FLASH.ld b/Devices/MatrixBlock5/STM32F103RETX_FLASH.ld new file mode 100644 index 00000000..9eb998fd --- /dev/null +++ b/Devices/MatrixBlock5/STM32F103RETX_FLASH.ld @@ -0,0 +1,177 @@ +/** + ****************************************************************************** + * @file LinkerScript.ld + * @author Auto-generated by STM32CubeIDE + * @brief Linker script for STM32F103RETx Device from STM32F1 series + * 512Kbytes FLASH + * 64Kbytes RAM + * + * Set heap size, stack size and stack location according + * to application requirements. + * + * Set memory bank area and size if external memory is used + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */ + +_Min_Heap_Size = 0x200; /* required amount of heap */ +_Min_Stack_Size = 0x400; /* required amount of stack */ + +/* Memories definition */ +MEMORY +{ +/* BOOTLOADER (r) : ORIGIN = 0x08000000, LENGTH = 8K */ +FLASH (rx) : ORIGIN = 0x08002000, LENGTH = 504K + +RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K +} + +/* 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 : { + . = ALIGN(4); + *(.ARM.extab* .gnu.linkonce.armextab.*) + . = ALIGN(4); + } >FLASH + + .ARM : { + . = ALIGN(4); + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + . = ALIGN(4); + } >FLASH + + .preinit_array : + { + . = ALIGN(4); + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + . = ALIGN(4); + } >FLASH + + .init_array : + { + . = ALIGN(4); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + . = ALIGN(4); + } >FLASH + + .fini_array : + { + . = 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 sections into "RAM" Ram type memory */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + + } >RAM AT> FLASH + + /* Uninitialized data section into "RAM" Ram type memory */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss section */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM + + /* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */ + ._user_heap_stack : + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(8); + } >RAM + + /* Remove information from the compiler libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/Devices/MatrixBlock5/Variants/MatrixFounderEdition/Config.h b/Devices/MatrixBlock5/Variants/MatrixFounderEdition/Config.h new file mode 100644 index 00000000..d425f87f --- /dev/null +++ b/Devices/MatrixBlock5/Variants/MatrixFounderEdition/Config.h @@ -0,0 +1,78 @@ +#pragma once + +#include "../../MatrixOSConfig.h" +#include "stm32f1xx_hal.h" + +#include +#include + +namespace MatrixBlock5 { +namespace FounderEdition { + +struct GpioPin { + GPIO_TypeDef* port; + uint16_t pin; +}; + +inline constexpr const char* kDeviceName = "MatrixBlock5"; +inline constexpr const char* kDeviceModel = "MB5F"; +inline constexpr const char* kManufacturerName = "203 Systems"; +inline constexpr const char* kProductName = "MatrixBlock5"; +inline constexpr uint16_t kUsbVid = 0x0203; +inline constexpr uint16_t kUsbPid = 0x1041; + +inline constexpr uint16_t kKeypadScanRateHz = 60; + +inline constexpr size_t kGridColumns = X_SIZE; +inline constexpr size_t kGridRows = Y_SIZE; +inline constexpr size_t kBrightnessSteps = 8; +inline constexpr size_t kTouchbarEntries = 16; + +inline const uint8_t kBrightnessLevels[kBrightnessSteps] = {8, 12, 24, 40, 64, 90, 128, 168}; + +inline const GpioPin kLedPin{GPIOC, GPIO_PIN_7}; +inline const GpioPin kFnPin{GPIOA, GPIO_PIN_8}; + +inline const GpioPin kKeypadColumns[kGridColumns] = { + {GPIOB, GPIO_PIN_12}, + {GPIOB, GPIO_PIN_13}, + {GPIOB, GPIO_PIN_14}, + {GPIOB, GPIO_PIN_15}, + {GPIOC, GPIO_PIN_6}, + {GPIOC, GPIO_PIN_7}, + {GPIOC, GPIO_PIN_8}, + {GPIOC, GPIO_PIN_9}, +}; + +inline const GpioPin kKeypadRows[kGridRows] = { + {GPIOB, GPIO_PIN_0}, + {GPIOB, GPIO_PIN_1}, + {GPIOA, GPIO_PIN_11}, + {GPIOA, GPIO_PIN_12}, + {GPIOC, GPIO_PIN_4}, + {GPIOA, GPIO_PIN_15}, + {GPIOC, GPIO_PIN_5}, + {GPIOC, GPIO_PIN_3}, +}; + +inline const GpioPin kTouchDataPin{GPIOA, GPIO_PIN_0}; +inline const GpioPin kTouchClockPin{GPIOA, GPIO_PIN_1}; + +inline const uint8_t kTouchbarMap[kTouchbarEntries] = {4, 5, 6, 7, 15, 14, 13, 12, 11, 10, 9, 8, 0, 1, 2, 3}; + +} // namespace FounderEdition +} // namespace MatrixBlock5 + +extern TIM_HandleTypeDef htim8; +extern DMA_HandleTypeDef hdma_tim8_ch2; + +namespace Device { +void LoadFounderEdition(); +} + +extern "C" { +void MX_DMA_Init(void); +void MX_TIM8_Init(void); +void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim); +void DMA2_Channel4_5_IRQHandler(void); +} diff --git a/Devices/MatrixBlock5/Variants/MatrixFounderEdition/FounderEdition.cpp b/Devices/MatrixBlock5/Variants/MatrixFounderEdition/FounderEdition.cpp new file mode 100644 index 00000000..ffa7aa7a --- /dev/null +++ b/Devices/MatrixBlock5/Variants/MatrixFounderEdition/FounderEdition.cpp @@ -0,0 +1,146 @@ +// Matrix Founder Edition Variant Configuration +#include "Device.h" +#include "WS2812/WS2812.h" +#include "Config.h" + +TIM_HandleTypeDef htim8; +DMA_HandleTypeDef hdma_tim8_ch2; + +extern "C" void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim); + +void MX_DMA_Init(void) { + /* DMA controller clock enable */ + __HAL_RCC_DMA2_CLK_ENABLE(); + + /* DMA interrupt init */ + /* DMA2_Channel4_5_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA2_Channel4_5_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(DMA2_Channel4_5_IRQn); +} + +void MX_TIM8_Init(void) { + TIM_MasterConfigTypeDef sMasterConfig = {0}; + TIM_OC_InitTypeDef sConfigOC = {0}; + TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; + + htim8.Instance = TIM8; + htim8.Init.Prescaler = 0; + htim8.Init.CounterMode = TIM_COUNTERMODE_UP; + htim8.Init.Period = WS2812::GetTimerPeriod(); + htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim8.Init.RepetitionCounter = 0; + htim8.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + if (HAL_TIM_PWM_Init(&htim8) != HAL_OK) + { Device::ErrorHandler(); } + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if (HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig) != HAL_OK) + { Device::ErrorHandler(); } + sConfigOC.OCMode = TIM_OCMODE_PWM1; + sConfigOC.Pulse = 0; + sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; + sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; + sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; + sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; + sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; + if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) + { Device::ErrorHandler(); } + 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.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; + if (HAL_TIMEx_ConfigBreakDeadTime(&htim8, &sBreakDeadTimeConfig) != HAL_OK) + { Device::ErrorHandler(); } + + HAL_TIM_MspPostInit(&htim8); +} + +void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim) { + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if (htim->Instance == TIM8) + { + __HAL_RCC_GPIOC_CLK_ENABLE(); + /**TIM8 GPIO Configuration + PC7 ------> TIM8_CH2 + */ + GPIO_InitStruct.Pin = GPIO_PIN_7; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + } +} + +extern "C" { +void DMA2_Channel4_5_IRQHandler(void) { + HAL_DMA_IRQHandler(&hdma_tim8_ch2); +} +} + +void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* htim_pwm) { + if (htim_pwm->Instance == TIM8) + { + /* Peripheral clock enable */ + __HAL_RCC_TIM8_CLK_ENABLE(); + + /* TIM8 DMA Init */ + hdma_tim8_ch2.Instance = DMA2_Channel5; + hdma_tim8_ch2.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_tim8_ch2.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_tim8_ch2.Init.MemInc = DMA_MINC_ENABLE; + hdma_tim8_ch2.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; // WORD for TIM CCR register + hdma_tim8_ch2.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; // BYTE for pwmBuffer + hdma_tim8_ch2.Init.Mode = DMA_NORMAL; + hdma_tim8_ch2.Init.Priority = DMA_PRIORITY_LOW; + if (HAL_DMA_Init(&hdma_tim8_ch2) != HAL_OK) + { Device::ErrorHandler(); } + + __HAL_LINKDMA(htim_pwm, hdma[TIM_DMA_ID_CC2], hdma_tim8_ch2); + } +} + +void LoadFounderEdition() { + using namespace MatrixBlock5::FounderEdition; + + static_assert(kGridColumns == X_SIZE, "FounderEdition grid width mismatch"); + static_assert(kGridRows == Y_SIZE, "FounderEdition grid height mismatch"); + static_assert(kTouchbarEntries == Device::KeyPad::touchbar_size, "FounderEdition touchbar size mismatch"); + + Device::LED::led_port = kLedPin.port; + Device::LED::led_pin = kLedPin.pin; + for (size_t i = 0; i < kBrightnessSteps; ++i) + { Device::LED::brightness_level[i] = kBrightnessLevels[i]; } + + Device::KeyPad::keypad_scanrate = kKeypadScanRateHz; + Device::KeyPad::fn_port = kFnPin.port; + Device::KeyPad::fn_pin = kFnPin.pin; + + for (size_t i = 0; i < kGridColumns; ++i) + { + Device::KeyPad::keypad_write_ports[i] = kKeypadColumns[i].port; + Device::KeyPad::keypad_write_pins[i] = kKeypadColumns[i].pin; + } + + for (size_t i = 0; i < kGridRows; ++i) + { + Device::KeyPad::keypad_read_ports[i] = kKeypadRows[i].port; + Device::KeyPad::keypad_read_pins[i] = kKeypadRows[i].pin; + } + + Device::KeyPad::touchData_Port = kTouchDataPin.port; + Device::KeyPad::touchData_Pin = kTouchDataPin.pin; + Device::KeyPad::touchClock_Port = kTouchClockPin.port; + Device::KeyPad::touchClock_Pin = kTouchClockPin.pin; + + for (size_t i = 0; i < kTouchbarEntries; ++i) + { Device::KeyPad::touchbar_map[i] = kTouchbarMap[i]; } + + Device::name = kDeviceName; + Device::model = kDeviceModel; + Device::manufacturer_name = kManufacturerName; + Device::product_name = kProductName; + Device::usb_vid = kUsbVid; + Device::usb_pid = kUsbPid; +} diff --git a/Devices/MatrixBlock5/Variants/MatrixFounderEdition/FounderEdition.cpp.bak b/Devices/MatrixBlock5/Variants/MatrixFounderEdition/FounderEdition.cpp.bak new file mode 100644 index 00000000..df785cfe --- /dev/null +++ b/Devices/MatrixBlock5/Variants/MatrixFounderEdition/FounderEdition.cpp.bak @@ -0,0 +1,307 @@ +// Define Device Specific Function +#include "Device.h" + +void LoadFounderEdition(); + +namespace Device +{ + namespace + { + void MX_DMA_Init(void) { + /* DMA controller clock enable */ + __HAL_RCC_DMA2_CLK_ENABLE(); + + /* DMA interrupt init */ + /* DMA2_Channel4_5_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA2_Channel4_5_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(DMA2_Channel4_5_IRQn); + } + + void MX_TIM8_Init(void) { + TIM_MasterConfigTypeDef sMasterConfig = {0}; + TIM_OC_InitTypeDef sConfigOC = {0}; + TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; + + htim8.Instance = TIM8; + htim8.Init.Prescaler = 0; + htim8.Init.CounterMode = TIM_COUNTERMODE_UP; + htim8.Init.Period = WS2812::GetTimerPeriod(); + htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim8.Init.RepetitionCounter = 0; + htim8.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + if (HAL_TIM_PWM_Init(&htim8) != HAL_OK) + { Device::ErrorHandler(); } + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if (HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig) != HAL_OK) + { Device::ErrorHandler(); } + sConfigOC.OCMode = TIM_OCMODE_PWM1; + sConfigOC.Pulse = 0; + sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; + sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH; + sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; + sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; + sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; + if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) + { Device::ErrorHandler(); } + 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.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; + if (HAL_TIMEx_ConfigBreakDeadTime(&htim8, &sBreakDeadTimeConfig) != HAL_OK) + { Device::ErrorHandler(); } + + HAL_TIM_MspPostInit(&htim8); + } + } + + void USB_Init() { + GPIO_InitTypeDef GPIO_InitStruct = {0}; + + /* Configure USB FS GPIOs */ + __HAL_RCC_GPIOA_CLK_ENABLE(); + + /* Configure USB D+ D- Pins */ + GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + // USB Clock enable + __HAL_RCC_USB_CLK_ENABLE(); + } + + void LED_Init() { + MX_DMA_Init(); + MX_TIM8_Init(); + WS2812::Init(&htim8, TIM_CHANNEL_2, led_count); + } + + void KeyPad_Init() { + GPIO_InitTypeDef GPIO_InitStruct = {0}; + + /* GPIO Ports Clock Enable */ + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + + /*Configure GPIO pin Output Level */ + HAL_GPIO_WritePin(GPIOC, Key8_Pin | Key7_Pin | Key6_Pin | Key5_Pin, GPIO_PIN_RESET); + + /*Configure GPIO pin Output Level */ + HAL_GPIO_WritePin(GPIOB, Key4_Pin | Key3_Pin | Key2_Pin | Key1_Pin, GPIO_PIN_RESET); + + /*Configure GPIO pins : Key8_Pin Key7_Pin Key6_Pin Key5_Pin */ + GPIO_InitStruct.Pin = Key8_Pin | Key7_Pin | Key6_Pin | Key5_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /*Configure GPIO pins : KeyRead5_Pin KeyRead8_Pin KeyRead7_Pin */ + GPIO_InitStruct.Pin = KeyRead5_Pin | KeyRead8_Pin | KeyRead7_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /*Configure GPIO pins : FN_Pin KeyRead4_Pin KeyRead3_Pin KeyRead6_Pin */ + GPIO_InitStruct.Pin = FN_Pin | KeyRead4_Pin | KeyRead3_Pin | KeyRead6_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + /*Configure GPIO pins : KeyRead2_Pin KeyRead1_Pin */ + GPIO_InitStruct.Pin = KeyRead2_Pin | KeyRead1_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + /*Configure GPIO pins : Key4_Pin Key3_Pin Key2_Pin Key1_Pin */ + GPIO_InitStruct.Pin = Key4_Pin | Key3_Pin | Key2_Pin | Key1_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + } + + void TouchBar_Init() { + GPIO_InitTypeDef GPIO_InitStruct = {0}; + + /* Configure TouchBar GPIOs */ + __HAL_RCC_GPIOA_CLK_ENABLE(); + + /*Configure GPIO pin Output Level */ + HAL_GPIO_WritePin(TouchClock_GPIO_Port, TouchClock_Pin, GPIO_PIN_RESET); + + /*Configure GPIO pins : TouchClock_Pin */ + GPIO_InitStruct.Pin = TouchClock_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(TouchClock_GPIO_Port, &GPIO_InitStruct); + + /*Configure GPIO pin : TouchData_Pin */ + GPIO_InitStruct.Pin = TouchData_Pin; + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + HAL_GPIO_Init(TouchData_GPIO_Port, &GPIO_InitStruct); + } + + void EEPROM_Init() {} +} + +TIM_HandleTypeDef htim8; +DMA_HandleTypeDef hdma_tim8_ch2; + +extern "C" { +void DMA2_Channel4_5_IRQHandler(void) { + HAL_DMA_IRQHandler(&hdma_tim8_ch2); +} +/** + * Initializes the Global MSP. + */ +void HAL_MspInit(void) { + /* USER CODE BEGIN MspInit 0 */ + + /* USER CODE END MspInit 0 */ + + __HAL_RCC_AFIO_CLK_ENABLE(); + __HAL_RCC_PWR_CLK_ENABLE(); + + /* System interrupt init*/ + + /** DISABLE: JTAG-DP Disabled and SW-DP Disabled + */ + // __HAL_AFIO_REMAP_SWJ_DISABLE(); + + /* USER CODE BEGIN MspInit 1 */ + + /* USER CODE END MspInit 1 */ +} + +// /** +// * @brief TIM_PWM MSP Initialization +// * This function configures the hardware resources used in this example +// * @param htim_pwm: TIM_PWM handle pointer +// * @retval None +// */ +void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* htim_pwm) { + if (htim_pwm->Instance == TIM8) + { + /* USER CODE BEGIN TIM8_MspInit 0 */ + + /* USER CODE END TIM8_MspInit 0 */ + /* Peripheral clock enable */ + __HAL_RCC_TIM8_CLK_ENABLE(); + + /* TIM8 DMA Init */ + /* TIM8_CH2 Init */ + hdma_tim8_ch2.Instance = DMA2_Channel5; + hdma_tim8_ch2.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_tim8_ch2.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_tim8_ch2.Init.MemInc = DMA_MINC_ENABLE; + hdma_tim8_ch2.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + hdma_tim8_ch2.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_tim8_ch2.Init.Mode = DMA_NORMAL; + hdma_tim8_ch2.Init.Priority = DMA_PRIORITY_HIGH; + if (HAL_DMA_Init(&hdma_tim8_ch2) != HAL_OK) + { Device::ErrorHandler(); } + + __HAL_LINKDMA(htim_pwm, hdma[TIM_DMA_ID_CC2], hdma_tim8_ch2); + + /* USER CODE BEGIN TIM8_MspInit 1 */ + + /* USER CODE END TIM8_MspInit 1 */ + } +} + +void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim) { + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if (htim->Instance == TIM8) + { + /* USER CODE BEGIN TIM8_MspPostInit 0 */ + + /* USER CODE END TIM8_MspPostInit 0 */ + + __HAL_RCC_GPIOC_CLK_ENABLE(); + /**TIM8 GPIO Configuration + PC7 ------> TIM8_CH2 + */ + GPIO_InitStruct.Pin = GPIO_PIN_7; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /* USER CODE BEGIN TIM8_MspPostInit 1 */ + + /* USER CODE END TIM8_MspPostInit 1 */ + } +} +// /** +// * @brief TIM_PWM MSP De-Initialization +// * This function freeze the hardware resources used in this example +// * @param htim_pwm: TIM_PWM handle pointer +// * @retval None +// */ +void HAL_TIM_PWM_MspDeInit(TIM_HandleTypeDef* htim_pwm) { + if (htim_pwm->Instance == TIM8) + { + /* USER CODE BEGIN TIM8_MspDeInit 0 */ + + /* USER CODE END TIM8_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_TIM8_CLK_DISABLE(); + + /* TIM8 DMA DeInit */ + HAL_DMA_DeInit(htim_pwm->hdma[TIM_DMA_ID_CC2]); + /* USER CODE BEGIN TIM8_MspDeInit 1 */ + + /* USER CODE END TIM8_MspDeInit 1 */ + } +} + +void LoadFounderEdition() { + // Configure LED + Device::LED::led_port = GPIOC; + Device::LED::led_pin = GPIO_PIN_7; + + // Configure FN key + Device::KeyPad::fn_port = GPIOA; + Device::KeyPad::fn_pin = GPIO_PIN_8; + + // Configure keypad write pins (columns) + Device::KeyPad::keypad_write_ports[0] = GPIOB; Device::KeyPad::keypad_write_pins[0] = GPIO_PIN_12; // Key1 + Device::KeyPad::keypad_write_ports[1] = GPIOB; Device::KeyPad::keypad_write_pins[1] = GPIO_PIN_13; // Key2 + Device::KeyPad::keypad_write_ports[2] = GPIOB; Device::KeyPad::keypad_write_pins[2] = GPIO_PIN_14; // Key3 + Device::KeyPad::keypad_write_ports[3] = GPIOB; Device::KeyPad::keypad_write_pins[3] = GPIO_PIN_15; // Key4 + Device::KeyPad::keypad_write_ports[4] = GPIOC; Device::KeyPad::keypad_write_pins[4] = GPIO_PIN_6; // Key5 + Device::KeyPad::keypad_write_ports[5] = GPIOC; Device::KeyPad::keypad_write_pins[5] = GPIO_PIN_7; // Key6 + Device::KeyPad::keypad_write_ports[6] = GPIOC; Device::KeyPad::keypad_write_pins[6] = GPIO_PIN_8; // Key7 + Device::KeyPad::keypad_write_ports[7] = GPIOC; Device::KeyPad::keypad_write_pins[7] = GPIO_PIN_9; // Key8 + + // Configure keypad read pins (rows) + Device::KeyPad::keypad_read_ports[0] = GPIOB; Device::KeyPad::keypad_read_pins[0] = GPIO_PIN_0; // KeyRead1 + Device::KeyPad::keypad_read_ports[1] = GPIOB; Device::KeyPad::keypad_read_pins[1] = GPIO_PIN_1; // KeyRead2 + Device::KeyPad::keypad_read_ports[2] = GPIOA; Device::KeyPad::keypad_read_pins[2] = GPIO_PIN_11; // KeyRead3 + Device::KeyPad::keypad_read_ports[3] = GPIOA; Device::KeyPad::keypad_read_pins[3] = GPIO_PIN_12; // KeyRead4 + Device::KeyPad::keypad_read_ports[4] = GPIOC; Device::KeyPad::keypad_read_pins[4] = GPIO_PIN_4; // KeyRead5 + Device::KeyPad::keypad_read_ports[5] = GPIOA; Device::KeyPad::keypad_read_pins[5] = GPIO_PIN_15; // KeyRead6 + Device::KeyPad::keypad_read_ports[6] = GPIOC; Device::KeyPad::keypad_read_pins[6] = GPIO_PIN_5; // KeyRead7 + Device::KeyPad::keypad_read_ports[7] = GPIOC; Device::KeyPad::keypad_read_pins[7] = GPIO_PIN_3; // KeyRead8 + + // Configure touchbar + Device::KeyPad::touchData_Port = GPIOA; + Device::KeyPad::touchData_Pin = GPIO_PIN_0; + Device::KeyPad::touchClock_Port = GPIOA; + Device::KeyPad::touchClock_Pin = GPIO_PIN_1; + + // Set device name and model + Device::name = "MatrixBlock5"; + Device::model = "MB5F"; + Device::product_name = "MatrixBlock5"; +} +} \ No newline at end of file diff --git a/Devices/MatrixBlock5/Variants/MatrixFounderEdition/STM32F103RETX_FLASH.ld b/Devices/MatrixBlock5/Variants/MatrixFounderEdition/STM32F103RETX_FLASH.ld new file mode 100644 index 00000000..c3d79b32 --- /dev/null +++ b/Devices/MatrixBlock5/Variants/MatrixFounderEdition/STM32F103RETX_FLASH.ld @@ -0,0 +1,177 @@ +/** + ****************************************************************************** + * @file LinkerScript.ld + * @author Auto-generated by STM32CubeIDE + * @brief Linker script for STM32F103RETx Device from STM32F1 series + * 512Kbytes FLASH + * 64Kbytes RAM + * + * Set heap size, stack size and stack location according + * to application requirements. + * + * Set memory bank area and size if external memory is used + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */ + +_Min_Heap_Size = 0x200; /* required amount of heap */ +_Min_Stack_Size = 0x400; /* required amount of stack */ + +/* Memories definition */ +MEMORY +{ +/* BOOTLOADER (r) : ORIGIN = 0x08000000, LENGTH = 8K */ +FLASH (rx) : ORIGIN = 0x08002000, LENGTH = 504K + +RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K +} + +/* 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 : { + . = ALIGN(4); + *(.ARM.extab* .gnu.linkonce.armextab.*) + . = ALIGN(4); + } >FLASH + + .ARM : { + . = ALIGN(4); + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + . = ALIGN(4); + } >FLASH + + .preinit_array : + { + . = ALIGN(4); + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + . = ALIGN(4); + } >FLASH + + .init_array : + { + . = ALIGN(4); + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + . = ALIGN(4); + } >FLASH + + .fini_array : + { + . = 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 sections into "RAM" Ram type memory */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + + } >RAM AT> FLASH + + /* Uninitialized data section into "RAM" Ram type memory */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss section */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM + + /* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */ + ._user_heap_stack : + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(8); + } >RAM + + /* Remove information from the compiler libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/Devices/MatrixBlock5/Variants/MatrixFounderEdition/stm32f1xx_hal_conf.h b/Devices/MatrixBlock5/Variants/MatrixFounderEdition/stm32f1xx_hal_conf.h new file mode 100644 index 00000000..e5ae9e2e --- /dev/null +++ b/Devices/MatrixBlock5/Variants/MatrixFounderEdition/stm32f1xx_hal_conf.h @@ -0,0 +1,378 @@ +/** + ****************************************************************************** + * @file USB_Device/HID_Standalone/Inc/stm32f1xx_hal_conf.h + * @author MCD Application Team + * @brief HAL configuration template file. + * This file should be copied to the application folder and renamed + * to stm32f1xx_hal_conf.h. + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2016 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F1xx_HAL_CONF_H +#define __STM32F1xx_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_ADC_MODULE_ENABLED */ +/* #define HAL_CAN_MODULE_ENABLED */ +/* #define HAL_CAN_LEGACY_MODULE_ENABLED */ +#define HAL_CORTEX_MODULE_ENABLED +/* #define HAL_CRC_MODULE_ENABLED */ +/* #define HAL_DAC_MODULE_ENABLED */ +#define HAL_DMA_MODULE_ENABLED +#define HAL_EXTI_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_GPIO_MODULE_ENABLED +/* #define HAL_I2C_MODULE_ENABLED */ +/* #define HAL_I2S_MODULE_ENABLED */ +/* #define HAL_IRDA_MODULE_ENABLED */ +/* #define HAL_IWDG_MODULE_ENABLED */ +/* #define HAL_NOR_MODULE_ENABLED */ +/* #define HAL_PCCARD_MODULE_ENABLED */ +// #define HAL_PCD_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_RTC_MODULE_ENABLED +/* #define HAL_SD_MODULE_ENABLED */ +/* #define HAL_SDRAM_MODULE_ENABLED */ +/* #define HAL_SMARTCARD_MODULE_ENABLED */ +/* #define HAL_SPI_MODULE_ENABLED */ +/* #define HAL_SRAM_MODULE_ENABLED */ +#define HAL_TIM_MODULE_ENABLED +// #define HAL_UART_MODULE_ENABLED +/* #define HAL_USART_MODULE_ENABLED */ +/* #define HAL_WWDG_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) +#if defined(USE_STM3210C_EVAL) +#define HSE_VALUE 25000000U /*!< Value of the External oscillator in Hz */ +#else +#define HSE_VALUE 8000000U /*!< Value of the External oscillator in Hz */ +#endif +#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 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 8000000U /*!< Value of the Internal oscillator in Hz */ +#endif /* HSI_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined(LSI_VALUE) +#define LSI_VALUE 40000U /*!< 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. */ + +/** + * @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 32768U /*!< Value of the External oscillator in Hz*/ +#endif /* LSE_VALUE */ + +#if !defined(LSE_STARTUP_TIMEOUT) +#define LSE_STARTUP_TIMEOUT 5000U /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/* 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 3300U /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY 0x00U /*!< tick interrupt priority */ +#define USE_RTOS 0U +#define PREFETCH_ENABLE 1U + +#define USE_HAL_ADC_REGISTER_CALLBACKS 0U /* ADC register callback disabled */ +#define USE_HAL_CAN_REGISTER_CALLBACKS 0U /* CAN register callback disabled */ +#define USE_HAL_CEC_REGISTER_CALLBACKS 0U /* CEC register callback disabled */ +#define USE_HAL_DAC_REGISTER_CALLBACKS 0U /* DAC register callback disabled */ +#define USE_HAL_ETH_REGISTER_CALLBACKS 0U /* ETH 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_MMC_REGISTER_CALLBACKS 0U /* MMC register callback disabled */ +#define USE_HAL_NAND_REGISTER_CALLBACKS 0U /* NAND register callback disabled */ +#define USE_HAL_NOR_REGISTER_CALLBACKS 0U /* NOR register callback disabled */ +#define USE_HAL_PCCARD_REGISTER_CALLBACKS 0U /* PCCARD register callback disabled */ +#define USE_HAL_PCD_REGISTER_CALLBACKS 0U /* PCD register callback disabled */ +#define USE_HAL_RTC_REGISTER_CALLBACKS 0U /* RTC register callback disabled */ +#define USE_HAL_SD_REGISTER_CALLBACKS 0U /* SD register callback disabled */ +#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS 0U /* SMARTCARD register callback disabled */ +#define USE_HAL_IRDA_REGISTER_CALLBACKS 0U /* IRDA register callback disabled */ +#define USE_HAL_SRAM_REGISTER_CALLBACKS 0U /* SRAM register callback disabled */ +#define USE_HAL_SPI_REGISTER_CALLBACKS 0U /* SPI register callback disabled */ +#define USE_HAL_TIM_REGISTER_CALLBACKS 1U /* 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 */ + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ +/* #define USE_FULL_ASSERT 1U */ + +/* ################## Ethernet peripheral configuration ##################### */ + +/* Section 1 : Ethernet peripheral configuration */ + +/* MAC ADDRESS: MAC_ADDR0:MAC_ADDR1:MAC_ADDR2:MAC_ADDR3:MAC_ADDR4:MAC_ADDR5 */ +#define MAC_ADDR0 2U +#define MAC_ADDR1 0U +#define MAC_ADDR2 0U +#define MAC_ADDR3 0U +#define MAC_ADDR4 0U +#define MAC_ADDR5 0U + +/* Definition of the Ethernet driver buffers size and count */ +#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for receive */ +#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE /* buffer size for transmit */ +#define ETH_RXBUFNB 8U /* 8 Rx buffers of size ETH_RX_BUF_SIZE */ +#define ETH_TXBUFNB 4U /* 4 Tx buffers of size ETH_TX_BUF_SIZE */ + +/* Section 2: PHY configuration section */ + +/* DP83848 PHY Address*/ +#define DP83848_PHY_ADDRESS 0x01U +/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/ +#define PHY_RESET_DELAY 0x000000FFU +/* PHY Configuration delay */ +#define PHY_CONFIG_DELAY 0x00000FFFU + +#define PHY_READ_TO 0x0000FFFFU +#define PHY_WRITE_TO 0x0000FFFFU + +/* Section 3: Common PHY Registers */ + +#define PHY_BCR ((uint16_t)0x0000) /*!< Transceiver Basic Control Register */ +#define PHY_BSR ((uint16_t)0x0001) /*!< Transceiver Basic Status Register */ + +#define PHY_RESET ((uint16_t)0x8000) /*!< PHY Reset */ +#define PHY_LOOPBACK ((uint16_t)0x4000) /*!< Select loop-back mode */ +#define PHY_FULLDUPLEX_100M ((uint16_t)0x2100) /*!< Set the full-duplex mode at 100 Mb/s */ +#define PHY_HALFDUPLEX_100M ((uint16_t)0x2000) /*!< Set the half-duplex mode at 100 Mb/s */ +#define PHY_FULLDUPLEX_10M ((uint16_t)0x0100) /*!< Set the full-duplex mode at 10 Mb/s */ +#define PHY_HALFDUPLEX_10M ((uint16_t)0x0000) /*!< Set the half-duplex mode at 10 Mb/s */ +#define PHY_AUTONEGOTIATION ((uint16_t)0x1000) /*!< Enable auto-negotiation function */ +#define PHY_RESTART_AUTONEGOTIATION ((uint16_t)0x0200) /*!< Restart auto-negotiation function */ +#define PHY_POWERDOWN ((uint16_t)0x0800) /*!< Select the power down mode */ +#define PHY_ISOLATE ((uint16_t)0x0400) /*!< Isolate PHY from MII */ + +#define PHY_AUTONEGO_COMPLETE ((uint16_t)0x0020) /*!< Auto-Negotiation process completed */ +#define PHY_LINKED_STATUS ((uint16_t)0x0004) /*!< Valid link established */ +#define PHY_JABBER_DETECTION ((uint16_t)0x0002) /*!< Jabber condition detected */ + +/* Section 4: Extended PHY Registers */ + +#define PHY_SR ((uint16_t)0x0010) /*!< PHY status register Offset */ +#define PHY_MICR ((uint16_t)0x0011) /*!< MII Interrupt Control Register */ +#define PHY_MISR ((uint16_t)0x0012) /*!< MII Interrupt Status and Misc. Control Register */ + +#define PHY_LINK_STATUS ((uint16_t)0x0001) /*!< PHY Link mask */ +#define PHY_SPEED_STATUS ((uint16_t)0x0002) /*!< PHY Speed mask */ +#define PHY_DUPLEX_STATUS ((uint16_t)0x0004) /*!< PHY Duplex mask */ + +#define PHY_MICR_INT_EN ((uint16_t)0x0002) /*!< PHY Enable interrupts */ +#define PHY_MICR_INT_OE ((uint16_t)0x0001) /*!< PHY Enable output interrupt events */ + +#define PHY_MISR_LINK_INT_EN ((uint16_t)0x0020) /*!< Enable Interrupt on change of link status */ +#define PHY_LINK_INTERRUPT ((uint16_t)0x2000) /*!< PHY link status interrupt mask */ + +/* ################## 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 1U + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED +#include "stm32f1xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED +#include "stm32f1xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_EXTI_MODULE_ENABLED +#include "stm32f1xx_hal_exti.h" +#endif /* HAL_EXTI_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED +#include "stm32f1xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_CAN_MODULE_ENABLED +#include "stm32f1xx_hal_can.h" +#endif /* HAL_CAN_MODULE_ENABLED */ + +#ifdef HAL_CAN_LEGACY_MODULE_ENABLED +#include "Legacy/stm32f1xx_hal_can_legacy.h" +#endif /* HAL_CAN_LEGACY_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED +#include "stm32f1xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED +#include "stm32f1xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED +#include "stm32f1xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED +#include "stm32f1xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED +#include "stm32f1xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED +#include "stm32f1xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED +#include "stm32f1xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED +#include "stm32f1xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_I2S_MODULE_ENABLED +#include "stm32f1xx_hal_i2s.h" +#endif /* HAL_I2S_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED +#include "stm32f1xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED +#include "stm32f1xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED +#include "stm32f1xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_PCCARD_MODULE_ENABLED +#include "stm32f1xx_hal_pccard.h" +#endif /* HAL_PCCARD_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED +#include "stm32f1xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SDRAM_MODULE_ENABLED +#include "stm32f1xx_hal_sdram.h" +#endif /* HAL_SDRAM_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED +#include "stm32f1xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED +#include "stm32f1xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED +#include "stm32f1xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED +#include "stm32f1xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED +#include "stm32f1xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED +#include "stm32f1xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED +#include "stm32f1xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED +#include "stm32f1xx_hal_pcd.h" +#endif /* HAL_PCD_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 /* __STM32F1xx_HAL_CONF_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/Devices/MatrixBlock5/family.mk b/Devices/MatrixBlock5/family.mk new file mode 100644 index 00000000..180f9206 --- /dev/null +++ b/Devices/MatrixBlock5/family.mk @@ -0,0 +1,32 @@ +UF2_FAMILY_ID = 0x5ee21072 +ST_FAMILY = f1 +DEPS_SUBMODULES += lib/CMSIS_5 core/stm32$(ST_FAMILY)/cmsis_device_$(ST_FAMILY) core/stm32$(ST_FAMILY)/stm32$(ST_FAMILY)xx_hal_driver + +# Detect whether shell style is windows or not +# https://stackoverflow.com/questions/714100/os-detecting-makefile/52062069#52062069 +ifeq '$(findstring ;,$(PATH))' ';' +CMDEXE := 1 +endif + +ifeq ($(CMDEXE),1) + CP = copy >nul + RM = del +else + CP = cp + RM = rm +endif + +.PHONY: build flash upload + +build: $(BUILD)/$(PROJECT)-$(DEVICE).bin + +$(BUILD)/$(PROJECT)-$(DEVICE).elf: + cmake -B $(BUILD) -Wno-dev . -DCMAKE_TOOLCHAIN_FILE=$(FAMILY_PATH)/toolchain-stm32f103.cmake -DFAMILY=$(FAMILY) -DDEVICE=$(DEVICE) -DMODE=$(MODE) -G"Unix Makefiles" + cmake --build $(BUILD) -- -j8 + +$(BUILD)/$(PROJECT)-$(DEVICE).bin: $(BUILD)/$(PROJECT)-$(DEVICE).elf + arm-none-eabi-objcopy -O binary "$<" "$@" + +flash upload: $(BUILD)/$(PROJECT)-$(DEVICE).bin + dfu-util "-a 0" "-d 0203:0003" -D"$<" -R + diff --git a/Devices/MatrixBlock5/toolchain-stm32f103.cmake b/Devices/MatrixBlock5/toolchain-stm32f103.cmake new file mode 100644 index 00000000..4e8eadbc --- /dev/null +++ b/Devices/MatrixBlock5/toolchain-stm32f103.cmake @@ -0,0 +1,29 @@ +# STM32F103 CMake Toolchain File + +set(CMAKE_SYSTEM_NAME Generic) +set(CMAKE_SYSTEM_PROCESSOR ARM) + +# Assume toolchain is in PATH like MatrixOS-2.6.0 +set(CMAKE_C_COMPILER arm-none-eabi-gcc) +set(CMAKE_CXX_COMPILER arm-none-eabi-g++) +set(CMAKE_ASM_COMPILER arm-none-eabi-gcc) +set(CMAKE_OBJCOPY arm-none-eabi-objcopy) +set(CMAKE_SIZE arm-none-eabi-size) + +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + +set(CMAKE_C_FLAGS_INIT "-mcpu=cortex-m3 -mthumb -mfpu=auto") +set(CMAKE_CXX_FLAGS_INIT "-mcpu=cortex-m3 -mthumb -mfpu=auto -fno-rtti -fno-exceptions") +set(CMAKE_ASM_FLAGS_INIT "-mcpu=cortex-m3 -mthumb -mfpu=auto -x assembler-with-cpp") + +# Suppress ARM assembler warnings - be more aggressive +set(CMAKE_C_FLAGS_INIT "${CMAKE_C_FLAGS_INIT} -Wa,--no-warn -Wno-error -Wno-error=all -Wno-unused-command-line-argument -Wno-implicit-fallthrough -Wno-format") +set(CMAKE_CXX_FLAGS_INIT "${CMAKE_CXX_FLAGS_INIT} -Wa,--no-warn -Wno-error -Wno-error=all -Wno-unused-command-line-argument -Wno-implicit-fallthrough -Wno-format") +set(CMAKE_ASM_FLAGS_INIT "${CMAKE_ASM_FLAGS_INIT} -Wa,--no-warn -Wno-error -Wno-error=all -Wno-unused-command-line-argument -Wno-implicit-fallthrough -Wno-format") + +set(CMAKE_EXE_LINKER_FLAGS_INIT "-specs=nosys.specs -specs=nano.specs -Wl,--gc-sections -Wl,-Map=${PROJECT_NAME}.map") + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) \ No newline at end of file diff --git a/Devices/MatrixESP32/Config.cmake b/Devices/MatrixESP32/Config.cmake new file mode 100644 index 00000000..812c3fac --- /dev/null +++ b/Devices/MatrixESP32/Config.cmake @@ -0,0 +1,5 @@ +# Device feature configuration for MatrixESP32 family +# These values must match the #define values in MatrixOSConfig.h + +set(DEVICE_STORAGE 1) +set(DEVICE_BATTERY 0) diff --git a/Devices/MatrixESP32/Drivers/Keypad.cpp b/Devices/MatrixESP32/Drivers/Keypad.cpp index 79141c7c..8530fa00 100644 --- a/Devices/MatrixESP32/Drivers/Keypad.cpp +++ b/Devices/MatrixESP32/Drivers/Keypad.cpp @@ -42,6 +42,12 @@ namespace Device::KeyPad { FSR::Init(); } } + // Timer callback wrapper with correct signature + static void KeypadTimerCallback(TimerHandle_t xTimer) { + (void)xTimer; + Scan(); + } + void StartKeyPad() { if (!velocity_sensitivity) { @@ -52,8 +58,7 @@ namespace Device::KeyPad FSR::Start(); } - keypad_timer = xTimerCreateStatic(NULL, configTICK_RATE_HZ / keypad_scanrate, true, NULL, reinterpret_cast(Scan), &keypad_timer_def); - + keypad_timer = xTimerCreateStatic(NULL, configTICK_RATE_HZ / keypad_scanrate, true, NULL, KeypadTimerCallback, &keypad_timer_def); xTimerStart(keypad_timer, 0); } diff --git a/Devices/MatrixESP32/MatrixOSConfig.h b/Devices/MatrixESP32/MatrixOSConfig.h index 1967a271..b067d376 100644 --- a/Devices/MatrixESP32/MatrixOSConfig.h +++ b/Devices/MatrixESP32/MatrixOSConfig.h @@ -1,10 +1,6 @@ #pragma once #include "Framework.h" -// Device feature configuration -#define DEVICE_STORAGE 1 -#define DEVICE_BATTERY 0 - #define FUNCTION_KEY 0 // Keypad Code for main function key #define X_SIZE 8 diff --git a/Library/CMSIS_5 b/Library/CMSIS_5 new file mode 160000 index 00000000..55b19837 --- /dev/null +++ b/Library/CMSIS_5 @@ -0,0 +1 @@ +Subproject commit 55b19837f5703e418ca37894d5745b1dc05e4c91 diff --git a/Library/FreeRTOS-Kernel b/Library/FreeRTOS-Kernel new file mode 160000 index 00000000..23328574 --- /dev/null +++ b/Library/FreeRTOS-Kernel @@ -0,0 +1 @@ +Subproject commit 233285746e7280e91239d64718ef52b32ee91f68 diff --git a/OS/FileSystem/CMakeLists.txt b/OS/FileSystem/CMakeLists.txt index 63092c4b..4161e8f4 100644 --- a/OS/FileSystem/CMakeLists.txt +++ b/OS/FileSystem/CMakeLists.txt @@ -1,21 +1,25 @@ -file(GLOB_RECURSE FILE_HEADERS "*.h") -set(FILE_SOURCES - File.cpp - FileSystem.cpp -) -# Local FatFS sources -set(FATFS_SOURCES - FatFS/ff.c - FatFS/ffunicode.c - FatFS/diskio.cpp - FatFS/ffsystem.c -) +# Only compile FileSystem.cpp if device has storage +if(DEVICE_STORAGE) + file(GLOB_RECURSE FILE_HEADERS "*.h") + + # Local FatFS sources - only needed when storage is available + set(FILE_SOURCES + FileSystem.cpp + File.cpp + FatFS/ff.c + FatFS/ffunicode.c + FatFS/diskio.cpp + FatFS/ffsystem.c + ) +else() + set(FILE_HEADERS "") + set(FILE_SOURCES "") +endif() add_library(MatrixOSFile ${FILE_HEADERS} ${FILE_SOURCES} - ${FATFS_SOURCES} ) target_include_directories(MatrixOSFile PUBLIC diff --git a/OS/Framework/Color/Color.cpp b/OS/Framework/Color/Color.cpp index 4f487f55..02254d89 100644 --- a/OS/Framework/Color/Color.cpp +++ b/OS/Framework/Color/Color.cpp @@ -1,5 +1,6 @@ #include "Color.h" #include +#include float fract(float x) { return x - int(x); } diff --git a/OS/Framework/Storage/SavedVar.h b/OS/Framework/Storage/SavedVar.h index 3e006108..675b3ae4 100644 --- a/OS/Framework/Storage/SavedVar.h +++ b/OS/Framework/Storage/SavedVar.h @@ -11,7 +11,7 @@ namespace MatrixOS::NVS enum SavedVarState { NotInited, Inited, Loaded, Deleted }; #define CreateSavedVar(scope, name, type, default_value) \ - SavedVar name = SavedVar(StaticHash(scope "-" #name), (type)default_value) + SavedVar name = SavedVar(StaticHash(scope "-" #name), (type)default_value) template class SavedVar { diff --git a/OS/LED/LED.cpp b/OS/LED/LED.cpp index 22f37ec1..fd0aeb1c 100644 --- a/OS/LED/LED.cpp +++ b/OS/LED/LED.cpp @@ -89,7 +89,10 @@ namespace MatrixOS::LED } UpdateBrightness(); + } + if (activeBufferSemaphore == nullptr) + { activeBufferSemaphore = xSemaphoreCreateMutex(); } @@ -102,7 +105,7 @@ namespace MatrixOS::LED } frameBuffers.clear(); - + CreateLayer(0); //Create Layer 0 - The active layer CreateLayer(0); //Create Layer 1 - The base layer diff --git a/OS/MIDI/MIDI.cpp b/OS/MIDI/MIDI.cpp index f0b8f380..62cb97be 100644 --- a/OS/MIDI/MIDI.cpp +++ b/OS/MIDI/MIDI.cpp @@ -11,14 +11,15 @@ namespace MatrixOS::MIDI if (!osPort) { osPort = new MidiPort("MatrixOS", MIDI_PORT_OS, MIDI_QUEUE_SIZE); } - + // Create the application queue if it doesn't exist if (!appQueue) { appQueue = xQueueCreate(MIDI_QUEUE_SIZE, sizeof(MidiPacket)); } - + // Create the receive task if it doesn't exist - if (!receiveTask) { + // Only create task if scheduler is already running (ESP32) or will be started later + if (!receiveTask && xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) { xTaskCreate(ReceiveTask, "MIDI_Receive", 2048, NULL, tskIDLE_PRIORITY + 2, &receiveTask); } } diff --git a/OS/System/Parameters.h b/OS/System/Parameters.h index bfda49d9..4b3162c7 100644 --- a/OS/System/Parameters.h +++ b/OS/System/Parameters.h @@ -31,7 +31,7 @@ #define MATRIXOS_LOG_USBCDC #define MATRIXOS_LOG_COLOR -#define APPLICATION_STACK_SIZE (configMINIMAL_STACK_SIZE * 64) +#define APPLICATION_STACK_SIZE (configMINIMAL_STACK_SIZE * 32) #define KEYEVENT_QUEUE_SIZE 16 #define MIDI_QUEUE_SIZE 128 diff --git a/OS/System/System.cpp b/OS/System/System.cpp index f3e22677..180b34f0 100644 --- a/OS/System/System.cpp +++ b/OS/System/System.cpp @@ -7,7 +7,9 @@ #include "../LED/LED.h" #include "../KeyPad/KeyPad.h" #include "../FileSystem/File.h" +#include "../FileSystem/FileSystem.h" #include "../MIDI/MIDI.h" +#include "task.h" extern std::unordered_map applications; @@ -29,6 +31,7 @@ namespace MatrixOS::SYS if (next_app_id != 0) { + auto& applications = GetApplications(); auto application = applications.find(next_app_id); if (application != applications.end()) { @@ -36,6 +39,10 @@ namespace MatrixOS::SYS application->second->name.c_str()); active_app_id = next_app_id; active_app = application->second->factory(); + if (active_app == NULL) { + MLOGE("Application Factory", "Factory returned NULL - allocation failed!"); + ErrorHandler("App allocation failed"); + } active_app_info = application->second; } } @@ -47,13 +54,19 @@ namespace MatrixOS::SYS MLOGD("Application Factory", "Can't find target app."); } MLOGD("Application Factory", "Launching Shell"); + MLOGD("Application Factory", "Free heap before Shell factory: %d bytes", xPortGetFreeHeapSize()); next_app_id = OS_SHELL; + auto& applications = GetApplications(); auto application = applications.find(next_app_id); if (application != applications.end()) { MLOGD("Application Factory", "Launching %s-%s", application->second->author.c_str(), application->second->name.c_str()); active_app = application->second->factory(); + if (active_app == NULL) { + MLOGE("Application Factory", "Shell factory returned NULL - allocation failed!"); + ErrorHandler("Shell allocation failed"); + } active_app_id = next_app_id; active_app_info = application->second; } @@ -78,7 +91,7 @@ namespace MatrixOS::SYS void Supervisor(void* param) { - MLOGD("Supervisor", "%d Apps registered", applications.size()); + MLOGD("Supervisor", "%d Apps registered", GetApplications().size()); active_app_task = xTaskCreateStatic(ApplicationFactory, "application", APPLICATION_STACK_SIZE, NULL, 1, application_stack, &application_taskdef); @@ -111,6 +124,9 @@ namespace MatrixOS::SYS void Begin(void) { Device::DeviceInit(); + // Initialize MIDI system before USB to ensure osPort exists + MatrixOS::MIDI::Init(); + MatrixOS::USB::Init(); InitSysModules(); @@ -141,7 +157,9 @@ namespace MatrixOS::SYS { MatrixOS::KeyPad::Init(); MatrixOS::LED::Init(); +#if DEVICE_STORAGE MatrixOS::FileSystem::Init(); +#endif MatrixOS::USB::SetMode(USB_MODE_NORMAL); MatrixOS::MIDI::Init(); MatrixOS::HID::Init(); @@ -271,7 +289,7 @@ namespace MatrixOS::SYS uint16_t GetApplicationCount() // Used by shell, for some reason shell can not access app_count { - return applications.size(); + return GetApplications().size(); } #define SYSTEM_VERSION_ID(major, minor, patch) ((major << 16) | (minor << 8) | patch) diff --git a/OS/UI/UI.h b/OS/UI/UI.h index 4bd63a24..0ebc310b 100644 --- a/OS/UI/UI.h +++ b/OS/UI/UI.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "UIComponents.h" #include "UIUtilities.h" diff --git a/OS/UI/UIUtilities.h b/OS/UI/UIUtilities.h index 050d7cfa..d1b05bb9 100644 --- a/OS/UI/UIUtilities.h +++ b/OS/UI/UIUtilities.h @@ -1,5 +1,6 @@ #pragma once #include "MatrixOS.h" + #include namespace MatrixOS::UIUtility diff --git a/OS/USB/CMakeLists.txt b/OS/USB/CMakeLists.txt index b0ac2d53..8ce523ad 100644 --- a/OS/USB/CMakeLists.txt +++ b/OS/USB/CMakeLists.txt @@ -1,5 +1,22 @@ file(GLOB_RECURSE USB_HEADERS "*.h") -file(GLOB_RECURSE USB_SOURCES "*.cpp" "*.c") + +# USB source files +set(USB_SOURCES + USB.cpp + HID.cpp + MIDI.cpp + CDC.cpp + TinyUSB/usb_desc_default.cpp + TinyUSB/usb_descriptors.cpp +) + +# Conditionally add MSC sources if device has storage +if(DEVICE_STORAGE) + list(APPEND USB_SOURCES + MSC.cpp + TinyUSB/usb_desc_msc.cpp + ) +endif() set(TINYUSB_DIR ${CMAKE_SOURCE_DIR}/Library/tinyusb/) @@ -15,7 +32,6 @@ set(TINYUSB_SOURCES ${TINYUSB_DIR}/src/class/dfu/dfu_rt_device.c ${TINYUSB_DIR}/src/class/hid/hid_device.c ${TINYUSB_DIR}/src/class/midi/midi_device.c - ${TINYUSB_DIR}/src/class/msc/msc_device.c ${TINYUSB_DIR}/src/class/net/ecm_rndis_device.c ${TINYUSB_DIR}/src/class/net/ncm_device.c ${TINYUSB_DIR}/src/class/usbtmc/usbtmc_device.c @@ -23,8 +39,13 @@ set(TINYUSB_SOURCES ${TINYUSB_DIR}/src/class/vendor/vendor_device.c ) +# Only include MSC device class if device has storage +if(DEVICE_STORAGE) + list(APPEND TINYUSB_SOURCES ${TINYUSB_DIR}/src/class/msc/msc_device.c) +endif() + # if(TINYUSB_MCU_OPT STREQUAL "ESP32S3" OR TINYUSB_MCU_OPT STREQUAL "ESP32S2") - list(APPEND TINYUSB_SOURCES + list(APPEND TINYUSB_SOURCES "${CMAKE_SOURCE_DIR}/Library/tinyusb/src/portable/synopsys/dwc2/dcd_dwc2.c" "${CMAKE_SOURCE_DIR}/Library/tinyusb/src/portable/synopsys/dwc2/dwc2_common.c" ) @@ -43,8 +64,8 @@ add_library(MatrixOSUSB ${PRINTF_SOURCES} ) -target_include_directories(MatrixOSUSB PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} +target_include_directories(MatrixOSUSB PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/TinyUSB ${TINYUSB_DIR}/src ${PRINTF_DIR}/src @@ -52,7 +73,12 @@ target_include_directories(MatrixOSUSB PUBLIC ) # target_compile_options(MatrixOSUSB PUBLIC -# "-DCFG_TUSB_MCU=OPT_MCU_${TINYUSB_MCU_OPT}" +# "-DCFG_TUSB_MCU=OPT_MCU_${TINYUSB_MCU_OPT}" # ) -target_link_libraries(MatrixOSUSB PUBLIC MatrixOSInterface) \ No newline at end of file +target_link_libraries(MatrixOSUSB PUBLIC MatrixOSInterface) + +# Apply device-specific TinyUSB compile options if provided +if(DEFINED DEVICE_TINYUSB_COMPILE_OPTIONS) + target_compile_options(MatrixOSUSB PRIVATE ${DEVICE_TINYUSB_COMPILE_OPTIONS}) +endif() diff --git a/OS/USB/MIDI.cpp b/OS/USB/MIDI.cpp index d1888761..534021f4 100644 --- a/OS/USB/MIDI.cpp +++ b/OS/USB/MIDI.cpp @@ -9,41 +9,43 @@ namespace MatrixOS::MIDI namespace MatrixOS::USB::MIDI { - std::vector ports; + std::vector ports; std::vector portTasks; std::vector portTaskNames; - + std::vector sysex_buffer; void portTask(void* param) { - uint8_t itf = ports.size(); - string portname = "USB MIDI " + std::to_string(itf + 1); - MidiPort port = MidiPort(portname, MIDI_PORT_USB + itf); - ports.push_back(&port); + uint8_t itf = (uint8_t)(uintptr_t)param; MidiPacket packet; while (true) { - if (port.Get(&packet, portMAX_DELAY)) - { tud_midi_stream_write(port.id % 0x100, packet.data, packet.Length()); } + if (ports[itf].Get(&packet, portMAX_DELAY)) + { tud_midi_stream_write(ports[itf].id % 0x100, packet.data, packet.Length()); } } } void Init() { - ports.clear(); - for (TaskHandle_t portTask : portTasks) { vTaskDelete(portTask); } + portTasks.clear(); + portTaskNames.clear(); + ports.clear(); + // Create ports and tasks ports.reserve(USB_MIDI_COUNT); portTasks.reserve(USB_MIDI_COUNT); - + for (uint8_t i = 0; i < USB_MIDI_COUNT; i++) { + string portname = "USB MIDI " + std::to_string(i + 1); + ports.emplace_back(portname, MIDI_PORT_USB + i); + portTasks.push_back(NULL); - portTaskNames.push_back("USB MIDI " + std::to_string(i + 1)); - xTaskCreate(portTask, portTaskNames.back().c_str(), configMINIMAL_STACK_SIZE * 2, NULL, configMAX_PRIORITIES - 2, + portTaskNames.push_back(portname); + xTaskCreate(portTask, portTaskNames.back().c_str(), configMINIMAL_STACK_SIZE * 2, (void*)(uintptr_t)i, configMAX_PRIORITIES - 2, &portTasks.back()); } } diff --git a/OS/USB/TinyUSB/tusb_config.h b/OS/USB/TinyUSB/tusb_config.h index 5e2d90fb..cbf1d964 100644 --- a/OS/USB/TinyUSB/tusb_config.h +++ b/OS/USB/TinyUSB/tusb_config.h @@ -99,7 +99,11 @@ extern "C" { //------------- CLASS -------------// #define CFG_TUD_CDC 1 +#if DEVICE_STORAGE #define CFG_TUD_MSC 1 +#else +#define CFG_TUD_MSC 0 +#endif #define CFG_TUD_HID 1 #define CFG_TUD_MIDI 1 #define CFG_TUD_VENDOR 0 @@ -117,8 +121,10 @@ extern "C" { #define CFG_TUD_HID_EP_BUFSIZE 64 -// MSC Buffer size of Device Mass storage +// MSC Buffer size of Device Mass storage (only if enabled) +#if DEVICE_STORAGE #define CFG_TUD_MSC_EP_BUFSIZE 512 +#endif enum { diff --git a/OS/USB/TinyUSB/usb_desc_default.cpp b/OS/USB/TinyUSB/usb_desc_default.cpp index dc5ae5f8..758b23a0 100644 --- a/OS/USB/TinyUSB/usb_desc_default.cpp +++ b/OS/USB/TinyUSB/usb_desc_default.cpp @@ -152,7 +152,7 @@ uint8_t const desc_default_configuration[] = { TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_DEFAULT_CDC_NOTIF, 8, EPNUM_DEFAULT_CDC_OUT, EPNUM_DEFAULT_CDC_IN, CFG_TUD_CDC_RX_BUFSIZE), // Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval - TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_HID, 0, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_DEFAULT_HID_OUT, EPNUM_DEFAULT_HID_IN, 64, 5) + TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_HID, 0, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_DEFAULT_HID_OUT, EPNUM_DEFAULT_HID_IN, CFG_TUD_HID_EP_BUFSIZE, 5) }; //--------------------------------------------------------------------+ diff --git a/OS/USB/TinyUSB/usb_descriptors.cpp b/OS/USB/TinyUSB/usb_descriptors.cpp index 7b45f240..a0342fcf 100644 --- a/OS/USB/TinyUSB/usb_descriptors.cpp +++ b/OS/USB/TinyUSB/usb_descriptors.cpp @@ -5,7 +5,9 @@ #include "usb_mode_interface.h" #include "usb_desc_default.h" +#if DEVICE_STORAGE #include "usb_desc_msc.h" +#endif //--------------------------------------------------------------------+ // Mode Dispatch Table @@ -18,12 +20,14 @@ const struct usb_mode_interface mode_table[] = { .get_string_descriptor = default_string_descriptor_cb, .get_hid_report_descriptor = default_hid_report_descriptor_cb }, +#if DEVICE_STORAGE [USB_MODE_MSC] = { .get_device_descriptor = msc_device_descriptor_cb, .get_configuration_descriptor = msc_configuration_descriptor_cb, .get_string_descriptor = msc_string_descriptor_cb, .get_hid_report_descriptor = NULL // MSC mode has no HID } +#endif }; //--------------------------------------------------------------------+ diff --git a/OS/USB/USB.h b/OS/USB/USB.h index 9c4035b5..2029ac83 100644 --- a/OS/USB/USB.h +++ b/OS/USB/USB.h @@ -10,6 +10,11 @@ enum USB_MODE { USB_MODE_MSC = 1 // MSC only }; +// Undefine STM32 peripheral macros that conflict with C++ namespace names +#ifdef USB +#undef USB +#endif + namespace MatrixOS::USB { void Init(USB_MODE mode = USB_MODE_NORMAL); @@ -20,4 +25,4 @@ namespace MatrixOS::USB { void Init(); } -} \ No newline at end of file +} diff --git a/OS/main.cpp b/OS/main.cpp index 65a2cfcb..f3cca39c 100644 --- a/OS/main.cpp +++ b/OS/main.cpp @@ -8,7 +8,14 @@ namespace MatrixOS::SYS int main() { MatrixOS::SYS::Begin(); - vTaskDelete(NULL); - return 0; + if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) { + vTaskStartScheduler(); + while(1); + } else { + // ESP32: Scheduler already running, delete this task + vTaskDelete(NULL); + } + + return 0; } \ No newline at end of file diff --git a/Platform/CMakeLists.txt b/Platform/CMakeLists.txt deleted file mode 100644 index 4e657e18..00000000 --- a/Platform/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -# Core layer - FreeRTOS and basic system components -add_library(MatrixOSCore INTERFACE) - -target_include_directories(MatrixOSCore INTERFACE - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/STM32F1 - ${CMAKE_CURRENT_SOURCE_DIR}/STM32F4 - ${CMAKE_CURRENT_SOURCE_DIR}/ESP32SX -) - -# Add FreeRTOS -add_subdirectory(lib/FreeRTOS-Kernel) - -# Link FreeRTOS to core -target_link_libraries(MatrixOSCore INTERFACE FreeRTOS) - -# Add other core libraries -add_subdirectory(lib/printf) -add_subdirectory(lib/tinyusb) -add_subdirectory(lib/cb0r) - -target_link_libraries(MatrixOSCore INTERFACE - printf - tinyusb - cb0r -) \ No newline at end of file diff --git a/Platform/STM32F1/WS2812/CMakeLists.txt b/Platform/STM32F1/WS2812/CMakeLists.txt new file mode 100644 index 00000000..c3d2f4e0 --- /dev/null +++ b/Platform/STM32F1/WS2812/CMakeLists.txt @@ -0,0 +1,20 @@ +file(GLOB_RECURSE WS2812_SOURCES "*.cpp" "*.c") +file(GLOB_RECURSE WS2812_HEADERS "*.h") + +add_library(WS2812 ${WS2812_SOURCES} ${WS2812_HEADERS}) + +target_include_directories(WS2812 PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/OS +) + +# STM32F1 specific WS2812 configuration +target_compile_definitions(WS2812 PUBLIC + WS2812_USE_TIMER + WS2812_TIMER=TIM8 + WS2812_TIMER_CHANNEL=TIM_CHANNEL_2 +) + +target_link_libraries(WS2812 PUBLIC + MatrixOSFramework +) \ No newline at end of file diff --git a/Platform/STM32F1/WS2812/WS2812.cpp b/Platform/STM32F1/WS2812/WS2812.cpp new file mode 100644 index 00000000..230a5c42 --- /dev/null +++ b/Platform/STM32F1/WS2812/WS2812.cpp @@ -0,0 +1,110 @@ +#include "WS2812.h" + +namespace Device +{ + void ErrorHandler(void); +} + +namespace WS2812 +{ + uint16_t numsOfLED; + uint8_t TH_DutyCycle; + uint8_t TL_DutyCycle; + TIM_HandleTypeDef* ws2812_timer = nullptr; + uint32_t ws2812_channel; + Color* frameBuffer = nullptr; + uint8_t* pwmBuffer = nullptr; + uint16_t bufferSize; + int32_t progress = -1; // -1 means signal end has been sent and ready for new job + + void Init(TIM_HandleTypeDef* timer, uint32_t channel, uint16_t led_count) { + ws2812_timer = timer; + ws2812_channel = channel; + numsOfLED = led_count; + + // Calculate buffer size and allocate PWM buffer + bufferSize = numsOfLED * 24 + LED_DMA_END_LENGTH * 2; + pwmBuffer = (uint8_t*)calloc(bufferSize, 1); + if (pwmBuffer == NULL) { + Device::ErrorHandler(); + return; + } + + // Register TIM callback for DMA completion + if (HAL_TIM_RegisterCallback(ws2812_timer, HAL_TIM_PWM_PULSE_FINISHED_CB_ID, DMAHandler) != HAL_OK) { + Device::ErrorHandler(); + } + } + + uint32_t GetTimerPeriod() { + uint32_t timerPeriod; + if (HAL_RCC_GetHCLKFreq() % 800000 == 0) { + timerPeriod = (HAL_RCC_GetHCLKFreq() / 800000) - 1; + } + else { + return -1; // Error: clock frequency not compatible + } + + // Calculate duty cycles for WS2812 timing + // TH (high time for '1'): ~0.8us = 173/256 of period + // TL (high time for '0'): ~0.4us = 82/256 of period + TH_DutyCycle = (timerPeriod * 173) >> 8; + TL_DutyCycle = (timerPeriod * 82) >> 8; + + return timerPeriod; + } + + void Show(Color* buffer, std::vector& brightness) { + // Safety checks + if (buffer == NULL || pwmBuffer == NULL || progress != -1) { + return; + } + + // Get brightness value (assume single partition for MatrixBlock5) + uint8_t local_brightness = brightness.size() > 0 ? brightness[0] : 255; + + // Set up for DMA transfer + progress = 0; + frameBuffer = buffer; + PrepLEDBuffer(local_brightness); + SendData(); + } + + void DMAHandler(TIM_HandleTypeDef* htim) { + HAL_TIM_PWM_Stop_DMA(htim, ws2812_channel); + progress = -1; + } + + void SendData() { + HAL_TIM_PWM_Start_DMA(ws2812_timer, ws2812_channel, (uint32_t*)pwmBuffer, bufferSize); + } + + void PrepLEDBuffer(uint8_t brightness) { + uint16_t index = 0; + + // Add start padding + for (uint8_t i = 0; i < LED_DMA_END_LENGTH; i++) { + pwmBuffer[index] = 0; + index++; + } + + // Fill PWM buffer with LED data + while (index <= (bufferSize - 24) && progress < numsOfLED) { + // Get GRB value with brightness applied + uint32_t GRB = frameBuffer[progress].GRB(brightness); + + // Convert each bit to PWM duty cycle + for (int8_t i = 23; i >= 0; i--) { + pwmBuffer[index] = (GRB & (1 << i)) ? TH_DutyCycle : TL_DutyCycle; + index++; + } + progress++; + } + + // Add end padding + for (uint8_t i = 0; i < LED_DMA_END_LENGTH; i++) { + pwmBuffer[index] = 0; + index++; + } + } +} diff --git a/Platform/STM32F1/WS2812/WS2812.h b/Platform/STM32F1/WS2812/WS2812.h new file mode 100644 index 00000000..d6e3e3ca --- /dev/null +++ b/Platform/STM32F1/WS2812/WS2812.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include +#include +#include "Framework.h" +#include "stm32f1xx_hal.h" +#include "FreeRTOS.h" +#include "timers.h" + +#define LED_DMA_END_LENGTH 80 + +namespace WS2812 +{ + inline bool dithering = false; + inline uint8_t dithering_threshold = 4; // Channel value lower than this will not dither + + void Init(TIM_HandleTypeDef* timer, uint32_t channel, uint16_t led_count); + void Show(Color* buffer, std::vector& brightness); + uint32_t GetTimerPeriod(); + + // DMA-based WS2812 functions + void DMAHandler(TIM_HandleTypeDef* htim); + void SendData(); + void PrepLEDBuffer(uint8_t brightness); + + extern uint16_t numsOfLED; + extern uint8_t TH_DutyCycle; + extern uint8_t TL_DutyCycle; + extern TIM_HandleTypeDef* ws2812_timer; + extern uint32_t ws2812_channel; + extern Color* frameBuffer; + extern uint8_t* pwmBuffer; + extern uint16_t bufferSize; + extern int32_t progress; +} \ No newline at end of file diff --git a/Platform/STM32F1/cmsis_device_f1 b/Platform/STM32F1/cmsis_device_f1 new file mode 160000 index 00000000..c8e9a4a4 --- /dev/null +++ b/Platform/STM32F1/cmsis_device_f1 @@ -0,0 +1 @@ +Subproject commit c8e9a4a4f16b6d2cb2a2083cbe5161025280fb22 diff --git a/Platform/STM32F1/stm32f1xx_hal_driver b/Platform/STM32F1/stm32f1xx_hal_driver new file mode 160000 index 00000000..53cf47b9 --- /dev/null +++ b/Platform/STM32F1/stm32f1xx_hal_driver @@ -0,0 +1 @@ +Subproject commit 53cf47b925068ed9c9196fd1842a045ee19bf0fa