Commit | Line | Data |
---|---|---|
11f8ba4e MM |
1 | #include "Pwm.h" |
2 | ||
29e809e0 | 3 | #include "utils.h" |
11f8ba4e MM |
4 | |
5 | #define PID_PWM_MAX 256 | |
6 | ||
93694d6b AW |
7 | // What ? |
8 | ||
11f8ba4e MM |
9 | Pwm::Pwm() |
10 | { | |
11 | _max = PID_PWM_MAX - 1; | |
12 | _pwm = -1; | |
bf9e8a8f JM |
13 | _sd_direction= false; |
14 | _sd_accumulator= 0; | |
11f8ba4e MM |
15 | } |
16 | ||
17 | void Pwm::pwm(int new_pwm) | |
18 | { | |
19 | _pwm = confine(new_pwm, 0, _max); | |
20 | } | |
21 | ||
22 | Pwm* Pwm::max_pwm(int new_max) | |
23 | { | |
6377620d | 24 | _max = confine(new_max, 0, PID_PWM_MAX - 1); |
a7f12bed | 25 | _pwm = confine( _pwm, 0, _max); |
11f8ba4e MM |
26 | return this; |
27 | } | |
28 | ||
29 | int Pwm::max_pwm() | |
30 | { | |
31 | return _max; | |
32 | } | |
33 | ||
34 | void Pwm::set(bool value) | |
35 | { | |
36 | _pwm = -1; | |
cb3460e9 | 37 | Pin::set(value); |
11f8ba4e MM |
38 | } |
39 | ||
40 | uint32_t Pwm::on_tick(uint32_t dummy) | |
41 | { | |
8cd3fa08 L |
42 | if ((_pwm < 0) || _pwm >= PID_PWM_MAX) { |
43 | return dummy; | |
44 | } | |
45 | else if (_pwm == 0) { | |
3773db1e | 46 | Pin::set(false); |
11f8ba4e | 47 | return dummy; |
3773db1e | 48 | } |
8cd3fa08 | 49 | else if (_pwm == PID_PWM_MAX - 1) { |
3773db1e L |
50 | Pin::set(true); |
51 | return dummy; | |
52 | } | |
11f8ba4e | 53 | |
b0c686e6 MM |
54 | /* |
55 | * Sigma-Delta PWM algorithm | |
56 | * | |
57 | * This Sigma-Delta implementation works by increasing _sd_accumulator by _pwm until we reach _half_ of max, | |
58 | * then decreasing by (max - target_pwm) until we hit zero | |
59 | * | |
60 | * While we're increasing, the output is 0 and while we're decreasing the output is 1 | |
61 | * | |
62 | * For example, with pwm=128 and a max of 256, we'll see the following pattern: | |
63 | * ACC ADD OUT | |
64 | * 0 128 1 // after the add, we hit 256/2 = 128 so we change direction | |
65 | * 128 -128 0 // after the add, we hit 0 so we change direction again | |
66 | * 0 128 1 | |
67 | * 128 -128 0 | |
68 | * as expected | |
69 | * | |
70 | * with a pwm value of 192 (75%) we'll see this: | |
71 | * ACC ADD OUT | |
72 | * 0 192 0 // after the add, we are beyond max/2 so we change direction | |
73 | * 192 -64 1 // haven't reached 0 yet | |
74 | * 128 -64 1 // haven't reached 0 yet | |
75 | * 64 -64 1 // after this add we reach 0, and change direction | |
76 | * 0 192 0 | |
77 | * 192 -64 1 | |
78 | * 128 -64 1 | |
79 | * 64 -64 1 | |
80 | * 0 192 0 | |
81 | * etcetera | |
82 | * | |
83 | * with a pwm value of 75 (about 29%) we'll see this pattern: | |
84 | * ACC ADD OUT | |
85 | * 0 75 0 | |
86 | * 75 75 0 | |
87 | * 150 -181 1 | |
88 | * -31 75 0 | |
89 | * 44 75 0 | |
90 | * 119 75 0 | |
91 | * 194 -181 1 | |
92 | * 13 -181 1 | |
93 | * -168 75 0 | |
94 | * -93 75 0 | |
95 | * -18 75 0 | |
96 | * 57 75 0 | |
97 | * 132 -181 1 | |
98 | * -49 75 0 | |
99 | * 26 75 0 | |
100 | * 101 75 0 | |
101 | * 176 -181 1 | |
102 | * -5 75 0 | |
103 | * 70 75 0 | |
104 | * 145 -181 1 | |
105 | * -36 75 0 | |
106 | * etcetera. This pattern has 6 '1's over a total of 21 lines which is on 28.57% of the time. If we let it run longer, it would get closer to the target as time went on | |
107 | */ | |
108 | ||
109 | // this line should never actually do anything, it's just a sanity check in case our accumulator gets corrupted somehow. | |
110 | // If we didn't check and the accumulator is corrupted, we could leave a heater on for quite a long time | |
111 | // the accumulator is kept within these limits by the normal operation of the Sigma-Delta algorithm | |
11f8ba4e MM |
112 | _sd_accumulator = confine(_sd_accumulator, -PID_PWM_MAX, PID_PWM_MAX << 1); |
113 | ||
b0c686e6 | 114 | // when _sd_direction == false, our output is 0 and our accumulator is increasing by _pwm |
11f8ba4e MM |
115 | if (_sd_direction == false) |
116 | { | |
b0c686e6 | 117 | // increment accumulator |
11f8ba4e | 118 | _sd_accumulator += _pwm; |
b0c686e6 | 119 | // if we've reached half of max, flip our direction |
11f8ba4e MM |
120 | if (_sd_accumulator >= (PID_PWM_MAX >> 1)) |
121 | _sd_direction = true; | |
122 | } | |
b0c686e6 | 123 | // when _sd_direction == true, our output is 1 and our accumulator is decreasing by (MAX - _pwm) |
11f8ba4e MM |
124 | else |
125 | { | |
b0c686e6 | 126 | // decrement accumulator |
11f8ba4e | 127 | _sd_accumulator -= (PID_PWM_MAX - _pwm); |
b0c686e6 | 128 | // if we've reached 0, flip our direction |
11f8ba4e MM |
129 | if (_sd_accumulator <= 0) |
130 | _sd_direction = false; | |
131 | } | |
cb3460e9 | 132 | Pin::set(_sd_direction); |
11f8ba4e MM |
133 | |
134 | return dummy; | |
135 | } |