Skip to content

Commit fbe126b

Browse files
committed
Generalize to support STM32H743 and emit errors for unknown chips.
1 parent f8cb812 commit fbe126b

2 files changed

Lines changed: 85 additions & 36 deletions

File tree

cmd/gpio/src/lib.rs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@
105105
//! ```
106106
//!
107107
108-
mod stm32h753;
108+
mod stm32h7;
109109

110110
use humility_cli::{ExecutionContext, Subcommand};
111111
use humility_cmd::{Archive, Attach, Command, CommandKind, Validate};
@@ -122,14 +122,24 @@ fn show_gpio_with_config(
122122
args: &[(u16, Option<u8>, String)],
123123
results: &[Result<Vec<u8>, IpcError>],
124124
) -> Result<()> {
125-
let hubris = context.archive.as_ref().unwrap();
125+
let hubris = context
126+
.archive
127+
.as_ref()
128+
.ok_or_else(|| anyhow!("Cannot get GPIO config: archive not loaded"))?;
126129
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}'")),
130+
if chip.to_ascii_lowercase().starts_with("stm32h7") {
131+
// Call the stm32h7-specific function
132+
stm32h7::show_gpio_with_config(
133+
context,
134+
gpio_input,
135+
chip.as_str(),
136+
args,
137+
results,
138+
)
139+
} else {
140+
Err(anyhow!(
141+
"GPIO `--with-config` is not supported for chip '{chip}'"
142+
))
133143
}
134144
} else {
135145
Err(anyhow!(
@@ -138,7 +148,6 @@ fn show_gpio_with_config(
138148
}
139149
}
140150

141-
142151
use std::convert::TryInto;
143152

144153
#[derive(Parser, Debug)]
Lines changed: 67 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
5+
use anyhow::{anyhow, Result};
16
use humility_cli::ExecutionContext;
27
use humility_hiffy::IpcError;
3-
use std::mem::MaybeUninit;
48
use std::fmt;
5-
use anyhow::{anyhow, Result};
6-
9+
use std::mem::MaybeUninit;
10+
711
use device::gpioa::RegisterBlock;
812
use humility_hiffy::HiffyFunction;
913
use std::collections::BTreeMap;
@@ -38,27 +42,30 @@ impl fmt::Display for PinConfig {
3842
}
3943
}
4044

45+
/// Store an STM32H7 GPIO group ID ('A', 'B', etc.) and the associated GPIO
46+
/// configuration register block to avoid repeated IO for each Pin.
4147
struct ConfigCache {
42-
cache: BTreeMap<String, RegisterBlock>,
48+
cache: BTreeMap<char, RegisterBlock>,
4349
}
4450

4551
impl ConfigCache {
4652
fn new() -> ConfigCache {
47-
let cache: BTreeMap<String, RegisterBlock> = BTreeMap::new();
53+
let cache: BTreeMap<char, RegisterBlock> = BTreeMap::new();
4854
Self { cache }
4955
}
5056

5157
fn get_pin_config(
5258
&mut self,
5359
context: &mut ExecutionContext,
54-
group: &str,
60+
chip: &str,
61+
group: char,
5562
pin: u32,
5663
) -> Result<PinConfig> {
57-
let rb = match self.cache.get(group) {
64+
let rb = match self.cache.get(&group) {
5865
None => {
59-
let rb = read_gpio_register_block(context, group)?;
60-
self.cache.insert(group.to_string(), rb);
61-
self.cache.get(group).unwrap()
66+
let rb = read_gpio_register_block(context, chip, group)?;
67+
self.cache.insert(group, rb);
68+
self.cache.get(&group).unwrap()
6269
}
6370
Some(rb) => rb,
6471
};
@@ -143,30 +150,52 @@ impl ConfigCache {
143150
}
144151
}
145152

146-
fn stm32h753_gpio_registerblock_addr(group: &str) -> Option<u32> {
153+
/// Lookup STM32H7 GPIO configuration register addresses.
154+
fn stm32h753_gpio_registerblock_addr(group: char) -> Option<u32> {
147155
// Section 11.4: GPIO registers
148156
match group {
149-
"A" => Some(device::GPIOA::ptr() as u32),
150-
"B" => Some(device::GPIOB::ptr() as u32),
151-
"C" => Some(device::GPIOC::ptr() as u32),
152-
"D" => Some(device::GPIOD::ptr() as u32),
153-
"E" => Some(device::GPIOE::ptr() as u32),
154-
"F" => Some(device::GPIOF::ptr() as u32),
155-
"G" => Some(device::GPIOG::ptr() as u32),
156-
"H" => Some(device::GPIOH::ptr() as u32),
157-
"I" => Some(device::GPIOI::ptr() as u32),
158-
"J" => Some(device::GPIOJ::ptr() as u32),
159-
"K" => Some(device::GPIOK::ptr() as u32),
157+
'A' => Some(device::GPIOA::ptr() as u32),
158+
'B' => Some(device::GPIOB::ptr() as u32),
159+
'C' => Some(device::GPIOC::ptr() as u32),
160+
'D' => Some(device::GPIOD::ptr() as u32),
161+
'E' => Some(device::GPIOE::ptr() as u32),
162+
'F' => Some(device::GPIOF::ptr() as u32),
163+
'G' => Some(device::GPIOG::ptr() as u32),
164+
'H' => Some(device::GPIOH::ptr() as u32),
165+
'I' => Some(device::GPIOI::ptr() as u32),
166+
'J' => Some(device::GPIOJ::ptr() as u32),
167+
'K' => Some(device::GPIOK::ptr() as u32),
160168
_ => None,
161169
}
162170
}
163171

172+
// Several other STM32 families share the same GPIO register format as the
173+
// STM32H7 series:
174+
// - STM32F7 series
175+
// - STM32G4 series
176+
// Support for those chips can be added if needed.
177+
// Note: verify that the non-STM32H7 series are using the same addressing or adapt.
178+
fn chip_has_group(chip: &str, group: char) -> Result<bool> {
179+
let name = chip.to_ascii_lowercase();
180+
181+
if name.starts_with("stm32h753") {
182+
Ok(matches!(group, 'A'..='K'))
183+
} else if name.starts_with("stm32h743") {
184+
Ok(matches!(group, 'A'..='I'))
185+
} else {
186+
Err(anyhow!("unknown STM32H7 chip '{}'", chip))
187+
}
188+
}
189+
164190
fn read_gpio_register_block(
165191
context: &mut ExecutionContext,
166-
group: &str,
192+
chip: &str,
193+
group: char,
167194
) -> Result<RegisterBlock> {
168195
let core = &mut **context.core.as_mut().unwrap();
169-
let addr = stm32h753_gpio_registerblock_addr(group).ok_or(anyhow!("no address for GPIO group {}", group))?;
196+
chip_has_group(chip, group)?;
197+
let addr = stm32h753_gpio_registerblock_addr(group)
198+
.ok_or(anyhow!("no address for GPIO group {}", group))?;
170199
let mut buffer = vec![0u8; std::mem::size_of::<RegisterBlock>()];
171200
core.read_8(addr, &mut buffer)?;
172201

@@ -183,15 +212,21 @@ fn read_gpio_register_block(
183212
pub fn show_gpio_with_config(
184213
context: &mut ExecutionContext,
185214
gpio_input: &HiffyFunction,
215+
chip: &str,
186216
args: &[(u16, Option<u8>, String)],
187217
results: &[Result<Vec<u8>, IpcError>],
188218
) -> Result<()> {
189219
let mut config_cache = ConfigCache::new();
190220
for (ndx, arg) in args.iter().enumerate() {
191221
match arg.1 {
192222
Some(pin) => {
193-
let config =
194-
config_cache.get_pin_config(context, &arg.2, pin as u32)?;
223+
let group = arg
224+
.2
225+
.chars()
226+
.next()
227+
.ok_or(anyhow!("invalid group '{}'", arg.2))?;
228+
let config = config_cache
229+
.get_pin_config(context, chip, group, pin as u32)?;
195230
println!(
196231
"{}:{:<2} = {} {}",
197232
arg.2,
@@ -219,8 +254,13 @@ pub fn show_gpio_with_config(
219254
let v = u16::from_le_bytes(*arr);
220255

221256
for i in 0..16 {
257+
let group = arg
258+
.2
259+
.chars()
260+
.next()
261+
.ok_or(anyhow!("invalid group '{}'", arg.2))?;
222262
let config = config_cache
223-
.get_pin_config(context, &arg.2, i as u32)?;
263+
.get_pin_config(context, chip, group, i as u32)?;
224264
println!(
225265
"{}:{:<2} = {} {}",
226266
arg.2,

0 commit comments

Comments
 (0)