LPC1768的usb使用--硬件篇
扫描二维码
随时随地手机看文章
LPC1768芯片带有USB设备控制器,前面写的文章都是在说比较简单的设备驱动,今天来说复杂一点的
首先是硬件层的配置
#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硬件寄存器级别的方法
extern void USB_Init(void);
//usb连接
extern void USB_Connect(BOOL con);
//usb复位
extern void USB_Reset(void);
//usb挂起
extern void USB_Suspend(void);
//usb挂起恢复
extern void USB_Resume(void);
//usb唤醒
extern void USB_WakeUp(void);
extern void USB_WakeUpCfg(BOOL cfg);
//usb设置地址
extern void USB_SetAddress(U32 adr);
//usb配置
extern void USB_Configure(BOOL cfg);
//usb根据配置描述符配置端点
extern void USB_ConfigEP(USB_ENDPOINT_DESCRIPTOR*pEPD);
//使能端点
extern void USB_EnableEP(U32 EPNum);
//禁止端点
extern void USB_DisableEP(U32 EPNum);
//端点复位
extern void USB_ResetEP(U32 EPNum);
//设置端点暂停
extern void USB_SetStallEP(U32 EPNum);
//清除端点暂停,设置特性
extern void USB_ClrStallEP(U32 EPNum);
//usb清除端点缓存
extern void USB_ClearEPBuf(U32 EPNum);
//读取usb缓冲区
extern U32 USB_ReadEP(U32 EPNum,U8*pData);
//写入usb in包的缓冲区
extern U32 USB_WriteEP(U32 EPNum,U8*pData,U32 cnt);
//获取当前usb帧号
extern U32 USB_GetFrame(void);
#endif
实现如下
#include "usbhw.h"
#define EP_MSK_CTRL 0x0001 /* 控制端点逻辑地址,第0端点 */
#define EP_MSK_BULK 0xC924 /* 批量端点逻辑地址 第2 5 8 11 14 15 */
#define EP_MSK_INT 0x4492 /* 中断端点逻辑地址 1 4 7 10 13 */
#define EP_MSK_ISO 0x1248 /* 同步端点逻辑地址 3 6 9 12 */
//端点的逻辑地址转换为物理地址,比如逻辑地址0x80 转换过来是物理端点1,
//(usb设置配置的时候发送来的端点号码是逻辑地址,需要转换)
U32 EPAdr(U32 EPNum)
{
U32 val;
val=(EPNum&0x0F)<<1;
if(EPNum&0x80)val+=1;//根据输入输出增减
return(val);
}
//usb写入命令
void WrCmd(U32 cmd)
{
LPC_USB->USBDevIntClr=CCEMTY_INT;//清除命令空中断
LPC_USB->USBCmdCode=cmd;
while((LPC_USB->USBDevIntSt&CCEMTY_INT)==0);//等待写入的命令被接受,空中断再次产生
}
//usb写入命令+数据,流程相当于上一个函数的重复
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);
}
//向端点写入命令,端点号应当是端点的逻辑地址
void WrCmdEP(U32 EPNum,U32 cmd)
{
LPC_USB->USBDevIntClr=CCEMTY_INT;
LPC_USB->USBCmdCode=CMD_SEL_EP(EPAdr(EPNum));//选择端点,发送的是命令形式的端点选择
while((LPC_USB->USBDevIntSt&CCEMTY_INT)==0);
LPC_USB->USBDevIntClr=CCEMTY_INT;
LPC_USB->USBCmdCode=cmd; //写入数据
while((LPC_USB->USBDevIntSt&CCEMTY_INT)==0);
}
//写入命令并读出数据 命令应当是读取命令 02
U32 RdCmdDat(U32 cmd)
{
LPC_USB->USBDevIntClr=CCEMTY_INT|CDFULL_INT;//清除命令为空,数据满中断
LPC_USB->USBCmdCode=cmd;
while((LPC_USB->USBDevIntSt&CDFULL_INT)==0);//等待数据满
return(LPC_USB->USBCmdData);
}
//USB总线复位,重新配置端点的寄存器
void USB_Reset(void)
{
LPC_USB->USBEpInd=0;
LPC_USB->USBMaxPSize=USB_MAX_PACKET0;
LPC_USB->USBEpInd=1;
LPC_USB->USBMaxPSize=USB_MAX_PACKET0;//两个控制端点都设置为最大包形式
while((LPC_USB->USBDevIntSt&EP_RLZED_INT)==0);//等待端点使用
LPC_USB->USBEpIntClr=0xFFFFFFFF;
LPC_USB->USBEpIntEn=0xFFFFFFFF^USB_DMA_EP;//使能DMA的端点,中断自动触发DMA,所以不开启中断
LPC_USB->USBDevIntClr=0xFFFFFFFF;
//当使用同步端点的时候要打开帧中断
LPC_USB->USBDevIntEn=DEV_STAT_INT|EP_SLOW_INT;//打开状态中断(复位挂起等)和慢速中断(默认情况下,端点中断都是慢速中断)
}
//usb设置设备的总线地址
void USB_SetAddress(U32 adr)
{
WrCmdDat(CMD_SET_ADDR,DAT_WR_BYTE(DEV_EN|adr));//连续写入两次,使能usb对该地址的响应
WrCmdDat(CMD_SET_ADDR,DAT_WR_BYTE(DEV_EN|adr));
}
//usb初始化
void USB_Init(void)
{
LPC_SC->PCONP|=(1<<15);//打开IO口时钟
//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; //初始化设置为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); //等待时钟状态切换完成
USB_Reset();
USB_SetAddress(0); //初始化未识别之前设置设备地址为0
NVIC_ClearPendingIRQ(USB_IRQn);
NVIC_SetPriority(USB_IRQn,NVIC_EncodePriority(SYS_NVIC_GROUP,USB_PreemptPriority,USB_SubPriority));//中断优先级别
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挂起事件发生之后自动调用的函数,处理挂起事务
void USB_Suspend(void)
{
usb_debug_printf("USB_Suspend rn");
mouse_connect=0;
}
//usb收到恢复指令之后自动调用的函数,处理恢复事务
void USB_Resume(void)
{
usb_debug_printf("USB_Resume rn");
mouse_connect=0;
}
//usb远程唤醒时间发生的时候自动调用的函数
void USB_WakeUp(void)
{
if(USB_DeviceStatus&USB_GETSTATUS_REMOTE_WAKEUP)
{