Skip to content

Commit e9921b7

Browse files
committed
Add and fix examples
1 parent 1104866 commit e9921b7

File tree

10 files changed

+1208
-0
lines changed

10 files changed

+1208
-0
lines changed

Cargo.toml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ stm32g4xx-hal = { git = "https://github.com/stm32-rs/stm32g4xx-hal", branch = "s
1818
defmt = { version = "0.3.10", optional = true }
1919
fugit = "0.3.7"
2020

21+
[dev-dependencies]
22+
cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] }
23+
defmt-rtt = "0.4.0"
24+
cortex-m-rt = "0.7.2"
25+
panic-probe = { version = "0.3.0", features = ["print-defmt"] }
26+
2127
[features]
2228
default = []
2329

@@ -45,3 +51,48 @@ stm32h753 = ["stm32h7", "stm32h7xx-hal/stm32h753", "hrtim_v1_1"]
4551
stm32g474 = ["stm32g4", "stm32g4xx-hal/stm32g474", "hrtim_v2"]
4652
stm32g484 = ["stm32g4", "stm32g4xx-hal/stm32g484", "hrtim_v2"]
4753
defmt = ["dep:defmt", "fugit/defmt"]
54+
55+
[[example]]
56+
name = "stm32g4-adc-trigger"
57+
required-features = ["stm32g4"]
58+
path = "examples/stm32g4/adc-trigger.rs"
59+
60+
[[example]]
61+
name = "stm32g4-capture"
62+
required-features = ["stm32g4"]
63+
path = "examples/stm32g4/capture.rs"
64+
65+
[[example]]
66+
name = "stm32g4-capture-dma"
67+
required-features = ["stm32g4"]
68+
path = "examples/stm32g4/capture-dma.rs"
69+
70+
[[example]]
71+
name = "stm32g4-eev-comp"
72+
required-features = ["stm32g4"]
73+
path = "examples/stm32g4/eev-comp.rs"
74+
75+
[[example]]
76+
name = "stm32g4-eev"
77+
required-features = ["stm32g4"]
78+
path = "examples/stm32g4/eev.rs"
79+
80+
[[example]]
81+
name = "stm32g4-flt-comp"
82+
required-features = ["stm32g4"]
83+
path = "examples/stm32g4/flt-comp.rs"
84+
85+
[[example]]
86+
name = "stm32g4-flt"
87+
required-features = ["stm32g4"]
88+
path = "examples/stm32g4/flt.rs"
89+
90+
[[example]]
91+
name = "stm32g4"
92+
required-features = ["stm32g4"]
93+
path = "examples/stm32g4/hrtim.rs"
94+
95+
[[example]]
96+
name = "stm32g4-master"
97+
required-features = ["stm32g4"]
98+
path = "examples/stm32g4/master.rs"

examples/stm32g4/adc-trigger.rs

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
/// Example showcasing the use of the HRTIM peripheral to trigger the ADC at various points of the switch cycle off HRTIM_TIMA
5+
use cortex_m_rt::entry;
6+
use panic_probe as _;
7+
use stm32_hrtim::{
8+
compare_register::HrCompareRegister, control::HrControltExt, output::HrOutput, timer::HrTimer,
9+
HrParts, HrPwmAdvExt, Pscl4,
10+
};
11+
use stm32g4xx_hal::{
12+
adc::{self, AdcClaim, ClockSource, Temperature, Vref},
13+
delay::SYSTDelayExt,
14+
dma::{self, channel::DMAExt, config::DmaConfig, TransferExt},
15+
gpio::GpioExt,
16+
pwr::PwrExt,
17+
rcc::{self, RccExt},
18+
stm32::{CorePeripherals, Peripherals},
19+
};
20+
21+
#[entry]
22+
fn main() -> ! {
23+
const VREF: f32 = 3.3;
24+
25+
defmt::info!("start");
26+
27+
let dp = Peripherals::take().unwrap();
28+
let cp = CorePeripherals::take().expect("cannot take core peripherals");
29+
30+
// Set system frequency to 16MHz * 15/1/2 = 120MHz
31+
// This would lead to HrTim running at 120MHz * 32 = 3.84...
32+
defmt::info!("rcc");
33+
let pwr = dp.PWR.constrain().freeze();
34+
let mut rcc = dp.RCC.freeze(
35+
rcc::Config::pll().pll_cfg(rcc::PllConfig {
36+
mux: rcc::PllSrc::HSI,
37+
n: rcc::PllNMul::MUL_15,
38+
m: rcc::PllMDiv::DIV_1,
39+
r: Some(rcc::PllRDiv::DIV_2),
40+
41+
..Default::default()
42+
}),
43+
pwr,
44+
);
45+
46+
let mut delay = cp.SYST.delay(&rcc.clocks);
47+
48+
let dma::channel::Channels { ch1: dma1ch1, .. } = dp.DMA1.split(&rcc);
49+
let config = DmaConfig::default()
50+
.transfer_complete_interrupt(true)
51+
.circular_buffer(true)
52+
.memory_increment(true);
53+
54+
defmt::info!("Setup Gpio");
55+
let gpioa = dp.GPIOA.split(&mut rcc);
56+
let pa0 = gpioa.pa0.into_analog();
57+
58+
let pin_a = gpioa.pa8;
59+
let pin_b = gpioa.pa9;
60+
61+
// ...with a prescaler of 4 this gives us a HrTimer with a tick rate of 960MHz
62+
// With max the max period set, this would be 960MHz/2^16 ~= 15kHz...
63+
let prescaler = Pscl4;
64+
65+
// . .
66+
// . 50% .
67+
// ------ ------
68+
//out1 | | | |
69+
// | | | |
70+
// -------- ---------- --------
71+
// . ^ ^
72+
// . | |
73+
//AD samlp pa0 temp
74+
let period = 0xFFFF;
75+
let (hr_control, ..) = dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration();
76+
let mut hr_control = hr_control.constrain();
77+
let HrParts {
78+
mut timer,
79+
mut cr1,
80+
mut cr3,
81+
mut cr4,
82+
out: (mut out1, mut out2),
83+
..
84+
} = dp
85+
.HRTIM_TIMA
86+
.pwm_advanced((pin_a, pin_b), &mut rcc)
87+
.prescaler(prescaler)
88+
.period(period)
89+
.finalize(&mut hr_control);
90+
91+
cr1.set_duty(period / 2);
92+
cr3.set_duty(period / 3);
93+
cr4.set_duty((2 * u32::from(period) / 3) as u16);
94+
95+
hr_control.adc_trigger1.enable_source(&cr3);
96+
hr_control.adc_trigger1.enable_source(&cr4);
97+
98+
out1.enable_rst_event(&cr1); // Set low on compare match with cr1
99+
out2.enable_rst_event(&cr1);
100+
101+
out1.enable_set_event(&timer); // Set high at new period
102+
out2.enable_set_event(&timer);
103+
104+
defmt::info!("Setup Adc1");
105+
let mut adc = dp
106+
.ADC1
107+
.claim(ClockSource::SystemClock, &rcc, &mut delay, true);
108+
109+
// TODO: Add the three lines below once the hal has been updated or this example will not work
110+
//adc.set_external_trigger((
111+
// adc::config::TriggerMode::RisingEdge,
112+
// &hr_control.adc_trigger1,
113+
//));
114+
adc.enable_temperature(&dp.ADC12_COMMON);
115+
adc.set_continuous(adc::config::Continuous::Discontinuous);
116+
adc.reset_sequence();
117+
adc.configure_channel(
118+
&pa0,
119+
adc::config::Sequence::One,
120+
adc::config::SampleTime::Cycles_640_5,
121+
);
122+
adc.configure_channel(
123+
&Temperature,
124+
adc::config::Sequence::Two,
125+
adc::config::SampleTime::Cycles_640_5,
126+
);
127+
128+
defmt::info!("Setup DMA");
129+
let first_buffer = cortex_m::singleton!(: [u16; 10] = [0; 10]).unwrap();
130+
131+
let mut transfer = dma1ch1.into_circ_peripheral_to_memory_transfer(
132+
adc.enable_dma(adc::config::Dma::Continuous),
133+
&mut first_buffer[..],
134+
config,
135+
);
136+
137+
transfer.start(|adc| adc.start_conversion());
138+
139+
out1.enable();
140+
out2.enable();
141+
142+
timer.start(&mut hr_control.control);
143+
144+
loop {
145+
let mut b = [0_u16; 4];
146+
let r = transfer.read_exact(&mut b);
147+
148+
defmt::info!("read: {}", r);
149+
assert!(r == b.len());
150+
151+
let millivolts = Vref::sample_to_millivolts((b[0] + b[2]) / 2);
152+
defmt::info!("pa3: {}mV", millivolts);
153+
let temp = Temperature::temperature_to_degrees_centigrade(
154+
(b[1] + b[3]) / 2,
155+
VREF,
156+
adc::config::Resolution::Twelve,
157+
);
158+
defmt::info!("temp: {}℃C", temp);
159+
}
160+
}

examples/stm32g4/capture-dma.rs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
/// Example showcasing the use of the HRTIM peripheral's capture function to detect phase shift between a digital event and the output of HRTIM_TIMA
5+
use cortex_m_rt::entry;
6+
use panic_probe as _;
7+
use stm32_hrtim::{
8+
capture,
9+
compare_register::HrCompareRegister,
10+
control::HrControltExt,
11+
external_event::{self, ToExternalEventSource},
12+
output::HrOutput,
13+
timer::{HrSlaveTimerCpt, HrTimer, TimerSplitCapture},
14+
HrParts, HrPwmAdvExt, Pscl128,
15+
};
16+
use stm32g4xx_hal::{
17+
dma::{channel::DMAExt, config::DmaConfig, TransferExt},
18+
gpio::GpioExt,
19+
pwr::PwrExt,
20+
rcc::{self, RccExt},
21+
stm32::Peripherals,
22+
};
23+
24+
#[entry]
25+
fn main() -> ! {
26+
defmt::info!("start");
27+
28+
let dp = Peripherals::take().unwrap();
29+
30+
// Set system frequency to 16MHz * 15/1/2 = 120MHz
31+
// This would lead to HrTim running at 120MHz * 32 = 3.84...
32+
defmt::info!("rcc");
33+
let pwr = dp.PWR.constrain().freeze();
34+
let mut rcc = dp.RCC.freeze(
35+
rcc::Config::pll().pll_cfg(rcc::PllConfig {
36+
mux: rcc::PllSrc::HSI,
37+
n: rcc::PllNMul::MUL_15,
38+
m: rcc::PllMDiv::DIV_1,
39+
r: Some(rcc::PllRDiv::DIV_2),
40+
41+
..Default::default()
42+
}),
43+
pwr,
44+
);
45+
46+
defmt::info!("Setup Gpio");
47+
let gpioa = dp.GPIOA.split(&mut rcc);
48+
let gpiob = dp.GPIOB.split(&mut rcc);
49+
50+
// PA8 (D7 on Nucleo G474RE)
51+
let pin_a = gpioa.pa8;
52+
53+
// PB5 (D4 on Nucleo G474RE)
54+
let input = gpiob.pb5.into_pull_down_input();
55+
56+
// ...with a prescaler of 128 this gives us a HrTimer with a tick rate of 30MHz
57+
// With max the max period set, this would be 30MHz/2^16 ~= 458Hz...
58+
let prescaler = Pscl128;
59+
60+
// t1 t2 .
61+
// | | .
62+
// v v .
63+
// . .
64+
// . 50% .
65+
// ------ ------
66+
//out1 | | | |
67+
// | | | |
68+
// -------- ---------- --------
69+
let period = 0xFFFF;
70+
let (mut hr_control, _flt_inputs, eev_inputs) =
71+
dp.HRTIM_COMMON.hr_control(&mut rcc).wait_for_calibration();
72+
73+
let eev_input6 = eev_inputs
74+
.eev_input6
75+
.bind(input)
76+
.edge_or_polarity(external_event::EdgeOrPolarity::Edge(
77+
external_event::Edge::Both,
78+
))
79+
.finalize(&mut hr_control);
80+
81+
let mut hr_control = hr_control.constrain();
82+
let HrParts {
83+
timer,
84+
mut cr1,
85+
out: mut out1,
86+
dma_channel,
87+
..
88+
} = dp
89+
.HRTIM_TIMA
90+
.pwm_advanced(pin_a, &mut rcc)
91+
.prescaler(prescaler)
92+
.period(period)
93+
.finalize(&mut hr_control);
94+
out1.enable_rst_event(&cr1); // Set low on compare match with cr1
95+
out1.enable_set_event(&timer); // Set high at new period
96+
cr1.set_duty(period / 2);
97+
98+
let TimerSplitCapture {
99+
mut timer,
100+
ch1: mut capture,
101+
..
102+
} = timer.split_capture();
103+
timer.start(&mut hr_control.control);
104+
out1.enable();
105+
106+
capture.enable_interrupt(true, &mut hr_control);
107+
capture.add_event(&eev_input6);
108+
109+
defmt::info!("Setup DMA");
110+
let channels = dp.DMA1.split(&rcc);
111+
let config = DmaConfig::default()
112+
.transfer_complete_interrupt(false)
113+
.circular_buffer(true)
114+
.memory_increment(true);
115+
116+
let first_buffer = cortex_m::singleton!(: [u32; 16] = [0; 16]).unwrap();
117+
let mut transfer = channels.ch1.into_circ_peripheral_to_memory_transfer(
118+
capture.enable_dma(dma_channel),
119+
&mut first_buffer[..],
120+
config,
121+
);
122+
123+
transfer.start(|_| ());
124+
125+
let mut old_duty = 0;
126+
loop {
127+
for duty in (u32::from(period) / 10)..(9 * u32::from(period) / 10) {
128+
let mut data = [0; 2];
129+
transfer.read_exact(&mut data);
130+
let [t1, t2] = data.map(|x| capture::dma_value_to_signed(x, period));
131+
cr1.set_duty(duty as u16);
132+
defmt::info!("Capture: t1: {}, t2: {}, duty: {}, ", t1, t2, old_duty);
133+
old_duty = duty;
134+
}
135+
}
136+
}

0 commit comments

Comments
 (0)