gpio.rs 18 KB

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