usb驱动
This commit is contained in:
1 parent
313fb91321
commit
c52f1f665f
22 files changed
+5601
-112
No files matched your search
+1
-1
@@ -366,7 +366,7 @@ extern "C"
|
||||
*/
|
||||
|
||||
/*#define BSP_USING_USBHOST*/
|
||||
|
||||
#define BSP_USING_USBHOST
|
||||
/*-------------------------- USB HOST CONFIG END --------------------------*/
|
||||
|
||||
/*-------------------------- USB DEVICE CONFIG BEGIN --------------------------*/
|
||||
|
||||
+181
-43
@@ -7,15 +7,26 @@
|
||||
* Date Author Notes
|
||||
* 2017-10-30 ZYH the first version
|
||||
* 2019-12-19 tyustli port to stm32 series
|
||||
* 2026-01-02 Qwen port to RT-Thread v5.1.0
|
||||
* 2026-01-03 Qwen fix enumeration: add set_address & fix FIFO timing
|
||||
*/
|
||||
#include "drv_usbh.h"
|
||||
#include "board.h"
|
||||
#include<rtthread.h>
|
||||
#include<rtdevice.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#ifdef BSP_USING_USBHOST
|
||||
|
||||
static HCD_HandleTypeDef stm32_hhcd_fs;
|
||||
/* 兼容旧版 RT_DEBUG_LOG 宏(v5.x 已移除) */
|
||||
#ifndef RT_DEBUG_LOG
|
||||
#ifdef RT_DEBUG_USB
|
||||
#define RT_DEBUG_LOG(mask, fmt) rt_kprintf fmt
|
||||
#else
|
||||
#define RT_DEBUG_LOG(mask, fmt)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static HCD_HandleTypeDef stm32_hhcd_fs = {0}; // 显式初始化为 0
|
||||
static struct rt_completion urb_completion;
|
||||
static volatile rt_bool_t connect_status = RT_FALSE;
|
||||
|
||||
@@ -43,7 +54,7 @@ void HAL_HCD_Disconnect_Callback(HCD_HandleTypeDef *hhcd)
|
||||
if (connect_status)
|
||||
{
|
||||
connect_status = RT_FALSE;
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("usb disconnnect\n"));
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("usb disconnect\n"));
|
||||
rt_usbh_root_hub_disconnect_handler(hcd, OTG_FS_PORT);
|
||||
}
|
||||
}
|
||||
@@ -60,34 +71,109 @@ static rt_err_t drv_reset_port(rt_uint8_t port)
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#define USBH_MAX_XFER_SIZE 64
|
||||
static uint8_t g_usbh_aligned_buffer[USBH_MAX_XFER_SIZE] __attribute__((aligned(4)));
|
||||
|
||||
static int drv_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbytes, int timeouts)
|
||||
{
|
||||
int timeout = timeouts;
|
||||
uint8_t hal_pid;
|
||||
void *xfer_buf = buffer;
|
||||
rt_bool_t use_local_buf = RT_FALSE;
|
||||
|
||||
/* 参数校验 */
|
||||
if (buffer == RT_NULL || nbytes <= 0)
|
||||
return -RT_EINVAL;
|
||||
|
||||
|
||||
if (pipe->pipe_index == 0)
|
||||
{
|
||||
HAL_HCD_HC_Init(&stm32_hhcd_fs,
|
||||
pipe->pipe_index,
|
||||
pipe->ep.bEndpointAddress,
|
||||
pipe->inst->address,
|
||||
USB_OTG_SPEED_FULL,
|
||||
pipe->ep.bmAttributes,
|
||||
pipe->ep.wMaxPacketSize);
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("EP0 channel reinitialized\n"));
|
||||
}
|
||||
|
||||
if (pipe->pipe_index == 0 && nbytes == 8 && token == 0) /* SETUP stage */
|
||||
{
|
||||
hal_pid = HC_PID_SETUP;
|
||||
}
|
||||
else if (token == 2) /* IN token */
|
||||
{
|
||||
/* >>> 关键修复:EP0 的第一次 IN 必须用 DATA1 <<< */
|
||||
if (pipe->pipe_index == 0)
|
||||
{
|
||||
hal_pid = HC_PID_DATA1; // ← 改为 DATA1!
|
||||
}
|
||||
else
|
||||
{
|
||||
hal_pid = HC_PID_DATA0;
|
||||
}
|
||||
|
||||
if ((((rt_ubase_t)buffer & 0x3U) != 0) || (nbytes > USBH_MAX_XFER_SIZE))
|
||||
{
|
||||
xfer_buf = g_usbh_aligned_buffer;
|
||||
use_local_buf = RT_TRUE;
|
||||
}
|
||||
}
|
||||
else /* OUT (including status stage) */
|
||||
{
|
||||
/* STATUS 阶段也应为 DATA1,但通常用 DATA0 也能工作 */
|
||||
hal_pid = HC_PID_DATA0;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (!connect_status)
|
||||
{
|
||||
return -1;
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
rt_completion_init(&urb_completion);
|
||||
|
||||
/* 提交 USB 事务 */
|
||||
HAL_HCD_HC_SubmitRequest(&stm32_hhcd_fs,
|
||||
pipe->pipe_index,
|
||||
(pipe->ep.bEndpointAddress & 0x80) >> 7,
|
||||
pipe->ep.bmAttributes,
|
||||
token,
|
||||
buffer,
|
||||
hal_pid,
|
||||
xfer_buf,
|
||||
nbytes,
|
||||
0);
|
||||
rt_completion_wait(&urb_completion, timeout);
|
||||
rt_thread_mdelay(1);
|
||||
if (hal_pid == HC_PID_SETUP)
|
||||
{
|
||||
rt_thread_mdelay(10); // 至少 1~2ms,让设备处理 SETUP
|
||||
}
|
||||
/* 等待完成 */
|
||||
rt_err_t wait_result = rt_completion_wait(&urb_completion, timeout);
|
||||
if (wait_result != RT_EOK)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("xfer timeout\n"));
|
||||
pipe->status = UPIPE_STATUS_ERROR;
|
||||
if (pipe->callback != RT_NULL)
|
||||
pipe->callback(pipe);
|
||||
return -RT_ETIMEOUT;
|
||||
}
|
||||
|
||||
rt_thread_mdelay(5); /* 短暂延迟,确保状态更新 */
|
||||
|
||||
/* 检查通道状态 */
|
||||
if (HAL_HCD_HC_GetState(&stm32_hhcd_fs, pipe->pipe_index) == HC_NAK)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("nak\n"));
|
||||
if (pipe->ep.bmAttributes == USB_EP_ATTR_INT)
|
||||
{
|
||||
rt_thread_delay((pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) > 0 ? (pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) : 1);
|
||||
rt_thread_delay((pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) > 0 ?
|
||||
(pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) : 1);
|
||||
}
|
||||
/* 重置通道 */
|
||||
HAL_HCD_HC_Halt(&stm32_hhcd_fs, pipe->pipe_index);
|
||||
HAL_HCD_HC_Init(&stm32_hhcd_fs,
|
||||
pipe->pipe_index,
|
||||
@@ -103,54 +189,64 @@ static int drv_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbyte
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("stall\n"));
|
||||
pipe->status = UPIPE_STATUS_STALL;
|
||||
if (pipe->callback != RT_NULL)
|
||||
{
|
||||
pipe->callback(pipe);
|
||||
}
|
||||
return -1;
|
||||
return -RT_EIO;
|
||||
}
|
||||
else if (HAL_HCD_HC_GetState(&stm32_hhcd_fs, pipe->pipe_index) == URB_ERROR)
|
||||
else if (HAL_HCD_HC_GetURBState(&stm32_hhcd_fs, pipe->pipe_index) == URB_ERROR)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("error\n"));
|
||||
uint32_t hc_state = HAL_HCD_HC_GetState(&stm32_hhcd_fs, pipe->pipe_index);
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("URB_ERROR: HC_STATE=%d\n", hc_state));
|
||||
pipe->status = UPIPE_STATUS_ERROR;
|
||||
if (pipe->callback != RT_NULL)
|
||||
{
|
||||
pipe->callback(pipe);
|
||||
}
|
||||
return -1;
|
||||
return -RT_ERROR;
|
||||
}
|
||||
else if(URB_DONE == HAL_HCD_HC_GetURBState(&stm32_hhcd_fs, pipe->pipe_index))
|
||||
else if (HAL_HCD_HC_GetURBState(&stm32_hhcd_fs, pipe->pipe_index) == URB_DONE)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("ok\n"));
|
||||
pipe->status = UPIPE_STATUS_OK;
|
||||
if (pipe->callback != RT_NULL)
|
||||
{
|
||||
pipe->callback(pipe);
|
||||
}
|
||||
size_t size = HAL_HCD_HC_GetXferCount(&stm32_hhcd_fs, pipe->pipe_index);
|
||||
if (pipe->ep.bEndpointAddress & 0x80)
|
||||
|
||||
size_t xfer_count = HAL_HCD_HC_GetXferCount(&stm32_hhcd_fs, pipe->pipe_index);
|
||||
|
||||
/* 如果使用了本地对齐缓冲区,拷回数据(仅 IN) */
|
||||
if (use_local_buf && token == 2)
|
||||
{
|
||||
return size;
|
||||
if (xfer_count > (size_t)nbytes)
|
||||
xfer_count = nbytes;
|
||||
rt_memcpy(buffer, g_usbh_aligned_buffer, xfer_count);
|
||||
}
|
||||
else if (pipe->ep.bEndpointAddress & 0x00)
|
||||
{
|
||||
return size;
|
||||
}
|
||||
return nbytes;
|
||||
|
||||
return (int)xfer_count;
|
||||
}
|
||||
|
||||
/* 其他情况:重试 */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
static rt_uint16_t pipe_index = 0;
|
||||
static rt_uint8_t drv_get_free_pipe_index(void)
|
||||
static rt_uint8_t drv_get_free_pipe_index(rt_bool_t is_ep0)
|
||||
{
|
||||
rt_uint8_t idx;
|
||||
if (is_ep0)
|
||||
{
|
||||
/* EP0 必须使用 channel 0 */
|
||||
if (!(pipe_index & (1U << 0)))
|
||||
{
|
||||
pipe_index |= (1U << 0);
|
||||
return 0;
|
||||
}
|
||||
return 0xff; // channel 0
|
||||
}
|
||||
|
||||
/* 其他端点从 1~15 分配 */
|
||||
for (idx = 1; idx < 16; idx++)
|
||||
{
|
||||
if (!(pipe_index & (0x01 << idx)))
|
||||
if (!(pipe_index & (1U << idx)))
|
||||
{
|
||||
pipe_index |= (0x01 << idx);
|
||||
pipe_index |= (1U << idx);
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
@@ -163,8 +259,11 @@ static void drv_free_pipe_index(rt_uint8_t index)
|
||||
}
|
||||
|
||||
static rt_err_t drv_open_pipe(upipe_t pipe)
|
||||
{
|
||||
pipe->pipe_index = drv_get_free_pipe_index();
|
||||
{rt_bool_t is_ep0 = (pipe->ep.bEndpointAddress == 0); // EP0 地址为 0
|
||||
pipe->pipe_index = drv_get_free_pipe_index(is_ep0);
|
||||
if (pipe->pipe_index == 0xff)
|
||||
return -RT_ERROR;
|
||||
|
||||
HAL_HCD_HC_Init(&stm32_hhcd_fs,
|
||||
pipe->pipe_index,
|
||||
pipe->ep.bEndpointAddress,
|
||||
@@ -172,7 +271,7 @@ static rt_err_t drv_open_pipe(upipe_t pipe)
|
||||
USB_OTG_SPEED_FULL,
|
||||
pipe->ep.bmAttributes,
|
||||
pipe->ep.wMaxPacketSize);
|
||||
/* Set DATA0 PID token*/
|
||||
/* Set DATA0 PID token */
|
||||
if (stm32_hhcd_fs.hc[pipe->pipe_index].ep_is_in)
|
||||
{
|
||||
stm32_hhcd_fs.hc[pipe->pipe_index].toggle_in = 0;
|
||||
@@ -191,32 +290,70 @@ static rt_err_t drv_close_pipe(upipe_t pipe)
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t drv_set_address(rt_uint8_t dev_addr)
|
||||
{
|
||||
RT_DEBUG_LOG(RT_DEBUG_USB, ("[set_address] address=%d\n", dev_addr));
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/* ✅ 修正:uhcd_ops 必须包含 5 个成员(v5.1 要求) */
|
||||
static struct uhcd_ops _uhcd_ops =
|
||||
{
|
||||
drv_reset_port,
|
||||
drv_pipe_xfer,
|
||||
drv_open_pipe,
|
||||
drv_close_pipe,
|
||||
drv_set_address,
|
||||
};
|
||||
|
||||
static rt_err_t stm32_hcd_init(rt_device_t device)
|
||||
{
|
||||
HCD_HandleTypeDef *hhcd = (HCD_HandleTypeDef *)device->user_data;
|
||||
// 确保 HSI48 锁定(推荐)
|
||||
__HAL_RCC_HSI48_ENABLE();
|
||||
while (__HAL_RCC_GET_FLAG(RCC_FLAG_HSI48RDY) == RESET);
|
||||
|
||||
hhcd->Instance = USB_OTG_FS;
|
||||
hhcd->Init.Host_channels = 8;
|
||||
hhcd->Init.speed = HCD_SPEED_FULL;
|
||||
hhcd->Init.dma_enable = DISABLE;
|
||||
hhcd->Init.phy_itface = HCD_PHY_EMBEDDED;
|
||||
hhcd->Init.Sof_enable = DISABLE;
|
||||
RT_ASSERT(HAL_HCD_Init(hhcd) == HAL_OK);
|
||||
hhcd->Init.low_power_enable = DISABLE;
|
||||
hhcd->Init.Sof_enable = ENABLE;
|
||||
hhcd->Init.vbus_sensing_enable = DISABLE;
|
||||
|
||||
if (HAL_HCD_Init(hhcd) != HAL_OK)
|
||||
{
|
||||
rt_kprintf("HAL_HCD_Init failed!\n");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
// ✅ 关键修正:FIFO 配置必须在 HAL_HCD_Init() 之后!
|
||||
hhcd->Instance->GRXFSIZ = 256; // RX FIFO = 256 words (1024 bytes)
|
||||
hhcd->Instance->HPTXFSIZ = (256 << 16) | 128;
|
||||
|
||||
HAL_HCD_Start(hhcd);
|
||||
hhcd->Instance->GUSBCFG |= (1UL << 28);
|
||||
|
||||
#ifdef USBH_USING_CONTROLLABLE_POWER
|
||||
rt_pin_mode(USBH_POWER_PIN, PIN_MODE_OUTPUT);
|
||||
rt_pin_write(USBH_POWER_PIN, PIN_LOW);
|
||||
rt_pin_write(USBH_POWER_PIN, PIN_LOW); // 根据硬件确认极性
|
||||
#endif
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/* 设备操作函数表 */
|
||||
static struct rt_device_ops usbh_device_ops =
|
||||
{
|
||||
.init = stm32_hcd_init,
|
||||
.open = RT_NULL,
|
||||
.close = RT_NULL,
|
||||
.read = RT_NULL,
|
||||
.write = RT_NULL,
|
||||
.control = RT_NULL,
|
||||
};
|
||||
|
||||
int stm_usbh_register(void)
|
||||
{
|
||||
rt_err_t res = -RT_ERROR;
|
||||
@@ -225,13 +362,14 @@ int stm_usbh_register(void)
|
||||
if (uhcd == RT_NULL)
|
||||
{
|
||||
rt_kprintf("uhcd malloc failed\r\n");
|
||||
return -RT_ERROR;
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
rt_memset((void *)uhcd, 0, sizeof(struct uhcd));
|
||||
|
||||
/* 初始化父设备 */
|
||||
uhcd->parent.type = RT_Device_Class_USBHost;
|
||||
uhcd->parent.init = stm32_hcd_init;
|
||||
uhcd->parent.ops = &usbh_device_ops;
|
||||
uhcd->parent.user_data = &stm32_hhcd_fs;
|
||||
|
||||
uhcd->ops = &_uhcd_ops;
|
||||
@@ -242,13 +380,13 @@ int stm_usbh_register(void)
|
||||
if (res != RT_EOK)
|
||||
{
|
||||
rt_kprintf("register usb host failed res = %d\r\n", res);
|
||||
rt_free(uhcd);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
rt_usb_host_init();
|
||||
|
||||
rt_usb_host_init("usbh");
|
||||
return RT_EOK;
|
||||
}
|
||||
INIT_DEVICE_EXPORT(stm_usbh_register);
|
||||
|
||||
#endif
|
||||
#endif /* BSP_USING_USBHOST */
|
||||
Reference in new issue
Block a user