LPC1768的usb使用--硬件篇
LPC1768芯片帶有USB設(shè)備控制器,前面寫的文章都是在說比較簡(jiǎn)單的設(shè)備驅(qū)動(dòng),今天來(lái)說復(fù)雜一點(diǎn)的
首先是硬件層的配置
#ifndef __USBHW_H__
#define __USBHW_H__
#include "debugSerial.h"
#include "usbreg.h"
#include "usb.h"
#include "usbuser.h"
#include "usbcfg.h"
#include "usbcore.h"
#include "usbep1.h"
U32 EPAdr(U32 EPNum);
//USB硬件寄存器級(jí)別的方法
extern void USB_Init(void);
//usb連接
extern void USB_Connect(BOOL con);
//usb復(fù)位
extern void USB_Reset(void);
//usb掛起
extern void USB_Suspend(void);
//usb掛起恢復(fù)
extern void USB_Resume(void);
//usb喚醒
extern void USB_WakeUp(void);
extern void USB_WakeUpCfg(BOOL cfg);
//usb設(shè)置地址
extern void USB_SetAddress(U32 adr);
//usb配置
extern void USB_Configure(BOOL cfg);
//usb根據(jù)配置描述符配置端點(diǎn)
extern void USB_ConfigEP(USB_ENDPOINT_DESCRIPTOR*pEPD);
//使能端點(diǎn)
extern void USB_EnableEP(U32 EPNum);
//禁止端點(diǎn)
extern void USB_DisableEP(U32 EPNum);
//端點(diǎn)復(fù)位
extern void USB_ResetEP(U32 EPNum);
//設(shè)置端點(diǎn)暫停
extern void USB_SetStallEP(U32 EPNum);
//清除端點(diǎn)暫停,設(shè)置特性
extern void USB_ClrStallEP(U32 EPNum);
//usb清除端點(diǎn)緩存
extern void USB_ClearEPBuf(U32 EPNum);
//讀取usb緩沖區(qū)
extern U32 USB_ReadEP(U32 EPNum,U8*pData);
//寫入usb in包的緩沖區(qū)
extern U32 USB_WriteEP(U32 EPNum,U8*pData,U32 cnt);
//獲取當(dāng)前usb幀號(hào)
extern U32 USB_GetFrame(void);
#endif
實(shí)現(xiàn)如下
#include "usbhw.h"
#define EP_MSK_CTRL 0x0001 /* 控制端點(diǎn)邏輯地址,第0端點(diǎn) */
#define EP_MSK_BULK 0xC924 /* 批量端點(diǎn)邏輯地址 第2 5 8 11 14 15 */
#define EP_MSK_INT 0x4492 /* 中斷端點(diǎn)邏輯地址 1 4 7 10 13 */
#define EP_MSK_ISO 0x1248 /* 同步端點(diǎn)邏輯地址 3 6 9 12 */
//端點(diǎn)的邏輯地址轉(zhuǎn)換為物理地址,比如邏輯地址0x80 轉(zhuǎn)換過來(lái)是物理端點(diǎn)1,
//(usb設(shè)置配置的時(shí)候發(fā)送來(lái)的端點(diǎn)號(hào)碼是邏輯地址,需要轉(zhuǎn)換)
U32 EPAdr(U32 EPNum)
{
U32 val;
val=(EPNum&0x0F)<<1;
if(EPNum&0x80)val+=1;//根據(jù)輸入輸出增減
return(val);
}
//usb寫入命令
void WrCmd(U32 cmd)
{
LPC_USB->USBDevIntClr=CCEMTY_INT;//清除命令空中斷
LPC_USB->USBCmdCode=cmd;
while((LPC_USB->USBDevIntSt&CCEMTY_INT)==0);//等待寫入的命令被接受,空中斷再次產(chǎn)生
}
//usb寫入命令+數(shù)據(jù),流程相當(dāng)于上一個(gè)函數(shù)的重復(fù)
void WrCmdDat(U32 cmd,U32 val)
{
LPC_USB->USBDevIntClr=CCEMTY_INT;
LPC_USB->USBCmdCode=cmd;
while((LPC_USB->USBDevIntSt&CCEMTY_INT)==0);
LPC_USB->USBDevIntClr=CCEMTY_INT;
LPC_USB->USBCmdCode=val;
while((LPC_USB->USBDevIntSt&CCEMTY_INT)==0);
}
//向端點(diǎn)寫入命令,端點(diǎn)號(hào)應(yīng)當(dāng)是端點(diǎn)的邏輯地址
void WrCmdEP(U32 EPNum,U32 cmd)
{
LPC_USB->USBDevIntClr=CCEMTY_INT;
LPC_USB->USBCmdCode=CMD_SEL_EP(EPAdr(EPNum));//選擇端點(diǎn),發(fā)送的是命令形式的端點(diǎn)選擇
while((LPC_USB->USBDevIntSt&CCEMTY_INT)==0);
LPC_USB->USBDevIntClr=CCEMTY_INT;
LPC_USB->USBCmdCode=cmd; //寫入數(shù)據(jù)
while((LPC_USB->USBDevIntSt&CCEMTY_INT)==0);
}
//寫入命令并讀出數(shù)據(jù) 命令應(yīng)當(dāng)是讀取命令 02
U32 RdCmdDat(U32 cmd)
{
LPC_USB->USBDevIntClr=CCEMTY_INT|CDFULL_INT;//清除命令為空,數(shù)據(jù)滿中斷
LPC_USB->USBCmdCode=cmd;
while((LPC_USB->USBDevIntSt&CDFULL_INT)==0);//等待數(shù)據(jù)滿
return(LPC_USB->USBCmdData);
}
//USB總線復(fù)位,重新配置端點(diǎn)的寄存器
void USB_Reset(void)
{
LPC_USB->USBEpInd=0;
LPC_USB->USBMaxPSize=USB_MAX_PACKET0;
LPC_USB->USBEpInd=1;
LPC_USB->USBMaxPSize=USB_MAX_PACKET0;//兩個(gè)控制端點(diǎn)都設(shè)置為最大包形式
while((LPC_USB->USBDevIntSt&EP_RLZED_INT)==0);//等待端點(diǎn)使用
LPC_USB->USBEpIntClr=0xFFFFFFFF;
LPC_USB->USBEpIntEn=0xFFFFFFFF^USB_DMA_EP;//使能DMA的端點(diǎn),中斷自動(dòng)觸發(fā)DMA,所以不開啟中斷
LPC_USB->USBDevIntClr=0xFFFFFFFF;
//當(dāng)使用同步端點(diǎn)的時(shí)候要打開幀中斷
LPC_USB->USBDevIntEn=DEV_STAT_INT|EP_SLOW_INT;//打開狀態(tài)中斷(復(fù)位掛起等)和慢速中斷(默認(rèn)情況下,端點(diǎn)中斷都是慢速中斷)
}
//usb設(shè)置設(shè)備的總線地址
void USB_SetAddress(U32 adr)
{
WrCmdDat(CMD_SET_ADDR,DAT_WR_BYTE(DEV_EN|adr));//連續(xù)寫入兩次,使能usb對(duì)該地址的響應(yīng)
WrCmdDat(CMD_SET_ADDR,DAT_WR_BYTE(DEV_EN|adr));
}
//usb初始化
void USB_Init(void)
{
LPC_SC->PCONP|=(1<<15);//打開IO口時(shí)鐘
//USB D+
LPC_PINCON->PINSEL1&=~(0X03L<<26);
LPC_PINCON->PINSEL1|=(1<<26); //功能 usbd+
//USB D+
LPC_PINCON->PINSEL1&=~(0X03L<<28);
LPC_PINCON->PINSEL1|=(1<<28); //功能 usbd-
//USB VBUS
LPC_PINCON->PINSEL3&=~(0X03L<<28);
LPC_PINCON->PINSEL3|=(2<<28); //功能 usb vbus
//USB CONNECT
LPC_PINCON->PINSEL4&=~(0X03L<<18);
LPC_PINCON->PINSEL4|=(0X01L<<18);
// LPC_PINCON->PINMODE4 &= ~(0X03L<<18); //使能上拉電阻
// LPC_PINCON->PINMODE_OD2 &= ~(0X01<<9); //正常推挽模式
// P2dir(9) = 1; //輸出
// P2high(9) = 1; //初始化設(shè)置為0
LPC_SC->PCONP|=(1UL<<31); /* USB PCLK -> enable USB Per. */
LPC_USB->USBClkCtrl=0x1A; /* Dev, PortSel, AHB clock enable */
while((LPC_USB->USBClkSt&0x1A)!=0x1A); //等待時(shí)鐘狀態(tài)切換完成
USB_Reset();
USB_SetAddress(0); //初始化未識(shí)別之前設(shè)置設(shè)備地址為0
NVIC_ClearPendingIRQ(USB_IRQn);
NVIC_SetPriority(USB_IRQn,NVIC_EncodePriority(SYS_NVIC_GROUP,USB_PreemptPriority,USB_SubPriority));//中斷優(yōu)先級(jí)別
NVIC_EnableIRQ(USB_IRQn); /* enable USB interrupt */
}
//usb軟連接選擇,為0 斷開 為1連接
void USB_Connect(BOOL con)
{
WrCmdDat(CMD_SET_DEV_STAT,DAT_WR_BYTE(con?DEV_CON:0));
// if(con)P2low(9) = 1;
// else P2high(9) = 1;
}
//usb掛起事件發(fā)生之后自動(dòng)調(diào)用的函數(shù),處理掛起事務(wù)
void USB_Suspend(void)
{
usb_debug_printf("USB_Suspend rn");
mouse_connect=0;
}
//usb收到恢復(fù)指令之后自動(dòng)調(diào)用的函數(shù),處理恢復(fù)事務(wù)
void USB_Resume(void)
{
usb_debug_printf("USB_Resume rn");
mouse_connect=0;
}
//usb遠(yuǎn)程喚醒時(shí)間發(fā)生的時(shí)候自動(dòng)調(diào)用的函數(shù)
void USB_WakeUp(void)
{
if(USB_DeviceStatus&USB_GETSTATUS_REMOTE_WAKEUP)
{