如何使用LPC1788微控制器通过USB进行通信?

时间:2014-04-11 11:30:26

标签: c usb microcontroller lpc

我目前正在使用恩智浦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 DEVICE STATUS命令从串行接口引擎读取以下值:

0x19 - (CON (connected), SUS_CH (suspend state change), and RST (bus reset))

使用USBlyzer,我只获得以下四个数据包:http://i.imgur.com/WRk7RBv.png

我期待即使PC端没有正确配置的描述符或匹配的驱动程序,我仍然应该收到更多。我原本期望在Endpoint 0中收到Get Descriptor请求。

我的主要功能只是初始化我的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设置地址功能:

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设置连接功能:

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 ERROR CODE命令,我发现在USB初始化功能结束时我最终会出现“意外数据包”错误。但是,如果我读取测试寄存器,我会按预期返回0xA50F,这意味着我与SIE的通信正在工作,我的USB / AHB时钟可能正确配置并正在运行。

1 个答案:

答案 0 :(得分:0)

我设法在IAR Embedded Workbench中获得了一个示例USB项目。基于此,我进行了两项修改,主要修复了我的程序:

  • 我将项目的配置从“半主题”更改为“SWO”,这使我的打印输出更快。

  • 我删除了以下行。它显然错误配置了USB时钟频率。

    LPC_SC->USBCLKSEL = 0x102;