Skip to main content

ch32v103_hal/
gpio.rs

1use ch32v1::ch32v103::{self as pac, AFIO, EXTI};
2use core::convert::Infallible;
3use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin, ToggleableOutputPin};
4use riscv::interrupt::free;
5
6/// choose which group of GPIO you want to use
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum Port {
9    /// GPIOA group, will effect GPIOA_xxxR register
10    GPIOA = 0x00,
11    /// GPIOB group, will effect GPIOB_xxxR register
12    GPIOB = 0x01,
13    /// GPIOC group, will effect GPIOC_xxxR register
14    GPIOC = 0x02,
15    /// GPIOD group, will effect GPIOD_xxxR register
16    GPIOD = 0x03,
17}
18
19/// Mode of a GPIO pin, it's GPIOx_CFGxR register value
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum PinMode {
23    Input = 0b00,
24    Output,
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum OutputType {
29    PushPull,
30    OpenDrain,
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum OutputSpeed {
35    /// GPIO 2Mhz speed
36    LowSpeed = 1,
37    /// GPIO 10Mhz speed
38    MediumSpeed,
39    /// GPIO 50Mhz speed
40    HighSpeed,
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44pub enum Pull {
45    PullUp,
46    PullDown,
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
50pub enum CfgLock {
51    Unlock,
52    Lock,
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub enum IntTrigger {
57    Rising = 0b01,
58    Falling = 0b10,
59    RisingFalling = 0b11,
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub enum PinState {
64    Low,
65    High,
66}
67/// GPIO Pin abstract structure
68pub struct Pin {
69    port: Port,
70    pin: u8,
71}
72
73impl Pin {
74    /// get GPIO Register
75    const fn regs(&self) -> *const pac::gpioa::RegisterBlock {
76        _regs(&self.port)
77    }
78
79    pub fn new(port: Port, pin: u8, mode: PinMode) -> Self {
80        // assert!(pin <= 15, "Pin range: 0~15");
81        free(|| {
82            let rcc = unsafe { &(*pac::RCC::ptr()) };
83
84            match port {
85                Port::GPIOA => {
86                    if rcc.apb2pcenr.read().iopaen().bit_is_clear() {
87                        rcc.apb2pcenr.modify(|_, w| w.iopaen().set_bit())
88                    }
89                }
90                Port::GPIOB => {
91                    if rcc.apb2pcenr.read().iopben().bit_is_clear() {
92                        rcc.apb2pcenr.modify(|_, w| w.iopben().set_bit())
93                    }
94                }
95                Port::GPIOC => {
96                    if rcc.apb2pcenr.read().iopcen().bit_is_clear() {
97                        rcc.apb2pcenr.modify(|_, w| w.iopcen().set_bit())
98                    }
99                }
100                Port::GPIOD => {
101                    if rcc.apb2pcenr.read().iopden().bit_is_clear() {
102                        rcc.apb2pcenr.modify(|_, w| w.iopden().set_bit())
103                    }
104                }
105            }
106        });
107
108        let pin = Self {
109            port: port,
110            pin: pin,
111        };
112
113        pin.mode(mode);
114
115        pin
116    }
117
118    pub fn mode(&self, mode: PinMode) {
119        let reg = unsafe { &(*self.regs()) };
120        free(|| {
121            let offset = 4 * (self.pin & !(0x01 << 3));
122            if self.pin >> 3 == 0 {
123                reg.cfglr.modify(|r, w| {
124                    let val = r.bits() & !(0x03 << offset) | ((mode as u32) << offset);
125                    unsafe { w.bits(val) }
126                })
127            } else {
128                reg.cfghr.modify(|r, w| {
129                    let val = r.bits() & !(0x03 << offset) | ((mode as u32) << offset);
130                    unsafe { w.bits(val) }
131                })
132            }
133        })
134    }
135
136    pub fn output_type(&self, val: OutputType) {
137        let reg = unsafe { &(*self.regs()) };
138        free(|| {
139            let offset = 4 * (self.pin & !(0x01 << 3));
140            if self.pin >> 3 == 0 {
141                reg.cfglr.modify(|r, w| {
142                    let bits = r.bits() & !(0x0c << offset) | ((val as u32) << (offset + 2));
143                    unsafe { w.bits(bits) }
144                })
145            }
146            if self.pin >> 3 == 1 {
147                let offset = 4 * (self.pin - 8);
148                reg.cfghr.modify(|r, w| {
149                    let bits = r.bits() & !(0x0c << offset) | ((val as u32) << (offset + 2));
150                    unsafe { w.bits(bits) }
151                })
152            }
153        })
154    }
155
156    pub fn output_speed(&self, speed: OutputSpeed) {
157        let reg = unsafe { &(*(self.regs())) };
158
159        free(|| {
160            if self.pin >> 3 == 0 {
161                let offset = 4 * (self.pin & !(0x01 << 3));
162                reg.cfglr.modify(|r, w| {
163                    let bits = r.bits() & !(0x03 << offset) | (speed as u32);
164                    unsafe { w.bits(bits) }
165                })
166            }
167            if self.pin >> 3 == 1 {
168                let offset = 4 * (self.pin - 8);
169                reg.cfghr.modify(|r, w| {
170                    let bits = r.bits() & !(0x03 << offset) | (speed as u32);
171                    unsafe { w.bits(bits) }
172                })
173            }
174        })
175    }
176
177    pub fn pull(&self, value: Pull) {
178        let reg = unsafe { &(*(self.regs())) };
179
180        free(|| {
181            let offset = 4 * (self.pin & !(0x01 << 3));
182
183            let mut current_mode = 0x00;
184
185            if self.pin >> 3 == 0 {
186                current_mode = (reg.cfglr.read().bits() & (0x03 << offset)) >> offset;
187            } else if self.pin >> 3 == 1 {
188                current_mode = (reg.cfghr.read().bits() & (0x03 << offset)) >> offset;
189            }
190
191            if current_mode == PinMode::Input as u32 {
192                reg.outdr.modify(|r, w| {
193                    let bits = r.bits() & !(0x01 << self.pin) | ((value as u32) << self.pin);
194                    unsafe { w.bits(bits) }
195                })
196            }
197        })
198    }
199
200    pub fn cfg_lock(&self, value: CfgLock) {
201        let reg = unsafe { &(*(self.regs())) };
202
203        free(|| {
204            if reg.lckr.read().lckk().is_unlocked() {
205                reg.lckr.modify(|_, w| w.lckk().locked())
206            }
207            todo!()
208        })
209    }
210
211    pub fn enable_int(&self, trigger: IntTrigger) {
212        let afio = unsafe { &(*AFIO::ptr()) };
213        let offset = (self.pin & 0x03) * 4;
214        let exti = unsafe { &(*(EXTI::ptr())) };
215
216        free(|| {
217            // Set AFIO EXTICRx to enable gpio exti line
218            if self.pin <= 3 {
219                afio.exticr1
220                    .modify(|_, w| unsafe { w.bits((self.port as u32) << offset) })
221            } else if self.pin <= 7 {
222                afio.exticr2
223                    .modify(|_, w| unsafe { w.bits((self.port as u32) << offset) })
224            } else if self.pin <= 11 {
225                afio.exticr3
226                    .modify(|_, w| unsafe { w.bits((self.port as u32) << offset) })
227            } else if self.pin <= 15 {
228                afio.exticr4
229                    .modify(|_, w| unsafe { w.bits((self.port as u32) << offset) })
230            }
231
232            // enable exti for pinX
233            exti.intenr
234                .modify(|_, w| unsafe { w.bits(0x01 << self.pin) });
235            // enable interrupt event for pinX
236            exti.evenr
237                .modify(|_, w| unsafe { w.bits(0x01 << self.pin) });
238            // set rising trigger
239            exti.rtenr
240                .modify(|_, w| unsafe { w.bits((trigger as u32 & 0x01) << self.pin) });
241            // set falling trigger
242            exti.ftenr
243                .modify(|_, w| unsafe { w.bits((trigger as u32 >> 1) << self.pin) });
244        })
245    }
246
247    pub fn disable_int(&self) {
248        let exti = unsafe { &(*(EXTI::ptr())) };
249
250        free(|| {
251            // enable exti for pinX
252            exti.intenr.modify(|_, w| unsafe { w.bits(0 << self.pin) });
253            // enable interrupt event for pinX
254            exti.evenr.modify(|_, w| unsafe { w.bits(0 << self.pin) });
255            // set rising trigger
256            exti.rtenr.modify(|_, w| unsafe { w.bits(0 << self.pin) });
257            // set falling trigger
258            exti.ftenr.modify(|_, w| unsafe { w.bits(0 << self.pin) });
259        })
260    }
261
262    pub fn get_state(&self) -> PinState {
263        let reg = unsafe { &(*(self.regs())) };
264        free(|| {
265            let state = (reg.indr.read().bits() & !(0x01 << self.pin)) >> self.pin;
266
267            if state == 1 {
268                PinState::High
269            } else {
270                PinState::Low
271            }
272        })
273    }
274
275    pub fn set_state(&self, value: PinState) {
276        let reg = unsafe { &(*(self.regs())) };
277
278        free(|| match value {
279            PinState::Low => reg.bcr.write(|w| unsafe { w.bits(0x01 << self.pin) }),
280            PinState::High => reg.bshr.write(|w| unsafe { w.bits(0x01 << self.pin) }),
281        })
282    }
283
284    pub fn is_high(&self) -> bool {
285        let reg = unsafe { &(*(self.regs())) };
286        free(|| {
287            let state = (reg.indr.read().bits() & (0x01 << self.pin)) >> self.pin;
288            if state == 0 {
289                false
290            } else {
291                true
292            }
293        })
294    }
295
296    pub fn is_low(&self) -> bool {
297        !self.is_high()
298    }
299
300    pub fn set_high(&self) {
301        self.set_state(PinState::High);
302    }
303
304    pub fn set_low(&self) {
305        self.set_state(PinState::Low);
306    }
307
308    pub fn toggle(&self) {
309        if self.is_high() {
310            self.set_low();
311        } else {
312            self.set_high();
313        }
314    }
315}
316
317impl InputPin for Pin {
318    type Error = Infallible;
319
320    fn is_high(&self) -> Result<bool, Self::Error> {
321        Ok(Pin::is_high(&self))
322    }
323
324    fn is_low(&self) -> Result<bool, Self::Error> {
325        Ok(Pin::is_low(&self))
326    }
327}
328
329impl OutputPin for Pin {
330    type Error = Infallible;
331
332    fn set_high(&mut self) -> Result<(), Self::Error> {
333        Ok(Pin::set_high(&self))
334    }
335
336    fn set_low(&mut self) -> Result<(), Self::Error> {
337        Ok(Pin::set_low(&self))
338    }
339
340    fn set_state(&mut self, state: embedded_hal::digital::v2::PinState) -> Result<(), Self::Error> {
341        match state {
342            embedded_hal::digital::v2::PinState::High => Ok(Pin::set_state(&self, PinState::High)),
343            embedded_hal::digital::v2::PinState::Low => Ok(Pin::set_state(&self, PinState::Low)),
344        }
345    }
346}
347
348impl ToggleableOutputPin for Pin {
349    type Error = Infallible;
350
351    fn toggle(&mut self) -> Result<(), Self::Error> {
352        Ok(Pin::toggle(&self))
353    }
354}
355
356impl StatefulOutputPin for Pin {
357    fn is_set_high(&self) -> Result<bool, Self::Error> {
358        Ok(Pin::is_high(&self))
359    }
360
361    fn is_set_low(&self) -> Result<bool, Self::Error> {
362        Ok(Pin::is_low(&self))
363    }
364}
365const fn _regs(port: &Port) -> *const pac::gpioa::RegisterBlock {
366    match port {
367        Port::GPIOA => pac::GPIOA::ptr(),
368        Port::GPIOB => pac::GPIOB::ptr(),
369        Port::GPIOC => pac::GPIOC::ptr(),
370        Port::GPIOD => pac::GPIOD::ptr(),
371    }
372}