aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob McWhirter <[email protected]>2021-05-28 13:31:40 -0400
committerBob McWhirter <[email protected]>2021-06-01 12:08:30 -0400
commit0c54c1afd12692bd88f223cc88bda23d463e2dd6 (patch)
tree251077bbadee05ff29027c479215e9cc28e5fd73
parent2aa836b0686ec358d0cbf27ba41039b5ddf6f63b (diff)
DAC v2 basics.
-rw-r--r--embassy-stm32/gen.py9
-rw-r--r--embassy-stm32/src/dac/mod.rs48
-rw-r--r--embassy-stm32/src/dac/v2.rs284
-rw-r--r--embassy-stm32/src/lib.rs2
m---------stm32-data0
5 files changed, 343 insertions, 0 deletions
diff --git a/embassy-stm32/gen.py b/embassy-stm32/gen.py
index b2b95ca8f..bfb791945 100644
--- a/embassy-stm32/gen.py
+++ b/embassy-stm32/gen.py
@@ -145,6 +145,15 @@ with open(output_file, 'w') as f:
145 if re.match('EXTI', irq): 145 if re.match('EXTI', irq):
146 exti_interrupts.append(irq) 146 exti_interrupts.append(irq)
147 147
148 if block_mod == 'dac':
149 f.write(f'impl_dac!({name});')
150 if 'dac_out1' in peri:
151 pin = peri['dac_out1']
152 f.write(f'impl_dac_pin!({name}, 1, {pin});')
153 if 'dac_out2' in peri:
154 pin = peri['dac_out2']
155 f.write(f'impl_dac_pin!({name}, 2, {pin});')
156
148 if not custom_singletons: 157 if not custom_singletons:
149 singletons.append(name) 158 singletons.append(name)
150 159
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
new file mode 100644
index 000000000..e1a603d40
--- /dev/null
+++ b/embassy-stm32/src/dac/mod.rs
@@ -0,0 +1,48 @@
1#![macro_use]
2
3#[cfg_attr(dac_v2, path = "v2.rs")]
4mod _version;
5use crate::gpio::NoPin;
6pub use _version::*;
7
8pub(crate) mod sealed {
9 use super::*;
10 use crate::gpio::{OptionalPin, Pin};
11
12 pub trait Instance {
13 fn regs() -> &'static crate::pac::dac::Dac;
14 }
15
16 pub trait DacPin<T: Instance, const C: u8>: OptionalPin {}
17}
18
19pub trait Instance: sealed::Instance + 'static {}
20
21pub trait DacPin<T: Instance, const C: u8>: sealed::DacPin<T, C> + 'static {}
22
23impl<T: Instance, const C: u8> DacPin<T, C> for NoPin {}
24impl<T: Instance, const C: u8> sealed::DacPin<T, C> for NoPin {}
25
26macro_rules! impl_dac {
27 ($inst:ident) => {
28 impl crate::dac::sealed::Instance for peripherals::$inst {
29 fn regs() -> &'static crate::pac::dac::Dac {
30 &crate::pac::$inst
31 }
32 }
33
34 impl crate::dac::Instance for peripherals::$inst {}
35 };
36}
37
38macro_rules! impl_dac_pin {
39 ($inst:ident, $channel:expr, $pin:ident ) => {
40 impl crate::dac::DacPin<peripherals::$inst, $channel> for peripherals::$pin {}
41
42 impl crate::dac::sealed::DacPin<peripherals::$inst, $channel> for peripherals::$pin {
43 //fn af_num(&self) -> u8 {
44 //$af
45 //}
46 }
47 };
48}
diff --git a/embassy-stm32/src/dac/v2.rs b/embassy-stm32/src/dac/v2.rs
new file mode 100644
index 000000000..18ac0f86a
--- /dev/null
+++ b/embassy-stm32/src/dac/v2.rs
@@ -0,0 +1,284 @@
1use crate::dac::{DacPin, Instance};
2use crate::gpio::Pin;
3use crate::gpio::{AnyPin, OptionalPin};
4use crate::pac::dac;
5use core::marker::PhantomData;
6use embassy::util::Unborrow;
7use embassy_extras::unborrow;
8
9pub enum Error {
10 UnconfiguredChannel,
11 InvalidValue,
12}
13
14pub enum Channel {
15 Ch1,
16 Ch2,
17}
18
19pub enum Ch1Trigger {
20 Tim6,
21 Tim3,
22 Tim7,
23 Tim15,
24 Tim2,
25 Exti9,
26 Software,
27}
28
29impl Ch1Trigger {
30 fn tsel(&self) -> dac::vals::Tsel1 {
31 match self {
32 Ch1Trigger::Tim6 => dac::vals::Tsel1::TIM6_TRGO,
33 Ch1Trigger::Tim3 => dac::vals::Tsel1::TIM3_TRGO,
34 Ch1Trigger::Tim7 => dac::vals::Tsel1::TIM7_TRGO,
35 Ch1Trigger::Tim15 => dac::vals::Tsel1::TIM15_TRGO,
36 Ch1Trigger::Tim2 => dac::vals::Tsel1::TIM2_TRGO,
37 Ch1Trigger::Exti9 => dac::vals::Tsel1::EXTI9,
38 Ch1Trigger::Software => dac::vals::Tsel1::SOFTWARE,
39 }
40 }
41}
42
43pub enum Ch2Trigger {
44 Tim6,
45 Tim8,
46 Tim7,
47 Tim5,
48 Tim2,
49 Tim4,
50 Exti9,
51 Software,
52}
53
54impl Ch2Trigger {
55 fn tsel(&self) -> dac::vals::Tsel2 {
56 match self {
57 Ch2Trigger::Tim6 => dac::vals::Tsel2::TIM6_TRGO,
58 Ch2Trigger::Tim8 => dac::vals::Tsel2::TIM8_TRGO,
59 Ch2Trigger::Tim7 => dac::vals::Tsel2::TIM7_TRGO,
60 Ch2Trigger::Tim5 => dac::vals::Tsel2::TIM5_TRGO,
61 Ch2Trigger::Tim2 => dac::vals::Tsel2::TIM2_TRGO,
62 Ch2Trigger::Tim4 => dac::vals::Tsel2::TIM4_TRGO,
63 Ch2Trigger::Exti9 => dac::vals::Tsel2::EXTI9,
64 Ch2Trigger::Software => dac::vals::Tsel2::SOFTWARE,
65 }
66 }
67}
68
69pub enum Alignment {
70 Left,
71 Right,
72}
73
74pub enum Value {
75 Bit8(u8),
76 Bit12(u16, Alignment),
77}
78
79pub struct Dac<'d, T: Instance> {
80 //peri: T,
81 ch1: Option<AnyPin>,
82 ch2: Option<AnyPin>,
83 phantom: PhantomData<&'d mut T>,
84}
85
86impl<'d, T: Instance> Dac<'d, T> {
87 pub fn new(
88 peri: impl Unborrow<Target = T> + 'd,
89 ch1: impl Unborrow<Target = impl DacPin<T, 1>>,
90 ch2: impl Unborrow<Target = impl DacPin<T, 2>>,
91 ) -> Self {
92 unborrow!(peri);
93 unborrow!(ch1, ch2);
94
95 let ch1 = ch1.degrade_optional();
96 if ch1.is_some() {
97 unsafe {
98 T::regs().cr().modify(|reg| {
99 reg.set_en1(true);
100 });
101 }
102 }
103
104 let ch2 = ch2.degrade_optional();
105 if ch2.is_some() {
106 unsafe {
107 T::regs().cr().modify(|reg| {
108 reg.set_en2(true);
109 });
110 }
111 }
112
113 let mut dac = Self {
114 ch1,
115 ch2,
116 phantom: PhantomData,
117 };
118
119 dac
120 }
121
122 pub fn enable_channel(&mut self, ch: Channel) -> Result<(), Error> {
123 match ch {
124 Channel::Ch1 => {
125 if self.ch1.is_none() {
126 Err(Error::UnconfiguredChannel)
127 } else {
128 unsafe {
129 T::regs().cr().modify(|reg| {
130 reg.set_en1(true);
131 });
132 }
133 Ok(())
134 }
135 }
136 Channel::Ch2 => {
137 if self.ch2.is_none() {
138 Err(Error::UnconfiguredChannel)
139 } else {
140 unsafe {
141 T::regs().cr().modify(|reg| {
142 reg.set_en2(true);
143 });
144 }
145 Ok(())
146 }
147 }
148 }
149 }
150
151 pub fn disable_channel(&mut self, ch: Channel) -> Result<(), Error> {
152 match ch {
153 Channel::Ch1 => {
154 if self.ch1.is_none() {
155 Err(Error::UnconfiguredChannel)
156 } else {
157 unsafe {
158 T::regs().cr().modify(|reg| {
159 reg.set_en1(true);
160 });
161 }
162 Ok(())
163 }
164 }
165 Channel::Ch2 => {
166 if self.ch2.is_none() {
167 Err(Error::UnconfiguredChannel)
168 } else {
169 unsafe {
170 T::regs().cr().modify(|reg| {
171 reg.set_en2(true);
172 });
173 }
174 Ok(())
175 }
176 }
177 }
178 }
179
180 pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> {
181 if self.ch1.is_none() {
182 return Err(Error::UnconfiguredChannel);
183 }
184 self.disable_channel(Channel::Ch1);
185 unsafe {
186 T::regs().cr().modify(|reg| {
187 reg.set_tsel1(trigger.tsel());
188 })
189 }
190 Ok(())
191 }
192
193 pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> {
194 if self.ch2.is_none() {
195 return Err(Error::UnconfiguredChannel);
196 }
197 self.disable_channel(Channel::Ch2);
198 unsafe {
199 T::regs().cr().modify(|reg| {
200 reg.set_tsel2(trigger.tsel());
201 })
202 }
203 Ok(())
204 }
205
206 pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> {
207 match ch {
208 Channel::Ch1 => {
209 if self.ch1.is_none() {
210 Err(Error::UnconfiguredChannel)
211 } else {
212 unsafe {
213 T::regs().swtrigr().write(|reg| {
214 reg.set_swtrig1(true);
215 });
216 }
217 Ok(())
218 }
219 }
220 Channel::Ch2 => {
221 if self.ch2.is_none() {
222 Err(Error::UnconfiguredChannel)
223 } else {
224 unsafe {
225 T::regs().swtrigr().write(|reg| {
226 reg.set_swtrig2(true);
227 });
228 }
229 Ok(())
230 }
231 }
232 }
233 }
234
235 pub fn trigger_all(&mut self) {
236 unsafe {
237 T::regs().swtrigr().write(|reg| {
238 reg.set_swtrig1(true);
239 reg.set_swtrig2(true);
240 })
241 }
242 }
243
244 pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> {
245 match ch {
246 Channel::Ch1 => {
247 if self.ch1.is_none() {
248 Err(Error::UnconfiguredChannel)
249 } else {
250 match value {
251 Value::Bit8(v) => unsafe {
252 T::regs().dhr8r1().write(|reg| reg.set_dacc1dhr(v));
253 },
254 Value::Bit12(v, Alignment::Left) => unsafe {
255 T::regs().dhr12l1().write(|reg| reg.set_dacc1dhr(v));
256 },
257 Value::Bit12(v, Alignment::Right) => unsafe {
258 T::regs().dhr12r1().write(|reg| reg.set_dacc1dhr(v));
259 },
260 }
261 Ok(())
262 }
263 }
264 Channel::Ch2 => {
265 if self.ch2.is_none() {
266 Err(Error::UnconfiguredChannel)
267 } else {
268 match value {
269 Value::Bit8(v) => unsafe {
270 T::regs().dhr8r2().write(|reg| reg.set_dacc2dhr(v));
271 },
272 Value::Bit12(v, Alignment::Left) => unsafe {
273 T::regs().dhr12l2().write(|reg| reg.set_dacc2dhr(v));
274 },
275 Value::Bit12(v, Alignment::Right) => unsafe {
276 T::regs().dhr12r2().write(|reg| reg.set_dacc2dhr(v));
277 },
278 }
279 Ok(())
280 }
281 }
282 }
283 }
284}
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 6a00f5f9b..c51f93eb5 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -23,6 +23,8 @@ pub mod rcc;
23// Sometimes-present hardware 23// Sometimes-present hardware
24#[cfg(timer)] 24#[cfg(timer)]
25pub mod clock; 25pub mod clock;
26#[cfg(dac)]
27pub mod dac;
26#[cfg(dma)] 28#[cfg(dma)]
27pub mod dma; 29pub mod dma;
28#[cfg(i2c)] 30#[cfg(i2c)]
diff --git a/stm32-data b/stm32-data
Subproject 64220ffdbf55b802f063ab209cdd7a788c95ca5 Subproject dfc67fe255e1e70101e9f1e3fb8b4fd8bb37362