如何使用LPC1788微控制器通过USB进行通信?
-
21-12-2019 - |
题
我现在正在使用NXP LPC1788微控制器,我试图将其配置为使用USB与Windows 7 PC通信。我的USB经验有限(我在本周开始时开始学习该协议),但我已经使用了LPC1788了一段时间,并且具有其他通信协议(CAN,I2C,SSP)的经验。
我想将我的微控制器配置为充当设备和PC作为主机的设备。我怀疑我需要配置微控制器以使用全速中断传输进行通信。此外,我稍后可能需要为PC创建自己的特定于供应商的USB驱动程序 - 我尚未这样做,并且我的描述符未正确配置。
我的特定问题是,当我运行我的程序并初始化/启用微控制器的USB设备时,我只收到两个USB中断。每个情况下的设备中断状态(Devintst)值为:
0x19 - (FRAME, DEVSTAT, and CCEMPTY interrupts)
0x1 - (FRAME interrupt)
.
在接收devstat中断的情况下,我使用get设备状态命令从串行接口引擎读取以下值:
0x19 - (CON (connected), SUS_CH (suspend state change), and RST (bus reset))
.
使用Ulbblezer,我只获得以下四个数据包: http://i.imgur.com/wrk7rbv .png
我期待即使没有正确配置的描述符或PC结束的匹配驱动程序,我仍然应该收到更多。我希望在端点0中接收一个get描述符请求。
我的主要功能只初始化我的USB设备并无限期地循环。
USB初始化代码如下所示:
void USBInit()
{
// Turn on power and clock
CLKPWR_ConfigPPWR(CLKPWR_PCONP_PCUSB, ENABLE);
// PLL0 clock is 96 MHz, usbclk should be 48 MHz.
LPC_SC->USBCLKSEL = 0x102;
// Configure USB pins.
PINSEL_ConfigPin(0, 29, 1); // USB_D+1
PINSEL_ConfigPin(0, 30, 1); // USB_D-1
PINSEL_ConfigPin(1, 18, 1); // USB_UP_LED1
PINSEL_ConfigPin(2, 9, 1); // USB_CONNECT1
PINSEL_ConfigPin(1, 30, 2); // USB_VBUS
//PINSEL_ConfigPin(1, 19, 2); // USB_PPWR1
PINSEL_SetPinMode(1, 30, PINSEL_BASICMODE_PLAINOUT);
// Set DEV_CLK_EN and AHB_CLK_EN.
LPC_USB->USBClkCtrl |= 0x12;
// Wait until change is reflected in clock status register.
while((LPC_USB->USBClkSt & 0x12) != 0x12);
// Select USB port 1.
LPC_USB->USBClkCtrl |= 0x8;
while((LPC_USB->USBClkSt & 0x8) == 0);
LPC_USB->StCtrl &= ~0x3;
LPC_USB->USBClkCtrl &= ~0x8;
// Reset the USB.
USBReset();
// Configure interrupt mode.
writeSIECommandData(CMD_SET_MODE, 0);
// Enable NVIC USB interrupts.
NVIC_EnableIRQ(USB_IRQn);
// Set device address to 0x0 and enable device & connection.
USBSetAddress(0);
USBSetConnection(TRUE);
//printf("USB initialised\n");
//printf("EpIntEn: 0x%x\n", LPC_USB->EpIntEn);
// No errors here (SIE Error code: 0x0).
USBPrintErrCode();
// Packet sequence violation here (SIE Error code: 0x11).
USBPrintErrCode();
}
.
USB重置功能:
void USBReset()
{
LPC_USB->EpInd = 0;
LPC_USB->MaxPSize = USB_MAX_PACKET_SIZE;
LPC_USB->EpInd = 1;
LPC_USB->MaxPSize = USB_MAX_PACKET_SIZE;
while ((LPC_USB->DevIntSt & EP_RLZED_INT) == 0);
LPC_USB->EpIntClr = 0xFFFFFFFF;
LPC_USB->EpIntEn = 0xFFFFFFFF;
LPC_USB->DevIntClr = 0xFFFFFFFF;
LPC_USB->DevIntEn = DEV_STAT_INT | EP_SLOW_INT | EP_FAST_INT;
}
.
USB SET地址功能:
void USBSetAddress(uint32_t addr)
{
writeSIECommandData(CMD_SET_ADDR, DAT_WR_BYTE(DEV_EN | addr));
writeSIECommandData(CMD_SET_ADDR, DAT_WR_BYTE(DEV_EN | addr));
}
.
USB SET连接功能:
void USBSetConnection(uint32_t connect)
{
writeSIECommandData(CMD_SET_DEV_STAT, DAT_WR_BYTE(connect ? DEV_CON : 0));
}
.
USB中断服务例程:
void USB_IRQHandler(void)
{
uint32_t data;
uint32_t interruptData = LPC_USB->DevIntSt;
printf("InterruptData: 0x%x\n", interruptData);
// Handle device status interrupt (reset, connection change, suspend/resume).
if(interruptData & DEV_STAT_INT)
{
LPC_USB->DevIntClr = DEV_STAT_INT;
writeSIECommand(CMD_GET_DEV_STAT);
data = readSIECommandData(DAT_GET_DEV_STAT);
printf("Data: 0x%x\n", data);
// Device reset.
if(data & DEV_RST)
{
USBReset();
USBResetCore();
printf("USB Reset\n");
}
// Connection change.
if(data & DEV_CON_CH)
{
printf("Connection change\n");
/* Pass */
}
// Suspend/resume.
if(data & DEV_SUS_CH)
{
if(data & DEV_SUS)
{
printf("USB Suspend\n");
USBSuspend();
}
else
{
printf("USB Resume\n");
USBResume();
}
}
return;
}
// Handle endpoint interrupt.
if(interruptData & EP_SLOW_INT)
{
printf("Endpoint interrupt\n");
}
if(interruptData & EP_FAST_INT)
{
printf("Endpoint interrupt\n");
}
}
.
终端输出:
InterruptData: 0x19
Data: 0x19
USB Reset
USB Resume
InterruptData: 0x1
.
编辑:使用sie的get错误代码命令,我发现我最终通过USB初始化功能结束时出现了“意外数据包”错误。但是,如果我读取测试寄存器,我会按预期恢复0xA50F,这意味着我与SIE的通信工作,我的USB / AHB时钟可能会正确配置和运行。
解决方案
我设法在IAR嵌入式工作台上工作的示例USB项目。基于此,我做了两个大多数修复了我的程序的变化:
-
我将我的项目的配置从“semihosted”改为“swo”,这使得我的打印输出更快。
-
我删除了以下行。它显然错误地配置了USB时钟速率。
LPC_SC->USBCLKSEL = 0x102;