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();
- }