cmcu为stm32h743IIt6
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

393 lines
11 KiB

/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-10-30 ZYH the first version
* 2019-12-19 tyustli port to stm32 series
3 weeks ago
* 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"
3 weeks ago
#include <rtthread.h>
#include <rtdevice.h>
#ifdef BSP_USING_USBHOST
3 weeks ago
/* 兼容旧版 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;
void OTG_FS_IRQHandler(void)
{
rt_interrupt_enter();
HAL_HCD_IRQHandler(&stm32_hhcd_fs);
rt_interrupt_leave();
}
void HAL_HCD_Connect_Callback(HCD_HandleTypeDef *hhcd)
{
uhcd_t hcd = (uhcd_t)hhcd->pData;
if (!connect_status)
{
connect_status = RT_TRUE;
RT_DEBUG_LOG(RT_DEBUG_USB, ("usb connected\n"));
rt_usbh_root_hub_connect_handler(hcd, OTG_FS_PORT, RT_FALSE);
}
}
void HAL_HCD_Disconnect_Callback(HCD_HandleTypeDef *hhcd)
{
uhcd_t hcd = (uhcd_t)hhcd->pData;
if (connect_status)
{
connect_status = RT_FALSE;
3 weeks ago
RT_DEBUG_LOG(RT_DEBUG_USB, ("usb disconnect\n"));
rt_usbh_root_hub_disconnect_handler(hcd, OTG_FS_PORT);
}
}
void HAL_HCD_HC_NotifyURBChange_Callback(HCD_HandleTypeDef *hhcd, uint8_t chnum, HCD_URBStateTypeDef urb_state)
{
rt_completion_done(&urb_completion);
}
static rt_err_t drv_reset_port(rt_uint8_t port)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("reset port\n"));
HAL_HCD_ResetPort(&stm32_hhcd_fs);
return RT_EOK;
}
3 weeks ago
#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;
3 weeks ago
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)
{
3 weeks ago
return -RT_ERROR;
}
3 weeks ago
rt_completion_init(&urb_completion);
3 weeks ago
/* 提交 USB 事务 */
HAL_HCD_HC_SubmitRequest(&stm32_hhcd_fs,
pipe->pipe_index,
(pipe->ep.bEndpointAddress & 0x80) >> 7,
pipe->ep.bmAttributes,
3 weeks ago
hal_pid,
xfer_buf,
nbytes,
0);
3 weeks ago
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)
{
3 weeks ago
rt_thread_delay((pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) > 0 ?
(pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) : 1);
}
3 weeks ago
/* 重置通道 */
HAL_HCD_HC_Halt(&stm32_hhcd_fs, pipe->pipe_index);
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);
continue;
}
else if (HAL_HCD_HC_GetState(&stm32_hhcd_fs, pipe->pipe_index) == HC_STALL)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("stall\n"));
pipe->status = UPIPE_STATUS_STALL;
if (pipe->callback != RT_NULL)
pipe->callback(pipe);
3 weeks ago
return -RT_EIO;
}
3 weeks ago
else if (HAL_HCD_HC_GetURBState(&stm32_hhcd_fs, pipe->pipe_index) == URB_ERROR)
{
3 weeks ago
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);
3 weeks ago
return -RT_ERROR;
}
3 weeks ago
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);
3 weeks ago
size_t xfer_count = HAL_HCD_HC_GetXferCount(&stm32_hhcd_fs, pipe->pipe_index);
/* 如果使用了本地对齐缓冲区,拷回数据(仅 IN) */
if (use_local_buf && token == 2)
{
3 weeks ago
if (xfer_count > (size_t)nbytes)
xfer_count = nbytes;
rt_memcpy(buffer, g_usbh_aligned_buffer, xfer_count);
}
3 weeks ago
return (int)xfer_count;
}
3 weeks ago
/* 其他情况:重试 */
continue;
}
}
static rt_uint16_t pipe_index = 0;
3 weeks ago
static rt_uint8_t drv_get_free_pipe_index(rt_bool_t is_ep0)
{
rt_uint8_t idx;
3 weeks ago
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++)
{
3 weeks ago
if (!(pipe_index & (1U << idx)))
{
3 weeks ago
pipe_index |= (1U << idx);
return idx;
}
}
return 0xff;
}
static void drv_free_pipe_index(rt_uint8_t index)
{
pipe_index &= ~(0x01 << index);
}
static rt_err_t drv_open_pipe(upipe_t pipe)
3 weeks ago
{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,
pipe->inst->address,
USB_OTG_SPEED_FULL,
pipe->ep.bmAttributes,
pipe->ep.wMaxPacketSize);
3 weeks ago
/* 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;
}
else
{
stm32_hhcd_fs.hc[pipe->pipe_index].toggle_out = 0;
}
return RT_EOK;
}
static rt_err_t drv_close_pipe(upipe_t pipe)
{
HAL_HCD_HC_Halt(&stm32_hhcd_fs, pipe->pipe_index);
drv_free_pipe_index(pipe->pipe_index);
return RT_EOK;
}
3 weeks ago
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,
3 weeks ago
drv_set_address,
};
static rt_err_t stm32_hcd_init(rt_device_t device)
{
HCD_HandleTypeDef *hhcd = (HCD_HandleTypeDef *)device->user_data;
3 weeks ago
// 确保 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;
3 weeks ago
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);
3 weeks ago
hhcd->Instance->GUSBCFG |= (1UL << 28);
#ifdef USBH_USING_CONTROLLABLE_POWER
rt_pin_mode(USBH_POWER_PIN, PIN_MODE_OUTPUT);
3 weeks ago
rt_pin_write(USBH_POWER_PIN, PIN_LOW); // 根据硬件确认极性
#endif
3 weeks ago
return RT_EOK;
}
3 weeks ago
/* 设备操作函数表 */
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;
uhcd_t uhcd = (uhcd_t)rt_malloc(sizeof(struct uhcd));
if (uhcd == RT_NULL)
{
rt_kprintf("uhcd malloc failed\r\n");
3 weeks ago
return -RT_ENOMEM;
}
rt_memset((void *)uhcd, 0, sizeof(struct uhcd));
3 weeks ago
/* 初始化父设备 */
uhcd->parent.type = RT_Device_Class_USBHost;
3 weeks ago
uhcd->parent.ops = &usbh_device_ops;
uhcd->parent.user_data = &stm32_hhcd_fs;
uhcd->ops = &_uhcd_ops;
uhcd->num_ports = OTG_FS_PORT;
stm32_hhcd_fs.pData = uhcd;
res = rt_device_register(&uhcd->parent, "usbh", RT_DEVICE_FLAG_DEACTIVATE);
if (res != RT_EOK)
{
rt_kprintf("register usb host failed res = %d\r\n", res);
3 weeks ago
rt_free(uhcd);
return -RT_ERROR;
}
3 weeks ago
rt_usb_host_init("usbh");
return RT_EOK;
}
INIT_DEVICE_EXPORT(stm_usbh_register);
3 weeks ago
#endif /* BSP_USING_USBHOST */