CMake构建CH58x项目,脱离eclipse使用Clion或者Vscode编写代码。
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.

651 lines
22 KiB

/********************************** (C) COPYRIGHT *******************************
* File Name : CH58x_usbhost.c
* Author : WCH
* Version : V1.2
* Date : 2021/11/17
* Description
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* SPDX-License-Identifier: Apache-2.0
*******************************************************************************/
#include "CH58x_common.h"
#if DISK_LIB_ENABLE
#include "CHRV3UFI.H"
#endif
uint8_t Usb2DevEndp0Size; // USB2设备的端点0的最大包尺寸
uint8_t FoundNewU2Dev;
_RootHubDev ThisUsb2Dev; //ROOT口
_DevOnHubPort DevOnU2HubPort[HUB_MAX_PORTS]; // 假定:不超过1个外部HUB,每个外部HUB不超过HUB_MAX_PORTS个端口(多了不管)
uint8_t *pU2HOST_RX_RAM_Addr;
uint8_t *pU2HOST_TX_RAM_Addr;
/*获取设备描述符*/
__attribute__((aligned(4))) const uint8_t SetupGetU2DevDescr[] = {USB_REQ_TYP_IN, USB_GET_DESCRIPTOR, 0x00,
USB_DESCR_TYP_DEVICE, 0x00, 0x00, sizeof(USB_DEV_DESCR), 0x00};
/*获取配置描述符*/
__attribute__((aligned(4))) const uint8_t SetupGetU2CfgDescr[] = {USB_REQ_TYP_IN, USB_GET_DESCRIPTOR, 0x00,
USB_DESCR_TYP_CONFIG, 0x00, 0x00, 0x04, 0x00};
/*设置USB地址*/
__attribute__((aligned(4))) const uint8_t SetupSetUsb2Addr[] = {USB_REQ_TYP_OUT, USB_SET_ADDRESS, USB_DEVICE_ADDR,
0x00, 0x00, 0x00, 0x00, 0x00};
/*设置USB配置*/
__attribute__((aligned(4))) const uint8_t SetupSetUsb2Config[] = {USB_REQ_TYP_OUT, USB_SET_CONFIGURATION,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/*设置USB接口配置*/
__attribute__((aligned(4))) const uint8_t SetupSetUsb2Interface[] = {USB_REQ_RECIP_INTERF, USB_SET_INTERFACE,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/*清除端点STALL*/
__attribute__((aligned(4))) const uint8_t SetupClrU2EndpStall[] = {USB_REQ_TYP_OUT | USB_REQ_RECIP_ENDP, USB_CLEAR_FEATURE,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
/*********************************************************************
* @fn DisableRootU2HubPort
*
* @brief ROOT-HUB端口,,
*
* @param none
*
* @return none
*/
void DisableRootU2HubPort(void)
{
#ifdef FOR_ROOT_UDISK_ONLY
CHRV3DiskStatus = DISK_DISCONNECT;
#endif
#ifndef DISK_BASE_BUF_LEN
ThisUsb2Dev.DeviceStatus = ROOT_DEV_DISCONNECT;
ThisUsb2Dev.DeviceAddress = 0x00;
#endif
}
/*********************************************************************
* @fn AnalyzeRootU2Hub
*
* @brief ROOT-HUB状态,ROOT-HUB端口的设备插拔事件
* ,DisableRootHubPort(),,,
*
* @param none
*
* @return ERR_SUCCESS为没有情况,ERR_USB_CONNECT为检测到新连接,ERR_USB_DISCON为检测到断开
*/
uint8_t AnalyzeRootU2Hub(void)
{
uint8_t s;
s = ERR_SUCCESS;
if(R8_USB2_MIS_ST & RB_UMS_DEV_ATTACH)
{ // 设备存在
#ifdef DISK_BASE_BUF_LEN
if(CHRV3DiskStatus == DISK_DISCONNECT
#else
if(ThisUsb2Dev.DeviceStatus == ROOT_DEV_DISCONNECT // 检测到有设备插入
#endif
|| (R8_U2HOST_CTRL & RB_UH_PORT_EN) == 0x00)
{ // 检测到有设备插入,但尚未允许,说明是刚插入
DisableRootU2HubPort(); // 关闭端口
#ifdef DISK_BASE_BUF_LEN
CHRV3DiskStatus = DISK_CONNECT;
#else
ThisUsb2Dev.DeviceSpeed = R8_USB2_MIS_ST & RB_UMS_DM_LEVEL ? 0 : 1;
ThisUsb2Dev.DeviceStatus = ROOT_DEV_CONNECTED; //置连接标志
#endif
PRINT("USB2 dev in\n");
s = ERR_USB_CONNECT;
}
}
#ifdef DISK_BASE_BUF_LEN
else if(CHRV3DiskStatus >= DISK_CONNECT)
{
#else
else if(ThisUsb2Dev.DeviceStatus >= ROOT_DEV_CONNECTED)
{ //检测到设备拔出
#endif
DisableRootU2HubPort(); // 关闭端口
PRINT("USB2 dev out\n");
if(s == ERR_SUCCESS)
s = ERR_USB_DISCON;
}
// R8_USB_INT_FG = RB_UIF_DETECT; // 清中断标志
return (s);
}
/*********************************************************************
* @fn SetHostUsb2Addr
*
* @brief USB主机当前操作的USB设备地址
*
* @param addr - USB设备地址
*
* @return none
*/
void SetHostUsb2Addr(uint8_t addr)
{
R8_USB2_DEV_AD = (R8_USB2_DEV_AD & RB_UDA_GP_BIT) | (addr & MASK_USB_ADDR);
}
/*********************************************************************
* @fn SetUsb2Speed
*
* @brief USB速度
*
* @param FullSpeed - USB速度
*
* @return none
*/
void SetUsb2Speed(uint8_t FullSpeed)
{
#ifndef DISK_BASE_BUF_LEN
if(FullSpeed) // 全速
{
R8_USB2_CTRL &= ~RB_UC_LOW_SPEED; // 全速
R8_U2H_SETUP &= ~RB_UH_PRE_PID_EN; // 禁止PRE PID
}
else
{
R8_USB2_CTRL |= RB_UC_LOW_SPEED; // 低速
}
#endif
(void)FullSpeed;
}
/*********************************************************************
* @fn ResetRootU2HubPort
*
* @brief ,线,,
*
* @param none
*
* @return none
*/
void ResetRootU2HubPort(void)
{
Usb2DevEndp0Size = DEFAULT_ENDP0_SIZE; //USB2设备的端点0的最大包尺寸
SetHostUsb2Addr(0x00);
R8_U2HOST_CTRL &= ~RB_UH_PORT_EN; // 关掉端口
SetUsb2Speed(1); // 默认为全速
R8_U2HOST_CTRL = (R8_U2HOST_CTRL & ~RB_UH_LOW_SPEED) | RB_UH_BUS_RESET; // 默认为全速,开始复位
mDelaymS(15); // 复位时间10mS到20mS
R8_U2HOST_CTRL = R8_U2HOST_CTRL & ~RB_UH_BUS_RESET; // 结束复位
mDelayuS(250);
R8_USB2_INT_FG = RB_UIF_DETECT; // 清中断标志
}
/*********************************************************************
* @fn EnableRootU2HubPort
*
* @brief 使ROOT-HUB端口,bUH_PORT_EN置1开启端口,
*
* @param none
*
* @return ERR_SUCCESS为检测到新连接,ERR_USB_DISCON为无连接
*/
uint8_t EnableRootU2HubPort(void)
{
#ifdef DISK_BASE_BUF_LEN
if(CHRV3DiskStatus < DISK_CONNECT)
CHRV3DiskStatus = DISK_CONNECT;
#else
if(ThisUsb2Dev.DeviceStatus < ROOT_DEV_CONNECTED)
ThisUsb2Dev.DeviceStatus = ROOT_DEV_CONNECTED;
#endif
if(R8_USB2_MIS_ST & RB_UMS_DEV_ATTACH)
{ // 有设备
#ifndef DISK_BASE_BUF_LEN
if((R8_U2HOST_CTRL & RB_UH_PORT_EN) == 0x00)
{ // 尚未使能
ThisUsb2Dev.DeviceSpeed = (R8_USB2_MIS_ST & RB_UMS_DM_LEVEL) ? 0 : 1;
if(ThisUsb2Dev.DeviceSpeed == 0)
R8_U2HOST_CTRL |= RB_UH_LOW_SPEED; // 低速
}
#endif
R8_U2HOST_CTRL |= RB_UH_PORT_EN; //使能HUB端口
return (ERR_SUCCESS);
}
return (ERR_USB_DISCON);
}
#ifndef DISK_BASE_BUF_LEN
/*********************************************************************
* @fn SelectU2HubPort
*
* @brief HUB口
*
* @param HubPortIndex - ROOT-HUB端口的外部HUB的指定端口
*
* @return None
*/
void SelectU2HubPort(uint8_t HubPortIndex)
{
if(HubPortIndex) // 选择操作指定的ROOT-HUB端口的外部HUB的指定端口
{
SetHostUsb2Addr(DevOnU2HubPort[HubPortIndex - 1].DeviceAddress); // 设置USB主机当前操作的USB设备地址
SetUsb2Speed(DevOnU2HubPort[HubPortIndex - 1].DeviceSpeed); // 设置当前USB速度
if(DevOnU2HubPort[HubPortIndex - 1].DeviceSpeed == 0) // 通过外部HUB与低速USB设备通讯需要前置ID
{
R8_U2EP1_CTRL |= RB_UH_PRE_PID_EN; // 启用PRE PID
mDelayuS(100);
}
}
else
{
SetHostUsb2Addr(ThisUsb2Dev.DeviceAddress); // 设置USB主机当前操作的USB设备地址
SetUsb2Speed(ThisUsb2Dev.DeviceSpeed); // 设置USB设备的速度
}
}
#endif
/*********************************************************************
* @fn WaitUSB2_Interrupt
*
* @brief USB中断
*
* @param none
*
* @return ERR_SUCCESS ,ERR_USB_UNKNOWN
*/
uint8_t WaitUSB2_Interrupt(void)
{
uint16_t i;
for(i = WAIT_USB_TOUT_200US; i != 0 && (R8_USB2_INT_FG & RB_UIF_TRANSFER) == 0; i--)
{
;
}
return ((R8_USB2_INT_FG & RB_UIF_TRANSFER) ? ERR_SUCCESS : ERR_USB_UNKNOWN);
}
/*********************************************************************
* @fn USB2HostTransact
*
* @brief ,/PID令牌,,20uS为单位的NAK重试总时间(0,0xFFFF),0,/
* ,,,
*
* @param endp_pid - , 4token_pid令牌, 4
* @param tog -
* @param timeout -
*
* @return ERR_USB_UNKNOWN
* ERR_USB_DISCON
* ERR_USB_CONNECT
* ERR_SUCCESS
*/
uint8_t USB2HostTransact(uint8_t endp_pid, uint8_t tog, uint32_t timeout)
{
uint8_t TransRetry;
uint8_t s, r;
uint16_t i;
R8_U2H_RX_CTRL = R8_U2H_TX_CTRL = tog;
TransRetry = 0;
do
{
R8_U2H_EP_PID = endp_pid; // 指定令牌PID和目的端点号
R8_USB2_INT_FG = RB_UIF_TRANSFER;
for(i = WAIT_USB_TOUT_200US; i != 0 && (R8_USB2_INT_FG & RB_UIF_TRANSFER) == 0; i--)
;
R8_U2H_EP_PID = 0x00; // 停止USB传输
if((R8_USB2_INT_FG & RB_UIF_TRANSFER) == 0)
{
return (ERR_USB_UNKNOWN);
}
if(R8_USB2_INT_FG & RB_UIF_DETECT)
{ // USB设备插拔事件
// mDelayuS( 200 ); // 等待传输完成
R8_USB2_INT_FG = RB_UIF_DETECT;
s = AnalyzeRootU2Hub(); // 分析ROOT-U2HUB状态
if(s == ERR_USB_CONNECT)
FoundNewU2Dev = 1;
#ifdef DISK_BASE_BUF_LEN
if(CHRV3DiskStatus == DISK_DISCONNECT)
{
return (ERR_USB_DISCON);
} // USB设备断开事件
if(CHRV3DiskStatus == DISK_CONNECT)
{
return (ERR_USB_CONNECT);
} // USB设备连接事件
#else
if(ThisUsb2Dev.DeviceStatus == ROOT_DEV_DISCONNECT)
{
return (ERR_USB_DISCON);
} // USB设备断开事件
if(ThisUsb2Dev.DeviceStatus == ROOT_DEV_CONNECTED)
{
return (ERR_USB_CONNECT);
} // USB设备连接事件
#endif
mDelayuS(200); // 等待传输完成
}
if(R8_USB2_INT_FG & RB_UIF_TRANSFER) // 传输完成事件
{
if(R8_USB2_INT_ST & RB_UIS_TOG_OK)
{
return (ERR_SUCCESS);
}
r = R8_USB2_INT_ST & MASK_UIS_H_RES; // USB设备应答状态
if(r == USB_PID_STALL)
{
return (r | ERR_USB_TRANSFER);
}
if(r == USB_PID_NAK)
{
if(timeout == 0)
{
return (r | ERR_USB_TRANSFER);
}
if(timeout < 0xFFFFFFFF)
timeout--;
--TransRetry;
}
else
switch(endp_pid >> 4)
{
case USB_PID_SETUP:
case USB_PID_OUT:
if(r)
{
return (r | ERR_USB_TRANSFER);
} // 不是超时/出错,意外应答
break; // 超时重试
case USB_PID_IN:
if(r == USB_PID_DATA0 || r == USB_PID_DATA1)
{ // 不同步则需丢弃后重试
} // 不同步重试
else if(r)
{
return (r | ERR_USB_TRANSFER);
} // 不是超时/出错,意外应答
break; // 超时重试
default:
return (ERR_USB_UNKNOWN); // 不可能的情况
break;
}
}
else
{ // 其它中断,不应该发生的情况
R8_USB2_INT_FG = 0xFF; /* 清中断标志 */
}
mDelayuS(15);
} while(++TransRetry < 3);
return (ERR_USB_TRANSFER); // 应答超时
}
/*********************************************************************
* @fn U2HostCtrlTransfer
*
* @brief ,8pSetupReq中,DataBuf为可选的收发缓冲区
*
* @param DataBuf - ,DataBuf需指向有效缓冲区用于存放后续数据
* @param RetLen - RetLen指向的字节变量中
*
* @return ERR_USB_BUF_OVER IN状态阶段出错
* ERR_SUCCESS
*/
uint8_t U2HostCtrlTransfer(uint8_t *DataBuf, uint8_t *RetLen)
{
uint16_t RemLen = 0;
uint8_t s, RxLen, RxCnt, TxCnt;
uint8_t *pBuf;
uint8_t *pLen;
pBuf = DataBuf;
pLen = RetLen;
mDelayuS(200);
if(pLen)
*pLen = 0; // 实际成功收发的总长度
R8_U2H_TX_LEN = sizeof(USB_SETUP_REQ);
s = USB2HostTransact(USB_PID_SETUP << 4 | 0x00, 0x00, 200000 / 20); // SETUP阶段,200mS超时
if(s != ERR_SUCCESS)
return (s);
R8_U2H_RX_CTRL = R8_U2H_TX_CTRL = RB_UH_R_TOG | RB_UH_R_AUTO_TOG | RB_UH_T_TOG | RB_UH_T_AUTO_TOG; // 默认DATA1
R8_U2H_TX_LEN = 0x01; // 默认无数据故状态阶段为IN
RemLen = pU2SetupReq->wLength;
if(RemLen && pBuf) // 需要收发数据
{
if(pU2SetupReq->bRequestType & USB_REQ_TYP_IN) // 收
{
while(RemLen)
{
mDelayuS(200);
s = USB2HostTransact(USB_PID_IN << 4 | 0x00, R8_U2H_RX_CTRL, 200000 / 20); // IN数据
if(s != ERR_SUCCESS)
return (s);
RxLen = R8_USB2_RX_LEN < RemLen ? R8_USB2_RX_LEN : RemLen;
RemLen -= RxLen;
if(pLen)
*pLen += RxLen; // 实际成功收发的总长度
for(RxCnt = 0; RxCnt != RxLen; RxCnt++)
{
*pBuf = pU2HOST_RX_RAM_Addr[RxCnt];
pBuf++;
}
if(R8_USB2_RX_LEN == 0 || (R8_USB2_RX_LEN & (Usb2DevEndp0Size - 1)))
break; // 短包
}
R8_U2H_TX_LEN = 0x00; // 状态阶段为OUT
}
else // 发
{
while(RemLen)
{
mDelayuS(200);
R8_U2H_TX_LEN = RemLen >= Usb2DevEndp0Size ? Usb2DevEndp0Size : RemLen;
for(TxCnt = 0; TxCnt != R8_U2H_TX_LEN; TxCnt++)
{
pU2HOST_TX_RAM_Addr[TxCnt] = *pBuf;
pBuf++;
}
s = USB2HostTransact(USB_PID_OUT << 4 | 0x00, R8_U2H_TX_CTRL, 200000 / 20); // OUT数据
if(s != ERR_SUCCESS)
return (s);
RemLen -= R8_U2H_TX_LEN;
if(pLen)
*pLen += R8_U2H_TX_LEN; // 实际成功收发的总长度
}
// R8_U2H_TX_LEN = 0x01; // 状态阶段为IN
}
}
mDelayuS(200);
s = USB2HostTransact((R8_U2H_TX_LEN ? USB_PID_IN << 4 | 0x00 : USB_PID_OUT << 4 | 0x00), RB_UH_R_TOG | RB_UH_T_TOG, 200000 / 20); // STATUS阶段
if(s != ERR_SUCCESS)
return (s);
if(R8_U2H_TX_LEN == 0)
return (ERR_SUCCESS); // 状态OUT
if(R8_USB2_RX_LEN == 0)
return (ERR_SUCCESS); // 状态IN,检查IN状态返回数据长度
return (ERR_USB_BUF_OVER); // IN状态阶段错误
}
/*********************************************************************
* @fn CopyU2SetupReqPkg
*
* @brief
*
* @param pReqPkt -
*
* @return none
*/
void CopyU2SetupReqPkg(const uint8_t *pReqPkt) // 复制控制传输的请求包
{
uint8_t i;
for(i = 0; i != sizeof(USB_SETUP_REQ); i++)
{
((uint8_t *)pU2SetupReq)[i] = *pReqPkt;
pReqPkt++;
}
}
/*********************************************************************
* @fn CtrlGetU2DeviceDescr
*
* @brief , pHOST_TX_RAM_Addr
*
* @param none
*
* @return ERR_USB_BUF_OVER
* ERR_SUCCESS
*/
uint8_t CtrlGetU2DeviceDescr(void)
{
uint8_t s;
uint8_t len;
Usb2DevEndp0Size = DEFAULT_ENDP0_SIZE;
CopyU2SetupReqPkg((uint8_t *)SetupGetU2DevDescr);
s = U2HostCtrlTransfer(U2Com_Buffer, &len); // 执行控制传输
if(s != ERR_SUCCESS)
return (s);
Usb2DevEndp0Size = ((PUSB_DEV_DESCR)U2Com_Buffer)->bMaxPacketSize0; // 端点0最大包长度,这是简化处理,正常应该先获取前8字节后立即更新UsbDevEndp0Size再继续
if(len < ((PUSB_SETUP_REQ)SetupGetU2DevDescr)->wLength)
return (ERR_USB_BUF_OVER); // 描述符长度错误
return (ERR_SUCCESS);
}
/*********************************************************************
* @fn CtrlGetU2ConfigDescr
*
* @brief , pHOST_TX_RAM_Addr
*
* @param none
*
* @return ERR_USB_BUF_OVER
* ERR_SUCCESS
*/
uint8_t CtrlGetU2ConfigDescr(void)
{
uint8_t s;
uint8_t len;
CopyU2SetupReqPkg((uint8_t *)SetupGetU2CfgDescr);
s = U2HostCtrlTransfer(U2Com_Buffer, &len); // 执行控制传输
if(s != ERR_SUCCESS)
return (s);
if(len < ((PUSB_SETUP_REQ)SetupGetU2CfgDescr)->wLength)
return (ERR_USB_BUF_OVER); // 返回长度错误
len = ((PUSB_CFG_DESCR)U2Com_Buffer)->wTotalLength;
CopyU2SetupReqPkg((uint8_t *)SetupGetU2CfgDescr);
pU2SetupReq->wLength = len; // 完整配置描述符的总长度
s = U2HostCtrlTransfer(U2Com_Buffer, &len); // 执行控制传输
if(s != ERR_SUCCESS)
return (s);
#ifdef DISK_BASE_BUF_LEN
if(len > 64)
len = 64;
memcpy(TxBuffer, U2Com_Buffer, len); //U盘操作时,需要拷贝到TxBuffer
#endif
return (ERR_SUCCESS);
}
/*********************************************************************
* @fn CtrlSetUsb2Address
*
* @brief USB设备地址
*
* @param addr -
*
* @return ERR_SUCCESS
*/
uint8_t CtrlSetUsb2Address(uint8_t addr)
{
uint8_t s;
CopyU2SetupReqPkg((uint8_t *)SetupSetUsb2Addr);
pU2SetupReq->wValue = addr; // USB设备地址
s = U2HostCtrlTransfer(NULL, NULL); // 执行控制传输
if(s != ERR_SUCCESS)
return (s);
SetHostUsb2Addr(addr); // 设置USB主机当前操作的USB设备地址
mDelaymS(10); // 等待USB设备完成操作
return (ERR_SUCCESS);
}
/*********************************************************************
* @fn CtrlSetUsb2Config
*
* @brief USB设备配置
*
* @param cfg -
*
* @return ERR_SUCCESS
*/
uint8_t CtrlSetUsb2Config(uint8_t cfg)
{
CopyU2SetupReqPkg((uint8_t *)SetupSetUsb2Config);
pU2SetupReq->wValue = cfg; // USB设备配置
return (U2HostCtrlTransfer(NULL, NULL)); // 执行控制传输
}
/*********************************************************************
* @fn CtrlClearU2EndpStall
*
* @brief STALL
*
* @param endp -
*
* @return ERR_SUCCESS
*/
uint8_t CtrlClearU2EndpStall(uint8_t endp)
{
CopyU2SetupReqPkg((uint8_t *)SetupClrU2EndpStall); // 清除端点的错误
pU2SetupReq->wIndex = endp; // 端点地址
return (U2HostCtrlTransfer(NULL, NULL)); // 执行控制传输
}
/*********************************************************************
* @fn CtrlSetUsb2Intercace
*
* @brief USB设备接口
*
* @param cfg -
*
* @return ERR_SUCCESS
*/
uint8_t CtrlSetUsb2Intercace(uint8_t cfg)
{
CopyU2SetupReqPkg((uint8_t *)SetupSetUsb2Interface);
pU2SetupReq->wValue = cfg; // USB设备配置
return (U2HostCtrlTransfer(NULL, NULL)); // 执行控制传输
}
/*********************************************************************
* @fn USB2_HostInit
*
* @brief USB主机功能初始化
*
* @param none
*
* @return none
*/
void USB2_HostInit(void)
{
R8_USB2_CTRL = RB_UC_HOST_MODE;
R8_U2HOST_CTRL = 0;
R8_USB2_DEV_AD = 0x00;
R8_U2H_EP_MOD = RB_UH_EP_TX_EN | RB_UH_EP_RX_EN;
R16_U2H_RX_DMA = (uint16_t)(uint32_t)pU2HOST_RX_RAM_Addr;
R16_U2H_TX_DMA = (uint16_t)(uint32_t)pU2HOST_TX_RAM_Addr;
R8_U2H_RX_CTRL = 0x00;
R8_U2H_TX_CTRL = 0x00;
R8_USB2_CTRL = RB_UC_HOST_MODE | RB_UC_INT_BUSY | RB_UC_DMA_EN;
R8_U2H_SETUP = RB_UH_SOF_EN;
R8_USB2_INT_FG = 0xFF;
DisableRootU2HubPort();
R8_USB2_INT_EN = RB_UIE_TRANSFER | RB_UIE_DETECT;
FoundNewU2Dev = 0;
}