S3C2440 USB 设备控制器(转)

【ARM学习笔记】三、S3C2440A的存储控制器及启动过程 存储控制器 S3C2440A是32位处理器,理论上拥有32根地址线,寻址空间0x00000000~0xFFFFFFFF,即4G 而实际上,S3C2440A只拥有27根地址线,实际物理寻址空间为0x00000000~0x07FFFFFF,即128MB 除了这27根地址线,S3C2440A还对外引出了8根片选信号线,这样组合起来就能达到1G的物理寻址空间,即0x00000000~0x 阅读详情

S3C2440 USB 设备控制器

        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的引脚以及控制寄存器,设置中断处理程序的入口,以及开启中断。

  1. void usb_init_slave(void)  
  2. {  
  3.         struct s3c24x0_gpio * const gpioregs = s3c24x0_get_base_gpio();  
  4.         char *mode;  
  5.   
  6.         Delay(10);  
  7.   
  8.         Usb_Isr_Init();    
  9.       //设置中断处理程序的入口,需要两个中断USBD与DMA2,USBD用于处理USB事务,DMA2用于处理DMA传输  
  10.          writel((readl(&gpioregs->MISCCR) & ~((1<<3) | (1<<13))), &gpioregs->MISCCR);  
  11. // USBD is selected instead of USBH1   
  12. // USB port 1 is enabled.  
  13. //  
  14. //  USBD should be initialized first of all.  
  15. //  
  16.         isUsbdSetConfiguration=0;  
  17.   
  18.         UsbdMain(); //主要配置函数  
  19.         Delay(10);  
  20.   
  21.         writel((readl(&gpioregs->GPCDAT) | (1<<5)), &gpioregs->GPCDAT);  
  22.         //这个操作和Mini2440开发板有关,在USB 设备的信号线上D+上接上了一个GPC5的一个上拉电阻,当GPC5输出高电平的时候,主机的集线器才能检测到设备,从而给复位信号  
  23.   
  24.  /* enable USB Device, thisway.diy */  
  25. #if USBDMA  
  26.         mode="DMA";     
  27. #else  
  28.         mode="Int";  
  29. #endif  
  30.         download_run=0; //The default menu is the Download & Run mode.  
  31.         printk("USB slave is enable!\n");  
  32.         //printk是我自己编写的打印函数  
  33. }  
        在配置完设备后,给GPC5一个高电平,主机就开始枚举设备的过程了。能不能开始这个过程关键是看设备是否配置正确。这就是要看UsbMain()这个函数了。他在usbmain.c中,如下:
  1. void UsbdMain(void)  
  2. {  
  3.     InitDescriptorTable();  
  4.     ConfigUsbd();   
  5.     PrepareEp1Fifo();   
  6. }  
        这个函数挺简单,但是调用了三个函数可不简单。第一个就是初始化一些USB描述符,比如设备描述符,配置描述符等,在usb控制传输的时候返回给设备。这个函数在usbsetup.c中。PrepareEp1Fifo()是配置端点1的,这里没有用到。关键的是ConfigUsbd()函数,这个函数是最主要的配置函数。在usblib.c中:
  1. void ConfigUsbd(void)  
  2. {  
  3.         struct s3c24x0_interrupt * intregs = s3c24x0_get_base_interrupt();  
  4.         ReconfigUsbd();  
  5.         writel((readl(&intregs->INTMSK) & ~(BIT_USBD)), &intregs->INTMSK);  
  6. }  
        这个函数是个封装函数,第一次配置调用他,并且开启中断。在重置USB的过程中调用的是ReconfigUsbd(),这个函数也在usblib.c中:
  1. void ReconfigUsbd(void)  
  2. {  
  3. // *** End point information ***  
  4. //   EP0: control  
  5. //   EP1: bulk in end point  
  6. //   EP2: not used  
  7. //   EP3: bulk out end point  
  8. //   EP4: not used  
  9.     struct s3c24x0_usb_device * const usbdevregs    = s3c24x0_get_base_usb_device();     
  10.    
  11.     writeb(PWR_REG_DEFAULT_VALUE, &usbdevregs->PWR_REG); //disable suspend mode  
  12.     writeb(0, &usbdevregs->INDEX_REG);   
  13.     writeb(FIFO_SIZE_8, &usbdevregs->MAXP_REG); //EP0 max packit size = 8   
  14.     writeb((EP0_SERVICED_OUT_PKT_RDY | EP0_SERVICED_SETUP_END), & usbdevregs->EP0_CSR_IN_CSR1_REG); //EP0:clear OUT_PKT_RDY & SETUP_END  
  15.     writeb(1, &usbdevregs->INDEX_REG);   
  16.   
  17. #if (EP1_PKT_SIZE==32)  
  18.     writeb(FIFO_SIZE_32, &usbdevregs->MAXP_REG); //EP1:max packit size = 32  
  19. #else  
  20.     writeb(FIFO_SIZE_64, &usbdevregs->MAXP_REG);     //EP1:max packit size = 64  
  21. #endif    
  22.     writeb((EPI_FIFO_FLUSH | EPI_CDT), &usbdevregs->EP0_CSR_IN_CSR1_REG);   
  23.     writeb((EPI_MODE_IN | EPI_IN_DMA_INT_MASK | EPI_BULK), &usbdevregs->IN_CSR2_REG);  //IN mode, IN_DMA_INT=masked      
  24.     writeb(EPO_CDT, &usbdevregs->OUT_CSR1_REG);   
  25.     writeb((EPO_BULK | EPO_OUT_DMA_INT_MASK), &usbdevregs->OUT_CSR2_REG);   
  26.   
  27.     writeb(2, &usbdevregs->INDEX_REG);   
  28.     writeb(FIFO_SIZE_64, &usbdevregs->MAXP_REG); //EP2:max packit size = 64  
  29.     writeb((EPI_FIFO_FLUSH | EPI_CDT | EPI_BULK), &usbdevregs->EP0_CSR_IN_CSR1_REG);   
  30.     writeb((EPI_MODE_IN | EPI_IN_DMA_INT_MASK), &usbdevregs->IN_CSR2_REG);  //IN mode, IN_DMA_INT=masked      
  31.     writeb(EPO_CDT, &usbdevregs->OUT_CSR1_REG);   
  32.     writeb((EPO_BULK | EPO_OUT_DMA_INT_MASK), &usbdevregs->OUT_CSR2_REG);   
  33.   
  34.     writeb(3, &usbdevregs->INDEX_REG);   
  35.     #if (EP3_PKT_SIZE==32)  
  36.     writeb(FIFO_SIZE_32, &usbdevregs->MAXP_REG); //EP3:max packit size = 32  
  37.     #else  
  38.     writeb(FIFO_SIZE_64, &usbdevregs->MAXP_REG); //EP3:max packit size = 64  
  39.     #endif  
  40.     writeb((EPI_FIFO_FLUSH | EPI_CDT | EPI_BULK), &usbdevregs->EP0_CSR_IN_CSR1_REG);       
  41.     writeb((EPI_MODE_OUT | EPI_IN_DMA_INT_MASK), &usbdevregs->IN_CSR2_REG); //OUT mode, IN_DMA_INT=masked      
  42.     writeb(EPO_CDT, &usbdevregs->OUT_CSR1_REG);   
  43.         //clear OUT_PKT_RDY, data_toggle_bit.  
  44.     //The data toggle bit should be cleared when initialization.  
  45.     writeb((EPO_BULK | EPO_OUT_DMA_INT_MASK), &usbdevregs->OUT_CSR2_REG);   
  46.   
  47.     writeb(4, &usbdevregs->INDEX_REG);   
  48.     writeb(FIFO_SIZE_64, &usbdevregs->MAXP_REG); //EP4:max packit size = 64  
  49.     writeb((EPI_FIFO_FLUSH | EPI_CDT | EPI_BULK), &usbdevregs->EP0_CSR_IN_CSR1_REG);   
  50.     writeb((EPI_MODE_OUT | EPI_IN_DMA_INT_MASK), &usbdevregs->IN_CSR2_REG); //OUT mode, IN_DMA_INT=masked      
  51.     writeb(EPO_CDT, &usbdevregs->OUT_CSR1_REG);   
  52.         //clear OUT_PKT_RDY, data_toggle_bit.  
  53.     //The data toggle bit should be cleared when initialization.  
  54.     writeb((EPO_BULK | EPO_OUT_DMA_INT_MASK), &usbdevregs->OUT_CSR2_REG);   
  55.       
  56.     writeb((EP0_INT | EP1_INT | EP2_INT | EP3_INT | EP4_INT), &usbdevregs->EP_INT_REG);   
  57.     writeb((RESET_INT | SUSPEND_INT | RESUME_INT), &usbdevregs->USB_INT_REG);   
  58.         //Clear all usbd pending bits  
  59.           
  60.     writeb((EP0_INT | EP1_INT | EP3_INT), &usbdevregs->EP_INT_EN_REG);   
  61.     writeb(RESET_INT, &usbdevregs->USB_INT_EN_REG);   
  62.         ep0State = EP0_STATE_INIT;  
  63.       
  64. }  
        可以看出首先是操作电源管理寄存器关闭自动挂起功能,然后就是针对每个端点来配置,主要设置端点的最大信息包的大小,端点类型,传输方向。以及是否支持DMA。最主要的是端点0与端点3因为其他三个端点没有用到。最后清除所有的中断状态寄存器的标志。
        usb 设备控制器最主要的部分就是中断处理程序,本程序中的USB中断处理程序是void IsrUsbd(void),在usbmain.c中:
  1. void IsrUsbd(void)  
  2. {  
  3.     struct s3c24x0_usb_device * const usbdevregs    = s3c24x0_get_base_usb_device();  
  4.     U8 usbdIntpnd,epIntpnd;  
  5.     U8 saveIndexReg = readb(&usbdevregs->INDEX_REG);  
  6.   
  7.     usbdIntpnd = readb(&usbdevregs->USB_INT_REG);  
  8.     epIntpnd = readb(&usbdevregs->EP_INT_REG);  
  9. //    printk( "[INT:EP_I=%x,USBI=%x]",epIntpnd,usbdIntpnd );  
  10.     if(usbdIntpnd&SUSPEND_INT)  
  11.     {  
  12.     writeb(SUSPEND_INT, &usbdevregs->USB_INT_REG);  
  13.     //  printk( "<SUS]");  
  14.     }  
  15.     if(usbdIntpnd&RESUME_INT)  
  16.     {  
  17.     writeb(RESUME_INT, &usbdevregs->USB_INT_REG);  
  18.     //  printk("<RSM]");  
  19.     }  
  20.     if(usbdIntpnd&RESET_INT)  
  21.     {  
  22.     //  printk( "<RST] ReconfigUsbd");    
  23.           
  24.         //ResetUsbd();  
  25.         ReconfigUsbd();  
  26.     writeb(RESET_INT, &usbdevregs->USB_INT_REG); //RESET_INT should be cleared after ResetUsbd().      
  27.         PrepareEp1Fifo();   
  28.     }  
  29.     //以上三个是USB设备中断,主要用到的是复位中断,当GPC5引脚为高时,USB 插入主机,就会产生这个中断  
  30.     if(epIntpnd&EP0_INT)  
  31.     {  
  32.     writeb(EP0_INT, &usbdevregs->EP_INT_REG);  
  33.         Ep0Handler();  
  34.     }  
  35.     //对于每个端点中断都有不同的处理程序,这个是端点0的处理程序。在设备枚举的过程中使用。  
  36.     if(epIntpnd&EP1_INT)  
  37.     {  
  38.     writeb(EP1_INT, &usbdevregs->EP_INT_REG);  
  39.         Ep1Handler();  
  40.     }  
  41.       
  42.     if(epIntpnd&EP2_INT)  
  43.     {  
  44.     writeb(EP2_INT, &usbdevregs->EP_INT_REG);  
  45.     //  printk("<2:TBD]\n");   //not implemented yet   
  46.         //Ep2Handler();  
  47.     }  
  48.   
  49.     if(epIntpnd&EP3_INT)  
  50.     {  
  51.     writeb(EP3_INT, &usbdevregs->EP_INT_REG);  
  52.     printk("Ep3hander\n");  
  53.         Ep3Handler();  
  54.     }  
  55.   
  56.     if(epIntpnd&EP4_INT)  
  57.     {  
  58.     writeb(EP4_INT, &usbdevregs->EP_INT_REG);  
  59.   //    printk("<4:TBD]\n");   //not implemented yet   
  60.         //Ep4Handler();  
  61.     }  
  62.   
  63.     ClearPending_my((int)BIT_USBD);    
  64.     writeb(saveIndexReg, &usbdevregs->INDEX_REG);      
  65. }  
        USB 最重要要的是时序,打印函数是很费时间的,所以如果在USB中断处理程序中加入打印函数,有可能造成总线超时,从而使得USB传输不能成功。下面针对USB设备枚举来说明以下控制传输,相应的中断处理程序Ep0Handler(),在usbsetup.c中:
        这个函数比较长,我就不贴代码了。这个函数主要就是针对中断的类型类进行相应的处理:
        writeb(0, &usbdevregs->INDEX_REG);
        ep0_csr = readb(&usbdevregs->EP0_CSR_IN_CSR1_REG);
        EP0_CSR_IN_CSR1_REG寄存器里面有相应端点的相应中断类型。其中有两种中断是不正常状态,EP0_SETUP_END这个标志表示,控制传输,SETUP阶段在数据包到来前,传输就结束了。造成这个原因有可能是总线超时,如果主机在送出SETUP包以及数据包之后,USB设备迟迟不发送应答包。EP0_SENT_STALL 当设备不正常的时候这个标志会置位。
        EP0_OUT_PKT_READY 这个标志是正常的状态,在USB设备接收到了一个正确的Token以及数据包是,这个标志就置位,从而程序可以从FIFO中读取数据根据setup包中根据请求类型来进行相应的处理。然后清除这个标志。USB设备控制器就会自动发送ACK包给主机,从而结束一个事务。类似,程序用到用于下载的OUT批量传输端点3的中断处理程序Ep3Handler也是这样一个流程。但是不同的是这里还用到了DMA传输。
  1. void Ep3Handler(void)  
  2. {  
  3.     struct s3c24x0_interrupt * intregs = s3c24x0_get_base_interrupt();  
  4.     struct s3c24x0_usb_device * const usbdevregs = s3c24x0_get_base_usb_device();  
  5.         U8 out_csr3;  
  6.         int fifoCnt;  
  7.     writeb(3, &usbdevregs->INDEX_REG);  
  8.     out_csr3 = readb(&usbdevregs->OUT_CSR1_REG);  
  9.       
  10.     printk("<3:%x]",out_csr3);  
  11.   
  12.     if(out_csr3 & EPO_OUT_PKT_READY)  
  13.     {    
  14.     printk("EPO_OUT_PKT_READ\n");   
  15.     fifoCnt = readb(&usbdevregs->OUT_FIFO_CNT1_REG);  
  16. #if 0  
  17.     RdPktEp3(ep3Buf,fifoCnt);  
  18.     PrintEpoPkt(ep3Buf,fifoCnt);  
  19. #else  
  20.   
  21.     if(downloadFileSize==0)  
  22.     {  
  23.         RdPktEp3((U8 *)downPt,8);     
  24.           
  25.         if(download_run==0)  
  26.         {  
  27.             downloadAddress=tempDownloadAddress;  
  28.         }  
  29.         else  
  30.         {  
  31.             downloadAddress=  
  32.                 *((U8 *)(downPt+0))+  
  33.             (*((U8 *)(downPt+1))<<8)+  
  34.             (*((U8 *)(downPt+2))<<16)+  
  35.             (*((U8 *)(downPt+3))<<24);  
  36.               
  37.             dwUSBBufReadPtr = downloadAddress;  
  38.             dwUSBBufWritePtr = downloadAddress;  
  39.         }  
  40.         downloadFileSize=  
  41.             *((U8 *)(downPt+4))+  
  42.         (*((U8 *)(downPt+5))<<8)+  
  43.         (*((U8 *)(downPt+6))<<16)+  
  44.         (*((U8 *)(downPt+7))<<24);  
  45.         checkSum=0;  
  46.         downPt=(U8 *)downloadAddress;  
  47.   
  48.         RdPktEp3_CheckSum((U8 *)downPt,fifoCnt-8); //The first 8-bytes are deleted.       
  49.         downPt+=fifoCnt-8;    
  50.           
  51.     #if USBDMA  
  52.             //CLR_EP3_OUT_PKT_READY() is not executed.   
  53.             //So, USBD may generate NAK until DMA2 is configured for USB_EP3;  
  54.         writel((readl(&intregs->INTMSK) | BIT_USBD), &intregs->INTMSK);  
  55.             return;   
  56.     #endif    
  57.     }  
  58.     else  
  59.     {  
  60.     #if USBDMA        
  61.         printk("<ERROR>");  
  62.     #endif      
  63.         RdPktEp3_CheckSum((U8 *)downPt,fifoCnt);          
  64.         downPt+=fifoCnt;  //fifoCnt=64  
  65.     }  
  66. #endif  
  67.     CLR_EP3_OUT_PKT_READY();  
  68.     return;  
  69.     }  
  70.   
  71.       
  72.     //I think that EPO_SENT_STALL will not be set to 1.  
  73.     if(out_csr3 & EPO_SENT_STALL)  
  74.     {     
  75.     printk("[STALL]");  
  76.     CLR_EP3_SENT_STALL();  
  77.     return;  
  78.     }     
  79. }  
        可以看出中断状态EPO_OUT_PKT_READY标志置位就代表着一个数据包的到来,这里是处理第一个数据包,由于端点3配置的大小为32个字节,所以一个包的数据就是32个字节。因为主机软件DNW在每个文件的头部加了8个字节的信息来标示下载地址与文件长度,所以这个就是处理下载地址与文件长度的信息的。最后下载地址保存在downloadAddress里,文件长度保存在downloadFileSize里。处理完第一个包后,首先禁止USBD中断这个为了设置端点3的DMA功能。在中断禁止的时候,主机发送的数据包都会被USB设备忽略,从而主机会从新发送。貌似这个中断处理函数只处理一个包的数据就关了中断,USB批量传输就进行不下去了。但是别急,程序中还有一个函数是进行批量传输先运行的,这就是usb_receive:
  1. u32 usb_receive(char *buf, size_t len, U32 wait)  
  2. {  
  3.     int first=1;  
  4.     U8 tempMem[16];  
  5.     U32 j;  
  6.     unsigned int dwRecvTimeSec = 0;  
  7.     char c;  
  8.     struct s3c24x0_interrupt * intregs = s3c24x0_get_base_interrupt();  
  9.   
  10.     dwUSBBufReadPtr = dwUSBBufBase; // USB_BUF_BASE; thiswa.diy, 2006.06.21  
  11.     dwUSBBufWritePtr = dwUSBBufBase; // USB_BUF_BASE; thiswa.diy, 2006.06.21  
  12.     bDMAPending = 0;  
  13.   
  14.     /* add by thisway.diy */  
  15.     tempDownloadAddress = dwUSBBufBase; // USB_BUF_BASE; thiswa.diy, 2006.06.21 // RAM_BASE, changed by thisway.diy for wince, 2006.06.18  
  16.   
  17.     downloadAddress=(U32)tempMem; //_RAM_STARTADDRESS;   
  18.     downPt=(unsigned char *)downloadAddress;  
  19.     //This address is used for receiving first 8 byte.  
  20.     downloadFileSize=0;  
  21.       
  22.   
  23.     /*******************************/  
  24.     /*    File download    */  
  25.     /*******************************/  
  26.     if(isUsbdSetConfiguration==0)  
  27.     {  
  28.         printk("USB host is not connected yet.\n");  
  29.     }  
  30.   
  31.     while(downloadFileSize==0) /* wait until send a file */  
  32.     {  
  33.         if(first==1 && isUsbdSetConfiguration!=0)  
  34.         {  
  35.             printk("USB host is connected. Waiting a download.\n");  
  36.             first=0;  
  37.         }  
  38.     }  
  39.   
  40.     printk("get downloadFileSize = %d !!\n",downloadFileSize);  
  41.   
  42.     /* add by thisway.diy */  
  43.     if (downloadFileSize - 10 > len)  
  44.     {  
  45.         printk("Length of file is too big : %d > %d\n", downloadFileSize - 10, len);  
  46.         return 0;  
  47.     }  
  48.       
  49.     Timer_InitEx();  
  50.     Timer_StartEx();  
  51.           
  52. #if USBDMA      
  53.   
  54.     writel((readl(&intregs->INTMSK) & ~(BIT_DMA2)), &intregs->INTMSK);   
  55.   
  56.     ClearEp3OutPktReady();   
  57.         // indicate the first packit is processed.  
  58.         // has been delayed for DMA2 cofiguration.  
  59.   
  60.     if(downloadFileSize>EP3_PKT_SIZE) //如果下载文件的大小比端点FIFO大,得开启DMA功能  
  61.     {  
  62.         if(downloadFileSize - EP3_PKT_SIZE<=(0x80000)) //DMA每次传输的最大数据为1023kb,所以如果大于这个数就得分多次DMA传输  
  63.         {  
  64.             /* set the source and length */  
  65.             dwUSBBufWritePtr = downloadAddress + EP3_PKT_SIZE-8;  
  66.             dwWillDMACnt = downloadFileSize - EP3_PKT_SIZE;  
  67.     }  
  68.         else //多次DMA传输  
  69.         {  
  70.             dwUSBBufWritePtr = downloadAddress + EP3_PKT_SIZE - 8;  
  71.             // dwWillDMACnt = 0x80000 - EP3_PKT_SIZE;  
  72.               
  73.             /* Changed by thisway.diy, 2006.06.22 
  74.              * We want When the first DMA interrupt happened,  
  75.              * it has received (0x80000 + 8) bytes data from PC 
  76.              * The format of data PC send out is: <ADDR(DATA):4>+<SIZE(n+10):4>+<DATA:n>+<CS:2> 
  77.              * So, the first 8 bytes isn't the real data we want 
  78.              * We want the dwUSBBufWritePtr is always 0x80000 aligin 
  79.              */  
  80.             dwWillDMACnt = 0x80000 + 8 - EP3_PKT_SIZE;  
  81.         }  
  82.         totalDmaCount = 0;  //DMA传输的次数  
  83.     ConfigEp3DmaMode(dwUSBBufWritePtr, dwWillDMACnt); //配置端点3DMA功能,然后设置地址,传输大小  
  84.     }  
  85.     else //如果下载文件的大小还没有端点FIFO大,那么没有必要开DMA了,加之第一个包已经处理了,所以直接更新写指针吧  
  86.     {  
  87.         dwUSBBufWritePtr = downloadAddress + downloadFileSize - 8;  
  88.         totalDmaCount = downloadFileSize;  
  89.     }  
  90. #endif  
  91.   
  92.     printk("\nNow, Downloading [ADDRESS:%xh,TOTAL:%d]\n",  
  93.             downloadAddress,downloadFileSize);  
  94.   
  95.     if (wait)  
  96.     {  
  97.         printk("RECEIVED FILE SIZE:%8d",0);  
  98.   
  99.         j = totalDmaCount + 0x10000;  
  100.         while (totalDmaCount != downloadFileSize)  
  101.         {  
  102.             if (totalDmaCount > j)  
  103.             {  
  104.                 printk("\b\b\b\b\b\b\b\b%8d", j);  
  105.                 j = totalDmaCount + 0x10000;  
  106.             }  
  107.         }  
  108.         printk("\b\b\b\b\b\b\b\b%8d ", totalDmaCount);  
  109.         dwRecvTimeSec = Timer_StopEx();  
  110.         if (dwRecvTimeSec == 0)  
  111.         {  
  112.             dwRecvTimeSec = 1;  
  113.         }  
  114.         printk("(%dKB/S, %dS)\n", (downloadFileSize/dwRecvTimeSec/1024), dwRecvTimeSec);  
  115.     }  
  116.   
  117.     return downloadFileSize - 10;  
  118. }  
        usb_receive函数紧接着usb_init_slave运行,如果主机枚举成功设备,那么就会设置downloadFileSize = 1,”USB host is connected. Waiting a download“就会输出到终端,从而执行以下的代码,否则就会等待USB设备配置完毕。头文件中是定义了USBDMA的,所以#if USBDMA 下面的代码就会执行。在说这段代码之前首先说一下Timer_InitEx(); Timer_StartEx();这两个函数的作用还有 if (wait)下面代码的作用,起始这些都是为了显示现在进度,以及下载平均耗时的,这里主要用了看门狗定时器作为定时硬件,如果定义了wait,那么程序会将下载信息显示在终端,然后还统计每秒传输的字节数。下面重点说明#if USBDMA下面的代码。
        这段代码的主要作用就是针对传输文件的大小来决定DMA的使用情况,如果使用DMA,则配置端点3为DMA模式,设置DMA传输的终点地址以及每次DMA传输的大小,开启DMA中断。当设置好DMA时,并打开了DMA中断,每传完一个设置的大小,就会进入DMA中断。所以如果传输文件的大小小于1023KB,那么只会进入一次DMA中断。下面就是DMA中断处理程序:
  1. void IsrDma2(void)  
  2. {  
  3.     struct s3c24x0_interrupt * intregs = s3c24x0_get_base_interrupt();  
  4.     struct s3c24x0_usb_device * const usbdevregs    = s3c24x0_get_base_usb_device();  
  5.         U8 out_csr3;  
  6.         U32 dwEmptyCnt;  
  7.     U8 saveIndexReg = readb(&usbdevregs->INDEX_REG);  
  8.     writeb(3, &usbdevregs->INDEX_REG);  
  9.     out_csr3 = readb(&usbdevregs->OUT_CSR1_REG);  
  10.   
  11.     ClearPending_my((int)BIT_DMA2);       
  12.   
  13.     /* thisway.diy, 2006.06.22  
  14.      * When the first DMA interrupt happened, it has received max (0x80000 + EP3_PKT_SIZE) bytes data from PC 
  15.      */  
  16.     if (!totalDmaCount)   
  17.         totalDmaCount = dwWillDMACnt + EP3_PKT_SIZE; //第一次中断的时候,我们已经接收到了一个包才进入的DMA传输,所以要加一个包的大小  
  18.     else  
  19.         totalDmaCount+=dwWillDMACnt;  
  20.   
  21.   
  22.     dwUSBBufWritePtr = ((dwUSBBufWritePtr + dwWillDMACnt - dwUSBBufBase) % dwUSBBufSize) + dwUSBBufBase;  
  23.     //更新内存写指针  
  24.     if(totalDmaCount>=downloadFileSize)// 最后一次DMA传输完成  
  25.     {  
  26.         totalDmaCount=downloadFileSize;  
  27.       
  28.         ConfigEp3IntMode(); //恢复端点3的设置    
  29.   
  30.         if(out_csr3& EPO_OUT_PKT_READY)  
  31.         {  
  32.             CLR_EP3_OUT_PKT_READY();  
  33.     }  
  34.     writel(((readl(&intregs->INTMSK) | BIT_DMA2) & ~(BIT_USBD)), &intregs->INTMSK);  
  35.         //禁止DMA中断,打开USBD中断  
  36.     }  
  37.     else  
  38.     {  
  39.         if((totalDmaCount+0x80000)<downloadFileSize) //下一次DMA不能传完文件  
  40.         {  
  41.             dwWillDMACnt = 0x80000;  
  42.     }  
  43.         else   //下一次DMA能够传完文件,那么就设置DMA传输的大小问剩下的字节数  
  44.         {  
  45.             dwWillDMACnt = downloadFileSize - totalDmaCount;  
  46.         }  
  47.   
  48.         dwEmptyCnt = (dwUSBBufReadPtr - dwUSBBufWritePtr - 1 + dwUSBBufSize) % dwUSBBufSize;  
  49.         if (dwEmptyCnt >= dwWillDMACnt)  
  50.         {  
  51.             ConfigEp3DmaMode(dwUSBBufWritePtr, dwWillDMACnt);  //重新配置一下DMA传输大小以及地址  
  52.         }  
  53.         else  
  54.         {  
  55.             bDMAPending = 1;  
  56.         }  
  57.     }  
  58.     writeb(saveIndexReg, &usbdevregs->INDEX_REG);  
  59. }  

        DMA中断处理程序在每次DMA传输完成后进入,根据还剩文件的字节数来决定是否继续传输,以及怎样传输。当传输完成后,禁止DMA中断,将端点3配置成中断模式,好进行下一次的批量传输。


【ARM学习笔记】一、S3C2440A官方简介 S3C2440A 是三星公司推出的16/32位精简指令集(RISC)微型处理器,它基于ARM v9系列的ARM920T核心,主要为手持设备和普通应用提供了低功耗的高性能的小型芯片微型控制器的解决方案。 S3C2440A 基于ARM920T 核心,0.13μm 的CMOS 标准宏单元和存储器单元。低功耗,简单,精致,且全静态设计特别适合于对成本和功率敏感型的应用。它采用了新的总线架构如先进微控制总 阅读详情

相关推荐

mini2440 usb device controller 驱动的分析--gadget设备(一)--device controller

USB是目前看到最复杂的驱动,内容很多,而且网上分析USB驱动的资料很少,因此我在学习的过程中走了很多弯路。在这里记录自己的学习过程,希望可以帮到其他研究USB驱动的同事。先推荐一本书:Bootstrap Yourself With Linux-USB Stack                USB的驱动分成两部分:host和gadget。usb是一个host driven的协议,即host是完全主动,每次通信过程都是由host发起的,包括读和写。而device只负责回应,不能主动去读写。

阿戟哥哥的专栏 3969

S3C2440 USB 设备控制器

S3C2440 USB 设备控制器         s3c2440 soc集成了一个usb1.1设备控制器,可以进行全速/低速的控制,中断与批量传输。除了端点0,具有四个端点,每个端点都可以作为中断与批量的端点,每个端点具有128 byte的FIFO,所以端点最大packet可以设置成128byte。并且支持DMA传输。任何一种设备控制器对于软件来说都是一组寄存器:数据,状态,控制。usb

窗外云天的专栏 8270

基于S3C2440的USB驱动开发完整实现

S3C2440是一款基于ARM920T内核的嵌入式微处理器,广泛应用于工业控制、手持设备和嵌入式终端等领域。其集成的USB 1.1控制器支持全速(Full-Speed)传输模式,具备Host(主机)与Device(设备)双工作模式,为嵌入式系统提供了灵活的外设扩展能力。位名称功能描述默认状态0UCLKENUSB PHY时钟输出使能禁用5USBCLKENUSB控制器主时钟使能禁用8HCLKENAHB总线时钟使能。

weixin_42186015的博客 1115

S3C2440 之USB设备篇

             S3C2440 之USB 设备篇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

xuxg2005的专栏 9200

深入探究s3c440 USB设备控制器裸机程序实践

在嵌入式系统的世界里,S3C2440微处理器是众多开发者和工程师的利器。作为一款广泛应用于智能终端和网络设备的高性能处理器,S3C2440通过其USB设备控制器提供了强大的通信能力,使其成为连接现代计算机与外围设备的关键组件。S3C2440由韩国三星公司开发,其集成了一个高效能的ARM920T核心,并具备丰富的外设接口,包括LCD控制器、触摸屏接口以及多种通信接口如UART、I2C、SPI和USB等。这使得它能够在多种应用场景下提供良好的性能。

weixin_26850469的博客 707

在Windows CE 5.0下开发S3C2440 USB驱动的方法与实践

在嵌入式系统领域中,USB(通用串行总线)已成为一种流行且重要的接口,被广泛应用于各种设备中进行数据交换和电源供应。Windows CE 5.0作为一款专为嵌入式设备设计的操作系统,其对USB设备的支持和USB驱动开发自然成为开发者的关注焦点。Samsung S3C2440是一款基于ARM920T核心的32位RISC微处理器,广泛应用于嵌入式系统领域。该处理器拥有最高203 MHz的处理速度,集成了丰富的外设接口,使其能够支持包括以太网、USB、串口等多种通信方式。

weixin_35266799的博客 673

WIN7上调试TQ2440 USB下载

在WIN7上需要使用软件TQBOARDDNW才可以传输文件, 不过在使用SECURECRT软件时,上电后,按a,会出现 USB host  is not connected yet,此时需要多次重启,会有连接上的时候。

whxngb的博客 1329

S3C2440开发板模拟U盘技术实现详解

本文还有配套的精品资源,点击获取 简介:本项目围绕基于Samsung S3C2440处理器的嵌入式开发板,通过技术实现模拟U盘功能。介绍S3C2440处理器的应用场景、ARM中断学习及U盘工作原理。详细阐述USB主机与设备模式、USB驱动开发、FIFO与DMA、FAT文件系统和中断处理等关键知识点,并提供USB通信的固件编程示例。学习者可通过实际项目资源深入理解嵌入式系统和...

weixin_36213081的博客 768

基于中断/DMA方式的串口通信

在DMA串口通信中,串口控制器和DMA控制器之间直接进行数据的传输,而不需要CPU的干预。通过配置DMA控制器,将相关传输的参数设置好,DMA控制器会独立地完成数据的传输并通知 CPU 传输完成,这样可以实现高速、低延迟的数据传输。编写一个字符串比较函数,将输入的数据字符串逐个与起始字符相比较,通过比较函数的返回值控制标志位,然后利用标志位的值不断改变而去控制字符串的发送。而TTL电平通常是正逻辑,高电平表示逻辑。在原有中断配置的基础上,打开USART1的DMA Settings选项,在栏中进行添加。

uoyaijsx的博客 224

mini2440开发板S3C2440处理器JFlash与JLink烧录配置实战

JLink调试器本质上是一个高速USB-to-JTAG/SWD协议转换设备,它将PC端调试指令转换为目标处理器可识别的底层电信号,并通过标准调试接口注入到目标芯片内部。该过程涉及多个层次的协议栈交互,包括物理层电平驱动、数据链路层状态机切换以及调试逻辑核心(Debug Access Port, DAP)的操作控制。mini2440开发板采用标准20-pin ARM JTAG插座,其关键信号定义如下:引脚号信号名方向功能说明4TCK输入。

weixin_35748962的博客 1196

Unix/Linux环境下的S3C2410/S3C2440触摸屏驱动编程

本文还有配套的精品资源,点击获取 简介:本资源包提供了针对三星S3C2410处理器(可能包括S3C2440升级版)的触摸屏驱动程序,适用于Unix或Linux操作系统。S3C2410/S3C2440是基于ARM920T内核的微处理器,广泛应用于嵌入式系统,如智能手机和平板电脑。驱动程序负责处理触摸屏信号,将其转换为屏幕坐标,并与用户空间应用程序交互。学习这个驱动程序的实现可...

weixin_32869687的博客 945

S3C2440和S3C6410性能比较

 比较项目 S3C2440 S3C6410 内核 ARM920T ARM1176JZF-S 主频 400MHZ 533MHZ/667MHZ 处理器类型 16/32-bit RISC 16/32-bit RISC 设计目标 高性能、低功耗 高性能、低功耗、高性价比 主要应用 手持设备 2.5G和3G通信服务 内部总线结构 32/16-bit 64/32-bit 多媒体硬件编码器/解码器 无 有(支持...

无语僧 7507

【学习K230-例程46】GT6700-UVC摄像头

UVC模块提供了USB摄像头的检测、配置和图像采集功能,支持单摄像头操作。本实验通过开发板上的USB接口连接摄像头,将摄像头捕获到的画面显示在显示设备上。print(f"模式{i}: {mode.width}x{mode.height} {mode.format}@{mode.fps}fps")print(f"摄像头检测: {‘已连接’ if plugin else ‘未连接’}, 设备信息: {devinfo}")检测系统是否连接了USB摄像头(当前仅支持单个摄像头检测)。获取摄像头支持的所有视频模式。

GilgameshJSS的博客 806

S3C2440系统时钟

++++++++++++++++++++++++++++++++++++++++++ 本文系本站原创,欢迎转载! 转载请注明出处: http://blog.csdn.net/mr_raptor/article/details/6555734 ++++++++++++++++++++++++++++++++++++++++++   系统时钟 MINI2440开发板在没有开启时钟前,整

mr_raptor的专栏 1万+

AI大模型学习(14)AI 小白入门!用 OpenCV+Python 打造人体姿态识别系统,超详细教程来了

这篇教程介绍了如何使用Python+OpenCV+MediaPipe搭建入门级人体姿态识别系统。主要内容包括:人体姿态识别的应用场景(如健身APP、体感游戏)、开发环境搭建(安装Python、OpenCV和MediaPipe库)、核心代码实现(通过30行代码完成摄像头姿态检测),以及进阶功能开发(深蹲动作纠正算法和PPT体感控制器)。教程详细解析了MediaPipe的BlazePose模型架构和33个关键点的生理学意义,并提供了多线程优化等性能提升方案。该项目适合AI初学者实践,无需复杂算法即可实现实时人体

isoft888的专栏,致力于C#/python分享物联网、大数据,神经网络的等领域,欢迎讨论交流! 1551

如何利用DeepSeek自动生成PLC程序?

在工业自动化领域,PLC是核心控制设备,其编程效率和质量直接影响生产线的运行效果。 然而,传统PLC编程依赖工程师手动编写代码,不仅耗时耗力,还容易出错。通过自动生成PLC程序,DeepSeek不仅大幅提升了编程效率,还优化了代码质量。 那么DeepSeek到底能否自动生成PLC程序呢? 有位电气工程师就尝试让DeepSeek设计一套五层电梯控制系统的PLC程序,下面就让我们看看吧。 技术原理:DeepSeek如何实现自动编程DeepSeek利用自然语言处理技术,将工程师输入的文本指令转换为PLC代码。例

Qinmingyue13的博客 6178

JZ2440开发板——S3C2440的时钟体系

1、深入讲解了S3C2440芯片的结构掌握了S3C2440的时钟体系架构和上电复位时序,其时钟源有两个:外部晶振或者外部时钟,通过OM[3:2]硬件选择;其内部主要调整频率的PLL有两个:MPLL(产生FCLK)和UPLL(产生UCLK);其主要的时钟频率有三个(FCLK->CPU使用,HCLK->AHB总线高速外设使用,PCLK->APB总线低速外设使用),其中HCLK和PCLK由FCLK分频而来。2、学习了如何进行芯片操作。

主要记录嵌入式学习与开发过程。 1770

Cadence创建异形焊盘教程(详细操作)

背景:一些常见的矩形/圆形焊盘,设置参数就可。碰到非规则的一些焊盘,那只能用Cadence Allegro PCB来画咯。 一、新建图形 【File】——>【New…】 弹出如下窗口,选择绘制的类型Shape symbol、路径,输入名字 二、设置参数 【Setup】——>【Design Parameters…】 Enhanced display modes:增强型显示模型。全部勾选上。 在【Design】设置单位为mm 设置偏移量(-50,-50) 三、绘制图形 1、找到原点,即参考

qq_42057393的博客 2万+

s3c2440裸奔之结束语

想了好久,最终还是决定结束该系列的内容。对照s3c2440数据手册,能讲解的内容我基本上都介绍了一遍。其中,限于手头没有相关硬件资源,SPI、UART的红外模式、AC97没有涉及,而USB设备控制器部分,由于还要用到上位机的驱动以及应用程序的开发,涉及的内容较多,已超出了“裸奔”的范围,因此也没有予以介绍,还请大家谅解。       为了便于大家的查找,我给出一个目录: 1、s3c2440启

赵春江的专栏 2万+

基于python+flask框架的基于微信小程序的CR公司建设项目信息管理系统-前台(开题+程序+论文) 计算机毕设

特别是随着移动互联网技术的普及,企业对便捷、高效的信息管理系统的需求日益迫切。另一方面,该系统集成了仓管、物料、财务、人事、供应商等多个模块,实现了数据的集中管理和信息共享,有助于企业实现精细化管理,降低运营成本,提升决策效率。:深入调研CR公司的业务需求,明确系统应具备的功能模块,包括仓管员管理模块(物料信息、退回记录、申请信息、仓库信息管理)、财务员管理模块(资金信息管理、采购与租赁款项处理)、人事管理模块、供应商管理模块、项目管理模块(项目信息、设备采购、物料采购、设备租赁)、以及考勤打卡模块等。

zhihao503的博客 960

01-系统技术架构师必备——软件架构设计基础与核心概念

摘要 本文系统阐述了软件架构设计的核心概念与方法论,重点涵盖以下内容:1)软件架构的四大要素(构件、连接件、约束、配置)及其边界划分;2)Garlan & Shaw五大架构风格(数据流、调用/返回、独立构件、虚拟机、仓库)的典型应用场景;3)基于电商库存系统的架构选型实战案例,展示如何根据业务需求(高并发、最终一致性)选择事件驱动架构配合Saga模式;4)介绍ABSD、DSSA等主流架构方法论及ISO/IEEE标准体系。文章融合金融与互联网领域的架构实践经验,为技术架构师提供系统性的知识框架和决策参考。

模界 | AI工程化实践者 182

[经典]三星系列S3C2440和S3C2450以及S3C6410之间的区别

 作为GPS、PDA、数字电视等手持设备的主要方案处理器提供方韩国Sumsung公司,最近又新推出ARM处理器S3C2450、S3C6410芯片。这些平台又与S3C2440处理器有哪些区别优势。S3C2440:      主频400MHz;  SDRam内存控制器; 支持Nor Flash和Nand Flash(SLC)  支持2种Flash启动;  内部LCD、I2C、Camera等控制器。

fushiqi的专栏 1852

实验2 存储器设计与实现【计算机组成原理】

实验2 存储器设计与实现【计算机组成原理】

小心星的博客 2398
上一篇: 2440初始化存储器原理(接上一篇)
下一篇: Linux usb 设备驱动 (1)
shareCode
博客等级 码龄15年 125粉丝 40原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值