|
73 | 73 | //! Port J 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 |
74 | 74 | //! Port K 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 |
75 | 75 | //! ``` |
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: |
78 | 78 | //! |
79 | 79 | //! ```console |
80 | 80 | //! $ humility gpio --input -with-config --pins B:0,B:14,E:1 |
|
85 | 85 | //! ``` |
86 | 86 | //! |
87 | 87 | //! 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. |
89 | 89 | //! |
90 | 90 | //! ### Configure |
91 | 91 | //! |
|
105 | 105 | //! ``` |
106 | 106 | //! |
107 | 107 |
|
| 108 | +mod stm32h753; |
| 109 | + |
108 | 110 | use humility_cli::{ExecutionContext, Subcommand}; |
109 | 111 | 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; |
113 | 113 |
|
114 | 114 | use anyhow::{anyhow, bail, Result}; |
115 | 115 | use clap::{CommandFactory, Parser}; |
116 | 116 | 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 | + |
117 | 141 |
|
118 | 142 | use std::convert::TryInto; |
119 | 143 |
|
@@ -167,251 +191,6 @@ struct GpioArgs { |
167 | 191 | pins: Option<Vec<String>>, |
168 | 192 | } |
169 | 193 |
|
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 | | - |
415 | 194 | fn gpio(context: &mut ExecutionContext) -> Result<()> { |
416 | 195 | let core = &mut **context.core.as_mut().unwrap(); |
417 | 196 | let Subcommand::Other(subargs) = context.cli.cmd.as_ref().unwrap(); |
@@ -526,8 +305,7 @@ fn gpio(context: &mut ExecutionContext) -> Result<()> { |
526 | 305 | let mut header = false; |
527 | 306 |
|
528 | 307 | 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)?; |
531 | 309 | } else { |
532 | 310 | for (ndx, arg) in args.iter().enumerate() { |
533 | 311 | match arg.1 { |
|
0 commit comments