aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuliDi <[email protected]>2023-06-19 13:42:25 +0200
committerJuliDi <[email protected]>2023-06-19 13:42:25 +0200
commitfe7b72948ab5d3682f23e305f3eb7186cc308b1b (patch)
tree8870f86008252c280f94f94f1ef2a51d0b87d6e5
parente0747e937f06ed280594e17c97d19784410b6e85 (diff)
add ValueArray type and respective write functions
-rw-r--r--embassy-stm32/src/dac/mod.rs210
1 files changed, 126 insertions, 84 deletions
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 525d45d72..4384a7c34 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -98,6 +98,14 @@ pub enum Value {
98 Bit12(u16, Alignment), 98 Bit12(u16, Alignment),
99} 99}
100 100
101#[derive(Debug, Copy, Clone, Eq, PartialEq)]
102#[cfg_attr(feature = "defmt", derive(defmt::Format))]
103pub enum ValueArray<'a> {
104 Bit8(&'a [u8]),
105 Bit12Left(&'a [u16]),
106 Bit12Right(&'a [u16]),
107}
108
101pub struct Dac<'d, T: Instance, Tx> { 109pub struct Dac<'d, T: Instance, Tx> {
102 channels: u8, 110 channels: u8,
103 txdma: PeripheralRef<'d, Tx>, 111 txdma: PeripheralRef<'d, Tx>,
@@ -129,21 +137,19 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
129 T::enable(); 137 T::enable();
130 T::reset(); 138 T::reset();
131 139
132 unsafe { 140 T::regs().mcr().modify(|reg| {
133 T::regs().mcr().modify(|reg| { 141 for ch in 0..channels {
134 for ch in 0..channels { 142 reg.set_mode(ch as usize, 0);
135 reg.set_mode(ch as usize, 0); 143 reg.set_mode(ch as usize, 0);
136 reg.set_mode(ch as usize, 0); 144 }
137 } 145 });
138 }); 146
139 147 T::regs().cr().modify(|reg| {
140 T::regs().cr().modify(|reg| { 148 for ch in 0..channels {
141 for ch in 0..channels { 149 reg.set_en(ch as usize, true);
142 reg.set_en(ch as usize, true); 150 reg.set_ten(ch as usize, true);
143 reg.set_ten(ch as usize, true); 151 }
144 } 152 });
145 });
146 }
147 153
148 Self { 154 Self {
149 channels, 155 channels,
@@ -161,13 +167,12 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
161 } 167 }
162 } 168 }
163 169
170 /// Set the enable register of the given channel
164 fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> { 171 fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> {
165 self.check_channel_exists(ch)?; 172 self.check_channel_exists(ch)?;
166 unsafe { 173 T::regs().cr().modify(|reg| {
167 T::regs().cr().modify(|reg| { 174 reg.set_en(ch.index(), on);
168 reg.set_en(ch.index(), on); 175 });
169 })
170 }
171 Ok(()) 176 Ok(())
172 } 177 }
173 178
@@ -179,112 +184,149 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
179 self.set_channel_enable(ch, false) 184 self.set_channel_enable(ch, false)
180 } 185 }
181 186
187 /// Performs all register accesses necessary to select a new trigger for CH1
182 pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> { 188 pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> {
183 self.check_channel_exists(Channel::Ch1)?; 189 self.check_channel_exists(Channel::Ch1)?;
184 unwrap!(self.disable_channel(Channel::Ch1)); 190 unwrap!(self.disable_channel(Channel::Ch1));
185 unsafe { 191 T::regs().cr().modify(|reg| {
186 T::regs().cr().modify(|reg| { 192 reg.set_tsel1(trigger.tsel());
187 reg.set_tsel1(trigger.tsel()); 193 });
188 })
189 }
190 Ok(()) 194 Ok(())
191 } 195 }
192 196
197 /// Performs all register accesses necessary to select a new trigger for CH2
193 pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> { 198 pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> {
194 self.check_channel_exists(Channel::Ch2)?; 199 self.check_channel_exists(Channel::Ch2)?;
195 unwrap!(self.disable_channel(Channel::Ch2)); 200 unwrap!(self.disable_channel(Channel::Ch2));
196 unsafe { 201 T::regs().cr().modify(|reg| {
197 T::regs().cr().modify(|reg| { 202 reg.set_tsel2(trigger.tsel());
198 reg.set_tsel2(trigger.tsel()); 203 });
199 })
200 }
201 Ok(()) 204 Ok(())
202 } 205 }
203 206
207 /// Perform a software trigger on a given channel
204 pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> { 208 pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> {
205 self.check_channel_exists(ch)?; 209 self.check_channel_exists(ch)?;
206 unsafe { 210 T::regs().swtrigr().write(|reg| {
207 T::regs().swtrigr().write(|reg| { 211 reg.set_swtrig(ch.index(), true);
208 reg.set_swtrig(ch.index(), true); 212 });
209 });
210 }
211 Ok(()) 213 Ok(())
212 } 214 }
213 215
216 /// Perform a software trigger on all channels
214 pub fn trigger_all(&mut self) { 217 pub fn trigger_all(&mut self) {
215 unsafe { 218 T::regs().swtrigr().write(|reg| {
216 T::regs().swtrigr().write(|reg| { 219 reg.set_swtrig(Channel::Ch1.index(), true);
217 reg.set_swtrig(Channel::Ch1.index(), true); 220 reg.set_swtrig(Channel::Ch2.index(), true);
218 reg.set_swtrig(Channel::Ch2.index(), true); 221 });
219 })
220 }
221 } 222 }
222 223
223 pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> { 224 pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> {
224 self.check_channel_exists(ch)?; 225 self.check_channel_exists(ch)?;
225 match value { 226 match value {
226 Value::Bit8(v) => unsafe { 227 Value::Bit8(v) => T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)),
227 T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)); 228 Value::Bit12(v, Alignment::Left) => T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)),
228 }, 229 Value::Bit12(v, Alignment::Right) => T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v)),
229 Value::Bit12(v, Alignment::Left) => unsafe {
230 T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v));
231 },
232 Value::Bit12(v, Alignment::Right) => unsafe {
233 T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v));
234 },
235 } 230 }
236 Ok(()) 231 Ok(())
237 } 232 }
238 233
234 /// Write `data` to the DAC via DMA.
235 ///
236 /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
237 /// This will configure a circular DMA transfer that periodically outputs the `data`.
238 ///
239 /// ## Current limitations
240 /// - Only CH1 Supported
241 ///
239 /// TODO: Allow an array of Value instead of only u16, right-aligned 242 /// TODO: Allow an array of Value instead of only u16, right-aligned
240 pub async fn write(&mut self, data: &[u16], circular: bool) -> Result<(), Error> 243 pub async fn write_8bit(&mut self, data_ch1: &[u8], circular: bool) -> Result<(), Error>
244 where
245 Tx: Dma<T>,
246 {
247 self.write_inner(ValueArray::Bit8(data_ch1), circular).await
248 }
249
250 pub async fn write_12bit_right_aligned(&mut self, data_ch1: &[u16], circular: bool) -> Result<(), Error>
251 where
252 Tx: Dma<T>,
253 {
254 self.write_inner(ValueArray::Bit12Right(data_ch1), circular).await
255 }
256
257 pub async fn write_12bit_left_aligned(&mut self, data_ch1: &[u16], circular: bool) -> Result<(), Error>
258 where
259 Tx: Dma<T>,
260 {
261 self.write_inner(ValueArray::Bit12Left(data_ch1), circular).await
262 }
263
264 async fn write_inner(&mut self, data_ch1: ValueArray<'_>, circular: bool) -> Result<(), Error>
241 where 265 where
242 Tx: Dma<T>, 266 Tx: Dma<T>,
243 { 267 {
244 // TODO: Make this a parameter or get it from the struct or so... 268 // TODO: Make this a parameter or get it from the struct or so...
245 const CHANNEL: usize = 0; 269 const CHANNEL: usize = 0;
246 270
247 //debug!("Starting DAC"); 271 // Enable DAC and DMA
248 unsafe { 272 T::regs().cr().modify(|w| {
249 T::regs().cr().modify(|w| { 273 w.set_en(CHANNEL, true);
250 w.set_en(CHANNEL, true); 274 w.set_dmaen(CHANNEL, true);
251 w.set_dmaen(CHANNEL, true); 275 });
252 });
253 }
254 276
255 let tx_request = self.txdma.request(); 277 let tx_request = self.txdma.request();
256 278
257 // Use the 12 bit right-aligned register for now. TODO: distinguish values 279 // Initiate the correct type of DMA transfer depending on what data is passed
258 let tx_dst = T::regs().dhr12r(CHANNEL).ptr() as *mut u16; 280 let tx_f = match data_ch1 {
259 281 ValueArray::Bit8(buf) => unsafe {
260 let tx_f = unsafe { 282 Transfer::new_write(
261 Transfer::new_write( 283 &mut self.txdma,
262 &mut self.txdma, 284 tx_request,
263 tx_request, 285 buf,
264 data, 286 T::regs().dhr8r(CHANNEL).as_ptr() as *mut u8,
265 tx_dst, 287 TransferOptions {
266 TransferOptions { 288 circular,
267 circular, 289 halt_transfer_ir: false,
268 halt_transfer_ir: false, 290 },
269 }, 291 )
270 ) 292 },
293 ValueArray::Bit12Left(buf) => unsafe {
294 Transfer::new_write(
295 &mut self.txdma,
296 tx_request,
297 buf,
298 T::regs().dhr12l(CHANNEL).as_ptr() as *mut u16,
299 TransferOptions {
300 circular,
301 halt_transfer_ir: false,
302 },
303 )
304 },
305 ValueArray::Bit12Right(buf) => unsafe {
306 Transfer::new_write(
307 &mut self.txdma,
308 tx_request,
309 buf,
310 T::regs().dhr12r(CHANNEL).as_ptr() as *mut u16,
311 TransferOptions {
312 circular,
313 halt_transfer_ir: false,
314 },
315 )
316 },
271 }; 317 };
272 318
273 //debug!("Awaiting tx_f");
274
275 tx_f.await; 319 tx_f.await;
276 320
277 // finish dma 321 // finish dma
278 unsafe { 322 // TODO: Do we need to check any status registers here?
279 // TODO: Do we need to check any status registers here? 323 T::regs().cr().modify(|w| {
280 324 // Disable the DAC peripheral
281 T::regs().cr().modify(|w| { 325 w.set_en(CHANNEL, false);
282 // Disable the dac peripheral 326 // Disable the DMA. TODO: Is this necessary?
283 w.set_en(CHANNEL, false); 327 w.set_dmaen(CHANNEL, false);
284 // Disable the DMA. TODO: Is this necessary? 328 });
285 w.set_dmaen(CHANNEL, false); 329
286 });
287 }
288 Ok(()) 330 Ok(())
289 } 331 }
290} 332}