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}