tmc2209_uart/registers/
mod.rs

1//! TMC2209 register definitions and traits.
2//!
3//! This module contains:
4//! - Register traits for type-safe access
5//! - The `Address` enum for all register addresses
6//! - Individual register structs with bitfield accessors
7
8mod gconf;
9mod gstat;
10mod ifcnt;
11mod slaveconf;
12mod otp_prog;
13mod otp_read;
14mod ioin;
15mod factory_conf;
16mod ihold_irun;
17mod tpowerdown;
18mod tstep;
19mod tpwmthrs;
20mod tcoolthrs;
21mod vactual;
22mod sgthrs;
23mod sg_result;
24mod coolconf;
25mod mscnt;
26mod mscuract;
27mod chopconf;
28mod drv_status;
29mod pwmconf;
30mod pwm_scale;
31mod pwm_auto;
32
33pub use gconf::Gconf;
34pub use gstat::Gstat;
35pub use ifcnt::Ifcnt;
36pub use slaveconf::Slaveconf;
37pub use otp_prog::OtpProg;
38pub use otp_read::OtpRead;
39pub use ioin::Ioin;
40pub use factory_conf::FactoryConf;
41pub use ihold_irun::IholdIrun;
42pub use tpowerdown::Tpowerdown;
43pub use tstep::Tstep;
44pub use tpwmthrs::Tpwmthrs;
45pub use tcoolthrs::Tcoolthrs;
46pub use vactual::Vactual;
47pub use sgthrs::Sgthrs;
48pub use sg_result::SgResult;
49pub use coolconf::Coolconf;
50pub use mscnt::Mscnt;
51pub use mscuract::Mscuract;
52pub use chopconf::Chopconf;
53pub use drv_status::DrvStatus;
54pub use pwmconf::Pwmconf;
55pub use pwm_scale::PwmScale;
56pub use pwm_auto::PwmAuto;
57
58/// Trait for all TMC2209 registers.
59pub trait Register: Sized + Copy + Clone + Default + Into<u32> + From<u32> {
60    /// The register address.
61    const ADDRESS: Address;
62
63    /// Get the register address.
64    fn address() -> Address {
65        Self::ADDRESS
66    }
67}
68
69/// Trait for registers that can be read.
70pub trait ReadableRegister: Register {}
71
72/// Trait for registers that can be written.
73pub trait WritableRegister: Register {}
74
75/// TMC2209 register addresses.
76///
77/// All registers in the TMC2209 and their 7-bit addresses.
78#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
79#[cfg_attr(feature = "defmt", derive(defmt::Format))]
80#[repr(u8)]
81pub enum Address {
82    /// Global configuration (0x00) - RW
83    Gconf = 0x00,
84    /// Global status flags (0x01) - R+WC
85    Gstat = 0x01,
86    /// Interface transmission counter (0x02) - R
87    Ifcnt = 0x02,
88    /// UART slave configuration (0x03) - W
89    Slaveconf = 0x03,
90    /// OTP programming (0x04) - W
91    OtpProg = 0x04,
92    /// OTP memory read (0x05) - R
93    OtpRead = 0x05,
94    /// Input pin states (0x06) - R
95    Ioin = 0x06,
96    /// Factory configuration (0x07) - RW
97    FactoryConf = 0x07,
98    /// Hold/run current (0x10) - W
99    IholdIrun = 0x10,
100    /// Power down delay (0x11) - W
101    Tpowerdown = 0x11,
102    /// Measured step time (0x12) - R
103    Tstep = 0x12,
104    /// StealthChop threshold (0x13) - W
105    Tpwmthrs = 0x13,
106    /// CoolStep threshold (0x14) - W
107    Tcoolthrs = 0x14,
108    /// UART velocity control (0x22) - W
109    Vactual = 0x22,
110    /// StallGuard threshold (0x40) - W
111    Sgthrs = 0x40,
112    /// StallGuard result (0x41) - R
113    SgResult = 0x41,
114    /// CoolStep configuration (0x42) - W
115    Coolconf = 0x42,
116    /// Microstep counter (0x6A) - R
117    Mscnt = 0x6A,
118    /// Microstep current (0x6B) - R
119    Mscuract = 0x6B,
120    /// Chopper configuration (0x6C) - RW
121    Chopconf = 0x6C,
122    /// Driver status (0x6F) - R
123    DrvStatus = 0x6F,
124    /// StealthChop PWM configuration (0x70) - RW
125    Pwmconf = 0x70,
126    /// PWM scaling result (0x71) - R
127    PwmScale = 0x71,
128    /// Automatic PWM values (0x72) - R
129    PwmAuto = 0x72,
130}
131
132impl Address {
133    /// Convert a u8 to an Address if it's a known register.
134    pub fn from_u8(value: u8) -> Option<Self> {
135        match value {
136            0x00 => Some(Address::Gconf),
137            0x01 => Some(Address::Gstat),
138            0x02 => Some(Address::Ifcnt),
139            0x03 => Some(Address::Slaveconf),
140            0x04 => Some(Address::OtpProg),
141            0x05 => Some(Address::OtpRead),
142            0x06 => Some(Address::Ioin),
143            0x07 => Some(Address::FactoryConf),
144            0x10 => Some(Address::IholdIrun),
145            0x11 => Some(Address::Tpowerdown),
146            0x12 => Some(Address::Tstep),
147            0x13 => Some(Address::Tpwmthrs),
148            0x14 => Some(Address::Tcoolthrs),
149            0x22 => Some(Address::Vactual),
150            0x40 => Some(Address::Sgthrs),
151            0x41 => Some(Address::SgResult),
152            0x42 => Some(Address::Coolconf),
153            0x6A => Some(Address::Mscnt),
154            0x6B => Some(Address::Mscuract),
155            0x6C => Some(Address::Chopconf),
156            0x6F => Some(Address::DrvStatus),
157            0x70 => Some(Address::Pwmconf),
158            0x71 => Some(Address::PwmScale),
159            0x72 => Some(Address::PwmAuto),
160            _ => None,
161        }
162    }
163
164    /// Check if this register is readable.
165    pub fn is_readable(self) -> bool {
166        matches!(
167            self,
168            Address::Gconf
169                | Address::Gstat
170                | Address::Ifcnt
171                | Address::OtpRead
172                | Address::Ioin
173                | Address::FactoryConf
174                | Address::Tstep
175                | Address::SgResult
176                | Address::Mscnt
177                | Address::Mscuract
178                | Address::Chopconf
179                | Address::DrvStatus
180                | Address::Pwmconf
181                | Address::PwmScale
182                | Address::PwmAuto
183        )
184    }
185
186    /// Check if this register is writable.
187    pub fn is_writable(self) -> bool {
188        matches!(
189            self,
190            Address::Gconf
191                | Address::Gstat
192                | Address::Slaveconf
193                | Address::OtpProg
194                | Address::FactoryConf
195                | Address::IholdIrun
196                | Address::Tpowerdown
197                | Address::Tpwmthrs
198                | Address::Tcoolthrs
199                | Address::Vactual
200                | Address::Sgthrs
201                | Address::Coolconf
202                | Address::Chopconf
203                | Address::Pwmconf
204        )
205    }
206
207    /// Get the raw address value.
208    pub fn as_u8(self) -> u8 {
209        self as u8
210    }
211}
212
213impl From<Address> for u8 {
214    fn from(addr: Address) -> u8 {
215        addr as u8
216    }
217}
218
219/// Microstep resolution setting.
220///
221/// Number of microsteps per full step.
222#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
223#[cfg_attr(feature = "defmt", derive(defmt::Format))]
224#[repr(u8)]
225pub enum MicrostepResolution {
226    /// 256 microsteps per full step (native resolution)
227    #[default]
228    M256 = 0,
229    /// 128 microsteps per full step
230    M128 = 1,
231    /// 64 microsteps per full step
232    M64 = 2,
233    /// 32 microsteps per full step
234    M32 = 3,
235    /// 16 microsteps per full step
236    M16 = 4,
237    /// 8 microsteps per full step
238    M8 = 5,
239    /// 4 microsteps per full step
240    M4 = 6,
241    /// 2 microsteps per full step (half step)
242    M2 = 7,
243    /// Full step
244    M1 = 8,
245}
246
247impl MicrostepResolution {
248    /// Convert from MRES register value.
249    pub fn from_mres(mres: u8) -> Self {
250        match mres {
251            0 => Self::M256,
252            1 => Self::M128,
253            2 => Self::M64,
254            3 => Self::M32,
255            4 => Self::M16,
256            5 => Self::M8,
257            6 => Self::M4,
258            7 => Self::M2,
259            8 => Self::M1,
260            _ => Self::M256,
261        }
262    }
263
264    /// Convert to MRES register value.
265    pub fn to_mres(self) -> u8 {
266        self as u8
267    }
268
269    /// Get the number of microsteps.
270    pub fn microsteps(self) -> u16 {
271        match self {
272            Self::M256 => 256,
273            Self::M128 => 128,
274            Self::M64 => 64,
275            Self::M32 => 32,
276            Self::M16 => 16,
277            Self::M8 => 8,
278            Self::M4 => 4,
279            Self::M2 => 2,
280            Self::M1 => 1,
281        }
282    }
283}
284
285/// Standstill mode when motor current is zero (IHOLD=0).
286#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
287#[cfg_attr(feature = "defmt", derive(defmt::Format))]
288#[repr(u8)]
289pub enum StandstillMode {
290    /// Normal operation
291    #[default]
292    Normal = 0,
293    /// Freewheeling
294    Freewheeling = 1,
295    /// Coil shorted using LS drivers (strong braking)
296    StrongBraking = 2,
297    /// Coil shorted using HS drivers (braking)
298    Braking = 3,
299}
300
301impl StandstillMode {
302    /// Convert from register value.
303    pub fn from_bits(value: u8) -> Self {
304        match value & 0x03 {
305            0 => Self::Normal,
306            1 => Self::Freewheeling,
307            2 => Self::StrongBraking,
308            3 => Self::Braking,
309            _ => Self::Normal,
310        }
311    }
312
313    /// Convert to register value.
314    pub fn to_bits(self) -> u8 {
315        self as u8
316    }
317}