Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: timer with PWM channels #516

Merged
merged 2 commits into from
Mar 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file removed .gitmodules
Empty file.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ if (HALST_STANDALONE)
FetchContent_Declare(
emil
GIT_REPOSITORY https://github.com/philips-software/amp-embedded-infra-lib.git
GIT_TAG 3b8d1a4703a6533d2dbc93322a044839b40da2d1 # unreleased
GIT_TAG a216de39bb3eab10c736a1f62ee734e79658af1d # unreleased
)
FetchContent_MakeAvailable(emil)

Expand Down
2 changes: 2 additions & 0 deletions hal_st/stm32fxxx/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ target_sources(hal_st.stm32fxxx PRIVATE
SystemTickStm.hpp
SystemTickTimerService.cpp
SystemTickTimerService.hpp
TimerPwmStm.cpp
TimerPwmStm.hpp
TimerStm.cpp
TimerStm.hpp
$<$<NOT:$<STREQUAL:${TARGET_MCU_FAMILY},stm32g0xx>>:UartStm.cpp>
Expand Down
129 changes: 129 additions & 0 deletions hal_st/stm32fxxx/TimerPwmStm.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#include "hal_st/stm32fxxx/TimerPwmStm.hpp"
#include "hal_st/stm32fxxx/GpioStm.hpp"
#include "hal_st/stm32fxxx/TimerStm.hpp"
#include <array>
#include <cstdint>

#if defined(HAS_PERIPHERAL_TIMER)

namespace
{
constexpr std::array channelPinConfigs{
hal::PinConfigTypeStm::timerChannel1,
hal::PinConfigTypeStm::timerChannel2,
hal::PinConfigTypeStm::timerChannel3,
hal::PinConfigTypeStm::timerChannel4
};

hal::PinConfigTypeStm GetChannelPinConfig(std::size_t index)
{
assert(index < channelPinConfigs.size());
return channelPinConfigs[index];
}

constexpr std::array timerChannels{
TIM_CHANNEL_1,
TIM_CHANNEL_2,
TIM_CHANNEL_3,
TIM_CHANNEL_4,
#if defined(TIM_CHANNEL_5)
TIM_CHANNEL_5,
#endif
#if defined(TIM_CHANNEL_6)
TIM_CHANNEL_6
#endif
};

uint32_t GetTimerChannel(std::size_t index)
{
assert(index < timerChannels.size());
return timerChannels[index];
}

const std::array ccr{
&TIM_TypeDef::CCR1,
&TIM_TypeDef::CCR2,
&TIM_TypeDef::CCR3,
&TIM_TypeDef::CCR4,
#if defined(TIM_CHANNEL_5)
&TIM_TypeDef::CCR5,
#endif
#if defined(TIM_CHANNEL_6)
&TIM_TypeDef::CCR6,
#endif
};

volatile std::uint32_t* GetCCRegister(TIM_TypeDef* tim, std::size_t index)
{
assert(index < ccr.size());
return &(tim->*ccr[index]);
}
}

namespace hal
{
TimerPwmBaseStm::TimerPwmBaseStm(uint8_t oneBasedIndex, TimerBaseStm::Timing timing)
: timer(oneBasedIndex, timing, { TimerBaseStm::CounterMode::up })
{}

PwmChannelGpio& TimerPwmBaseStm::Channel(uint8_t channelOneBasedIndex)
{
return channels[channelOneBasedIndex - 1];
}

void TimerPwmBaseStm::Start()
{
for (auto& channel : channels)
channel.Start();

timer.Start();
}

void TimerPwmBaseStm::Stop()
{
timer.Stop();

for (auto& channel : channels)
channel.Stop();
}

PwmChannelGpio::PwmChannelGpio(uint8_t timerOneBasedIndex, uint8_t channelOneBasedIndex, TIM_HandleTypeDef& handle, GpioPinStm& pin)
: timerIndex(timerOneBasedIndex - 1)
, channelIndex(channelOneBasedIndex - 1)
, handle(handle)
, pin(pin, GetChannelPinConfig(channelIndex), timerOneBasedIndex)
, ccr(GetCCRegister(handle.Instance, channelIndex))
{
TIM_OC_InitTypeDef init{};
init.OCMode = TIM_OCMODE_PWM1;
init.Pulse = 0;
init.OCPolarity = TIM_OCPOLARITY_HIGH;
init.OCFastMode = TIM_OCFAST_DISABLE;
auto result = HAL_TIM_PWM_ConfigChannel(&handle, &init, GetTimerChannel(channelIndex));
assert(result == HAL_OK);
}

void PwmChannelGpio::SetDuty(uint8_t dutyPercent)
{
assert(dutyPercent >= 0 && dutyPercent <= 100);
*ccr = handle.Instance->ARR * dutyPercent / 100;
}

void PwmChannelGpio::SetPulse(uint32_t pulseOn, uint32_t period)
{
*ccr = pulseOn;
handle.Instance->ARR = period;
}

void PwmChannelGpio::Start()
{
HAL_TIM_PWM_Start(&handle, GetTimerChannel(channelIndex));
}

void PwmChannelGpio::Stop()
{
HAL_TIM_PWM_Stop(&handle, GetTimerChannel(channelIndex));
}
}

#endif
87 changes: 87 additions & 0 deletions hal_st/stm32fxxx/TimerPwmStm.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#ifndef HAL_ST_TIMER_PWM_ST_HPP
#define HAL_ST_TIMER_PWM_ST_HPP

#include "hal/interfaces/PulseWidthModulation.hpp"
#include "hal_st/stm32fxxx/GpioStm.hpp"
#include "hal_st/stm32fxxx/TimerStm.hpp"
#include "infra/util/MemoryRange.hpp"
#include <array>
#include <cstddef>
#include <cstdint>
#include <utility>

#if defined(HAS_PERIPHERAL_TIMER)

namespace hal
{
namespace detail
{
template<typename T, std::size_t... Is>
constexpr std::array<T, sizeof...(Is)> CreateArray(uint8_t timerOneBasedIndex, TIM_HandleTypeDef& handle, infra::MemoryRange<GpioPinStm> pins, std::index_sequence<Is...>)
{
return { { (Is, T{ timerOneBasedIndex, Is + 1, handle, pins[Is] })... } };
}
}

template<std::size_t N, typename T>
constexpr std::array<T, N> CreateArray(uint8_t timerOneBasedIndex, TIM_HandleTypeDef& handle, infra::MemoryRange<GpioPinStm> pins)
{
return detail::CreateArray<T>(timerOneBasedIndex, handle, pins, std::make_index_sequence<N>());
}

class PwmChannelGpio;

class TimerPwmBaseStm
{
public:
TimerPwmBaseStm(uint8_t oneBasedIndex, TimerBaseStm::Timing timing);

PwmChannelGpio& Channel(uint8_t channelOneBasedIndex);

void Start();
void Stop();

protected:
FreeRunningTimerStm timer;
infra::MemoryRange<PwmChannelGpio> channels;
};

template<std::size_t Channels>
class TimerPwmWithChannels
: public TimerPwmBaseStm
{
public:
TimerPwmWithChannels(uint8_t oneBasedIndex, TimerBaseStm::Timing timing, infra::MemoryRange<GpioPinStm> pins)
: TimerPwmBaseStm(oneBasedIndex, timing)
, channelStorage(CreateArray<Channels, PwmChannelGpio>(oneBasedIndex, timer.Handle(), pins))
{
channels = channelStorage;
}

private:
std::array<PwmChannelGpio, Channels> channelStorage;
};

class PwmChannelGpio
: public PulseWidthModulation
{
public:
PwmChannelGpio(uint8_t timerOneBasedIndex, uint8_t channelOneBasedIndex, TIM_HandleTypeDef& handle, GpioPinStm& pin);

void SetDuty(uint8_t dutyPercent) override;
void SetPulse(uint32_t pulseOn, uint32_t period) override;
void Start() override;
void Stop() override;

private:
uint8_t timerIndex;
uint8_t channelIndex;
TIM_HandleTypeDef& handle;
PeripheralPinStm pin;
volatile std::uint32_t* ccr;
};
}

#endif

#endif // HAL_ST_TIMER_PWM_ST_HPP
6 changes: 6 additions & 0 deletions hal_st/stm32fxxx/TimerStm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ namespace hal

protected:
TIM_HandleTypeDef handle = {};

public:
auto& Handle()
{
return handle;
}
};

class FreeRunningTimerStm
Expand Down
Loading