SVD文件编写详细说明
/</-- CPU核心名称 --> < revision > r0p1 </ revision > <!-- 核心版本 --> < endian > little </ endian > <!-- 字节序 --> < mpuPresent > false </ mpuPresent > <!-- 是否有MPU --> < fpuPresent > false </ fpuPresent > <!-
·
SVD文件编写详细说明
概述
SVD(System View Description)文件是ARM CMSIS(Cortex Microcontroller Software Interface Standard)的一部分,用于描述微控制器的外设寄存器结构。SVD文件采用XML格式,为调试器、IDE和代码生成工具提供标准化的设备描述。
目录
1. SVD文件基本结构
1.1 XML声明和根元素
<?xml version="1.0" encoding="utf-8"?>
<device schemaVersion="1.1"
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd">
<!-- 设备内容 -->
</device>
关键属性说明:
schemaVersion: SVD文件格式版本(通常为"1.1")xmlns:xs: XML Schema命名空间声明xs:noNamespaceSchemaLocation: 指向CMSIS-SVD.xsd模式文件
1.2 完整结构层次
<device>
<!-- 设备基本信息 -->
<vendor>厂商名称</vendor>
<vendorID>厂商ID</vendorID>
<name>设备名称</name>
<description>设备描述</description>
<series>系列名称</series>
<version>版本号</version>
<!-- CPU信息 -->
<cpu>
<!-- CPU详细配置 -->
</cpu>
<!-- 全局属性 -->
<addressUnitBits>8</addressUnitBits>
<width>32</width>
<size>32</size>
<access>read-write</access>
<resetValue>0x0</resetValue>
<resetMask>0x0</resetMask>
<!-- 外设列表 -->
<peripherals>
<peripheral>
<!-- 外设定义 -->
</peripheral>
</peripherals>
</device>
2. XML语法规范
2.1 基本XML规则
- 所有标签必须正确闭合
- 属性值必须用引号包围
- 标签名称区分大小写
- 特殊字符需要转义:
<→<>→>&→&"→"'→'
2.2 命名规范
- 标签名称使用驼峰命名法(camelCase)
- 属性名称使用驼峰命名法
- 寄存器名称使用大写字母和下划线
- 字段名称使用大写字母和下划线
2.3 注释规范
<!-- 这是XML注释 -->
<!--
多行注释
用于详细说明
-->
3. 设备信息定义
3.1 厂商信息
<vendor>HolyChip Semiconductor Co.Ltd</vendor>
<vendorID>HolyChip</vendorID>
3.2 设备基本信息
<name>HC32F0653</name>
<description>HC32F0653 32-bit ARM Cortex-M0+ Microcontroller</description>
<series>HC32F0</series>
<version>1.2</version>
3.3 全局属性
<addressUnitBits>8</addressUnitBits> <!-- 地址单位位数 -->
<width>32</width> <!-- 数据宽度 -->
<size>32</size> <!-- 寄存器大小 -->
<access>read-write</access> <!-- 默认访问权限 -->
<resetValue>0x0</resetValue> <!-- 复位值 -->
<resetMask>0x0</resetMask> <!-- 复位掩码 -->
4. CPU信息定义
4.1 CPU基本配置
<cpu>
<name>CM0+</name> <!-- CPU核心名称 -->
<revision>r0p1</revision> <!-- 核心版本 -->
<endian>little</endian> <!-- 字节序 -->
<mpuPresent>false</mpuPresent> <!-- 是否有MPU -->
<fpuPresent>false</fpuPresent> <!-- 是否有FPU -->
<nvicPrioBits>2</nvicPrioBits> <!-- NVIC优先级位数 -->
<vendorSystickConfig>false</vendorSystickConfig> <!-- 厂商SysTick配置 -->
</cpu>
4.2 支持的CPU类型
CM0- Cortex-M0CM0+- Cortex-M0+CM3- Cortex-M3CM4- Cortex-M4CM7- Cortex-M7CM23- Cortex-M23CM33- Cortex-M33
5. 外设定义
5.1 外设基本结构
<peripheral>
<name>FLASH</name> <!-- 外设名称 -->
<description>Flash Memory Controller</description> <!-- 外设描述 -->
<baseAddress>0x40000000</baseAddress> <!-- 基地址 -->
<size>32</size> <!-- 外设大小 -->
<!-- 中断定义 -->
<interrupt>
<name>FLASH</name>
<description>Flash Interrupt</description>
<value>1</value>
</interrupt>
<!-- 地址块定义 -->
<addressBlock>
<offset>0x0</offset>
<size>0x20</size>
<usage>registers</usage>
</addressBlock>
<!-- 寄存器列表 -->
<registers>
<!-- 寄存器定义 -->
</registers>
</peripheral>
5.2 外设属性说明
name: 外设名称,用于代码生成description: 外设功能描述baseAddress: 外设基地址(十六进制)size: 外设大小(字节)groupName: 外设分组名称(可选)
5.3 外设派生
<peripheral derivedFrom="TIMER1">
<name>TIMER2</name>
<baseAddress>0x40001000</baseAddress>
<!-- 继承TIMER1的所有定义,可以覆盖特定属性 -->
</peripheral>
6. 寄存器定义
6.1 寄存器基本结构
<register>
<name>ACR</name> <!-- 寄存器名称 -->
<displayName>Access Control Register</displayName> <!-- 显示名称 -->
<description>Flash Access Control Register</description> <!-- 描述 -->
<addressOffset>0x0</addressOffset> <!-- 地址偏移 -->
<size>32</size> <!-- 寄存器大小 -->
<access>read-write</access> <!-- 访问权限 -->
<resetValue>0x00000000</resetValue> <!-- 复位值 -->
<resetMask>0xFFFFFFFF</resetMask> <!-- 复位掩码 -->
<dataType>uint32_t</dataType> <!-- 数据类型 -->
<!-- 字段定义 -->
<fields>
<!-- 字段列表 -->
</fields>
</register>
6.2 寄存器属性说明
name: 寄存器名称(必需)displayName: 显示名称(可选)description: 寄存器描述(可选)addressOffset: 相对于外设基地址的偏移(必需)size: 寄存器大小,单位位(必需)access: 访问权限(read-only, write-only, read-write)resetValue: 复位值(十六进制)resetMask: 复位掩码dataType: 数据类型(uint8_t, uint16_t, uint32_t等)
6.3 寄存器数组
<register>
<name>GPIO_%s</name> <!-- 使用%s表示数组 -->
<dim>8</dim> <!-- 数组大小 -->
<dimIncrement>0x40</dimIncrement> <!-- 地址增量 -->
<dimIndex>0-7</dimIndex> <!-- 索引范围 -->
<addressOffset>0x0</addressOffset>
<size>32</size>
<access>read-write</access>
</register>
7. 字段定义
7.1 字段基本结构
<field>
<name>FETCH</name> <!-- 字段名称 -->
<description>Flash Fetch Enable</description> <!-- 字段描述 -->
<bitOffset>5</bitOffset> <!-- 位偏移 -->
<bitWidth>2</bitWidth> <!-- 位宽度 -->
<msb>6</msb> <!-- 最高位位置 -->
<lsb>5</lsb> <!-- 最低位位置 -->
<access>read-write</access> <!-- 访问权限 -->
<resetValue>0</resetValue> <!-- 复位值 -->
<!-- 枚举值定义 -->
<enumeratedValues>
<enumeratedValue>
<name>Disabled</name>
<description>Fetch disabled</description>
<value>0</value>
</enumeratedValue>
<enumeratedValue>
<name>Enabled</name>
<description>Fetch enabled</description>
<value>1</value>
</enumeratedValue>
</enumeratedValues>
</field>
7.2 字段属性说明
name: 字段名称(必需)description: 字段描述(可选)bitOffset: 位偏移(从0开始)bitWidth: 位宽度msb: 最高位位置(可选,可替代bitOffset+bitWidth)lsb: 最低位位置(可选)access: 访问权限resetValue: 复位值
7.3 字段访问权限
read-only: 只读write-only: 只写read-write: 读写writeOnce: 只写一次read-writeOnce: 读写一次
7.4 枚举值定义
<enumeratedValues>
<name>FETCH_Values</name> <!-- 枚举名称 -->
<usage>read</usage> <!-- 使用场景 -->
<enumeratedValue>
<name>Disabled</name>
<description>Fetch disabled</description>
<value>0</value>
<isDefault>true</isDefault> <!-- 默认值 -->
</enumeratedValue>
<enumeratedValue>
<name>Enabled</name>
<description>Fetch enabled</description>
<value>1</value>
</enumeratedValue>
</enumeratedValues>
8. 中断定义
8.1 中断基本结构
<interrupt>
<name>FLASH</name> <!-- 中断名称 -->
<description>Flash Memory Interrupt</description> <!-- 中断描述 -->
<value>1</value> <!-- 中断号 -->
</interrupt>
8.2 中断属性说明
name: 中断名称(必需)description: 中断描述(可选)value: 中断向量号(必需)
9. 地址块定义
9.1 地址块基本结构
<addressBlock>
<offset>0x0</offset> <!-- 偏移地址 -->
<size>0x20</size> <!-- 块大小 -->
<usage>registers</usage> <!-- 用途 -->
<protection>n</protection> <!-- 保护级别 -->
</addressBlock>
9.2 地址块用途类型
registers: 寄存器区域buffer: 缓冲区区域reserved: 保留区域
10. 编写注意事项
10.1 命名规范
-
寄存器名称:使用大写字母和下划线
<name>GPIO_CRL</name> <!-- 正确 --> <name>gpio_crl</name> <!-- 错误 --> -
字段名称:使用大写字母和下划线
<name>MODE0</name> <!-- 正确 --> <name>mode0</name> <!-- 错误 --> -
外设名称:使用大写字母
<name>GPIOA</name> <!-- 正确 --> <name>gpioa</name> <!-- 错误 -->
10.2 地址对齐
- 确保所有地址都是按字节对齐的
- 寄存器地址偏移必须是寄存器大小的整数倍
- 字段位偏移必须在0到31之间(32位寄存器)
10.3 数据类型一致性
- 确保所有相同大小的寄存器使用相同的数据类型
- 字段宽度不能超过寄存器大小
- 位偏移和宽度必须合理
10.4 描述信息
- 为每个外设、寄存器和字段提供清晰的描述
- 使用英文描述,避免使用特殊字符
- 描述应该准确反映功能
10.5 复位值设置
- 正确设置复位值和复位掩码
- 复位值应该是十六进制格式
- 复位掩码用于标识哪些位在复位时有效
11. 从SVD生成其他文件
11.1 生成头文件
使用SVDConv工具可以从SVD文件生成C/C++头文件:
# 基本用法
SVDConv.exe HC32F0653.svd -o output_dir
# 指定输出格式
SVDConv.exe HC32F0653.svd -o output_dir --format=cmsis
# 生成特定文件类型
SVDConv.exe HC32F0653.svd -o output_dir --header --sfd --sfr
11.2 生成SFD文件
SFD(Special Function Data)文件包含调试器使用的特殊功能数据:
<!-- SVD中的字段定义 -->
<field>
<name>MODE0</name>
<msb>1</msb>
<lsb>0</lsb>
<access>read-write</access>
</field>
生成的SFD文件内容:
// ------------------------------- Field Item: GPIO_CRL_MODE0 -----------------------------------
// SVD Line: 123
// <item> SFDITEM_FIELD__GPIO_CRL_MODE0
// <name> MODE0 </name>
// <rw>
// <i> [Bits 1..0] RW (@ 0x40010800) MODE0 </i>
// <edit>
// <loc> ( (unsigned char)((GPIO_CRL >> 0) & 0x3), ((GPIO_CRL = (GPIO_CRL & ~(0x3UL << 0 )) | ((unsigned long)(Gui_u8:GuiVal & 0x3) << 0 ) ) )) </loc>
// </edit>
// </item>
11.3 生成SFR文件
SFR(Special Function Register)文件包含寄存器定义:
// ---------------------------- Register Item Address: GPIO_CRL --------------------------------
// SVD Line: 120
unsigned int GPIO_CRL __AT (0x40010800);
11.4 生成CMSIS头文件
// 寄存器基地址定义
#define GPIOA_BASE 0x40010800UL
#define GPIOB_BASE 0x40010C00UL
// 寄存器结构体定义
typedef struct {
__IO uint32_t CRL; // 0x00
__IO uint32_t CRH; // 0x04
__IO uint32_t IDR; // 0x08
__IO uint32_t ODR; // 0x0C
__IO uint32_t BSRR; // 0x10
__IO uint32_t BRR; // 0x14
__IO uint32_t LCKR; // 0x18
} GPIO_TypeDef;
// 外设实例定义
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
#define GPIOB ((GPIO_TypeDef *) GPIOB_BASE)
12. 验证和检查
12.1 XML语法验证
# 使用xmllint验证XML语法
xmllint --noout HC32F0653.svd
# 使用XML Schema验证
xmllint --schema CMSIS-SVD.xsd HC32F0653.svd --noout
12.2 逻辑验证检查项
- 地址重叠检查:确保没有寄存器地址重叠
- 字段重叠检查:确保同一寄存器内字段不重叠
- 位范围检查:确保字段位范围在寄存器范围内
- 访问权限检查:确保访问权限设置合理
- 复位值检查:确保复位值在字段范围内
12.3 使用SVDConv验证
# 验证SVD文件
SVDConv.exe HC32F0653.svd --validate
# 生成报告
SVDConv.exe HC32F0653.svd --report=validation_report.txt
12.4 常见错误和修复
-
XML语法错误
<!-- 错误:标签未闭合 --> <register> <name>ACR</name> <addressOffset>0x0</addressOffset> <!-- 正确:标签正确闭合 --> <register> <name>ACR</name> <addressOffset>0x0</addressOffset> </register> -
地址重叠错误
<!-- 错误:地址重叠 --> <register> <name>REG1</name> <addressOffset>0x0</addressOffset> </register> <register> <name>REG2</name> <addressOffset>0x0</addressOffset> <!-- 重叠 --> </register> <!-- 正确:地址不重叠 --> <register> <name>REG1</name> <addressOffset>0x0</addressOffset> </register> <register> <name>REG2</name> <addressOffset>0x4</addressOffset> <!-- 不重叠 --> </register> -
字段位范围错误
<!-- 错误:位范围超出寄存器范围 --> <field> <name>FIELD1</name> <msb>35</msb> <!-- 超出32位寄存器范围 --> <lsb>32</lsb> </field> <!-- 正确:位范围在寄存器范围内 --> <field> <name>FIELD1</name> <msb>31</msb> <!-- 在32位寄存器范围内 --> <lsb>0</lsb> </field>
13. 工具推荐
13.1 官方工具
- SVDConv: ARM官方SVD转换工具
- CMSIS-SVD.xsd: XML Schema验证文件
- Keil MDK: 集成SVD支持
13.2 第三方工具
- XMLSpy: 专业的XML编辑器
- Notepad++: 免费文本编辑器,支持XML语法高亮
- Visual Studio Code: 现代代码编辑器,支持XML扩展
13.3 在线工具
- XML Validator: 在线XML验证工具
- JSON to XML: 格式转换工具
13.4 验证脚本示例
#!/usr/bin/env python3
"""
SVD文件验证脚本
"""
import xml.etree.ElementTree as ET
import sys
def validate_svd(filename):
try:
# 解析XML文件
tree = ET.parse(filename)
root = tree.getroot()
print(f"正在验证 {filename}...")
# 检查基本结构
if root.tag != 'device':
print("错误:根元素必须是'device'")
return False
# 检查必需元素
required_elements = ['vendor', 'name', 'cpu', 'peripherals']
for elem in required_elements:
if root.find(elem) is None:
print(f"错误:缺少必需元素 '{elem}'")
return False
# 检查外设定义
peripherals = root.find('peripherals')
if peripherals is not None:
for peripheral in peripherals.findall('peripheral'):
name = peripheral.find('name')
base_addr = peripheral.find('baseAddress')
if name is None or base_addr is None:
print("错误:外设缺少名称或基地址")
return False
print("验证通过!")
return True
except ET.ParseError as e:
print(f"XML解析错误:{e}")
return False
except Exception as e:
print(f"验证错误:{e}")
return False
if __name__ == "__main__":
if len(sys.argv) != 2:
print("用法:python validate_svd.py <svd_file>")
sys.exit(1)
filename = sys.argv[1]
if validate_svd(filename):
sys.exit(0)
else:
sys.exit(1)
总结
SVD文件是描述微控制器外设结构的重要XML文件,正确编写SVD文件需要:
- 遵循XML语法规范:确保标签正确闭合,属性值用引号包围
- 使用正确的命名规范:寄存器、字段使用大写字母和下划线
- 确保地址不重叠:所有寄存器和字段地址必须唯一
- 提供清晰的描述:为外设、寄存器和字段提供准确描述
- 正确设置访问权限:根据硬件特性设置合适的访问权限
- 验证文件正确性:使用工具验证XML语法和逻辑正确性
通过遵循这些规范和注意事项,可以创建高质量的SVD文件,为调试器和开发工具提供准确的设备描述信息。
更多推荐



所有评论(0)