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
//! ITM (Instrumentation Trace Macrocell)

use core::fmt::{self, Arguments, Write};

use cortex_m;

use peripheral;

struct Port {}

impl Write for Port {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        let stim = &cortex_m::peripheral::itm().stim[0];

        // TODO send in 32-bit chunks
        for byte in s.bytes() {
            while !stim.is_fifo_ready() {}
            stim.write_u8(byte);
        }

        Ok(())
    }
}

/// Initializes the ITM port
///
/// # Safety
///
/// - Must be called once
/// - Must be called in an interrupt-free environment
pub unsafe fn init() {
    let dbgmcu = peripheral::dbgmcu_mut();
    let dcb = cortex_m::peripheral::dcb_mut();
    let itm = cortex_m::peripheral::itm_mut();

    // DBGMCU: enable asynchronous tracing
    // NOTE(0b00) asynchronous mode
    dbgmcu.cr.modify(|_, w| w.trace_ioen(true).trace_mode(0b00));

    // DCB: enable the ITM
    let demcr = dcb.demcr.read();
    dcb.demcr.write({
        // Enable DWT and ITM
        const TRCENA: u32 = 1 << 24;

        demcr | TRCENA
    });

    // ITM: unlock the peripheral
    const KEY: u32 = 0xc5acce55;
    itm.lar.write(KEY);

    // ITM: enable the whole peripheral and assign an ID
    let tcr = itm.tcr.read();
    itm.tcr.write({
        // Enables the ITM
        const ITMENA: u32 = 1;
        // The ID of the ITM port. Anything different than 0 will do
        const TRACE_BUS_ID: u32 = 0b1 << 16;
        const TRACE_BUS_ID_MASK: u32 = 0b1111111 << 16;

        ((tcr | ITMENA) & !TRACE_BUS_ID_MASK) | TRACE_BUS_ID
    });

    // ITM: enable the stimulus port 0
    let ter = itm.ter[0].read();
    itm.ter[0].write({
        // Which port
        const N: u32 = 0;

        ter | 1 << N
    });
}

#[doc(hidden)]
pub fn write_fmt(args: Arguments) {
    Port {}.write_fmt(args).ok();
}

#[doc(hidden)]
pub fn write_str(s: &str) {
    Port {}.write_str(s).ok();
}