S3C2440 之USB 设备篇 S3C2440 有2 个USB 主机接口和1 个USB 设备接口, 本篇讲述USB 设备接口。 1 USB 的分类及主机接口和设备接口的区别 1.1USB2.0 按照速度分为以下三类High-speed USB2.0 :理论速度480Mbps ,对应之前的USB2.0 ;
1.2 低速USB 全速USB 硬件设备接口的区别USB 通过D-,D+ 信号的状态判断设备的插入,如下图所示,D+ 接上拉电阻为全速设备,D- 接下拉为低速设备。
1.3 MINI2440USB 设备接口的区别Mini2440 开发板只有一个USB 主机接口和一个USB 设备接口,均为USB 全速接口。Mini2440 USB 设备的D+ 是由GPC5 来控制的,如果GPC5 输出高电平,则D+ 上相当于通过上拉电阻接到+5V ,则设备启用;如果GPC5 输出低电平,则D+ 上相当于通过下拉电阻接到GND ,则设备禁用。
2 S3C2440USB 设备的固件枚举过程分析2.1 S3C2440 USB 设备的端点2440 有5 个端点,EP0 ,EP1 ,EP2 ,EP3 ,EP4, 。 EP0 是用于USB 设备枚举,传输方式为control 方式。EP1 到 EP4 用于数据传输。端点的传输方向有两种,IN 和OUT ,这个由 IN_CSR2_REG 来配置。 端点的传输方式,批量(bulk ),中断(interrupt )也是由 IN_CSR2_REG 来配置。
由上图看到,BIT6 用于配置是批量模式,BIT5 用于配置传输方向。
2.2 S3C2440 USB 程序分析 整个USB 枚举过程其实是很简单的,首先进行USB 时钟的初始化,设置为48MHz ;然后GPC5 使能,表示全速设备,然后设置USBD1 为USB 设备,禁止USB 挂起,这样调用 UsbdMain(); 进行必要的初始化,这样就准备完成了。 当我们把2440 的USB 口插入到电脑主机的时候,会产生USB 设备复位中断,我们在设备复位中断中进行一些初始化,整个枚举就进入到一个状态机中,一步一步直到枚举完成。
// 初始化USB 设备时钟 48MHZ ChangeUPllValue(0x38,2,2); // UCLK=48Mhz
// GPC5 使能, 输出为高电平, 表示全速设备 rGPCCON &= ~(3<<10); rGPCCON |= (1<<10); // output rGPCUP |= (1<<5); // pullup disable rGPCDAT |= (1<<5); // ourtput
rMISCCR=rMISCCR&~(1<<3); // USBD1 设置为设备( 不是主机) rMISCCR=rMISCCR&~(1<<13); // USBD1 设置为普通模式( 不是挂起模式) UsbdMain(); while(1) { delay(); }
我们看下函数UsbdMain 的定义 void UsbdMain(void) { InitDescriptorTable(); // 初始化设备描述符
ConfigUsbd(); // USB 配置
PrepareEp1Fifo(); // 端点1 初始化 }
我们看下函数ConfigUsbd void ConfigUsbd(void) { ReconfigUsbd(); // 重新配置USB
pISR_USBD =(unsigned)IsrUsbd; // 安装中断函数 ClearPending(BIT_USBD); // 清除USB 中断挂起标记 rINTMSK&=~(BIT_USBD); // 允许USB 中断 }
void ReconfigUsbd(void) { // *** End point information *** // EP0: control // EP1: bulk in end point // EP2: not used // EP3: bulk out end point // EP4: not used
// 禁止设备进入挂起模式( 正常模式) rPWR_REG=PWR_REG_DEFAULT_VALUE;
rINDEX_REG=0; //EP0 max packit size = 8 最大数据包 rMAXP_REG=FIFO_SIZE_8; //EP0:clear OUT_PKT_RDY & SETUP_END rEP0_CSR=EP0_SERVICED_OUT_PKT_RDY|EP0_SERVICED_SETUP_END;
rINDEX_REG=1; #if (EP1_PKT_SIZE==32) //EP1:max packit size = 32 rMAXP_REG=FIFO_SIZE_32; #else //EP1:max packit size = 64 rMAXP_REG=FIFO_SIZE_64; #endif
rIN_CSR1_REG=EPI_FIFO_FLUSH|EPI_CDT; //IN mode, IN_DMA_INT=masked, 端点方向为IN, 批量传输模式, 中断禁止. rIN_CSR2_REG=EPI_MODE_IN|EPI_IN_DMA_INT_MASK|EPI_BULK;
rOUT_CSR1_REG=EPO_CDT; rOUT_CSR2_REG=EPO_BULK|EPO_OUT_DMA_INT_MASK;
rINDEX_REG=2; //EP2:max packit size = 64 rMAXP_REG=FIFO_SIZE_64; rIN_CSR1_REG=EPI_FIFO_FLUSH|EPI_CDT|EPI_BULK; //IN mode, IN_DMA_INT=masked rIN_CSR2_REG=EPI_MODE_IN|EPI_IN_DMA_INT_MASK; rOUT_CSR1_REG=EPO_CDT; rOUT_CSR2_REG=EPO_BULK|EPO_OUT_DMA_INT_MASK;
rINDEX_REG=3; #if (EP3_PKT_SIZE==32) //EP3:max packit size = 32 rMAXP_REG=FIFO_SIZE_32; #else //EP3:max packit size = 64 rMAXP_REG=FIFO_SIZE_64; #endif //OUT mode, IN_DMA_INT=masked rIN_CSR1_REG=EPI_FIFO_FLUSH|EPI_CDT|EPI_BULK;
rIN_CSR2_REG=EPI_MODE_OUT|EPI_IN_DMA_INT_MASK; rOUT_CSR1_REG=EPO_CDT; //clear OUT_PKT_RDY, data_toggle_bit. //The data toggle bit should be cleared when initialization. rOUT_CSR2_REG=EPO_BULK|EPO_OUT_DMA_INT_MASK;
rINDEX_REG=4; rMAXP_REG=FIFO_SIZE_64; //EP4:max packit size = 64 rIN_CSR1_REG=EPI_FIFO_FLUSH|EPI_CDT|EPI_BULK; //OUT mode, IN_DMA_INT=masked rIN_CSR2_REG=EPI_MODE_OUT|EPI_IN_DMA_INT_MASK; //clear OUT_PKT_RDY, data_toggle_bit. rOUT_CSR1_REG=EPO_CDT;
//The data toggle bit should be cleared when initialization. rOUT_CSR2_REG=EPO_BULK|EPO_OUT_DMA_INT_MASK;
// 清除中断标记位 rEP_INT_REG=EP0_INT|EP1_INT|EP2_INT|EP3_INT|EP4_INT; //Clear all usbd pending bits rUSB_INT_REG=RESET_INT|SUSPEND_INT|RESUME_INT;
//EP0,1,3 & reset interrupt are enabled // 中断使能寄存器 rEP_INT_EN_REG=EP0_INT|EP1_INT|EP3_INT; // USB 复位中断使能 rUSB_INT_EN_REG=RESET_INT; // 端点0 状态设置为初始化 ep0State=EP0_STATE_INIT; }
void IsrUsbd(void) { U8 usbdIntpnd,epIntpnd; U8 saveIndexReg=rINDEX_REG; usbdIntpnd=rUSB_INT_REG; // 读取USB 中断寄存器 epIntpnd=rEP_INT_REG; // 读取断点中断寄存器 //DbgPrintf( "[INT:EP_I=%x,USBI=%x]",epIntpnd,usbIntpnd );
if(usbdIntpnd&SUSPEND_INT) { rUSB_INT_REG=SUSPEND_INT; DbgPrintf( "<SUS]"); } if(usbdIntpnd&RESUME_INT) { rUSB_INT_REG=RESUME_INT; DbgPrintf("<RSM]"); } if(usbdIntpnd&RESET_INT) // 收到复位信号, 重新配置USB 设备配置 { DbgPrintf( "<RST]");
// 中断标记清零 rUSB_INT_REG = RESET_INT; //RESET_INT should be cleared after ResetUsbd().
//ResetUsbd(); ReconfigUsbd();
Test(); //PrepareEp1Fifo();
}
if(epIntpnd&EP0_INT) { rEP_INT_REG=EP0_INT; Ep0Handler(); } if(epIntpnd&EP1_INT) { rEP_INT_REG=EP1_INT; Ep1Handler(); }
if(epIntpnd&EP2_INT) { rEP_INT_REG=EP2_INT; DbgPrintf("<2:TBD]"); //not implemented yet //Ep2Handler(); }
if(epIntpnd&EP3_INT) { rEP_INT_REG=EP3_INT; Ep3Handler(); }
if(epIntpnd&EP4_INT) { rEP_INT_REG=EP4_INT; DbgPrintf("<4:TBD]"); //not implemented yet //Ep4Handler(); }
ClearPending(BIT_USBD);
rINDEX_REG=saveIndexReg; }
void Test() { U8 in_csr1; rINDEX_REG=1; in_csr1=rIN_CSR1_REG; SET_EP1_IN_PKT_READY(); } |
|