分类: LINUX
2012-02-18 12:41:36
S3C2440 有2 个USB 主机接口和1 个USB 设备接口, 本篇讲述USB 设备接口。
1 USB 的分类及主机接口和设备接口的区别
1.1USB2.0 按照速度分为以下三类High-speed USB2.0 :理论速度480Mbps ,对应之前的USB2.0 ;
Full-speed USB2.0 :理论速度12Mbps ,也就是过去的USB1.1 ;
Low-speed USB2.0 :理论速度1.5Mbps ,这个一般用于鼠标、键盘等对速度要求不高的外部设备。
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( "
}
if(usbdIntpnd&RESUME_INT)
{
rUSB_INT_REG=RESUME_INT;
DbgPrintf("
}
if(usbdIntpnd&RESET_INT) // 收到复位信号, 重新配置USB 设备配置
{
DbgPrintf( "
// 中断标记清零
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();
}