Skip to main content

cortex_m/
itm.rs

1//! Instrumentation Trace Macrocell
2//!
3//! **NOTE** This module is only available on ARMv7-M and newer.
4
5use core::{fmt, ptr, slice};
6
7use crate::peripheral::itm::Stim;
8
9// NOTE assumes that `bytes` is 32-bit aligned
10unsafe fn write_words(stim: &mut Stim, bytes: &[u32]) {
11    unsafe {
12        let mut p = bytes.as_ptr();
13        for _ in 0..bytes.len() {
14            while !stim.is_fifo_ready() {}
15            stim.write_u32(ptr::read(p));
16            p = p.offset(1);
17        }
18    }
19}
20
21/// Writes an aligned byte slice to the ITM.
22///
23/// `buffer` must be 4-byte aligned.
24unsafe fn write_aligned_impl(port: &mut Stim, buffer: &[u8]) {
25    unsafe {
26        let len = buffer.len();
27
28        if len == 0 {
29            return;
30        }
31
32        let split = len & !0b11;
33        #[allow(clippy::cast_ptr_alignment)]
34        write_words(
35            port,
36            slice::from_raw_parts(buffer.as_ptr() as *const u32, split >> 2),
37        );
38
39        // 3 bytes or less left
40        let mut left = len & 0b11;
41        let mut ptr = buffer.as_ptr().add(split);
42
43        // at least 2 bytes left
44        if left > 1 {
45            while !port.is_fifo_ready() {}
46
47            #[allow(clippy::cast_ptr_alignment)]
48            port.write_u16(ptr::read(ptr as *const u16));
49
50            ptr = ptr.offset(2);
51            left -= 2;
52        }
53
54        // final byte
55        if left == 1 {
56            while !port.is_fifo_ready() {}
57            port.write_u8(*ptr);
58        }
59    }
60}
61
62struct Port<'p>(&'p mut Stim);
63
64impl fmt::Write for Port<'_> {
65    #[inline]
66    fn write_str(&mut self, s: &str) -> fmt::Result {
67        write_all(self.0, s.as_bytes());
68        Ok(())
69    }
70}
71
72/// A wrapper type that aligns its contents on a 4-Byte boundary.
73///
74/// ITM transfers are most efficient when the data is 4-Byte-aligned. This type provides an easy
75/// way to accomplish and enforce such an alignment.
76#[repr(align(4))]
77pub struct Aligned<T: ?Sized>(pub T);
78
79/// Writes `buffer` to an ITM port.
80#[allow(clippy::missing_inline_in_public_items)]
81pub fn write_all(port: &mut Stim, buffer: &[u8]) {
82    unsafe {
83        let mut len = buffer.len();
84        let mut ptr = buffer.as_ptr();
85
86        if len == 0 {
87            return;
88        }
89
90        // 0x01 OR 0x03
91        if ptr as usize % 2 == 1 {
92            while !port.is_fifo_ready() {}
93            port.write_u8(*ptr);
94
95            // 0x02 OR 0x04
96            ptr = ptr.offset(1);
97            len -= 1;
98        }
99
100        // 0x02
101        if ptr as usize % 4 == 2 {
102            if len > 1 {
103                // at least 2 bytes
104                while !port.is_fifo_ready() {}
105
106                // We checked the alignment above, so this is safe
107                #[allow(clippy::cast_ptr_alignment)]
108                port.write_u16(ptr::read(ptr as *const u16));
109
110                // 0x04
111                ptr = ptr.offset(2);
112                len -= 2;
113            } else {
114                if len == 1 {
115                    // last byte
116                    while !port.is_fifo_ready() {}
117                    port.write_u8(*ptr);
118                }
119
120                return;
121            }
122        }
123
124        // The remaining data is 4-byte aligned, but might not be a multiple of 4 bytes
125        write_aligned_impl(port, slice::from_raw_parts(ptr, len));
126    }
127}
128
129/// Writes a 4-byte aligned `buffer` to an ITM port.
130///
131/// # Examples
132///
133/// ```no_run
134/// # use cortex_m::{itm::{self, Aligned}, peripheral::ITM};
135/// # let port = unsafe { &mut (*ITM::PTR).stim[0] };
136/// let mut buffer = Aligned([0; 14]);
137///
138/// buffer.0.copy_from_slice(b"Hello, world!\n");
139///
140/// itm::write_aligned(port, &buffer);
141///
142/// // Or equivalently
143/// itm::write_aligned(port, &Aligned(*b"Hello, world!\n"));
144/// ```
145#[allow(clippy::missing_inline_in_public_items)]
146pub fn write_aligned(port: &mut Stim, buffer: &Aligned<[u8]>) {
147    unsafe { write_aligned_impl(port, &buffer.0) }
148}
149
150/// Writes `fmt::Arguments` to the ITM `port`
151#[inline]
152pub fn write_fmt(port: &mut Stim, args: fmt::Arguments) {
153    use core::fmt::Write;
154
155    Port(port).write_fmt(args).ok();
156}
157
158/// Writes a string to the ITM `port`
159#[inline]
160pub fn write_str(port: &mut Stim, string: &str) {
161    write_all(port, string.as_bytes())
162}