libyggdrasil  v1.0.0
sink_driver.hpp
Go to the documentation of this file.
1  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * _____.___. .___ .__.__ *
3  * \__ | | ____ ____ __| _/___________ _____|__| | *
4  * / | |/ ___\ / ___\ / __ |\_ __ \__ \ / ___/ | | *
5  * \____ / /_/ > /_/ > /_/ | | | \// __ \_\___ \| | |__ *
6  * / ______\___ /\___ /\____ | |__| (____ /____ >__|____/ *
7  * \/ /_____//_____/ \/ \/ \/ *
8  * - Yggdrasil - *
9  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
10  * This software can be used by students and other personal of the *
11  * Bern University of Applied Sciences under the terms of the MIT *
12  * license. *
13  * For other persons this software is under the terms of the GNU *
14  * General Public License version 2. *
15  * *
16  * Copyright © 2021, Bern University of Applied Sciences. *
17  * All rights reserved. *
18  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
26 #pragma once
27 
29 #include <cpp/common/types.hpp>
30 #include <cpp/common/utils.hpp>
31 
32 namespace bsp::ygg::prph {
33 
34 
38  class SinkDriver {
39  public:
40  SinkDriver() = delete;
41 
47  static bool init() {
48  return true;
49  }
50 
54  enum class Channel {
55  A = 0,
56  B = 1,
57  C = 2,
58  D = 3,
59  };
60 
65  class Servo {
66  public:
67  Servo() = delete;
68 
78  static void set(Channel channel, float percent) {
79  if(checkMode(channel) == false) return; // Chech if the channel is configured as a servo channel
80 
81  percent = math::clamp(percent, -100.0F, 100.0F);
82 
83  float dutyCycle = ((MidPosition + ((Servo::s_delta[enumValue(channel)] / 100.0F) * percent)) / TPWM) * 100.0F; // get the high time in ms and calculate the duty cycle
84 
85  switch(channel){
86  case Channel::A:
87  bsp::SinkDriverTimerCHA.setDutyCycle(dutyCycle);
88  break;
89  case Channel::B:
90  bsp::SinkDriverTimerCHB.setDutyCycle(dutyCycle);
91  break;
92  case Channel::C:
93  bsp::SinkDriverTimerCHC.setDutyCycle(dutyCycle);
94  break;
95  case Channel::D:
96  bsp::SinkDriverTimerCHD.setDutyCycle(dutyCycle);
97  break;
98  }
99 
100 
101  }
102 
109  static void setDeltaHighTime(Channel channel, u16 delta) {
110  Servo::s_delta[enumValue(channel)] = delta;
111  }
112 
113 
114  private:
115  static inline std::array s_delta = { 600, 600, 600, 600 }; // Delta value for each channel in ms
116  constexpr static inline u16 MidPosition = 1500; // 1.5ms high time pulse which represents 0° rotation (minimal is MidPosition - Delta, maximal is MidPosition + Delta)
117  constexpr static inline u16 TPWM = 20000; // Period of the pwm frequency in ms
118 
126  static bool checkMode(Channel channel) {
127  if (SinkDriver::s_mode[static_cast<u8>(channel)] != Mode::Servo) {
128 
129  switch(channel){
130  case Channel::A:
131  if (bsp::SinkDriverTimerA::getPwmFrequency() != 50) {
132  if(!bsp::SinkDriverTimerA::setPwmFrequency(50,40000)) return false;
133  }
134  bsp::SinkDriverTimerCHA.startPwm();
135  break;
136  case Channel::B:
137  if (bsp::SinkDriverTimerB::getPwmFrequency() != 50) {
138  if(!bsp::SinkDriverTimerB::setPwmFrequency(50,40000)) return false;
139  }
140  bsp::SinkDriverTimerCHB.startPwm();
141  break;
142  case Channel::C:
143  if (bsp::SinkDriverTimerC::getPwmFrequency() != 50) {
144  if(!bsp::SinkDriverTimerC::setPwmFrequency(50,40000)) return false;
145  }
146  bsp::SinkDriverTimerCHC.startPwm();
147  break;
148  case Channel::D:
149  if (bsp::SinkDriverTimerD::getPwmFrequency() != 50) {
150  if(!bsp::SinkDriverTimerD::setPwmFrequency(50,40000)) return false;
151  }
152  bsp::SinkDriverTimerCHD.startPwm();
153  break;
154  }
155 
156  SinkDriver::s_mode[enumValue(channel)] = Mode::Servo;
157  }
158  return true;
159  }
160  };
161 
167  class PWM{
168  public:
169  PWM() = delete;
170 
171  /*
172  * @brief Set the duty cycle
173  *
174  * @param channel Channel which should be changed
175  * @param dutyCycle Duty cycle
176  */
177  static void setDuty(Channel channel, float dutyCycle) {
178  if(SinkDriver::s_mode[enumValue(channel)] != Mode::PWM){
179  // Set to high active state and start the pwm for the used channel
180  switch(channel){
181  case Channel::A:
182  bsp::SinkDriverTimerCHA.startPwm();
183  bsp::SinkDriverTimerCHA.setPolarityHigh();
184  break;
185  case Channel::B:
186  bsp::SinkDriverTimerCHB.startPwm();
187  bsp::SinkDriverTimerCHB.setPolarityHigh();
188  break;
189  case Channel::C:
190  bsp::SinkDriverTimerCHC.startPwm();
191  bsp::SinkDriverTimerCHC.setPolarityHigh();
192  break;
193  case Channel::D:
194  bsp::SinkDriverTimerCHD.startPwm();
195  bsp::SinkDriverTimerCHD.setPolarityHigh();
196  break;
197  }
198  SinkDriver::s_mode[enumValue(channel)] = Mode::PWM;
199  }
200 
201  // Set the duty cycle for the used channel
202  switch(channel){
203  case Channel::A:
204  bsp::SinkDriverTimerCHA.setDutyCycle(dutyCycle);
205  break;
206  case Channel::B:
207  bsp::SinkDriverTimerCHB.setDutyCycle(dutyCycle);
208  break;
209  case Channel::C:
210  bsp::SinkDriverTimerCHC.setDutyCycle(dutyCycle);
211  break;
212  case Channel::D:
213  bsp::SinkDriverTimerCHD.setDutyCycle(dutyCycle);
214  break;
215  }
216 
217  }
218 
230  static bool setFrequency(u32 frequency, u16 resolution = 0) {
231  for(auto mode : s_mode){
232  if(mode == Mode::Servo) return false;
233  }
234  bsp::SinkDriverTimerA::setPwmFrequency(frequency, resolution);
235  bsp::SinkDriverTimerB::setPwmFrequency(frequency, resolution);
236  bsp::SinkDriverTimerC::setPwmFrequency(frequency, resolution);
237  bsp::SinkDriverTimerD::setPwmFrequency(frequency, resolution);
238 
239  return true;
240  }
241 
249  static u32 getFrequency(Channel channel) {
250  switch(channel){
251  case Channel::A:
252  return bsp::SinkDriverTimerA::getPwmFrequency();
253  break;
254  case Channel::B:
255  return bsp::SinkDriverTimerB::getPwmFrequency();
256  break;
257  case Channel::C:
258  return bsp::SinkDriverTimerC::getPwmFrequency();
259  break;
260  case Channel::D:
261  return bsp::SinkDriverTimerD::getPwmFrequency();
262  break;
263  default:
264  bsp::unreachable();
265  break;
266  }
267  }
268 
269  };
270 
271 
275  class Out{
276  public:
277  Out() = delete;
278 
285  static void set(Channel channel, bool state) {
286  if(SinkDriver::s_mode[enumValue(channel)] != Mode::GPIO) {
287 
288  // Enable the pwm and set the duty cycle to 0
289  switch(channel){
290  case Channel::A:
291  bsp::SinkDriverTimerCHA.startPwm();
292  bsp::SinkDriverTimerCHA.setDutyCycle(0.0F);
293  break;
294  case Channel::B:
295  bsp::SinkDriverTimerCHB.startPwm();
296  bsp::SinkDriverTimerCHB.setDutyCycle(0.0F);
297  break;
298  case Channel::C:
299  bsp::SinkDriverTimerCHC.startPwm();
300  bsp::SinkDriverTimerCHC.setDutyCycle(0.0F);
301  break;
302  case Channel::D:
303  bsp::SinkDriverTimerCHD.startPwm();
304  bsp::SinkDriverTimerCHD.setDutyCycle(0.0F);
305  break;
306  }
307 
308  SinkDriver::s_mode[enumValue(channel)] = Mode::GPIO;
309  }
310 
311  // Set the pwm polarity according to the state. Since the duty cycle is 0 this action will result in a always low
312  // or always high. A duty of 100% usually is not really 100%
313  switch(channel){
314  case Channel::A:
315  bsp::SinkDriverTimerCHA.setPolarityHigh(!state);
316  break;
317  case Channel::B:
318  bsp::SinkDriverTimerCHB.setPolarityHigh(!state);
319  break;
320  case Channel::C:
321  bsp::SinkDriverTimerCHC.setPolarityHigh(!state);
322  break;
323  case Channel::D:
324  bsp::SinkDriverTimerCHD.setPolarityHigh(!state);
325  break;
326  }
327 
328  }
329 
330  };
331 
332  private:
333 
337  enum class Mode {
338  Uninitialised = 0,
339  GPIO = 1,
340  PWM = 2,
341  Servo = 3,
342  };
343 
344  static inline std::array s_mode = { Mode::Uninitialised,Mode::Uninitialised,Mode::Uninitialised,Mode::Uninitialised };
345 
346 
347  };
348 
349 }
bsp::ygg::prph::SinkDriver::PWM::PWM
PWM()=delete
bsp::ygg::prph::SinkDriver::Channel
Channel
Timer Channels.
Definition: sink_driver.hpp:54
u16
uint16_t u16
Definition: types.h:37
bsp::ygg::prph::SinkDriver::init
static bool init()
Initialization function.
Definition: sink_driver.hpp:47
utils.hpp
Commonly used helper functions.
u8
uint8_t u8
Unsigned integer definitions.
Definition: types.h:36
bsp::ygg::prph::SinkDriver::Servo
Servo driver.
Definition: sink_driver.hpp:65
bsp::ygg::prph::SinkDriver::PWM::getFrequency
static u32 getFrequency(Channel channel)
Get the pwm frequency.
Definition: sink_driver.hpp:249
types.hpp
Commonly used type definitions and helper templates.
bsp::ygg::prph::SinkDriver::SinkDriver
SinkDriver()=delete
u32
uint32_t u32
Definition: types.h:38
bsp::enumValue
auto enumValue(T value)
Casts a scoped enum type into its underlying value.
Definition: utils.hpp:151
bsp::ygg::prph::SinkDriver::Channel::A
@ A
Timer channel A.
bsp::ygg::prph::SinkDriver::PWM::setDuty
static void setDuty(Channel channel, float dutyCycle)
Definition: sink_driver.hpp:177
bsp::ygg::prph::SinkDriver::Channel::C
@ C
Timer channel C.
bsp::ygg::prph::SinkDriver::Servo::setDeltaHighTime
static void setDeltaHighTime(Channel channel, u16 delta)
Function to set the high time of the pwm pulse.
Definition: sink_driver.hpp:109
bsp::ygg::prph::SinkDriver
Sink driver containing classes to use the driver as GPIO, as PWM Module or as Servo port.
Definition: sink_driver.hpp:38
bsp::math::clamp
constexpr T clamp(T value, T min, T max)
Clamps a input value between a min and max value.
Definition: math.hpp:66
bsp::ygg::prph::SinkDriver::Channel::B
@ B
Timer channel B.
attributes.hpp
Commonly used C++ and GNU attributes.
bsp::ygg::prph::SinkDriver::Out
GPIO driver.
Definition: sink_driver.hpp:275
bsp::ygg::prph::SinkDriver::Channel::D
@ D
Timer channel D.
bsp::ygg::prph::SinkDriver::Out::set
static void set(Channel channel, bool state)
set the sink driver pin state
Definition: sink_driver.hpp:285
bsp::ygg::prph::SinkDriver::Out::Out
Out()=delete
bsp::ygg::prph::SinkDriver::PWM::setFrequency
static bool setFrequency(u32 frequency, u16 resolution=0)
Set the pwm frequency and (optional) the maximal ticks within on cycle for all channels.
Definition: sink_driver.hpp:230
bsp::ygg::prph::SinkDriver::Servo::Servo
Servo()=delete
bsp::ygg::prph::SinkDriver::Servo::set
static void set(Channel channel, float percent)
Set the servo arm rotation in percent relative to its maximal value.
Definition: sink_driver.hpp:78
bsp::ygg::prph::SinkDriver::PWM
Pwm driver.
Definition: sink_driver.hpp:167
bsp::ygg::prph
Definition: color_sensor.hpp:32