Skip to content

Commit e4f8609

Browse files
committed
Add hrtim examples
1 parent 0579900 commit e4f8609

File tree

10 files changed

+1158
-5
lines changed

10 files changed

+1158
-5
lines changed

Cargo.toml

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,13 @@ codegen-units = 1
129129
incremental = false
130130
lto = true
131131

132+
[[test]]
133+
name = "tests"
134+
harness = false
135+
136+
[lib]
137+
test = false
138+
132139
[[example]]
133140
name = "flash_with_rtic"
134141
required-features = ["stm32g474"]
@@ -141,9 +148,47 @@ required-features = ["usb"]
141148
name = "cordic"
142149
required-features = ["cordic"]
143150

144-
[[test]]
145-
name = "tests"
146-
harness = false
151+
[[example]]
152+
name = "hrtim-adc-trigger"
153+
required-features = ["hrtim"]
154+
path = "examples/hrtim/adc-trigger.rs"
147155

148-
[lib]
149-
test = false
156+
[[example]]
157+
name = "hrtim-capture"
158+
required-features = ["hrtim"]
159+
path = "examples/hrtim/capture.rs"
160+
161+
[[example]]
162+
name = "hrtim-capture-dma"
163+
required-features = ["hrtim"]
164+
path = "examples/hrtim/capture-dma.rs"
165+
166+
[[example]]
167+
name = "hrtim-eev-comp"
168+
required-features = ["hrtim"]
169+
path = "examples/hrtim/eev-comp.rs"
170+
171+
[[example]]
172+
name = "hrtim-eev"
173+
required-features = ["hrtim"]
174+
path = "examples/hrtim/eev.rs"
175+
176+
[[example]]
177+
name = "hrtim-flt-comp"
178+
required-features = ["hrtim"]
179+
path = "examples/hrtim/flt-comp.rs"
180+
181+
[[example]]
182+
name = "hrtim-flt"
183+
required-features = ["hrtim"]
184+
path = "examples/hrtim/flt.rs"
185+
186+
[[example]]
187+
name = "hrtim"
188+
required-features = ["hrtim"]
189+
path = "examples/hrtim/hrtim.rs"
190+
191+
[[example]]
192+
name = "hrtim-master"
193+
required-features = ["hrtim"]
194+
path = "examples/hrtim/master.rs"

examples/hrtim/adc-trigger.rs

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

examples/hrtim/capture-dma.rs

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

0 commit comments

Comments
 (0)