Generate i2c instances from metadata (#3678)

This commit is contained in:
Dániel Buga 2025-06-24 14:18:22 +02:00 committed by GitHub
parent c71cbcd2c3
commit c72889a73d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 108 additions and 20 deletions

View File

@ -3114,7 +3114,7 @@ fn estimate_ack_failed_reason(_register_block: &RegisterBlock) -> AcknowledgeChe
}
}
macro_rules! instance {
crate::peripherals::for_each_i2c_master!(
($inst:ident, $peri:ident, $scl:ident, $sda:ident, $interrupt:ident) => {
impl Instance for crate::peripherals::$inst<'_> {
fn parts(&self) -> (&Info, &State) {
@ -3141,12 +3141,7 @@ macro_rules! instance {
}
}
};
}
#[cfg(i2c_master_i2c0)]
instance!(I2C0, I2cExt0, I2CEXT0_SCL, I2CEXT0_SDA, I2C_EXT0);
#[cfg(i2c_master_i2c1)]
instance!(I2C1, I2cExt1, I2CEXT1_SCL, I2CEXT1_SDA, I2C_EXT1);
);
crate::any_peripheral! {
/// Any I2C peripheral.

View File

@ -122,4 +122,5 @@ crate::peripherals! {
]
}
include!(concat!(env!("OUT_DIR"), "/_generated_peris.rs"));
include!(concat!(env!("OUT_DIR"), "/_generated_gpio.rs"));

View File

@ -82,4 +82,5 @@ crate::peripherals! {
]
}
include!(concat!(env!("OUT_DIR"), "/_generated_peris.rs"));
include!(concat!(env!("OUT_DIR"), "/_generated_gpio.rs"));

View File

@ -100,4 +100,5 @@ crate::peripherals! {
]
}
include!(concat!(env!("OUT_DIR"), "/_generated_peris.rs"));
include!(concat!(env!("OUT_DIR"), "/_generated_gpio.rs"));

View File

@ -145,4 +145,5 @@ crate::peripherals! {
]
}
include!(concat!(env!("OUT_DIR"), "/_generated_peris.rs"));
include!(concat!(env!("OUT_DIR"), "/_generated_gpio.rs"));

View File

@ -130,4 +130,5 @@ crate::peripherals! {
]
}
include!(concat!(env!("OUT_DIR"), "/_generated_peris.rs"));
include!(concat!(env!("OUT_DIR"), "/_generated_gpio.rs"));

View File

@ -129,4 +129,5 @@ crate::peripherals! {
]
}
include!(concat!(env!("OUT_DIR"), "/_generated_peris.rs"));
include!(concat!(env!("OUT_DIR"), "/_generated_gpio.rs"));

View File

@ -138,4 +138,5 @@ crate::peripherals! {
]
}
include!(concat!(env!("OUT_DIR"), "/_generated_peris.rs"));
include!(concat!(env!("OUT_DIR"), "/_generated_gpio.rs"));

View File

@ -551,7 +551,10 @@ output_signals = [
[device.i2c_master]
support_status = "supported"
instances = [{ name = "i2c0" }, { name = "i2c1" }]
instances = [
{ name = "i2c0", sys_instance = "I2cExt0", scl = "I2CEXT0_SCL", sda = "I2CEXT0_SDA", interrupt = "I2C_EXT0" },
{ name = "i2c1", sys_instance = "I2cExt1", scl = "I2CEXT1_SCL", sda = "I2CEXT1_SDA", interrupt = "I2C_EXT1" },
]
ll_intr_mask = 0x3ffff
fifo_size = 32
max_bus_timeout = 0xFFFFF

View File

@ -195,7 +195,9 @@ output_signals = [
[device.i2c_master]
support_status = "supported"
instances = [{ name = "i2c0" }]
instances = [
{ name = "i2c0", sys_instance = "I2cExt0", scl = "I2CEXT0_SCL", sda = "I2CEXT0_SDA", interrupt = "I2C_EXT0" },
]
has_fsm_timeouts = true
has_hw_bus_clear = true
ll_intr_mask = 0x3ffff

View File

@ -244,7 +244,9 @@ output_signals = [
[device.i2c_master]
support_status = "supported"
instances = [{ name = "i2c0" }]
instances = [
{ name = "i2c0", sys_instance = "I2cExt0", scl = "I2CEXT0_SCL", sda = "I2CEXT0_SDA", interrupt = "I2C_EXT0" },
]
has_fsm_timeouts = true
has_hw_bus_clear = true
ll_intr_mask = 0x3ffff

View File

@ -367,7 +367,9 @@ output_signals = [
[device.i2c_master]
support_status = "supported"
instances = [{ name = "i2c0" }]
instances = [
{ name = "i2c0", sys_instance = "I2cExt0", scl = "I2CEXT0_SCL", sda = "I2CEXT0_SDA", interrupt = "I2C_EXT0" },
]
has_fsm_timeouts = true
has_hw_bus_clear = true
ll_intr_mask = 0x3ffff

View File

@ -311,7 +311,10 @@ output_signals = [
[device.i2c_master]
support_status = "supported"
instances = [{ name = "i2c0" }, { name = "i2c1" }]
instances = [
{ name = "i2c0", sys_instance = "I2cExt0", scl = "I2CEXT0_SCL", sda = "I2CEXT0_SDA", interrupt = "I2C_EXT0" },
{ name = "i2c1", sys_instance = "I2cExt1", scl = "I2CEXT1_SCL", sda = "I2CEXT1_SDA", interrupt = "I2C_EXT1" },
]
has_fsm_timeouts = true
has_hw_bus_clear = true
ll_intr_mask = 0x3ffff

View File

@ -337,7 +337,10 @@ output_signals = [
]
[device.i2c_master]
support_status = "supported"
instances = [{ name = "i2c0" }, { name = "i2c1" }]
instances = [
{ name = "i2c0", sys_instance = "I2cExt0", scl = "I2CEXT0_SCL", sda = "I2CEXT0_SDA", interrupt = "I2C_EXT0" },
{ name = "i2c1", sys_instance = "I2cExt1", scl = "I2CEXT1_SCL", sda = "I2CEXT1_SDA", interrupt = "I2C_EXT1" },
]
ll_intr_mask = 0x1ffff
fifo_size = 32
has_bus_timeout_enable = true

View File

@ -485,7 +485,10 @@ output_signals = [
[device.i2c_master]
support_status = "supported"
instances = [{ name = "i2c0" }, { name = "i2c1" }]
instances = [
{ name = "i2c0", sys_instance = "I2cExt0", scl = "I2CEXT0_SCL", sda = "I2CEXT0_SDA", interrupt = "I2C_EXT0" },
{ name = "i2c1", sys_instance = "I2cExt1", scl = "I2CEXT1_SCL", sda = "I2CEXT1_SDA", interrupt = "I2C_EXT1" },
]
has_fsm_timeouts = true
has_hw_bus_clear = true
ll_intr_mask = 0x3ffff

View File

@ -49,6 +49,14 @@ impl SupportStatus {
#[derive(Debug, Default, Clone, serde::Deserialize, serde::Serialize)]
pub(crate) struct EmptyInstanceConfig {}
#[derive(Debug, Default, Clone, serde::Deserialize, serde::Serialize)]
pub(crate) struct I2cMasterInstanceConfig {
pub sys_instance: String,
pub scl: String,
pub sda: String,
pub interrupt: String,
}
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "snake_case")]
pub(crate) enum PinCapability {
@ -349,7 +357,7 @@ driver_configs![
peripherals: &["hmac"],
properties: {}
},
I2cMasterProperties {
I2cMasterProperties<I2cMasterInstanceConfig> {
driver: i2c_master,
name: "I2C master",
peripherals: &["i2c0", "i2c1"],

View File

@ -375,6 +375,7 @@ impl Config {
self.generate_properties(out_dir, "_generated.rs");
self.generate_gpios(out_dir, "_generated_gpio.rs");
self.generate_gpio_extras(out_dir, "_generated_gpio_extras.rs");
self.generate_peripherals(out_dir, "_generated_peris.rs");
}
fn generate_properties(&self, out_dir: &Path, file_name: &str) {
@ -597,8 +598,8 @@ impl Config {
let io_mux_accessor = if gpio.remap_iomux_pin_registers {
let iomux_pin_regs = gpio.pins_and_signals.pins.iter().map(|pin| {
let pin = number(pin.pin);
let reg = quote::format_ident!("GPIO{pin}");
let accessor = quote::format_ident!("gpio{pin}");
let reg = format_ident!("GPIO{pin}");
let accessor = format_ident!("gpio{pin}");
quote::quote! { #pin => transmute::<&'static io_mux::#reg, &'static io_mux::GPIO0>(iomux.#accessor()), }
});
@ -728,6 +729,43 @@ impl Config {
save(&out_file, g);
}
fn generate_peripherals(&self, out_dir: &Path, file_name: &str) {
let out_file = out_dir.join(file_name).to_string_lossy().to_string();
let i2c_master_instance_cfgs = self
.device
.peri_config
.i2c_master
.iter()
.flat_map(|peri| {
peri.instances.iter().map(|instance| {
let instance_config = &instance.instance_config;
let instance = format_ident!("{}", instance.name.to_uppercase());
let sys = format_ident!("{}", instance_config.sys_instance);
let sda = format_ident!("{}", instance_config.sda);
let scl = format_ident!("{}", instance_config.scl);
let int = format_ident!("{}", instance_config.interrupt);
// The order and meaning of these tokens must match their use in the
// `for_each_i2c_master!` call.
quote::quote! {
#instance, #sys, #scl, #sda, #int
}
})
})
.collect::<Vec<_>>();
let for_each_i2c_master = generate_for_each_macro("i2c_master", &i2c_master_instance_cfgs);
let g = quote::quote! {
#for_each_i2c_master
};
save(&out_file, g);
}
}
fn render_signals(enum_name: &str, signals: &[IoMuxSignal]) -> TokenStream {
@ -743,7 +781,7 @@ fn render_signals(enum_name: &str, signals: &[IoMuxSignal]) -> TokenStream {
continue;
};
let name = quote::format_ident!("{}", signal.name);
let name = format_ident!("{}", signal.name);
let value = number(id);
variants.push(quote::quote! {
#name = #value,
@ -756,13 +794,13 @@ fn render_signals(enum_name: &str, signals: &[IoMuxSignal]) -> TokenStream {
continue;
};
let name = quote::format_ident!("{}", signal.name);
let name = format_ident!("{}", signal.name);
variants.push(quote::quote! {
#name,
});
}
let enum_name = quote::format_ident!("{enum_name}");
let enum_name = format_ident!("{enum_name}");
quote::quote! {
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
@ -775,6 +813,28 @@ fn render_signals(enum_name: &str, signals: &[IoMuxSignal]) -> TokenStream {
}
}
fn generate_for_each_macro(name: &str, branches: &[TokenStream]) -> TokenStream {
let macro_name = format_ident!("for_each_{name}");
quote::quote! {
// This macro is called in esp-hal to implement a driver's
// Instance trait for available peripherals. It works by defining, then calling an inner
// macro that substitutes the properties into the template provided by the call in esp-hal.
macro_rules! #macro_name {
(
$pattern:tt => $code:tt;
) => {
macro_rules! _for_each_inner {
($pattern) => $code;
}
#(_for_each_inner!(( #branches ));)*
};
}
pub(crate) use #macro_name;
}
}
fn save(path: impl AsRef<Path>, tokens: TokenStream) {
let source = tokens.to_string();