gpio.rs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. //! # General Purpose I/Os
  2. // TODO the pins here currently correspond to the LQFP-48 package. There should be Cargo features
  3. // that let you select different microcontroller packages
  4. use core::marker::PhantomData;
  5. use crate::rcc::APB2;
  6. /// Extension trait to split a GPIO peripheral in independent pins and registers
  7. pub trait GpioExt {
  8. /// The to split the GPIO into
  9. type Parts;
  10. /// Splits the GPIO block into independent pins and registers
  11. fn split(self, apb2: &mut APB2) -> Self::Parts;
  12. }
  13. /// Input mode (type state)
  14. pub struct Input<MODE> {
  15. _mode: PhantomData<MODE>,
  16. }
  17. /// Floating input (type state)
  18. pub struct Floating;
  19. /// Pulled down input (type state)
  20. pub struct PullDown;
  21. /// Pulled up input (type state)
  22. pub struct PullUp;
  23. /// Output mode (type state)
  24. pub struct Output<MODE> {
  25. _mode: PhantomData<MODE>,
  26. }
  27. /// Push pull output (type state)
  28. pub struct PushPull;
  29. /// Open drain output (type state)
  30. pub struct OpenDrain;
  31. /// Analog mode (type state)
  32. pub struct Analog;
  33. /// Alternate function
  34. pub struct Alternate<MODE> {
  35. _mode: PhantomData<MODE>,
  36. }
  37. pub enum State {
  38. High,
  39. Low,
  40. }
  41. macro_rules! gpio {
  42. ($GPIOX:ident, $gpiox:ident, $gpioy:ident, $iopxenr:ident, $iopxrst:ident, $PXx:ident, [
  43. $($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty, $CR:ident),)+
  44. ]) => {
  45. /// GPIO
  46. pub mod $gpiox {
  47. use core::marker::PhantomData;
  48. use crate::hal::digital::{InputPin, OutputPin, StatefulOutputPin, toggleable};
  49. use crate::pac::{$gpioy, $GPIOX};
  50. use crate::rcc::APB2;
  51. use super::{
  52. Alternate, Floating, GpioExt, Input,
  53. OpenDrain,
  54. Output,
  55. PullDown,
  56. PullUp,
  57. PushPull,
  58. Analog,
  59. State,
  60. };
  61. /// GPIO parts
  62. pub struct Parts {
  63. /// Opaque CRL register
  64. pub crl: CRL,
  65. /// Opaque CRH register
  66. pub crh: CRH,
  67. $(
  68. /// Pin
  69. pub $pxi: $PXi<$MODE>,
  70. )+
  71. }
  72. impl GpioExt for $GPIOX {
  73. type Parts = Parts;
  74. fn split(self, apb2: &mut APB2) -> Parts {
  75. apb2.enr().modify(|_, w| w.$iopxenr().set_bit());
  76. apb2.rstr().modify(|_, w| w.$iopxrst().set_bit());
  77. apb2.rstr().modify(|_, w| w.$iopxrst().clear_bit());
  78. Parts {
  79. crl: CRL { _0: () },
  80. crh: CRH { _0: () },
  81. $(
  82. $pxi: $PXi { _mode: PhantomData },
  83. )+
  84. }
  85. }
  86. }
  87. /// Opaque CRL register
  88. pub struct CRL {
  89. _0: (),
  90. }
  91. impl CRL {
  92. // NOTE(allow) we get a warning on GPIOC because it only has 3 high pins
  93. #[allow(dead_code)]
  94. pub(crate) fn cr(&mut self) -> &$gpioy::CRL {
  95. unsafe { &(*$GPIOX::ptr()).crl }
  96. }
  97. }
  98. /// Opaque CRH register
  99. pub struct CRH {
  100. _0: (),
  101. }
  102. impl CRH {
  103. pub(crate) fn cr(&mut self) -> &$gpioy::CRH {
  104. unsafe { &(*$GPIOX::ptr()).crh }
  105. }
  106. }
  107. /// Partially erased pin
  108. pub struct $PXx<MODE> {
  109. i: u8,
  110. _mode: PhantomData<MODE>,
  111. }
  112. impl<MODE> OutputPin for $PXx<Output<MODE>> {
  113. fn set_high(&mut self) {
  114. // NOTE(unsafe) atomic write to a stateless register
  115. unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << self.i)) }
  116. }
  117. fn set_low(&mut self) {
  118. // NOTE(unsafe) atomic write to a stateless register
  119. unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (16 + self.i))) }
  120. }
  121. }
  122. impl<MODE> InputPin for $PXx<Input<MODE>> {
  123. fn is_high(&self) -> bool {
  124. !self.is_low()
  125. }
  126. fn is_low(&self) -> bool {
  127. // NOTE(unsafe) atomic read with no side effects
  128. unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << self.i) == 0 }
  129. }
  130. }
  131. impl <MODE> StatefulOutputPin for $PXx<Output<MODE>> {
  132. fn is_set_high(&self) -> bool {
  133. !self.is_set_low()
  134. }
  135. fn is_set_low(&self) -> bool {
  136. // NOTE(unsafe) atomic read with no side effects
  137. unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << self.i) == 0 }
  138. }
  139. }
  140. impl <MODE> toggleable::Default for $PXx<Output<MODE>> {}
  141. impl InputPin for $PXx<Output<OpenDrain>> {
  142. fn is_high(&self) -> bool {
  143. !self.is_low()
  144. }
  145. fn is_low(&self) -> bool {
  146. // NOTE(unsafe) atomic read with no side effects
  147. unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << self.i) == 0 }
  148. }
  149. }
  150. $(
  151. /// Pin
  152. pub struct $PXi<MODE> {
  153. _mode: PhantomData<MODE>,
  154. }
  155. impl<MODE> $PXi<MODE> {
  156. /// Configures the pin to operate as an alternate function push-pull output
  157. /// pin.
  158. pub fn into_alternate_push_pull(
  159. self,
  160. cr: &mut $CR,
  161. ) -> $PXi<Alternate<PushPull>> {
  162. let offset = (4 * $i) % 32;
  163. // Alternate function output push pull
  164. let cnf = 0b10;
  165. // Output mode, max speed 50 MHz
  166. let mode = 0b11;
  167. let bits = (cnf << 2) | mode;
  168. // input mode
  169. cr
  170. .cr()
  171. .modify(|r, w| unsafe {
  172. w.bits((r.bits() & !(0b1111 << offset)) | (bits << offset))
  173. });
  174. $PXi { _mode: PhantomData }
  175. }
  176. /// Configures the pin to operate as an alternate function open-drain output
  177. /// pin.
  178. pub fn into_alternate_open_drain(
  179. self,
  180. cr: &mut $CR,
  181. ) -> $PXi<Alternate<OpenDrain>> {
  182. let offset = (4 * $i) % 32;
  183. // Alternate function output open drain
  184. let cnf = 0b11;
  185. // Output mode, max speed 50 MHz
  186. let mode = 0b11;
  187. let bits = (cnf << 2) | mode;
  188. // input mode
  189. cr
  190. .cr()
  191. .modify(|r, w| unsafe {
  192. w.bits((r.bits() & !(0b1111 << offset)) | (bits << offset))
  193. });
  194. $PXi { _mode: PhantomData }
  195. }
  196. /// Configures the pin to operate as a floating input pin
  197. pub fn into_floating_input(
  198. self,
  199. cr: &mut $CR,
  200. ) -> $PXi<Input<Floating>> {
  201. let offset = (4 * $i) % 32;
  202. // Floating input
  203. let cnf = 0b01;
  204. // Input mode
  205. let mode = 0b00;
  206. let bits = (cnf << 2) | mode;
  207. // input mode
  208. cr
  209. .cr()
  210. .modify(|r, w| unsafe {
  211. w.bits((r.bits() & !(0b1111 << offset)) | (bits << offset))
  212. });
  213. $PXi { _mode: PhantomData }
  214. }
  215. /// Configures the pin to operate as a pulled down input pin
  216. pub fn into_pull_down_input(
  217. self,
  218. cr: &mut $CR,
  219. ) -> $PXi<Input<PullDown>> {
  220. let offset = (4 * $i) % 32;
  221. // Pull up/down input
  222. let cnf = 0b10;
  223. // Input mode
  224. let mode = 0b00;
  225. let bits = (cnf << 2) | mode;
  226. //pull down:
  227. // NOTE(unsafe) atomic write to a stateless register
  228. unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (16 + $i))) }
  229. // input mode
  230. cr
  231. .cr()
  232. .modify(|r, w| unsafe {
  233. w.bits((r.bits() & !(0b1111 << offset)) | (bits << offset))
  234. });
  235. $PXi { _mode: PhantomData }
  236. }
  237. /// Configures the pin to operate as a pulled up input pin
  238. pub fn into_pull_up_input(
  239. self,
  240. cr: &mut $CR,
  241. ) -> $PXi<Input<PullUp>> {
  242. let offset = (4 * $i) % 32;
  243. // Pull up/down input
  244. let cnf = 0b10;
  245. // Input mode
  246. let mode = 0b00;
  247. let bits = (cnf << 2) | mode;
  248. //pull up:
  249. // NOTE(unsafe) atomic write to a stateless register
  250. unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << $i)) }
  251. // input mode
  252. cr
  253. .cr()
  254. .modify(|r, w| unsafe {
  255. w.bits((r.bits() & !(0b1111 << offset)) | (bits << offset))
  256. });
  257. $PXi { _mode: PhantomData }
  258. }
  259. /// Configures the pin to operate as an open-drain output pin.
  260. /// Initial state will be low.
  261. pub fn into_open_drain_output(
  262. self,
  263. cr: &mut $CR,
  264. ) -> $PXi<Output<OpenDrain>> {
  265. self.into_open_drain_output_with_state(cr, State::Low)
  266. }
  267. /// Configures the pin to operate as an open-drain output pin.
  268. /// `initial_state` specifies whether the pin should be initially high or low.
  269. pub fn into_open_drain_output_with_state(
  270. self,
  271. cr: &mut $CR,
  272. initial_state: State,
  273. ) -> $PXi<Output<OpenDrain>> {
  274. let offset = (4 * $i) % 32;
  275. // General purpose output open-drain
  276. let cnf = 0b01;
  277. // Open-Drain Output mode, max speed 50 MHz
  278. let mode = 0b11;
  279. let bits = (cnf << 2) | mode;
  280. let mut res = $PXi { _mode: PhantomData };
  281. match initial_state {
  282. State::High => res.set_high(),
  283. State::Low => res.set_low(),
  284. }
  285. cr
  286. .cr()
  287. .modify(|r, w| unsafe {
  288. w.bits((r.bits() & !(0b1111 << offset)) | (bits << offset))
  289. });
  290. res
  291. }
  292. /// Configures the pin to operate as an push-pull output pin.
  293. /// Initial state will be low.
  294. pub fn into_push_pull_output(
  295. self,
  296. cr: &mut $CR,
  297. ) -> $PXi<Output<PushPull>> {
  298. self.into_push_pull_output_with_state(cr, State::Low)
  299. }
  300. /// Configures the pin to operate as an push-pull output pin.
  301. /// `initial_state` specifies whether the pin should be initially high or low.
  302. pub fn into_push_pull_output_with_state(
  303. self,
  304. cr: &mut $CR,
  305. initial_state: State,
  306. ) -> $PXi<Output<PushPull>> {
  307. let offset = (4 * $i) % 32;
  308. // General purpose output push-pull
  309. let cnf = 0b00;
  310. // Output mode, max speed 50 MHz
  311. let mode = 0b11;
  312. let bits = (cnf << 2) | mode;
  313. let mut res = $PXi { _mode: PhantomData };
  314. match initial_state {
  315. State::High => res.set_high(),
  316. State::Low => res.set_low(),
  317. }
  318. cr
  319. .cr()
  320. .modify(|r, w| unsafe {
  321. w.bits((r.bits() & !(0b1111 << offset)) | (bits << offset))
  322. });
  323. res
  324. }
  325. /// Configures the pin to operate as an analog input pin
  326. pub fn into_analog(self, cr: &mut $CR) -> $PXi<Analog> {
  327. let offset = (4 * $i) % 32;
  328. // Analog input
  329. let cnf = 0b00;
  330. // Input mode
  331. let mode = 0b00;
  332. let bits = (cnf << 2) | mode;
  333. // analog mode
  334. cr
  335. .cr()
  336. .modify(|r, w| unsafe {
  337. w.bits((r.bits() & !(0b1111 << offset)) | (bits << offset))
  338. });
  339. $PXi { _mode: PhantomData }
  340. }
  341. }
  342. impl<MODE> $PXi<MODE> {
  343. /// Erases the pin number from the type
  344. ///
  345. /// This is useful when you want to collect the pins into an array where you
  346. /// need all the elements to have the same type
  347. pub fn downgrade(self) -> $PXx<MODE> {
  348. $PXx {
  349. i: $i,
  350. _mode: self._mode,
  351. }
  352. }
  353. }
  354. impl<MODE> OutputPin for $PXi<Output<MODE>> {
  355. fn set_high(&mut self) {
  356. // NOTE(unsafe) atomic write to a stateless register
  357. unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << $i)) }
  358. }
  359. fn set_low(&mut self) {
  360. // NOTE(unsafe) atomic write to a stateless register
  361. unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (16 + $i))) }
  362. }
  363. }
  364. impl<MODE> StatefulOutputPin for $PXi<Output<MODE>> {
  365. fn is_set_high(&self) -> bool {
  366. !self.is_set_low()
  367. }
  368. fn is_set_low(&self) -> bool {
  369. // NOTE(unsafe) atomic read with no side effects
  370. unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << $i) == 0 }
  371. }
  372. }
  373. impl<MODE> toggleable::Default for $PXi<Output<MODE>> {}
  374. impl<MODE> OutputPin for $PXi<Alternate<MODE>> {
  375. fn set_high(&mut self) {
  376. // NOTE(unsafe) atomic write to a stateless register
  377. unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << $i)) }
  378. }
  379. fn set_low(&mut self) {
  380. // NOTE(unsafe) atomic write to a stateless register
  381. unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (16 + $i))) }
  382. }
  383. }
  384. impl<MODE> StatefulOutputPin for $PXi<Alternate<MODE>> {
  385. fn is_set_high(&self) -> bool {
  386. !self.is_set_low()
  387. }
  388. fn is_set_low(&self) -> bool {
  389. // NOTE(unsafe) atomic read with no side effects
  390. unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << $i) == 0 }
  391. }
  392. }
  393. impl<MODE> InputPin for $PXi<Input<MODE>> {
  394. fn is_high(&self) -> bool {
  395. !self.is_low()
  396. }
  397. fn is_low(&self) -> bool {
  398. // NOTE(unsafe) atomic read with no side effects
  399. unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << $i) == 0 }
  400. }
  401. }
  402. impl InputPin for $PXi<Output<OpenDrain>> {
  403. fn is_high(&self) -> bool {
  404. !self.is_low()
  405. }
  406. fn is_low(&self) -> bool {
  407. // NOTE(unsafe) atomic read with no side effects
  408. unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << $i) == 0 }
  409. }
  410. }
  411. )+
  412. }
  413. }
  414. }
  415. gpio!(GPIOA, gpioa, gpioa, iopaen, ioparst, PAx, [
  416. PA0: (pa0, 0, Input<Floating>, CRL),
  417. PA1: (pa1, 1, Input<Floating>, CRL),
  418. PA2: (pa2, 2, Input<Floating>, CRL),
  419. PA3: (pa3, 3, Input<Floating>, CRL),
  420. PA4: (pa4, 4, Input<Floating>, CRL),
  421. PA5: (pa5, 5, Input<Floating>, CRL),
  422. PA6: (pa6, 6, Input<Floating>, CRL),
  423. PA7: (pa7, 7, Input<Floating>, CRL),
  424. PA8: (pa8, 8, Input<Floating>, CRH),
  425. PA9: (pa9, 9, Input<Floating>, CRH),
  426. PA10: (pa10, 10, Input<Floating>, CRH),
  427. PA11: (pa11, 11, Input<Floating>, CRH),
  428. PA12: (pa12, 12, Input<Floating>, CRH),
  429. PA13: (pa13, 13, Input<Floating>, CRH),
  430. PA14: (pa14, 14, Input<Floating>, CRH),
  431. PA15: (pa15, 15, Input<Floating>, CRH),
  432. ]);
  433. gpio!(GPIOB, gpiob, gpioa, iopben, iopbrst, PBx, [
  434. PB0: (pb0, 0, Input<Floating>, CRL),
  435. PB1: (pb1, 1, Input<Floating>, CRL),
  436. PB2: (pb2, 2, Input<Floating>, CRL),
  437. PB3: (pb3, 3, Input<Floating>, CRL),
  438. PB4: (pb4, 4, Input<Floating>, CRL),
  439. PB5: (pb5, 5, Input<Floating>, CRL),
  440. PB6: (pb6, 6, Input<Floating>, CRL),
  441. PB7: (pb7, 7, Input<Floating>, CRL),
  442. PB8: (pb8, 8, Input<Floating>, CRH),
  443. PB9: (pb9, 9, Input<Floating>, CRH),
  444. PB10: (pb10, 10, Input<Floating>, CRH),
  445. PB11: (pb11, 11, Input<Floating>, CRH),
  446. PB12: (pb12, 12, Input<Floating>, CRH),
  447. PB13: (pb13, 13, Input<Floating>, CRH),
  448. PB14: (pb14, 14, Input<Floating>, CRH),
  449. PB15: (pb15, 15, Input<Floating>, CRH),
  450. ]);
  451. #[cfg(not(feature = "stm32f100"))]
  452. gpio!(GPIOC, gpioc, gpioa, iopcen, iopcrst, PCx, [
  453. PC13: (pc13, 13, Input<Floating>, CRH),
  454. PC14: (pc14, 14, Input<Floating>, CRH),
  455. PC15: (pc15, 15, Input<Floating>, CRH),
  456. ]);
  457. #[cfg(feature = "stm32f100")]
  458. gpio!(GPIOC, gpioc, gpioa, iopcen, iopcrst, PCx, [
  459. PC8: (pc8, 8, Input<Floating>, CRH),
  460. PC9: (pc9, 9, Input<Floating>, CRH),
  461. ]);