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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
//! # SIM - System Integration Module
//!
//! ## SIM_SCGC - System Clock Gating Control Register
//!
//! This module controls whether or not a module is connected to the bus clock.
//! This register is controlled by each peripherals respective (software)
//! module.
//!
//! ## SIM_BUSDIV
//!
//! This contains a single bit field that controls whether the bus divider is
//! equal to or half that of the system clock. Because the maximum allowed
//! speed of the bus clock is 20MHz compared to the 40MHz allowed for the
//! system clock, the bus clock divider must be set appropriately if the system
//! clock exceeds 20MHz. By default the system clock is 16MHz.
//!
//!
//! ## SIM_SOPT - System Options Register
//!
//! The SIM holds system configuration options, such as trigger sources, RESET
//! pin usage, etc. All of the options will be implemented in their respective
//! (software) modules. For example reset pin usage is handled by [crate::gpio]
//! , and the bus divider is handled by [crate::clocks].
//!
//! ## UUID
//!
//! the MCU's 64bit UUID.
//!
//! ## SIM_PINSEL - Pin Selection Register
//!
//! The SIM also holds the Pin Selection Register (SIM_PINSEL) which configures
//! the pins that certain peripherals use for inputs and outputs. This
//! functionality is not controlled by this (software) module, but is instead
//! implemented by their repsective modules. For example SIM_PINSEL\[UART0\] is
//! handled within the UART (software) module.

use crate::{pac::SIM, HALExt};

impl HALExt for SIM {
    type T = Sim;
    /// Split the SIM peripheral into useful chunks
    fn split(self) -> Sim {
        Sim {
            id: Id { _0: () },
            status: Status { _0: () },
            uuid: UUID,
        }
    }
}

/// Struct containings type structs for the Sim interface.
pub struct Sim {
    /// Getters for the ID portion of the Status and ID register
    pub id: Id,
    /// Getters for the Status portion of the Status and ID register
    pub status: Status,
    /// Getters for the UUID register
    pub uuid: UUID,
}

/// Status type
pub struct Status {
    _0: (),
}

/// ID type
pub struct Id {
    _0: (),
}

/// Enumeration for the number of pins on the device.
///
/// returned by status_id.pinout()
#[repr(u8)]
pub enum DevicePinOuts {
    /// 8 Pin device
    Pin8 = 0,
    /// 16 Pin device
    Pin16 = 1,
    /// 20 Pin device
    Pin20 = 2,
    /// 24 Pin device
    Pin24 = 3,
    /// 32 Pin device
    Pin32 = 4,
    /// 44 Pin device
    Pin44 = 5,
    /// 48 Pin device
    Pin48 = 6,
    /// 64 Pin device
    Pin64 = 7,
    /// 80 Pin device
    Pin80 = 8,
    /// 100 Pin device
    Pin100 = 10,
    /// Effectively Invalid
    Reserved,
}

impl Id {
    /// Return the Kinetis Family ID (4 bits)
    pub fn family(&self) -> u8 {
        unsafe { &(*SIM::ptr()) }.srsid.read().famid().bits()
    }

    /// Return the Kinetis sub-family ID (4 bits)
    pub fn subfamily(&self) -> u8 {
        unsafe { &(*SIM::ptr()) }.srsid.read().subfamid().bits()
    }

    /// Return the device revision number (4 bits)
    pub fn revision(&self) -> u8 {
        unsafe { &(*SIM::ptr()) }.srsid.read().rev_id().bits()
    }

    /// Device pin id
    pub fn pinout(&self) -> DevicePinOuts {
        let sim = unsafe { &(*SIM::ptr()) };

        match sim.srsid.read().pinid().bits() {
            0 => DevicePinOuts::Pin8,
            1 => DevicePinOuts::Pin16,
            2 => DevicePinOuts::Pin20,
            3 => DevicePinOuts::Pin24,
            4 => DevicePinOuts::Pin32,
            5 => DevicePinOuts::Pin44,
            6 => DevicePinOuts::Pin48,
            7 => DevicePinOuts::Pin64,
            8 => DevicePinOuts::Pin80,
            10 => DevicePinOuts::Pin100,
            _ => DevicePinOuts::Reserved,
        }
    }
}

impl Status {
    /// A reset was caused by a module failing to acknowledge entering Stop
    /// mode
    pub fn stop_error_reset(&self) -> bool {
        unsafe { &(*SIM::ptr()) }.srsid.read().sackerr().bit()
    }

    /// A reset was caused by debugger request
    ///
    /// The request is made in the MDM-AP register, this is called MDMAP in
    /// SIM_SRSID (section 12.2.1 of KEA64RM).
    pub fn debugger_reset(&self) -> bool {
        unsafe { &(*SIM::ptr()) }.srsid.read().mdmap().bit()
    }

    /// A reset was caused by software request
    pub fn software_reset(&self) -> bool {
        unsafe { &(*SIM::ptr()) }.srsid.read().sw().bit()
    }

    /// A reset was caused by a core lockup event
    pub fn lockup_reset(&self) -> bool {
        unsafe { &(*SIM::ptr()) }.srsid.read().lockup().bit()
    }

    /// A reset was caused by power-on
    ///
    /// For normal startup, this is set, if there was some other reason for
    /// reseting, this is cleared.
    pub fn power_on_reset(&self) -> bool {
        unsafe { &(*SIM::ptr()) }.srsid.read().por().bit()
    }

    /// A reset was caused by the reset Pin
    pub fn pin_reset(&self) -> bool {
        unsafe { &(*SIM::ptr()) }.srsid.read().pin().bit()
    }

    /// A reset was caused by the watchdog.
    pub fn watchdog_reset(&self) -> bool {
        unsafe { &(*SIM::ptr()) }.srsid.read().wdog().bit()
    }

    /// A reset was caused by the Internal Clock Source Peripheral
    ///
    /// This is called LOC (Loss Of Clock?) rest in KEA64RM (sect 12.2.1)
    pub fn ics_reset(&self) -> bool {
        unsafe { &(*SIM::ptr()) }.srsid.read().loc().bit()
    }

    /// A reset was caused by low voltage (brown out)
    ///
    /// Brown out detection is controlled by the Power Mangement Controller
    /// (PMC) Peripheral
    pub fn lv_reset(&self) -> bool {
        unsafe { &(*SIM::ptr()) }.srsid.read().lvd().bit()
    }
}

/// Universally Unique IDentifier
pub struct UUID;

impl UUID {
    /// Returns the UUID as a u64
    pub fn uuid(&self) -> u64 {
        ((self.uuid_h() as u64) << 32) | (self.uuid_l() as u64)
    }

    /// Returns lower 32bits of UUID as u32
    pub fn uuid_l(&self) -> u32 {
        unsafe { &(*SIM::ptr()) }.uuidh.read().bits()
    }

    /// Returns upper 32bits of UUID as u32
    pub fn uuid_h(&self) -> u32 {
        unsafe { &(*SIM::ptr()) }.uuidl.read().bits()
    }
}