aboutsummaryrefslogtreecommitdiff
path: root/examples/stm32l4/src/bin/dac_dma.rs
blob: 44edec72897183321b7a939d6c0ce8adb1f5b736 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#![no_std]
#![no_main]

use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::dac::{DacCh1, DacCh2, ValueArray};
use embassy_stm32::mode::Async;
use embassy_stm32::pac::timer::vals::Mms;
use embassy_stm32::peripherals::{DAC1, TIM6, TIM7};
use embassy_stm32::rcc::frequency;
use embassy_stm32::time::Hertz;
use embassy_stm32::timer::low_level::Timer;
use embassy_stm32::Peri;
use micromath::F32Ext;
use {defmt_rtt as _, panic_probe as _};

#[embassy_executor::main]
async fn main(spawner: Spawner) {
    let config = embassy_stm32::Config::default();

    // Initialize the board and obtain a Peripherals instance
    let p: embassy_stm32::Peripherals = embassy_stm32::init(config);

    // Obtain two independent channels (p.DAC1 can only be consumed once, though!)
    let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split();

    spawner.spawn(dac_task1(p.TIM6, dac_ch1).unwrap());
    spawner.spawn(dac_task2(p.TIM7, dac_ch2).unwrap());
}

#[embassy_executor::task]
async fn dac_task1(tim: Peri<'static, TIM6>, mut dac: DacCh1<'static, DAC1, Async>) {
    let data: &[u8; 256] = &calculate_array::<256>();

    info!("TIM6 frequency is {}", frequency::<TIM6>());
    const FREQUENCY: Hertz = Hertz::hz(200);

    // Compute the reload value such that we obtain the FREQUENCY for the sine
    let reload: u32 = (frequency::<TIM6>().0 / FREQUENCY.0) / data.len() as u32;

    // Depends on your clock and on the specific chip used, you may need higher or lower values here
    if reload < 10 {
        error!("Reload value {} below threshold!", reload);
    }

    dac.set_trigger(embassy_stm32::dac::TriggerSel::Tim6);
    dac.set_triggering(true);
    dac.enable();

    let tim = Timer::new(tim);
    tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1));
    tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE));
    tim.regs_basic().cr1().modify(|w| {
        w.set_opm(false);
        w.set_cen(true);
    });

    debug!(
        "TIM6 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}",
        frequency::<TIM6>(),
        FREQUENCY,
        reload,
        reload as u16,
        data.len()
    );

    // Loop technically not necessary if DMA circular mode is enabled
    loop {
        info!("Loop DAC1");
        dac.write(ValueArray::Bit8(data), true).await;
    }
}

#[embassy_executor::task]
async fn dac_task2(tim: Peri<'static, TIM7>, mut dac: DacCh2<'static, DAC1, Async>) {
    let data: &[u8; 256] = &calculate_array::<256>();

    info!("TIM7 frequency is {}", frequency::<TIM7>());

    const FREQUENCY: Hertz = Hertz::hz(600);
    let reload: u32 = (frequency::<TIM7>().0 / FREQUENCY.0) / data.len() as u32;

    if reload < 10 {
        error!("Reload value {} below threshold!", reload);
    }

    let tim = Timer::new(tim);
    tim.regs_basic().arr().modify(|w| w.set_arr(reload as u16 - 1));
    tim.regs_basic().cr2().modify(|w| w.set_mms(Mms::UPDATE));
    tim.regs_basic().cr1().modify(|w| {
        w.set_opm(false);
        w.set_cen(true);
    });

    dac.set_trigger(embassy_stm32::dac::TriggerSel::Tim7);
    dac.set_triggering(true);
    dac.enable();

    debug!(
        "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}",
        frequency::<TIM7>(),
        FREQUENCY,
        reload,
        reload as u16,
        data.len()
    );

    dac.write(ValueArray::Bit8(data), true).await;
}

fn to_sine_wave(v: u8) -> u8 {
    if v >= 128 {
        // top half
        let r = 3.14 * ((v - 128) as f32 / 128.0);
        (r.sin() * 128.0 + 127.0) as u8
    } else {
        // bottom half
        let r = 3.14 + 3.14 * (v as f32 / 128.0);
        (r.sin() * 128.0 + 127.0) as u8
    }
}

fn calculate_array<const N: usize>() -> [u8; N] {
    let mut res = [0; N];
    let mut i = 0;
    while i < N {
        res[i] = to_sine_wave(i as u8);
        i += 1;
    }
    res
}