mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-28 04:40:52 +00:00
Generate i2c instances from metadata (#3678)
This commit is contained in:
parent
c71cbcd2c3
commit
c72889a73d
@ -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.
|
||||
|
@ -122,4 +122,5 @@ crate::peripherals! {
|
||||
]
|
||||
}
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/_generated_peris.rs"));
|
||||
include!(concat!(env!("OUT_DIR"), "/_generated_gpio.rs"));
|
||||
|
@ -82,4 +82,5 @@ crate::peripherals! {
|
||||
]
|
||||
}
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/_generated_peris.rs"));
|
||||
include!(concat!(env!("OUT_DIR"), "/_generated_gpio.rs"));
|
||||
|
@ -100,4 +100,5 @@ crate::peripherals! {
|
||||
]
|
||||
}
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/_generated_peris.rs"));
|
||||
include!(concat!(env!("OUT_DIR"), "/_generated_gpio.rs"));
|
||||
|
@ -145,4 +145,5 @@ crate::peripherals! {
|
||||
]
|
||||
}
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/_generated_peris.rs"));
|
||||
include!(concat!(env!("OUT_DIR"), "/_generated_gpio.rs"));
|
||||
|
@ -130,4 +130,5 @@ crate::peripherals! {
|
||||
]
|
||||
}
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/_generated_peris.rs"));
|
||||
include!(concat!(env!("OUT_DIR"), "/_generated_gpio.rs"));
|
||||
|
@ -129,4 +129,5 @@ crate::peripherals! {
|
||||
]
|
||||
}
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/_generated_peris.rs"));
|
||||
include!(concat!(env!("OUT_DIR"), "/_generated_gpio.rs"));
|
||||
|
@ -138,4 +138,5 @@ crate::peripherals! {
|
||||
]
|
||||
}
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/_generated_peris.rs"));
|
||||
include!(concat!(env!("OUT_DIR"), "/_generated_gpio.rs"));
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"],
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user