From e7bedde83560f0e8a066b093a9182023729fc149 Mon Sep 17 00:00:00 2001 From: Thad House Date: Sat, 19 Jun 2021 01:21:07 -0700 Subject: [PATCH] [HLT] Add PWM tests that use DMA as the back end (#3447) Both a decent DMA test, and slightly more reliable PWM test. --- .../src/main/native/cpp/PWMTests.cpp | 138 ++++++++++++++++++ .../src/main/native/cpp/TestEnvironment.cpp | 1 + .../main/native/include/LifetimeWrappers.h | 18 +++ 3 files changed, 157 insertions(+) diff --git a/crossConnIntegrationTests/src/main/native/cpp/PWMTests.cpp b/crossConnIntegrationTests/src/main/native/cpp/PWMTests.cpp index 8238b50147..0757cfecd2 100644 --- a/crossConnIntegrationTests/src/main/native/cpp/PWMTests.cpp +++ b/crossConnIntegrationTests/src/main/native/cpp/PWMTests.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -18,6 +19,128 @@ using namespace hlt; class PWMTest : public ::testing::TestWithParam> {}; +void TestTimingDMA(int squelch, std::pair param) { + // Initialize DMA + int32_t status = 0; + DMAHandle dmaHandle(&status); + ASSERT_NE(dmaHandle, HAL_kInvalidHandle); + ASSERT_EQ(0, status); + + status = 0; + PWMHandle pwmHandle(param.first, &status); + ASSERT_NE(pwmHandle, HAL_kInvalidHandle); + ASSERT_EQ(0, status); + + // Ensure our PWM is disabled, and set up properly + HAL_SetPWMRaw(pwmHandle, 0, &status); + HAL_SetPWMConfig(pwmHandle, 2.0, 1.0, 1.0, 0, 0, &status); + HAL_SetPWMPeriodScale(pwmHandle, squelch, &status); + + unsigned int checkPeriod = 0; + switch (squelch) { + case (0): + checkPeriod = 5050; + break; + case (1): + checkPeriod = 10100; + break; + case (3): + checkPeriod = 20200; + break; + } + + status = 0; + DIOHandle dioHandle(param.second, true, &status); + ASSERT_NE(dioHandle, HAL_kInvalidHandle); + + HAL_AddDMADigitalSource(dmaHandle, dioHandle, &status); + ASSERT_EQ(0, status); + + HAL_SetDMAExternalTrigger(dmaHandle, dioHandle, + HAL_AnalogTriggerType::HAL_Trigger_kInWindow, true, + true, &status); + ASSERT_EQ(0, status); + + // Loop to test 5 speeds + for (unsigned int testWidth = 1000; testWidth < 2100; testWidth += 250) { + HAL_StartDMA(dmaHandle, 1024, &status); + ASSERT_EQ(0, status); + + while (true) { + int32_t remaining = 0; + HAL_DMASample testSample; + HAL_ReadDMA(dmaHandle, &testSample, 0.01, &remaining, &status); + if (remaining == 0) { + break; + } + } + + HAL_SetPWMSpeed(pwmHandle, (testWidth - 1000) / 1000.0, &status); + + constexpr const int kSampleCount = 15; + HAL_DMASample dmaSamples[kSampleCount]; + int readCount = 0; + while (readCount < kSampleCount) { + status = 0; + int32_t remaining = 0; + HAL_DMAReadStatus readStatus = HAL_ReadDMA( + dmaHandle, &dmaSamples[readCount], 1.0, &remaining, &status); + ASSERT_EQ(0, status); + ASSERT_EQ(HAL_DMAReadStatus::HAL_DMA_OK, readStatus); + readCount++; + } + + HAL_SetPWMSpeed(pwmHandle, 0, &status); + HAL_StopDMA(dmaHandle, &status); + + // Find first rising edge + int startIndex = 4; + while (startIndex < 6) { + status = 0; + auto value = HAL_GetDMASampleDigitalSource(&dmaSamples[startIndex], + dioHandle, &status); + ASSERT_EQ(0, status); + if (value) + break; + startIndex++; + } + ASSERT_LT(startIndex, 6); + + // Check that samples alternate + bool previous = false; + int iterationCount = 0; + for (int i = startIndex; i < startIndex + 8; i++) { + auto value = + HAL_GetDMASampleDigitalSource(&dmaSamples[i], dioHandle, &status); + ASSERT_EQ(0, status); + ASSERT_NE(previous, value); + previous = !previous; + iterationCount++; + } + ASSERT_EQ(iterationCount, 8); + iterationCount = 0; + + // Check width between samples + for (int i = startIndex; i < startIndex + 8; i += 2) { + auto width = HAL_GetDMASampleTime(&dmaSamples[i + 1], &status) - + HAL_GetDMASampleTime(&dmaSamples[i], &status); + ASSERT_NEAR(testWidth, width, 10); + iterationCount++; + } + ASSERT_EQ(iterationCount, 4); + iterationCount = 0; + + // Check period between samples + for (int i = startIndex; i < startIndex + 6; i += 2) { + auto period = HAL_GetDMASampleTime(&dmaSamples[i + 2], &status) - + HAL_GetDMASampleTime(&dmaSamples[i], &status); + ASSERT_NEAR(checkPeriod, period, 10); + iterationCount++; + } + ASSERT_EQ(iterationCount, 3); + } +} + struct InterruptCheckData { wpi::SmallVector risingStamps; wpi::SmallVector fallingStamps; @@ -171,6 +294,21 @@ TEST_P(PWMTest, TestTiming1x) { TestTiming(0, param); } +TEST_P(PWMTest, TestTimingDMA4x) { + auto param = GetParam(); + TestTimingDMA(3, param); +} + +TEST_P(PWMTest, TestTimingDMA2x) { + auto param = GetParam(); + TestTimingDMA(1, param); +} + +TEST_P(PWMTest, TestTimingDMA1x) { + auto param = GetParam(); + TestTimingDMA(0, param); +} + TEST(PWMTest, TestAllocateAll) { wpi::SmallVector pwmHandles; for (int i = 0; i < HAL_GetNumPWMChannels(); i++) { diff --git a/crossConnIntegrationTests/src/main/native/cpp/TestEnvironment.cpp b/crossConnIntegrationTests/src/main/native/cpp/TestEnvironment.cpp index d1b9a6d63d..ee8c2b1b24 100644 --- a/crossConnIntegrationTests/src/main/native/cpp/TestEnvironment.cpp +++ b/crossConnIntegrationTests/src/main/native/cpp/TestEnvironment.cpp @@ -61,6 +61,7 @@ class TestEnvironment : public testing::Environment { fmt::print("Waiting for enable: {}\n", enableCounter++); } + std::this_thread::sleep_for(500ms); } ~TestEnvironment() override { m_mockDS.Stop(); } diff --git a/crossConnIntegrationTests/src/main/native/include/LifetimeWrappers.h b/crossConnIntegrationTests/src/main/native/include/LifetimeWrappers.h index c8fbb6e2da..22dc5bce07 100644 --- a/crossConnIntegrationTests/src/main/native/include/LifetimeWrappers.h +++ b/crossConnIntegrationTests/src/main/native/include/LifetimeWrappers.h @@ -4,6 +4,7 @@ #pragma once +#include #include namespace hlt { @@ -27,6 +28,23 @@ struct InterruptHandle { HAL_InterruptHandle handle = 0; }; +struct DMAHandle { + public: + explicit DMAHandle(int32_t* status) { handle = HAL_InitializeDMA(status); } + DMAHandle(const DMAHandle&) = delete; + DMAHandle operator=(const DMAHandle&) = delete; + + DMAHandle(DMAHandle&&) = default; + DMAHandle& operator=(DMAHandle&&) = default; + + ~DMAHandle() { HAL_FreeDMA(handle); } + + operator HAL_DMAHandle() const { return handle; } + + private: + HAL_DMAHandle handle = 0; +}; + struct DIOHandle { public: DIOHandle() {}