diff options
| author | JuliDi <[email protected]> | 2023-06-23 12:14:40 +0200 |
|---|---|---|
| committer | JuliDi <[email protected]> | 2023-06-23 12:14:40 +0200 |
| commit | 915f79c974ace037e914397b42eb9d2448bd5ca3 (patch) | |
| tree | e3cf5740b8c5da95b89a00a068c3329043c64521 | |
| parent | ea04a0277bb19719188e904a86e28c34f9801c96 (diff) | |
allow independent use of ch1 and ch2 on dac
| -rw-r--r-- | embassy-stm32/src/dac/mod.rs | 150 |
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 | ||
| 24 | impl Channel { | 24 | impl 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 | ||
| 111 | pub struct Dac<'d, T: Instance, Tx> { | 111 | pub 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 | ||
| 117 | impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { | 118 | impl<'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(()) |
