use crate::soc::st::tim::{Counter, Family, Flags, Kind, Part, Timer};
use crate::soc::stm32h743::generated::{tim1, tim2, tim6, tim15, tim16, tim17};
pub const TIMERS: [Timer; 7] = [
Timer::new("TIM2", Counter::Wide, Kind::General),
Timer::new("TIM3", Counter::Narrow, Kind::General),
Timer::new("TIM4", Counter::Narrow, Kind::General),
Timer::new("TIM5", Counter::Wide, Kind::General),
Timer::new("TIM12", Counter::Narrow, Kind::TwoChannelSlave),
Timer::new("TIM13", Counter::Narrow, Kind::OneChannel),
Timer::new("TIM14", Counter::Narrow, Kind::OneChannel),
];
pub const ADVANCED_TIMERS: [Timer; 2] = [
Timer::new("TIM1", Counter::Narrow, Kind::Advanced),
Timer::new("TIM8", Counter::Narrow, Kind::Advanced),
];
pub const BASIC_TIMERS: [Timer; 2] = [
Timer::new("TIM6", Counter::Narrow, Kind::Basic),
Timer::new("TIM7", Counter::Narrow, Kind::Basic),
];
pub const TIMER_15: Timer = Timer::new("TIM15", Counter::Narrow, Kind::TwoChannelBreak);
pub const TIMER_16: Timer = Timer::new("TIM16", Counter::Narrow, Kind::OneChannelBreak);
pub const TIMER_17: Timer = Timer::new("TIM17", Counter::Narrow, Kind::OneChannelBreak);
pub trait Stm32h743Family: Family<Instance = Timer> {}
#[derive(Debug, Clone, Copy)]
pub struct General;
#[derive(Debug, Clone, Copy)]
pub struct Advanced;
#[derive(Debug, Clone, Copy)]
pub struct Basic;
#[derive(Debug, Clone, Copy)]
pub struct Tim15;
#[derive(Debug, Clone, Copy)]
pub struct Tim16;
#[derive(Debug, Clone, Copy)]
pub struct Tim17;
const BREAK: usize = 0;
const UPDATE: usize = 1;
const TRIGGER_AND_COMMUTATION: usize = 2;
const CAPTURE_COMPARE: usize = 3;
impl Family for General {
type Register = tim2::Register;
type Instance = Timer;
const PART: &'static Part = &super::PART;
const KINDS: &'static [Kind] = &[Kind::General, Kind::TwoChannelSlave, Kind::OneChannel];
}
impl Family for Advanced {
type Register = tim1::Register;
type Instance = Timer;
const PART: &'static Part = &super::PART;
const KINDS: &'static [Kind] = &[Kind::Advanced];
const LINES: usize = 4;
fn line(flags: Flags) -> usize {
match flags {
Flags::Break => BREAK,
Flags::Update => UPDATE,
Flags::TriggerAndCommutation => TRIGGER_AND_COMMUTATION,
Flags::CaptureCompare => CAPTURE_COMPARE,
}
}
}
impl Family for Basic {
type Register = tim6::Register;
type Instance = Timer;
const PART: &'static Part = &super::PART;
const KINDS: &'static [Kind] = &[Kind::Basic];
}
impl Family for Tim15 {
type Register = tim15::Register;
type Instance = Timer;
const PART: &'static Part = &super::PART;
const KINDS: &'static [Kind] = &[Kind::TwoChannelBreak];
}
impl Family for Tim16 {
type Register = tim16::Register;
type Instance = Timer;
const PART: &'static Part = &super::PART;
const KINDS: &'static [Kind] = &[Kind::OneChannelBreak];
}
impl Family for Tim17 {
type Register = tim17::Register;
type Instance = Timer;
const PART: &'static Part = &super::PART;
const KINDS: &'static [Kind] = &[Kind::OneChannelBreak];
}
impl Stm32h743Family for General {}
impl Stm32h743Family for Advanced {}
impl Stm32h743Family for Basic {}
impl Stm32h743Family for Tim15 {}
impl Stm32h743Family for Tim16 {}
impl Stm32h743Family for Tim17 {}
#[cfg(test)]
mod tests {
use super::*;
use crate::soc::Layout;
use crate::soc::st::tim::family::{Map, ROWS, SLOTS, Slot, offsets};
use crate::soc::{FieldSpec, RegisterSpec};
fn layouts() -> [(&'static str, &'static [RegisterSpec]); 6] {
[
("tim1", <tim1::Register as Layout>::REGISTERS),
("tim2", <tim2::Register as Layout>::REGISTERS),
("tim6", <tim6::Register as Layout>::REGISTERS),
("tim15", <tim15::Register as Layout>::REGISTERS),
("tim16", <tim16::Register as Layout>::REGISTERS),
("tim17", <tim17::Register as Layout>::REGISTERS),
]
}
fn slot_at(offset: u32) -> Option<Slot> {
let offsets = offsets(&super::super::PART);
Slot::ALL
.into_iter()
.find(|slot| offsets[slot.index()] == Some(offset))
}
#[test]
fn the_slots_are_the_advanced_timers_registers_in_offset_order() {
let offsets: Vec<u32> = offsets(&super::super::PART).into_iter().flatten().collect();
let mut sorted = offsets.clone();
sorted.sort_unstable();
sorted.dedup();
assert_eq!(offsets, sorted, "ascending and distinct");
let distinct: std::collections::BTreeSet<u32> = tim1::REGISTERS
.iter()
.map(|register| register.offset)
.collect();
assert_eq!(
distinct.into_iter().collect::<Vec<u32>>(),
offsets,
"a slot for every offset of the advanced timer's table, the two views of a mode register one"
);
assert!(SLOTS > offsets.len(), "and the slots this part has none of");
}
#[test]
fn every_row_of_every_layout_is_a_slot_at_its_offset() {
assert_eq!(tim1::REGISTERS.len(), ROWS);
let part = offsets(&super::super::PART);
for (name, table) in layouts() {
assert!(table.len() <= ROWS, "{name}");
for (row, register) in table.iter().enumerate() {
let slot = slot_at(register.offset)
.unwrap_or_else(|| panic!("{name} {} has no slot", register.name));
assert_eq!(
part[slot.index()],
Some(register.offset),
"{name} {}",
register.name
);
assert!(row < ROWS);
}
}
let map = Map::of(&tim1::REGISTERS, &part);
assert_eq!(
map.row(Slot::Ccmr1),
Some(tim1::Register::Ccmr1Input.index())
);
assert_eq!(map.row(Slot::Ccr6), Some(tim1::Register::Ccr6.index()));
assert_eq!(
map.slot(tim1::Register::Ccmr1Output.index()),
Some(Slot::Ccmr1)
);
let basic = Map::of(&tim6::REGISTERS, &part);
assert_eq!(
basic.row(Slot::Smcr),
None,
"the basic timer has no slave mode controller"
);
assert_eq!(basic.row(Slot::Cnt), Some(tim6::Register::Cnt.index()));
let small = Map::of(&tim16::REGISTERS, &part);
assert_eq!(small.row(Slot::Ccr2), None);
assert_eq!(
small.row(Slot::Af1),
Some(tim16::Register::Tim16Af1.index())
);
}
fn field_of(
table: &'static [RegisterSpec],
register: &str,
name: &str,
) -> Option<&'static FieldSpec> {
table
.iter()
.find(|candidate| candidate.name == register)?
.fields
.iter()
.find(|field| field.name == name)
}
#[test]
fn a_field_the_layouts_share_sits_at_the_same_bits_in_each() {
const RENAMED: [(&str, &str, &str, &str); 3] = [
("tim2", "CCMR2_Output", "O24CE", "OC4CE"),
("tim15", "SMCR", "TS_2_0", "TS"),
("tim1", "CCMR2_Output", "OC4M_4", "OC4M_3"),
];
let mut compared = 0;
for (name, table) in layouts() {
if name == "tim1" {
continue;
}
for register in table {
let Some(twin) = tim1::REGISTERS.iter().find(|candidate| {
candidate.offset == register.offset
&& candidate.name.split('_').next() == register.name.split('_').next()
}) else {
continue;
};
for field in register.fields {
let renamed = RENAMED
.iter()
.find(|(layout, owner, from, _)| {
*layout == name && *owner == register.name && *from == field.name
})
.map(|(_, _, _, to)| *to);
let wanted = renamed.unwrap_or(field.name);
let Some(counterpart) = twin
.fields
.iter()
.find(|candidate| candidate.name == wanted)
else {
continue;
};
assert_eq!(
(field.bit, field.width),
(counterpart.bit, counterpart.width),
"{name} {}.{}",
register.name,
field.name
);
compared += 1;
}
}
}
assert!(compared > 150, "{compared} fields compared");
assert!(field_of(tim1::REGISTERS.as_slice(), "SMCR", "TS_4_3").is_some());
}
#[test]
fn each_kind_belongs_to_the_family_whose_layout_has_its_channels() {
fn channels<F: Family>() -> Vec<(Kind, usize)> {
F::KINDS
.iter()
.map(|kind| {
let capture = <F::Register as Layout>::REGISTERS
.iter()
.filter(|register| {
(13..=16).contains(&(register.offset / 4))
|| (22..=23).contains(&(register.offset / 4))
})
.count();
(*kind, capture)
})
.collect()
}
for (kind, registers) in channels::<Advanced>() {
assert_eq!(registers, usize::from(kind.channels()), "{kind:?}");
}
for (kind, registers) in channels::<General>() {
assert!(registers >= usize::from(kind.channels()), "{kind:?}");
}
for (kind, registers) in channels::<Tim15>() {
assert_eq!(registers, usize::from(kind.channels()), "{kind:?}");
}
for (kind, registers) in channels::<Tim16>() {
assert_eq!(registers, usize::from(kind.channels()), "{kind:?}");
}
for (kind, registers) in channels::<Basic>() {
assert_eq!(registers, usize::from(kind.channels()), "{kind:?}");
}
let every: Vec<Kind> = [
General::KINDS,
Advanced::KINDS,
Basic::KINDS,
Tim15::KINDS,
Tim16::KINDS,
Tim17::KINDS,
]
.concat();
for kind in [
Kind::Advanced,
Kind::General,
Kind::TwoChannelSlave,
Kind::OneChannel,
Kind::TwoChannelBreak,
Kind::OneChannelBreak,
Kind::Basic,
] {
assert!(every.contains(&kind), "{kind:?} has a family");
}
}
#[test]
fn the_instance_tables_name_the_fourteen_timers_once() {
let mut names: Vec<&str> = TIMERS
.iter()
.chain(&ADVANCED_TIMERS)
.chain(&BASIC_TIMERS)
.chain([&TIMER_15, &TIMER_16, &TIMER_17])
.map(|timer| timer.instance)
.collect();
assert_eq!(names.len(), 14, "TIM9 to TIM11 are not in this part");
names.sort_unstable();
names.dedup();
assert_eq!(names.len(), 14);
let wide: Vec<&str> = TIMERS
.iter()
.filter(|timer| timer.counter == Counter::Wide)
.map(|timer| timer.instance)
.collect();
assert_eq!(wide, ["TIM2", "TIM5"], "39.2");
for timer in TIMERS {
assert!(General::KINDS.contains(&timer.kind));
}
}
}