目录
1. 中断使能位
2. USB 控制寄存器(USB_CTRL)
3. USB 设备物理端口控制寄存器(UDEV_CTRL)
4. 初始化端点0
5. 初始化其他端点
6. 初始化地址
7. 启动USB设备
8. 允许USB端口
9. 初始化中断
在初始化前需要先关闭USB中断。
IE_USB = 0;
该位位于扩展中断使能寄存器(IE_EX)中
设置USB为设备模式,即
USB_CTRL = 0;
位7为0表示设备模式, 其他位清零。
设置位7位1,禁止DP/DM下拉电阻;位2为0,选择12Mbps全速模式。
UDEV_CTRL = bUD_PD_DIS;
CH549/CH548一共支持5个双向端点。除了端点0是发送和接收共用数据缓冲区,其他4个端点需要单独空间,而且也是最大支持64字节。而端点1~3支持DMA和双数据缓冲区(单向时),端点4不支持双数据缓冲区,而且它的缓冲区在端点0缓冲区的后面。
端点 0 是默认端点,必须是控制传输,发送和接收共用一个 64 字节数据缓冲区,支持DMA传输。
#define EP0_IN_MEM_SIZE (64)
#define EP0_OUT_MEM_SIZE (64)
#define USBEP_BUFFER_ADDR_START 0x0000
端点的大小最大64字节,可以小于64字节,当小于64字节时需要多留2个字节。比如设置端点0的大小为32个字节,那么分配的buffer大小要为32+2 = 34字节。不过当端点为双向时,大小必须为64字节,对于端点0,如果要用到端点4,大小必须为64字节。
#ifdef __SDCC
EXTERN xdata uint8_t _at_ (USBEP_BUFFER_ADDR_START) usbEp0Buffer[EP0_IN_MEM_SIZE + EP4_OUT_MEM_SIZE + EP4_IN_MEM_SIZE];
#else
EXTERN xdata uint8_t usbEp0Buffer[EP0_IN_MEM_SIZE + EP4_OUT_MEM_SIZE + EP4_IN_MEM_SIZ] _at_ (USBEP_BUFFER_ADDR_START);
#endif
另外,buffer的起始地址必须2字节对齐(偶地址)。
初始化端点0的DMA地址即可完成初始化
UEP0_DMA = (uint16_t)usbEp0Buffer;
根据实际的应用定义对应的端点,以端点1为例,假设端点1作为IN端点。
#define EP1_OUT_MEM_SIZE 0
#define EP1_IN_MEM_SIZE 4
定义端点1用到的缓存空间。
#if (EP1_OUT_MEM_SIZE > 0 || EP1_IN_MEM_SIZE > 0)
#define USBEP1_BUFFER_ADDR_START (USBEP_BUFFER_ADDR_START + sizeof(usbEp0Buffer))
#ifdef __SDCC
EXTERN xdata uint8_t _at_ USBEP1_BUFFER_ADDR_START usbEp1Buffer[EP1_OUT_MEM_SIZE + EP1_IN_MEM_SIZE];
#else
EXTERN xdata uint8_t usbEp1Buffer[EP1_OUT_MEM_SIZE + EP1_IN_MEM_SIZE] _at_ USBEP1_BUFFER_ADDR_START;
#endif
#endif
将usbEp1Buffer的起始地址定义在端点0的缓冲区的后面(端点0和端点4的缓冲区大小)。
而端点1的缓存空间分OUT和IN2个空间,前面是OUT空间,后面是IN空间(如果只是IN,则OUT空间为0)。
#if (EP1_OUT_MEM_SIZE > 0 || EP1_IN_MEM_SIZE > 0)
UEP1_DMA = (uint16_t)usbEp1Buffer;
UEP1_CTRL = 0;
#if(EP1_OUT_MEM_SIZE > 0)
UEP1_CTRL |= bUEP_AUTO_TOG | UEP_R_RES_ACK;
UEP4_1_MOD |= bUEP1_RX_EN; //OUT Enable
#endif
#if(EP1_IN_MEM_SIZE > 0)
UEP1_CTRL |= bUEP_AUTO_TOG | UEP_T_RES_NAK;
UEP4_1_MOD |= bUEP1_TX_EN; //IN Enable
#endif
UEP1_T_LEN = 0;
#endif
同样,端点1也支持DMA,初始化DMA地址,然后根据IN还是OUT初始化UEP1_CTRL和UEP4_1_MOD,设置bUEP_AUTO_TOG的目的是让芯片在发送成功或者接收成功后自动翻转相应的同步触发位(不理解为什么端点0没有这样设置),最后发送长度清空,即将UEP1_T_LEN清0。
端点2和端点3的初始化与端点1类似。而端点4比较特殊,它的收发缓存区的地址在端点0后面,这里就只定义一个指针
#if(EP4_OUT_MEM_SIZE > 0 || EP4_IN_MEM_SIZE > 0)
EXTERN xdata uint8_t *usbEp4Buffer;
#endif
然后在初始化这个指针指向usbEp0Buffer中端点4部分的缓冲区即可。
#if (EP4_OUT_MEM_SIZE > 0 || EP4_IN_MEM_SIZE > 0)
usbEp4Buffer = usbEp0Buffer + EP0_IN_MEM_SIZE;
UEP4_CTRL = 0;
#if(EP4_OUT_MEM_SIZE > 0)
UEP4_CTRL |= bUEP_AUTO_TOG | UEP_R_RES_ACK;
UEP1_4_MOD |= bUEP4_RX_EN; //OUT Enable
#endif
#if(EP4_IN_MEM_SIZE > 0)
UEP4_CTRL |= bUEP_AUTO_TOG | UEP_T_RES_NAK;
UEP1_4_MOD |= bUEP4_TX_EN; //IN Enable
#endif
UEP4_T_LEN = 0;
#endif
注意,当端点(1 - 4)为双向时, OUT的大小必须为64字节。当使用端点4时,,端点0的缓冲区大小必须为64字节。而端点1-3为双向双缓冲区时,缓冲区大小必须是256字节
默认地址为0
USB_DEV_AD = 0x00;
USB_CTRL |= bUC_DEV_PU_EN | bUC_INT_BUSY | bUC_DMA_EN; // 启动USB设备及DMA,在中断期间中断标志未清除前自动返回NAK
bUC_DEV_PU_EN: 使能 USB 设备传输并且启用内部上拉电阻
bUC_INT_BUSY:自动应答忙 NAK
bUC_DMA_EN:使能 USB 的 DMA 和 DMA 中断
UDEV_CTRL |= bUD_PORT_EN; // 允许USB端口
bUD_PORT_EN:使能物理端口
USB_INT_FG = 0xFF; // 清中断标志
USB_INT_EN = bUIE_SUSPEND | bUIE_TRANSFER | bUIE_BUS_RST;
IE_USB = 1;