一、前言传统EB引脚配置的痛点近期在做国芯516pin芯片的EB配置开发工作该芯片引脚数量多、PORT端口占用量大引脚功能配置繁杂。在传统手动配置模式下仅PORT引脚的参数配置工作就需要耗费大量时间和人力同时存在两个核心痛点1.效率极低数百个引脚的模式、方向、上下拉、功能复用等参数需要逐一点击配置重复性操作多耗时耗力2.出错率高人工手动配置极易出现参数填错、引脚漏配、功能选错等问题后续排查纠错成本极高。为解决以上问题我摸索出一套ExcelPython自动化EB引脚配置方案通过表格统一管理引脚参数脚本自动解析生成标准ARXML配置文件再导入EB工具生成最终CFG配置文件彻底替代手动配置大幅提升开发效率、规避人工错误。二、整体自动化实现思路整套方案核心逻辑标准化Excel引脚参数表格 → Python脚本批量解析 → 自动生成EB识别的ARXML文件 → EB导入文件一键生成CFG配置全程无需手动逐个配置引脚参数。整体落地流程分为四大步骤制作ARXML模板、定位EB核心配置脚本、搭建标准化Excel配置表、编写Python自动生成脚本最终完成EB导入生成。三、详细落地实操流程1、导出EB标准PORT配置ARXML模板ARXML是EB工具的标准配置导入文件想要实现自动配置首先需要获取适配当前芯片、当前EB工程的标准ARXML模板保证后续生成的文件格式、字段、参数完全兼容EB工具。模板导出步骤在EB工程的项目名称上右键选择导入导出功能根据工具指引导出当前工程PORT模块的标准ARXML配置文件作为后续脚本生成文件的基准模板。2、定位EB底层配置参数文件.m文件EB所有PORT引脚的配置参数、模式定义、属性规则均由对应的.m配置文件定义这是保障自动化配置参数精准有效的核心依据。文件存放路径EB安装目录下的plugins\Port_ARCH3DXXM10I0RX\generate文件夹中该文件定义了PORT引脚的全部可配置参数包含引脚模式、端口方向、复用功能、上下拉模式等所有EB可视化配置选项后续Excel表格的字段、Python脚本的参数映射均需要严格对齐该文件的参数规则。3、搭建标准化Excel引脚配置表为了统一管理所有引脚参数规避配置混乱完全参照EB工具的原生配置选项搭建专属Excel配置表格。所有引脚参数提前从芯片pinmux手册中筛选提取统一录入表格实现引脚配置标准化、可追溯、可批量修改。Excel核心配置字段完全对齐EB配置项ID引脚唯一标识PCR引脚控制寄存器配置参数DIR引脚方向配置输入/输出FUNCTION引脚复用功能配置PULLPUSH引脚上下拉/推挽模式配置拓展字段可根据EB实际配置项新增速率、中断模式、默认电平参数等所有引脚配置信息统一录入表格后后续修改、新增、删除引脚配置仅需编辑表格即可无需操作EB工具。4、Python脚本自动化生成ARXML文件基于搭建好的Excel表格和标准ARXML模板编写Python自动化解析生成脚本。脚本核心功能1. 批量读取Excel表格中所有引脚的标准化配置参数2. 按照EB的ARXML模板格式、.m文件参数规则自动填充、替换模板中的引脚配置内容3. 批量生成可被EB工具直接识别、导入的完整ARXML配置文件。脚本运行后无需人工干预一键生成完整引脚配置文件彻底解放双手。5、EB导入配置一键生成CFG文件1. 打开EB工程通过导入功能将Python脚本生成的ARXML文件导入工程2. 导入完成后直接点击EB生成按钮即可自动生成对应的PORT配置CFG文件3. 最终配置效果与手动逐一点击配置完全一致且参数零错误、高效率。四、方案核心优势1.效率质变数百个引脚配置从数小时人工操作缩短至几十秒脚本自动生成极大节省开发工时2.零人工误差参数统一基于pinmux手册录入表格脚本精准映射参数彻底杜绝人工漏配、错配问题3.可维护性强所有引脚配置集中在Excel表格版本管理、参数修改、批量迭代极其方便4.通用性高方案可适配同系列多款芯片仅需更新Excel字段和对应ARXML模板即可复用。五、方案使用限制与注意事项该自动化方案稳定性依赖两大核心条件也是方案最大的使用限制实操过程中需要重点注意1.MCU Pinmux手册必须稳定芯片引脚功能、寄存器参数、复用定义不能频繁变更若pinmux参数迭代更新会导致表格参数与实际芯片定义不匹配生成的配置文件存在隐患2.EB插件配置规则固定EB对应的PORT插件、.m底层配置文件参数规则不能改动。一旦EB插件更新、参数字段变更会出现Excel参数、脚本映射规则与EB解析规则不匹配导致ARXML配置失效、报错。总结只要芯片Pinmux定义、EB插件配置规则保持稳定这套自动化方案可以完美落地大幅提升PORT引脚配置效率降低开发失误率。六、资源开源说明本文配套全部源文件已整理完毕包含标准化Excel引脚配置模板、Python自动生成脚本、EB标准ARXML模板文件大家可以直接下载作为参考。七、总结与展望传统EB引脚手动配置模式在多引脚芯片开发中存在明显短板效率低、容错率差。而ExcelPythonARXML的自动化配置方案通过标准化、脚本化、批量化的思路完美解决了多引脚PORT配置的痛点。后续可继续优化脚本功能增加参数校验、异常报错、配置比对功能进一步提升方案的稳定性和智能化程度适配更多型号芯片的EB自动化配置开发。python代码如下import xml.etree.ElementTree as ET import pandas as pd import re import os # 全局路径配置 EXCEL_PATH rC:/Users/ccore/Desktop/08PCSN_EB_Config.xlsx ORIGINAL_ARXML_PATH rC:/Users/ccore/Desktop/EPS_3008PCSN_HL/EB_TEST.arxml OUTPUT_ARXML_PATH rC:/Users/ccore/Desktop/EPS_3008PCSN_HL/EB_TEST_FIXED.arxml RESOURCE_FILE_PATH rD:/EB/plugins/Port_ARCH3DXXM10I0RX/generate/Matterhorn_Resource_Ccfc3008pcsn.m NS {ns: http://autosar.org/schema/r4.0} ET.register_namespace(, http://autosar.org/schema/r4.0) ET.register_namespace(xsi, http://www.w3.org/2001/XMLSchema-instance) def bool_to_int(value): if pd.isna(value): return 0 val_str str(value).strip() if val_str in [是, true, True, 1]: return 1 return 0 def normalize_mode_name(mode_name): if not mode_name: return mode_name name mode_name.strip().upper() replacements { SENTO: SENT0, # 数字0容易写成字母O SENT0_RX: SENT0_RX, # 已正确则不变 GTM_TOMO: GTM_TOM, # 修正可能缺少的 M } for old, new in replacements.items(): if old in name: name name.replace(old, new) return name def parse_resource_pinmap(resource_path, keep_firstTrue, override_mapNone, verboseFalse): with open(resource_path, r, encodingutf-8) as f: content f.read() # 定位 $PortUseEIOMUX1 分支 start_marker [!IF $PortUseEIOMUX1!] end_marker [!ELSE!] start_pos content.find(start_marker) if start_pos -1: print(警告未找到 $PortUseEIOMUX1 分支将尝试提取所有 _PORT 条目。) pinmap_section content else: end_pos content.find(end_marker, start_pos) if end_pos -1: end_pos content.find([!ENDIF!], start_pos) if end_pos -1: pinmap_section content[start_pos len(start_marker):] else: pinmap_section content[start_pos len(start_marker):end_pos] else: pinmap_section content[start_pos len(start_marker):end_pos] # 提取 PinMap 变量 pinmap_pattern re.compile(r\[\!VAR PinMap\!\](.*?)\[\!ENDVAR\!\], re.DOTALL) pinmap_match pinmap_pattern.search(pinmap_section) if pinmap_match: pinmap_text pinmap_match.group(1) else: print(警告未找到 PinMap 变量将尝试从当前块中提取所有 _PORT 条目。) pinmap_text pinmap_section # 匹配所有 _PORT 条目 pattern re.compile(r([A-Za-z0-9_])_PORT(\d);(\d)) matches pattern.findall(pinmap_text) if not matches: print(警告在 PortUseEIOMUX1 分支中未找到任何 _PORT 条目。) return {} temp {} for mode_name, pcr_str, idx_str in matches: pcr int(pcr_str) idx int(idx_str) if pcr not in temp: temp[pcr] {} if idx in temp[pcr]: if keep_first: if verbose: print(f警告PCR{pcr} 索引{idx} 重复定义保留第一个 {temp[pcr][idx]}忽略 {mode_name}) else: if verbose: print(f警告PCR{pcr} 索引{idx} 重复定义覆盖为 {mode_name}) temp[pcr][idx] mode_name else: temp[pcr][idx] mode_name # 应用手动覆盖 if override_map: for pcr, idx_dict in override_map.items(): if pcr not in temp: temp[pcr] {} for idx, mode in idx_dict.items(): temp[pcr][idx] mode print(f手动修正PCR{pcr} 索引{idx} 设置为 {mode}) # 转换为列表缺失索引用 GPIO 补位 pcr_mode_map {} for pcr, idx_dict in temp.items(): max_idx max(idx_dict.keys()) mode_list [None] * (max_idx 1) for idx, mode in idx_dict.items(): mode_list[idx] mode mode_list [m if m is not None else PORT_PIN_MODE_GPIO for m in mode_list] pcr_mode_map[pcr] mode_list print(f解析完成共识别到 {len(pcr_mode_map)} 个 PCR 的映射。) return pcr_mode_map def create_parameter_node(parent, param_type, def_ref, value): param ET.SubElement(parent, param_type) def_node ET.SubElement(param, DEFINITION-REF) def_node.text def_ref.strip() val_node ET.SubElement(param, VALUE) val_node.text str(value).strip() return param def create_pin_container(pin_name, pin_row, pcr_map): 单引脚 ECUC-CONTAINER-VALUE 生成适配新 Excel 列名 pin_container ET.Element(ECUC-CONTAINER-VALUE) ET.SubElement(pin_container, SHORT-NAME).text pin_name def_ref ET.SubElement(pin_container, DEFINITION-REF) def_ref.text /PortConfig/Port/PortConfigSet/PortContainer/PortPin param_root ET.SubElement(pin_container, PARAMETER-VALUES) # ---------- 布尔参数新列名 ---------- create_parameter_node(param_root, ECUC-NUMERICAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinWpde, bool_to_int(pin_row.get(PinWpde, 否))) create_parameter_node(param_root, ECUC-NUMERICAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinWpue, bool_to_int(pin_row.get(PinWpue, 否))) create_parameter_node(param_root, ECUC-NUMERICAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinSafeMode, bool_to_int(pin_row.get(Pin Safe Mode, 否))) create_parameter_node(param_root, ECUC-NUMERICAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinWithReadBack, bool_to_int(pin_row.get(PinWithReadBack, 否))) create_parameter_node(param_root, ECUC-NUMERICAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinHysteresisControl, bool_to_int(pin_row.get(PinHysteresisControl, 否))) create_parameter_node(param_root, ECUC-NUMERICAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinModeChangeable, bool_to_int(pin_row.get(Pin Mode Changeable, 否))) create_parameter_node(param_root, ECUC-NUMERICAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinDirectionChangeable, bool_to_int(pin_row.get(Pin Direction Changeable, 否))) # ---------- 方向参数将 O/I 转为完整枚举 ---------- raw_dir str(pin_row.get(Pin Direction, I)).strip().upper() if raw_dir O: direction_val PORT_PIN_OUT else: # 默认输入 direction_val PORT_PIN_IN create_parameter_node(param_root, ECUC-TEXTUAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinDirection, direction_val) # ---------- 其他数值/文本参数新列名 ---------- create_parameter_node(param_root, ECUC-NUMERICAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinId, pin_row.get(Pin Id, 0)) create_parameter_node(param_root, ECUC-NUMERICAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinPcr, pin_row.get(tPinPcr, 0)) # 注意PortPin Initial Mode 已被删除不再生成节点 create_parameter_node(param_root, ECUC-TEXTUAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinInputLevelSelection, pin_row.get(PinInputLevelSelection, AUTOMOTIVE)) create_parameter_node(param_root, ECUC-TEXTUAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinLevelValue, pin_row.get(Pin Level Value, PORT_PIN_LEVEL_LOW)) create_parameter_node(param_root, ECUC-TEXTUAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinOutputDriveControl, pin_row.get(PinOutputDriveControl, PORT_OUTPUT_BUFFER_DISABLED)) create_parameter_node(param_root, ECUC-TEXTUAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinOutputEdgeRateControl, pin_row.get(PinOutputEdgeRateControl, WEAK_DRIVE)) # ---------- 核心PortPinMode 处理 ---------- # 优先使用 Excel 中手动填写的 PinMode custom_mode str(pin_row.get(PinMode, )).strip() if custom_mode and custom_mode ! : # 简单标准化若需要可调用 normalize_mode_name pin_mode custom_mode print(f使用自定义模式[{pin_name}]{pin_mode}) else: # 否则根据方向和 FuncIndex 查找 try: pcr_num int(pin_row.get(tPinPcr, 0)) func_idx int(pin_row.get(FuncIndex, 0)) direction str(pin_row.get(Pin Direction, I)).strip().upper() if direction O: actual_index func_idx 20 else: # 输入 actual_index func_idx except Exception as e: print(f警告[{pin_name}]数值异常默认GPIOerr{e}) pin_mode PORT_PIN_MODE_GPIO else: if pcr_num in pcr_map: mode_list pcr_map[pcr_num] if 0 actual_index len(mode_list): pin_mode mode_list[actual_index] dir_desc OUT if direction O else IN print(f匹配[{pin_name}] PCR{pcr_num} {dir_desc} 索引{actual_index} → {pin_mode}) else: print(f警告[{pin_name}] 索引{actual_index}越界PCR{pcr_num}长度{len(mode_list)}使用GPIO) pin_mode PORT_PIN_MODE_GPIO else: print(f警告[{pin_name}] PCR{pcr_num}未定义使用GPIO) pin_mode PORT_PIN_MODE_GPIO create_parameter_node(param_root, ECUC-TEXTUAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinMode, pin_mode) ET.SubElement(pin_container, SUB-CONTAINERS) return pin_container def main(): print( 开始解析 C*Core 资源文件仅 PortUseEIOMUX1 分支 ) pcr_mode_map parse_resource_pinmap(RESOURCE_FILE_PATH, keep_firstTrue) print(f资源解析完成PCR 列表{sorted(pcr_mode_map.keys())}\n) print( 读取 Excel 引脚配置 ) df pd.read_excel(EXCEL_PATH) df.columns df.columns.str.strip() # 去除列名空格 # 必要列名称已更新 required_cols [名称, 分组名称, PinPcr, FuncIndex] missing [col for col in required_cols if col not in df.columns] if missing: print(f错误Excel 缺少必要列{missing}) return df_valid df.dropna(subsetrequired_cols).reset_index(dropTrue) print(fExcel 有效引脚行数{len(df_valid)}) # 统计分组 group_count {} for _, row in df_valid.iterrows(): g row[分组名称] group_count[g] group_count.get(g, 0) 1 print(\n 加载原始 ARXML 文件 ) if not os.path.exists(ORIGINAL_ARXML_PATH): print(f错误原始 ARXML 不存在 {ORIGINAL_ARXML_PATH}) return tree ET.parse(ORIGINAL_ARXML_PATH) root tree.getroot() port_cfg_set root.find(.//ns:ECUC-CONTAINER-VALUE[ns:SHORT-NAMEPortConfigSet], NS) if port_cfg_set is None: print(ERROR未找到 PortConfigSet 节点) return sub_root port_cfg_set.find(ns:SUB-CONTAINERS, NS) if sub_root is None: sub_root ET.SubElement(port_cfg_set, SUB-CONTAINERS) else: old_groups sub_root.findall(ns:ECUC-CONTAINER-VALUE, NS) for g in old_groups: sub_root.remove(g) print(已清空原有 Port 分组) group_dict {} print(\n 创建 Port 分组容器 ) for g_name, pin_total in group_count.items(): group_node ET.SubElement(sub_root, ECUC-CONTAINER-VALUE) ET.SubElement(group_node, SHORT-NAME).text g_name def_ref ET.SubElement(group_node, DEFINITION-REF) def_ref.text /PortConfig/Port/PortConfigSet/PortContainer param_grp ET.SubElement(group_node, PARAMETER-VALUES) num_param ET.SubElement(param_grp, ECUC-NUMERICAL-PARAM-VALUE) num_def ET.SubElement(num_param, DEFINITION-REF) num_def.text /PortConfig/Port/PortConfigSet/PortContainer/PortNumberOfPortPins ET.SubElement(num_param, VALUE).text str(pin_total) ET.SubElement(group_node, SUB-CONTAINERS) group_dict[g_name] group_node print(f创建分组【{g_name}】引脚总数{pin_total}) print(\n 批量生成引脚配置 ) for _, row in df_valid.iterrows(): pin_name row[名称] g_name row[分组名称] group_node group_dict.get(g_name) if group_node is None: print(f跳过{pin_name}分组{g_name}不存在) continue pin_parent group_node.find(SUB-CONTAINERS) exist_pin pin_parent.find(fECUC-CONTAINER-VALUE[SHORT-NAME{pin_name}]) if exist_pin is not None: print(f跳过重复引脚 {g_name}/{pin_name}) continue pin_elem create_pin_container(pin_name, row, pcr_mode_map) pin_parent.append(pin_elem) print(f\n 输出修复后 ARXML{OUTPUT_ARXML_PATH} ) ET.indent(tree, space ) tree.write(OUTPUT_ARXML_PATH, encodingutf-8, xml_declarationTrue) print(✅ ARXML 生成完成。) if __name__ __main__: main()
EB引脚配置自动化方案|告别手动繁琐配PIN,Excel+Python批量生成ARXML实现一键配置
一、前言传统EB引脚配置的痛点近期在做国芯516pin芯片的EB配置开发工作该芯片引脚数量多、PORT端口占用量大引脚功能配置繁杂。在传统手动配置模式下仅PORT引脚的参数配置工作就需要耗费大量时间和人力同时存在两个核心痛点1.效率极低数百个引脚的模式、方向、上下拉、功能复用等参数需要逐一点击配置重复性操作多耗时耗力2.出错率高人工手动配置极易出现参数填错、引脚漏配、功能选错等问题后续排查纠错成本极高。为解决以上问题我摸索出一套ExcelPython自动化EB引脚配置方案通过表格统一管理引脚参数脚本自动解析生成标准ARXML配置文件再导入EB工具生成最终CFG配置文件彻底替代手动配置大幅提升开发效率、规避人工错误。二、整体自动化实现思路整套方案核心逻辑标准化Excel引脚参数表格 → Python脚本批量解析 → 自动生成EB识别的ARXML文件 → EB导入文件一键生成CFG配置全程无需手动逐个配置引脚参数。整体落地流程分为四大步骤制作ARXML模板、定位EB核心配置脚本、搭建标准化Excel配置表、编写Python自动生成脚本最终完成EB导入生成。三、详细落地实操流程1、导出EB标准PORT配置ARXML模板ARXML是EB工具的标准配置导入文件想要实现自动配置首先需要获取适配当前芯片、当前EB工程的标准ARXML模板保证后续生成的文件格式、字段、参数完全兼容EB工具。模板导出步骤在EB工程的项目名称上右键选择导入导出功能根据工具指引导出当前工程PORT模块的标准ARXML配置文件作为后续脚本生成文件的基准模板。2、定位EB底层配置参数文件.m文件EB所有PORT引脚的配置参数、模式定义、属性规则均由对应的.m配置文件定义这是保障自动化配置参数精准有效的核心依据。文件存放路径EB安装目录下的plugins\Port_ARCH3DXXM10I0RX\generate文件夹中该文件定义了PORT引脚的全部可配置参数包含引脚模式、端口方向、复用功能、上下拉模式等所有EB可视化配置选项后续Excel表格的字段、Python脚本的参数映射均需要严格对齐该文件的参数规则。3、搭建标准化Excel引脚配置表为了统一管理所有引脚参数规避配置混乱完全参照EB工具的原生配置选项搭建专属Excel配置表格。所有引脚参数提前从芯片pinmux手册中筛选提取统一录入表格实现引脚配置标准化、可追溯、可批量修改。Excel核心配置字段完全对齐EB配置项ID引脚唯一标识PCR引脚控制寄存器配置参数DIR引脚方向配置输入/输出FUNCTION引脚复用功能配置PULLPUSH引脚上下拉/推挽模式配置拓展字段可根据EB实际配置项新增速率、中断模式、默认电平参数等所有引脚配置信息统一录入表格后后续修改、新增、删除引脚配置仅需编辑表格即可无需操作EB工具。4、Python脚本自动化生成ARXML文件基于搭建好的Excel表格和标准ARXML模板编写Python自动化解析生成脚本。脚本核心功能1. 批量读取Excel表格中所有引脚的标准化配置参数2. 按照EB的ARXML模板格式、.m文件参数规则自动填充、替换模板中的引脚配置内容3. 批量生成可被EB工具直接识别、导入的完整ARXML配置文件。脚本运行后无需人工干预一键生成完整引脚配置文件彻底解放双手。5、EB导入配置一键生成CFG文件1. 打开EB工程通过导入功能将Python脚本生成的ARXML文件导入工程2. 导入完成后直接点击EB生成按钮即可自动生成对应的PORT配置CFG文件3. 最终配置效果与手动逐一点击配置完全一致且参数零错误、高效率。四、方案核心优势1.效率质变数百个引脚配置从数小时人工操作缩短至几十秒脚本自动生成极大节省开发工时2.零人工误差参数统一基于pinmux手册录入表格脚本精准映射参数彻底杜绝人工漏配、错配问题3.可维护性强所有引脚配置集中在Excel表格版本管理、参数修改、批量迭代极其方便4.通用性高方案可适配同系列多款芯片仅需更新Excel字段和对应ARXML模板即可复用。五、方案使用限制与注意事项该自动化方案稳定性依赖两大核心条件也是方案最大的使用限制实操过程中需要重点注意1.MCU Pinmux手册必须稳定芯片引脚功能、寄存器参数、复用定义不能频繁变更若pinmux参数迭代更新会导致表格参数与实际芯片定义不匹配生成的配置文件存在隐患2.EB插件配置规则固定EB对应的PORT插件、.m底层配置文件参数规则不能改动。一旦EB插件更新、参数字段变更会出现Excel参数、脚本映射规则与EB解析规则不匹配导致ARXML配置失效、报错。总结只要芯片Pinmux定义、EB插件配置规则保持稳定这套自动化方案可以完美落地大幅提升PORT引脚配置效率降低开发失误率。六、资源开源说明本文配套全部源文件已整理完毕包含标准化Excel引脚配置模板、Python自动生成脚本、EB标准ARXML模板文件大家可以直接下载作为参考。七、总结与展望传统EB引脚手动配置模式在多引脚芯片开发中存在明显短板效率低、容错率差。而ExcelPythonARXML的自动化配置方案通过标准化、脚本化、批量化的思路完美解决了多引脚PORT配置的痛点。后续可继续优化脚本功能增加参数校验、异常报错、配置比对功能进一步提升方案的稳定性和智能化程度适配更多型号芯片的EB自动化配置开发。python代码如下import xml.etree.ElementTree as ET import pandas as pd import re import os # 全局路径配置 EXCEL_PATH rC:/Users/ccore/Desktop/08PCSN_EB_Config.xlsx ORIGINAL_ARXML_PATH rC:/Users/ccore/Desktop/EPS_3008PCSN_HL/EB_TEST.arxml OUTPUT_ARXML_PATH rC:/Users/ccore/Desktop/EPS_3008PCSN_HL/EB_TEST_FIXED.arxml RESOURCE_FILE_PATH rD:/EB/plugins/Port_ARCH3DXXM10I0RX/generate/Matterhorn_Resource_Ccfc3008pcsn.m NS {ns: http://autosar.org/schema/r4.0} ET.register_namespace(, http://autosar.org/schema/r4.0) ET.register_namespace(xsi, http://www.w3.org/2001/XMLSchema-instance) def bool_to_int(value): if pd.isna(value): return 0 val_str str(value).strip() if val_str in [是, true, True, 1]: return 1 return 0 def normalize_mode_name(mode_name): if not mode_name: return mode_name name mode_name.strip().upper() replacements { SENTO: SENT0, # 数字0容易写成字母O SENT0_RX: SENT0_RX, # 已正确则不变 GTM_TOMO: GTM_TOM, # 修正可能缺少的 M } for old, new in replacements.items(): if old in name: name name.replace(old, new) return name def parse_resource_pinmap(resource_path, keep_firstTrue, override_mapNone, verboseFalse): with open(resource_path, r, encodingutf-8) as f: content f.read() # 定位 $PortUseEIOMUX1 分支 start_marker [!IF $PortUseEIOMUX1!] end_marker [!ELSE!] start_pos content.find(start_marker) if start_pos -1: print(警告未找到 $PortUseEIOMUX1 分支将尝试提取所有 _PORT 条目。) pinmap_section content else: end_pos content.find(end_marker, start_pos) if end_pos -1: end_pos content.find([!ENDIF!], start_pos) if end_pos -1: pinmap_section content[start_pos len(start_marker):] else: pinmap_section content[start_pos len(start_marker):end_pos] else: pinmap_section content[start_pos len(start_marker):end_pos] # 提取 PinMap 变量 pinmap_pattern re.compile(r\[\!VAR PinMap\!\](.*?)\[\!ENDVAR\!\], re.DOTALL) pinmap_match pinmap_pattern.search(pinmap_section) if pinmap_match: pinmap_text pinmap_match.group(1) else: print(警告未找到 PinMap 变量将尝试从当前块中提取所有 _PORT 条目。) pinmap_text pinmap_section # 匹配所有 _PORT 条目 pattern re.compile(r([A-Za-z0-9_])_PORT(\d);(\d)) matches pattern.findall(pinmap_text) if not matches: print(警告在 PortUseEIOMUX1 分支中未找到任何 _PORT 条目。) return {} temp {} for mode_name, pcr_str, idx_str in matches: pcr int(pcr_str) idx int(idx_str) if pcr not in temp: temp[pcr] {} if idx in temp[pcr]: if keep_first: if verbose: print(f警告PCR{pcr} 索引{idx} 重复定义保留第一个 {temp[pcr][idx]}忽略 {mode_name}) else: if verbose: print(f警告PCR{pcr} 索引{idx} 重复定义覆盖为 {mode_name}) temp[pcr][idx] mode_name else: temp[pcr][idx] mode_name # 应用手动覆盖 if override_map: for pcr, idx_dict in override_map.items(): if pcr not in temp: temp[pcr] {} for idx, mode in idx_dict.items(): temp[pcr][idx] mode print(f手动修正PCR{pcr} 索引{idx} 设置为 {mode}) # 转换为列表缺失索引用 GPIO 补位 pcr_mode_map {} for pcr, idx_dict in temp.items(): max_idx max(idx_dict.keys()) mode_list [None] * (max_idx 1) for idx, mode in idx_dict.items(): mode_list[idx] mode mode_list [m if m is not None else PORT_PIN_MODE_GPIO for m in mode_list] pcr_mode_map[pcr] mode_list print(f解析完成共识别到 {len(pcr_mode_map)} 个 PCR 的映射。) return pcr_mode_map def create_parameter_node(parent, param_type, def_ref, value): param ET.SubElement(parent, param_type) def_node ET.SubElement(param, DEFINITION-REF) def_node.text def_ref.strip() val_node ET.SubElement(param, VALUE) val_node.text str(value).strip() return param def create_pin_container(pin_name, pin_row, pcr_map): 单引脚 ECUC-CONTAINER-VALUE 生成适配新 Excel 列名 pin_container ET.Element(ECUC-CONTAINER-VALUE) ET.SubElement(pin_container, SHORT-NAME).text pin_name def_ref ET.SubElement(pin_container, DEFINITION-REF) def_ref.text /PortConfig/Port/PortConfigSet/PortContainer/PortPin param_root ET.SubElement(pin_container, PARAMETER-VALUES) # ---------- 布尔参数新列名 ---------- create_parameter_node(param_root, ECUC-NUMERICAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinWpde, bool_to_int(pin_row.get(PinWpde, 否))) create_parameter_node(param_root, ECUC-NUMERICAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinWpue, bool_to_int(pin_row.get(PinWpue, 否))) create_parameter_node(param_root, ECUC-NUMERICAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinSafeMode, bool_to_int(pin_row.get(Pin Safe Mode, 否))) create_parameter_node(param_root, ECUC-NUMERICAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinWithReadBack, bool_to_int(pin_row.get(PinWithReadBack, 否))) create_parameter_node(param_root, ECUC-NUMERICAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinHysteresisControl, bool_to_int(pin_row.get(PinHysteresisControl, 否))) create_parameter_node(param_root, ECUC-NUMERICAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinModeChangeable, bool_to_int(pin_row.get(Pin Mode Changeable, 否))) create_parameter_node(param_root, ECUC-NUMERICAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinDirectionChangeable, bool_to_int(pin_row.get(Pin Direction Changeable, 否))) # ---------- 方向参数将 O/I 转为完整枚举 ---------- raw_dir str(pin_row.get(Pin Direction, I)).strip().upper() if raw_dir O: direction_val PORT_PIN_OUT else: # 默认输入 direction_val PORT_PIN_IN create_parameter_node(param_root, ECUC-TEXTUAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinDirection, direction_val) # ---------- 其他数值/文本参数新列名 ---------- create_parameter_node(param_root, ECUC-NUMERICAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinId, pin_row.get(Pin Id, 0)) create_parameter_node(param_root, ECUC-NUMERICAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinPcr, pin_row.get(tPinPcr, 0)) # 注意PortPin Initial Mode 已被删除不再生成节点 create_parameter_node(param_root, ECUC-TEXTUAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinInputLevelSelection, pin_row.get(PinInputLevelSelection, AUTOMOTIVE)) create_parameter_node(param_root, ECUC-TEXTUAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinLevelValue, pin_row.get(Pin Level Value, PORT_PIN_LEVEL_LOW)) create_parameter_node(param_root, ECUC-TEXTUAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinOutputDriveControl, pin_row.get(PinOutputDriveControl, PORT_OUTPUT_BUFFER_DISABLED)) create_parameter_node(param_root, ECUC-TEXTUAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinOutputEdgeRateControl, pin_row.get(PinOutputEdgeRateControl, WEAK_DRIVE)) # ---------- 核心PortPinMode 处理 ---------- # 优先使用 Excel 中手动填写的 PinMode custom_mode str(pin_row.get(PinMode, )).strip() if custom_mode and custom_mode ! : # 简单标准化若需要可调用 normalize_mode_name pin_mode custom_mode print(f使用自定义模式[{pin_name}]{pin_mode}) else: # 否则根据方向和 FuncIndex 查找 try: pcr_num int(pin_row.get(tPinPcr, 0)) func_idx int(pin_row.get(FuncIndex, 0)) direction str(pin_row.get(Pin Direction, I)).strip().upper() if direction O: actual_index func_idx 20 else: # 输入 actual_index func_idx except Exception as e: print(f警告[{pin_name}]数值异常默认GPIOerr{e}) pin_mode PORT_PIN_MODE_GPIO else: if pcr_num in pcr_map: mode_list pcr_map[pcr_num] if 0 actual_index len(mode_list): pin_mode mode_list[actual_index] dir_desc OUT if direction O else IN print(f匹配[{pin_name}] PCR{pcr_num} {dir_desc} 索引{actual_index} → {pin_mode}) else: print(f警告[{pin_name}] 索引{actual_index}越界PCR{pcr_num}长度{len(mode_list)}使用GPIO) pin_mode PORT_PIN_MODE_GPIO else: print(f警告[{pin_name}] PCR{pcr_num}未定义使用GPIO) pin_mode PORT_PIN_MODE_GPIO create_parameter_node(param_root, ECUC-TEXTUAL-PARAM-VALUE, /PortConfig/Port/PortConfigSet/PortContainer/PortPin/PortPinMode, pin_mode) ET.SubElement(pin_container, SUB-CONTAINERS) return pin_container def main(): print( 开始解析 C*Core 资源文件仅 PortUseEIOMUX1 分支 ) pcr_mode_map parse_resource_pinmap(RESOURCE_FILE_PATH, keep_firstTrue) print(f资源解析完成PCR 列表{sorted(pcr_mode_map.keys())}\n) print( 读取 Excel 引脚配置 ) df pd.read_excel(EXCEL_PATH) df.columns df.columns.str.strip() # 去除列名空格 # 必要列名称已更新 required_cols [名称, 分组名称, PinPcr, FuncIndex] missing [col for col in required_cols if col not in df.columns] if missing: print(f错误Excel 缺少必要列{missing}) return df_valid df.dropna(subsetrequired_cols).reset_index(dropTrue) print(fExcel 有效引脚行数{len(df_valid)}) # 统计分组 group_count {} for _, row in df_valid.iterrows(): g row[分组名称] group_count[g] group_count.get(g, 0) 1 print(\n 加载原始 ARXML 文件 ) if not os.path.exists(ORIGINAL_ARXML_PATH): print(f错误原始 ARXML 不存在 {ORIGINAL_ARXML_PATH}) return tree ET.parse(ORIGINAL_ARXML_PATH) root tree.getroot() port_cfg_set root.find(.//ns:ECUC-CONTAINER-VALUE[ns:SHORT-NAMEPortConfigSet], NS) if port_cfg_set is None: print(ERROR未找到 PortConfigSet 节点) return sub_root port_cfg_set.find(ns:SUB-CONTAINERS, NS) if sub_root is None: sub_root ET.SubElement(port_cfg_set, SUB-CONTAINERS) else: old_groups sub_root.findall(ns:ECUC-CONTAINER-VALUE, NS) for g in old_groups: sub_root.remove(g) print(已清空原有 Port 分组) group_dict {} print(\n 创建 Port 分组容器 ) for g_name, pin_total in group_count.items(): group_node ET.SubElement(sub_root, ECUC-CONTAINER-VALUE) ET.SubElement(group_node, SHORT-NAME).text g_name def_ref ET.SubElement(group_node, DEFINITION-REF) def_ref.text /PortConfig/Port/PortConfigSet/PortContainer param_grp ET.SubElement(group_node, PARAMETER-VALUES) num_param ET.SubElement(param_grp, ECUC-NUMERICAL-PARAM-VALUE) num_def ET.SubElement(num_param, DEFINITION-REF) num_def.text /PortConfig/Port/PortConfigSet/PortContainer/PortNumberOfPortPins ET.SubElement(num_param, VALUE).text str(pin_total) ET.SubElement(group_node, SUB-CONTAINERS) group_dict[g_name] group_node print(f创建分组【{g_name}】引脚总数{pin_total}) print(\n 批量生成引脚配置 ) for _, row in df_valid.iterrows(): pin_name row[名称] g_name row[分组名称] group_node group_dict.get(g_name) if group_node is None: print(f跳过{pin_name}分组{g_name}不存在) continue pin_parent group_node.find(SUB-CONTAINERS) exist_pin pin_parent.find(fECUC-CONTAINER-VALUE[SHORT-NAME{pin_name}]) if exist_pin is not None: print(f跳过重复引脚 {g_name}/{pin_name}) continue pin_elem create_pin_container(pin_name, row, pcr_mode_map) pin_parent.append(pin_elem) print(f\n 输出修复后 ARXML{OUTPUT_ARXML_PATH} ) ET.indent(tree, space ) tree.write(OUTPUT_ARXML_PATH, encodingutf-8, xml_declarationTrue) print(✅ ARXML 生成完成。) if __name__ __main__: main()