tmc2209_uart/
driver.rs

1//! TMC2209 high-level driver.
2//!
3//! This module provides the main `Tmc2209` struct for communicating with
4//! TMC2209 stepper motor drivers via UART.
5
6use crate::datagram::{ReadRequest, ReadResponse, ResponseReader, WriteRequest};
7use crate::error::Error;
8use crate::registers::{
9    Chopconf, Coolconf, DrvStatus, Gconf, Gstat, Ifcnt, IholdIrun, Ioin, MicrostepResolution,
10    Mscnt, Pwmconf, ReadableRegister, SgResult, Sgthrs, Tcoolthrs, Tpwmthrs, Tstep, Vactual,
11    WritableRegister,
12};
13
14/// TMC2209 driver over UART.
15///
16/// This struct provides methods for reading and writing TMC2209 registers
17/// via a UART interface. Both blocking and async versions are available
18/// depending on enabled features.
19///
20/// # Type Parameters
21///
22/// * `U` - UART peripheral type implementing `embedded_io::Read + embedded_io::Write`
23///         or `embedded_io_async::Read + embedded_io_async::Write`
24///
25/// # Example (blocking)
26///
27/// ```ignore
28/// use tmc2209::{Tmc2209, registers::IholdIrun};
29///
30/// let mut driver = Tmc2209::new(uart, 0);
31///
32/// // Read a register
33/// let status = driver.read_register::<DrvStatus>()?;
34///
35/// // Write a register
36/// let mut irun = IholdIrun::new();
37/// irun.set_irun(16).set_ihold(8);
38/// driver.write_register(&irun)?;
39/// ```
40pub struct Tmc2209<U> {
41    /// UART peripheral.
42    uart: U,
43    /// Slave address (0-3).
44    slave_addr: u8,
45    /// Response reader for parsing incoming data.
46    reader: ResponseReader,
47}
48
49impl<U> Tmc2209<U> {
50    /// Create a new TMC2209 driver.
51    ///
52    /// # Arguments
53    ///
54    /// * `uart` - UART peripheral for communication
55    /// * `slave_addr` - Slave address (0-3)
56    ///
57    /// # Panics
58    ///
59    /// Panics if `slave_addr` is greater than 3.
60    pub fn new(uart: U, slave_addr: u8) -> Self {
61        assert!(slave_addr <= 3, "Slave address must be 0-3");
62        Self {
63            uart,
64            slave_addr,
65            reader: ResponseReader::new(),
66        }
67    }
68
69    /// Get the slave address.
70    pub fn slave_addr(&self) -> u8 {
71        self.slave_addr
72    }
73
74    /// Set the slave address.
75    ///
76    /// # Panics
77    ///
78    /// Panics if `addr` is greater than 3.
79    pub fn set_slave_addr(&mut self, addr: u8) {
80        assert!(addr <= 3, "Slave address must be 0-3");
81        self.slave_addr = addr;
82    }
83
84    /// Get a reference to the UART peripheral.
85    pub fn uart(&self) -> &U {
86        &self.uart
87    }
88
89    /// Get a mutable reference to the UART peripheral.
90    pub fn uart_mut(&mut self) -> &mut U {
91        &mut self.uart
92    }
93
94    /// Release the UART peripheral.
95    pub fn release(self) -> U {
96        self.uart
97    }
98
99    /// Create a read request for a register.
100    fn read_request<R: ReadableRegister>(&self) -> ReadRequest {
101        ReadRequest::new(self.slave_addr, R::ADDRESS)
102    }
103
104    /// Create a write request for a register.
105    fn write_request<R: WritableRegister>(&self, reg: &R) -> WriteRequest {
106        WriteRequest::new(self.slave_addr, R::ADDRESS, (*reg).into())
107    }
108}
109
110// ============================================================================
111// Blocking API
112// ============================================================================
113
114#[cfg(feature = "blocking")]
115impl<U, E> Tmc2209<U>
116where
117    U: embedded_io::Read<Error = E> + embedded_io::Write<Error = E>,
118{
119    /// Read a register (blocking).
120    ///
121    /// Sends a read request and waits for the response.
122    ///
123    /// # Type Parameters
124    ///
125    /// * `R` - Register type to read (must implement `ReadableRegister`)
126    ///
127    /// # Returns
128    ///
129    /// The register value, or an error if communication fails.
130    pub fn read_register<R: ReadableRegister>(&mut self) -> Result<R, Error<E>> {
131        let request = self.read_request::<R>();
132
133        // Send the read request
134        self.uart
135            .write_all(request.as_bytes())
136            .map_err(Error::Uart)?;
137        self.uart.flush().map_err(Error::Uart)?;
138
139        // Read the response
140        // TMC2209 echoes back the request, then sends the response
141        // We need to skip the echo (4 bytes) and read the response (8 bytes)
142        let mut echo_buf = [0u8; 4];
143        self.read_exact(&mut echo_buf)?;
144
145        let response = self.read_response()?;
146
147        // Verify the register address matches
148        let expected_addr = R::ADDRESS as u8;
149        if response.reg_addr() != expected_addr {
150            return Err(Error::AddressMismatch {
151                expected: expected_addr,
152                actual: response.reg_addr(),
153            });
154        }
155
156        Ok(R::from(response.data()))
157    }
158
159    /// Write a register (blocking).
160    ///
161    /// Sends a write request to update a register value.
162    ///
163    /// # Arguments
164    ///
165    /// * `reg` - Register value to write
166    ///
167    /// # Returns
168    ///
169    /// `Ok(())` on success, or an error if communication fails.
170    pub fn write_register<R: WritableRegister>(&mut self, reg: &R) -> Result<(), Error<E>> {
171        let request = self.write_request(reg);
172
173        // Send the write request
174        self.uart
175            .write_all(request.as_bytes())
176            .map_err(Error::Uart)?;
177        self.uart.flush().map_err(Error::Uart)?;
178
179        // Read back the echo (8 bytes) - TMC2209 echoes write requests
180        let mut echo_buf = [0u8; 8];
181        self.read_exact(&mut echo_buf)?;
182
183        Ok(())
184    }
185
186    /// Read a register by raw address (blocking).
187    ///
188    /// Use this when you need to read a register by its raw address value.
189    pub fn read_raw(&mut self, reg_addr: u8) -> Result<u32, Error<E>> {
190        let request = ReadRequest::from_raw_addr(self.slave_addr, reg_addr);
191
192        self.uart
193            .write_all(request.as_bytes())
194            .map_err(Error::Uart)?;
195        self.uart.flush().map_err(Error::Uart)?;
196
197        // Skip echo
198        let mut echo_buf = [0u8; 4];
199        self.read_exact(&mut echo_buf)?;
200
201        let response = self.read_response()?;
202        Ok(response.data())
203    }
204
205    /// Write a register by raw address (blocking).
206    ///
207    /// Use this when you need to write a register by its raw address value.
208    pub fn write_raw(&mut self, reg_addr: u8, data: u32) -> Result<(), Error<E>> {
209        let request = WriteRequest::from_raw(self.slave_addr, reg_addr, data);
210
211        self.uart
212            .write_all(request.as_bytes())
213            .map_err(Error::Uart)?;
214        self.uart.flush().map_err(Error::Uart)?;
215
216        // Read back echo
217        let mut echo_buf = [0u8; 8];
218        self.read_exact(&mut echo_buf)?;
219
220        Ok(())
221    }
222
223    /// Helper to read exact number of bytes.
224    fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Error<E>> {
225        let mut total_read = 0;
226        while total_read < buf.len() {
227            let n = self.uart.read(&mut buf[total_read..]).map_err(Error::Uart)?;
228            if n == 0 {
229                return Err(Error::NoResponse);
230            }
231            total_read += n;
232        }
233        Ok(())
234    }
235
236    /// Helper to read a complete response.
237    fn read_response(&mut self) -> Result<ReadResponse, Error<E>> {
238        self.reader.reset();
239        let mut buf = [0u8; 8];
240        self.read_exact(&mut buf)?;
241
242        let (_, result) = self.reader.feed(&buf);
243        result.ok_or(Error::NoResponse)?
244    }
245
246    // ========================================================================
247    // Convenience methods (blocking)
248    // ========================================================================
249
250    /// Check if the driver is communicating properly.
251    ///
252    /// Reads IFCNT and verifies we get a valid response.
253    pub fn is_connected(&mut self) -> bool {
254        self.read_register::<Ifcnt>().is_ok()
255    }
256
257    /// Get the interface transmission counter.
258    ///
259    /// This counter increments on each successful UART write.
260    /// Useful for verifying communication.
261    pub fn ifcnt(&mut self) -> Result<u8, Error<E>> {
262        let reg = self.read_register::<Ifcnt>()?;
263        Ok(reg.count())
264    }
265
266    /// Get the global status flags.
267    pub fn gstat(&mut self) -> Result<Gstat, Error<E>> {
268        self.read_register()
269    }
270
271    /// Clear the global status flags (write to clear).
272    pub fn clear_gstat(&mut self) -> Result<(), Error<E>> {
273        // Writing 1s clears the flags
274        let gstat = Gstat::from(0x07);
275        self.write_register(&gstat)
276    }
277
278    /// Get the input pin states.
279    pub fn ioin(&mut self) -> Result<Ioin, Error<E>> {
280        self.read_register()
281    }
282
283    /// Get the driver status.
284    pub fn drv_status(&mut self) -> Result<DrvStatus, Error<E>> {
285        self.read_register()
286    }
287
288    /// Get the current step time (inverse of velocity).
289    pub fn tstep(&mut self) -> Result<u32, Error<E>> {
290        let reg = self.read_register::<Tstep>()?;
291        Ok(reg.tstep())
292    }
293
294    /// Get the StallGuard result.
295    pub fn sg_result(&mut self) -> Result<u16, Error<E>> {
296        let reg = self.read_register::<SgResult>()?;
297        Ok(reg.result())
298    }
299
300    /// Get the microstep counter position (0-1023).
301    pub fn mscnt(&mut self) -> Result<u16, Error<E>> {
302        let reg = self.read_register::<Mscnt>()?;
303        Ok(reg.count())
304    }
305
306    /// Set the motor currents.
307    ///
308    /// # Arguments
309    ///
310    /// * `run_current` - Run current (0-31)
311    /// * `hold_current` - Hold current (0-31)
312    /// * `hold_delay` - Delay before reducing to hold current (0-15)
313    pub fn set_current(
314        &mut self,
315        run_current: u8,
316        hold_current: u8,
317        hold_delay: u8,
318    ) -> Result<(), Error<E>> {
319        let mut reg = IholdIrun::new();
320        reg.set_irun(run_current)
321            .set_ihold(hold_current)
322            .set_iholddelay(hold_delay);
323        self.write_register(&reg)
324    }
325
326    /// Set the microstep resolution.
327    pub fn set_microsteps(&mut self, resolution: MicrostepResolution) -> Result<(), Error<E>> {
328        let mut chopconf = self.read_register::<Chopconf>()?;
329        chopconf.set_microstep_resolution(resolution);
330        self.write_register(&chopconf)
331    }
332
333    /// Enable or disable the driver.
334    ///
335    /// When TOFF=0, the driver is disabled.
336    pub fn set_enabled(&mut self, enabled: bool) -> Result<(), Error<E>> {
337        let mut chopconf = self.read_register::<Chopconf>()?;
338        if enabled {
339            // Use default TOFF=3 if currently disabled
340            if chopconf.toff() == 0 {
341                chopconf.set_toff(3);
342            }
343        } else {
344            chopconf.set_toff(0);
345        }
346        self.write_register(&chopconf)
347    }
348
349    /// Set velocity for internal motion controller (VACTUAL).
350    ///
351    /// # Arguments
352    ///
353    /// * `velocity` - Velocity value (signed, 23-bit range)
354    ///   - Positive: Forward motion
355    ///   - Negative: Reverse motion
356    ///   - 0: Stop
357    pub fn set_velocity(&mut self, velocity: i32) -> Result<(), Error<E>> {
358        let mut reg = Vactual::new();
359        reg.set_velocity(velocity);
360        self.write_register(&reg)
361    }
362
363    /// Stop the motor (set VACTUAL to 0).
364    pub fn stop(&mut self) -> Result<(), Error<E>> {
365        self.set_velocity(0)
366    }
367
368    /// Set the StallGuard threshold.
369    ///
370    /// Higher values make stall detection more sensitive.
371    pub fn set_stall_threshold(&mut self, threshold: u8) -> Result<(), Error<E>> {
372        let mut reg = Sgthrs::new();
373        reg.set_threshold(threshold);
374        self.write_register(&reg)
375    }
376
377    /// Enable StealthChop mode.
378    pub fn enable_stealthchop(&mut self) -> Result<(), Error<E>> {
379        let mut gconf = self.read_register::<Gconf>()?;
380        gconf.set_en_spreadcycle(false);
381        self.write_register(&gconf)
382    }
383
384    /// Enable SpreadCycle mode.
385    pub fn enable_spreadcycle(&mut self) -> Result<(), Error<E>> {
386        let mut gconf = self.read_register::<Gconf>()?;
387        gconf.set_en_spreadcycle(true);
388        self.write_register(&gconf)
389    }
390
391    /// Check if motor is in standstill.
392    pub fn is_standstill(&mut self) -> Result<bool, Error<E>> {
393        let status = self.drv_status()?;
394        Ok(status.stst())
395    }
396
397    /// Check if overtemperature warning is active.
398    pub fn is_overtemperature_warning(&mut self) -> Result<bool, Error<E>> {
399        let status = self.drv_status()?;
400        Ok(status.otpw())
401    }
402
403    /// Check if overtemperature shutdown is active.
404    pub fn is_overtemperature_shutdown(&mut self) -> Result<bool, Error<E>> {
405        let status = self.drv_status()?;
406        Ok(status.ot())
407    }
408
409    // ========================================================================
410    // CoolStep and StallGuard methods (blocking)
411    // ========================================================================
412
413    /// Enable CoolStep adaptive current control.
414    ///
415    /// CoolStep automatically reduces motor current when load is low,
416    /// saving power and reducing heat.
417    ///
418    /// # Arguments
419    ///
420    /// * `semin` - Minimum StallGuard value for current increase (1-15, 0 disables)
421    /// * `semax` - Hysteresis for current decrease (0-15)
422    ///
423    /// # Example
424    ///
425    /// ```ignore
426    /// // Enable CoolStep with moderate sensitivity
427    /// driver.enable_coolstep(4, 2)?;
428    /// ```
429    pub fn enable_coolstep(&mut self, semin: u8, semax: u8) -> Result<(), Error<E>> {
430        let mut coolconf = Coolconf::new();
431        coolconf
432            .set_semin(semin.min(15))
433            .set_semax(semax.min(15))
434            .set_seup(0)  // +1 current step
435            .set_sedn(0); // -32 current step
436        self.write_register(&coolconf)
437    }
438
439    /// Disable CoolStep.
440    pub fn disable_coolstep(&mut self) -> Result<(), Error<E>> {
441        let coolconf = Coolconf::new(); // semin=0 disables CoolStep
442        self.write_register(&coolconf)
443    }
444
445    /// Set the CoolStep velocity threshold (TCOOLTHRS).
446    ///
447    /// CoolStep and StallGuard are only active when TSTEP < TCOOLTHRS.
448    /// Below this velocity, CoolStep and stall detection are disabled.
449    ///
450    /// # Arguments
451    ///
452    /// * `threshold` - TSTEP threshold value (0 = disabled, 0xFFFFF = always active)
453    pub fn set_coolstep_threshold(&mut self, threshold: u32) -> Result<(), Error<E>> {
454        let mut tcoolthrs = Tcoolthrs::new();
455        tcoolthrs.set_threshold(threshold);
456        self.write_register(&tcoolthrs)
457    }
458
459    /// Set the StealthChop velocity threshold (TPWMTHRS).
460    ///
461    /// Above this velocity, the driver switches from StealthChop to SpreadCycle.
462    ///
463    /// # Arguments
464    ///
465    /// * `threshold` - TSTEP threshold value (0 = only SpreadCycle, 0xFFFFF = only StealthChop)
466    pub fn set_stealthchop_threshold(&mut self, threshold: u32) -> Result<(), Error<E>> {
467        let mut tpwmthrs = Tpwmthrs::new();
468        tpwmthrs.set_threshold(threshold);
469        self.write_register(&tpwmthrs)
470    }
471
472    // ========================================================================
473    // Sensorless homing methods (blocking)
474    // ========================================================================
475
476    /// Configure stall detection for sensorless homing.
477    ///
478    /// This sets up the StallGuard feature to detect when the motor
479    /// hits an endstop or obstacle.
480    ///
481    /// # Arguments
482    ///
483    /// * `threshold` - StallGuard threshold (0-255, higher = more sensitive)
484    ///
485    /// # Note
486    ///
487    /// For sensorless homing to work properly:
488    /// - Use SpreadCycle mode (not StealthChop)
489    /// - Set appropriate TCOOLTHRS (stall detection only works above this velocity)
490    /// - Move at a consistent, moderate speed
491    ///
492    /// # Example
493    ///
494    /// ```ignore
495    /// // Configure for sensorless homing
496    /// driver.configure_stall_detection(50)?;
497    /// driver.enable_spreadcycle()?;
498    /// driver.set_coolstep_threshold(0)?; // Enable at all velocities
499    ///
500    /// // Move towards endstop
501    /// driver.set_velocity(-1000)?;
502    ///
503    /// // Poll for stall
504    /// loop {
505    ///     if driver.is_stalled()? {
506    ///         driver.stop()?;
507    ///         break;
508    ///     }
509    /// }
510    /// ```
511    pub fn configure_stall_detection(&mut self, threshold: u8) -> Result<(), Error<E>> {
512        // Set StallGuard threshold
513        self.set_stall_threshold(threshold)?;
514
515        // Enable DIAG output for stall indication
516        let mut gconf = self.read_register::<Gconf>()?;
517        gconf.set_diag0_stall(true);
518        self.write_register(&gconf)?;
519
520        Ok(())
521    }
522
523    /// Check if the motor is currently stalled.
524    ///
525    /// Returns true if the StallGuard result is below the threshold.
526    /// Only valid when motor is moving and TSTEP < TCOOLTHRS.
527    pub fn is_stalled(&mut self) -> Result<bool, Error<E>> {
528        let sg_result = self.sg_result()?;
529        // SG_RESULT of 0 indicates stall
530        Ok(sg_result == 0)
531    }
532
533    /// Get the current load indicator from StallGuard.
534    ///
535    /// Returns a value from 0 (high load/stall) to 510 (no load).
536    /// Useful for load monitoring and stall detection tuning.
537    pub fn load_indicator(&mut self) -> Result<u16, Error<E>> {
538        self.sg_result()
539    }
540
541    // ========================================================================
542    // PWM and StealthChop configuration (blocking)
543    // ========================================================================
544
545    /// Configure StealthChop PWM settings.
546    ///
547    /// # Arguments
548    ///
549    /// * `pwm_ofs` - PWM amplitude offset (0-255)
550    /// * `pwm_grad` - PWM amplitude gradient (0-255)
551    /// * `autoscale` - Enable automatic current scaling
552    /// * `autograd` - Enable automatic gradient adaptation
553    pub fn configure_stealthchop(
554        &mut self,
555        pwm_ofs: u8,
556        pwm_grad: u8,
557        autoscale: bool,
558        autograd: bool,
559    ) -> Result<(), Error<E>> {
560        let mut pwmconf = self.read_register::<Pwmconf>()?;
561        pwmconf
562            .set_pwm_ofs(pwm_ofs)
563            .set_pwm_grad(pwm_grad)
564            .set_pwm_autoscale(autoscale)
565            .set_pwm_autograd(autograd);
566        self.write_register(&pwmconf)
567    }
568
569    /// Set VSENSE for current sense resistor scaling.
570    ///
571    /// # Arguments
572    ///
573    /// * `high_sensitivity` - true for high sensitivity (low current range),
574    ///                        false for low sensitivity (high current range)
575    pub fn set_vsense(&mut self, high_sensitivity: bool) -> Result<(), Error<E>> {
576        let mut chopconf = self.read_register::<Chopconf>()?;
577        chopconf.set_vsense(high_sensitivity);
578        self.write_register(&chopconf)
579    }
580
581    /// Configure chopper settings for optimal performance.
582    ///
583    /// # Arguments
584    ///
585    /// * `toff` - Off-time (1-15, 0 disables driver)
586    /// * `hstrt` - Hysteresis start (0-7)
587    /// * `hend` - Hysteresis end (0-15)
588    /// * `tbl` - Comparator blank time (0-3)
589    pub fn configure_chopper(
590        &mut self,
591        toff: u8,
592        hstrt: u8,
593        hend: u8,
594        tbl: u8,
595    ) -> Result<(), Error<E>> {
596        let mut chopconf = self.read_register::<Chopconf>()?;
597        chopconf
598            .set_toff(toff.min(15))
599            .set_hstrt(hstrt.min(7))
600            .set_hend(hend.min(15))
601            .set_tbl(tbl.min(3));
602        self.write_register(&chopconf)
603    }
604
605    /// Enable interpolation to 256 microsteps.
606    ///
607    /// When enabled, the driver interpolates between microsteps
608    /// for smoother motion, even at lower microstep settings.
609    pub fn set_interpolation(&mut self, enabled: bool) -> Result<(), Error<E>> {
610        let mut chopconf = self.read_register::<Chopconf>()?;
611        chopconf.set_intpol(enabled);
612        self.write_register(&chopconf)
613    }
614
615    /// Read the actual motor current scale being used.
616    ///
617    /// This reflects CoolStep adjustments if enabled.
618    /// Returns a value from 0-31.
619    pub fn actual_current_scale(&mut self) -> Result<u8, Error<E>> {
620        let status = self.drv_status()?;
621        Ok(status.cs_actual())
622    }
623
624    /// Check if the driver is currently in StealthChop mode.
625    pub fn is_stealthchop_active(&mut self) -> Result<bool, Error<E>> {
626        let status = self.drv_status()?;
627        Ok(status.stealth())
628    }
629
630    /// Get a comprehensive status summary.
631    ///
632    /// Returns a tuple of (errors_present, warnings_present, is_running).
633    pub fn status_summary(&mut self) -> Result<(bool, bool, bool), Error<E>> {
634        let status = self.drv_status()?;
635
636        let errors = status.has_error();
637        let warnings = status.otpw() || status.open_load_detected();
638        let running = !status.stst();
639
640        Ok((errors, warnings, running))
641    }
642}
643
644// ============================================================================
645// Async API
646// ============================================================================
647
648#[cfg(feature = "async")]
649impl<U, E> Tmc2209<U>
650where
651    U: embedded_io_async::Read<Error = E> + embedded_io_async::Write<Error = E>,
652{
653    /// Read a register (async).
654    ///
655    /// Sends a read request and waits for the response.
656    pub async fn read_register_async<R: ReadableRegister>(&mut self) -> Result<R, Error<E>> {
657        let request = self.read_request::<R>();
658
659        // Send the read request
660        self.uart
661            .write_all(request.as_bytes())
662            .await
663            .map_err(Error::Uart)?;
664        self.uart.flush().await.map_err(Error::Uart)?;
665
666        // Skip the echo (4 bytes)
667        let mut echo_buf = [0u8; 4];
668        self.read_exact_async(&mut echo_buf).await?;
669
670        // Read the response
671        let response = self.read_response_async().await?;
672
673        // Verify the register address matches
674        let expected_addr = R::ADDRESS as u8;
675        if response.reg_addr() != expected_addr {
676            return Err(Error::AddressMismatch {
677                expected: expected_addr,
678                actual: response.reg_addr(),
679            });
680        }
681
682        Ok(R::from(response.data()))
683    }
684
685    /// Write a register (async).
686    ///
687    /// Sends a write request to update a register value.
688    pub async fn write_register_async<R: WritableRegister>(
689        &mut self,
690        reg: &R,
691    ) -> Result<(), Error<E>> {
692        let request = self.write_request(reg);
693
694        // Send the write request
695        self.uart
696            .write_all(request.as_bytes())
697            .await
698            .map_err(Error::Uart)?;
699        self.uart.flush().await.map_err(Error::Uart)?;
700
701        // Read back the echo (8 bytes)
702        let mut echo_buf = [0u8; 8];
703        self.read_exact_async(&mut echo_buf).await?;
704
705        Ok(())
706    }
707
708    /// Read a register by raw address (async).
709    pub async fn read_raw_async(&mut self, reg_addr: u8) -> Result<u32, Error<E>> {
710        let request = ReadRequest::from_raw_addr(self.slave_addr, reg_addr);
711
712        self.uart
713            .write_all(request.as_bytes())
714            .await
715            .map_err(Error::Uart)?;
716        self.uart.flush().await.map_err(Error::Uart)?;
717
718        // Skip echo
719        let mut echo_buf = [0u8; 4];
720        self.read_exact_async(&mut echo_buf).await?;
721
722        let response = self.read_response_async().await?;
723        Ok(response.data())
724    }
725
726    /// Write a register by raw address (async).
727    pub async fn write_raw_async(&mut self, reg_addr: u8, data: u32) -> Result<(), Error<E>> {
728        let request = WriteRequest::from_raw(self.slave_addr, reg_addr, data);
729
730        self.uart
731            .write_all(request.as_bytes())
732            .await
733            .map_err(Error::Uart)?;
734        self.uart.flush().await.map_err(Error::Uart)?;
735
736        // Read back echo
737        let mut echo_buf = [0u8; 8];
738        self.read_exact_async(&mut echo_buf).await?;
739
740        Ok(())
741    }
742
743    /// Helper to read exact number of bytes (async).
744    async fn read_exact_async(&mut self, buf: &mut [u8]) -> Result<(), Error<E>> {
745        let mut total_read = 0;
746        while total_read < buf.len() {
747            let n = self
748                .uart
749                .read(&mut buf[total_read..])
750                .await
751                .map_err(Error::Uart)?;
752            if n == 0 {
753                return Err(Error::NoResponse);
754            }
755            total_read += n;
756        }
757        Ok(())
758    }
759
760    /// Helper to read a complete response (async).
761    async fn read_response_async(&mut self) -> Result<ReadResponse, Error<E>> {
762        self.reader.reset();
763        let mut buf = [0u8; 8];
764        self.read_exact_async(&mut buf).await?;
765
766        let (_, result) = self.reader.feed(&buf);
767        result.ok_or(Error::NoResponse)?
768    }
769
770    // ========================================================================
771    // Convenience methods (async)
772    // ========================================================================
773
774    /// Check if the driver is communicating properly (async).
775    pub async fn is_connected_async(&mut self) -> bool {
776        self.read_register_async::<Ifcnt>().await.is_ok()
777    }
778
779    /// Get the interface transmission counter (async).
780    pub async fn ifcnt_async(&mut self) -> Result<u8, Error<E>> {
781        let reg = self.read_register_async::<Ifcnt>().await?;
782        Ok(reg.count())
783    }
784
785    /// Get the driver status (async).
786    pub async fn drv_status_async(&mut self) -> Result<DrvStatus, Error<E>> {
787        self.read_register_async().await
788    }
789
790    /// Set the motor currents (async).
791    pub async fn set_current_async(
792        &mut self,
793        run_current: u8,
794        hold_current: u8,
795        hold_delay: u8,
796    ) -> Result<(), Error<E>> {
797        let mut reg = IholdIrun::new();
798        reg.set_irun(run_current)
799            .set_ihold(hold_current)
800            .set_iholddelay(hold_delay);
801        self.write_register_async(&reg).await
802    }
803
804    /// Set the microstep resolution (async).
805    pub async fn set_microsteps_async(
806        &mut self,
807        resolution: MicrostepResolution,
808    ) -> Result<(), Error<E>> {
809        let mut chopconf = self.read_register_async::<Chopconf>().await?;
810        chopconf.set_microstep_resolution(resolution);
811        self.write_register_async(&chopconf).await
812    }
813
814    /// Set velocity for internal motion controller (async).
815    pub async fn set_velocity_async(&mut self, velocity: i32) -> Result<(), Error<E>> {
816        let mut reg = Vactual::new();
817        reg.set_velocity(velocity);
818        self.write_register_async(&reg).await
819    }
820
821    /// Stop the motor (async).
822    pub async fn stop_async(&mut self) -> Result<(), Error<E>> {
823        self.set_velocity_async(0).await
824    }
825
826    // ========================================================================
827    // CoolStep and StallGuard methods (async)
828    // ========================================================================
829
830    /// Enable CoolStep adaptive current control (async).
831    pub async fn enable_coolstep_async(&mut self, semin: u8, semax: u8) -> Result<(), Error<E>> {
832        let mut coolconf = Coolconf::new();
833        coolconf
834            .set_semin(semin.min(15))
835            .set_semax(semax.min(15))
836            .set_seup(0)
837            .set_sedn(0);
838        self.write_register_async(&coolconf).await
839    }
840
841    /// Disable CoolStep (async).
842    pub async fn disable_coolstep_async(&mut self) -> Result<(), Error<E>> {
843        let coolconf = Coolconf::new();
844        self.write_register_async(&coolconf).await
845    }
846
847    /// Set the CoolStep velocity threshold (async).
848    pub async fn set_coolstep_threshold_async(&mut self, threshold: u32) -> Result<(), Error<E>> {
849        let mut tcoolthrs = Tcoolthrs::new();
850        tcoolthrs.set_threshold(threshold);
851        self.write_register_async(&tcoolthrs).await
852    }
853
854    /// Set the StealthChop velocity threshold (async).
855    pub async fn set_stealthchop_threshold_async(
856        &mut self,
857        threshold: u32,
858    ) -> Result<(), Error<E>> {
859        let mut tpwmthrs = Tpwmthrs::new();
860        tpwmthrs.set_threshold(threshold);
861        self.write_register_async(&tpwmthrs).await
862    }
863
864    // ========================================================================
865    // Sensorless homing methods (async)
866    // ========================================================================
867
868    /// Configure stall detection for sensorless homing (async).
869    pub async fn configure_stall_detection_async(&mut self, threshold: u8) -> Result<(), Error<E>> {
870        // Set StallGuard threshold
871        let mut sgthrs = Sgthrs::new();
872        sgthrs.set_threshold(threshold);
873        self.write_register_async(&sgthrs).await?;
874
875        // Enable DIAG output for stall indication
876        let mut gconf = self.read_register_async::<Gconf>().await?;
877        gconf.set_diag0_stall(true);
878        self.write_register_async(&gconf).await?;
879
880        Ok(())
881    }
882
883    /// Check if the motor is currently stalled (async).
884    pub async fn is_stalled_async(&mut self) -> Result<bool, Error<E>> {
885        let sg = self.read_register_async::<SgResult>().await?;
886        Ok(sg.result() == 0)
887    }
888
889    /// Get the current load indicator from StallGuard (async).
890    pub async fn load_indicator_async(&mut self) -> Result<u16, Error<E>> {
891        let sg = self.read_register_async::<SgResult>().await?;
892        Ok(sg.result())
893    }
894
895    // ========================================================================
896    // Mode selection (async)
897    // ========================================================================
898
899    /// Enable StealthChop mode (async).
900    pub async fn enable_stealthchop_async(&mut self) -> Result<(), Error<E>> {
901        let mut gconf = self.read_register_async::<Gconf>().await?;
902        gconf.set_en_spreadcycle(false);
903        self.write_register_async(&gconf).await
904    }
905
906    /// Enable SpreadCycle mode (async).
907    pub async fn enable_spreadcycle_async(&mut self) -> Result<(), Error<E>> {
908        let mut gconf = self.read_register_async::<Gconf>().await?;
909        gconf.set_en_spreadcycle(true);
910        self.write_register_async(&gconf).await
911    }
912
913    /// Enable or disable the driver (async).
914    pub async fn set_enabled_async(&mut self, enabled: bool) -> Result<(), Error<E>> {
915        let mut chopconf = self.read_register_async::<Chopconf>().await?;
916        if enabled {
917            if chopconf.toff() == 0 {
918                chopconf.set_toff(3);
919            }
920        } else {
921            chopconf.set_toff(0);
922        }
923        self.write_register_async(&chopconf).await
924    }
925
926    /// Check if motor is in standstill (async).
927    pub async fn is_standstill_async(&mut self) -> Result<bool, Error<E>> {
928        let status = self.drv_status_async().await?;
929        Ok(status.stst())
930    }
931}