历史上的今天
返回首页

历史上的今天

今天是:2025年10月12日(星期日)

正在发生

2022年10月12日 | S3C2440 USB 设备控制器

2022-10-12 来源:csdn

s3c2440 soc集成了一个usb1.1设备控制器,可以进行全速/低速的控制,中断与批量传输。除了端点0,具有四个端点,每个端点都可以作为中断与批量的端点,每个端点具有128 byte的FIFO,所以端点最大packet可以设置成128byte。并且支持DMA传输。任何一种设备控制器对于软件来说都是一组寄存器:数据,状态,控制。usb 设备控制器也不例外。设置好相应的控制寄存器,并且在数据来时读取数据寄存器,需要发送数据的时候将数据写入输出寄存器。而这种数据的通信建立在对状态寄存器的读取上,往往还会有中断与DMA的操作。s3c2440 usb设备控制器的寄存器分为以下几组:


(1):电源管理寄存器

        PWR_REG 负责USB设备挂起等电源设置

(2):地址寄存器

        存储USB设备的地址,当主机枚举设备设备的时候设置

(3):中断控制寄存器

        EP_INT_REG    端点中断状态寄存器,每当一个端点事件发生的时候,相应的位就会置1

        USB_INT_REG   设备中断状态寄存器,主要有三个中断:唤醒,复位,挂起

        EP_INT_EN_REG  端点中断使能寄存器

        EP_INT_EN_REG  设备中断使能寄存器

(4):编号寄存器


因为USB 设备控制器有五个端点,并且五个端点寄存器大同小异,所以硬件设计上使用了编号寄存器:名字相同但物理寄存器不同。有一个INDEX_REG寄存器,它里面的值指示了具体的哪组物理寄存器。这样的寄存器有七个分别是:

        MAXP_REG: 端点最大信息包大小

        IN_CSR1_REG

        IN_CSR2_REG

        OUT_CSR1_REG

        OUT_CSR2_REG

        OUT_FIFO_CNT1_REG

        OUT_FIFO_CNT2_REG

(5):FIFO寄存器

        EPO_FIFO_REG

        EP1_FIFO_REG

        EP2_FIFO_REG

        EP3_FIFO_REG

        EP4_FIFO_REG

(6):DMA寄存器

        端点1~4,每个端点六个,用于设置端点的DMA传输。


USB设备控制器处理了大部分的USB传输细节,并产生相应的中断。所以对USB设备控制器的编程,最关键的部分就是中断处理的部分。比如端点每收到一个token以及后面的数据包,就会产生相应的中断。软件只需要在中断处理程序中读取数据,并且清除中断标志。USB设备控制器就会自动发送应答包。现在网上比较流行的操作s3c2440 usb 设备控制器的程序就是移植到u-boot里面的usb下载程序。因为在u-boot的环境下所以调试起来没有在裸机上来的方便,所以我将这个程序移植到了裸机上,编译环境arm-linux-gcc。下面大体介绍以下这个程序的流程:


这个程序主要是完成了USB设备的枚举,与批量OUT传输,并且开启了DMA,OUT传输用的端点是端点3。这个程序首先从init_usb_slave() 开始:这个函数主要是设置usb slave的引脚以及控制寄存器,设置中断处理程序的入口,以及开启中断。


void usb_init_slave(void)

{

        struct s3c24x0_gpio * const gpioregs = s3c24x0_get_base_gpio();

        char *mode;

 

        Delay(10);

 

        Usb_Isr_Init();  

      //设置中断处理程序的入口,需要两个中断USBD与DMA2,USBD用于处理USB事务,DMA2用于处理DMA传输

         writel((readl(&gpioregs->MISCCR) & ~((1<<3) | (1<<13))), &gpioregs->MISCCR);

// USBD is selected instead of USBH1 

// USB port 1 is enabled.

//

//  USBD should be initialized first of all.

//

        isUsbdSetConfiguration=0;

 

        UsbdMain(); //主要配置函数

        Delay(10);

 

        writel((readl(&gpioregs->GPCDAT) | (1<<5)), &gpioregs->GPCDAT);

        //这个操作和Mini2440开发板有关,在USB 设备的信号线上D+上接上了一个GPC5的一个上拉电阻,当GPC5输出高电平的时候,主机的集线器才能检测到设备,从而给复位信号

 

 /* enable USB Device, thisway.diy */

#if USBDMA

        mode="DMA";   

#else

        mode="Int";

#endif

        download_run=0; //The default menu is the Download & Run mode.

        printk("USB slave is enable!n");

        //printk是我自己编写的打印函数

}

在配置完设备后,给GPC5一个高电平,主机就开始枚举设备的过程了。能不能开始这个过程关键是看设备是否配置正确。这就是要看UsbMain()这个函数了。他在usbmain.c中,如下:

void UsbdMain(void)

{

    InitDescriptorTable();

    ConfigUsbd(); 

    PrepareEp1Fifo(); 

}


这个函数挺简单,但是调用了三个函数可不简单。第一个就是初始化一些USB描述符,比如设备描述符,配置描述符等,在usb控制传输的时候返回给设备。这个函数在usbsetup.c中。PrepareEp1Fifo()是配置端点1的,这里没有用到。关键的是ConfigUsbd()函数,这个函数是最主要的配置函数。在usblib.c中:

void ConfigUsbd(void)

{

        struct s3c24x0_interrupt * intregs = s3c24x0_get_base_interrupt();

        ReconfigUsbd();

        writel((readl(&intregs->INTMSK) & ~(BIT_USBD)), &intregs->INTMSK);

}


这个函数是个封装函数,第一次配置调用他,并且开启中断。在重置USB的过程中调用的是ReconfigUsbd(),这个函数也在usblib.c中:

void ReconfigUsbd(void)

{

// *** End point information ***

//   EP0: control

//   EP1: bulk in end point

//   EP2: not used

//   EP3: bulk out end point

//   EP4: not used

struct s3c24x0_usb_device * const usbdevregs = s3c24x0_get_base_usb_device();   

 

writeb(PWR_REG_DEFAULT_VALUE, &usbdevregs->PWR_REG); //disable suspend mode

writeb(0, &usbdevregs->INDEX_REG); 

writeb(FIFO_SIZE_8, &usbdevregs->MAXP_REG); //EP0 max packit size = 8 

writeb((EP0_SERVICED_OUT_PKT_RDY | EP0_SERVICED_SETUP_END), & usbdevregs->EP0_CSR_IN_CSR1_REG); //EP0:clear OUT_PKT_RDY & SETUP_END

writeb(1, &usbdevregs->INDEX_REG); 

 

#if (EP1_PKT_SIZE==32)

writeb(FIFO_SIZE_32, &usbdevregs->MAXP_REG); //EP1:max packit size = 32

#else

writeb(FIFO_SIZE_64, &usbdevregs->MAXP_REG); //EP1:max packit size = 64

#endif

writeb((EPI_FIFO_FLUSH | EPI_CDT), &usbdevregs->EP0_CSR_IN_CSR1_REG); 

writeb((EPI_MODE_IN | EPI_IN_DMA_INT_MASK | EPI_BULK), &usbdevregs->IN_CSR2_REG);  //IN mode, IN_DMA_INT=masked    

writeb(EPO_CDT, &usbdevregs->OUT_CSR1_REG); 

writeb((EPO_BULK | EPO_OUT_DMA_INT_MASK), &usbdevregs->OUT_CSR2_REG); 

 

writeb(2, &usbdevregs->INDEX_REG); 

writeb(FIFO_SIZE_64, &usbdevregs->MAXP_REG); //EP2:max packit size = 64

writeb((EPI_FIFO_FLUSH | EPI_CDT | EPI_BULK), &usbdevregs->EP0_CSR_IN_CSR1_REG); 

writeb((EPI_MODE_IN | EPI_IN_DMA_INT_MASK), &usbdevregs->IN_CSR2_REG);  //IN mode, IN_DMA_INT=masked    

writeb(EPO_CDT, &usbdevregs->OUT_CSR1_REG); 

writeb((EPO_BULK | EPO_OUT_DMA_INT_MASK), &usbdevregs->OUT_CSR2_REG); 

 

writeb(3, &usbdevregs->INDEX_REG); 

    #if (EP3_PKT_SIZE==32)

writeb(FIFO_SIZE_32, &usbdevregs->MAXP_REG); //EP3:max packit size = 32

    #else

writeb(FIFO_SIZE_64, &usbdevregs->MAXP_REG); //EP3:max packit size = 64

    #endif

writeb((EPI_FIFO_FLUSH | EPI_CDT | EPI_BULK), &usbdevregs->EP0_CSR_IN_CSR1_REG);

writeb((EPI_MODE_OUT | EPI_IN_DMA_INT_MASK), &usbdevregs->IN_CSR2_REG); //OUT mode, IN_DMA_INT=masked    

writeb(EPO_CDT, &usbdevregs->OUT_CSR1_REG); 

    //clear OUT_PKT_RDY, data_toggle_bit.

//The data toggle bit should be cleared when initialization.

writeb((EPO_BULK | EPO_OUT_DMA_INT_MASK), &usbdevregs->OUT_CSR2_REG); 

 

writeb(4, &usbdevregs->INDEX_REG); 

writeb(FIFO_SIZE_64, &usbdevregs->MAXP_REG); //EP4:max packit size = 64

writeb((EPI_FIFO_FLUSH | EPI_CDT | EPI_BULK), &usbdevregs->EP0_CSR_IN_CSR1_REG); 

writeb((EPI_MODE_OUT | EPI_IN_DMA_INT_MASK), &usbdevregs->IN_CSR2_REG); //OUT mode, IN_DMA_INT=masked    

writeb(EPO_CDT, &usbdevregs->OUT_CSR1_REG); 

    //clear OUT_PKT_RDY, data_toggle_bit.

//The data toggle bit should be cleared when initialization.

writeb((EPO_BULK | EPO_OUT_DMA_INT_MASK), &usbdevregs->OUT_CSR2_REG); 

    

writeb((EP0_INT | EP1_INT | EP2_INT | EP3_INT | EP4_INT), &usbdevregs->EP_INT_REG); 

writeb((RESET_INT | SUSPEND_INT | RESUME_INT), &usbdevregs->USB_INT_REG); 

    //Clear all usbd pending bits

   

writeb((EP0_INT | EP1_INT | EP3_INT), &usbdevregs->EP_INT_EN_REG); 

writeb(RESET_INT, &usbdevregs->USB_INT_EN_REG); 

        ep0State = EP0_STATE_INIT;

    

}


可以看出首先是操作电源管理寄存器关闭自动挂起功能,然后就是针对每个端点来配置,主要设置端点的最大信息包的大小,端点类型,传输方向。以及是否支持DMA。最主要的是端点0与端点3因为其他三个端点没有用到。最后清除所有的中断状态寄存器的标志。


usb 设备控制器最主要的部分就是中断处理程序,本程序中的USB中断处理程序是void IsrUsbd(void),在usbmain.c中:

void IsrUsbd(void)

{

    struct s3c24x0_usb_device * const usbdevregs = s3c24x0_get_base_usb_device();

    U8 usbdIntpnd,epIntpnd;

    U8 saveIndexReg = readb(&usbdevregs->INDEX_REG);

 

    usbdIntpnd = readb(&usbdevregs->USB_INT_REG);

    epIntpnd = readb(&usbdevregs->EP_INT_REG);

//    printk( "[INT:EP_I=%x,USBI=%x]",epIntpnd,usbdIntpnd );

    if(usbdIntpnd&SUSPEND_INT)

    {

writeb(SUSPEND_INT, &usbdevregs->USB_INT_REG);

    // printk( "    }

    if(usbdIntpnd&RESUME_INT)

    {

writeb(RESUME_INT, &usbdevregs->USB_INT_REG);

    // printk("    }

    if(usbdIntpnd&RESET_INT)

    {

    // printk( "   

    //ResetUsbd();

    ReconfigUsbd();

writeb(RESET_INT, &usbdevregs->USB_INT_REG); //RESET_INT should be cleared after ResetUsbd().   

        PrepareEp1Fifo(); 

    }

    //以上三个是USB设备中断,主要用到的是复位中断,当GPC5引脚为高时,USB 插入主机,就会产生这个中断

    if(epIntpnd&EP0_INT)

    {

writeb(EP0_INT, &usbdevregs->EP_INT_REG);

    Ep0Handler();

    }

    //对于每个端点中断都有不同的处理程序,这个是端点0的处理程序。在设备枚举的过程中使用。

    if(epIntpnd&EP1_INT)

    {

writeb(EP1_INT, &usbdevregs->EP_INT_REG);

    Ep1Handler();

    }

    

    if(epIntpnd&EP2_INT)

    {

writeb(EP2_INT, &usbdevregs->EP_INT_REG);

    // printk("<2:TBD]n");   //not implemented yet

    //Ep2Handler();

    }

 

    if(epIntpnd&EP3_INT)

    {

writeb(EP3_INT, &usbdevregs->EP_INT_REG);

printk("Ep3handern");

    Ep3Handler();

    }

 

    if(epIntpnd&EP4_INT)

    {

writeb(EP4_INT, &usbdevregs->EP_INT_REG);

  //  printk("<4:TBD]n");   //not implemented yet

    //Ep4Handler();

    }

 

    ClearPending_my((int)BIT_USBD);  

writeb(saveIndexReg, &usbdevregs->INDEX_REG);    

推荐阅读

史海拾趣

General Electric Company公司的发展小趣事
内部集成了频率补偿机制,确保在高频信号下电路的稳定性。
全智景(Allvision)公司的发展小趣事

随着技术的不断进步,全智景公司开始寻求跨界合作的机会,以拓展其技术的应用领域。公司与多家汽车制造商达成了合作协议,将其电子视觉技术应用于汽车自动驾驶系统。通过精准的图像识别和处理,全智景的技术帮助汽车实现了更高级别的自动驾驶功能,提升了行车安全性和驾驶体验。这一跨界合作不仅拓宽了全智景公司的业务范围,也为其带来了更多的商业机会。

Ecera Comtek Corp公司的发展小趣事

随着公司实力的不断增强,Ecera Comtek Corp公司开始寻求更广阔的发展空间。公司决定进军国际市场,拓展海外业务。然而,国际市场的竞争更加激烈,Ecera Comtek Corp公司面临着来自全球各地的强大竞争对手。为了应对这一挑战,Ecera Comtek Corp公司加强了与国际合作伙伴的联系,共同研发新产品,开拓新市场。同时,公司还加大了对海外市场的宣传力度,提高了品牌的知名度和美誉度。经过几年的努力,Ecera Comtek Corp公司的产品逐渐在国际市场上获得了认可,海外业务也取得了显著的进展。

Anderson Electronics Inc公司的发展小趣事

随着全球化趋势的加强,Anderson Electronics Inc公司开始寻求国际合作,与国外知名电子企业开展技术交流和合作研发。通过与国际先进技术的融合和创新,公司成功开发出了一系列具有国际竞争力的新产品。这些产品不仅在国内市场取得了成功,还远销海外,为公司带来了可观的利润和更广阔的发展空间。

Foxboro I C T Inc公司的发展小趣事

随着公司规模的扩大和产品线的丰富,Anderson Electronics Inc公司开始积极拓展市场。公司通过与各大电子产品零售商建立合作关系,将产品销往全国各地。同时,公司还加大了品牌宣传力度,通过广告、展会等多种渠道提升品牌知名度和影响力。在市场拓展的过程中,公司始终坚持质量第一的原则,以优质的产品和服务赢得了客户的信赖和支持。

Entegris公司的发展小趣事

在半导体材料领域,对纯度的要求越来越高。Entegris通过不断的技术创新,提升材料的纯度,以满足晶圆厂对材料的高要求。同时,随着制程工艺的步骤增多,控制污染的环节也随之增加,Entegris在微尘控制方面也面临着巨大的挑战。

问答坊 | AI 解惑

S3C2410 应用电路

好久没来这透个气了,今天用单面板画了个S3C2410应用电路S3C2410 Core + SD Card +RS232 + UDA1371 Audio + TFT4.3 Touch,其它资料以后我会完善.星期天把晒的单面板照片发上来.…

查看全部问答>

uclinux内核的打印信息怎样去掉?大侠帮忙~~~

uclinux内核的打印信息怎样去掉? 应该是打印信息重新定向,内核应该有配置的地方,可惜我没找到 不知哪位达人能帮忙指点下 再具体介绍下问题的由来:当驱动报错时,会在板子外接的lcd屏上显示报错信息, 这些信息应该是内核打印信息,我就是想 ...…

查看全部问答>

提供Freescale CodeWarrior 6.2破解

提供Freescale CodeWarrior 6.2破解,支持HC08全系列单片机,无代码限制 l联系lzgzyf@126.com    …

查看全部问答>

wince 上传文件到服务器

从网上看了一些  wince都不支持。 …

查看全部问答>

大家都来说上几句啊,,谢谢

大家在s3c2410,2413,2440的时候,memorey control 中 bank 是什么意思啊?然后 bank 和 外围芯片的片选(cs)有什么联系吗?刚刚入行,请各位老鸟们给予真诚的解答…

查看全部问答>

如何校准电子秤

请教各位网友,如何校准电子秤?…

查看全部问答>

TSP-Link—TSP控制基础

测试设置   对于这项测试,仪表通过TSP-Link连接,2602型仪表作为控制主机。这种测试没有使用触发模式,只有一个逐行执行的测试脚本。在一个可以使用TSP-Link的系统中,一定要有一个仪表(连接到通信总线如GPIB或Ethernet的单元)作为控制 ...…

查看全部问答>

【TI首届低功耗设计大赛】MSP430FR5969程序体验

刚拿到MSP430FR5969的时候匆匆忙忙的就编写了简单的程序,错过了板子自带的程序。 这几天重新刷回开箱程序。 这个代码包含:GPIO控制(LED,按键),ADC,中断,低功耗模式,UART通信,板载超级电容电压检测,FRAM特性展示等等应有尽有。 按照官 ...…

查看全部问答>

#以拆会友#ThinkPad笔记本硬盘拆解

本帖最后由 DavidZH 于 2015-8-9 20:05 编辑 绝对原装ThinkPad笔记本硬盘,使用的是西部数据,WD2500BEVS, 拆开看看! 内部谍照第一张, 那油光油光的可以当镜子了! 内部电路图:从拆出来的电路来看,主芯片只有三课,也很常见 特写主电路图 ...…

查看全部问答>

DSP CMD文件内存分配问题

请问TI  C2000 DSP在进行RAM仿真时,内存中Reserved部分,可以参加内存分配么,为什么我在配置CMD文件时,发现Reserved内存可以分配到PAGE1中,编译、调试都没问题,但如果将Reserved内存分配到PAGE0中时,编译没问题,但是无法load prog ...…

查看全部问答>