在前段時間我連續寫了15篇關于【.Net Micro Framework PortingKit–?】的系列文章,初步介紹了.Net Micro Framework在Cortex-M3平台上的移植過程,最近一段時間又對另外兩塊Cortex-M3開發闆進行了相關的移植工作,新實作了USB驅動、SPI驅動、觸摸屏驅動、LCD驅動(ILI9325),除此之外還新開發了TinyGUI圖形庫,該圖形庫僅需要極少量的記憶體便能運作在Cortex-M3平台上。從今天開始,我會陸續寫這方面開發的相關文章。
第一次編寫USB的驅動,是在Ti DM355平台上,當時用了大概二個多月的時間才移植成功,花了這麼長的時間,一是USB運作機制非常複雜,二是對嵌入式開發當時并不是特别熟悉。在此期間我寫四篇關于USB的文章,有興趣的朋友可參考一下《Micro Framework USB Driver開發》、《MF Porting之USB驅動開發》、《【.Net MF新特性】Usb雙接口支援》和《.Net Micro Framework - USB Mass Storage功能實作》。
STM32F103系列的晶片,其USB接口僅支援Device模式,不像Ti DM355其接口支援OTG、Host、Device三種模式,是以寄存器通路相對比較簡單(不過ST最新推出的互聯性晶片,其USB接口和Ti的一樣了)。
USB接口支援8個端點,資料傳輸支援三種模式:DMA、雙緩沖、單緩沖,簡單期間,我僅實作了單緩沖模式。
首先,我們需要聲明USB寄存器相對應的結構體,以期友善操作相關的寄存器。
struct CortexM3_USB_Base
{
//+ 0x40
/****/ volatile UINT16 CNTR; //控制寄存器
static const UINT16 CNTR_CTRM = ((UINT16)0x8000); //成功傳輸中斷标志
static const UINT16 CNTR_PMAOVRM = ((UINT16)0x4000); //分組緩沖區溢出中斷标志
略……
};
struct CortexM3_USB_EndPoint
{
/****/ volatile UINT16 EP; //端點寄存器
static const UINT16 EP_CTR_RX = ((UINT16)0x8000); //正确接收标志
static const UINT16 EP_DTOG_RX = ((UINT16)0x4000); //用于資料接收的資料翻轉位
略…….
};
struct CortexM3_USB_BTABLE
{
static const UINT32 c_Base = 0x40006000; //~0x400063FF USB/CAN共享的SRAM 512位元組(c_PMA_Base)
/****/ volatile UINT16 ADDR_TX; //發送緩沖區位址
static const UINT16 ADDR_TX_Mask = ((UINT16)0xFFFE);
UINT16 RESERVED0;
略…….
};
struct CortexM3_USB
{
static const UINT32 c_Base = 0x40005C00;
static const UINT32 c_CFGR_USBPRE_BB = 0x42000000 + 0x21004 * 32 + 0x16 * 4;
static const UINT32 c_USB_MAX_EP = 3; //8
CortexM3_USB_EndPoint EP[8]; //0x0-0x1c
UINT16 RESERVED0[16];
CortexM3_USB_Base Base; //0x40-0x4c
};
USB提供兩個中斷信号,一個是c_IRQ_Index_USB_HP_CAN_TX,另一個是c_IRQ_Index_USB_LP_CAN_RX0,不過前一個對低速傳輸似乎必要性不大。
是以這裡僅啟用第二種中斷,代碼如下:
if(!CPU_INTC_ActivateInterruptEx( CortexM3_NVIC::c_IRQ_Index_USB_LP_CAN_RX0, (UINT32)(void *)USB_LP_IRQHandler)) return FALSE;
此外控制USB軟連接配接的GPIO為PB14,啟用USB功能前,要置位該Pin腳。
CPU_GPIO_DisablePin( USB_EN_PIN,RESISTOR_DISABLED,TRUE,GPIO_ALT_MODE_9); //DISABLE
CPU_GPIO_DisablePin( USB_EN_PIN,RESISTOR_DISABLED,TRUE,GPIO_ALT_MODE_5); //ENABLE
針對.Net Micro Framework來說,USB僅用到三個端點,是以隻需用初始化這三個端點即可,相關代碼如下:
CortexM3_USB &USB = CortexM3::USB();
USB.Base.DADDR = CortexM3_USB_Base::DADDR_EF | 0;
//EP0
USB.EP[0].EP = CortexM3_USB_EndPoint::EP_TYPE_CONTROL | (0 & CortexM3_USB_EndPoint::EP_EA);
SetTxStatus(0,CortexM3_USB_EndPoint::EP_TX_NAK);
SetRxStatus(0,CortexM3_USB_EndPoint::EP_RX_VALID);
//lcd_printf("EP0:%x/r/n",USB.EP[0].EP);
//EP1
USB.EP[1].EP = CortexM3_USB_EndPoint::EP_TYPE_BULK | (1 & CortexM3_USB_EndPoint::EP_EA);
SetTxStatus(1,CortexM3_USB_EndPoint::EP_TX_NAK);
SetRxStatus(1,CortexM3_USB_EndPoint::EP_RX_DISABLED);
if(USB.EP[1].EP & CortexM3_USB_EndPoint::EP_DTOG_RX) USB.EP[1].EP |= CortexM3_USB_EndPoint::EP_DTOG_RX;
if(USB.EP[1].EP & CortexM3_USB_EndPoint::EP_DTOG_TX) USB.EP[1].EP |= CortexM3_USB_EndPoint::EP_DTOG_TX;
//EP2
USB.EP[2].EP = CortexM3_USB_EndPoint::EP_TYPE_BULK | (2 & CortexM3_USB_EndPoint::EP_EA);
SetTxStatus(2,CortexM3_USB_EndPoint::EP_TX_DISABLED);
SetRxStatus(2,CortexM3_USB_EndPoint::EP_RX_VALID);
if(USB.EP[2].EP & CortexM3_USB_EndPoint::EP_DTOG_RX) USB.EP[2].EP |= CortexM3_USB_EndPoint::EP_DTOG_RX;
if(USB.EP[2].EP & CortexM3_USB_EndPoint::EP_DTOG_TX) USB.EP[2].EP |= CortexM3_USB_EndPoint::EP_DTOG_TX;
限于篇幅,這裡的代碼僅列這麼多,有興趣的朋友請參考.Net Micro Framework的相關USB驅動的源碼,其架構大同小異。
最終成功運作的效果圖如下:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5yYxkTNmRmYkZWZhRjY2IGOxUTZ0kzNjFDZzgDMiNjZx8CX5d2bs92Yl1iclB3bsVmdlR2LcNWaw9CXt92Yu4GZjlGbh5yYjV3Lc9CX6MHc0RHaiojIsJye.png)