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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]
use panic_halt as _;
#[rtic::app(device = stm32f4xx_hal::pac, peripherals = true)]
mod app {
use stm32f4xx_hal::pac::ADC1;
use stm32f4xx_hal::{
adc::{
config::{AdcConfig, SampleTime},
Adc,
},
gpio::{self, Analog, Edge, Input, Output, PushPull},
pac::TIM1,
prelude::*,
timer,
};
use defmt_rtt as _;
// A simple placeholder for the analog pin
struct Potentiometer {
analog_input: gpio::PA1<Analog>,
}
// Resources shared between tasks
#[shared]
struct Shared {
delayval: u32,
adc_module: Adc<ADC1>,
}
// Local resources to specific tasks (cannot be shared)
#[local]
struct Local {
button: gpio::PA0<Input>,
pot_instance: Potentiometer,
led: gpio::PC13<Output<PushPull>>,
delay: timer::DelayMs<TIM1>,
}
#[init]
fn init(ctx: init::Context) -> (Shared, Local) {
let mut dp = ctx.device;
// Configure and obtain handle for delay abstraction
// 1) Promote RCC structure to HAL to be able to configure clocks
let rcc = dp.RCC.constrain();
// 2) Configure the system clocks
// 25 MHz must be used for HSE on the Blackpill-STM32F411CE board according to manual
let clocks = rcc.cfgr.use_hse(25.MHz()).freeze();
// 3) Create delay handle
let delay = dp.TIM1.delay_ms(&clocks);
// Configure the LED pin as a push pull output and obtain handle
// On the Blackpill STM32F411CEU6 there is an on-board LED connected to pin PC13
// 1) Promote the GPIOC PAC struct
let gpioc = dp.GPIOC.split();
// 2) Configure PORTC OUTPUT Pins and Obtain Handle
let led = gpioc.pc13.into_push_pull_output();
// Configure the button pin as input and obtain handle
// On the Blackpill STM32F411CEU6 there is a button connected to pin PA0
// 3) Promote the GPIOA PAC struct
let gpioa: gpio::gpioa::Parts = dp.GPIOA.split();
// 4) Configure Pin and Obtain Handle
let mut button = gpioa.pa0.into_pull_up_input();
// 5) Configure pin A1 of the blackpill to be of type analog
// the input does not need to be mutable since we are only reading it.
let analog_input = gpioa.pa1.into_analog();
// 6) Configure the ADC modulke for single-shot conversion
let mut adc = Adc::adc1(dp.ADC1, true, AdcConfig::default());
// Calibrate by calculates the system VDDA by sampling the internal VREF
// channel and comparing the result with the value stored at the factory.
adc.calibrate();
let pot_instance = Potentiometer {
analog_input: analog_input,
};
// Configure Button Pin for Interrupts
// 7) Promote SYSCFG structure to HAL to be able to configure interrupts
let mut syscfg = dp.SYSCFG.constrain();
// 8) Make button an interrupt source
button.make_interrupt_source(&mut syscfg);
// 9) Configure the interruption to be triggered on a rising edge
button.trigger_on_edge(&mut dp.EXTI, Edge::Rising);
// 10) Enable gpio interrupt for button
button.enable_interrupt(&mut dp.EXTI);
(
// Initialization of shared resources. In this case delay value and the ADC instance
Shared {
delayval: 2000_u32,
adc_module: adc,
},
// Initialization of task local resources
Local {
button,
pot_instance,
led,
delay,
},
)
}
// Background task, runs whenever no other tasks are running
#[idle(local = [led, delay], shared = [delayval])]
fn idle(mut ctx: idle::Context) -> ! {
let led = ctx.local.led;
let delay = ctx.local.delay;
loop {
// Turn On LED
led.set_high();
// Obtain shared delay variable and delay
delay.delay_ms(ctx.shared.delayval.lock(|del| *del));
// Turn off LED
led.set_low();
// Obtain shared delay variable and delay
delay.delay_ms(ctx.shared.delayval.lock(|del| *del));
}
}
// Handle the IRQ generated when the button is pressed and interact with local and shared resources.
#[task(binds = EXTI0, local = [button, pot_instance], shared=[delayval, adc_module])]
fn gpio_interrupt_handler(mut ctx: gpio_interrupt_handler::Context) {
ctx.shared.delayval.lock(|del| {
*del = *del - 100_u32;
if *del < 200_u32 {
*del = 2000_u32;
}
*del
});
ctx.shared.delayval.lock(|del| {
defmt::info!("Current delay value {:?}", del);
});
// Obtain the Potentiometer instance that belongs to this task ONLY
let analog_input = &ctx.local.pot_instance.analog_input;
// Obtain the shared instance of Adc and do one conversion of the value seen
ctx.shared.adc_module.lock(|adc_module| {
let sample = adc_module.convert(analog_input, SampleTime::Cycles_480);
defmt::info!("Current ADC value {:?}\n", sample);
});
ctx.local.button.clear_interrupt_pending_bit();
}
}
|