Skip to content

Commit bfea76e

Browse files
committed
Add hrtim examples
1 parent fcad567 commit bfea76e

File tree

11 files changed

+1348
-10
lines changed

11 files changed

+1348
-10
lines changed

Cargo.toml

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,19 @@ codegen-units = 1
140140
incremental = false
141141
lto = true
142142

143+
[[test]]
144+
name = "nucleo-g474"
145+
harness = false
146+
required-features = ["stm32g474", "defmt", "cordic"]
147+
148+
[[test]]
149+
name = "nucleo-g474_w_jumpers"
150+
harness = false
151+
required-features = ["stm32g474", "defmt"]
152+
153+
[lib]
154+
test = false
155+
143156
[[example]]
144157
name = "can-echo"
145158
required-features = ["can"]
@@ -156,15 +169,52 @@ required-features = ["usb"]
156169
name = "cordic"
157170
required-features = ["cordic"]
158171

159-
[[test]]
160-
name = "nucleo-g474"
161-
harness = false
162-
required-features = ["stm32g474", "defmt", "cordic"]
172+
[[example]]
173+
name = "hrtim-adc-trigger"
174+
required-features = ["hrtim"]
175+
path = "examples/hrtim/adc-trigger.rs"
163176

164-
[[test]]
165-
name = "nucleo-g474_w_jumpers"
166-
harness = false
167-
required-features = ["stm32g474", "defmt", "cordic"]
177+
[[example]]
178+
name = "hrtim-capture"
179+
required-features = ["hrtim"]
180+
path = "examples/hrtim/capture.rs"
168181

169-
[lib]
170-
test = false
182+
[[example]]
183+
name = "hrtim-deadtime"
184+
required-features = ["hrtim"]
185+
path = "examples/hrtim/deadtime.rs"
186+
187+
[[example]]
188+
name = "hrtim-capture-dma"
189+
required-features = ["hrtim"]
190+
path = "examples/hrtim/capture-dma.rs"
191+
192+
[[example]]
193+
name = "hrtim-eev-comp"
194+
required-features = ["hrtim"]
195+
path = "examples/hrtim/eev-comp.rs"
196+
197+
[[example]]
198+
name = "hrtim-eev"
199+
required-features = ["hrtim"]
200+
path = "examples/hrtim/eev.rs"
201+
202+
[[example]]
203+
name = "hrtim-flt-comp"
204+
required-features = ["hrtim"]
205+
path = "examples/hrtim/flt-comp.rs"
206+
207+
[[example]]
208+
name = "hrtim-flt"
209+
required-features = ["hrtim"]
210+
path = "examples/hrtim/flt.rs"
211+
212+
[[example]]
213+
name = "hrtim"
214+
required-features = ["hrtim"]
215+
path = "examples/hrtim/hrtim.rs"
216+
217+
[[example]]
218+
name = "hrtim-master"
219+
required-features = ["hrtim"]
220+
path = "examples/hrtim/master.rs"

examples/hrtim/adc-trigger.rs

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

examples/hrtim/capture-dma.rs

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

0 commit comments

Comments
 (0)