diff --git a/drivers/CoreDAC/CMakeLists.txt b/drivers/CoreDAC/CMakeLists.txt index c50cf4348a..630e91469a 100644 --- a/drivers/CoreDAC/CMakeLists.txt +++ b/drivers/CoreDAC/CMakeLists.txt @@ -25,3 +25,9 @@ target_link_libraries(CoreDAC mbed-os CoreSTM32Hal ) + +if(${CMAKE_PROJECT_NAME} STREQUAL "LekaOSUnitTests") + leka_unit_tests_sources( + tests/CoreSTM32HalBasicTimer_test.cpp + ) +endif() diff --git a/drivers/CoreDAC/tests/CoreSTM32HalBasicTimer_test.cpp b/drivers/CoreDAC/tests/CoreSTM32HalBasicTimer_test.cpp new file mode 100644 index 0000000000..16a11f9e79 --- /dev/null +++ b/drivers/CoreDAC/tests/CoreSTM32HalBasicTimer_test.cpp @@ -0,0 +1,200 @@ +// Leka - LekaOS +// Copyright 2024 APF France handicap +// SPDX-License-Identifier: Apache-2.0 + +#include "CoreSTM32HalBasicTimer.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "mocks/leka/CoreSTM32Hal.h" +#include "mocks/leka/STM32HalBasicTimer.h" + +using namespace leka; + +using testing::_; +using ::testing::DoAll; +using ::testing::InSequence; +using ::testing::MockFunction; +using ::testing::Return; +using ::testing::SaveArg; +using ::testing::SaveArgPointee; + +class CoreSTM32HalBasicTimerTest : public ::testing::Test +{ + protected: + void SetUp() override + { + basic_timer.registerCallback(callback.AsStdFunction()); + + EXPECT_CALL(halmock, HAL_TIM_RegisterCallback(_, HAL_TIM_BASE_MSPINIT_CB_ID, _)) + .WillOnce(DoAll(SaveArg<2>(&mspinit_callback), Return(HAL_StatusTypeDef::HAL_OK))); + EXPECT_CALL(halmock, HAL_TIM_RegisterCallback(_, HAL_TIM_BASE_MSPDEINIT_CB_ID, _)) + .WillOnce(DoAll(SaveArg<2>(&mspdeinit_callback), Return(HAL_StatusTypeDef::HAL_OK))); + EXPECT_CALL(halmock, HAL_TIM_RegisterCallback(_, HAL_TIM_PERIOD_ELAPSED_CB_ID, _)) + .WillOnce(DoAll(SaveArg<2>(&period_elapsed_callback), Return(HAL_StatusTypeDef::HAL_OK))); + + EXPECT_CALL(halmock, HAL_TIM_Base_Init); + EXPECT_CALL(halmock, HAL_TIMEx_MasterConfigSynchronization) + .WillOnce(DoAll(SaveArgPointee<1>(&basic_timer_master_config), Return(HAL_StatusTypeDef::HAL_OK))); + + basic_timer.initialize(); + } + // void TearDown() override {} + + mock::CoreSTM32Hal halmock; + + CoreSTM32HalBasicTimer basic_timer {halmock}; + TIM_MasterConfigTypeDef basic_timer_master_config {}; + + MockFunction callback; + + std::function mspinit_callback = [](TIM_HandleTypeDef *) {}; + std::function mspdeinit_callback = [](TIM_HandleTypeDef *) {}; + std::function period_elapsed_callback = [](TIM_HandleTypeDef *) {}; +}; + +TEST_F(CoreSTM32HalBasicTimerTest, initializationDefault) +{ + EXPECT_NE(&basic_timer, nullptr); + + auto handle = basic_timer.getHandle(); + EXPECT_NE(&handle, nullptr); + auto allowed_instance = handle.Instance == TIM6 || handle.Instance == TIM7; + EXPECT_TRUE(allowed_instance); +} + +TEST_F(CoreSTM32HalBasicTimerTest, initialize) +{ + { + InSequence seq; + + { + EXPECT_CALL(halmock, HAL_TIM_RegisterCallback(_, HAL_TIM_BASE_MSPINIT_CB_ID, _)); + EXPECT_CALL(halmock, HAL_TIM_RegisterCallback(_, HAL_TIM_BASE_MSPDEINIT_CB_ID, _)); + } // MSP callbacks + + { + EXPECT_CALL(halmock, HAL_TIM_Base_Init); + EXPECT_CALL(halmock, HAL_TIMEx_MasterConfigSynchronization); + } // BasicTimer config + + { + EXPECT_CALL(halmock, HAL_TIM_RegisterCallback(_, HAL_TIM_PERIOD_ELAPSED_CB_ID, _)); + } // Callback on event + } + + basic_timer.initialize(); +} + +TEST_F(CoreSTM32HalBasicTimerTest, initializeMspInit) +{ + auto *basic_timer_instance = basic_timer.getHandle().Instance; + + if (basic_timer_instance == TIM6) { + EXPECT_CALL(halmock, HAL_RCC_TIM6_CLK_ENABLE); + EXPECT_CALL(halmock, HAL_NVIC_SetPriority(TIM6_DAC_IRQn, _, _)); + EXPECT_CALL(halmock, HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn)); + } else if (basic_timer_instance == TIM7) { + EXPECT_CALL(halmock, HAL_RCC_TIM7_CLK_ENABLE); + EXPECT_CALL(halmock, HAL_NVIC_SetPriority(TIM7_IRQn, _, _)); + EXPECT_CALL(halmock, HAL_NVIC_EnableIRQ(TIM7_IRQn)); + } else { + FAIL(); // Only timers 6 and 7 can be used as Basic Timer + } + + mspinit_callback(&basic_timer.getHandle()); +} + +TEST_F(CoreSTM32HalBasicTimerTest, initializeMspDeinit) +{ + auto *basic_timer_instance = basic_timer.getHandle().Instance; + + if (basic_timer_instance == TIM6) { + EXPECT_CALL(halmock, HAL_RCC_TIM6_CLK_DISABLE); + } else if (basic_timer_instance == TIM7) { + EXPECT_CALL(halmock, HAL_RCC_TIM7_CLK_DISABLE); + } else { + FAIL(); // Only timers 6 and 7 can be used as Basic Timer + } + + mspdeinit_callback(&basic_timer.getHandle()); +} + +TEST_F(CoreSTM32HalBasicTimerTest, initializeConfig) +{ + auto timer_handle = basic_timer.getHandle(); + + auto CK_INT = float(108'000'000.0); + auto default_sample_rate = float(44'100.0); + auto divider = std::round(CK_INT / default_sample_rate); + + // The prescaler can divide the counter clock frequency by any factor between 1 and 65536, see 28.3.1 of RM + auto prescaler = timer_handle.Init.Prescaler; + EXPECT_LE(prescaler, 0xFFF); + + // The counter counts from 0 to the auto-reload value, see 28.3.2 of RM + auto auto_reload_value = timer_handle.Init.Period; + EXPECT_GE(auto_reload_value, 1); + EXPECT_LE(auto_reload_value, 0xFFF); + + // To fit required frequency (default sample rate), multiplying prescaler and auto-reload value must give + // approximately the divider + EXPECT_NEAR((prescaler + 1) * (auto_reload_value + 1), divider, 1); + + // Disable shadow write + EXPECT_EQ(timer_handle.Init.AutoReloadPreload, TIM_AUTORELOAD_PRELOAD_DISABLE); + + // The update event is selected as a trigger output, see 28.4.2 of RM + EXPECT_EQ(basic_timer_master_config.MasterOutputTrigger, TIM_TRGO_UPDATE); + + // ? Config not available for BasicTimer (TIM6 and TIM7) + // _htim.Init.CounterMode; + // _htim.Init.ClockDivision; + // _htim.Init.RepetitionCounter; + // timerMasterConfig.MasterSlaveMode; +} + +TEST_F(CoreSTM32HalBasicTimerTest, initializePeriodElapsedCallback) +{ + EXPECT_CALL(callback, Call); + period_elapsed_callback(&basic_timer.getHandle()); +} + +TEST_F(CoreSTM32HalBasicTimerTest, linkDACTimer) +{ + basic_timer.linkDACTimer(nullptr); + + DAC_ChannelConfTypeDef dac_config {}; + + basic_timer.linkDACTimer(&dac_config); + + auto *basic_timer_instance = basic_timer.getHandle().Instance; + if (basic_timer_instance == TIM6) { + EXPECT_EQ(dac_config.DAC_Trigger, DAC_TRIGGER_T6_TRGO); + } else if (basic_timer_instance == TIM7) { + EXPECT_EQ(dac_config.DAC_Trigger, DAC_TRIGGER_T7_TRGO); + } else { + FAIL(); // Only timers 6 and 7 can be used as DAC Timer + } +} + +TEST_F(CoreSTM32HalBasicTimerTest, terminate) +{ + EXPECT_CALL(halmock, HAL_TIM_Base_DeInit); + + basic_timer.terminate(); +} + +TEST_F(CoreSTM32HalBasicTimerTest, start) +{ + EXPECT_CALL(halmock, HAL_TIM_Base_Start_IT); + + basic_timer.start(); +} + +TEST_F(CoreSTM32HalBasicTimerTest, stop) +{ + EXPECT_CALL(halmock, HAL_TIM_Base_Stop_IT); + + basic_timer.stop(); +} diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index ac790e5550..b48f77d5eb 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -253,7 +253,7 @@ add_subdirectory(template) # Register drivers leka_register_unit_tests_for_driver(CoreBattery) leka_register_unit_tests_for_driver(CoreBufferedSerial) -leka_register_unit_tests_for_driver(CoreQDAC) +leka_register_unit_tests_for_driver(CoreDAC) leka_register_unit_tests_for_driver(CoreEventFlags) leka_register_unit_tests_for_driver(CoreEventQueue) leka_register_unit_tests_for_driver(CoreFlashMemory) @@ -270,6 +270,7 @@ leka_register_unit_tests_for_driver(CoreMicrophone) leka_register_unit_tests_for_driver(CoreMotor) leka_register_unit_tests_for_driver(CoreMutex) leka_register_unit_tests_for_driver(CorePwm) +leka_register_unit_tests_for_driver(CoreQDAC) leka_register_unit_tests_for_driver(CoreQSPI) leka_register_unit_tests_for_driver(CoreRFIDReader) leka_register_unit_tests_for_driver(CoreSPI)