Skip to content

Commit f8cb812

Browse files
committed
Refactor STM32H753 GPIO configuration printing support to a module.
Applied several suggestions from Matt. Co-authored-by: Matt Keeter <matt@oxide.computer>
1 parent 7ed2ba5 commit f8cb812

4 files changed

Lines changed: 270 additions & 255 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ tlvc-text = {git = "https://github.com/oxidecomputer/tlvc"}
101101
vsc7448-info = { git = "https://github.com/oxidecomputer/vsc7448.git" }
102102
vsc7448-types = { git = "https://github.com/oxidecomputer/vsc7448.git" }
103103
ipcc-data = { git = "https://github.com/oxidecomputer/ipcc-rs" }
104-
stm32h7 = { version = "0.14", default-features = false }
105104

106105
#
107106
# We depend on the oxide-stable branch of Oxide's fork of probe-rs to assure
@@ -248,6 +247,7 @@ serde-xml-rs = "0.5.1"
248247
sha2 = "0.10.1"
249248
splitty = "0.1.0"
250249
srec = "0.2"
250+
stm32h7 = { version = "0.14", features = ["stm32h753"] }
251251
strum = "0.22"
252252
strum_macros = "0.22"
253253
syn = "1.0"

cmd/gpio/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ clap.workspace = true
1010
anyhow.workspace = true
1111
parse_int.workspace = true
1212
lazy_static.workspace = true
13-
stm32h7 = { workspace = true, features = ["rt", "stm32h753"] }
13+
stm32h7.workspace = true
1414
zerocopy.workspace = true
1515

1616
humility-cli.workspace = true

cmd/gpio/src/lib.rs

Lines changed: 31 additions & 253 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@
7373
//! Port J 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
7474
//! Port K 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
7575
//! ```
76-
//! To get input values with GPIO configuration settings,
77-
//! use the --with-config or -w flag with --input:
76+
//! To get input values with STM32H753 GPIO configuration settings,
77+
//! use the `--with-config` or `-w` flag with --input:
7878
//!
7979
//! ```console
8080
//! $ humility gpio --input -with-config --pins B:0,B:14,E:1
@@ -85,7 +85,7 @@
8585
//! ```
8686
//!
8787
//! If no pins are specified, then the pin names, values and config settings
88-
//! are printeed one per line for all GPIO pins.
88+
//! are printed one per line for all GPIO pins.
8989
//!
9090
//! ### Configure
9191
//!
@@ -105,15 +105,39 @@
105105
//! ```
106106
//!
107107
108+
mod stm32h753;
109+
108110
use humility_cli::{ExecutionContext, Subcommand};
109111
use humility_cmd::{Archive, Attach, Command, CommandKind, Validate};
110-
use humility_hiffy::{HiffyContext, IpcError};
111-
use std::mem::MaybeUninit;
112-
use std::str;
112+
use humility_hiffy::HiffyContext;
113113

114114
use anyhow::{anyhow, bail, Result};
115115
use clap::{CommandFactory, Parser};
116116
use hif::*;
117+
use humility_hiffy::IpcError;
118+
119+
fn show_gpio_with_config(
120+
context: &mut ExecutionContext,
121+
gpio_input: &humility_hiffy::HiffyFunction,
122+
args: &[(u16, Option<u8>, String)],
123+
results: &[Result<Vec<u8>, IpcError>],
124+
) -> Result<()> {
125+
let hubris = context.archive.as_ref().unwrap();
126+
if let Some(chip) = hubris.chip() {
127+
match chip.as_str() {
128+
"stm32h7" => {
129+
// Call the stm32h753-specific function
130+
stm32h753::show_gpio_with_config(context, gpio_input, args, results)
131+
}
132+
_ => Err(anyhow!("GPIO `--with-config` is not supported for chip '{chip}'")),
133+
}
134+
} else {
135+
Err(anyhow!(
136+
"GPIO `--with-config` is not supported when chip is not specified"
137+
))
138+
}
139+
}
140+
117141

118142
use std::convert::TryInto;
119143

@@ -167,251 +191,6 @@ struct GpioArgs {
167191
pins: Option<Vec<String>>,
168192
}
169193

170-
use device::gpioa::RegisterBlock;
171-
use humility_hiffy::HiffyFunction;
172-
use lazy_static::lazy_static;
173-
use std::collections::BTreeMap;
174-
use std::ops::RangeInclusive;
175-
use stm32h7::stm32h753 as device;
176-
177-
lazy_static! {
178-
static ref GPIO_REGISTERS: BTreeMap<&'static str, RangeInclusive<u32>> = {
179-
let mut map = BTreeMap::new();
180-
// Section 11.4: GPIO registers
181-
map.insert("A", 0x58020000..=0x580203FF);
182-
map.insert("B", 0x58020400..=0x580207FF);
183-
map.insert("C", 0x58020800..=0x58020BFF);
184-
map.insert("D", 0x58020C00..=0x58020FFF);
185-
map.insert("E", 0x58021000..=0x580213FF);
186-
map.insert("F", 0x58021400..=0x580217FF);
187-
map.insert("G", 0x58021800..=0x58021BFF);
188-
map.insert("H", 0x58021C00..=0x58021FFF);
189-
map.insert("I", 0x58022000..=0x580223FF);
190-
map.insert("J", 0x58022400..=0x580227FF);
191-
map.insert("K", 0x58022800..=0x58022BFF);
192-
map
193-
};
194-
}
195-
196-
// This is a hack.
197-
struct PinConfig {
198-
mode: String,
199-
otype: String,
200-
speed: String,
201-
pull: String,
202-
input: String,
203-
output: String,
204-
lock: String,
205-
alternate: String,
206-
}
207-
208-
use std::fmt;
209-
210-
impl fmt::Display for PinConfig {
211-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212-
// Use the write! macro to format the output to the formatter 'f'
213-
write!(
214-
f,
215-
"{}:{}:{}:{}:{}:{}:{}:{}",
216-
self.mode,
217-
self.otype,
218-
self.speed,
219-
self.pull,
220-
self.alternate,
221-
self.lock,
222-
self.input,
223-
self.output
224-
)
225-
}
226-
}
227-
228-
struct ConfigCache {
229-
cache: BTreeMap<String, RegisterBlock>,
230-
}
231-
232-
impl ConfigCache {
233-
fn new() -> ConfigCache {
234-
let cache: BTreeMap<String, RegisterBlock> = BTreeMap::new();
235-
Self { cache }
236-
}
237-
238-
fn get_pin_config(
239-
&mut self,
240-
context: &mut ExecutionContext,
241-
group: &str,
242-
pin: u32,
243-
) -> Result<PinConfig> {
244-
let rb = match self.cache.get(group) {
245-
None => {
246-
let rb = read_gpio_register_block(context, group)?;
247-
self.cache.insert(group.to_string(), rb);
248-
self.cache.get(group).unwrap()
249-
}
250-
Some(rb) => rb,
251-
};
252-
253-
let reg = rb.moder.read().bits();
254-
let mode = match (reg >> (pin * 2)) & 3 {
255-
0 => "Input",
256-
1 => "Output",
257-
2 => "Alternate",
258-
3 => "Analog",
259-
_ => unreachable!(),
260-
};
261-
262-
let reg = rb.otyper.read().bits();
263-
let otype = match (reg >> pin) & 1 {
264-
0 => "OutPushPull",
265-
1 => "OutOpenDrain",
266-
_ => unreachable!(),
267-
};
268-
269-
let reg = rb.ospeedr.read().bits();
270-
let speed = match (reg >> (pin * 2)) & 3 {
271-
0 => "LowSpeed",
272-
1 => "MediumSpeed",
273-
2 => "HighSpeed",
274-
3 => "VeryHighSpeed",
275-
_ => unreachable!(),
276-
};
277-
278-
let reg = rb.pupdr.read().bits();
279-
let pull = match (reg >> (pin * 2)) & 3 {
280-
0 => "NoPull",
281-
1 => "PullUp",
282-
2 => "PullDown",
283-
3 => "ReservedPull",
284-
_ => unreachable!(),
285-
};
286-
287-
let reg = rb.idr.read().bits();
288-
let input = match (reg >> pin) & 1 {
289-
0 => "InZero",
290-
1 => "InOne",
291-
_ => unreachable!(),
292-
};
293-
294-
let reg = rb.odr.read().bits();
295-
let output = match (reg >> pin) & 1 {
296-
0 => "OutZero",
297-
1 => "OutOne",
298-
_ => unreachable!(),
299-
};
300-
301-
// Note: Bit 16 indicates that the register is locked or unlocked.
302-
let reg = rb.lckr.read().bits();
303-
let lock = match (reg >> pin) & 1 {
304-
0 => "Unlocked",
305-
1 => "Locked",
306-
_ => unreachable!(),
307-
};
308-
309-
let alternate = format!(
310-
"AF{}",
311-
if pin < 8 {
312-
let reg = rb.afrl.read().bits();
313-
(reg >> (pin * 4)) & 15
314-
} else {
315-
let reg = rb.afrh.read().bits();
316-
(reg >> ((pin - 8) * 4)) & 15
317-
}
318-
);
319-
320-
Ok(PinConfig {
321-
mode: mode.to_string(),
322-
otype: otype.to_string(),
323-
speed: speed.to_string(),
324-
pull: pull.to_string(),
325-
input: input.to_string(),
326-
output: output.to_string(),
327-
lock: lock.to_string(),
328-
alternate,
329-
})
330-
}
331-
}
332-
333-
fn read_gpio_register_block(
334-
context: &mut ExecutionContext,
335-
group: &str,
336-
) -> Result<RegisterBlock> {
337-
let core = &mut **context.core.as_mut().unwrap();
338-
let span = GPIO_REGISTERS
339-
.get(group)
340-
.ok_or(anyhow!("no address for GPIO group {}", group))?;
341-
let mut buffer = vec![0u8; std::mem::size_of::<RegisterBlock>()];
342-
core.read_8(*span.start(), &mut buffer)?;
343-
344-
let mut rb: MaybeUninit<RegisterBlock> = MaybeUninit::uninit();
345-
// let ptr: *mut u8 = rb.as_mut_ptr() as *mut u8;
346-
unsafe {
347-
// Get a mutable pointer to the allocated memory
348-
let dest_ptr = rb.as_mut_ptr() as *mut u8;
349-
350-
// Copy the raw bytes into the struct's memory location
351-
// Ensure the size of raw_bytes matches the size of MyStruct
352-
// to avoid out-of-bounds access.
353-
std::ptr::copy_nonoverlapping(buffer.as_ptr(), dest_ptr, buffer.len());
354-
355-
Ok(rb.assume_init())
356-
}
357-
}
358-
359-
fn show_gpio_with_config(
360-
context: &mut ExecutionContext,
361-
gpio_input: &HiffyFunction,
362-
args: &[(u16, Option<u8>, String)],
363-
results: &[Result<Vec<u8>, IpcError>],
364-
) -> Result<()> {
365-
let mut config_cache = ConfigCache::new();
366-
for (ndx, arg) in args.iter().enumerate() {
367-
match arg.1 {
368-
Some(pin) => {
369-
let config =
370-
config_cache.get_pin_config(context, &arg.2, pin as u32)?;
371-
println!(
372-
"{}:{:<2} = {} {}",
373-
arg.2,
374-
pin,
375-
match results[ndx] {
376-
Err(code) => {
377-
gpio_input.strerror(code)
378-
}
379-
Ok(ref val) => {
380-
let arr: &[u8; 2] = val[0..2].try_into()?;
381-
let v = u16::from_le_bytes(*arr);
382-
format!("{}", (v >> pin) & 1)
383-
}
384-
},
385-
config
386-
);
387-
}
388-
389-
None => match results[ndx] {
390-
Err(code) => {
391-
println!("Port {}: {}", arg.2, gpio_input.strerror(code))
392-
}
393-
Ok(ref val) => {
394-
let arr: &[u8; 2] = val[0..2].try_into()?;
395-
let v = u16::from_le_bytes(*arr);
396-
397-
for i in 0..16 {
398-
let config = config_cache
399-
.get_pin_config(context, &arg.2, i as u32)?;
400-
println!(
401-
"{}:{:<2} = {} ({})",
402-
arg.2,
403-
i,
404-
(v >> i) & 1,
405-
config
406-
);
407-
}
408-
}
409-
},
410-
}
411-
}
412-
Ok(())
413-
}
414-
415194
fn gpio(context: &mut ExecutionContext) -> Result<()> {
416195
let core = &mut **context.core.as_mut().unwrap();
417196
let Subcommand::Other(subargs) = context.cli.cmd.as_ref().unwrap();
@@ -526,8 +305,7 @@ fn gpio(context: &mut ExecutionContext) -> Result<()> {
526305
let mut header = false;
527306

528307
if subargs.with_config {
529-
let _ =
530-
show_gpio_with_config(context, &gpio_input, &args, &results);
308+
show_gpio_with_config(context, &gpio_input, &args, &results)?;
531309
} else {
532310
for (ndx, arg) in args.iter().enumerate() {
533311
match arg.1 {

0 commit comments

Comments
 (0)