关注微信公众号,提前获取相关推文 本项目旨在设计和开发一个高性能、兼容性强的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" #define EXTERNAL_CRYSTAL_FREQ 24000000UL void hal_clock_init (uint32_t target_cpu_freq) { REG_CLK_CTRL |= CLK_CTRL_EXT_OSC_EN; uint32_t pll_multiplier = target_cpu_freq / EXTERNAL_CRYSTAL_FREQ; REG_PLL_CTRL = (pll_multiplier << PLL_CTRL_MULTIPLIER_SHIFT) | PLL_CTRL_PLL_EN; REG_CLK_CTRL |= CLK_CTRL_SYS_CLK_SRC_PLL; REG_CLK_USB_DIV = 1 ; REG_CLK_M2_DIV = 1 ; } uint32_t hal_clock_get_cpu_freq (void ) { return system_cpu_frequency; } 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 : 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" 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 ; if (mode == GPIO_MODE_OUTPUT) { REG_GPIO_MODE[reg_group_index] |= (1 << pin_num); } else { REG_GPIO_MODE[reg_group_index] &= ~(1 << pin_num); } 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 { REG_GPIO_PULLUP[reg_group_index] &= ~(1 << pin_num); REG_GPIO_PULLDOWN[reg_group_index] &= ~(1 << pin_num); } } 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 { REG_GPIO_OUTPUT_CLEAR[reg_group_index] |= (1 << pin_num); } } 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; } }
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" #include "usb_descriptors.h" 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;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[];#define USB_ENDPOINT_BULK_IN 1 #define USB_ENDPOINT_BULK_OUT 2 #define USB_ENDPOINT_CONTROL 0 void usb_controller_irq_handler (void ) { uint32_t usb_interrupt_status = hal_usb_get_interrupt_status(); if (usb_interrupt_status & USB_INTERRUPT_RESET) { 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) { usb_handle_setup_packet(); } if (usb_interrupt_status & USB_INTERRUPT_ENDPOINT0) { usb_handle_endpoint0_event(); } if (usb_interrupt_status & USB_INTERRUPT_ENDPOINT1) { usb_handle_endpoint_bulk_in_event(); } if (usb_interrupt_status & USB_INTERRUPT_ENDPOINT2) { usb_handle_endpoint_bulk_out_event(); } hal_usb_clear_interrupt_status(usb_interrupt_status); } 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 : hal_usb_stall_endpoint(USB_ENDPOINT_CONTROL); break ; } } 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: break ; case USB_REQ_CLEAR_FEATURE: break ; case USB_REQ_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 ); } void usb_controller_init (void ) { hal_usb_init(); hal_usb_enable_interrupts(); usb_device_state = USB_STATE_DETACHED; } static void usb_handle_endpoint_bulk_in_event (void ) { } static void usb_handle_endpoint_bulk_out_event (void ) { } static void usb_handle_class_request (uint8_t request, uint16_t value, uint16_t index, uint16_t length) { } static void usb_handle_vendor_request (uint8_t request, uint16_t value, uint16_t index, uint16_t length) { }
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" #include "m2_nvme_driver.h" void protocol_converter_handle_msc_scsi_command (const MSC_SCSICommandBlock_t *scsi_cmd_block) { uint8_t opcode = scsi_cmd_block->opcode; switch (opcode) { case SCSI_OPCODE_INQUIRY: { MSC_SCSIInquiryData_t inquiry_data; usb_msc_send_data_response((uint8_t *)&inquiry_data, sizeof (inquiry_data)); break ; } case SCSI_OPCODE_READ_CAPACITY_10: { MSC_SCSIReadCapacity10Data_t capacity_data; uint64_t disk_capacity_bytes = m2_nvme_get_disk_capacity(); capacity_data.last_lba = disk_capacity_bytes / 512 - 1 ; 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: { uint32_t lba = scsi_cmd_block->lba; uint16_t block_count = scsi_cmd_block->block_count; uint32_t data_length = block_count * 512 ; uint8_t *data_buffer = usb_msc_get_data_buffer(); 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); } else { usb_msc_send_command_status(MSC_STATUS_CHECK_CONDITION); } break ; } case SCSI_OPCODE_WRITE_10: case SCSI_OPCODE_WRITE_12: { uint32_t lba = scsi_cmd_block->lba; uint16_t block_count = scsi_cmd_block->block_count; uint32_t data_length = block_count * 512 ; uint8_t *data_buffer = usb_msc_get_data_buffer(); usb_msc_receive_data_command(data_buffer, data_length); 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 { usb_msc_send_command_status(MSC_STATUS_CHECK_CONDITION); } break ; } case SCSI_OPCODE_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); } break ; } default : 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" #include "protocol_converter.h" 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; void usb_msc_init (void ) { msc_state = MSC_STATE_IDLE; msc_data_buffer = msc_data_length = 0 ; msc_data_transferred = 0 ; } 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: usb_msc_send_control_data(&lun_count, 1 ); break ; case MSC_REQ_RESET: usb_msc_reset(); usb_send_status_stage(); break ; default : usb_stall_control_endpoint(); break ; } } void usb_msc_handle_bulk_out_event (void ) { if (msc_state == MSC_STATE_IDLE) { hal_usb_receive_data(USB_ENDPOINT_BULK_OUT, (uint8_t *)¤t_scsi_cmd_block, sizeof (MSC_SCSICommandBlock_t)); msc_state = MSC_STATE_COMMAND_PHASE; protocol_converter_handle_msc_scsi_command(¤t_scsi_cmd_block); } 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(); } } } 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(); } 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(); } } 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; }
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" 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;M2_NVMeResult_t m2_nvme_init (void ) { hal_m2_pcie_init(); 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; hal_m2_pcie_controller_reset(); NVMe_ControllerCapabilities_t controller_capabilities; hal_m2_pcie_read_controller_capabilities(&controller_capabilities); hal_m2_pcie_enable_controller(); 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 ) { NVMe_Command_t command; NVMe_CompletionQueueEntry_t completion; M2_NVMeResult_t result = m2_nvme_submit_admin_command(&command, &completion); if (result != M2_NVME_RESULT_OK) { return 0 ; } 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; 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) { NVMe_Command_t command; NVMe_CompletionQueueEntry_t completion; M2_NVMeResult_t result = m2_nvme_submit_io_command(&command, &completion); if (result != M2_NVMe_RESULT_OK) { return result; } if (!m2_nvme_wait_command_completion(&completion, NVME_COMMAND_TIMEOUT_MS)) { return M2_NVME_RESULT_COMMAND_TIMEOUT; } if (completion.sqes != NVME_COMMAND_STATUS_SUCCESS) { return M2_NVME_RESULT_COMMAND_ERROR; } return M2_NVME_RESULT_OK; } M2_NVMeResult_t m2_nvme_write_blocks (uint32_t lba, uint16_t block_count, const uint8_t *data_buffer) { return M2_NVMe_RESULT_OK; } static M2_NVMeResult_t m2_nvme_submit_admin_command (NVMe_Command_t *command, NVMe_CompletionQueueEntry_t *completion) { return M2_NVMe_RESULT_OK; } static M2_NVMeResult_t m2_nvme_submit_io_command (NVMe_Command_t *command, NVMe_CompletionQueueEntry_t *completion) { return M2_NVMe_RESULT_OK; } static bool m2_nvme_wait_command_completion (NVMe_CompletionQueueEntry_t *completion, uint32_t timeout_ms) { return true ; } M2_NVMeDeviceStatus_t m2_nvme_get_device_status (void ) { return m2_nvme_device_status; }
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 语言和实践验证的技术和方法,我们可以构建一个可靠、高效、可扩展的系统平台。上述代码示例仅为框架和关键模块的展示,实际的完整代码实现会更加复杂和庞大,需要根据具体的硬件平台和需求进行详细设计和开发。希望这份详细的说明能够帮助您理解整个嵌入式系统的开发流程和代码设计架构。