Skip to content

Commit 422fd75

Browse files
MirabellensaftJonas Schievink
authored andcommitted
DAC driver and example
1 parent f966590 commit 422fd75

File tree

3 files changed

+137
-0
lines changed

3 files changed

+137
-0
lines changed

examples/dac_sine.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
//! Example usage for DAC on STM32F303
5+
// Based on example in stm32hal by David-OConnor
6+
7+
use panic_semihosting as _;
8+
9+
use cortex_m_rt::entry;
10+
11+
use stm32f3xx_hal::{
12+
dac::{Dac, DacChannel},
13+
pac,
14+
prelude::*,
15+
};
16+
17+
const LUT_LEN: usize = 256;
18+
19+
// A lookup table for sin(x), over one period, using values from 0 - 4095; ie the full range of
20+
// the STM32 12-bit onboard DAC. Compared to computation, this is faster, at the expense of memory use.
21+
pub static SIN_X: [u16; crate::LUT_LEN] = [
22+
2048, 2098, 2148, 2198, 2248, 2298, 2348, 2398, 2447, 2496, 2545, 2594, 2642, 2690, 2737, 2784,
23+
2831, 2877, 2923, 2968, 3013, 3057, 3100, 3143, 3185, 3226, 3267, 3307, 3346, 3385, 3423, 3459,
24+
3495, 3530, 3565, 3598, 3630, 3662, 3692, 3722, 3750, 3777, 3804, 3829, 3853, 3876, 3898, 3919,
25+
3939, 3958, 3975, 3992, 4007, 4021, 4034, 4045, 4056, 4065, 4073, 4080, 4085, 4089, 4093, 4094,
26+
4095, 4094, 4093, 4089, 4085, 4080, 4073, 4065, 4056, 4045, 4034, 4021, 4007, 3992, 3975, 3958,
27+
3939, 3919, 3898, 3876, 3853, 3829, 3804, 3777, 3750, 3722, 3692, 3662, 3630, 3598, 3565, 3530,
28+
3495, 3459, 3423, 3385, 3346, 3307, 3267, 3226, 3185, 3143, 3100, 3057, 3013, 2968, 2923, 2877,
29+
2831, 2784, 2737, 2690, 2642, 2594, 2545, 2496, 2447, 2398, 2348, 2298, 2248, 2198, 2148, 2098,
30+
2048, 1997, 1947, 1897, 1847, 1797, 1747, 1697, 1648, 1599, 1550, 1501, 1453, 1405, 1358, 1311,
31+
1264, 1218, 1172, 1127, 1082, 1038, 995, 952, 910, 869, 828, 788, 749, 710, 672, 636, 600, 565,
32+
530, 497, 465, 433, 403, 373, 345, 318, 291, 266, 242, 219, 197, 176, 156, 137, 120, 103, 88,
33+
74, 61, 50, 39, 30, 22, 15, 10, 6, 2, 1, 0, 1, 2, 6, 10, 15, 22, 30, 39, 50, 61, 74, 88, 103,
34+
120, 137, 156, 176, 197, 219, 242, 266, 291, 318, 345, 373, 403, 433, 465, 497, 530, 565, 600,
35+
636, 672, 710, 749, 788, 828, 869, 910, 952, 995, 1038, 1082, 1127, 1172, 1218, 1264, 1311,
36+
1358, 1405, 1453, 1501, 1550, 1599, 1648, 1697, 1747, 1797, 1847, 1897, 1947, 1997,
37+
];
38+
39+
#[entry]
40+
/// Main Thread
41+
fn main() -> ! {
42+
// Get peripherals, clocks and freeze them
43+
let dp = pac::Peripherals::take().unwrap();
44+
let mut rcc = dp.RCC.constrain();
45+
// let clocks = rcc.cfgr.freeze(&mut dp.FLASH.constrain().acr);
46+
47+
// Set up pin PA4 as analog pin.
48+
let mut gpioa = dp.GPIOA.split(&mut rcc.ahb);
49+
let _dac1_out1 = gpioa.pa4.into_analog(&mut gpioa.moder, &mut gpioa.pupdr);
50+
51+
// set up led for blinking loop
52+
let mut gpioe = dp.GPIOE.split(&mut rcc.ahb);
53+
let mut ok_led = gpioe
54+
.pe15
55+
.into_push_pull_output(&mut gpioe.moder, &mut gpioe.otyper);
56+
57+
// set up dac1, data is twelve bits, alighned right
58+
let mut dac1 = Dac::new(dp.DAC1, &mut rcc.apb1);
59+
// enable channel one for single channel mode
60+
dac1.enable_channel(DacChannel::One);
61+
62+
let mut led = true;
63+
64+
loop {
65+
// lookup values for sine wave and write in buffer
66+
for value in SIN_X {
67+
dac1.write_data(value);
68+
cortex_m::asm::delay(8_000);
69+
}
70+
if led {
71+
ok_led.set_low().unwrap();
72+
led = false;
73+
} else {
74+
ok_led.set_high().unwrap();
75+
led = true;
76+
}
77+
}
78+
}

src/dac.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//Based on stm32hal by David-OConnor
2+
3+
use cortex_m::asm;
4+
5+
use crate::{
6+
gpio::{self, Analog},
7+
pac::{dac1, DAC1},
8+
rcc::{Rcc, Clocks, AHB, APB1},
9+
};
10+
11+
#[cfg(any(
12+
feature = "stm32f303xb",
13+
feature = "stm32f303xc",
14+
feature = "stm32f303xd",
15+
feature = "stm32f303xe",
16+
))]
17+
use crate::pac::DMA1::{self};
18+
19+
use crate::pac::{self, rcc, RCC};
20+
21+
pub enum DacChannel {
22+
One,
23+
Two,
24+
}
25+
26+
/// Represents a Digital to Analog Converter (DAC) peripheral.
27+
pub struct Dac {
28+
regs: DAC1,
29+
}
30+
31+
// todo: Calculate the VDDA vref, as you do with onboard ADCs!
32+
impl Dac {
33+
/// Initialize a DAC peripheral, including enabling and resetting
34+
35+
pub fn new(regs: DAC1, abp1: &mut APB1) -> Self {
36+
37+
abp1.enr().modify(|_, w| w.dac1en().set_bit());
38+
abp1.rstr().modify(|_, w| w.dac1rst().set_bit());
39+
abp1.rstr().modify(|_, w| w.dac1rst().clear_bit());
40+
41+
Self { regs }
42+
}
43+
44+
pub fn enable_channel(&mut self, channel: DacChannel) {
45+
let cr = &self.regs.cr;
46+
47+
cr.modify(|_, w| match channel {
48+
DacChannel::One => w.en1().set_bit(),
49+
DacChannel::Two => w.en2().set_bit(),
50+
});
51+
}
52+
53+
/// the data parameter MUST be a 12-bit value -- values outside that range will result in misbehavior
54+
pub fn write_data(&mut self, data: u16) {
55+
56+
self.regs.dhr12r1.write(|w| w.dacc1dhr().bits(data))
57+
}
58+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ pub mod adc;
187187
#[cfg(all(feature = "can", not(feature = "svd-f301")))]
188188
#[cfg_attr(docsrs, doc(cfg(feature = "can")))]
189189
pub mod can;
190+
pub mod dac;
190191
pub mod delay;
191192
pub mod dma;
192193
pub mod flash;

0 commit comments

Comments
 (0)