久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

S3C2440 USB 設備控制器

 WUCANADA 2013-10-05

S3C2440 USB 設備控制器

分類: USB 1655人閱讀 評論(0) 收藏 舉報

S3C2440 USB 設備控制器

        s3c2440 soc集成了一個usb1.1設備控制器,,可以進行全速/低速的控制,中斷與批量傳輸,。除了端點0,具有四個端點,,每個端點都可以作為中斷與批量的端點, 每個端點具有128 byte的FIFO,,所以端點最大packet可以設置成128byte,。并且支持DMA傳輸。任何一種設備控制器對于軟件來說都是一組寄存器:數(shù)據(jù),,狀 態(tài),,控制。usb 設備控制器也不例外,。設置好相應的控制寄存器,,并且在數(shù)據(jù)來時讀取數(shù)據(jù)寄存器,需要發(fā)送數(shù)據(jù)的時候將數(shù)據(jù)寫入輸出寄存器,。而這種數(shù)據(jù)的通信建立在對狀態(tài)寄 存器的讀取上,,往往還會有中斷與DMA的操作。s3c2440 usb設備控制器的寄存器分為以下幾組:

(1):電源管理寄存器
        PWR_REG 負責USB設備掛起等電源設置
(2):地址寄存器
        存儲USB設備的地址,,當主機枚舉設備設備的時候設置
(3):中斷控制寄存器
        EP_INT_REG    端點中斷狀態(tài)寄存器,,每當一個端點事件發(fā)生的時候,相應的位就會置1
        USB_INT_REG   設備中斷狀態(tài)寄存器,,主要有三個中斷:喚醒,,復位,掛起
        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傳輸細節(jié),,并產生相應的中斷,。所以對USB設備控制器的編程,最關鍵的部分就是中斷處理的部分,。比如端點每收到一個 token以及后面的數(shù)據(jù)包,,就會產生相應的中斷。軟件只需要在中斷處理程序中讀取數(shù)據(jù),,并且清除中斷標志,。USB設備控制器就會自動發(fā)送應答包。現(xiàn)在網 上比較流行的操作s3c2440 usb 設備控制器的程序就是移植到u-boot里面的usb下載程序,。因為在u-boot的環(huán)境下所以調試起來沒有在裸機上來的方便,,所以我將這個程序移植到了 裸機上,編譯環(huán)境arm-linux-gcc,。下面大體介紹以下這個程序的流程:

        這個程序主要是完成了USB設備的枚舉,,與批量OUT傳輸,,并且開啟了DMA,,OUT傳輸用的端點是端點3,。這個程序首先從 init_usb_slave() 開始:這個函數(shù)主要是設置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(); //主要配置函數(shù)  
  19.         Delay(10);  
  20.   
  21.         writel((readl(&gpioregs->GPCDAT) | (1<<5)), &gpioregs->GPCDAT);  
  22.         //這個操作和Mini2440開發(fā)板有關,,在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是我自己編寫的打印函數(shù)  
  33. }  
        在配置完設備后,給GPC5一個高電平,,主機就開始枚舉設備的過程了,。能不能開始這個過程關鍵是看設備是否配置正確。這就是要看UsbMain()這個函數(shù)了,。他在usbmain.c中,,如下:
  1. void UsbdMain(void)  
  2. {  
  3.     InitDescriptorTable();  
  4.     ConfigUsbd();   
  5.     PrepareEp1Fifo();   
  6. }  
        這個函數(shù)挺簡單,但是調用了三個函數(shù)可不簡單,。第一個就是初始化一些USB描述符,,比如設備描述符,,配置描述符等,,在usb控制傳輸?shù)臅r候返回給設備。這 個函數(shù)在usbsetup.c中。PrepareEp1Fifo()是配置端點1的,,這里沒有用到,。關鍵的是ConfigUsbd()函數(shù),這個函數(shù)是最 主要的配置函數(shù),。在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. }  
        這個函數(shù)是個封裝函數(shù),,第一次配置調用他,并且開啟中斷,。在重置USB的過程中調用的是ReconfigUsbd(),,這個函數(shù)也在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因為其他三個端點沒有用到。最后清除所有的中斷狀態(tài)寄存器的標志,。
        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 最重要要的是時序,,打印函數(shù)是很費時間的,所以如果在USB中斷處理程序中加入打印函數(shù),,有可能造成總線超時,,從而使得USB傳輸不能成功。下面針對 USB設備枚舉來說明以下控制傳輸,,相應的中斷處理程序Ep0Handler(),,在usbsetup.c中:
        這個函數(shù)比較長,我就不貼代碼了,。這個函數(shù)主要就是針對中斷的類型類進行相應的處理:
        writeb(0, &usbdevregs->INDEX_REG);
        ep0_csr = readb(&usbdevregs->EP0_CSR_IN_CSR1_REG);
        EP0_CSR_IN_CSR1_REG寄存器里面有相應端點的相應中斷類型,。其中有兩種中斷是不正常狀態(tài),EP0_SETUP_END這個標志表示,,控 制傳輸,,SETUP階段在數(shù)據(jù)包到來前,,傳輸就結束了。造成這個原因有可能是總線超時,,如果主機在送出SETUP包以及數(shù)據(jù)包之后,,USB設備遲遲不發(fā)送 應答包。EP0_SENT_STALL 當設備不正常的時候這個標志會置位,。
        EP0_OUT_PKT_READY 這個標志是正常的狀態(tài),,在USB設備接收到了一個正確的Token以及數(shù)據(jù)包是,這個標志就置位,,從而程序可以從FIFO中讀取數(shù)據(jù)根據(jù)setup包中根 據(jù)請求類型來進行相應的處理,。然后清除這個標志。USB設備控制器就會自動發(fā)送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. }  
        可以看出中斷狀態(tài)EPO_OUT_PKT_READY標志置位就代表著一個數(shù)據(jù)包的到來,這里是處理第一個數(shù)據(jù)包,,由于端點3配置的大小為32個字節(jié),,所 以一個包的數(shù)據(jù)就是32個字節(jié)。因為主機軟件DNW在每個文件的頭部加了8個字節(jié)的信息來標示下載地址與文件長度,,所以這個就是處理下載地址與文件長度的 信息的,。最后下載地址保存在downloadAddress里,文件長度保存在downloadFileSize里,。處理完第一個包后,,首先禁止USBD 中斷這個為了設置端點3的DMA功能。在中斷禁止的時候,,主機發(fā)送的數(shù)據(jù)包都會被USB設備忽略,,從而主機會從新發(fā)送。貌似這個中斷處理函數(shù)只處理一個包 的數(shù)據(jù)就關了中斷,,USB批量傳輸就進行不下去了,。但是別急,程序中還有一個函數(shù)是進行批量傳輸先運行的,,這就是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每次傳輸?shù)淖畲髷?shù)據(jù)為1023kb,所以如果大于這個數(shù)就得分多次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傳輸?shù)拇螖?shù)  
  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函數(shù)緊接著usb_init_slave運行,,如果主機枚舉成功設備,,那么就會設置downloadFileSize = 1,”USB host is connected. Waiting a download“就會輸出到終端,從而執(zhí)行以下的代碼,,否則就會等待USB設備配置完畢。頭文件中是定義了USBDMA的,,所以#if USBDMA 下面的代碼就會執(zhí)行,。在說這段代碼之前首先說一下Timer_InitEx(); Timer_StartEx();這兩個函數(shù)的作用還有 if (wait)下面代碼的作用,起始這些都是為了顯示現(xiàn)在進度,,以及下載平均耗時的,,這里主要用了看門狗定時器作為定時硬件,如果定義了wait,,那么程序 會將下載信息顯示在終端,,然后還統(tǒng)計每秒傳輸?shù)淖止?jié)數(shù)。下面重點說明#if USBDMA下面的代碼,。
        這段代碼的主要作用就是針對傳輸文件的大小來決定DMA的使用情況,,如果使用DMA,則配置端點3為DMA模式,,設置DMA傳輸?shù)慕K點地址以及每次DMA 傳輸?shù)拇笮?,開啟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傳輸?shù)拇笮柺O碌淖止?jié)數(shù)  
  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傳輸完成后進入,,根據(jù)還剩文件的字節(jié)數(shù)來決定是否繼續(xù)傳輸,以及怎樣傳輸,。當傳輸完成后,,禁止DMA中斷,將端點3配置成中斷模式,,好進行下一次的批量傳輸,。

程序源代碼在 http://download.csdn.net/detail/yaozhenguo2006/4182352




    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,,不代表本站觀點,。請注意甄別內容中的聯(lián)系方式,、誘導購買等信息,謹防詐騙,。如發(fā)現(xiàn)有害或侵權內容,,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多