Allow M18 to turn off selected motors
[clinton/Smoothieware.git] / src / libs / Pwm.cpp
1 #include "Pwm.h"
2
3 #include "utils.h"
4
5 #define PID_PWM_MAX 256
6
7 // What ?
8
9 Pwm::Pwm()
10 {
11 _max = PID_PWM_MAX - 1;
12 _pwm = -1;
13 _sd_direction= false;
14 _sd_accumulator= 0;
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 {
24 _max = confine(new_max, 0, PID_PWM_MAX - 1);
25 _pwm = confine( _pwm, 0, _max);
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;
37 Pin::set(value);
38 }
39
40 uint32_t Pwm::on_tick(uint32_t dummy)
41 {
42 if ((_pwm < 0) || _pwm >= PID_PWM_MAX) {
43 return dummy;
44 }
45 else if (_pwm == 0) {
46 Pin::set(false);
47 return dummy;
48 }
49 else if (_pwm == PID_PWM_MAX - 1) {
50 Pin::set(true);
51 return dummy;
52 }
53
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
112 _sd_accumulator = confine(_sd_accumulator, -PID_PWM_MAX, PID_PWM_MAX << 1);
113
114 // when _sd_direction == false, our output is 0 and our accumulator is increasing by _pwm
115 if (_sd_direction == false)
116 {
117 // increment accumulator
118 _sd_accumulator += _pwm;
119 // if we've reached half of max, flip our direction
120 if (_sd_accumulator >= (PID_PWM_MAX >> 1))
121 _sd_direction = true;
122 }
123 // when _sd_direction == true, our output is 1 and our accumulator is decreasing by (MAX - _pwm)
124 else
125 {
126 // decrement accumulator
127 _sd_accumulator -= (PID_PWM_MAX - _pwm);
128 // if we've reached 0, flip our direction
129 if (_sd_accumulator <= 0)
130 _sd_direction = false;
131 }
132 Pin::set(_sd_direction);
133
134 return dummy;
135 }