aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuliDi <[email protected]>2023-06-23 12:14:40 +0200
committerJuliDi <[email protected]>2023-06-23 12:14:40 +0200
commit915f79c974ace037e914397b42eb9d2448bd5ca3 (patch)
treee3cf5740b8c5da95b89a00a068c3329043c64521
parentea04a0277bb19719188e904a86e28c34f9801c96 (diff)
allow independent use of ch1 and ch2 on dac
-rw-r--r--embassy-stm32/src/dac/mod.rs150
1 files changed, 100 insertions, 50 deletions
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 42646d20d..5b39758bf 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -22,7 +22,7 @@ pub enum Channel {
22} 22}
23 23
24impl Channel { 24impl Channel {
25 fn index(&self) -> usize { 25 const fn index(&self) -> usize {
26 match self { 26 match self {
27 Channel::Ch1 => 0, 27 Channel::Ch1 => 0,
28 Channel::Ch2 => 1, 28 Channel::Ch2 => 1,
@@ -109,72 +109,100 @@ pub enum ValueArray<'a> {
109} 109}
110 110
111pub struct Dac<'d, T: Instance, Tx> { 111pub struct Dac<'d, T: Instance, Tx> {
112 channels: u8, 112 ch1: bool,
113 ch2: bool,
113 txdma: PeripheralRef<'d, Tx>, 114 txdma: PeripheralRef<'d, Tx>,
114 _peri: PeripheralRef<'d, T>, 115 _peri: PeripheralRef<'d, T>,
115} 116}
116 117
117impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { 118impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
118 /// Create a new instance with one channel 119 pub fn new_ch1(
119 pub fn new_1ch(
120 peri: impl Peripheral<P = T> + 'd, 120 peri: impl Peripheral<P = T> + 'd,
121 txdma: impl Peripheral<P = Tx> + 'd, 121 txdma: impl Peripheral<P = Tx> + 'd,
122 _ch1: impl Peripheral<P = impl DacPin<T, 1>> + 'd, 122 _ch1: impl Peripheral<P = impl DacPin<T, 1>> + 'd,
123 ) -> Self { 123 ) -> Self {
124 into_ref!(peri); 124 into_ref!(peri);
125 Self::new_inner(peri, 1, txdma) 125 Self::new_inner(peri, true, false, txdma)
126 } 126 }
127 127
128 /// Create a new instance with two channels 128 pub fn new_ch2(
129 pub fn new_2ch( 129 peri: impl Peripheral<P = T> + 'd,
130 txdma: impl Peripheral<P = Tx> + 'd,
131 _ch2: impl Peripheral<P = impl DacPin<T, 2>> + 'd,
132 ) -> Self {
133 into_ref!(peri);
134 Self::new_inner(peri, false, true, txdma)
135 }
136
137 pub fn new_ch1_and_ch2(
130 peri: impl Peripheral<P = T> + 'd, 138 peri: impl Peripheral<P = T> + 'd,
131 txdma: impl Peripheral<P = Tx> + 'd, 139 txdma: impl Peripheral<P = Tx> + 'd,
132 _ch1: impl Peripheral<P = impl DacPin<T, 1>> + 'd, 140 _ch1: impl Peripheral<P = impl DacPin<T, 1>> + 'd,
133 _ch2: impl Peripheral<P = impl DacPin<T, 2>> + 'd, 141 _ch2: impl Peripheral<P = impl DacPin<T, 2>> + 'd,
134 ) -> Self { 142 ) -> Self {
135 into_ref!(peri); 143 into_ref!(peri);
136 Self::new_inner(peri, 2, txdma) 144 Self::new_inner(peri, true, true, txdma)
137 } 145 }
138 146
139 /// Perform initialisation steps for the DAC 147 /// Perform initialisation steps for the DAC
140 fn new_inner(peri: PeripheralRef<'d, T>, channels: u8, txdma: impl Peripheral<P = Tx> + 'd) -> Self { 148 fn new_inner(peri: PeripheralRef<'d, T>, ch1: bool, ch2: bool, txdma: impl Peripheral<P = Tx> + 'd) -> Self {
141 into_ref!(txdma); 149 into_ref!(txdma);
142 T::enable(); 150 T::enable();
143 T::reset(); 151 T::reset();
144 152
145 T::regs().mcr().modify(|reg| { 153 let mut dac = Self {
146 for ch in 0..channels { 154 ch1,
147 reg.set_mode(ch as usize, 0); 155 ch2,
148 reg.set_mode(ch as usize, 0);
149 }
150 });
151
152 T::regs().cr().modify(|reg| {
153 for ch in 0..channels {
154 reg.set_en(ch as usize, true);
155 reg.set_ten(ch as usize, true);
156 }
157 });
158
159 Self {
160 channels,
161 txdma, 156 txdma,
162 _peri: peri, 157 _peri: peri,
158 };
159
160 // Configure each activated channel. All results can be `unwrap`ed since they
161 // will only error if the channel is not configured (i.e. ch1, ch2 are false)
162 if ch1 {
163 dac.set_channel_mode(Channel::Ch1, 0).unwrap();
164 dac.enable_channel(Channel::Ch1).unwrap();
165 dac.set_trigger_enable(Channel::Ch1, true).unwrap();
163 } 166 }
167 if ch2 {
168 dac.set_channel_mode(Channel::Ch2, 0).unwrap();
169 dac.enable_channel(Channel::Ch2).unwrap();
170 dac.set_trigger_enable(Channel::Ch2, true).unwrap();
171 }
172
173 dac
164 } 174 }
165 175
166 /// Check the channel is configured 176 /// Check the channel is configured
167 fn check_channel_exists(&self, ch: Channel) -> Result<(), Error> { 177 fn check_channel_configured(&self, ch: Channel) -> Result<(), Error> {
168 if ch == Channel::Ch2 && self.channels < 2 { 178 if (ch == Channel::Ch1 && !self.ch1) || (ch == Channel::Ch2 && !self.ch2) {
169 Err(Error::UnconfiguredChannel) 179 Err(Error::UnconfiguredChannel)
170 } else { 180 } else {
171 Ok(()) 181 Ok(())
172 } 182 }
173 } 183 }
174 184
175 /// Set the enable register of the given channel 185 /// Enable trigger of the given channel
186 fn set_trigger_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> {
187 self.check_channel_configured(ch)?;
188 T::regs().cr().modify(|reg| {
189 reg.set_ten(ch.index(), on);
190 });
191 Ok(())
192 }
193
194 /// Set mode register of the given channel
195 fn set_channel_mode(&mut self, ch: Channel, val: u8) -> Result<(), Error> {
196 self.check_channel_configured(ch)?;
197 T::regs().mcr().modify(|reg| {
198 reg.set_mode(ch.index(), val);
199 });
200 Ok(())
201 }
202
203 /// Set enable register of the given channel
176 fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> { 204 fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> {
177 self.check_channel_exists(ch)?; 205 self.check_channel_configured(ch)?;
178 T::regs().cr().modify(|reg| { 206 T::regs().cr().modify(|reg| {
179 reg.set_en(ch.index(), on); 207 reg.set_en(ch.index(), on);
180 }); 208 });
@@ -193,7 +221,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
193 221
194 /// Select a new trigger for CH1 (disables the channel) 222 /// Select a new trigger for CH1 (disables the channel)
195 pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> { 223 pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> {
196 self.check_channel_exists(Channel::Ch1)?; 224 self.check_channel_configured(Channel::Ch1)?;
197 unwrap!(self.disable_channel(Channel::Ch1)); 225 unwrap!(self.disable_channel(Channel::Ch1));
198 T::regs().cr().modify(|reg| { 226 T::regs().cr().modify(|reg| {
199 reg.set_tsel1(trigger.tsel()); 227 reg.set_tsel1(trigger.tsel());
@@ -203,7 +231,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
203 231
204 /// Select a new trigger for CH2 (disables the channel) 232 /// Select a new trigger for CH2 (disables the channel)
205 pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> { 233 pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> {
206 self.check_channel_exists(Channel::Ch2)?; 234 self.check_channel_configured(Channel::Ch2)?;
207 unwrap!(self.disable_channel(Channel::Ch2)); 235 unwrap!(self.disable_channel(Channel::Ch2));
208 T::regs().cr().modify(|reg| { 236 T::regs().cr().modify(|reg| {
209 reg.set_tsel2(trigger.tsel()); 237 reg.set_tsel2(trigger.tsel());
@@ -213,7 +241,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
213 241
214 /// Perform a software trigger on `ch` 242 /// Perform a software trigger on `ch`
215 pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> { 243 pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> {
216 self.check_channel_exists(ch)?; 244 self.check_channel_configured(ch)?;
217 T::regs().swtrigr().write(|reg| { 245 T::regs().swtrigr().write(|reg| {
218 reg.set_swtrig(ch.index(), true); 246 reg.set_swtrig(ch.index(), true);
219 }); 247 });
@@ -232,7 +260,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
232 /// 260 ///
233 /// The `value` is written to the corresponding "data holding register" 261 /// The `value` is written to the corresponding "data holding register"
234 pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> { 262 pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> {
235 self.check_channel_exists(ch)?; 263 self.check_channel_configured(ch)?;
236 match value { 264 match value {
237 Value::Bit8(v) => T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)), 265 Value::Bit8(v) => T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)),
238 Value::Bit12Left(v) => T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)), 266 Value::Bit12Left(v) => T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)),
@@ -241,39 +269,61 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
241 Ok(()) 269 Ok(())
242 } 270 }
243 271
244 /// Write `data` to the DAC via DMA. 272 /// Write `data` to the DAC CH1 via DMA.
245 /// 273 ///
246 /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set. 274 /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
247 /// This will configure a circular DMA transfer that periodically outputs the `data`. 275 /// This will configure a circular DMA transfer that periodically outputs the `data`.
248 /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. 276 /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
249 /// 277 ///
250 /// ## Current limitations 278 /// **Important:** Channel 1 has to be configured for the DAC instance!
251 /// - Only CH1 Supported 279 pub async fn write_ch1(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
280 where
281 Tx: Dma<T>,
282 {
283 self.check_channel_configured(Channel::Ch1)?;
284 self.write_inner(data, circular, Channel::Ch1).await
285 }
286
287 /// Write `data` to the DAC CH2 via DMA.
288 ///
289 /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
290 /// This will configure a circular DMA transfer that periodically outputs the `data`.
291 /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
252 /// 292 ///
253 pub async fn write(&mut self, data_ch1: ValueArray<'_>, circular: bool) -> Result<(), Error> 293 /// **Important:** Channel 2 has to be configured for the DAC instance!
294 pub async fn write_ch2(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
295 where
296 Tx: Dma<T>,
297 {
298 self.check_channel_configured(Channel::Ch2)?;
299 self.write_inner(data, circular, Channel::Ch2).await
300 }
301
302 /// Performs the dma write for the given channel.
303 /// TODO: Should self be &mut?
304 async fn write_inner(&self, data_ch1: ValueArray<'_>, circular: bool, channel: Channel) -> Result<(), Error>
254 where 305 where
255 Tx: Dma<T>, 306 Tx: Dma<T>,
256 { 307 {
257 // TODO: Make this a parameter or get it from the struct or so... 308 let channel = channel.index();
258 const CHANNEL: usize = 0;
259 309
260 // Enable DAC and DMA 310 // Enable DAC and DMA
261 T::regs().cr().modify(|w| { 311 T::regs().cr().modify(|w| {
262 w.set_en(CHANNEL, true); 312 w.set_en(channel, true);
263 w.set_dmaen(CHANNEL, true); 313 w.set_dmaen(channel, true);
264 }); 314 });
265 315
266 let tx_request = self.txdma.request(); 316 let tx_request = self.txdma.request();
267 let channel = &self.txdma; 317 let dma_channel = &self.txdma;
268 318
269 // Initiate the correct type of DMA transfer depending on what data is passed 319 // Initiate the correct type of DMA transfer depending on what data is passed
270 let tx_f = match data_ch1 { 320 let tx_f = match data_ch1 {
271 ValueArray::Bit8(buf) => unsafe { 321 ValueArray::Bit8(buf) => unsafe {
272 Transfer::new_write( 322 Transfer::new_write(
273 channel, 323 dma_channel,
274 tx_request, 324 tx_request,
275 buf, 325 buf,
276 T::regs().dhr8r(CHANNEL).as_ptr() as *mut u8, 326 T::regs().dhr8r(channel).as_ptr() as *mut u8,
277 TransferOptions { 327 TransferOptions {
278 circular, 328 circular,
279 half_transfer_ir: false, 329 half_transfer_ir: false,
@@ -283,10 +333,10 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
283 }, 333 },
284 ValueArray::Bit12Left(buf) => unsafe { 334 ValueArray::Bit12Left(buf) => unsafe {
285 Transfer::new_write( 335 Transfer::new_write(
286 channel, 336 dma_channel,
287 tx_request, 337 tx_request,
288 buf, 338 buf,
289 T::regs().dhr12l(CHANNEL).as_ptr() as *mut u16, 339 T::regs().dhr12l(channel).as_ptr() as *mut u16,
290 TransferOptions { 340 TransferOptions {
291 circular, 341 circular,
292 half_transfer_ir: false, 342 half_transfer_ir: false,
@@ -296,10 +346,10 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
296 }, 346 },
297 ValueArray::Bit12Right(buf) => unsafe { 347 ValueArray::Bit12Right(buf) => unsafe {
298 Transfer::new_write( 348 Transfer::new_write(
299 channel, 349 dma_channel,
300 tx_request, 350 tx_request,
301 buf, 351 buf,
302 T::regs().dhr12r(CHANNEL).as_ptr() as *mut u16, 352 T::regs().dhr12r(channel).as_ptr() as *mut u16,
303 TransferOptions { 353 TransferOptions {
304 circular, 354 circular,
305 half_transfer_ir: false, 355 half_transfer_ir: false,
@@ -315,9 +365,9 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
315 // TODO: Do we need to check any status registers here? 365 // TODO: Do we need to check any status registers here?
316 T::regs().cr().modify(|w| { 366 T::regs().cr().modify(|w| {
317 // Disable the DAC peripheral 367 // Disable the DAC peripheral
318 w.set_en(CHANNEL, false); 368 w.set_en(channel, false);
319 // Disable the DMA. TODO: Is this necessary? 369 // Disable the DMA. TODO: Is this necessary?
320 w.set_dmaen(CHANNEL, false); 370 w.set_dmaen(channel, false);
321 }); 371 });
322 372
323 Ok(()) 373 Ok(())