Skip to main content

hal_mik32/
epic.rs

1//! Управление внешним контроллером прерываний EPIC.
2//!
3//! "Штатный" контроллер прерываний в ядре отключен. Управление
4//! статусом (вкл, выкл) осуществляется через регистр mie (см. модуль interrupts).
5//!
6//! Все прерывания обрабатываются единым обработчиком trap_handler.
7//! // TODO: вынести listen для level в отдельный, чтобы можно было писать сразу несколько линий,
8//! а не по одной, так как при записи в регистр mask_level_set перезаписывается вся маска целиком
9use core::option::Option;
10use core::u32;
11use mik32_pac::Epic;
12
13/// Тип срабатывания прерывания
14///
15/// # Variants
16///
17/// - `Edge` - по фронту
18/// - `Level` - по уровню
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum Trigger {
21    Edge,  // Срабатывание по фронту
22    Level, // Срабатывание по уровню
23}
24
25/// Линии прерывания
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27#[repr(u32)]
28pub enum InterruptLine {
29    Timer32_0 = 1 << 0,         // Таймер 32_0 - линия 0
30    USART0 = 1 << 1,            // USART0 - линия 1
31    USART1 = 1 << 2,            // USART1 - линия 2
32    SPI0 = 1 << 3,              // SPI0 - линия 3
33    SPI1 = 1 << 4,              // SPI1 - линия 4
34    GPIO = 1 << 5,              // GPIO - линия 5
35    I2C0 = 1 << 6,              // I2C0 - линия 6
36    I2C1 = 1 << 7,              // I2C1 - линия 7
37    WDT = 1 << 8,               // WDT - линия 8
38    Timer16_0 = 1 << 9,         // Таймер 16_0 - линия 9
39    Timer16_1 = 1 << 10,        // Таймер 16_1 - линия 10
40    Timer16_2 = 1 << 11,        // Таймер 16_2 - линия 11
41    Timer32_1 = 1 << 12,        // Таймер 32_1 - линия 12
42    Timer32_2 = 1 << 13,        // Таймер 32_2 - линия 13
43    SPIFI = 1 << 14,            // SPIFI - линия 14
44    RTC = 1 << 15,              // RTC - линия 15
45    EEPROM = 1 << 16,           // EEPROM - линия 16
46    WdtDom3 = 1 << 17,          // WDT домен 3 - линия 17
47    WdtSpifi = 1 << 18,         // WDT SPIFI - линия 18
48    WdtEeprom = 1 << 19,        // WDT EEPROM - линия 19
49    DMA = 1 << 20,              // DMA - линия 20
50    FrequencyMonitor = 1 << 21, // Монитор частоты - линия 21
51    AVCCOver = 1 << 22,         // AVCC выше порога - линия 22
52    AVCCUnder = 1 << 23,        // AVCC ниже порога - линия 23
53    VCCOver = 1 << 24,          // VCC выше порога - линия 24
54    VCCUnder = 1 << 25,         // VCC ниже порога - линия 25
55    LowBattery = 1 << 26,       // Низкий заряд батареи - линия 26
56    BrownOut = 1 << 27,         // Brown Out - линия 27
57    TSENS = 1 << 28,            // Датчик температуры - линия 28
58    ADC = 1 << 29,              // ADC - линия 29
59    DAC0 = 1 << 30,             // DAC0 - линия 30
60    DAC1 = 1 << 31,             // DAC1 - линия 31
61}
62
63#[derive(Debug)]
64pub enum Error {
65    LineLevelSet,
66    LineEdgeSet,
67    LineNeverSet,
68}
69
70/// Контроллер прерываний
71pub struct EPIC {
72    dp: Epic,
73    line_mask: u32,
74}
75
76impl EPIC {
77    /// Конструктор
78    ///
79    /// # Arguments
80    ///
81    /// - `dp` (`Epic`) - контроллер прерываний из PAC
82    ///
83    /// # Returns
84    ///
85    /// - `Self` - экземпляр контроллера
86    ///
87    /// # Examples
88    ///
89    /// ```
90    /// use crate::epic::EPIC;
91    ///
92    /// let dp = Peripherals::take().unwrap();
93    /// let mut epic = EPIC::new(dp.epic);
94    /// ```
95    pub fn new(dp: Epic) -> Self {
96        Self {
97            dp: dp,
98            line_mask: 0u32,
99        }
100    }
101
102    /// Включает линию прерывания
103    ///
104    /// Если на линию уже было включено прерывание, но другого типа
105    /// (включаете "по фронту", а уже было включено "по уровеню"), то вернётся ошибка
106    ///
107    /// # Arguments
108    ///
109    /// - `line` (`InterruptLine`) - линия прерывания
110    /// - `trigger` (`Trigger`) - тип срабатывания прерывания (по фронту или по уровню)
111    ///
112    /// # Returns
113    ///
114    /// - `Result<(), Error>` - успех включения прерывания
115    ///
116    /// # Errors
117    ///
118    /// На линию уже было включено прерывание другого типа
119    ///
120    /// # Examples
121    ///
122    /// ```
123    /// use crate::epic::EPIC;
124    ///
125    /// let dp = Peripherals::take().unwrap();
126    /// let mut epic = EPIC::new(dp.epic);
127    /// epic.listen(InterruptLine::Timer32_1); // Включим прерывание по линии таймера
128    /// ```
129    pub fn listen(&mut self, line: InterruptLine, trigger: Trigger) -> Result<(), Error> {
130        match trigger {
131            Trigger::Edge => {
132                if self.line_mask & (line as u32) != 0 {
133                    return Err(Error::LineLevelSet);
134                }
135
136                self.dp
137                    .mask_edge_set()
138                    .modify(|_, w| unsafe { w.bits(line as u32) });
139            }
140            Trigger::Level => {
141                self.line_mask = self.line_mask | (line as u32);
142
143                if self.dp.mask_edge_set().read().bits() & self.line_mask != 0 {
144                    return Err(Error::LineEdgeSet);
145                }
146
147                self.dp
148                    .mask_level_set()
149                    .write(|w| unsafe { w.bits(self.line_mask) });
150            }
151        }
152        Ok(())
153    }
154
155    /// Выключает прерывания по конкретной линии
156    /// Отключаются все прерввания, по фронту и по уровню.
157    ///
158    /// # Arguments
159    ///
160    /// - `line` (`InterruptLine`) - какую линию прервываний отключить, если `None`, то отключить все линии
161    ///
162    /// # Examples
163    ///
164    /// ```
165    /// use crate::epic::EPIC;
166    /// use mik32_pac::Peripherals;
167    ///
168    /// let dp = Peripherals::take().unwrap();
169    /// let mut epic = EPIC::new(dp.epic);
170    /// epic.unlisten(InterruptLine::Timer32_1); // Выключим прерывание по линии таймера
171    /// ```
172    pub fn unlisten(&mut self, line: Option<InterruptLine>) {
173        if let Some(line) = line {
174            // Выключаем "по фронту"
175            self.dp
176                .mask_edge_clear()
177                .modify(|_, w| unsafe { w.bits(line as u32) });
178
179            // Выключаем "по уровню"
180            self.line_mask = self.line_mask & !(line as u32);
181            self.dp
182                .mask_level_clear()
183                .write(|w| unsafe { w.bits(line as u32) });
184        } else {
185            // Выключаем все "по фронту"
186            self.dp
187                .mask_edge_clear()
188                .modify(|_, w| unsafe { w.bits(u32::MAX) });
189
190            // Выключаем все "по уровню"
191            self.line_mask = 0u32;
192            self.dp
193                .mask_level_clear()
194                .write(|w| unsafe { w.bits(u32::MAX) });
195        }
196    }
197
198    /// Произошло ли событие?
199    ///
200    /// # Arguments
201    /// - `event` (`InterruptEvent`) - проверяемое событие
202    ///
203    /// # Returns
204    ///
205    /// - `bool` - случилось ли событие
206    ///
207    /// # Examples
208    ///
209    /// ```
210    /// use crate::epic::EPIC;
211    /// use mik32_pac::Peripherals;
212    ///
213    /// let dp = Peripherals::take().unwrap();
214    /// let mut epic = EPIC::new(dp.epic);
215    /// epic.listen(InterruptLine::Timer32_1); // Включим прерывание по линии таймера
216    /// let is_timer_event_happend: bool = epic.event(InterruptLine::Timer32_1);
217    /// ```
218    pub fn event(&self, line: InterruptLine) -> bool {
219        match line {
220            InterruptLine::ADC => {
221                return self.dp.raw_status().read().adc().bit_is_set();
222            }
223            InterruptLine::DAC0 => {
224                return self.dp.raw_status().read().dac0().bit_is_set();
225            }
226            InterruptLine::DAC1 => {
227                return self.dp.raw_status().read().dac1().bit_is_set();
228            }
229            InterruptLine::DMA => {
230                return self.dp.raw_status().read().dma().bit_is_set();
231            }
232            InterruptLine::EEPROM => {
233                return self.dp.raw_status().read().eeprom().bit_is_set();
234            }
235            InterruptLine::FrequencyMonitor => {
236                return self.dp.raw_status().read().frequency_monitor().bit_is_set();
237            }
238            InterruptLine::GPIO => {
239                return self.dp.raw_status().read().gpio().bit_is_set();
240            }
241            InterruptLine::I2C0 => {
242                return self.dp.raw_status().read().i2c_0().bit_is_set();
243            }
244            InterruptLine::I2C1 => {
245                return self.dp.raw_status().read().i2c_1().bit_is_set();
246            }
247            InterruptLine::AVCCOver => {
248                return self.dp.raw_status().read().pvd_avcc_over().bit_is_set();
249            }
250            InterruptLine::AVCCUnder => {
251                return self.dp.raw_status().read().pvd_avcc_under().bit_is_set();
252            }
253            InterruptLine::VCCOver => {
254                return self.dp.raw_status().read().pvd_vcc_over().bit_is_set();
255            }
256            InterruptLine::VCCUnder => {
257                return self.dp.raw_status().read().pvd_vcc_under().bit_is_set();
258            }
259            InterruptLine::RTC => {
260                return self.dp.raw_status().read().rtc().bit_is_set();
261            }
262            InterruptLine::SPI0 => {
263                return self.dp.raw_status().read().spi_0().bit_is_set();
264            }
265            InterruptLine::SPI1 => {
266                return self.dp.raw_status().read().spi_1().bit_is_set();
267            }
268            InterruptLine::SPIFI => {
269                return self.dp.raw_status().read().spifi().bit_is_set();
270            }
271            InterruptLine::LowBattery => {
272                return self.dp.raw_status().read().battery_non_good().bit_is_set();
273            }
274            InterruptLine::Timer16_0 => {
275                return self.dp.raw_status().read().timer16_0().bit_is_set();
276            }
277            InterruptLine::Timer16_1 => {
278                return self.dp.raw_status().read().timer16_1().bit_is_set();
279            }
280            InterruptLine::Timer16_2 => {
281                return self.dp.raw_status().read().timer16_2().bit_is_set();
282            }
283            InterruptLine::Timer32_0 => {
284                return self.dp.raw_status().read().timer32_0().bit_is_set();
285            }
286            InterruptLine::Timer32_1 => {
287                return self.dp.raw_status().read().timer32_1().bit_is_set();
288            }
289            InterruptLine::Timer32_2 => {
290                return self.dp.raw_status().read().timer32_2().bit_is_set();
291            }
292            InterruptLine::TSENS => {
293                return self.dp.raw_status().read().tsens().bit_is_set();
294            }
295            InterruptLine::USART0 => {
296                return self.dp.raw_status().read().usart_0().bit_is_set();
297            }
298            InterruptLine::USART1 => {
299                return self.dp.raw_status().read().usart_1().bit_is_set();
300            }
301            InterruptLine::WDT => {
302                return self.dp.raw_status().read().wdt().bit_is_set();
303            }
304            InterruptLine::WdtDom3 => {
305                return self.dp.raw_status().read().wdt_bus_dom3().bit_is_set();
306            }
307            InterruptLine::WdtEeprom => {
308                return self.dp.raw_status().read().wdt_bus_eeprom().bit_is_set();
309            }
310            InterruptLine::WdtSpifi => {
311                return self.dp.raw_status().read().wdt_bus_spifi().bit_is_set();
312            }
313            InterruptLine::BrownOut => {
314                return self.dp.raw_status().read().bor().bit_is_set();
315            }
316        }
317    }
318
319    ///  Очищает флаги всех прерываний
320    ///
321    /// # Examples
322    ///
323    /// ```
324    /// use crate::epic::EPIC;
325    /// use mik32_pac::Peripherals;
326    /// let dp = Peripherals::take().unwrap();
327    /// let mut epic = EPIC::new(dp.epic);
328    /// epic.unlisten(InterruptLine::Timer32_1); // Выключим прерывание по линии таймера
329    /// ```
330    pub fn clear(&mut self) {
331        self.dp.clear().write(|w| unsafe { w.bits(0xFFFFFFFF) });
332    }
333}