1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
//! PWMCONF - StealthChop PWM configuration register (0x70)
use super::{Address, ReadableRegister, Register, StandstillMode, WritableRegister};
/// StealthChop PWM configuration register.
///
/// Controls StealthChop PWM operation for silent motor operation.
/// StealthChop uses voltage PWM instead of current chopping.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Pwmconf(u32);
impl Pwmconf {
/// Default value with StealthChop enabled and auto-tuning.
/// PWM_OFS=36, PWM_GRAD=14, pwm_freq=1, pwm_autoscale=1, pwm_autograd=1
pub const DEFAULT: u32 = 0xC10D0024;
/// Create with default values.
pub fn new() -> Self {
Self(Self::DEFAULT)
}
/// Get PWM_OFS (0-255).
///
/// User-defined PWM amplitude offset (0-255).
/// When pwm_autoscale=1: Used as base for automatic scaling.
/// When pwm_autoscale=0: Used directly as PWM amplitude.
pub fn pwm_ofs(&self) -> u8 {
(self.0 & 0xFF) as u8
}
/// Set PWM_OFS (0-255).
pub fn set_pwm_ofs(&mut self, value: u8) -> &mut Self {
self.0 = (self.0 & !0xFF) | (value as u32);
self
}
/// Get PWM_GRAD (0-255).
///
/// User-defined PWM amplitude gradient.
/// Velocity-dependent gradient for PWM amplitude.
/// When pwm_autoscale=1: Scaled automatically.
pub fn pwm_grad(&self) -> u8 {
((self.0 >> 8) & 0xFF) as u8
}
/// Set PWM_GRAD (0-255).
pub fn set_pwm_grad(&mut self, value: u8) -> &mut Self {
self.0 = (self.0 & !(0xFF << 8)) | ((value as u32) << 8);
self
}
/// Get PWM_FREQ (0-3).
///
/// PWM frequency selection:
/// - 0: fPWM = 2/1024 fCLK
/// - 1: fPWM = 2/683 fCLK (recommended)
/// - 2: fPWM = 2/512 fCLK
/// - 3: fPWM = 2/410 fCLK
pub fn pwm_freq(&self) -> u8 {
((self.0 >> 16) & 0x03) as u8
}
/// Set PWM_FREQ (0-3).
pub fn set_pwm_freq(&mut self, value: u8) -> &mut Self {
self.0 = (self.0 & !(0x03 << 16)) | (((value as u32) & 0x03) << 16);
self
}
/// Get PWM_AUTOSCALE.
///
/// Enable automatic current scaling:
/// - true: Automatic tuning (recommended)
/// - false: Use PWM_GRAD and PWM_OFS directly
pub fn pwm_autoscale(&self) -> bool {
(self.0 >> 18) & 1 != 0
}
/// Set PWM_AUTOSCALE.
pub fn set_pwm_autoscale(&mut self, value: bool) -> &mut Self {
if value {
self.0 |= 1 << 18;
} else {
self.0 &= !(1 << 18);
}
self
}
/// Get PWM_AUTOGRAD.
///
/// Enable automatic gradient tuning:
/// - true: Automatic gradient adaptation (recommended)
/// - false: Use PWM_GRAD directly
pub fn pwm_autograd(&self) -> bool {
(self.0 >> 19) & 1 != 0
}
/// Set PWM_AUTOGRAD.
pub fn set_pwm_autograd(&mut self, value: bool) -> &mut Self {
if value {
self.0 |= 1 << 19;
} else {
self.0 &= !(1 << 19);
}
self
}
/// Get FREEWHEEL (0-3).
///
/// Standstill mode when motor current is zero:
/// - 0: Normal operation
/// - 1: Freewheeling
/// - 2: Coil shorted using LS drivers (strong braking)
/// - 3: Coil shorted using HS drivers (braking)
pub fn freewheel(&self) -> u8 {
((self.0 >> 20) & 0x03) as u8
}
/// Set FREEWHEEL (0-3).
pub fn set_freewheel(&mut self, value: u8) -> &mut Self {
self.0 = (self.0 & !(0x03 << 20)) | (((value as u32) & 0x03) << 20);
self
}
/// Get the freewheel mode as enum.
pub fn standstill_mode(&self) -> StandstillMode {
StandstillMode::from_bits(self.freewheel())
}
/// Set the freewheel mode from enum.
pub fn set_standstill_mode(&mut self, mode: StandstillMode) -> &mut Self {
self.set_freewheel(mode.to_bits())
}
/// Get PWM_REG (0-15).
///
/// Maximum PWM amplitude change per half wave:
/// - 1-15: Limit PWM amplitude change
/// - 0: No limit (not recommended)
pub fn pwm_reg(&self) -> u8 {
((self.0 >> 24) & 0x0F) as u8
}
/// Set PWM_REG (0-15).
pub fn set_pwm_reg(&mut self, value: u8) -> &mut Self {
self.0 = (self.0 & !(0x0F << 24)) | (((value as u32) & 0x0F) << 24);
self
}
/// Get PWM_LIM (0-15).
///
/// PWM automatic scale amplitude limit when switching on.
/// Limits starting current during StealthChop operation.
pub fn pwm_lim(&self) -> u8 {
((self.0 >> 28) & 0x0F) as u8
}
/// Set PWM_LIM (0-15).
pub fn set_pwm_lim(&mut self, value: u8) -> &mut Self {
self.0 = (self.0 & !(0x0F << 28)) | (((value as u32) & 0x0F) << 28);
self
}
/// Get the raw register value.
pub fn raw(&self) -> u32 {
self.0
}
/// Create from raw value.
pub fn from_raw(value: u32) -> Self {
Self(value)
}
}
impl Default for Pwmconf {
fn default() -> Self {
Self::new()
}
}
impl Register for Pwmconf {
const ADDRESS: Address = Address::Pwmconf;
}
impl ReadableRegister for Pwmconf {}
impl WritableRegister for Pwmconf {}
impl From<u32> for Pwmconf {
fn from(value: u32) -> Self {
Self(value)
}
}
impl From<Pwmconf> for u32 {
fn from(reg: Pwmconf) -> u32 {
reg.0
}
}