2021-04-20 01:37:49 +00:00
|
|
|
import xmltodict
|
|
|
|
import yaml
|
|
|
|
import re
|
|
|
|
import json
|
|
|
|
import os
|
|
|
|
import toml
|
|
|
|
from collections import OrderedDict
|
|
|
|
from glob import glob
|
|
|
|
|
|
|
|
abspath = os.path.abspath(__file__)
|
|
|
|
dname = os.path.dirname(abspath)
|
|
|
|
os.chdir(dname)
|
|
|
|
|
2021-04-25 20:35:51 +00:00
|
|
|
# ======= load chips
|
2021-04-20 01:37:49 +00:00
|
|
|
chips = {}
|
|
|
|
for f in sorted(glob('stm32-data/data/chips/*.yaml')):
|
2021-04-26 18:11:46 +00:00
|
|
|
if 'STM32F4' not in f and 'STM32L4' not in f:
|
2021-04-20 01:37:49 +00:00
|
|
|
continue
|
|
|
|
with open(f, 'r') as f:
|
|
|
|
chip = yaml.load(f, Loader=yaml.SafeLoader)
|
|
|
|
chip['name'] = chip['name'].lower()
|
|
|
|
print(chip['name'])
|
|
|
|
chips[chip['name']] = chip
|
|
|
|
|
2021-04-25 20:35:51 +00:00
|
|
|
# ======= load GPIO AF
|
|
|
|
gpio_afs = {}
|
|
|
|
for f in sorted(glob('stm32-data/data/gpio_af/*.yaml')):
|
|
|
|
name = f.split('/')[-1].split('.')[0]
|
|
|
|
with open(f, 'r') as f:
|
|
|
|
af = yaml.load(f, Loader=yaml.SafeLoader)
|
|
|
|
gpio_afs[name] = af
|
|
|
|
|
2021-04-20 01:37:49 +00:00
|
|
|
# ========= Update chip/mod.rs
|
|
|
|
|
|
|
|
with open('src/chip/mod.rs', 'w') as f:
|
|
|
|
for chip in chips.values():
|
|
|
|
f.write(
|
|
|
|
f'#[cfg_attr(feature="{chip["name"]}", path="{chip["name"]}.rs")]\n')
|
|
|
|
f.write('mod chip;\n')
|
|
|
|
f.write('pub use chip::*;\n')
|
|
|
|
|
|
|
|
# ========= Update Cargo features
|
|
|
|
|
|
|
|
features = {name: [] for name, chip in chips.items()}
|
|
|
|
|
|
|
|
SEPARATOR_START = '# BEGIN GENERATED FEATURES\n'
|
|
|
|
SEPARATOR_END = '# END GENERATED FEATURES\n'
|
|
|
|
|
|
|
|
with open('Cargo.toml', 'r') as f:
|
|
|
|
cargo = f.read()
|
|
|
|
before, cargo = cargo.split(SEPARATOR_START, maxsplit=1)
|
|
|
|
_, after = cargo.split(SEPARATOR_END, maxsplit=1)
|
|
|
|
cargo = before + SEPARATOR_START + toml.dumps(features) + SEPARATOR_END + after
|
|
|
|
with open('Cargo.toml', 'w') as f:
|
|
|
|
f.write(cargo)
|
|
|
|
|
|
|
|
# ========= Generate per-chip mod
|
|
|
|
|
|
|
|
for chip in chips.values():
|
2021-04-23 21:47:34 +00:00
|
|
|
print(f'generating {chip["name"]}')
|
2021-04-25 20:35:51 +00:00
|
|
|
af = gpio_afs[chip['gpio_af']]
|
2021-04-20 01:37:49 +00:00
|
|
|
peripherals = []
|
2021-04-23 21:47:34 +00:00
|
|
|
impls = []
|
|
|
|
pins = set()
|
|
|
|
|
|
|
|
# TODO this should probably come from the yamls?
|
|
|
|
# We don't want to hardcode the EXTI peripheral addr
|
2021-04-20 01:37:49 +00:00
|
|
|
peripherals.extend((f'EXTI{x}' for x in range(16)))
|
|
|
|
|
2021-05-05 14:18:09 +00:00
|
|
|
exti_base = chip['peripherals']['EXTI']['address']
|
|
|
|
syscfg_base = chip['peripherals']['SYSCFG']['address']
|
2021-04-23 21:47:34 +00:00
|
|
|
gpio_base = chip['peripherals']['GPIOA']['address']
|
|
|
|
gpio_stride = 0x400
|
|
|
|
|
|
|
|
for (name, peri) in chip['peripherals'].items():
|
|
|
|
if name.startswith('GPIO'):
|
|
|
|
port = name[4:]
|
|
|
|
port_num = ord(port) - ord('A')
|
|
|
|
|
|
|
|
assert peri['address'] == gpio_base + gpio_stride*port_num
|
|
|
|
|
|
|
|
for pin_num in range(16):
|
|
|
|
pin = f'P{port}{pin_num}'
|
|
|
|
pins.add(pin)
|
|
|
|
peripherals.append(pin)
|
2021-04-25 20:35:51 +00:00
|
|
|
impls.append(f'impl_gpio_pin!({pin}, {port_num}, {pin_num}, EXTI{pin_num});')
|
2021-04-23 21:47:34 +00:00
|
|
|
continue
|
|
|
|
|
|
|
|
# TODO maybe we should only autogenerate the known ones...??
|
|
|
|
peripherals.append(name)
|
2021-04-20 01:37:49 +00:00
|
|
|
|
2021-04-25 20:35:51 +00:00
|
|
|
if 'block' not in peri:
|
|
|
|
continue
|
|
|
|
|
2021-05-01 01:07:17 +00:00
|
|
|
if peri['block'] in ('usart_v1/USART', 'usart_v1/UART'):
|
2021-04-25 20:35:51 +00:00
|
|
|
impls.append(f'impl_usart!({name}, 0x{peri["address"]:x});')
|
|
|
|
for pin, funcs in af.items():
|
|
|
|
if pin in pins:
|
|
|
|
if func := funcs.get(f'{name}_RX'):
|
|
|
|
impls.append(f'impl_usart_pin!({name}, RxPin, {pin}, {func});')
|
|
|
|
if func := funcs.get(f'{name}_TX'):
|
|
|
|
impls.append(f'impl_usart_pin!({name}, TxPin, {pin}, {func});')
|
|
|
|
if func := funcs.get(f'{name}_CTS'):
|
|
|
|
impls.append(f'impl_usart_pin!({name}, CtsPin, {pin}, {func});')
|
|
|
|
if func := funcs.get(f'{name}_RTS'):
|
|
|
|
impls.append(f'impl_usart_pin!({name}, RtsPin, {pin}, {func});')
|
|
|
|
if func := funcs.get(f'{name}_CK'):
|
|
|
|
impls.append(f'impl_usart_pin!({name}, CkPin, {pin}, {func});')
|
|
|
|
|
2021-04-26 18:11:46 +00:00
|
|
|
if peri['block'] == 'rng_v1/RNG':
|
|
|
|
impls.append(f'impl_rng!(0x{peri["address"]:x});')
|
|
|
|
|
2021-05-01 01:07:17 +00:00
|
|
|
irq_variants = []
|
|
|
|
irq_vectors = []
|
|
|
|
irq_fns = []
|
|
|
|
irq_declares = []
|
|
|
|
|
|
|
|
irqs = {num: name for name, num in chip['interrupts'].items()}
|
|
|
|
irq_count = max(irqs.keys()) + 1
|
|
|
|
for num, name in irqs.items():
|
|
|
|
irq_variants.append(f'{name} = {num},')
|
|
|
|
irq_fns.append(f'fn {name}();')
|
|
|
|
irq_declares.append(f'declare!({name});')
|
|
|
|
for num in range(irq_count):
|
|
|
|
if name := irqs.get(num):
|
|
|
|
irq_vectors.append(f'Vector {{ _handler: {name} }},')
|
|
|
|
else:
|
|
|
|
irq_vectors.append(f'Vector {{ _reserved: 0 }},')
|
2021-04-20 01:37:49 +00:00
|
|
|
|
2021-05-01 01:07:17 +00:00
|
|
|
with open(f'src/chip/{chip["name"]}.rs', 'w') as f:
|
2021-04-20 01:37:49 +00:00
|
|
|
f.write(f"""
|
2021-05-01 01:07:17 +00:00
|
|
|
use embassy_extras::peripherals;
|
|
|
|
peripherals!({','.join(peripherals)});
|
2021-05-05 14:18:09 +00:00
|
|
|
pub const SYSCFG_BASE: usize = 0x{syscfg_base:x};
|
|
|
|
pub const EXTI_BASE: usize = 0x{exti_base:x};
|
2021-05-01 01:07:17 +00:00
|
|
|
pub const GPIO_BASE: usize = 0x{gpio_base:x};
|
|
|
|
pub const GPIO_STRIDE: usize = 0x{gpio_stride:x};
|
|
|
|
|
|
|
|
pub mod interrupt {{
|
|
|
|
pub use cortex_m::interrupt::{{CriticalSection, Mutex}};
|
|
|
|
pub use embassy::interrupt::{{declare, take, Interrupt}};
|
|
|
|
pub use embassy_extras::interrupt::Priority4 as Priority;
|
|
|
|
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
|
|
#[allow(non_camel_case_types)]
|
|
|
|
enum InterruptEnum {{
|
|
|
|
{''.join(irq_variants)}
|
|
|
|
}}
|
|
|
|
unsafe impl cortex_m::interrupt::InterruptNumber for InterruptEnum {{
|
|
|
|
#[inline(always)]
|
|
|
|
fn number(self) -> u16 {{
|
|
|
|
self as u16
|
|
|
|
}}
|
|
|
|
}}
|
|
|
|
|
|
|
|
{''.join(irq_declares)}
|
|
|
|
}}
|
|
|
|
mod interrupt_vector {{
|
|
|
|
extern "C" {{
|
|
|
|
{''.join(irq_fns)}
|
|
|
|
}}
|
|
|
|
pub union Vector {{
|
|
|
|
_handler: unsafe extern "C" fn(),
|
|
|
|
_reserved: u32,
|
|
|
|
}}
|
|
|
|
#[link_section = ".vector_table.interrupts"]
|
|
|
|
#[no_mangle]
|
|
|
|
pub static __INTERRUPTS: [Vector; {irq_count}] = [
|
|
|
|
{''.join(irq_vectors)}
|
|
|
|
];
|
|
|
|
}}
|
2021-04-20 01:37:49 +00:00
|
|
|
""")
|
2021-04-23 21:47:34 +00:00
|
|
|
for i in impls:
|
|
|
|
f.write(i)
|
2021-04-20 01:37:49 +00:00
|
|
|
|
|
|
|
|
2021-04-23 21:47:34 +00:00
|
|
|
# format
|
|
|
|
os.system('rustfmt src/chip/*')
|