CH549/CH548学习笔记9 - USB Device端点处理过程

目录

1. 端点读

2. 端点写

3. SETUP过程

3.1 预置NAK

3.2 处理SETUP数据

3.3 设置ACK

4. IN过程

5. OUT过程


端点处理最重要的是端点0的处理过程,注意端点0和端点4都不支持自动翻转同步标志位的功能。

1. 端点读

当主机OUT数据后,芯片会把数据放在对应端点的buffer中,所以读这些buffer就可以得到对应的数据。注意,双向buffer中的前半段是OUT Buffer。而有效数据长度共用一个寄存器USB_RX_LEN。

uint8_t usbReadBuf(uint8_t port, uint8_t* buf, uint8_t len)
{
    xdata uint8_t *pUsbBuf[] = 
    {
        usbEp0Buffer,
        #if(EP1_OUT_MEM_SIZE > 0)
        usbEp1Buffer,
        #else
        NULL,
        #endif
        #if(EP2_OUT_MEM_SIZE > 0)
        usbEp2Buffer,
        #else
        NULL,
        #endif
        #if(EP3_OUT_MEM_SIZE > 0)
        usbEp3Buffer,
        #else
        NULL,
        #endif
        #if(EP4_OUT_MEM_SIZE > 0)
        usbEp4Buffer,
        #else
        NULL,
        #endif
    };
    uint8_t length;
    if(port > USB_EP_MAX)
        return 0;
    if(len > USB_RX_LEN)
        length = USB_RX_LEN;
    if(pUsbBuf[port] != NULL)
    {
        memcpy(buf, pUsbBuf[port], length);
    }
    return length;
}

2. 端点写

将数据拷贝到对应端点的缓冲区,然后设置端点的发送长度寄存器UEPn_T_LEN,最后设置UEPn_CTRL寄存器使能发送。 

uint8_t usbWriteBuf(uint8_t port, uint8_t* buf, uint8_t len)
{
    uint8_t length = 0;
    
    switch(port)
    {
        case 0:
            length = (len > EP0_IN_MEM_SIZE) ? len : EP0_IN_MEM_SIZE;
            memcpy(usbEp0Buffer, buf, len);
            UEP0_T_LEN = length;
            UEP0_CTRL = (UEP0_CTRL & ~ MASK_UEP_T_RES) | UEP_T_RES_ACK;
            break;
        #if (EP1_IN_MEM_SIZE > 0)
        case 1:
            length = (len > EP1_IN_MEM_SIZE) ? len : EP1_IN_MEM_SIZE;
            memcpy(usbEp1Buffer + EP1_OUT_MEM_SIZE, buf, len);
            UEP1_T_LEN = length;
            UEP1_CTRL = (UEP1_CTRL & ~ MASK_UEP_T_RES) | UEP_T_RES_ACK;
            break;
        #endif
        #if (EP2_IN_MEM_SIZE > 0)
        case 2:
            length = (len > EP2_IN_MEM_SIZE) ? len : EP2_IN_MEM_SIZE;
            memcpy(usbEp2Buffer + EP2_OUT_MEM_SIZE, buf, len);
            UEP2_T_LEN = len;
            UEP2_CTRL = (UEP2_CTRL & ~ MASK_UEP_T_RES) | UEP_T_RES_ACK;
            break;
        #endif
        #if (EP3_IN_MEM_SIZE > 0)
        case 3:
            length = (len > EP3_IN_MEM_SIZE) ? len : EP3_IN_MEM_SIZE;
            memcpy(usbEp3Buffer + EP3_OUT_MEM_SIZE, buf, len);
            UEP3_T_LEN = length;
            UEP3_CTRL = (UEP3_CTRL & ~ MASK_UEP_T_RES) | UEP_T_RES_ACK;
            break;
        #endif
        #if (EP4_IN_MEM_SIZE > 0)
        case 4:
            length = (len > EP4_IN_MEM_SIZE) ? len : EP4IN_MEM_SIZE;
            memcpy(usbEp4Buffer + EP4_OUT_MEM_SIZE, buf, len);
            UEP4_T_LEN = length;
            UEP4_CTRL = (UEP4_CTRL & ~ MASK_UEP_T_RES) | UEP_T_RES_ACK;
            break;
        #endif
    }
    return length;
}

3. SETUP过程

对应中断处理case UIS_TOKEN_SETUP的情况。

3.1 预置NAK

UEP0_CTRL = UEP0_CTRL & (~MASK_UEP_T_RES )| UEP_T_RES_NAK;

设置NAK表示端点0正忙。

3.2 处理SETUP数据

这一步与其他芯片处理方式一样。

3.3 设置ACK

UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;

SETUP必定是DATA0,所以这里将CTRL设置为 DATA1,并恢复ACK状态。

完整的Setup处理过程如下:

case UIS_TOKEN_SETUP:
    if(ep != 0)
        break;
    if(USB_RX_LEN != (sizeof(gUsbReqInfo)))
    {
        UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL;//STALL
        break;
    }
    usbReadBuf(USB_EP0, (uint8_t *)(&gUsbReqInfo), sizeof(gUsbReqInfo));
    UEP0_CTRL = UEP0_CTRL & (~MASK_UEP_T_RES )| UEP_T_RES_NAK;
    //Setup处理过程
    UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK; //Default DATA1 and return ACK
    break;

4. IN过程

对应中断处理case UIS_TOKEN_IN的情况,这个过程分端点0和其他端点的情况。

端点0和端点4都不支持自动翻转同步标志位,所以要添加对应的翻转命令。端点0在数据大于0的情况下才翻转。

case UIS_TOKEN_IN:
    if(ep == 0)
    {
        if(gUsbReqInfo.wLength > 0)
            UEP0_CTRL ^= bUEP_T_TOG;
        //端点0 IN操作
    }
    else
    {
        void(*usbEpnIntUser[])(void) =
        {
            usbEp1InUsr,
            usbEp2InUsr,
            usbEp3InUsr,
            usbEp4InUsr,
        };
        if(ep == 4)
            UEP4_CTRL ^= bUEP_T_TOG;
        (*usbEpnIntUser[ep - 1])();
    }
    break;

5. OUT过程

对应中断处理case UIS_TOKEN_OUT的情况,和IN类似。

case UIS_TOKEN_OUT:
    if(ep == 0)
    {
        UEP0_CTRL ^= bUEP_R_TOG;
        //端点0 OUT处理过程
    }
    else
    {
        void(*usbEpnIntUser[])(void) =
        {
            usbEp1OutUsr,
            usbEp2OutUsr,
            usbEp3OutUsr,
            usbEp4OutUsr,
        };
        if(ep == 4)
            UEP4_CTRL ^= bUEP_R_TOG;
        (*usbEpnIntUser[ep - 1])();
    }
    break;

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值