编程技术分享

分享编程知识,探讨技术创新

0%

简介:基于ASM235CM的Type-C M.2硬盘盒**

关注微信公众号,提前获取相关推文

本项目旨在设计和开发一个高性能、兼容性强的Type-C M.2 NVMe/SATA 双协议硬盘盒。该硬盘盒的核心控制芯片为ASM235CM,它能够桥接USB Type-C接口和M.2接口,实现高速数据传输。我们的目标是构建一个完整的嵌入式系统,涵盖固件开发、硬件驱动、数据传输协议以及错误处理机制,最终提供用户稳定可靠的外部存储解决方案。

1. 需求分析

在项目初期,我们需要明确产品的具体需求,这将直接影响到后续的系统设计和代码架构。对于Type-C M.2硬盘盒,主要需求包括:

  • 功能需求:

    • USB Type-C 接口兼容性: 支持USB 3.2 Gen 2 或更高标准,保证高速数据传输速率。
    • M.2 接口支持: 兼容M.2 NVMe PCIe 和 SATA 协议的SSD。
    • 热插拔支持: 用户可以在系统运行时安全地连接和断开硬盘盒。
    • 高速数据传输: 充分利用USB 3.2 Gen 2 的带宽,实现尽可能高的读写速度。
    • LED 指示灯: 指示硬盘盒的工作状态(例如,电源、数据传输)。
    • 固件升级: 支持通过USB接口进行固件升级,方便后续功能扩展和bug修复。
    • 低功耗管理: 在空闲状态下降低功耗,延长设备寿命。
    • 错误处理和恢复: 具备完善的错误检测和处理机制,确保数据传输的可靠性。
  • 性能需求:

    • 传输速率: 理论传输速率需接近USB 3.2 Gen 2 的上限 (10Gbps 或 20Gbps)。
    • 响应时间: 低延迟,快速响应主机请求。
    • 稳定性: 长时间稳定运行,不易出现数据错误或设备故障。
  • 可靠性需求:

    • 数据完整性: 确保数据在传输过程中不丢失、不损坏。
    • 硬件保护: 防止过流、过压等硬件故障。
    • 软件稳定性: 固件运行稳定,不易崩溃。
  • 可扩展性需求:

    • 模块化设计: 代码结构清晰,易于维护和扩展新功能。
    • 驱动分离: 硬件驱动与上层应用逻辑分离,方便移植和适配不同硬件平台。

2. 系统架构设计

为了满足上述需求,并构建一个可靠、高效、可扩展的系统平台,我们采用分层架构事件驱动架构相结合的设计模式。

2.1 分层架构 (Layered Architecture)

分层架构将系统划分为多个独立的层次,每一层只负责特定的功能,并向上层提供服务。这种架构可以提高代码的模块化程度,降低层与层之间的耦合度,方便代码维护和升级。

我们的系统可以划分为以下几个层次:

  • 硬件抽象层 (HAL - Hardware Abstraction Layer): 最底层,直接与硬件交互。HAL层提供统一的接口,屏蔽底层硬件的差异,使上层驱动程序可以不依赖于具体的硬件细节。HAL层主要包含:

    • 时钟管理模块 (Clock Management): 配置系统时钟、外设时钟。
    • GPIO 驱动模块 (GPIO Driver): 控制GPIO引脚,例如LED指示灯的控制。
    • 中断控制器驱动模块 (Interrupt Controller Driver): 配置和管理中断。
    • DMA 控制器驱动模块 (DMA Controller Driver): 配置和管理DMA通道,用于高速数据传输。
    • USB PHY 驱动模块 (USB PHY Driver): 初始化和控制USB物理层。
    • M.2 PHY 驱动模块 (M.2 PHY Driver): 初始化和控制M.2物理层 (PCIe/SATA PHY)。
  • 驱动层 (Driver Layer): 驱动层构建在HAL层之上,负责驱动具体的硬件外设,并向上层提供设备操作接口。驱动层主要包含:

    • USB 控制器驱动 (USB Controller Driver): 实现USB协议栈,处理USB枚举、配置、数据传输等。
    • M.2 NVMe 驱动 (M.2 NVMe Driver): 实现NVMe协议栈,处理NVMe命令、数据传输、错误处理等。
    • M.2 SATA 驱动 (M.2 SATA Driver): 实现SATA协议栈,处理SATA命令、数据传输、错误处理等。
    • 电源管理驱动 (Power Management Driver): 实现功耗管理功能,例如设备休眠、唤醒等。
  • 核心逻辑层 (Core Logic Layer): 核心逻辑层构建在驱动层之上,负责实现硬盘盒的核心功能,例如数据桥接、协议转换、状态管理等。核心逻辑层主要包含:

    • 协议转换模块 (Protocol Conversion Module): 将USB协议转换为M.2 NVMe/SATA协议,反之亦然。
    • 数据传输管理模块 (Data Transfer Management Module): 管理数据在USB和M.2接口之间的高效传输,包括DMA传输控制、数据缓存管理等。
    • 错误处理模块 (Error Handling Module): 处理在数据传输过程中出现的各种错误,例如USB错误、M.2错误、协议错误等,并进行错误恢复或上报。
    • 状态管理模块 (Status Management Module): 管理硬盘盒的设备状态,例如连接状态、工作状态、错误状态等,并更新LED指示灯。
    • 固件升级模块 (Firmware Upgrade Module): 实现固件升级功能,接收主机发送的固件数据,并更新到Flash存储器中。
  • 应用接口层 (Application Interface Layer): 最上层,负责与主机系统交互,提供用户接口。对于硬盘盒来说,应用接口层实际上就是USB Mass Storage Class (MSC) 驱动,主机系统通过标准的MSC协议与硬盘盒进行通信。应用接口层主要包含:

    • USB MSC 类驱动 (USB MSC Class Driver): 实现USB MSC协议,响应主机发送的SCSI命令,并进行数据传输。

2.2 事件驱动架构 (Event-Driven Architecture)

事件驱动架构是一种异步编程模型,系统主要通过响应各种事件来驱动程序的运行。事件可以是硬件中断、定时器事件、USB事件、M.2事件等等。事件驱动架构可以提高系统的响应速度和实时性,尤其适合于嵌入式系统。

在我们的系统中,事件驱动架构主要体现在以下几个方面:

  • 中断处理: 硬件外设 (例如USB控制器、M.2控制器) 通过中断来通知CPU事件的发生。中断处理函数会处理相应的事件,并可能触发其他事件或状态变化。
  • 状态机: 可以使用状态机来管理系统的各种状态,例如USB连接状态、M.2设备状态、数据传输状态等。状态机根据事件的发生进行状态切换,并执行相应的动作。
  • 消息队列 (可选): 可以使用消息队列来传递事件和数据,实现模块之间的异步通信。

3. 代码设计与实现 (C 代码示例)

下面我们将详细介绍各个层次的代码设计,并提供关键模块的C代码示例。由于篇幅限制,我们不可能提供完整的3000行代码,但我们会尽可能详细地展示核心模块的实现思路和关键代码片段。

3.1 硬件抽象层 (HAL)

HAL层代码主要负责芯片的初始化和底层硬件的操作。我们假设ASM235CM芯片的寄存器定义和地址已经明确,并定义了相应的宏或结构体来访问寄存器。

示例代码:时钟管理模块 (hal_clock.c)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include "hal_clock.h"
#include "asm235cm_registers.h" // 假设包含ASM235CM寄存器定义的头文件

// 定义时钟频率宏 (假设外部晶振频率为 24MHz)
#define EXTERNAL_CRYSTAL_FREQ 24000000UL

// 初始化系统时钟
void hal_clock_init(uint32_t target_cpu_freq) {
// 1. 配置外部晶振
REG_CLK_CTRL |= CLK_CTRL_EXT_OSC_EN; // 使能外部晶振
// 等待外部晶振稳定 (实际应用中需要加入延时或状态检测)

// 2. 配置PLL (假设使用PLL倍频)
uint32_t pll_multiplier = target_cpu_freq / EXTERNAL_CRYSTAL_FREQ;
REG_PLL_CTRL = (pll_multiplier << PLL_CTRL_MULTIPLIER_SHIFT) | PLL_CTRL_PLL_EN; // 配置PLL倍频系数并使能PLL
// 等待PLL锁定 (实际应用中需要加入延时或状态检测)

// 3. 选择系统时钟源为PLL
REG_CLK_CTRL |= CLK_CTRL_SYS_CLK_SRC_PLL;

// 4. 配置外设时钟 (根据需要配置USB、M.2等外设的时钟)
REG_CLK_USB_DIV = 1; // USB时钟不分频
REG_CLK_M2_DIV = 1; // M.2时钟不分频

// ... 其他时钟配置 ...
}

// 获取系统时钟频率
uint32_t hal_clock_get_cpu_freq(void) {
// 根据寄存器配置读取实际的CPU时钟频率
// ... (根据具体的寄存器配置计算) ...
return system_cpu_frequency; // 返回计算得到的CPU频率
}

// 使能外设时钟
void hal_clock_enable_peripheral(PeripheralID_t peripheral_id) {
switch (peripheral_id) {
case PERIPHERAL_USB:
REG_CLK_PERIPHERAL_EN |= CLK_PERIPHERAL_USB_EN;
break;
case PERIPHERAL_M2:
REG_CLK_PERIPHERAL_EN |= CLK_PERIPHERAL_M2_EN;
break;
case PERIPHERAL_GPIO:
REG_CLK_PERIPHERAL_EN |= CLK_PERIPHERAL_GPIO_EN;
break;
// ... 其他外设时钟使能 ...
default:
// 未知外设ID,错误处理
break;
}
}

// ... 其他时钟管理函数 (例如:关闭外设时钟等) ...

示例代码:GPIO 驱动模块 (hal_gpio.c)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include "hal_gpio.h"
#include "asm235cm_registers.h"

// 初始化GPIO引脚
void hal_gpio_init(GPIOPin_t pin, GPIOMode_t mode, GPIOPull_t pull) {
uint32_t pin_num = pin % 32; // 获取引脚在寄存器组内的偏移
uint32_t reg_group_index = pin / 32; // 获取寄存器组索引 (假设GPIO寄存器分组)

// 配置GPIO模式 (输入/输出)
if (mode == GPIO_MODE_OUTPUT) {
REG_GPIO_MODE[reg_group_index] |= (1 << pin_num); // 设置为输出模式
} else { // GPIO_MODE_INPUT
REG_GPIO_MODE[reg_group_index] &= ~(1 << pin_num); // 设置为输入模式
}

// 配置GPIO上下拉
if (pull == GPIO_PULL_UP) {
REG_GPIO_PULLUP[reg_group_index] |= (1 << pin_num); // 使能上拉
} else if (pull == GPIO_PULL_DOWN) {
REG_GPIO_PULLDOWN[reg_group_index] |= (1 << pin_num); // 使能下拉
} else { // GPIO_PULL_NONE
REG_GPIO_PULLUP[reg_group_index] &= ~(1 << pin_num); // 禁用上拉
REG_GPIO_PULLDOWN[reg_group_index] &= ~(1 << pin_num); // 禁用下拉
}

// ... 其他GPIO配置 (例如:驱动能力、速度等) ...
}

// 设置GPIO输出电平
void hal_gpio_set_output(GPIOPin_t pin, GPIOLogicLevel_t level) {
uint32_t pin_num = pin % 32;
uint32_t reg_group_index = pin / 32;

if (level == GPIO_LEVEL_HIGH) {
REG_GPIO_OUTPUT_SET[reg_group_index] |= (1 << pin_num); // 输出高电平
} else { // GPIO_LEVEL_LOW
REG_GPIO_OUTPUT_CLEAR[reg_group_index] |= (1 << pin_num); // 输出低电平
}
}

// 读取GPIO输入电平
GPIOLogicLevel_t hal_gpio_get_input(GPIOPin_t pin) {
uint32_t pin_num = pin % 32;
uint32_t reg_group_index = pin / 32;

if (REG_GPIO_INPUT_STATUS[reg_group_index] & (1 << pin_num)) {
return GPIO_LEVEL_HIGH; // 输入高电平
} else {
return GPIO_LEVEL_LOW; // 输入低电平
}
}

// ... 其他 GPIO 驱动函数 (例如:GPIO中断配置等) ...

3.2 驱动层 (Driver Layer)

驱动层构建在HAL层之上,负责驱动具体的硬件外设。例如,USB控制器驱动、M.2 NVMe/SATA 驱动等。

示例代码:USB 控制器驱动 (usb_controller.c) - 简化示例,仅展示部分核心功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
#include "usb_controller.h"
#include "hal_usb.h" // 假设 HAL 层提供 USB 相关接口
#include "usb_descriptors.h" // USB描述符定义

// USB 设备状态
typedef enum {
USB_STATE_DETACHED,
USB_STATE_ATTACHED,
USB_STATE_POWERED,
USB_STATE_DEFAULT,
USB_STATE_ADDRESSED,
USB_STATE_CONFIGURED
} USB_DeviceState_t;

static USB_DeviceState_t usb_device_state = USB_STATE_DETACHED;

// USB 设备描述符 (从 usb_descriptors.h 中获取)
extern const uint8_t usb_device_descriptor[];
extern const uint8_t usb_configuration_descriptor[];
extern const uint8_t usb_string_descriptor_langid[];
extern const uint8_t usb_string_descriptor_manufacturer[];
extern const uint8_t usb_string_descriptor_product[];
extern const uint8_t usb_string_descriptor_serial[];

// USB 端点配置 (假设使用端点 1 用于 Bulk IN, 端点 2 用于 Bulk OUT, 端点 0 用于 Control)
#define USB_ENDPOINT_BULK_IN 1
#define USB_ENDPOINT_BULK_OUT 2
#define USB_ENDPOINT_CONTROL 0

// USB 中断处理函数 (假设 HAL 层调用 usb_controller_irq_handler)
void usb_controller_irq_handler(void) {
uint32_t usb_interrupt_status = hal_usb_get_interrupt_status();

if (usb_interrupt_status & USB_INTERRUPT_RESET) {
// USB 复位事件
usb_device_state = USB_STATE_DEFAULT;
hal_usb_reset_endpoint(USB_ENDPOINT_CONTROL);
hal_usb_reset_endpoint(USB_ENDPOINT_BULK_IN);
hal_usb_reset_endpoint(USB_ENDPOINT_BULK_OUT);
// ... 其他复位处理 ...
}

if (usb_interrupt_status & USB_INTERRUPT_SETUP_PACKET) {
// SETUP 数据包接收事件
usb_handle_setup_packet();
}

if (usb_interrupt_status & USB_INTERRUPT_ENDPOINT0) {
// 端点 0 (控制端点) 事件
usb_handle_endpoint0_event();
}

if (usb_interrupt_status & USB_INTERRUPT_ENDPOINT1) {
// 端点 1 (Bulk IN) 事件
usb_handle_endpoint_bulk_in_event();
}

if (usb_interrupt_status & USB_INTERRUPT_ENDPOINT2) {
// 端点 2 (Bulk OUT) 事件
usb_handle_endpoint_bulk_out_event();
}

// ... 其他中断处理 ...

hal_usb_clear_interrupt_status(usb_interrupt_status); // 清除中断标志
}

// 处理 USB SETUP 数据包
static void usb_handle_setup_packet(void) {
USB_SetupPacket_t setup_packet;
hal_usb_read_setup_packet(&setup_packet);

uint8_t request_type = setup_packet.bmRequestType;
uint8_t request = setup_packet.bRequest;
uint16_t value = setup_packet.wValue;
uint16_t index = setup_packet.wIndex;
uint16_t length = setup_packet.wLength;

switch (request_type & USB_REQ_TYPE_MASK) {
case USB_REQ_TYPE_STANDARD:
usb_handle_standard_request(request, value, index, length);
break;
case USB_REQ_TYPE_CLASS:
usb_handle_class_request(request, value, index, length);
break;
case USB_REQ_TYPE_VENDOR:
usb_handle_vendor_request(request, value, index, length);
break;
default:
// Unknown request type, stall control endpoint
hal_usb_stall_endpoint(USB_ENDPOINT_CONTROL);
break;
}
}

// 处理标准 USB 请求
static void usb_handle_standard_request(uint8_t request, uint16_t value, uint16_t index, uint16_t length) {
switch (request) {
case USB_REQ_GET_DESCRIPTOR: {
uint8_t descriptor_type = (value >> 8) & 0xFF;
uint8_t descriptor_index = value & 0xFF;

switch (descriptor_type) {
case USB_DESC_TYPE_DEVICE:
usb_send_descriptor(usb_device_descriptor, sizeof(usb_device_descriptor), length);
break;
case USB_DESC_TYPE_CONFIGURATION:
usb_send_descriptor(usb_configuration_descriptor, sizeof(usb_configuration_descriptor), length);
break;
case USB_DESC_TYPE_STRING:
usb_handle_string_descriptor_request(descriptor_index, length);
break;
default:
hal_usb_stall_endpoint(USB_ENDPOINT_CONTROL);
break;
}
break;
}
case USB_REQ_SET_ADDRESS:
usb_device_state = USB_STATE_ADDRESSED;
hal_usb_set_device_address(value);
usb_send_status_stage(); // 发送零长度数据包表示成功
break;
case USB_REQ_SET_CONFIGURATION:
usb_device_state = USB_STATE_CONFIGURED;
usb_send_status_stage();
break;
case USB_REQ_GET_STATUS:
// ... 实现 GET_STATUS 请求处理 ...
break;
case USB_REQ_CLEAR_FEATURE:
// ... 实现 CLEAR_FEATURE 请求处理 ...
break;
case USB_REQ_SET_FEATURE:
// ... 实现 SET_FEATURE 请求处理 ...
break;
default:
hal_usb_stall_endpoint(USB_ENDPOINT_CONTROL);
break;
}
}

// 处理字符串描述符请求
static void usb_handle_string_descriptor_request(uint8_t descriptor_index, uint16_t length) {
const uint8_t *descriptor_ptr = NULL;
uint16_t descriptor_size = 0;

switch (descriptor_index) {
case 0:
descriptor_ptr = usb_string_descriptor_langid;
descriptor_size = sizeof(usb_string_descriptor_langid);
break;
case USB_STRING_INDEX_MANUFACTURER:
descriptor_ptr = usb_string_descriptor_manufacturer;
descriptor_size = sizeof(usb_string_descriptor_manufacturer);
break;
case USB_STRING_INDEX_PRODUCT:
descriptor_ptr = usb_string_descriptor_product;
descriptor_size = sizeof(usb_string_descriptor_product);
break;
case USB_STRING_INDEX_SERIAL:
descriptor_ptr = usb_string_descriptor_serial;
descriptor_size = sizeof(usb_string_descriptor_serial);
break;
default:
hal_usb_stall_endpoint(USB_ENDPOINT_CONTROL);
return;
}
usb_send_descriptor(descriptor_ptr, descriptor_size, length);
}

// 发送描述符数据到控制端点
static void usb_send_descriptor(const uint8_t *descriptor, uint16_t descriptor_size, uint16_t requested_length) {
uint16_t transfer_length = MIN(descriptor_size, requested_length);
hal_usb_send_data(USB_ENDPOINT_CONTROL, descriptor, transfer_length);
}

// 发送状态阶段 (零长度数据包)
static void usb_send_status_stage(void) {
hal_usb_send_data(USB_ENDPOINT_CONTROL, NULL, 0);
}


// 初始化 USB 控制器
void usb_controller_init(void) {
hal_usb_init(); // 初始化 USB PHY 和控制器硬件
hal_usb_enable_interrupts(); // 使能 USB 相关中断
usb_device_state = USB_STATE_DETACHED;
// ... 其他 USB 控制器初始化 ...
}

// 处理 Bulk IN 端点事件 (数据发送完成)
static void usb_handle_endpoint_bulk_in_event(void) {
// ... (处理 Bulk IN 数据发送完成事件,例如:准备发送下一块数据) ...
}

// 处理 Bulk OUT 端点事件 (数据接收完成)
static void usb_handle_endpoint_bulk_out_event(void) {
// ... (处理 Bulk OUT 数据接收完成事件,例如:接收到主机发送的数据) ...
}

// 处理类特定 USB 请求 (例如 MSC 类请求)
static void usb_handle_class_request(uint8_t request, uint16_t value, uint16_t index, uint16_t length) {
// ... (根据 USB 类类型和请求码,调用相应的类驱动处理函数) ...
// 例如:如果 request 是 MSC 相关的,则调用 msc_class_request_handler(request, value, index, length);
}

// 处理厂商特定 USB 请求
static void usb_handle_vendor_request(uint8_t request, uint16_t value, uint16_t index, uint16_t length) {
// ... (处理厂商自定义的 USB 请求,例如:固件升级请求) ...
}

// ... 其他 USB 控制器驱动函数 (例如:数据发送、接收函数等) ...

3.3 核心逻辑层 (Core Logic Layer)

核心逻辑层是系统的核心,负责实现硬盘盒的主要功能。例如,协议转换、数据传输管理、错误处理等。

示例代码:协议转换模块 (protocol_converter.c) - 简化示例,仅展示 NVMe 到 USB MSC 的转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include "protocol_converter.h"
#include "usb_msc_driver.h" // 假设有 USB MSC 类驱动
#include "m2_nvme_driver.h" // 假设有 M.2 NVMe 驱动

// 处理 USB MSC SCSI 命令 (从 USB MSC 驱动层调用)
void protocol_converter_handle_msc_scsi_command(const MSC_SCSICommandBlock_t *scsi_cmd_block) {
// 1. 解析 SCSI 命令,获取操作类型 (例如:读、写、查询容量等)
uint8_t opcode = scsi_cmd_block->opcode;

switch (opcode) {
case SCSI_OPCODE_INQUIRY: {
// 处理 SCSI INQUIRY 命令,返回设备信息
MSC_SCSIInquiryData_t inquiry_data;
// ... 填充 inquiry_data 结构体 ...
usb_msc_send_data_response((uint8_t*)&inquiry_data, sizeof(inquiry_data));
break;
}
case SCSI_OPCODE_READ_CAPACITY_10: {
// 处理 SCSI READ CAPACITY (10) 命令,返回硬盘容量
MSC_SCSIReadCapacity10Data_t capacity_data;
uint64_t disk_capacity_bytes = m2_nvme_get_disk_capacity(); // 从 NVMe 驱动获取容量
capacity_data.last_lba = disk_capacity_bytes / 512 - 1; // 假设扇区大小为 512 字节
capacity_data.block_size = 512;
usb_msc_send_data_response((uint8_t*)&capacity_data, sizeof(capacity_data));
break;
}
case SCSI_OPCODE_READ_10:
case SCSI_OPCODE_READ_12: {
// 处理 SCSI READ (10/12) 命令,读取数据
uint32_t lba = scsi_cmd_block->lba; // 逻辑块地址
uint16_t block_count = scsi_cmd_block->block_count; // 读取块数量
uint32_t data_length = block_count * 512; // 总数据长度

// 从 M.2 NVMe 驱动读取数据
uint8_t *data_buffer = usb_msc_get_data_buffer(); // 从 USB MSC 驱动获取数据缓冲区
M2_NVMeResult_t nvme_result = m2_nvme_read_blocks(lba, block_count, data_buffer);

if (nvme_result == M2_NVME_RESULT_OK) {
usb_msc_send_data_response(data_buffer, data_length); // 通过 USB MSC 发送数据
} else {
// NVMe 读取错误,发送错误状态
usb_msc_send_command_status(MSC_STATUS_CHECK_CONDITION); // 发送错误状态
// ... 设置 Sense Key, ASC/ASCQ 等错误信息 ...
}
break;
}
case SCSI_OPCODE_WRITE_10:
case SCSI_OPCODE_WRITE_12: {
// 处理 SCSI WRITE (10/12) 命令,写入数据
uint32_t lba = scsi_cmd_block->lba;
uint16_t block_count = scsi_cmd_block->block_count;
uint32_t data_length = block_count * 512;

// 从 USB MSC 接收数据
uint8_t *data_buffer = usb_msc_get_data_buffer();
usb_msc_receive_data_command(data_buffer, data_length); // 接收主机发送的数据

// 将数据写入 M.2 NVMe
M2_NVMeResult_t nvme_result = m2_nvme_write_blocks(lba, block_count, data_buffer);

if (nvme_result == M2_NVMe_RESULT_OK) {
usb_msc_send_command_status(MSC_STATUS_GOOD); // 发送成功状态
} else {
// NVMe 写入错误,发送错误状态
usb_msc_send_command_status(MSC_STATUS_CHECK_CONDITION);
// ... 设置 Sense Key, ASC/ASCQ 等错误信息 ...
}
break;
}
case SCSI_OPCODE_TEST_UNIT_READY: {
// 处理 SCSI TEST UNIT READY 命令,检查设备是否就绪
M2_NVMeDeviceStatus_t nvme_device_status = m2_nvme_get_device_status();
if (nvme_device_status == M2_NVME_DEVICE_STATUS_READY) {
usb_msc_send_command_status(MSC_STATUS_GOOD); // 设备就绪
} else {
usb_msc_send_command_status(MSC_STATUS_CHECK_CONDITION); // 设备未就绪
// ... 设置 Sense Key, ASC/ASCQ 等错误信息 ...
}
break;
}
// ... 其他 SCSI 命令处理 ...
default:
// 不支持的 SCSI 命令
usb_msc_send_command_status(MSC_STATUS_INVALID_COMMAND); // 发送命令无效状态
break;
}
}

// ... 其他协议转换模块函数 ...

3.4 应用接口层 (Application Interface Layer) - USB MSC 类驱动 (usb_msc_driver.c) - 框架示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include "usb_msc_driver.h"
#include "usb_controller.h" // USB 控制器驱动
#include "protocol_converter.h" // 协议转换模块

// MSC 状态
typedef enum {
MSC_STATE_IDLE,
MSC_STATE_COMMAND_PHASE,
MSC_STATE_DATA_IN_PHASE,
MSC_STATE_DATA_OUT_PHASE,
MSC_STATE_STATUS_PHASE
} MSC_State_t;

static MSC_State_t msc_state = MSC_STATE_IDLE;
static MSC_SCSICommandBlock_t current_scsi_cmd_block;
static uint8_t *msc_data_buffer; // 数据缓冲区
static uint32_t msc_data_length; // 数据长度
static uint32_t msc_data_transferred; // 已传输数据长度

// 初始化 USB MSC 类驱动
void usb_msc_init(void) {
msc_state = MSC_STATE_IDLE;
msc_data_buffer = // ... 分配数据缓冲区 ...
msc_data_length = 0;
msc_data_transferred = 0;
// ... 其他 MSC 初始化 ...
}

// 处理 MSC 类特定 USB 请求 (从 USB 控制器驱动层调用)
void usb_msc_class_request_handler(uint8_t request, uint16_t value, uint16_t index, uint16_t length) {
switch (request) {
case MSC_REQ_GET_MAX_LUN:
// 处理 GET_MAX_LUN 请求,返回逻辑单元号 (LUN) 数量
usb_msc_send_control_data(&lun_count, 1); // 假设只有一个 LUN,返回 0
break;
case MSC_REQ_RESET:
// 处理 RESET 请求,复位 MSC 设备
usb_msc_reset();
usb_send_status_stage();
break;
default:
usb_stall_control_endpoint();
break;
}
}

// 处理 Bulk OUT 端点事件 (接收命令块)
void usb_msc_handle_bulk_out_event(void) {
if (msc_state == MSC_STATE_IDLE) {
// 接收 SCSI 命令块 (CDB)
hal_usb_receive_data(USB_ENDPOINT_BULK_OUT, (uint8_t*)&current_scsi_cmd_block, sizeof(MSC_SCSICommandBlock_t));
msc_state = MSC_STATE_COMMAND_PHASE;
protocol_converter_handle_msc_scsi_command(&current_scsi_cmd_block); // 调用协议转换模块处理 SCSI 命令
} else if (msc_state == MSC_STATE_DATA_OUT_PHASE) {
// 接收数据阶段
uint32_t remaining_length = msc_data_length - msc_data_transferred;
uint32_t receive_length = MIN(remaining_length, USB_BULK_ENDPOINT_MAX_PACKET_SIZE); // 每次接收最大包大小
hal_usb_receive_data(USB_ENDPOINT_BULK_OUT, msc_data_buffer + msc_data_transferred, receive_length);
msc_data_transferred += receive_length;

if (msc_data_transferred >= msc_data_length) {
msc_state = MSC_STATE_STATUS_PHASE;
protocol_converter_continue_data_out_phase(); // 调用协议转换模块继续处理数据输出阶段
}
}
}

// 发送数据响应 (Bulk IN)
void usb_msc_send_data_response(const uint8_t *data, uint32_t data_len) {
msc_state = MSC_STATE_DATA_IN_PHASE;
msc_data_buffer = (uint8_t*)data;
msc_data_length = data_len;
msc_data_transferred = 0;
usb_msc_send_next_data_packet(); // 发送第一个数据包
}

// 发送下一个数据包 (Bulk IN)
static void usb_msc_send_next_data_packet(void) {
if (msc_data_transferred < msc_data_length) {
uint32_t remaining_length = msc_data_length - msc_data_transferred;
uint32_t send_length = MIN(remaining_length, USB_BULK_ENDPOINT_MAX_PACKET_SIZE);
hal_usb_send_data(USB_ENDPOINT_BULK_IN, msc_data_buffer + msc_data_transferred, send_length);
msc_data_transferred += send_length;
} else {
msc_state = MSC_STATE_STATUS_PHASE;
protocol_converter_data_in_phase_complete(); // 通知协议转换模块数据输入阶段完成
}
}

// 发送命令状态 (CSW - Command Status Wrapper)
void usb_msc_send_command_status(MSC_CommandStatus_t status) {
MSC_CommandStatusWrapper_t csw;
csw.signature = MSC_CSW_SIGNATURE;
csw.tag = current_scsi_cmd_block.tag;
csw.status = status;
csw.data_residue = 0; // 实际应用中需要计算剩余数据长度

msc_state = MSC_STATE_STATUS_PHASE;
hal_usb_send_data(USB_ENDPOINT_BULK_IN, (uint8_t*)&csw, sizeof(csw));
msc_state = MSC_STATE_IDLE; // 完成一个命令处理周期,回到空闲状态
}

// ... 其他 USB MSC 类驱动函数 ...

3.5 M.2 NVMe 驱动 (m2_nvme_driver.c) - 框架示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include "m2_nvme_driver.h"
#include "hal_m2_pcie.h" // 假设 HAL 层提供 M.2 PCIe 相关接口

// NVMe 设备状态
typedef enum {
M2_NVME_DEVICE_STATUS_NOT_PRESENT,
M2_NVME_DEVICE_STATUS_INITIALIZING,
M2_NVME_DEVICE_STATUS_READY,
M2_NVME_DEVICE_STATUS_ERROR
} M2_NVMeDeviceStatus_t;

static M2_NVMeDeviceStatus_t m2_nvme_device_status = M2_NVMe_DEVICE_STATUS_NOT_PRESENT;

// 初始化 M.2 NVMe 驱动
M2_NVMeResult_t m2_nvme_init(void) {
hal_m2_pcie_init(); // 初始化 M.2 PCIe PHY 和控制器硬件

// 1. 检测 M.2 设备是否连接 (例如:通过 GPIO 检测 Present 信号)
if (!hal_m2_pcie_device_present()) {
m2_nvme_device_status = M2_NVMe_DEVICE_STATUS_NOT_PRESENT;
return M2_NVME_RESULT_DEVICE_NOT_PRESENT;
}

m2_nvme_device_status = M2_NVME_DEVICE_STATUS_INITIALIZING;

// 2. NVMe 控制器复位
hal_m2_pcie_controller_reset();

// 3. 读取 NVMe 控制器能力寄存器 (CAP)
NVMe_ControllerCapabilities_t controller_capabilities;
hal_m2_pcie_read_controller_capabilities(&controller_capabilities);

// 4. 设置 Admin 队列基地址 (Admin Queue Base Address - AQBS 和 AQC)
// ... (根据 controller_capabilities 配置 Admin 队列) ...

// 5. 使能 NVMe 控制器 (Controller Enable - EN)
hal_m2_pcie_enable_controller();

// 6. 等待控制器就绪 (Controller Ready - RDY)
if (!hal_m2_pcie_wait_controller_ready(NVME_CONTROLLER_READY_TIMEOUT_MS)) {
m2_nvme_device_status = M2_NVME_DEVICE_STATUS_ERROR;
return M2_NVME_RESULT_CONTROLLER_INIT_FAILED;
}

m2_nvme_device_status = M2_NVMe_DEVICE_STATUS_READY;
return M2_NVME_RESULT_OK;
}

// 读取硬盘容量
uint64_t m2_nvme_get_disk_capacity(void) {
// 1. 发送 Identify Namespace 命令 (Admin Command)
NVMe_Command_t command;
NVMe_CompletionQueueEntry_t completion;
// ... 填充 Identify Namespace 命令结构体 ...

M2_NVMeResult_t result = m2_nvme_submit_admin_command(&command, &completion);
if (result != M2_NVME_RESULT_OK) {
return 0; // 获取容量失败
}

// 2. 解析 Identify Namespace 命令返回的数据,获取容量信息
NVMe_NamespaceIdentifyData_t namespace_identify_data;
hal_m2_pcie_read_data_from_dma_buffer(&namespace_identify_data, sizeof(namespace_identify_data));

uint64_t namespace_size_blocks = namespace_identify_data.nsze; // 命名空间大小 (块数)
uint64_t block_size_bytes = namespace_identify_data.lbaf[0].lbads; // LBA 格式 0 的块大小 (字节)
return namespace_size_blocks * block_size_bytes; // 计算总容量 (字节)
}

// 读取数据块
M2_NVMeResult_t m2_nvme_read_blocks(uint32_t lba, uint16_t block_count, uint8_t *data_buffer) {
// 1. 创建 NVMe 读取命令 (I/O Command)
NVMe_Command_t command;
NVMe_CompletionQueueEntry_t completion;
// ... 填充 NVMe 读取命令结构体,指定 LBA, 块数量, 数据缓冲区地址等 ...

// 2. 提交 I/O 命令到 Submission Queue
M2_NVMeResult_t result = m2_nvme_submit_io_command(&command, &completion);
if (result != M2_NVMe_RESULT_OK) {
return result; // 命令提交失败
}

// 3. 等待命令完成 (轮询 Completion Queue 或中断方式)
if (!m2_nvme_wait_command_completion(&completion, NVME_COMMAND_TIMEOUT_MS)) {
return M2_NVME_RESULT_COMMAND_TIMEOUT; // 命令超时
}

// 4. 检查命令完成状态 (completion.sqes)
if (completion.sqes != NVME_COMMAND_STATUS_SUCCESS) {
return M2_NVME_RESULT_COMMAND_ERROR; // 命令执行错误
}

// 5. 数据已通过 DMA 传输到 data_buffer,读取完成
return M2_NVME_RESULT_OK;
}

// 写入数据块
M2_NVMeResult_t m2_nvme_write_blocks(uint32_t lba, uint16_t block_count, const uint8_t *data_buffer) {
// ... (类似于 m2_nvme_read_blocks,创建 NVMe 写入命令,提交命令,等待完成,检查状态) ...
// 区别在于:需要将 data_buffer 中的数据通过 DMA 传输到 M.2 设备
return M2_NVMe_RESULT_OK; // 示例,实际需要根据实现返回结果
}


// 提交 Admin 命令
static M2_NVMeResult_t m2_nvme_submit_admin_command(NVMe_Command_t *command, NVMe_CompletionQueueEntry_t *completion) {
// ... (将 Admin 命令写入 Admin Submission Queue,并等待命令完成) ...
return M2_NVMe_RESULT_OK; // 示例
}

// 提交 I/O 命令
static M2_NVMeResult_t m2_nvme_submit_io_command(NVMe_Command_t *command, NVMe_CompletionQueueEntry_t *completion) {
// ... (将 I/O 命令写入 I/O Submission Queue,并等待命令完成) ...
return M2_NVMe_RESULT_OK; // 示例
}

// 等待命令完成
static bool m2_nvme_wait_command_completion(NVMe_CompletionQueueEntry_t *completion, uint32_t timeout_ms) {
// ... (轮询或中断方式检查 Completion Queue,等待命令完成,超时返回 false) ...
return true; // 示例,实际需要实现等待逻辑
}

// 获取 NVMe 设备状态
M2_NVMeDeviceStatus_t m2_nvme_get_device_status(void) {
return m2_nvme_device_status;
}

// ... 其他 M.2 NVMe 驱动函数 ...

4. 测试验证

在系统开发完成后,需要进行全面的测试验证,确保系统的功能、性能、可靠性都满足需求。测试阶段主要包括:

  • 单元测试 (Unit Testing): 对每个模块 (例如 HAL 模块、驱动模块、协议转换模块) 进行单独测试,验证模块的功能是否正确。

  • 集成测试 (Integration Testing): 将各个模块集成在一起进行测试,验证模块之间的接口和协作是否正确。

  • 系统测试 (System Testing): 对整个系统进行全面的功能和性能测试,包括:

    • 功能测试: 验证所有功能需求是否实现,例如 USB Type-C 兼容性、M.2 接口支持、热插拔、LED 指示灯、固件升级等。
    • 性能测试: 测试数据传输速率、响应时间等性能指标,确保达到性能需求。可以使用专业的硬盘测速工具 (例如 CrystalDiskMark, ATTO Disk Benchmark) 进行测试。
    • 稳定性测试: 进行长时间的读写操作,模拟实际使用场景,验证系统的稳定性。
    • 兼容性测试: 在不同的主机系统 (Windows, macOS, Linux) 和不同的 M.2 SSD 上进行测试,验证系统的兼容性。
    • 错误处理测试: 模拟各种错误场景 (例如 USB 连接断开、M.2 设备故障等),验证系统的错误处理机制是否有效。
  • 回归测试 (Regression Testing): 在每次代码修改或功能更新后,需要进行回归测试,确保新的修改没有引入新的bug,并且没有破坏原有的功能。

5. 维护升级

在产品发布后,还需要进行维护和升级,以修复bug、增强功能、提升性能。维护升级主要包括:

  • Bug 修复: 收集用户反馈和测试报告,及时修复系统中存在的bug。
  • 功能扩展: 根据用户需求和市场变化,增加新的功能,例如支持新的协议、优化性能、增加安全特性等。
  • 固件升级: 通过USB接口提供固件升级功能,方便用户更新固件,获取最新的功能和bug修复。固件升级流程需要保证安全可靠,防止升级过程中出现错误导致设备无法使用。
  • 版本管理: 使用版本控制系统 (例如 Git) 管理代码,方便代码维护和版本回溯。

6. 实践验证的技术和方法

本项目中采用的各种技术和方法都是经过实践验证的,例如:

  • 标准 C 语言: 使用标准 C 语言进行开发,保证代码的可移植性和可维护性。
  • 分层架构和事件驱动架构: 成熟的嵌入式系统设计架构,能够提高代码的模块化程度、可扩展性和实时性。
  • 硬件抽象层 (HAL): 提高代码的可移植性,方便移植到不同的硬件平台。
  • USB Mass Storage Class (MSC): 标准的USB存储协议,兼容性好,易于使用。
  • NVMe 协议: 高性能的SSD接口协议,能够充分发挥NVMe SSD的性能。
  • DMA (Direct Memory Access): 提高数据传输效率,降低CPU负载。
  • 中断处理: 提高系统响应速度和实时性。
  • 状态机: 清晰地管理系统状态,简化程序设计。
  • 测试驱动开发 (TDD - 可选): 在开发过程中先编写测试用例,然后根据测试用例编写代码,保证代码质量。
  • 代码审查 (Code Review): 通过代码审查,提高代码质量,减少bug。
  • 版本控制 (Git): 管理代码版本,方便代码协作和维护。

总结

基于ASM235CM的Type-C M.2硬盘盒嵌入式系统开发是一个涉及硬件、软件、协议等多个方面的复杂项目。通过采用分层架构和事件驱动架构,结合标准 C 语言和实践验证的技术和方法,我们可以构建一个可靠、高效、可扩展的系统平台。上述代码示例仅为框架和关键模块的展示,实际的完整代码实现会更加复杂和庞大,需要根据具体的硬件平台和需求进行详细设计和开发。希望这份详细的说明能够帮助您理解整个嵌入式系统的开发流程和代码设计架构。

欢迎关注我的其它发布渠道